Skip to content

Instantly share code, notes, and snippets.

@humazed
Last active September 21, 2017 00:06
Show Gist options
  • Select an option

  • Save humazed/990a72f759b2250e1e18212dabbda533 to your computer and use it in GitHub Desktop.

Select an option

Save humazed/990a72f759b2250e1e18212dabbda533 to your computer and use it in GitHub Desktop.
okhttp transport for appengine
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();
}
}
}
}
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();
}
}
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(&quot;127.0.0.1&quot;, 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(&quot;certs.jks&quot;), &quot;password&quot;);
* </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(&quot;certs.pem&quot;));
* </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