/** * galaxy inc. * meetup client for android */ package com.galaxy.meetup.client.android.network.http; import java.io.FilterOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.URI; import java.net.URL; import java.util.Iterator; import java.util.zip.GZIPInputStream; import org.apache.http.Header; import org.apache.http.HeaderIterator; import org.apache.http.HttpEntity; import org.apache.http.HttpHost; import org.apache.http.HttpRequest; import org.apache.http.HttpRequestInterceptor; import org.apache.http.HttpResponse; import org.apache.http.HttpResponseInterceptor; import org.apache.http.client.HttpResponseException; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPut; import org.apache.http.client.methods.HttpRequestBase; import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.client.params.HttpClientParams; import org.apache.http.client.protocol.RequestAddCookies; import org.apache.http.client.protocol.ResponseProcessCookies; import org.apache.http.conn.ManagedClientConnection; import org.apache.http.conn.scheme.PlainSocketFactory; import org.apache.http.conn.scheme.Scheme; import org.apache.http.conn.scheme.SchemeRegistry; import org.apache.http.conn.ssl.SSLSocketFactory; import org.apache.http.cookie.Cookie; import org.apache.http.cookie.CookieOrigin; import org.apache.http.cookie.CookieSpec; import org.apache.http.cookie.CookieSpecRegistry; import org.apache.http.cookie.MalformedCookieException; import org.apache.http.entity.HttpEntityWrapper; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.impl.conn.SingleClientConnManager; import org.apache.http.params.BasicHttpParams; import org.apache.http.params.HttpParams; import org.apache.http.protocol.HttpContext; import android.os.StrictMode; import android.util.Log; import com.galaxy.meetup.client.android.network.NetworkException; import com.galaxy.meetup.client.util.EsLog; /** * * @author sihai * */ public class HttpTransaction implements HttpRequestInterceptor, HttpResponseInterceptor { private static final HttpParams sHttpParams; private static final SchemeRegistry sSupportedSchemes; private boolean mAborted; private final String url; private final MeetupRequest request; private final HttpRequestBase mHttpMethod; private final HttpTransactionListener mListener; private HttpTransactionMetrics mMetrics; static { sSupportedSchemes = new SchemeRegistry(); BasicHttpParams basichttpparams = new BasicHttpParams(); sHttpParams = basichttpparams; basichttpparams.setParameter("http.socket.timeout", Integer.valueOf(0x15f90)); sHttpParams.setParameter("http.connection.timeout", Integer.valueOf(3000)); sSupportedSchemes.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); sSupportedSchemes.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443)); } public HttpTransaction(String method, String url, HttpRequestConfiguration httprequestconfiguration, HttpTransactionListener httptransactionlistener) throws IOException { this(method, url, httprequestconfiguration, null, httptransactionlistener); } public HttpTransaction(String method, String url, HttpRequestConfiguration httprequestconfiguration, MeetupRequest request, HttpTransactionListener httptransactionlistener) throws IOException { this.url = url; if (method.equals("POST")) mHttpMethod = new HttpPost(url); else if (method.equals("PUT")) mHttpMethod = new HttpPut(url); else throw new NetworkException((new StringBuilder("Unsupported method: ")).append(method).toString()); if (httptransactionlistener == null) throw new NetworkException("The listener cannot be null"); mListener = httptransactionlistener; httprequestconfiguration.addHeaders(mHttpMethod); this.request = request; if (request != null) ((HttpPost) mHttpMethod).setEntity(request.toEntity()); } @Override public final void process(HttpRequest httprequest, HttpContext httpcontext) { CookieSpecRegistry cookiespecregistry = (CookieSpecRegistry)httpcontext.getAttribute("http.cookiespec-registry"); HttpHost httphost = (HttpHost)httpcontext.getAttribute("http.target_host"); ManagedClientConnection managedclientconnection = (ManagedClientConnection)httpcontext.getAttribute("http.connection"); String s = HttpClientParams.getCookiePolicy(httprequest.getParams()); URI uri = ((HttpUriRequest)httprequest).getURI(); String s1 = httphost.getHostName(); int i = httphost.getPort(); if(i < 0) i = managedclientconnection.getRemotePort(); CookieOrigin cookieorigin = new CookieOrigin(s1, i, uri.getPath(), managedclientconnection.isSecure()); httpcontext.setAttribute("http.cookie-spec", cookiespecregistry.getCookieSpec(s, httprequest.getParams())); httpcontext.setAttribute("http.cookie-origin", cookieorigin); if(mMetrics != null) mMetrics.setConnectionMetrics(managedclientconnection.getMetrics()); } @Override public final void process(HttpResponse httpresponse, HttpContext httpcontext) { CookieSpec cookiespec = (CookieSpec)httpcontext.getAttribute("http.cookie-spec"); CookieOrigin cookieorigin = (CookieOrigin)httpcontext.getAttribute("http.cookie-origin"); processCookies(httpresponse.headerIterator("Set-Cookie"), cookiespec, cookieorigin); if(cookiespec.getVersion() > 0) processCookies(httpresponse.headerIterator("Set-Cookie2"), cookiespec, cookieorigin); } public final void abort() { if(mAborted) { return; } if(null == mHttpMethod) { return; } if(android.os.Build.VERSION.SDK_INT < 9) { mHttpMethod.abort(); } else { StrictMode.ThreadPolicy threadpolicy = StrictMode.getThreadPolicy(); StrictMode.setThreadPolicy(android.os.StrictMode.ThreadPolicy.LAX); mHttpMethod.abort(); StrictMode.setThreadPolicy(threadpolicy); } } public final boolean isAborted() { boolean flag; if (mAborted) flag = true; else if (mHttpMethod != null) flag = mHttpMethod.isAborted(); else flag = false; return flag; } public final void onStartResultProcessing() { if(mMetrics != null) mMetrics.onStartResultProcessing(); } public final void setHttpTransactionMetrics(HttpTransactionMetrics httptransactionmetrics) { mMetrics = httptransactionmetrics; } final void printHeaders() { if(EsLog.isLoggable("HttpTransaction", 3)) { StringBuilder stringbuilder = new StringBuilder("HTTP headers:\n"); Header aheader[] = mHttpMethod.getAllHeaders(); int i = aheader.length; int j = 0; while(j < i) { Header header = aheader[j]; if("Authorization".equals(header.getName())) stringbuilder.append("Authorization: <removed>"); else stringbuilder.append(header.toString()); stringbuilder.append("\n"); j++; } Log.d("HttpTransaction", stringbuilder.toString()); } } public final void execute() throws NetworkException { _execute_v2_(); } private void _execute_v1_() throws NetworkException { int statusCode = 0; String reason = "Unknown"; DefaultHttpClient defaulthttpclient = null; InputStream inputstream = null; try { if(mAborted) { if(mMetrics != null) mMetrics.onEndTransaction(); throw new NetworkException("Canceled"); } defaulthttpclient = new DefaultHttpClient(new SingleClientConnManager(sHttpParams, sSupportedSchemes), sHttpParams); defaulthttpclient.removeRequestInterceptorByClass(RequestAddCookies.class); defaulthttpclient.removeResponseInterceptorByClass(ResponseProcessCookies.class); defaulthttpclient.addRequestInterceptor(this); defaulthttpclient.addResponseInterceptor(this); if(mAborted) { throw new NetworkException("Canceled"); } HttpResponse httpresponse = defaulthttpclient.execute(mHttpMethod); if(mAborted) { throw new NetworkException("Canceled"); } statusCode = httpresponse.getStatusLine().getStatusCode(); reason = httpresponse.getStatusLine().getReasonPhrase(); HttpEntity httpentity = httpresponse.getEntity(); Header[] aheader = httpresponse.getAllHeaders(); String encoding = null; if(httpentity.getContentEncoding() != null) { encoding = httpentity.getContentEncoding().getValue(); } String contentType = httpentity.getContentType().getValue(); int k = contentType.indexOf(';'); if(k != -1) contentType = contentType.substring(0, k); int length = (int)httpentity.getContentLength(); if(EsLog.isLoggable("HttpTransaction", 3)) Log.d("HttpTransaction", (new StringBuilder("readFromHttpStream: Encoding: ")).append(encoding).append(", type: ").append(contentType).append(", length: ").append(length).toString()); inputstream = httpentity.getContent(); if(null != encoding && encoding.equals("gzip")) { inputstream = new GZIPInputStream(inputstream); } if(statusCode == 200) { mListener.onHttpReadFromStream(inputstream, contentType, length, aheader); } else { mListener.onHttpReadErrorFromStream(inputstream, contentType, length, aheader, statusCode); } } catch (NetworkException e) { reason = e.getMessage(); throw e; } catch (IOException e) { reason = e.getMessage(); } finally { if(defaulthttpclient != null) defaulthttpclient.getConnectionManager().shutdown(); if(null != inputstream) { try { inputstream.close(); } catch (IOException e) { // TODO e.printStackTrace(); } } if(mMetrics != null) mMetrics.onEndTransaction(); mListener.onHttpTransactionComplete(statusCode, reason, new HttpResponseException(statusCode, reason)); } } private void _execute_v2_() throws NetworkException { int statusCode = 0; String reason = "Unknown"; HttpURLConnection httpurlconnection = null; try { HttpEntity entity = this.request.toEntity(); httpurlconnection = (HttpURLConnection)(new URL(url)).openConnection(); httpurlconnection.setInstanceFollowRedirects(false); httpurlconnection.setDoOutput(true); httpurlconnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); httpurlconnection.setRequestProperty("Content-Length", Long.toString(entity.getContentLength())); OutputStream outputstream = httpurlconnection.getOutputStream(); entity.writeTo(outputstream); outputstream.flush(); statusCode = httpurlconnection.getResponseCode(); if(statusCode == 200) { mListener.onHttpReadFromStream(httpurlconnection.getInputStream(), "", -1, null); } else { mListener.onHttpReadErrorFromStream(httpurlconnection.getInputStream(), null, -1, null, statusCode); } } catch (IOException e) { reason = e.getMessage(); } finally { if(null != httpurlconnection) { httpurlconnection.disconnect(); } mListener.onHttpTransactionComplete(statusCode, reason, new HttpResponseException(statusCode, reason)); } } //=========================================================================== // Private Function //=========================================================================== private void processCookies(HeaderIterator headeriterator, CookieSpec cookiespec, CookieOrigin cookieorigin) { while (headeriterator.hasNext()) { Header header = headeriterator.nextHeader(); try { Iterator iterator = cookiespec.parse(header, cookieorigin) .iterator(); while (iterator.hasNext()) { Cookie cookie = (Cookie) iterator.next(); mListener.onHttpCookie(cookie); } } catch (MalformedCookieException malformedcookieexception) { Log.e("HttpTransaction", "Malformed cookie", malformedcookieexception); } } } //=========================================================================== // Inner class //=========================================================================== public static interface HttpTransactionListener { void onHttpCookie(Cookie cookie); void onHttpReadErrorFromStream(InputStream inputstream, String s, int i, Header aheader[], int j) throws IOException; void onHttpReadFromStream(InputStream inputstream, String s, int i, Header aheader[]) throws IOException; void onHttpTransactionComplete(int i, String s, Exception exception); } private static final class CountingOutputStream extends FilterOutputStream { private final long mChunk; private final long mLength; private long mNext; private final HttpTransaction mTransaction; private long mTransferred; public CountingOutputStream(HttpTransaction httptransaction, OutputStream outputstream, long l) { super(outputstream); mTransaction = httptransaction; mLength = 2L * l; mTransferred = 0L; mChunk = mLength / 5L; mNext = mChunk; } public final void write(int i) throws IOException { super.write(i); mTransferred = 1L + mTransferred; if (mTransferred >= mNext) { super.flush(); HttpTransactionListener _tmp = mTransaction.mListener; long _tmp1 = mTransferred; long _tmp2 = mLength; mNext = mNext + mChunk; } } public final void write(byte abyte0[], int i, int j) throws IOException { super.write(abyte0, i, j); mTransferred = mTransferred + (long) j; if (mTransferred >= mNext) { super.flush(); HttpTransactionListener _tmp = mTransaction.mListener; long _tmp1 = mTransferred; long _tmp2 = mLength; mNext = mNext + mChunk; } } } private static final class MyInputStreamEntity extends HttpEntityWrapper { private final HttpTransaction mTransaction; public MyInputStreamEntity(HttpTransaction httptransaction, HttpEntity httpentity) { super(httpentity); mTransaction = httptransaction; } public final void writeTo(OutputStream outputstream) throws IOException { super.writeTo(new CountingOutputStream(mTransaction, outputstream,getContentLength())); } } }