Skip to content

Instantly share code, notes, and snippets.

@LOG-TAG
Created July 25, 2014 07:55
Show Gist options
  • Save LOG-TAG/d0419bc2207f1a7ec444 to your computer and use it in GitHub Desktop.
Save LOG-TAG/d0419bc2207f1a7ec444 to your computer and use it in GitHub Desktop.
/*
* Copyright 2013-2014 KdSoft
*
* 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.kd.lib.droid.net;
import com.android.volley.AuthFailureError;
import com.android.volley.Request;
import com.android.volley.toolbox.HttpStack;
import com.kd.lib.droid.ErrorHandler;
import com.squareup.okhttp.Cache;
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.File;
import java.io.IOException;
import java.net.URL;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import kr.co.kdsoft.droidlib.GlobalContextApplication;
/**
* Class to integrate volley with okhttp
*
* @author ceram1
* @see com.android.volley.toolbox.Volley
* @see com.squareup.okhttp.OkHttpClient
* @since 1.0.05
*/
public class OkHttpStack implements HttpStack {
/**
* Directory to save cache
*/
private static final File CACHE_DIR = GlobalContextApplication.getContext().getCacheDir();
private final OkHttpClient client = new OkHttpClient();
private OkHttpClient mClient;
public OkHttpStack() {
client.setFollowSslRedirects(true);// Allow http -> https redirect and https -> http redirect
try {
client.setCache(new Cache(new File(CACHE_DIR, "http_okhttp"), 10 * 1024 * 1024));
} catch (IOException e) {
ErrorHandler.handle(e);// Handle with errorhandler
}
}
@Override
public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)
throws IOException, AuthFailureError {
final String url = request.getUrl();
final com.squareup.okhttp.Request.Builder okHttpRequestBuilder = new com.squareup.okhttp.Request.Builder();
URL parsedUrl = new URL(url);
int timeoutMs = request.getTimeoutMs();
client.setConnectTimeout(timeoutMs, TimeUnit.MILLISECONDS);// OkHttp-UrlConnection -> setConnectionTimeout(long)
client.setReadTimeout(timeoutMs, TimeUnit.MILLISECONDS);// OkHttp-UrlConnection -> setReadTimeout(long)
final 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);
final com.squareup.okhttp.Request okHttpRequest = okHttpRequestBuilder.build();
final Call okHttpCall = client.newCall(okHttpRequest);
final Response okHttpResponse = okHttpCall.execute();
final int responseCode = okHttpResponse.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.");
}
final Protocol protocol = okHttpResponse.protocol();
StatusLine responseStatus = new BasicStatusLine(parseProtocol(protocol), okHttpResponse.code(), okHttpResponse.message());
BasicHttpResponse response = new BasicHttpResponse(responseStatus);
response.setEntity(entityFromOkHttpResponse(okHttpResponse));
final 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) {
final BasicHttpEntity entity = new BasicHttpEntity();
final ResponseBody body = r.body();
entity.setContent(body.byteStream());
entity.setContentLength(body.contentLength());
entity.setContentEncoding(r.header("Content-Encoding"));// Default action for UrlConnection
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:
// This is the deprecated way that needs to be handled for backwards compatibility.
// If the request's post body is null, then the assumption is that the request is
// GET. Otherwise, it is assumed that the request is a POST.
byte[] postBody = request.getPostBody();
if (postBody != null) {
// Prepare output. There is no need to set Content-Length explicitly,
// since this is handled by HttpURLConnection using the size of the prepared
// output stream.
builder.post(RequestBody.create(MediaType.parse(request.getPostBodyContentType()), postBody));
}
break;
case Request.Method.GET:
// Not necessary to set the request method because connection defaults to GET but
// being explicit here.
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 final 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);//TODO Check volley implementation because I'm not sure if this is okay.
case HTTP_2:
return new ProtocolVersion("HTTP", 2, 0);
}
throw new IllegalAccessError("Unkwown protocol");
}
private static final RequestBody createRequestBody(Request r) throws AuthFailureError {
final byte[] body = r.getBody();
if (body == null) return null;
return RequestBody.create(MediaType.parse(r.getBodyContentType()), body);
}
public OkHttpClient getClient() {
return mClient;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment