com.google.api.client.http.okhttp.OkHttpTransport.java Source code

Java tutorial

Introduction

Here is the source code for com.google.api.client.http.okhttp.OkHttpTransport.java

Source

/*
 * Copyright (c) 2010 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */

package com.google.api.client.http.okhttp;

import com.google.api.client.http.HttpMethods;
import com.google.api.client.http.HttpTransport;
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 com.squareup.okhttp.OkHttpClient;

import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.Proxy;
import java.net.URL;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.util.Arrays;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;

/**
 * Thread-safe HTTP low-level transport based on the {@code java.net} package.
 * <p/>
 * <p>
 * Users should consider modifying the keep alive property on {@link com.google.api.client.http.okhttp.OkHttpTransport} to control
 * whether the socket should be returned to a pool of connected sockets. More information is
 * available <a
 * href='http://docs.oracle.com/javase/7/docs/technotes/guides/net/http-keepalive.html'>here</a>.
 * </p>
 * <p/>
 * <p>
 * We honor the default global caching behavior. To change the default behavior use
 * {@link java.net.HttpURLConnection#setDefaultUseCaches(boolean)}.
 * </p>
 * <p/>
 * <p>
 * Upgrade warning: in prior version 1.14 caching was always disabled, but starting with version
 * 1.15 we honor the default global caching behavior.
 * </p>
 * <p/>
 * <p>
 * Implementation is thread-safe. For maximum efficiency, applications should use a single
 * globally-shared instance of the HTTP transport.
 * </p>
 *
 * @author Yaniv Inbar
 * @since 1.0
 */
public final class OkHttpTransport extends HttpTransport {

    /**
     * All valid request methods as specified in {@link java.net.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;

    private final OkHttpClient okHttpClient;

    /**
     * Constructor with the default behavior.
     * <p/>
     * <p>
     * Instead use {@link com.google.api.client.http.okhttp.OkHttpTransport.Builder} to modify behavior.
     * </p>
     */
    public OkHttpTransport() {
        this(null, 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
     * @param okHttpClient
     */
    OkHttpTransport(Proxy proxy, SSLSocketFactory sslSocketFactory, HostnameVerifier hostnameVerifier,
            OkHttpClient okHttpClient) {
        this.proxy = proxy;
        this.sslSocketFactory = sslSocketFactory;
        this.hostnameVerifier = hostnameVerifier;
        this.okHttpClient = okHttpClient == null ? new OkHttpClient() : okHttpClient;
    }

    @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) {
            okHttpClient.setProxy(proxy);
        }
        HttpURLConnection connection = okHttpClient.open(connUrl);

        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);
    }

    /**
     * Builder for {@link com.google.api.client.http.okhttp.OkHttpTransport}.
     * <p/>
     * <p>
     * Implementation is not thread-safe.
     * </p>
     *
     * @since 1.13
     */
    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;

        private OkHttpClient okHttpClient;

        /**
         * 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 java.security.cert.CertificateFactory#generateCertificates(java.io.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 com.google.api.client.util.SecurityUtils#loadKeyStore}
         *                   or {@link com.google.api.client.util.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 com.google.api.client.util.Beta} <br/>
         * Disables validating server SSL certificates by setting the SSL socket factory using
         * {@link com.google.api.client.util.SslUtils#trustAllSSLContext()} for the SSL context and
         * {@link com.google.api.client.util.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;
        }

        public Builder setOkHttpClient(OkHttpClient okHttpClient) {
            this.okHttpClient = okHttpClient;
            return this;
        }

        /**
         * Returns a new instance of {@link com.google.api.client.http.okhttp.OkHttpTransport} based on the options.
         */
        public OkHttpTransport build() {
            return new OkHttpTransport(proxy, sslSocketFactory, hostnameVerifier, okHttpClient);
        }
    }
}