Package com.google.appengine.api.urlfetch

Source Code of com.google.appengine.api.urlfetch.URLFetchServiceImpl

// Copyright 2007 Google Inc. All rights reserved.

package com.google.appengine.api.urlfetch;

import com.google.appengine.api.urlfetch.URLFetchServicePb.URLFetchRequest;
import com.google.appengine.api.urlfetch.URLFetchServicePb.URLFetchRequest.RequestMethod;
import com.google.appengine.api.urlfetch.URLFetchServicePb.URLFetchResponse;
import com.google.appengine.api.urlfetch.URLFetchServicePb.URLFetchResponse.Header;
import com.google.appengine.api.urlfetch.URLFetchServicePb.URLFetchServiceError.ErrorCode;
import com.google.appengine.api.utils.FutureWrapper;
import com.google.apphosting.api.ApiProxy;
import com.google.protobuf.ByteString;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.net.UnknownHostException;
import java.util.concurrent.Future;
import java.util.logging.Logger;

import javax.net.ssl.SSLHandshakeException;

class URLFetchServiceImpl implements URLFetchService {
  static final String PACKAGE = "urlfetch";

  private static final Logger logger = Logger.getLogger(URLFetchServiceImpl.class.getName());

  @Override
  public HTTPResponse fetch(URL url) throws IOException {
    return fetch(new HTTPRequest(url));
  }

  @Override
  public HTTPResponse fetch(HTTPRequest request) throws IOException {
    byte[] responseBytes;
    try {
      responseBytes = ApiProxy.makeSyncCall(
          PACKAGE, "Fetch",
          convertToPb(request).toByteArray(),
          createApiConfig(request.getFetchOptions()));
    } catch (ApiProxy.RequestTooLargeException ex) {
      throw new IOException("The request exceeded the maximum permissible size");
    } catch (ApiProxy.ApplicationException ex) {
      Throwable cause = convertApplicationException(request.getURL(), ex);
      if (cause instanceof RuntimeException) {
        throw (RuntimeException) cause;
      } else if (cause instanceof IOException) {
        throw (IOException) cause;
      } else {
        throw new RuntimeException(cause);
      }
    } catch (ApiProxy.ApiDeadlineExceededException ex) {
      throw new SocketTimeoutException("Timeout while fetching: " + request.getURL());
    }

    URLFetchResponse responseProto = URLFetchResponse.newBuilder().mergeFrom(responseBytes).build();
    if (!request.getFetchOptions().getAllowTruncate() && responseProto.getContentWasTruncated()) {
      throw new ResponseTooLargeException(request.getURL().toString());
    }
    return convertFromPb(responseProto);
  }

  @Override
  public Future<HTTPResponse> fetchAsync(URL url) {
    return fetchAsync(new HTTPRequest(url));
  }

  @Override
  public Future<HTTPResponse> fetchAsync(HTTPRequest request) {
    final FetchOptions fetchOptions = request.getFetchOptions();
    final URL url = request.getURL();

    Future<byte[]> response = ApiProxy.makeAsyncCall(PACKAGE, "Fetch",
        convertToPb(request).toByteArray(), createApiConfig(fetchOptions));

    return new FutureWrapper<byte[], HTTPResponse>(response) {
      @Override
      protected HTTPResponse wrap(byte[] responseBytes) throws IOException {
        URLFetchResponse responseProto =
            URLFetchResponse.newBuilder().mergeFrom(responseBytes).build();
        if (!fetchOptions.getAllowTruncate() && responseProto.getContentWasTruncated()) {
          throw new ResponseTooLargeException(url.toString());
        }
        return convertFromPb(responseProto);
      }

      @Override
      protected Throwable convertException(Throwable cause) {
        if (cause instanceof ApiProxy.ApplicationException) {
          return convertApplicationException(url, (ApiProxy.ApplicationException) cause);
        } else if (cause instanceof ApiProxy.ApiDeadlineExceededException) {
          return new SocketTimeoutException("Timeout while fetching: " + url);
        }
        return cause;
      }
    };
  }

  private ApiProxy.ApiConfig createApiConfig(FetchOptions options) {
    ApiProxy.ApiConfig apiConfig = new ApiProxy.ApiConfig();
    apiConfig.setDeadlineInSeconds(options.getDeadline());
    return apiConfig;
  }

  private String getURLExceptionMessage(String formatString, String url, String errorDetail) {
    if (errorDetail == null || errorDetail.trim().isEmpty()) {
      return String.format(formatString, url);
    } else {
      return String.format(formatString + ", error: %s", url, errorDetail);
    }
  }

