Skip to content

Instantly share code, notes, and snippets.

@bryanstern
Last active April 24, 2022 03:17

Revisions

  1. bryanstern revised this gist Feb 22, 2015. 1 changed file with 3 additions and 1 deletion.
    4 changes: 3 additions & 1 deletion OkHttpStack.java
    Original file line number Diff line number Diff line change
    @@ -111,7 +111,9 @@ private static HttpEntity entityFromOkHttpResponse(Response r) throws IOExceptio
    entity.setContentLength(body.contentLength());
    entity.setContentEncoding(r.header("Content-Encoding"));

    entity.setContentType(body.contentType().type());
    if (body.contentType() != null) {
    entity.setContentType(body.contentType().type());
    }
    return entity;
    }

  2. bryanstern created this gist Feb 20, 2015.
    179 changes: 179 additions & 0 deletions OkHttpStack.java
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,179 @@
    /**
    * The MIT License (MIT)
    *
    * Copyright (c) 2015 Circle Internet Financial
    *
    * Permission is hereby granted, free of charge, to any person obtaining a copy
    * of this software and associated documentation files (the "Software"), to deal
    * in the Software without restriction, including without limitation the rights
    * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    * copies of the Software, and to permit persons to whom the Software is
    * furnished to do so, subject to the following conditions:
    *
    * The above copyright notice and this permission notice shall be included in
    * all copies or substantial portions of the Software.
    *
    * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    * THE SOFTWARE.
    */
    package com.circle.android.api;

    import com.android.volley.AuthFailureError;
    import com.android.volley.Request;
    import com.android.volley.toolbox.HttpStack;
    import com.squareup.okhttp.Call;
    import com.squareup.okhttp.Headers;
    import com.squareup.okhttp.MediaType;
    import com.squareup.okhttp.OkHttpClient;
    import com.squareup.okhttp.Protocol;
    import com.squareup.okhttp.RequestBody;
    import com.squareup.okhttp.Response;
    import com.squareup.okhttp.ResponseBody;

    import org.apache.http.HttpEntity;
    import org.apache.http.HttpResponse;
    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.util.Map;
    import java.util.concurrent.TimeUnit;


    /**
    * OkHttp backed {@link com.android.volley.toolbox.HttpStack HttpStack} that does not
    * use okhttp-urlconnection
    */
    public class OkHttpStack implements HttpStack {

    private final OkHttpClient mClient;

    public OkHttpStack(OkHttpClient client) {
    this.mClient = client;
    }

    @Override
    public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)
    throws IOException, AuthFailureError {

    OkHttpClient client = mClient.clone();
    int timeoutMs = request.getTimeoutMs();
    client.setConnectTimeout(timeoutMs, TimeUnit.MILLISECONDS);
    client.setReadTimeout(timeoutMs, TimeUnit.MILLISECONDS);
    client.setWriteTimeout(timeoutMs, TimeUnit.MILLISECONDS);

    com.squareup.okhttp.Request.Builder okHttpRequestBuilder = new com.squareup.okhttp.Request.Builder();
    okHttpRequestBuilder.url(request.getUrl());

    Map<String, String> headers = request.getHeaders();
    for (final String name : headers.keySet()) {
    okHttpRequestBuilder.addHeader(name, headers.get(name));
    }
    for (final String name : additionalHeaders.keySet()) {
    okHttpRequestBuilder.addHeader(name, additionalHeaders.get(name));
    }

    setConnectionParametersForRequest(okHttpRequestBuilder, request);

    com.squareup.okhttp.Request okHttpRequest = okHttpRequestBuilder.build();
    Call okHttpCall = client.newCall(okHttpRequest);
    Response okHttpResponse = okHttpCall.execute();

    StatusLine responseStatus = new BasicStatusLine(parseProtocol(okHttpResponse.protocol()), okHttpResponse.code(), okHttpResponse.message());
    BasicHttpResponse response = new BasicHttpResponse(responseStatus);
    response.setEntity(entityFromOkHttpResponse(okHttpResponse));

    Headers responseHeaders = okHttpResponse.headers();
    for (int i = 0, len = responseHeaders.size(); i < len; i++) {
    final String name = responseHeaders.name(i), value = responseHeaders.value(i);
    if (name != null) {
    response.addHeader(new BasicHeader(name, value));
    }
    }

    return response;
    }

    private static HttpEntity entityFromOkHttpResponse(Response r) throws IOException {
    BasicHttpEntity entity = new BasicHttpEntity();
    ResponseBody body = r.body();

    entity.setContent(body.byteStream());
    entity.setContentLength(body.contentLength());
    entity.setContentEncoding(r.header("Content-Encoding"));

    entity.setContentType(body.contentType().type());
    return entity;
    }

    @SuppressWarnings("deprecation")
    private static void setConnectionParametersForRequest(com.squareup.okhttp.Request.Builder builder, Request<?> request)
    throws IOException, AuthFailureError {
    switch (request.getMethod()) {
    case Request.Method.DEPRECATED_GET_OR_POST:
    // Ensure backwards compatibility. Volley assumes a request with a null body is a GET.
    byte[] postBody = request.getPostBody();
    if (postBody != null) {
    builder.post(RequestBody.create(MediaType.parse(request.getPostBodyContentType()), postBody));
    }
    break;
    case Request.Method.GET:
    builder.get();
    break;
    case Request.Method.DELETE:
    builder.delete();
    break;
    case Request.Method.POST:
    builder.post(createRequestBody(request));
    break;
    case Request.Method.PUT:
    builder.put(createRequestBody(request));
    break;
    case Request.Method.HEAD:
    builder.head();
    break;
    case Request.Method.OPTIONS:
    builder.method("OPTIONS", null);
    break;
    case Request.Method.TRACE:
    builder.method("TRACE", null);
    break;
    case Request.Method.PATCH:
    builder.patch(createRequestBody(request));
    break;
    default:
    throw new IllegalStateException("Unknown method type.");
    }
    }

    private static ProtocolVersion parseProtocol(final Protocol p) {
    switch (p) {
    case HTTP_1_0:
    return new ProtocolVersion("HTTP", 1, 0);
    case HTTP_1_1:
    return new ProtocolVersion("HTTP", 1, 1);
    case SPDY_3:
    return new ProtocolVersion("SPDY", 3, 1);
    case HTTP_2:
    return new ProtocolVersion("HTTP", 2, 0);
    }

    throw new IllegalAccessError("Unkwown protocol");
    }

    private static RequestBody createRequestBody(Request r) throws AuthFailureError {
    final byte[] body = r.getBody();
    if (body == null) return null;

    return RequestBody.create(MediaType.parse(r.getBodyContentType()), body);
    }
    }