2 * Copyright (C) 2008 ZXing authors
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package com.google.zxing.client.android;
19 import org.apache.http.Header;
20 import org.apache.http.HttpEntity;
21 import org.apache.http.HttpHost;
22 import org.apache.http.HttpMessage;
23 import org.apache.http.HttpRequest;
24 import org.apache.http.HttpRequestInterceptor;
25 import org.apache.http.HttpResponse;
26 import org.apache.http.client.HttpClient;
27 import org.apache.http.client.ResponseHandler;
28 import org.apache.http.client.methods.HttpUriRequest;
29 import org.apache.http.client.params.HttpClientParams;
30 import org.apache.http.client.protocol.ClientContext;
31 import org.apache.http.conn.ClientConnectionManager;
32 import org.apache.http.conn.scheme.PlainSocketFactory;
33 import org.apache.http.conn.scheme.Scheme;
34 import org.apache.http.conn.scheme.SchemeRegistry;
35 import org.apache.http.conn.ssl.SSLSocketFactory;
36 import org.apache.http.entity.AbstractHttpEntity;
37 import org.apache.http.entity.ByteArrayEntity;
38 import org.apache.http.impl.client.DefaultHttpClient;
39 import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
40 import org.apache.http.params.BasicHttpParams;
41 import org.apache.http.params.HttpConnectionParams;
42 import org.apache.http.params.HttpParams;
43 import org.apache.http.params.HttpProtocolParams;
44 import org.apache.http.protocol.BasicHttpContext;
45 import org.apache.http.protocol.BasicHttpProcessor;
46 import org.apache.http.protocol.HttpContext;
48 import java.io.ByteArrayOutputStream;
49 import java.io.IOException;
50 import java.io.InputStream;
51 import java.io.OutputStream;
52 import java.util.zip.GZIPInputStream;
53 import java.util.zip.GZIPOutputStream;
56 * <p>Subclass of the Apache {@link DefaultHttpClient} that is configured with
57 * reasonable default settings and registered schemes for Android, and
58 * also lets the user add {@link HttpRequestInterceptor} classes.
59 * Don't create this directly, use the {@link #newInstance} factory method.</p>
61 * <p>This client processes cookies but does not retain them by default.
62 * To retain cookies, simply add a cookie store to the HttpContext:
63 * <pre>context.setAttribute(ClientContext.COOKIE_STORE, cookieStore);</pre>
66 public final class AndroidHttpClient implements HttpClient {
68 // Gzip of data shorter than this probably won't be worthwhile
69 private static final long DEFAULT_SYNC_MIN_GZIP_BYTES = 256;
72 * Set if HTTP requests are blocked from being executed on this thread
74 private static final ThreadLocal<Boolean> sThreadBlocked =
75 new ThreadLocal<Boolean>();
78 * Interceptor throws an exception if the executing thread is blocked
80 private static final HttpRequestInterceptor sThreadCheckInterceptor =
81 new HttpRequestInterceptor() {
82 public void process(HttpRequest request, HttpContext context) {
83 if (sThreadBlocked.get() != null && sThreadBlocked.get()) {
84 throw new RuntimeException("This thread forbids HTTP requests");
90 * Create a new HttpClient with reasonable defaults (which you can update).
92 * @param userAgent to report in your HTTP requests.
93 * @return AndroidHttpClient for you to use for all your requests.
95 public static AndroidHttpClient newInstance(String userAgent) {
96 HttpParams params = new BasicHttpParams();
98 // Turn off stale checking. Our connections break all the time anyway,
99 // and it's not worth it to pay the penalty of checking every time.
100 HttpConnectionParams.setStaleCheckingEnabled(params, false);
102 // Default connection and socket timeout of 20 seconds. Tweak to taste.
103 HttpConnectionParams.setConnectionTimeout(params, 20 * 1000);
104 HttpConnectionParams.setSoTimeout(params, 20 * 1000);
105 HttpConnectionParams.setSocketBufferSize(params, 8192);
107 // Don't handle redirects -- return them to the caller. Our code
108 // often wants to re-POST after a redirect, which we must do ourselves.
109 HttpClientParams.setRedirecting(params, false);
111 // Set the specified user agent and register standard protocols.
112 HttpProtocolParams.setUserAgent(params, userAgent);
113 SchemeRegistry schemeRegistry = new SchemeRegistry();
114 schemeRegistry.register(new Scheme("http",
115 PlainSocketFactory.getSocketFactory(), 80));
116 schemeRegistry.register(new Scheme("https",
117 SSLSocketFactory.getSocketFactory(), 443));
118 ClientConnectionManager manager =
119 new ThreadSafeClientConnManager(params, schemeRegistry);
121 // We use a factory method to modify superclass initialization
122 // parameters without the funny call-a-static-method dance.
123 return new AndroidHttpClient(manager, params);
126 private final HttpClient delegate;
129 private AndroidHttpClient(ClientConnectionManager ccm, HttpParams params) {
130 this.delegate = new DefaultHttpClient(ccm, params) {
132 protected BasicHttpProcessor createHttpProcessor() {
133 // Add interceptor to prevent making requests from main thread.
134 BasicHttpProcessor processor = super.createHttpProcessor();
135 processor.addRequestInterceptor(sThreadCheckInterceptor);
140 protected HttpContext createHttpContext() {
141 // Same as DefaultHttpClient.createHttpContext() minus the
143 HttpContext context = new BasicHttpContext();
144 context.setAttribute(ClientContext.AUTHSCHEME_REGISTRY, getAuthSchemes());
145 context.setAttribute(ClientContext.COOKIESPEC_REGISTRY, getCookieSpecs());
146 context.setAttribute(ClientContext.CREDS_PROVIDER, getCredentialsProvider());
153 * Block this thread from executing HTTP requests.
154 * Used to guard against HTTP requests blocking the main application thread.
156 * @param blocked if HTTP requests run on this thread should be denied
158 public static void setThreadBlocked(boolean blocked) {
159 sThreadBlocked.set(blocked);
163 * Modifies a request to indicate to the server that we would like a
164 * gzipped response. (Uses the "Accept-Encoding" HTTP header.)
166 * @param request the request to modify
167 * @see #getUngzippedContent
169 public static void modifyRequestToAcceptGzipResponse(HttpMessage request) {
170 request.addHeader("Accept-Encoding", "gzip");
174 * Gets the input stream from a response entity. If the entity is gzipped
175 * then this will get a stream over the uncompressed data.
177 * @param entity the entity whose content should be read
178 * @return the input stream to read from
179 * @throws IOException
181 public static InputStream getUngzippedContent(HttpEntity entity) throws IOException {
182 InputStream responseStream = entity.getContent();
183 if (responseStream == null) {
184 return responseStream;
186 Header header = entity.getContentEncoding();
187 if (header == null) {
188 return responseStream;
190 String contentEncoding = header.getValue();
191 if (contentEncoding == null) {
192 return responseStream;
194 if (contentEncoding.contains("gzip")) {
195 responseStream = new GZIPInputStream(responseStream);
197 return responseStream;
200 public void close() {
204 public HttpParams getParams() {
205 return delegate.getParams();
208 public ClientConnectionManager getConnectionManager() {
209 return delegate.getConnectionManager();
212 public HttpResponse execute(HttpUriRequest request) throws IOException {
213 return delegate.execute(request);
216 public HttpResponse execute(HttpUriRequest request, HttpContext context) throws IOException {
217 return delegate.execute(request, context);
220 public HttpResponse execute(HttpHost target, HttpRequest request) throws IOException {
221 return delegate.execute(target, request);
224 public HttpResponse execute(HttpHost target, HttpRequest request,
225 HttpContext context) throws IOException {
226 return delegate.execute(target, request, context);
229 public <T> T execute(HttpUriRequest request, ResponseHandler<? extends T> responseHandler) throws IOException {
230 return delegate.execute(request, responseHandler);
233 public <T> T execute(HttpUriRequest request, ResponseHandler<? extends T> responseHandler, HttpContext context)
235 return delegate.execute(request, responseHandler, context);
238 public <T> T execute(HttpHost target, HttpRequest request, ResponseHandler<? extends T> responseHandler)
240 return delegate.execute(target, request, responseHandler);
243 public <T> T execute(HttpHost target, HttpRequest request,
244 ResponseHandler<? extends T> responseHandler,
247 return delegate.execute(target, request, responseHandler, context);
251 * Compress data to send to server.
252 * Creates a Http Entity holding the gzipped data.
253 * The data will not be compressed if it is too short.
255 * @param data The bytes to compress
256 * @return Entity holding the data
258 public static AbstractHttpEntity getCompressedEntity(byte[] data) throws IOException {
259 AbstractHttpEntity entity;
260 if (data.length < DEFAULT_SYNC_MIN_GZIP_BYTES) {
261 entity = new ByteArrayEntity(data);
263 ByteArrayOutputStream arr = new ByteArrayOutputStream();
264 OutputStream zipper = new GZIPOutputStream(arr);
270 entity = new ByteArrayEntity(arr.toByteArray());
271 entity.setContentEncoding("gzip");