diff options
author | Koushik Dutta <koushd@gmail.com> | 2013-03-23 11:26:53 -0700 |
---|---|---|
committer | Koushik Dutta <koushd@gmail.com> | 2013-03-23 11:26:53 -0700 |
commit | a26eb862f12ea82d55fe9ca794366e57c0173aec (patch) | |
tree | d695705194f3f633d70a176a9c81fd5cc2337cde | |
parent | a9f3cb26f3065b7c931857ad4a117face4e68ad1 (diff) | |
download | AndroidAsync-a26eb862f12ea82d55fe9ca794366e57c0173aec.tar.gz AndroidAsync-a26eb862f12ea82d55fe9ca794366e57c0173aec.tar.bz2 AndroidAsync-a26eb862f12ea82d55fe9ca794366e57c0173aec.zip |
rename refactor some classes. minor stats and fixes for cache code.
20 files changed, 479 insertions, 502 deletions
diff --git a/AndroidAsync/src/com/koushikdutta/async/AsyncSSLSocket.java b/AndroidAsync/src/com/koushikdutta/async/AsyncSSLSocket.java index 8ece9bf..e45d9c0 100644 --- a/AndroidAsync/src/com/koushikdutta/async/AsyncSSLSocket.java +++ b/AndroidAsync/src/com/koushikdutta/async/AsyncSSLSocket.java @@ -1,401 +1,7 @@ package com.koushikdutta.async; -import java.nio.ByteBuffer; -import java.security.KeyStore; import java.security.cert.X509Certificate; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLEngine; -import javax.net.ssl.SSLEngineResult; -import javax.net.ssl.SSLEngineResult.HandshakeStatus; -import javax.net.ssl.SSLEngineResult.Status; -import javax.net.ssl.SSLException; -import javax.net.ssl.TrustManager; -import javax.net.ssl.TrustManagerFactory; -import javax.net.ssl.X509TrustManager; - -import junit.framework.Assert; - -import org.apache.http.conn.ssl.StrictHostnameVerifier; - -import android.os.Build; - -import com.koushikdutta.async.callback.CompletedCallback; -import com.koushikdutta.async.callback.DataCallback; -import com.koushikdutta.async.callback.WritableCallback; - -public class AsyncSSLSocket implements AsyncSocketWrapper, IAsyncSSLSocket { - AsyncSocket mSocket; - BufferedDataEmitter mEmitter; - BufferedDataSink mSink; - ByteBuffer mReadTmp = ByteBuffer.allocate(8192); - boolean mUnwrapping = false; - - public AsyncSSLSocket(AsyncSocket socket, String host, int port) { - mSocket = socket; - - if (host != null) { - engine = ctx.createSSLEngine(host, port); - } - else { - engine = ctx.createSSLEngine(); - } - mHost = host; - mPort = port; - engine.setUseClientMode(true); - mSink = new BufferedDataSink(socket); - mSink.setMaxBuffer(0); - - // SSL needs buffering of data written during handshake. - // aka exhcange.setDatacallback - mEmitter = new BufferedDataEmitter(socket); -// socket.setDataCallback(mEmitter); - - mEmitter.setDataCallback(new DataCallback() { - @Override - public void onDataAvailable(DataEmitter emitter, ByteBufferList bb) { - if (mUnwrapping) - return; - try { - mUnwrapping = true; - - ByteBufferList out = new ByteBufferList(); - - mReadTmp.position(0); - mReadTmp.limit(mReadTmp.capacity()); - ByteBuffer b; - if (bb.size() > 1) - b = bb.read(bb.remaining()); - else if (bb.size() == 1) - b = bb.peek(); - else { - b = ByteBuffer.allocate(0); - } - - while (true) { - int remaining = b.remaining(); - - SSLEngineResult res = engine.unwrap(b, mReadTmp); - if (res.getStatus() == Status.BUFFER_OVERFLOW) { - addToPending(out); - mReadTmp = ByteBuffer.allocate(mReadTmp.remaining() * 2); - remaining = -1; - } - handleResult(res); - if (b.remaining() == remaining) - break; - } - - addToPending(out); - Util.emitAllData(AsyncSSLSocket.this, out); - } - catch (Exception ex) { - ex.printStackTrace(); - report(ex); - } - finally { - mUnwrapping = false; - } - } - }); - } - - void addToPending(ByteBufferList out) { - if (mReadTmp.position() > 0) { - mReadTmp.limit(mReadTmp.position()); - mReadTmp.position(0); - out.add(mReadTmp); - mReadTmp = ByteBuffer.allocate(mReadTmp.capacity()); - } - } - - static SSLContext ctx; - static { - // following is the "trust the system" certs setup - try { - // critical extension 2.5.29.15 is implemented improperly prior to 4.0.3. - // https://code.google.com/p/android/issues/detail?id=9307 - // https://groups.google.com/forum/?fromgroups=#!topic/netty/UCfqPPk5O4s - // certs that use this extension will throw in Cipher.java. - // fallback is to use a custom SSLContext, and hack around the x509 extension. - if (Build.VERSION.SDK_INT <= 15) - throw new Exception(); - ctx = SSLContext.getInstance("Default"); - } - catch (Exception ex) { - try { - ctx = SSLContext.getInstance("TLS"); - TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() { - public java.security.cert.X509Certificate[] getAcceptedIssuers() { - return new X509Certificate[] {}; - } - - public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) { - } - - public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) { - for (X509Certificate cert : certs) { - cert.getCriticalExtensionOIDs().remove("2.5.29.15"); - } - } - } }; - ctx.init(null, trustAllCerts, null); - } - catch (Exception ex2) { - ex.printStackTrace(); - ex2.printStackTrace(); - } - } - } - - SSLEngine engine; - boolean finishedHandshake = false; - - private String mHost; - public String getHost() { - return mHost; - } - - private int mPort; - public int getPort() { - return mPort; - } - - private void handleResult(SSLEngineResult res) { - if (res.getHandshakeStatus() == HandshakeStatus.NEED_TASK) { - final Runnable task = engine.getDelegatedTask(); - task.run(); - } - - if (res.getHandshakeStatus() == HandshakeStatus.NEED_WRAP) { - write(ByteBuffer.allocate(0)); - } - - if (res.getHandshakeStatus() == HandshakeStatus.NEED_UNWRAP) { - mEmitter.onDataAvailable(); - } - - try { - if (!finishedHandshake && (engine.getHandshakeStatus() == HandshakeStatus.NOT_HANDSHAKING || engine.getHandshakeStatus() == HandshakeStatus.FINISHED)) { - TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); - tmf.init((KeyStore) null); - boolean trusted = false; - for (TrustManager tm : tmf.getTrustManagers()) { - try { - X509TrustManager xtm = (X509TrustManager) tm; - peerCertificates = (X509Certificate[]) engine.getSession().getPeerCertificates(); - xtm.checkServerTrusted(peerCertificates, "SSL"); - if (mHost != null) { - StrictHostnameVerifier verifier = new StrictHostnameVerifier(); - verifier.verify(mHost, StrictHostnameVerifier.getCNs(peerCertificates[0]), StrictHostnameVerifier.getDNSSubjectAlts(peerCertificates[0])); - } - trusted = true; - break; - } - catch (Exception ex) { - ex.printStackTrace(); - } - } - finishedHandshake = true; - if (!trusted) { - AsyncSSLException e = new AsyncSSLException(); - report(e); - if (!e.getIgnore()) - throw e; - } - Assert.assertNotNull(mWriteableCallback); - mWriteableCallback.onWriteable(); - mEmitter.onDataAvailable(); - } - } - catch (Exception ex) { - report(ex); - } - } - - private void writeTmp() { - mWriteTmp.limit(mWriteTmp.position()); - mWriteTmp.position(0); - if (mWriteTmp.remaining() > 0) - mSink.write(mWriteTmp); - } - - boolean checkWrapResult(SSLEngineResult res) { - if (res.getStatus() == Status.BUFFER_OVERFLOW) { - mWriteTmp = ByteBuffer.allocate(mWriteTmp.remaining() * 2); - return false; - } - return true; - } - - private boolean mWrapping = false; - ByteBuffer mWriteTmp = ByteBuffer.allocate(8192); - @Override - public void write(ByteBuffer bb) { - if (mWrapping) - return; - if (mSink.remaining() > 0) - return; - mWrapping = true; - int remaining; - SSLEngineResult res = null; - do { - // if the handshake is finished, don't send - // 0 bytes of data, since that makes the ssl connection die. - // it wraps a 0 byte package, and craps out. - if (finishedHandshake && bb.remaining() == 0) { - mWrapping = false; - return; - } - remaining = bb.remaining(); - mWriteTmp.position(0); - mWriteTmp.limit(mWriteTmp.capacity()); - try { - res = engine.wrap(bb, mWriteTmp); - if (!checkWrapResult(res)) - remaining = -1; - writeTmp(); - handleResult(res); - } - catch (SSLException e) { - report(e); - } - } - while ((remaining != bb.remaining() || (res != null && res.getHandshakeStatus() == HandshakeStatus.NEED_WRAP)) && mSink.remaining() == 0); - mWrapping = false; - } - - @Override - public void write(ByteBufferList bb) { - if (mWrapping) - return; - if (mSink.remaining() > 0) - return; - mWrapping = true; - int remaining; - SSLEngineResult res = null; - do { - // if the handshake is finished, don't send - // 0 bytes of data, since that makes the ssl connection die. - // it wraps a 0 byte package, and craps out. - if (finishedHandshake && bb.remaining() == 0) { - mWrapping = false; - return; - } - remaining = bb.remaining(); - mWriteTmp.position(0); - mWriteTmp.limit(mWriteTmp.capacity()); - try { - res = engine.wrap(bb.toArray(), mWriteTmp); - if (!checkWrapResult(res)) - remaining = -1; - writeTmp(); - handleResult(res); - } - catch (SSLException e) { - report(e); - } - } - while ((remaining != bb.remaining() || (res != null && res.getHandshakeStatus() == HandshakeStatus.NEED_WRAP)) && mSink.remaining() == 0); - mWrapping = false; - } - - WritableCallback mWriteableCallback; - @Override - public void setWriteableCallback(WritableCallback handler) { - mWriteableCallback = handler; - } - - @Override - public WritableCallback getWriteableCallback() { - return mWriteableCallback; - } - - private void report(Exception e) { - CompletedCallback cb = getEndCallback(); - if (cb != null) - cb.onCompleted(e); - } - - DataCallback mDataCallback; - @Override - public void setDataCallback(DataCallback callback) { - mDataCallback = callback; - } - - @Override - public DataCallback getDataCallback() { - return mDataCallback; - } - - @Override - public boolean isChunked() { - return mSocket.isChunked(); - } - - @Override - public boolean isOpen() { - return mSocket.isOpen(); - } - - @Override - public void close() { - mSocket.close(); - } - - @Override - public void setClosedCallback(CompletedCallback handler) { - mSocket.setClosedCallback(handler); - } - - @Override - public CompletedCallback getClosedCallback() { - return mSocket.getClosedCallback(); - } - - @Override - public void setEndCallback(CompletedCallback callback) { - mSocket.setEndCallback(callback); - } - - @Override - public CompletedCallback getEndCallback() { - return mSocket.getEndCallback(); - } - - @Override - public void pause() { - mSocket.pause(); - } - - @Override - public void resume() { - mSocket.resume(); - } - - @Override - public boolean isPaused() { - return mSocket.isPaused(); - } - - @Override - public AsyncServer getServer() { - return mSocket.getServer(); - } - - @Override - public AsyncSocket getSocket() { - return mSocket; - } - - @Override - public DataEmitter getDataEmitter() { - return mSocket; - } - - X509Certificate[] peerCertificates; - @Override - public X509Certificate[] getPeerCertificates() { - return peerCertificates; - } +public interface AsyncSSLSocket extends AsyncSocket { + public X509Certificate[] getPeerCertificates(); } diff --git a/AndroidAsync/src/com/koushikdutta/async/AsyncSSLSocketWrapper.java b/AndroidAsync/src/com/koushikdutta/async/AsyncSSLSocketWrapper.java new file mode 100644 index 0000000..bddbe17 --- /dev/null +++ b/AndroidAsync/src/com/koushikdutta/async/AsyncSSLSocketWrapper.java @@ -0,0 +1,402 @@ +package com.koushikdutta.async; + +import java.nio.ByteBuffer; +import java.security.KeyStore; +import java.security.cert.X509Certificate; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLEngineResult; +import javax.net.ssl.SSLEngineResult.HandshakeStatus; +import javax.net.ssl.SSLEngineResult.Status; +import javax.net.ssl.SSLException; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; +import javax.net.ssl.X509TrustManager; + +import junit.framework.Assert; + +import org.apache.http.conn.ssl.StrictHostnameVerifier; + +import android.os.Build; + +import com.koushikdutta.async.callback.CompletedCallback; +import com.koushikdutta.async.callback.DataCallback; +import com.koushikdutta.async.callback.WritableCallback; +import com.koushikdutta.async.wrapper.AsyncSocketWrapper; + +public class AsyncSSLSocketWrapper implements AsyncSocketWrapper, AsyncSSLSocket { + AsyncSocket mSocket; + BufferedDataEmitter mEmitter; + BufferedDataSink mSink; + ByteBuffer mReadTmp = ByteBuffer.allocate(8192); + boolean mUnwrapping = false; + + public AsyncSSLSocketWrapper(AsyncSocket socket, String host, int port) { + mSocket = socket; + + if (host != null) { + engine = ctx.createSSLEngine(host, port); + } + else { + engine = ctx.createSSLEngine(); + } + mHost = host; + mPort = port; + engine.setUseClientMode(true); + mSink = new BufferedDataSink(socket); + mSink.setMaxBuffer(0); + + // SSL needs buffering of data written during handshake. + // aka exhcange.setDatacallback + mEmitter = new BufferedDataEmitter(socket); +// socket.setDataCallback(mEmitter); + + mEmitter.setDataCallback(new DataCallback() { + @Override + public void onDataAvailable(DataEmitter emitter, ByteBufferList bb) { + if (mUnwrapping) + return; + try { + mUnwrapping = true; + + ByteBufferList out = new ByteBufferList(); + + mReadTmp.position(0); + mReadTmp.limit(mReadTmp.capacity()); + ByteBuffer b; + if (bb.size() > 1) + b = bb.read(bb.remaining()); + else if (bb.size() == 1) + b = bb.peek(); + else { + b = ByteBuffer.allocate(0); + } + + while (true) { + int remaining = b.remaining(); + + SSLEngineResult res = engine.unwrap(b, mReadTmp); + if (res.getStatus() == Status.BUFFER_OVERFLOW) { + addToPending(out); + mReadTmp = ByteBuffer.allocate(mReadTmp.remaining() * 2); + remaining = -1; + } + handleResult(res); + if (b.remaining() == remaining) + break; + } + + addToPending(out); + Util.emitAllData(AsyncSSLSocketWrapper.this, out); + } + catch (Exception ex) { + ex.printStackTrace(); + report(ex); + } + finally { + mUnwrapping = false; + } + } + }); + } + + void addToPending(ByteBufferList out) { + if (mReadTmp.position() > 0) { + mReadTmp.limit(mReadTmp.position()); + mReadTmp.position(0); + out.add(mReadTmp); + mReadTmp = ByteBuffer.allocate(mReadTmp.capacity()); + } + } + + static SSLContext ctx; + static { + // following is the "trust the system" certs setup + try { + // critical extension 2.5.29.15 is implemented improperly prior to 4.0.3. + // https://code.google.com/p/android/issues/detail?id=9307 + // https://groups.google.com/forum/?fromgroups=#!topic/netty/UCfqPPk5O4s + // certs that use this extension will throw in Cipher.java. + // fallback is to use a custom SSLContext, and hack around the x509 extension. + if (Build.VERSION.SDK_INT <= 15) + throw new Exception(); + ctx = SSLContext.getInstance("Default"); + } + catch (Exception ex) { + try { + ctx = SSLContext.getInstance("TLS"); + TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() { + public java.security.cert.X509Certificate[] getAcceptedIssuers() { + return new X509Certificate[] {}; + } + + public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) { + } + + public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) { + for (X509Certificate cert : certs) { + cert.getCriticalExtensionOIDs().remove("2.5.29.15"); + } + } + } }; + ctx.init(null, trustAllCerts, null); + } + catch (Exception ex2) { + ex.printStackTrace(); + ex2.printStackTrace(); + } + } + } + + SSLEngine engine; + boolean finishedHandshake = false; + + private String mHost; + public String getHost() { + return mHost; + } + + private int mPort; + public int getPort() { + return mPort; + } + + private void handleResult(SSLEngineResult res) { + if (res.getHandshakeStatus() == HandshakeStatus.NEED_TASK) { + final Runnable task = engine.getDelegatedTask(); + task.run(); + } + + if (res.getHandshakeStatus() == HandshakeStatus.NEED_WRAP) { + write(ByteBuffer.allocate(0)); + } + + if (res.getHandshakeStatus() == HandshakeStatus.NEED_UNWRAP) { + mEmitter.onDataAvailable(); + } + + try { + if (!finishedHandshake && (engine.getHandshakeStatus() == HandshakeStatus.NOT_HANDSHAKING || engine.getHandshakeStatus() == HandshakeStatus.FINISHED)) { + TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + tmf.init((KeyStore) null); + boolean trusted = false; + for (TrustManager tm : tmf.getTrustManagers()) { + try { + X509TrustManager xtm = (X509TrustManager) tm; + peerCertificates = (X509Certificate[]) engine.getSession().getPeerCertificates(); + xtm.checkServerTrusted(peerCertificates, "SSL"); + if (mHost != null) { + StrictHostnameVerifier verifier = new StrictHostnameVerifier(); + verifier.verify(mHost, StrictHostnameVerifier.getCNs(peerCertificates[0]), StrictHostnameVerifier.getDNSSubjectAlts(peerCertificates[0])); + } + trusted = true; + break; + } + catch (Exception ex) { + ex.printStackTrace(); + } + } + finishedHandshake = true; + if (!trusted) { + AsyncSSLException e = new AsyncSSLException(); + report(e); + if (!e.getIgnore()) + throw e; + } + Assert.assertNotNull(mWriteableCallback); + mWriteableCallback.onWriteable(); + mEmitter.onDataAvailable(); + } + } + catch (Exception ex) { + report(ex); + } + } + + private void writeTmp() { + mWriteTmp.limit(mWriteTmp.position()); + mWriteTmp.position(0); + if (mWriteTmp.remaining() > 0) + mSink.write(mWriteTmp); + } + + boolean checkWrapResult(SSLEngineResult res) { + if (res.getStatus() == Status.BUFFER_OVERFLOW) { + mWriteTmp = ByteBuffer.allocate(mWriteTmp.remaining() * 2); + return false; + } + return true; + } + + private boolean mWrapping = false; + ByteBuffer mWriteTmp = ByteBuffer.allocate(8192); + @Override + public void write(ByteBuffer bb) { + if (mWrapping) + return; + if (mSink.remaining() > 0) + return; + mWrapping = true; + int remaining; + SSLEngineResult res = null; + do { + // if the handshake is finished, don't send + // 0 bytes of data, since that makes the ssl connection die. + // it wraps a 0 byte package, and craps out. + if (finishedHandshake && bb.remaining() == 0) { + mWrapping = false; + return; + } + remaining = bb.remaining(); + mWriteTmp.position(0); + mWriteTmp.limit(mWriteTmp.capacity()); + try { + res = engine.wrap(bb, mWriteTmp); + if (!checkWrapResult(res)) + remaining = -1; + writeTmp(); + handleResult(res); + } + catch (SSLException e) { + report(e); + } + } + while ((remaining != bb.remaining() || (res != null && res.getHandshakeStatus() == HandshakeStatus.NEED_WRAP)) && mSink.remaining() == 0); + mWrapping = false; + } + + @Override + public void write(ByteBufferList bb) { + if (mWrapping) + return; + if (mSink.remaining() > 0) + return; + mWrapping = true; + int remaining; + SSLEngineResult res = null; + do { + // if the handshake is finished, don't send + // 0 bytes of data, since that makes the ssl connection die. + // it wraps a 0 byte package, and craps out. + if (finishedHandshake && bb.remaining() == 0) { + mWrapping = false; + return; + } + remaining = bb.remaining(); + mWriteTmp.position(0); + mWriteTmp.limit(mWriteTmp.capacity()); + try { + res = engine.wrap(bb.toArray(), mWriteTmp); + if (!checkWrapResult(res)) + remaining = -1; + writeTmp(); + handleResult(res); + } + catch (SSLException e) { + report(e); + } + } + while ((remaining != bb.remaining() || (res != null && res.getHandshakeStatus() == HandshakeStatus.NEED_WRAP)) && mSink.remaining() == 0); + mWrapping = false; + } + + WritableCallback mWriteableCallback; + @Override + public void setWriteableCallback(WritableCallback handler) { + mWriteableCallback = handler; + } + + @Override + public WritableCallback getWriteableCallback() { + return mWriteableCallback; + } + + private void report(Exception e) { + CompletedCallback cb = getEndCallback(); + if (cb != null) + cb.onCompleted(e); + } + + DataCallback mDataCallback; + @Override + public void setDataCallback(DataCallback callback) { + mDataCallback = callback; + } + + @Override + public DataCallback getDataCallback() { + return mDataCallback; + } + + @Override + public boolean isChunked() { + return mSocket.isChunked(); + } + + @Override + public boolean isOpen() { + return mSocket.isOpen(); + } + + @Override + public void close() { + mSocket.close(); + } + + @Override + public void setClosedCallback(CompletedCallback handler) { + mSocket.setClosedCallback(handler); + } + + @Override + public CompletedCallback getClosedCallback() { + return mSocket.getClosedCallback(); + } + + @Override + public void setEndCallback(CompletedCallback callback) { + mSocket.setEndCallback(callback); + } + + @Override + public CompletedCallback getEndCallback() { + return mSocket.getEndCallback(); + } + + @Override + public void pause() { + mSocket.pause(); + } + + @Override + public void resume() { + mSocket.resume(); + } + + @Override + public boolean isPaused() { + return mSocket.isPaused(); + } + + @Override + public AsyncServer getServer() { + return mSocket.getServer(); + } + + @Override + public AsyncSocket getSocket() { + return mSocket; + } + + @Override + public DataEmitter getDataEmitter() { + return mSocket; + } + + X509Certificate[] peerCertificates; + @Override + public X509Certificate[] getPeerCertificates() { + return peerCertificates; + } +} diff --git a/AndroidAsync/src/com/koushikdutta/async/DataWrapperSocket.java b/AndroidAsync/src/com/koushikdutta/async/DataWrapperSocket.java index 6164faf..a3c48b0 100644 --- a/AndroidAsync/src/com/koushikdutta/async/DataWrapperSocket.java +++ b/AndroidAsync/src/com/koushikdutta/async/DataWrapperSocket.java @@ -4,6 +4,7 @@ import java.nio.ByteBuffer; import com.koushikdutta.async.callback.CompletedCallback; import com.koushikdutta.async.callback.WritableCallback; +import com.koushikdutta.async.wrapper.AsyncSocketWrapper; public class DataWrapperSocket extends FilteredDataEmitter implements AsyncSocketWrapper { private AsyncSocket mSocket; diff --git a/AndroidAsync/src/com/koushikdutta/async/FilteredDataEmitter.java b/AndroidAsync/src/com/koushikdutta/async/FilteredDataEmitter.java index eac9b5b..77e49b3 100644 --- a/AndroidAsync/src/com/koushikdutta/async/FilteredDataEmitter.java +++ b/AndroidAsync/src/com/koushikdutta/async/FilteredDataEmitter.java @@ -4,6 +4,7 @@ import junit.framework.Assert; import com.koushikdutta.async.callback.CompletedCallback; import com.koushikdutta.async.callback.DataCallback; +import com.koushikdutta.async.wrapper.DataEmitterWrapper; public class FilteredDataEmitter implements DataEmitter, DataCallback, DataEmitterWrapper { DataEmitter mEmitter; diff --git a/AndroidAsync/src/com/koushikdutta/async/IAsyncSSLSocket.java b/AndroidAsync/src/com/koushikdutta/async/IAsyncSSLSocket.java deleted file mode 100644 index 95dcfa5..0000000 --- a/AndroidAsync/src/com/koushikdutta/async/IAsyncSSLSocket.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.koushikdutta.async; - -import java.security.cert.X509Certificate; - -public interface IAsyncSSLSocket extends AsyncSocket { - public X509Certificate[] getPeerCertificates(); -} diff --git a/AndroidAsync/src/com/koushikdutta/async/PushParser.java b/AndroidAsync/src/com/koushikdutta/async/PushParser.java index cab5b50..271715c 100644 --- a/AndroidAsync/src/com/koushikdutta/async/PushParser.java +++ b/AndroidAsync/src/com/koushikdutta/async/PushParser.java @@ -1,9 +1,6 @@ package com.koushikdutta.async; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; import java.lang.reflect.Method; -import java.lang.reflect.Modifier; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Hashtable; diff --git a/AndroidAsync/src/com/koushikdutta/async/Util.java b/AndroidAsync/src/com/koushikdutta/async/Util.java index 13436cf..c42c6a1 100644 --- a/AndroidAsync/src/com/koushikdutta/async/Util.java +++ b/AndroidAsync/src/com/koushikdutta/async/Util.java @@ -11,6 +11,8 @@ import junit.framework.Assert; import com.koushikdutta.async.callback.CompletedCallback; import com.koushikdutta.async.callback.DataCallback; import com.koushikdutta.async.callback.WritableCallback; +import com.koushikdutta.async.wrapper.AsyncSocketWrapper; +import com.koushikdutta.async.wrapper.DataEmitterWrapper; public class Util { public static void emitAllData(DataEmitter emitter, ByteBufferList list) { diff --git a/AndroidAsync/src/com/koushikdutta/async/http/AsyncSSLSocketMiddleware.java b/AndroidAsync/src/com/koushikdutta/async/http/AsyncSSLSocketMiddleware.java index 1fe5c81..fe2f8e9 100644 --- a/AndroidAsync/src/com/koushikdutta/async/http/AsyncSSLSocketMiddleware.java +++ b/AndroidAsync/src/com/koushikdutta/async/http/AsyncSSLSocketMiddleware.java @@ -2,7 +2,7 @@ package com.koushikdutta.async.http; import java.net.URI; -import com.koushikdutta.async.AsyncSSLSocket; +import com.koushikdutta.async.AsyncSSLSocketWrapper; import com.koushikdutta.async.AsyncSocket; import com.koushikdutta.async.callback.ConnectCallback; @@ -17,7 +17,7 @@ public class AsyncSSLSocketMiddleware extends AsyncSocketMiddleware { @Override public void onConnectCompleted(Exception ex, AsyncSocket socket) { if (ex == null) { - callback.onConnectCompleted(ex, new AsyncSSLSocket(socket, uri.getHost(), port)); + callback.onConnectCompleted(ex, new AsyncSSLSocketWrapper(socket, uri.getHost(), port)); } else { callback.onConnectCompleted(ex, socket); diff --git a/AndroidAsync/src/com/koushikdutta/async/http/AsyncSocketMiddleware.java b/AndroidAsync/src/com/koushikdutta/async/http/AsyncSocketMiddleware.java index cbf7031..28d79fd 100644 --- a/AndroidAsync/src/com/koushikdutta/async/http/AsyncSocketMiddleware.java +++ b/AndroidAsync/src/com/koushikdutta/async/http/AsyncSocketMiddleware.java @@ -64,7 +64,7 @@ public class AsyncSocketMiddleware extends SimpleMiddleware { mClient.getServer().post(new Runnable() { @Override public void run() { - Log.i("AsyncHttpSocket", "Reusing socket."); +// Log.i("AsyncHttpSocket", "Reusing keep-alive socket"); data.connectCallback.onConnectCompleted(null, socket); } }); @@ -95,7 +95,7 @@ public class AsyncSocketMiddleware extends SimpleMiddleware { return; } - Log.i("AsynchttpSocket", "recycling"); +// Log.i("AsynchttpSocket", "Recycling keep-alive socket"); final URI uri = data.request.getUri(); final int port = getSchemePort(data.request.getUri()); diff --git a/AndroidAsync/src/com/koushikdutta/async/http/ResponseCacheMiddleware.java b/AndroidAsync/src/com/koushikdutta/async/http/ResponseCacheMiddleware.java index 4171db0..2c10640 100644 --- a/AndroidAsync/src/com/koushikdutta/async/http/ResponseCacheMiddleware.java +++ b/AndroidAsync/src/com/koushikdutta/async/http/ResponseCacheMiddleware.java @@ -2,7 +2,6 @@ package com.koushikdutta.async.http; import java.io.BufferedWriter; import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FilterInputStream; import java.io.FilterOutputStream; @@ -34,26 +33,24 @@ import javax.net.ssl.SSLPeerUnverifiedException; import android.os.Parcel; import android.os.Parcelable; import android.util.Base64; -import android.util.Log; +import com.koushikdutta.async.AsyncSSLSocket; import com.koushikdutta.async.AsyncServer; import com.koushikdutta.async.AsyncSocket; import com.koushikdutta.async.ByteBufferList; import com.koushikdutta.async.Cancelable; import com.koushikdutta.async.DataEmitter; -import com.koushikdutta.async.DataWrapperSocket; import com.koushikdutta.async.FilteredDataEmitter; -import com.koushikdutta.async.IAsyncSSLSocket; import com.koushikdutta.async.SimpleCancelable; import com.koushikdutta.async.callback.CompletedCallback; import com.koushikdutta.async.callback.DataCallback; import com.koushikdutta.async.callback.WritableCallback; +import com.koushikdutta.async.http.libcore.Charsets; +import com.koushikdutta.async.http.libcore.DiskLruCache; import com.koushikdutta.async.http.libcore.RawHeaders; import com.koushikdutta.async.http.libcore.ResponseHeaders; import com.koushikdutta.async.http.libcore.ResponseSource; -import com.koushikdutta.async.util.cache.Charsets; -import com.koushikdutta.async.util.cache.DiskLruCache; -import com.koushikdutta.async.util.cache.StrictLineReader; +import com.koushikdutta.async.http.libcore.StrictLineReader; public class ResponseCacheMiddleware extends SimpleMiddleware { private DiskLruCache cache; @@ -97,7 +94,7 @@ public class ResponseCacheMiddleware extends SimpleMiddleware { } } - private class CachedSSLSocket extends CachedSocket implements IAsyncSSLSocket { + private class CachedSSLSocket extends CachedSocket implements AsyncSSLSocket { public CachedSSLSocket(CacheResponse cacheResponse) { super(cacheResponse); } @@ -327,31 +324,11 @@ public class ResponseCacheMiddleware extends SimpleMiddleware { RawHeaders rawResponseHeaders = RawHeaders.fromMultimap(responseHeadersMap); ResponseHeaders cachedResponseHeaders = new ResponseHeaders(data.request.getUri(), rawResponseHeaders); - - //// - if (false) { - final CachedSocket ss = entry.isHttps() ? new CachedSSLSocket((EntrySecureCacheResponse)candidate) : new CachedSocket((EntryCacheResponse)candidate); - - ss.pending.add(ByteBuffer.wrap(rawResponseHeaders.toHeaderString().getBytes())); - - client.getServer().post(new Runnable() { - @Override - public void run() { - data.connectCallback.onConnectCompleted(null, ss); - ss.spewInternal(); - } - }); - - if (true) - return new SimpleCancelable(); - } - /// - - long now = System.currentTimeMillis(); responseSource = cachedResponseHeaders.chooseResponseSource(now, data.request.getHeaders()); if (responseSource == ResponseSource.CACHE) { + cacheStoreCount++; final CachedSocket socket = entry.isHttps() ? new CachedSSLSocket((EntrySecureCacheResponse)candidate) : new CachedSocket((EntryCacheResponse)candidate); client.getServer().post(new Runnable() { @@ -513,17 +490,41 @@ public class ResponseCacheMiddleware extends SimpleMiddleware { } } + int conditionalCacheHitCount; + int cacheHitCount; + int networkCount; + int cacheStoreCount; + + public int getConditionalCacheHitCount() { + return conditionalCacheHitCount; + } + public int getCacheHitCount() { + return cacheHitCount; + } + public int getNetworkCount() { + return networkCount; + } + public int getCacheStoreCount() { + return cacheStoreCount; + } + // step 3) if this is a conditional cache request, serve it from the cache if necessary // otherwise, see if it is cacheable @Override public void onBodyDecoder(OnBodyData data) { + CachedSocket cached = (CachedSocket) com.koushikdutta.async.Util.getWrappedSocket(data.socket, CachedSocket.class); + if (cached != null) + return; + CacheData cacheData = data.state.getParcelable("cache-data"); if (cacheData != null) { if (cacheData.cachedResponseHeaders.validate(data.headers)) { data.headers = cacheData.cachedResponseHeaders.combine(data.headers); data.headers.getHeaders().setStatusLine(cacheData.cachedResponseHeaders.getHeaders().getStatusLine()); + conditionalCacheHitCount++; + BodySpewer bodySpewer = new BodySpewer(); bodySpewer.cacheResponse = cacheData.candidate; bodySpewer.setDataEmitter(data.bodyEmitter); @@ -539,8 +540,15 @@ public class ResponseCacheMiddleware extends SimpleMiddleware { if (!caching) return; - if (!data.headers.isCacheable(data.request.getHeaders())) + if (!data.headers.isCacheable(data.request.getHeaders()) || !data.request.getMethod().equals(AsyncHttpGet.METHOD)) { + /* + * Don't cache non-GET responses. We're technically allowed to cache + * HEAD requests and some POST requests, but the complexity of doing + * so is high and the benefit is low. + */ + networkCount++; return; + } String key = uriToKey(data.request.getUri()); RawHeaders varyHeaders = data.request.getHeaders().getHeaders().getAll(data.headers.getVaryFields()); @@ -564,27 +572,24 @@ public class ResponseCacheMiddleware extends SimpleMiddleware { data.bodyEmitter = cacher; data.state.putParcelable("body-cacher", cacher); + cacheStoreCount++; } catch (Exception e) { // Log.e(LOGTAG, "error", e); if (cacher.cacheRequest != null) cacher.cacheRequest.abort(); cacher.cacheRequest = null; + networkCount++; } } @Override public void onRequestComplete(OnRequestCompleteData data) { -// CachingSocket caching = (CachingSocket)com.koushikdutta.async.Util.getWrappedSocket(data.socket, CachingSocket.class); -// if (caching == null) -// return; - BodyCacher cacher = data.state.getParcelable("body-cacher"); if (cacher == null) return; -// Log.i(LOGTAG, "Cache done: " + ex); try { if (data.exception != null) cacher.abort(); diff --git a/AndroidAsync/src/com/koushikdutta/async/util/cache/Arrays.java b/AndroidAsync/src/com/koushikdutta/async/http/libcore/Arrays.java index fc16d7b..e076acf 100644 --- a/AndroidAsync/src/com/koushikdutta/async/util/cache/Arrays.java +++ b/AndroidAsync/src/com/koushikdutta/async/http/libcore/Arrays.java @@ -1,4 +1,4 @@ -package com.koushikdutta.async.util.cache; +package com.koushikdutta.async.http.libcore; import java.lang.reflect.Array; diff --git a/AndroidAsync/src/com/koushikdutta/async/util/cache/Charsets.java b/AndroidAsync/src/com/koushikdutta/async/http/libcore/Charsets.java index 8116a52..575b147 100644 --- a/AndroidAsync/src/com/koushikdutta/async/util/cache/Charsets.java +++ b/AndroidAsync/src/com/koushikdutta/async/http/libcore/Charsets.java @@ -1,4 +1,4 @@ -package com.koushikdutta.async.util.cache; +package com.koushikdutta.async.http.libcore; import java.nio.charset.Charset; diff --git a/AndroidAsync/src/com/koushikdutta/async/util/cache/DiskLruCache.java b/AndroidAsync/src/com/koushikdutta/async/http/libcore/DiskLruCache.java index 9031d4f..729b401 100644 --- a/AndroidAsync/src/com/koushikdutta/async/util/cache/DiskLruCache.java +++ b/AndroidAsync/src/com/koushikdutta/async/http/libcore/DiskLruCache.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.koushikdutta.async.util.cache; +package com.koushikdutta.async.http.libcore; import java.io.BufferedWriter; import java.io.Closeable; diff --git a/AndroidAsync/src/com/koushikdutta/async/util/cache/IOUtils.java b/AndroidAsync/src/com/koushikdutta/async/http/libcore/IOUtils.java index cad50ba..81cc1ea 100644 --- a/AndroidAsync/src/com/koushikdutta/async/util/cache/IOUtils.java +++ b/AndroidAsync/src/com/koushikdutta/async/http/libcore/IOUtils.java @@ -1,4 +1,4 @@ -package com.koushikdutta.async.util.cache; +package com.koushikdutta.async.http.libcore; import java.io.Closeable; import java.io.File; diff --git a/AndroidAsync/src/com/koushikdutta/async/util/cache/Streams.java b/AndroidAsync/src/com/koushikdutta/async/http/libcore/Streams.java index c723f8f..b78f52c 100644 --- a/AndroidAsync/src/com/koushikdutta/async/util/cache/Streams.java +++ b/AndroidAsync/src/com/koushikdutta/async/http/libcore/Streams.java @@ -1,4 +1,4 @@ -package com.koushikdutta.async.util.cache; +package com.koushikdutta.async.http.libcore; import java.io.IOException; import java.io.Reader; diff --git a/AndroidAsync/src/com/koushikdutta/async/util/cache/StrictLineReader.java b/AndroidAsync/src/com/koushikdutta/async/http/libcore/StrictLineReader.java index 541b89b..6c6308f 100644 --- a/AndroidAsync/src/com/koushikdutta/async/util/cache/StrictLineReader.java +++ b/AndroidAsync/src/com/koushikdutta/async/http/libcore/StrictLineReader.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.koushikdutta.async.util.cache; +package com.koushikdutta.async.http.libcore; import java.io.ByteArrayOutputStream; import java.io.Closeable; diff --git a/AndroidAsync/src/com/koushikdutta/async/AsyncSocketWrapper.java b/AndroidAsync/src/com/koushikdutta/async/wrapper/AsyncSocketWrapper.java index c8bcdfa..5e28382 100644 --- a/AndroidAsync/src/com/koushikdutta/async/AsyncSocketWrapper.java +++ b/AndroidAsync/src/com/koushikdutta/async/wrapper/AsyncSocketWrapper.java @@ -1,4 +1,6 @@ -package com.koushikdutta.async; +package com.koushikdutta.async.wrapper; + +import com.koushikdutta.async.AsyncSocket; public interface AsyncSocketWrapper extends AsyncSocket, DataEmitterWrapper { public AsyncSocket getSocket(); diff --git a/AndroidAsync/src/com/koushikdutta/async/DataEmitterWrapper.java b/AndroidAsync/src/com/koushikdutta/async/wrapper/DataEmitterWrapper.java index 5b9beee..d057a61 100644 --- a/AndroidAsync/src/com/koushikdutta/async/DataEmitterWrapper.java +++ b/AndroidAsync/src/com/koushikdutta/async/wrapper/DataEmitterWrapper.java @@ -1,4 +1,6 @@ -package com.koushikdutta.async; +package com.koushikdutta.async.wrapper; + +import com.koushikdutta.async.DataEmitter; public interface DataEmitterWrapper extends DataEmitter { public DataEmitter getDataEmitter(); diff --git a/AndroidAsync/src/com/koushikdutta/async/SimpleWrapperSocket.java b/AndroidAsync/src/com/koushikdutta/async/wrapper/SimpleWrapperSocket.java index 0ed6c32..a540ea9 100644 --- a/AndroidAsync/src/com/koushikdutta/async/SimpleWrapperSocket.java +++ b/AndroidAsync/src/com/koushikdutta/async/wrapper/SimpleWrapperSocket.java @@ -1,7 +1,11 @@ -package com.koushikdutta.async; +package com.koushikdutta.async.wrapper; import java.nio.ByteBuffer; +import com.koushikdutta.async.AsyncServer; +import com.koushikdutta.async.AsyncSocket; +import com.koushikdutta.async.ByteBufferList; +import com.koushikdutta.async.DataEmitter; import com.koushikdutta.async.callback.CompletedCallback; import com.koushikdutta.async.callback.DataCallback; import com.koushikdutta.async.callback.WritableCallback; diff --git a/AndroidAsyncSample/src/com/koushikdutta/async/sample/MainActivity.java b/AndroidAsyncSample/src/com/koushikdutta/async/sample/MainActivity.java index 4b2fe88..2f23cc4 100644 --- a/AndroidAsyncSample/src/com/koushikdutta/async/sample/MainActivity.java +++ b/AndroidAsyncSample/src/com/koushikdutta/async/sample/MainActivity.java @@ -46,50 +46,7 @@ public class MainActivity extends Activity { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - new Thread() { - public void run() { - try { - HttpResponseCache cache; - try { - File httpCacheDir = new File(getCacheDir(), "http"); - long httpCacheSize = 10 * 1024 * 1024; // 10 MiB - cache = HttpResponseCache.install(httpCacheDir, httpCacheSize); - } - catch (IOException e) { - Log.i("cache", "HTTP response cache installation failed:" + e); - return; - } - URL url = new URL("https://desksms.appspot.com"); - URLConnection conn = url.openConnection(); - for (String header: conn.getRequestProperties().keySet()) { - System.out.println(header + ": "); - for (String value: conn.getRequestProperties().get(header)) { - System.out.println(value); - } - } - for (String header: conn.getHeaderFields().keySet()) { - System.out.println(header + ": " + conn.getHeaderField(header)); - } - InputStream in = conn.getInputStream(); - int count = 0; - while (in.read() != -1) { - count++; - } - in.close(); - System.out.println("count: " + count); - - System.out.println("cache count: " + cache.getHitCount()); - System.out.println("network count: " + cache.getNetworkCount()); - } - catch (Exception e) { - e.printStackTrace(); - } - }; - }.start(); - - if (cacher == null) { - try { cacher = ResponseCacheMiddleware.addCache(AsyncHttpClient.getDefaultInstance(), getFileStreamPath("asynccache"), 1024 * 1024 * 10); cacher.setCaching(false); @@ -142,7 +99,6 @@ public class MainActivity extends Activity { e.printStackTrace(); return; } - System.out.println(result.getAbsolutePath()); Bitmap bitmap = BitmapFactory.decodeFile(filename); result.delete(); if (bitmap == null) @@ -173,7 +129,6 @@ public class MainActivity extends Activity { e.printStackTrace(); return; } - System.out.println(result.getAbsolutePath()); Bitmap bitmap = BitmapFactory.decodeFile(filename); result.delete(); if (bitmap == null) @@ -199,8 +154,15 @@ public class MainActivity extends Activity { chart.setImageBitmap(null); getFile(rommanager, "https://raw.github.com/koush/AndroidAsync/master/rommanager.png", getFileStreamPath(randomFile()).getAbsolutePath()); -// getFile(tether, "https://raw.github.com/koush/AndroidAsync/master/tether.png", getFileStreamPath(randomFile()).getAbsolutePath()); -// getFile(desksms, "https://raw.github.com/koush/AndroidAsync/master/desksms.png", getFileStreamPath(randomFile()).getAbsolutePath()); -// getChartFile(); + getFile(tether, "https://raw.github.com/koush/AndroidAsync/master/tether.png", getFileStreamPath(randomFile()).getAbsolutePath()); + getFile(desksms, "https://raw.github.com/koush/AndroidAsync/master/desksms.png", getFileStreamPath(randomFile()).getAbsolutePath()); + getChartFile(); + + Log.i(LOGTAG, "cache hit: " + cacher.getCacheHitCount()); + Log.i(LOGTAG, "cache store: " + cacher.getCacheStoreCount()); + Log.i(LOGTAG, "conditional cache hit: " + cacher.getConditionalCacheHitCount()); + Log.i(LOGTAG, "network: " + cacher.getNetworkCount()); } + + private static final String LOGTAG = "AsyncSample"; } |