1d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru/* 2d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * Copyright (C) 2011 The Android Open Source Project 3d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * 4d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * Licensed under the Apache License, Version 2.0 (the "License"); 5d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * you may not use this file except in compliance with the License. 6d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * You may obtain a copy of the License at 7d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * 8d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * http://www.apache.org/licenses/LICENSE-2.0 9d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * 10d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * Unless required by applicable law or agreed to in writing, software 11d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * distributed under the License is distributed on an "AS IS" BASIS, 12d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * See the License for the specific language governing permissions and 14d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * limitations under the License. 15d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru */ 16d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 17d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Querupackage com.android.volley.toolbox; 18d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 19d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport com.android.volley.AuthFailureError; 20d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport com.android.volley.Request; 21e48f4430bfd3030350aa5ba827b449c37e2fadc9Jean-Baptiste Queruimport com.android.volley.Request.Method; 22d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 23d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport org.apache.http.HttpEntity; 24d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport org.apache.http.HttpResponse; 25d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport org.apache.http.NameValuePair; 26d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport org.apache.http.client.HttpClient; 27e48f4430bfd3030350aa5ba827b449c37e2fadc9Jean-Baptiste Queruimport org.apache.http.client.methods.HttpDelete; 28e48f4430bfd3030350aa5ba827b449c37e2fadc9Jean-Baptiste Queruimport org.apache.http.client.methods.HttpEntityEnclosingRequestBase; 29d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport org.apache.http.client.methods.HttpGet; 30d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport org.apache.http.client.methods.HttpPost; 31e48f4430bfd3030350aa5ba827b449c37e2fadc9Jean-Baptiste Queruimport org.apache.http.client.methods.HttpPut; 32d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport org.apache.http.client.methods.HttpUriRequest; 33d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport org.apache.http.entity.ByteArrayEntity; 34d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport org.apache.http.message.BasicNameValuePair; 35d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport org.apache.http.params.HttpConnectionParams; 36d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport org.apache.http.params.HttpParams; 37d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 38d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport java.io.IOException; 39d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport java.util.ArrayList; 40d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport java.util.List; 41d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport java.util.Map; 42d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 43d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru/** 44d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * An HttpStack that performs request over an {@link HttpClient}. 45d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru */ 46d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Querupublic class HttpClientStack implements HttpStack { 47d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru protected final HttpClient mClient; 48d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 49e48f4430bfd3030350aa5ba827b449c37e2fadc9Jean-Baptiste Queru private final static String HEADER_CONTENT_TYPE = "Content-Type"; 50e48f4430bfd3030350aa5ba827b449c37e2fadc9Jean-Baptiste Queru 51d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru public HttpClientStack(HttpClient client) { 52d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru mClient = client; 53d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 54d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 55d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru private static void addHeaders(HttpUriRequest httpRequest, Map<String, String> headers) { 56d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru for (String key : headers.keySet()) { 57d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru httpRequest.setHeader(key, headers.get(key)); 58d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 59d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 60d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 61d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru @SuppressWarnings("unused") 62d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru private static List<NameValuePair> getPostParameterPairs(Map<String, String> postParams) { 63d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru List<NameValuePair> result = new ArrayList<NameValuePair>(postParams.size()); 64d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru for (String key : postParams.keySet()) { 65d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru result.add(new BasicNameValuePair(key, postParams.get(key))); 66d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 67d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru return result; 68d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 69d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 70d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru @Override 71d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders) 72d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru throws IOException, AuthFailureError { 73e48f4430bfd3030350aa5ba827b449c37e2fadc9Jean-Baptiste Queru HttpUriRequest httpRequest = createHttpRequest(request, additionalHeaders); 74d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru addHeaders(httpRequest, additionalHeaders); 75d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru addHeaders(httpRequest, request.getHeaders()); 76d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru onPrepareRequest(httpRequest); 77d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru HttpParams httpParams = httpRequest.getParams(); 78d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru int timeoutMs = request.getTimeoutMs(); 79d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru // TODO: Reevaluate this connection timeout based on more wide-scale 80d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru // data collection and possibly different for wifi vs. 3G. 81d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru HttpConnectionParams.setConnectionTimeout(httpParams, 5000); 82d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru HttpConnectionParams.setSoTimeout(httpParams, timeoutMs); 83d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru return mClient.execute(httpRequest); 84d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 85d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 86d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru /** 87e48f4430bfd3030350aa5ba827b449c37e2fadc9Jean-Baptiste Queru * Creates the appropriate subclass of HttpUriRequest for passed in request. 88e48f4430bfd3030350aa5ba827b449c37e2fadc9Jean-Baptiste Queru */ 89e48f4430bfd3030350aa5ba827b449c37e2fadc9Jean-Baptiste Queru @SuppressWarnings("deprecation") 90e48f4430bfd3030350aa5ba827b449c37e2fadc9Jean-Baptiste Queru /* protected */ static HttpUriRequest createHttpRequest(Request<?> request, 91e48f4430bfd3030350aa5ba827b449c37e2fadc9Jean-Baptiste Queru Map<String, String> additionalHeaders) throws AuthFailureError { 92e48f4430bfd3030350aa5ba827b449c37e2fadc9Jean-Baptiste Queru switch (request.getMethod()) { 93e48f4430bfd3030350aa5ba827b449c37e2fadc9Jean-Baptiste Queru case Method.DEPRECATED_GET_OR_POST: { 94e48f4430bfd3030350aa5ba827b449c37e2fadc9Jean-Baptiste Queru // This is the deprecated way that needs to be handled for backwards compatibility. 95e48f4430bfd3030350aa5ba827b449c37e2fadc9Jean-Baptiste Queru // If the request's post body is null, then the assumption is that the request is 96e48f4430bfd3030350aa5ba827b449c37e2fadc9Jean-Baptiste Queru // GET. Otherwise, it is assumed that the request is a POST. 97e48f4430bfd3030350aa5ba827b449c37e2fadc9Jean-Baptiste Queru byte[] postBody = request.getPostBody(); 98e48f4430bfd3030350aa5ba827b449c37e2fadc9Jean-Baptiste Queru if (postBody != null) { 99e48f4430bfd3030350aa5ba827b449c37e2fadc9Jean-Baptiste Queru HttpPost postRequest = new HttpPost(request.getUrl()); 100e48f4430bfd3030350aa5ba827b449c37e2fadc9Jean-Baptiste Queru postRequest.addHeader(HEADER_CONTENT_TYPE, request.getPostBodyContentType()); 101e48f4430bfd3030350aa5ba827b449c37e2fadc9Jean-Baptiste Queru HttpEntity entity; 102e48f4430bfd3030350aa5ba827b449c37e2fadc9Jean-Baptiste Queru entity = new ByteArrayEntity(postBody); 103e48f4430bfd3030350aa5ba827b449c37e2fadc9Jean-Baptiste Queru postRequest.setEntity(entity); 104e48f4430bfd3030350aa5ba827b449c37e2fadc9Jean-Baptiste Queru return postRequest; 105e48f4430bfd3030350aa5ba827b449c37e2fadc9Jean-Baptiste Queru } else { 106e48f4430bfd3030350aa5ba827b449c37e2fadc9Jean-Baptiste Queru return new HttpGet(request.getUrl()); 107e48f4430bfd3030350aa5ba827b449c37e2fadc9Jean-Baptiste Queru } 108e48f4430bfd3030350aa5ba827b449c37e2fadc9Jean-Baptiste Queru } 109e48f4430bfd3030350aa5ba827b449c37e2fadc9Jean-Baptiste Queru case Method.GET: 110e48f4430bfd3030350aa5ba827b449c37e2fadc9Jean-Baptiste Queru return new HttpGet(request.getUrl()); 111e48f4430bfd3030350aa5ba827b449c37e2fadc9Jean-Baptiste Queru case Method.DELETE: 112e48f4430bfd3030350aa5ba827b449c37e2fadc9Jean-Baptiste Queru return new HttpDelete(request.getUrl()); 113e48f4430bfd3030350aa5ba827b449c37e2fadc9Jean-Baptiste Queru case Method.POST: { 114e48f4430bfd3030350aa5ba827b449c37e2fadc9Jean-Baptiste Queru HttpPost postRequest = new HttpPost(request.getUrl()); 115e48f4430bfd3030350aa5ba827b449c37e2fadc9Jean-Baptiste Queru postRequest.addHeader(HEADER_CONTENT_TYPE, request.getBodyContentType()); 116e48f4430bfd3030350aa5ba827b449c37e2fadc9Jean-Baptiste Queru setEntityIfNonEmptyBody(postRequest, request); 117e48f4430bfd3030350aa5ba827b449c37e2fadc9Jean-Baptiste Queru return postRequest; 118e48f4430bfd3030350aa5ba827b449c37e2fadc9Jean-Baptiste Queru } 119e48f4430bfd3030350aa5ba827b449c37e2fadc9Jean-Baptiste Queru case Method.PUT: { 120e48f4430bfd3030350aa5ba827b449c37e2fadc9Jean-Baptiste Queru HttpPut putRequest = new HttpPut(request.getUrl()); 121e48f4430bfd3030350aa5ba827b449c37e2fadc9Jean-Baptiste Queru putRequest.addHeader(HEADER_CONTENT_TYPE, request.getBodyContentType()); 122e48f4430bfd3030350aa5ba827b449c37e2fadc9Jean-Baptiste Queru setEntityIfNonEmptyBody(putRequest, request); 123e48f4430bfd3030350aa5ba827b449c37e2fadc9Jean-Baptiste Queru return putRequest; 124e48f4430bfd3030350aa5ba827b449c37e2fadc9Jean-Baptiste Queru } 125e48f4430bfd3030350aa5ba827b449c37e2fadc9Jean-Baptiste Queru default: 126e48f4430bfd3030350aa5ba827b449c37e2fadc9Jean-Baptiste Queru throw new IllegalStateException("Unknown request method."); 127e48f4430bfd3030350aa5ba827b449c37e2fadc9Jean-Baptiste Queru } 128e48f4430bfd3030350aa5ba827b449c37e2fadc9Jean-Baptiste Queru } 129e48f4430bfd3030350aa5ba827b449c37e2fadc9Jean-Baptiste Queru 130e48f4430bfd3030350aa5ba827b449c37e2fadc9Jean-Baptiste Queru private static void setEntityIfNonEmptyBody(HttpEntityEnclosingRequestBase httpRequest, 131e48f4430bfd3030350aa5ba827b449c37e2fadc9Jean-Baptiste Queru Request<?> request) throws AuthFailureError { 132e48f4430bfd3030350aa5ba827b449c37e2fadc9Jean-Baptiste Queru byte[] body = request.getBody(); 133e48f4430bfd3030350aa5ba827b449c37e2fadc9Jean-Baptiste Queru if (body != null) { 134e48f4430bfd3030350aa5ba827b449c37e2fadc9Jean-Baptiste Queru HttpEntity entity = new ByteArrayEntity(body); 135e48f4430bfd3030350aa5ba827b449c37e2fadc9Jean-Baptiste Queru httpRequest.setEntity(entity); 136e48f4430bfd3030350aa5ba827b449c37e2fadc9Jean-Baptiste Queru } 137e48f4430bfd3030350aa5ba827b449c37e2fadc9Jean-Baptiste Queru } 138e48f4430bfd3030350aa5ba827b449c37e2fadc9Jean-Baptiste Queru 139e48f4430bfd3030350aa5ba827b449c37e2fadc9Jean-Baptiste Queru /** 140d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * Called before the request is executed using the underlying HttpClient. 141d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * 142d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * <p>Overwrite in subclasses to augment the request.</p> 143d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru */ 144d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru protected void onPrepareRequest(HttpUriRequest request) throws IOException { 145d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru // Nothing. 146d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 147d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru} 148