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 } 71 } 72 builder.method(method, body); 73 74 return builder.build(); 75 } 76 77 private static HttpResponse transformResponse(Response response) throws IOException { 78 int code = response.code(); 79 String message = response.message(); 80 BasicHttpResponse httpResponse = new BasicHttpResponse(HTTP_1_1, code, message); 81 82 ResponseBody body = response.body(); 83 InputStreamEntity entity = new InputStreamEntity(body.byteStream(), body.contentLength()); 84 httpResponse.setEntity(entity); 85 86 Headers headers = response.headers(); 87 for (int i = 0, size = headers.size(); i < size; i++) { 88 String name = headers.name(i); 89 String value = headers.value(i); 90 httpResponse.addHeader(name, value); 91 if ("Content-Type".equalsIgnoreCase(name)) { 92 entity.setContentType(value); 93 } else if ("Content-Encoding".equalsIgnoreCase(name)) { 94 entity.setContentEncoding(value); 95 } 96 } 97 98 return httpResponse; 99 } 100 101 private final HttpParams params = new AbstractHttpParams() { 102 @Override public Object getParameter(String name) { 103 if (name.equals(ConnRouteParams.DEFAULT_PROXY)) { 104 Proxy proxy = client.getProxy(); 105 if (proxy == null) { 106 return null; 107 } 108 InetSocketAddress address = (InetSocketAddress) proxy.address(); 109 return new HttpHost(address.getHostName(), address.getPort()); 110 } 111 throw new IllegalArgumentException(name); 112 } 113 114 @Override public HttpParams setParameter(String name, Object value) { 115 if (name.equals(ConnRouteParams.DEFAULT_PROXY)) { 116 HttpHost host = (HttpHost) value; 117 Proxy proxy = null; 118 if (host != null) { 119 proxy = new Proxy(HTTP, new InetSocketAddress(host.getHostName(), host.getPort())); 120 } 121 client.setProxy(proxy); 122 return this; 123 } 124 throw new IllegalArgumentException(name); 125 } 126 127 @Override public HttpParams copy() { 128 throw new UnsupportedOperationException(); 129 } 130 131 @Override public boolean removeParameter(String name) { 132 throw new UnsupportedOperationException(); 133 } 134 }; 135 136 private final OkHttpClient client; 137 138 public OkApacheClient() { 139 this(new OkHttpClient()); 140 } 141 142 public OkApacheClient(OkHttpClient client) { 143 this.client = client; 144 } 145 146 @Override public HttpParams getParams() { 147 return params; 148 } 149 150 @Override public ClientConnectionManager getConnectionManager() { 151 throw new UnsupportedOperationException(); 152 } 153 154 @Override public HttpResponse execute(HttpUriRequest request) throws IOException { 155 return execute(null, request, (HttpContext) null); 156 } 157 158 @Override public HttpResponse execute(HttpUriRequest request, HttpContext context) 159 throws IOException { 160 return execute(null, request, context); 161 } 162 163 @Override public HttpResponse execute(HttpHost host, HttpRequest request) throws IOException { 164 return execute(host, request, (HttpContext) null); 165 } 166 167 @Override public HttpResponse execute(HttpHost host, HttpRequest request, HttpContext context) 168 throws IOException { 169 Request okRequest = transformRequest(request); 170 Response okResponse = client.newCall(okRequest).execute(); 171 return transformResponse(okResponse); 172 } 173 174 @Override public <T> T execute(HttpUriRequest request, ResponseHandler<? extends T> handler) 175 throws IOException { 176 return execute(null, request, handler, null); 177 } 178 179 @Override public <T> T execute(HttpUriRequest request, ResponseHandler<? extends T> handler, 180 HttpContext context) throws IOException { 181 return execute(null, request, handler, context); 182 } 183 184 @Override public <T> T execute(HttpHost host, HttpRequest request, 185 ResponseHandler<? extends T> handler) throws IOException { 186 return execute(host, request, handler, null); 187 } 188 189 @Override public <T> T execute(HttpHost host, HttpRequest request, 190 ResponseHandler<? extends T> handler, HttpContext context) throws IOException { 191 HttpResponse response = execute(host, request, context); 192 try { 193 return handler.handleResponse(response); 194 } finally { 195 consumeContentQuietly(response); 196 } 197 } 198 199 private static void consumeContentQuietly(HttpResponse response) { 200 try { 201 response.getEntity().consumeContent(); 202 } catch (Throwable ignored) { 203 } 204 } 205 } 206