com.yangcong345.android.phone.manager.OkHttpStack.java Source code

Java tutorial

Introduction

Here is the source code for com.yangcong345.android.phone.manager.OkHttpStack.java

Source

/*
 * Copyright (C) 2011 The Android Open Source Project
 *
 * 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.yangcong345.android.phone.manager;

import com.android.volley.AuthFailureError;
import com.android.volley.Request;
import com.android.volley.Request.Method;
import com.android.volley.toolbox.HttpStack;

import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.ProtocolVersion;
import org.apache.http.StatusLine;
import org.apache.http.entity.BasicHttpEntity;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicHttpResponse;
import org.apache.http.message.BasicStatusLine;

import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import javax.net.ssl.SSLSocketFactory;

import okhttp3.CacheControl;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.ResponseBody;

/**
 * An {@link HttpStack} based on okHttp.
 */
public class OkHttpStack implements HttpStack {

    /**
     * An interface for transforming URLs before use.
     */
    public interface UrlRewriter {
        /**
         * Returns a URL to use instead of the provided one, or null to indicate
         * this URL should not be used at all.
         */
        public String rewriteUrl(String originalUrl);
    }

    private final UrlRewriter mUrlRewriter;
    private final SSLSocketFactory mSslSocketFactory;

    public OkHttpStack() {
        this(null);
    }

    /**
     * @param urlRewriter Rewriter to use for request URLs
     */
    public OkHttpStack(UrlRewriter urlRewriter) {
        this(urlRewriter, null);
    }

    /**
     * @param urlRewriter      Rewriter to use for request URLs
     * @param sslSocketFactory SSL factory to use for HTTPS connections
     */
    public OkHttpStack(UrlRewriter urlRewriter, SSLSocketFactory sslSocketFactory) {
        mUrlRewriter = urlRewriter;
        mSslSocketFactory = sslSocketFactory;
    }

    @Override
    public synchronized HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)
            throws IOException, AuthFailureError {
        String url = request.getUrl();

        if (mUrlRewriter != null) {
            String rewritten = mUrlRewriter.rewriteUrl(url);
            if (rewritten == null) {
                throw new IOException("URL blocked by rewriter: " + url);
            }
            url = rewritten;
        }

        /*init request builder*/
        okhttp3.Request.Builder okRequestBuilder = new okhttp3.Request.Builder().url(url)
                .cacheControl(new CacheControl.Builder().maxAge(0, TimeUnit.SECONDS).build());

        /*set request headers*/
        HashMap<String, String> map = new HashMap<String, String>();
        map.putAll(request.getHeaders());
        map.putAll(additionalHeaders);
        for (String headerName : map.keySet()) {
            okRequestBuilder.addHeader(headerName, map.get(headerName));
        }

        /*set request method*/
        setRequestMethod(okRequestBuilder, request);

        okhttp3.Request okRequest = okRequestBuilder.build();

        /*init request client*/
        int timeoutMs = request.getTimeoutMs();
        OkHttpClient.Builder okClientBuilder = new OkHttpClient.Builder();
        okClientBuilder.followRedirects(HttpURLConnection.getFollowRedirects())
                .followSslRedirects(HttpURLConnection.getFollowRedirects())
                .connectTimeout(timeoutMs, TimeUnit.MILLISECONDS).readTimeout(timeoutMs, TimeUnit.MILLISECONDS);

        if (okRequest.isHttps() && mSslSocketFactory != null) {
            okClientBuilder.sslSocketFactory(mSslSocketFactory);
        }

        // Initialize HttpResponse with data from the HttpURLConnection.
        ProtocolVersion protocolVersion = new ProtocolVersion("HTTP", 1, 1);

        OkHttpClient okClient = okClientBuilder.build();

        Response okResponse = okClient.newCall(okRequest).execute();
        int responseCode = okResponse.code();
        if (responseCode == -1) {
            // -1 is returned by getResponseCode() if the response code could not be retrieved.
            // Signal to the caller that something was wrong with the connection.
            throw new IOException("Could not retrieve response code from HttpUrlConnection.");
        }
        StatusLine responseStatus = new BasicStatusLine(protocolVersion, responseCode, okResponse.message());
        BasicHttpResponse response = new BasicHttpResponse(responseStatus);
        if (hasResponseBody(request.getMethod(), responseStatus.getStatusCode())) {
            response.setEntity(entityFromOkHttp(okResponse));
        }

        for (int i = 0; i < okResponse.headers().size(); i++) {
            String name = okResponse.headers().name(i);
            String value = okResponse.headers().value(i);
            Header h = new BasicHeader(name, value);
            response.addHeader(h);
        }
        return response;
    }

    /**
     * Checks if a response message contains a body.
     *
     * @param requestMethod request method
     * @param responseCode  response status code
     * @return whether the response has a body
     * @see <a href="https://tools.ietf.org/html/rfc7230#section-3.3">RFC 7230 section 3.3</a>
     */

    private static boolean hasResponseBody(int requestMethod, int responseCode) {
        return requestMethod != Request.Method.HEAD
                && !(HttpStatus.SC_CONTINUE <= responseCode && responseCode < HttpStatus.SC_OK)
                && responseCode != HttpStatus.SC_NO_CONTENT && responseCode != HttpStatus.SC_NOT_MODIFIED;
    }

    /**
     * Initializes an {@link HttpEntity} from the given {@link HttpURLConnection}.
     *
     * @return an HttpEntity populated with data from <code>connection</code>.
     */
    private static HttpEntity entityFromOkHttp(Response okResponse) {
        ResponseBody rb = okResponse.body();

        BasicHttpEntity entity = new BasicHttpEntity();
        InputStream inputStream = rb.byteStream();
        entity.setContent(inputStream);
        entity.setContentLength(rb.contentLength());
        entity.setContentType(rb.contentType().type());
        return entity;
    }

    private void setRequestMethod(okhttp3.Request.Builder builder, Request<?> request)
            throws IOException, AuthFailureError {
        switch (request.getMethod()) {
        case Method.DEPRECATED_GET_OR_POST:
            throw new IllegalStateException("unRecognize request method Method.DEPRECATED_GET_OR_POST");
        case Method.GET:
            builder.get();
            break;
        case Method.DELETE:
            builder.delete();
            break;
        case Method.POST:
            RequestBody body = checkRequestBody(request);
            if (body != null) {
                builder.post(body);
            }
            break;
        case Method.PUT:
            body = checkRequestBody(request);
            if (body != null) {
                builder.put(body);
            }
            break;
        case Method.HEAD:
            builder.head();
            break;
        case Method.OPTIONS:
            throw new IllegalStateException("unRecognize request method Method.OPTIONS");
        case Method.TRACE:
            throw new IllegalStateException("unRecognize request method Method.TRACE");
        case Method.PATCH:
            body = checkRequestBody(request);
            if (body != null) {
                builder.patch(body);
            }
            break;
        default:
            throw new IllegalStateException("Unknown method type.");
        }
    }

    private static RequestBody checkRequestBody(Request<?> request) throws IOException, AuthFailureError {
        byte[] body = request.getBody();
        if (body != null) {
            RequestBody requestBody = RequestBody.create(MediaType.parse(request.getBodyContentType()), body);
            return requestBody;
        }

        return null;
    }
}