  private Throwable convertApplicationException(URL requestUrl,
                                                ApiProxy.ApplicationException ex) {
    String urlString = requestUrl.toString();
    ErrorCode errorCode = ErrorCode.valueOf(ex.getApplicationError());
    String errorDetail = ex.getErrorDetail();
    switch (errorCode) {
      case INVALID_URL:
        return new MalformedURLException(
            getURLExceptionMessage("Invalid URL specified: %s", urlString, errorDetail));
      case CLOSED:
        return new IOException(getURLExceptionMessage(
            "Connection closed unexpectedly by server at URL: %s", urlString, null));
      case TOO_MANY_REDIRECTS:
        return new IOException(getURLExceptionMessage(
            "Too many redirects at URL: %s with redirect=true", urlString, null));
      case MALFORMED_REPLY:
        return new IOException(getURLExceptionMessage(
            "Malformed HTTP reply received from server at URL: %s", urlString, errorDetail));
      case RESPONSE_TOO_LARGE:
        return new ResponseTooLargeException(urlString);
      case DNS_ERROR:
        return new UnknownHostException(getURLExceptionMessage(
            "DNS host lookup failed for URL: %s", urlString, null));
      case FETCH_ERROR:
        return new IOException(getURLExceptionMessage(
            "Could not fetch URL: %s", urlString, errorDetail));
      case INTERNAL_TRANSIENT_ERROR:
        return new InternalTransientException(urlString);
      case DEADLINE_EXCEEDED:
        return new SocketTimeoutException(getURLExceptionMessage(
            "Timeout while fetching URL: %s", urlString, null));
      case SSL_CERTIFICATE_ERROR:
        return new SSLHandshakeException(getURLExceptionMessage(
            "Could not verify SSL certificate for URL: %s", urlString, null));
      case UNSPECIFIED_ERROR:
      default:
        return new IOException(ex.getErrorDetail());
    }
  }

  private URLFetchRequest convertToPb(HTTPRequest request) {
    URLFetchRequest.Builder requestProto = URLFetchRequest.newBuilder();
    requestProto.setUrl(request.getURL().toExternalForm());

    byte[] payload = request.getPayload();
    if (payload != null) {
      requestProto.setPayload(ByteString.copyFrom(payload));
    }

    switch(request.getMethod()) {
      case GET:
        requestProto.setMethod(RequestMethod.GET);
        break;
      case POST:
        requestProto.setMethod(RequestMethod.POST);
        break;
      case HEAD:
        requestProto.setMethod(RequestMethod.HEAD);
        break;
      case PUT:
        requestProto.setMethod(RequestMethod.PUT);
        break;
      case DELETE:
        requestProto.setMethod(RequestMethod.DELETE);
        break;
      case PATCH:
        requestProto.setMethod(RequestMethod.PATCH);
        break;
      default:
        throw new IllegalArgumentException("unknown method: " + request.getMethod());
    }

    for (HTTPHeader header : request.getHeaders()) {
      URLFetchRequest.Header.Builder headerProto = URLFetchRequest.Header.newBuilder();
      headerProto.setKey(header.getName());
      headerProto.setValue(header.getValue());
      requestProto.addHeader(headerProto);
    }

    requestProto.setFollowRedirects(
        request.getFetchOptions().getFollowRedirects());

    switch (request.getFetchOptions().getCertificateValidationBehavior()) {
      case VALIDATE:
        requestProto.setMustValidateServerCertificate(true);
        break;
      case DO_NOT_VALIDATE:
        requestProto.setMustValidateServerCertificate(false);
        break;
      default:
    }

    return requestProto.build();
  }

  private HTTPResponse convertFromPb(URLFetchResponse responseProto) {
    HTTPResponse response = new HTTPResponse(responseProto.getStatusCode());
    if (responseProto.hasContent()) {
      response.setContent(responseProto.getContent().toByteArray());
    }

    for (Header header : responseProto.getHeaderList()) {
      response.addHeader(header.getKey(), header.getValue());
    }

    if (responseProto.hasFinalUrl() &&
        responseProto.getFinalUrl().length() > 0) {
      try {
        response.setFinalUrl(new URL(responseProto.getFinalUrl()));
      } catch (MalformedURLException e) {
        logger.severe("malformed final URL: " + e);
      }
    }

    return response;
  }
}
TOP

Related Classes of com.google.appengine.api.urlfetch.URLFetchServiceImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.