1 // Copyright 2013 Square, Inc. 2 package com.squareup.okhttp.apache; 3 4 import com.squareup.okhttp.Headers; 5 import com.squareup.okhttp.OkHttpClient; 6 import com.squareup.okhttp.Request; 7 import com.squareup.okhttp.RequestBody; 8 import com.squareup.okhttp.Response; 9 import com.squareup.okhttp.ResponseBody; 10 import java.io.IOException; 11 import java.net.InetSocketAddress; 12 import java.net.Proxy; 13 import org.apache.http.Header; 14 import org.apache.http.HttpEntity; 15 import org.apache.http.HttpEntityEnclosingRequest; 16 import org.apache.http.HttpHost; 17 import org.apache.http.HttpRequest; 18 import org.apache.http.HttpResponse; 19 import org.apache.http.RequestLine; 20 import org.apache.http.client.HttpClient; 21 import org.apache.http.client.ResponseHandler; 22 import org.apache.http.client.methods.HttpUriRequest; 23 import org.apache.http.conn.ClientConnectionManager; 24 import org.apache.http.conn.params.ConnRouteParams; 25 import org.apache.http.entity.InputStreamEntity; 26 import org.apache.http.message.BasicHttpResponse; 27 import org.apache.http.params.AbstractHttpParams; 28 import org.apache.http.params.HttpParams; 29 import org.apache.http.protocol.HttpContext; 30 31 import static java.net.Proxy.Type.HTTP; 32 import static org.apache.http.HttpVersion.HTTP_1_1; 33 34 /** 35 * Implements Apache's {@link HttpClient} API using {@link OkHttpClient}. 36 * <p> 37 * <strong>Warning:</strong> Many core features of Apache HTTP client are not implemented by this 38 * API. This includes the keep-alive strategy, cookie store, credentials provider, route planner 39 * and others. 40 */ 41 public final class OkApacheClient implements HttpClient { 42 private static Request transformRequest(HttpRequest request) { 43 Request.Builder builder = new Request.Builder(); 44 45 RequestLine requestLine = request.getRequestLine(); 46 String method = requestLine.getMethod(); 47 builder.url(requestLine.getUri()); 48 49 String contentType = null; 50 for (Header header : request.getAllHeaders()) { 51 String name = header.getName(); 52 if ("Content-Type".equalsIgnoreCase(name)) { 53 contentType = header.getValue(); 54 } else { 55 builder.header(name, header.getValue()); 56 } 57 } 58 59 RequestBody body = null; 60 if (request instanceof HttpEntityEnclosingRequest) { 61 HttpEntity entity = ((HttpEntityEnclosingRequest) request).getEntity(); 62 if (entity != null) { 63 // Wrap the entity in a custom Body which takes care of the content, length, and type. 64 body = new HttpEntityBody(entity, contentType); 65 66 Header encoding = entity.getContentEncoding(); 67 if (encoding != null) { 68 builder.header(encoding.getName(), encoding.getValue()); 69 } 70 } else { 71 body = RequestBody.create(null, new byte[0]); 72 } 73 } 74 builder.method(method, body); 75 76 return builder.build(); 77 } 78 79 private static HttpResponse transformResponse(Response response) throws IOException { 80 int code = response.code(); 81 String message = response.message(); 82 BasicHttpResponse httpResponse = new BasicHttpResponse(HTTP_1_1, code, message); 83 84 ResponseBody body = response.body(); 85 InputStreamEntity entity = new InputStreamEntity(body.byteStream(), body.contentLength()); 86 httpResponse.setEntity(entity); 87 88 Headers headers = response.headers(); 89 for (int i = 0, size = headers.size(); i < size; i++) { 90 String name = headers.name(i); 91 String value = headers.value(i); 92 httpResponse.addHeader(name, value); 93 if ("Content-Type".equalsIgnoreCase(name)) { 94 entity.setContentType(value); 95 } else if ("Content-Encoding".equalsIgnoreCase(name)) { 96 entity.setContentEncoding(value); 97 } 98 } 99 100 return httpResponse; 101 } 102 103 private final HttpParams params = new AbstractHttpParams() { 104 @Override public Object getParameter(String name) { 105 if (name.equals(ConnRouteParams.DEFAULT_PROXY)) { 106 Proxy proxy = client.getProxy(); 107 if (proxy == null) { 108 return null; 109 } 110 InetSocketAddress address = (InetSocketAddress) proxy.address(); 111 return new HttpHost(address.getHostName(), address.getPort()); 112 } 113 throw new IllegalArgumentException(name); 114 } 115 116 @Override public HttpParams setParameter(String name, Object value) { 117 if (name.equals(ConnRouteParams.DEFAULT_PROXY)) { 118 HttpHost host = (HttpHost) value; 119 Proxy proxy = null; 120 if (host != null) { 121 proxy = new Proxy(HTTP, new InetSocketAddress(host.getHostName(), host.getPort())); 122 } 123 client.setProxy(proxy); 124 return this; 125 } 126 throw new IllegalArgumentException(name); 127 } 128 129 @Override public HttpParams copy() { 130 throw new UnsupportedOperationException(); 131 } 132 133 @Override public boolean removeParameter(String name) { 134 throw new UnsupportedOperationException(); 135 } 136 }; 137 138 private final OkHttpClient client; 139 140 public OkApacheClient() { 141 this(new OkHttpClient()); 142 } 143 144 public OkApacheClient(OkHttpClient client) { 145 this.client = client; 146 } 147 148 @Override public HttpParams getParams() { 149 return params; 150 } 151 152 @Override public ClientConnectionManager getConnectionManager() { 153 throw new UnsupportedOperationException(); 154 } 155 156 @Override public HttpResponse execute(HttpUriRequest request) throws IOException { 157 return execute(null, request, (HttpContext) null); 158 } 159 160 @Override public HttpResponse execute(HttpUriRequest request, HttpContext context) 161 throws IOException { 162 return execute(null, request, context); 163 } 164 165 @Override public HttpResponse execute(HttpHost host, HttpRequest request) throws IOException { 166 return execute(host, request, (HttpContext) null); 167 } 168 169 @Override public HttpResponse execute(HttpHost host, HttpRequest request, HttpContext context) 170 throws IOException { 171 Request okRequest = transformRequest(request); 172 Response okResponse = client.newCall(okRequest).execute(); 173 return transformResponse(okResponse); 174 } 175 176 @Override public <T> T execute(HttpUriRequest request, ResponseHandler<? extends T> handler) 177 throws IOException { 178 return execute(null, request, handler, null); 179 } 180 181 @Override public <T> T execute(HttpUriRequest request, ResponseHandler<? extends T> handler, 182 HttpContext context) throws IOException { 183 return execute(null, request, handler, context); 184 } 185 186 @Override public <T> T execute(HttpHost host, HttpRequest request, 187 ResponseHandler<? extends T> handler) throws IOException { 188 return execute(host, request, handler, null); 189 } 190 191 @Override public <T> T execute(HttpHost host, HttpRequest request, 192 ResponseHandler<? extends T> handler, HttpContext context) throws IOException { 193 HttpResponse response = execute(host, request, context); 194 try { 195 return handler.handleResponse(response); 196 } finally { 197 consumeContentQuietly(response); 198 } 199 } 200 201 private static void consumeContentQuietly(HttpResponse response) { 202 try { 203 response.getEntity().consumeContent(); 204 } catch (Throwable ignored) { 205 } 206 } 207 } 208