package fast.rocket.http; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.NameValuePair; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpDelete; import org.apache.http.client.methods.HttpEntityEnclosingRequestBase; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPut; import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.cookie.Cookie; import org.apache.http.entity.ByteArrayEntity; import org.apache.http.impl.client.AbstractHttpClient; import org.apache.http.message.BasicNameValuePair; import org.apache.http.params.HttpConnectionParams; import org.apache.http.params.HttpParams; import android.text.TextUtils; import fast.rocket.error.AuthFailureError; import fast.rocket.request.Request; import fast.rocket.request.Request.Method; import fast.rocket.request.filecore.FilePart; import fast.rocket.request.filecore.MultiPartRequest; import fast.rocket.request.filecore.MultipartEntity; import fast.rocket.request.filecore.StringPart; import fast.rocket.request.filecore.MultiPartRequest.MultiPartParam; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Map; /** * An HttpStack that performs request over an {@link HttpClient}. */ public class HttpClientStack implements HttpStack { protected final HttpClient mClient; private final static String HEADER_CONTENT_TYPE = "Content-Type"; public HttpClientStack(HttpClient client) { mClient = client; } private static void addHeaders(HttpUriRequest httpRequest, Map<String, String> headers) { for (String key : headers.keySet()) { httpRequest.setHeader(key, headers.get(key)); } } @SuppressWarnings("unused") private static List<NameValuePair> getPostParameterPairs(Map<String, String> postParams) { List<NameValuePair> result = new ArrayList<NameValuePair>(postParams.size()); for (String key : postParams.keySet()) { result.add(new BasicNameValuePair(key, postParams.get(key))); } return result; } @Override public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders) throws IOException, AuthFailureError { HttpUriRequest httpRequest = createHttpRequest(request, additionalHeaders); addHeaders(httpRequest, additionalHeaders); addHeaders(httpRequest, request.getHeaders()); onPrepareRequest(httpRequest); HttpParams httpParams = httpRequest.getParams(); int timeoutMs = request.getTimeoutMs(); // Reevaluate this connection timeout based on more wide-scale // data collection and possibly different for wifi vs. 3G. HttpConnectionParams.setConnectionTimeout(httpParams, 5000); HttpConnectionParams.setSoTimeout(httpParams, timeoutMs); if (request.isCookieEnabled()) { setCookie(mClient); } return mClient.execute(httpRequest); } /** * Creates the appropriate subclass of HttpUriRequest for passed in request. */ @SuppressWarnings("deprecation") /* protected */ static HttpUriRequest createHttpRequest(Request<?> request, Map<String, String> additionalHeaders) throws AuthFailureError, IOException { final String requestUrl = request.getUrl(); switch (request.getMethod()) { case Method.DEPRECATED_GET_OR_POST: { // This is the deprecated way that needs to be handled for backwards compatibility. // If the request's post body is null, then the assumption is that the request is // GET. Otherwise, it is assumed that the request is a POST. byte[] postBody = request.getPostBody(); if (postBody != null) { HttpPost postRequest = new HttpPost(requestUrl); postRequest.addHeader(HEADER_CONTENT_TYPE, request.getPostBodyContentType()); HttpEntity entity; entity = new ByteArrayEntity(postBody); postRequest.setEntity(entity); return postRequest; } else { return new HttpGet(requestUrl); } } case Method.GET: request.setSSLRequest(requestUrl.startsWith("https")); return new HttpGet(requestUrl); case Method.DELETE: return new HttpDelete(requestUrl); case Method.POST: { request.setSSLRequest(requestUrl.startsWith("https")); HttpPost postRequest = new HttpPost(requestUrl); postRequest.addHeader(HEADER_CONTENT_TYPE, request.getBodyContentType()); setEntityIfNonEmptyBody(postRequest, request); return postRequest; } case Method.PUT: { HttpPut putRequest = new HttpPut(requestUrl); putRequest.addHeader(HEADER_CONTENT_TYPE, request.getBodyContentType()); setEntityIfNonEmptyBody(putRequest, request); return putRequest; } default: throw new IllegalStateException("Unknown request method."); } } private static void setEntityIfNonEmptyBody(HttpEntityEnclosingRequestBase httpRequest, Request<?> request) throws IOException, AuthFailureError { if (request instanceof MultiPartRequest) { final Map<String, MultiPartParam> multipartParams = ((MultiPartRequest<?>) request).getMultipartParams(); final Map<String, String> filesToUpload = ((MultiPartRequest<?>) request).getFilesToUpload(); MultipartEntity multipartEntity = new MultipartEntity(); for (String key : multipartParams.keySet()) { multipartEntity.addPart(new StringPart(key, multipartParams.get(key).value)); } for (String key : filesToUpload.keySet()) { File file = new File(filesToUpload.get(key)); if(!file.exists()) { throw new IOException(String.format("File not found: %s", file.getAbsolutePath())); } if(file.isDirectory()) { throw new IOException(String.format("File is a directory: %s", file.getAbsolutePath())); } multipartEntity.addPart(new FilePart(key, file, null, null)); } httpRequest.setEntity(multipartEntity); } else { byte[] body = request.getBody(); if (body != null) { HttpEntity entity = new ByteArrayEntity(body); httpRequest.setEntity(entity); } } } /** * Called before the request is executed using the underlying HttpClient. * * <p>Overwrite in subclasses to augment the request.</p> */ protected void onPrepareRequest(HttpUriRequest request) throws IOException { // Nothing. } private String setCookie(HttpClient httpClient) { List<Cookie> cookies = ((AbstractHttpClient) httpClient).getCookieStore().getCookies(); StringBuilder sb = new StringBuilder(); final int size = cookies.size(); for (int i = 0; i < size; i++) { Cookie cookie = cookies.get(i); String cookieName = cookie.getName(); String cookieValue = cookie.getValue(); if (!TextUtils.isEmpty(cookieName) && !TextUtils.isEmpty(cookieValue)) { sb.append(cookieName + "=" ); sb.append(cookieValue + ";" ); } } return sb.toString(); } }