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