Last active
September 21, 2017 00:06
-
-
Save humazed/990a72f759b2250e1e18212dabbda533 to your computer and use it in GitHub Desktop.
okhttp transport for appengine
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import com.google.api.client.http.LowLevelHttpRequest; | |
| import com.google.api.client.http.LowLevelHttpResponse; | |
| import com.google.api.client.util.Preconditions; | |
| import java.io.IOException; | |
| import java.io.OutputStream; | |
| import java.net.HttpURLConnection; | |
| public class OkHttpRequest extends LowLevelHttpRequest { | |
| private final HttpURLConnection connection; | |
| /** | |
| * @param connection HTTP URL connection | |
| */ | |
| OkHttpRequest(HttpURLConnection connection) { | |
| this.connection = connection; | |
| } | |
| @Override | |
| public void addHeader(String name, String value) { | |
| connection.addRequestProperty(name, value); | |
| } | |
| @Override | |
| public void setTimeout(int connectTimeout, int readTimeout) { | |
| connection.setReadTimeout(readTimeout); | |
| connection.setConnectTimeout(connectTimeout); | |
| } | |
| @Override | |
| public LowLevelHttpResponse execute() throws IOException { | |
| HttpURLConnection connection = this.connection; | |
| // write content | |
| if (getStreamingContent() != null) { | |
| String contentType = getContentType(); | |
| if (contentType != null) { | |
| addHeader("Content-Type", contentType); | |
| } | |
| String contentEncoding = getContentEncoding(); | |
| if (contentEncoding != null) { | |
| addHeader("Content-Encoding", contentEncoding); | |
| } | |
| long contentLength = getContentLength(); | |
| if (contentLength >= 0) { | |
| addHeader("Content-Length", Long.toString(contentLength)); | |
| } | |
| String requestMethod = connection.getRequestMethod(); | |
| if ("POST".equals(requestMethod) || "PUT".equals(requestMethod)) { | |
| connection.setDoOutput(true); | |
| // see | |
| // http://developer.android.com/reference/java/net/HttpURLConnection.html | |
| if (contentLength >= 0 && contentLength <= Integer.MAX_VALUE) { | |
| connection.setFixedLengthStreamingMode((int) contentLength); | |
| } else { | |
| connection.setChunkedStreamingMode(0); | |
| } | |
| OutputStream out = connection.getOutputStream(); | |
| try { | |
| getStreamingContent().writeTo(out); | |
| } finally { | |
| out.close(); | |
| } | |
| } else { | |
| // cannot call setDoOutput(true) because it would change a GET | |
| // method to POST | |
| // for HEAD, OPTIONS, DELETE, or TRACE it would throw an | |
| // exceptions | |
| Preconditions.checkArgument(contentLength == 0, | |
| "%s with non-zero content length is not supported", | |
| requestMethod); | |
| } | |
| } | |
| // connect | |
| boolean successfulConnection = false; | |
| try { | |
| connection.connect(); | |
| OkHttpResponse response = new OkHttpResponse(connection); | |
| successfulConnection = true; | |
| return response; | |
| } finally { | |
| if (!successfulConnection) { | |
| connection.disconnect(); | |
| } | |
| } | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import com.google.api.client.http.HttpStatusCodes; | |
| import com.google.api.client.http.LowLevelHttpResponse; | |
| import java.io.IOException; | |
| import java.io.InputStream; | |
| import java.net.HttpURLConnection; | |
| import java.util.ArrayList; | |
| import java.util.List; | |
| import java.util.Map; | |
| public class OkHttpResponse extends LowLevelHttpResponse { | |
| private final HttpURLConnection connection; | |
| private final int responseCode; | |
| private final String responseMessage; | |
| private final ArrayList<String> headerNames = new ArrayList<String>(); | |
| private final ArrayList<String> headerValues = new ArrayList<String>(); | |
| OkHttpResponse(HttpURLConnection connection) throws IOException { | |
| this.connection = connection; | |
| int responseCode = connection.getResponseCode(); | |
| this.responseCode = responseCode == -1 ? 0 : responseCode; | |
| responseMessage = connection.getResponseMessage(); | |
| List<String> headerNames = this.headerNames; | |
| List<String> headerValues = this.headerValues; | |
| for (Map.Entry<String, List<String>> entry : connection | |
| .getHeaderFields().entrySet()) { | |
| String key = entry.getKey(); | |
| if (key != null) { | |
| for (String value : entry.getValue()) { | |
| if (value != null) { | |
| headerNames.add(key); | |
| headerValues.add(value); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| @Override | |
| public int getStatusCode() { | |
| return responseCode; | |
| } | |
| @Override | |
| public InputStream getContent() throws IOException { | |
| HttpURLConnection connection = this.connection; | |
| return HttpStatusCodes.isSuccess(responseCode) ? connection | |
| .getInputStream() : connection.getErrorStream(); | |
| } | |
| @Override | |
| public String getContentEncoding() { | |
| return connection.getContentEncoding(); | |
| } | |
| @Override | |
| public long getContentLength() { | |
| String string = connection.getHeaderField("Content-Length"); | |
| return string == null ? -1 : Long.parseLong(string); | |
| } | |
| @Override | |
| public String getContentType() { | |
| return connection.getHeaderField("Content-Type"); | |
| } | |
| @Override | |
| public String getReasonPhrase() { | |
| return responseMessage; | |
| } | |
| @Override | |
| public String getStatusLine() { | |
| String result = connection.getHeaderField(0); | |
| return result != null && result.startsWith("HTTP/1.") ? result : null; | |
| } | |
| @Override | |
| public int getHeaderCount() { | |
| return headerNames.size(); | |
| } | |
| @Override | |
| public String getHeaderName(int index) { | |
| return headerNames.get(index); | |
| } | |
| @Override | |
| public String getHeaderValue(int index) { | |
| return headerValues.get(index); | |
| } | |
| /** | |
| * Closes the connection to the HTTP server. | |
| */ | |
| @Override | |
| public void disconnect() { | |
| connection.disconnect(); | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import com.google.api.client.http.HttpMethods; | |
| import com.google.api.client.http.HttpTransport; | |
| import com.google.api.client.http.javanet.NetHttpTransport; | |
| import com.google.api.client.util.Beta; | |
| import com.google.api.client.util.Preconditions; | |
| import com.google.api.client.util.SecurityUtils; | |
| import com.google.api.client.util.SslUtils; | |
| import java.io.IOException; | |
| import java.io.InputStream; | |
| import java.net.HttpURLConnection; | |
| import java.net.Proxy; | |
| import java.net.URL; | |
| import java.net.URLConnection; | |
| import java.security.GeneralSecurityException; | |
| import java.security.KeyStore; | |
| import java.security.cert.CertificateFactory; | |
| import java.util.Arrays; | |
| import javax.net.ssl.HostnameVerifier; | |
| import javax.net.ssl.HttpsURLConnection; | |
| import javax.net.ssl.SSLContext; | |
| import javax.net.ssl.SSLSocketFactory; | |
| import okhttp3.OkHttpClient; | |
| import okhttp3.OkUrlFactory; | |
| /** | |
| * I shamelessly copied most if this source code from the NetHttpTransport, but | |
| * I just wanted to replace the HttpUrlConnection with OkHttp. | |
| * | |
| * @author Till Klocke | |
| */ | |
| public class OkHttpTransport extends HttpTransport { | |
| /** | |
| * The OkHttpClient to use. Can be set via builder or a new default instance | |
| * will be created. | |
| */ | |
| private OkHttpClient okClient; | |
| /** | |
| * All valid request methods as specified in | |
| * {@link HttpURLConnection#setRequestMethod}, sorted in ascending | |
| * alphabetical order. | |
| */ | |
| private static final String[] SUPPORTED_METHODS = {HttpMethods.DELETE, | |
| HttpMethods.GET, HttpMethods.HEAD, HttpMethods.OPTIONS, | |
| HttpMethods.POST, HttpMethods.PUT, HttpMethods.TRACE}; | |
| static { | |
| Arrays.sort(SUPPORTED_METHODS); | |
| } | |
| /** | |
| * HTTP proxy or {@code null} to use the proxy settings from <a href= | |
| * "http://docs.oracle.com/javase/7/docs/api/java/net/doc-files/net-properties.html" | |
| * >system properties</a>. | |
| */ | |
| private final Proxy proxy; | |
| /** | |
| * SSL socket factory or {@code null} for the default. | |
| */ | |
| private final SSLSocketFactory sslSocketFactory; | |
| /** | |
| * Host name verifier or {@code null} for the default. | |
| */ | |
| private final HostnameVerifier hostnameVerifier; | |
| /** | |
| * Constructor with the default behavior. | |
| * <p> | |
| * <p> | |
| * Instead use {@link Builder} to modify behavior. | |
| * </p> | |
| */ | |
| public OkHttpTransport() { | |
| this(new OkHttpClient(), null, null, null); | |
| } | |
| /** | |
| * @param proxy HTTP proxy or {@code null} to use the proxy settings from <a | |
| * href= | |
| * "http://docs.oracle.com/javase/7/docs/api/java/net/doc-files/net-properties.html" | |
| * > system properties</a> | |
| * @param sslSocketFactory SSL socket factory or {@code null} for the default | |
| * @param hostnameVerifier host name verifier or {@code null} for the default | |
| */ | |
| OkHttpTransport(OkHttpClient okClient, Proxy proxy, SSLSocketFactory sslSocketFactory, HostnameVerifier hostnameVerifier) { | |
| if (okClient != null) { | |
| this.okClient = okClient; | |
| } else { | |
| this.okClient = new OkHttpClient(); | |
| } | |
| this.proxy = proxy; | |
| this.sslSocketFactory = sslSocketFactory; | |
| this.hostnameVerifier = hostnameVerifier; | |
| } | |
| @Override | |
| public boolean supportsMethod(String method) { | |
| return Arrays.binarySearch(SUPPORTED_METHODS, method) >= 0; | |
| } | |
| @Override | |
| protected OkHttpRequest buildRequest(String method, String url) throws IOException { | |
| Preconditions.checkArgument(supportsMethod(method), "HTTP method %s not supported", method); | |
| // connection with proxy settings | |
| URL connUrl = new URL(url); | |
| if (proxy != null) { | |
| throw new UnsupportedOperationException("setting proxy un supported at this point"); | |
| // okClient.setProxy(proxy); | |
| } | |
| URLConnection conn = new OkUrlFactory(okClient).open(connUrl); | |
| HttpURLConnection connection = (HttpURLConnection) conn; | |
| connection.setRequestMethod(method); | |
| // SSL settings | |
| if (connection instanceof HttpsURLConnection) { | |
| HttpsURLConnection secureConnection = (HttpsURLConnection) connection; | |
| if (hostnameVerifier != null) { | |
| secureConnection.setHostnameVerifier(hostnameVerifier); | |
| } | |
| if (sslSocketFactory != null) { | |
| secureConnection.setSSLSocketFactory(sslSocketFactory); | |
| } | |
| } | |
| return new OkHttpRequest(connection); | |
| } | |
| public OkHttpClient getOkHttpClient() { | |
| return okClient; | |
| } | |
| /** | |
| * Builder for {@link OkHttpTransport}. | |
| * <p> | |
| * <p> | |
| * Implementation is not thread-safe. | |
| * </p> | |
| */ | |
| public static final class Builder { | |
| /** | |
| * SSL socket factory or {@code null} for the default. | |
| */ | |
| private SSLSocketFactory sslSocketFactory; | |
| /** | |
| * Host name verifier or {@code null} for the default. | |
| */ | |
| private HostnameVerifier hostnameVerifier; | |
| /** | |
| * HTTP proxy or {@code null} to use the proxy settings from <a href= | |
| * "http://docs.oracle.com/javase/7/docs/api/java/net/doc-files/net-properties.html" | |
| * >system properties</a>. | |
| */ | |
| private Proxy proxy; | |
| /** | |
| * The OkHttpClient to use for building the OkHttpTransport. May be | |
| * null, then a default OkHttpClient will be used. | |
| */ | |
| private OkHttpClient okClient; | |
| /** | |
| * Sets the HTTP proxy or {@code null} to use the proxy settings from <a | |
| * href= | |
| * "http://docs.oracle.com/javase/7/docs/api/java/net/doc-files/net-properties.html" | |
| * >system properties</a>. | |
| * <p> | |
| * <p> | |
| * For example: | |
| * </p> | |
| * <p> | |
| * <pre> | |
| * setProxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1", 8080))) | |
| * </pre> | |
| */ | |
| public Builder setProxy(Proxy proxy) { | |
| this.proxy = proxy; | |
| return this; | |
| } | |
| /** | |
| * Sets the SSL socket factory based on root certificates in a Java | |
| * KeyStore. | |
| * <p> | |
| * <p> | |
| * Example usage: | |
| * </p> | |
| * <p> | |
| * <pre> | |
| * trustCertificatesFromJavaKeyStore(new FileInputStream("certs.jks"), "password"); | |
| * </pre> | |
| * | |
| * @param keyStoreStream input stream to the key store (closed at the end of this | |
| * method in a finally block) | |
| * @param storePass password protecting the key store file | |
| * @since 1.14 | |
| */ | |
| public Builder trustCertificatesFromJavaKeyStore( | |
| InputStream keyStoreStream, String storePass) | |
| throws GeneralSecurityException, IOException { | |
| KeyStore trustStore = SecurityUtils.getJavaKeyStore(); | |
| SecurityUtils.loadKeyStore(trustStore, keyStoreStream, storePass); | |
| return trustCertificates(trustStore); | |
| } | |
| /** | |
| * Sets the SSL socket factory based root certificates generated from | |
| * the specified stream using | |
| * {@link CertificateFactory#generateCertificates(InputStream)}. | |
| * <p> | |
| * <p> | |
| * Example usage: | |
| * </p> | |
| * <p> | |
| * <pre> | |
| * trustCertificatesFromStream(new FileInputStream("certs.pem")); | |
| * </pre> | |
| * | |
| * @param certificateStream certificate stream | |
| * @since 1.14 | |
| */ | |
| public Builder trustCertificatesFromStream(InputStream certificateStream) | |
| throws GeneralSecurityException, IOException { | |
| KeyStore trustStore = SecurityUtils.getJavaKeyStore(); | |
| trustStore.load(null, null); | |
| SecurityUtils.loadKeyStoreFromCertificates(trustStore, | |
| SecurityUtils.getX509CertificateFactory(), | |
| certificateStream); | |
| return trustCertificates(trustStore); | |
| } | |
| /** | |
| * Sets the SSL socket factory based on a root certificate trust store. | |
| * | |
| * @param trustStore certificate trust store (use for example | |
| * {@link SecurityUtils#loadKeyStore} or | |
| * {@link SecurityUtils#loadKeyStoreFromCertificates}) | |
| * @since 1.14 | |
| */ | |
| public Builder trustCertificates(KeyStore trustStore) | |
| throws GeneralSecurityException { | |
| SSLContext sslContext = SslUtils.getTlsSslContext(); | |
| SslUtils.initSslContext(sslContext, trustStore, | |
| SslUtils.getPkixTrustManagerFactory()); | |
| return setSslSocketFactory(sslContext.getSocketFactory()); | |
| } | |
| /** | |
| * {@link Beta} <br/> | |
| * Disables validating server SSL certificates by setting the SSL socket | |
| * factory using {@link SslUtils#trustAllSSLContext()} for the SSL | |
| * context and {@link SslUtils#trustAllHostnameVerifier()} for the host | |
| * name verifier. | |
| * <p> | |
| * <p> | |
| * Be careful! Disabling certificate validation is dangerous and should | |
| * only be done in testing environments. | |
| * </p> | |
| */ | |
| @Beta | |
| public Builder doNotValidateCertificate() | |
| throws GeneralSecurityException { | |
| hostnameVerifier = SslUtils.trustAllHostnameVerifier(); | |
| sslSocketFactory = SslUtils.trustAllSSLContext().getSocketFactory(); | |
| return this; | |
| } | |
| /** | |
| * Returns the SSL socket factory. | |
| */ | |
| public SSLSocketFactory getSslSocketFactory() { | |
| return sslSocketFactory; | |
| } | |
| /** | |
| * Sets the SSL socket factory or {@code null} for the default. | |
| */ | |
| public Builder setSslSocketFactory(SSLSocketFactory sslSocketFactory) { | |
| this.sslSocketFactory = sslSocketFactory; | |
| return this; | |
| } | |
| /** | |
| * Returns the host name verifier or {@code null} for the default. | |
| */ | |
| public HostnameVerifier getHostnameVerifier() { | |
| return hostnameVerifier; | |
| } | |
| /** | |
| * Sets the host name verifier or {@code null} for the default. | |
| */ | |
| public Builder setHostnameVerifier(HostnameVerifier hostnameVerifier) { | |
| this.hostnameVerifier = hostnameVerifier; | |
| return this; | |
| } | |
| /** | |
| * Set the OkHttpClient to use, if you don't want to use an OkHttpClient | |
| * with default configuration. | |
| * | |
| * @param okClient | |
| * @return | |
| */ | |
| public Builder setOkHttpClient(OkHttpClient okClient) { | |
| this.okClient = okClient; | |
| return this; | |
| } | |
| /** | |
| * Returns a new instance of {@link NetHttpTransport} based on the | |
| * options. | |
| */ | |
| public OkHttpTransport build() { | |
| return new OkHttpTransport(okClient, proxy, sslSocketFactory, | |
| hostnameVerifier); | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment