aboutsummaryrefslogtreecommitdiffstats
path: root/AndroidAsync
diff options
context:
space:
mode:
authorKoushik Dutta <koushd@gmail.com>2014-07-28 20:07:37 -0700
committerKoushik Dutta <koushd@gmail.com>2014-07-28 20:07:37 -0700
commit1280d7b44e14dbac19f773136742224bcab91302 (patch)
treeb0409cb1a6c26347891b141157c0b4ec4d9711cb /AndroidAsync
parent9ec1a8ded7e3b59da7c2b53ebe0e4cf4ece566e1 (diff)
downloadAndroidAsync-1280d7b44e14dbac19f773136742224bcab91302.tar.gz
AndroidAsync-1280d7b44e14dbac19f773136742224bcab91302.tar.bz2
AndroidAsync-1280d7b44e14dbac19f773136742224bcab91302.zip
spdy posting works.
Diffstat (limited to 'AndroidAsync')
-rw-r--r--AndroidAsync/src/com/koushikdutta/async/http/AsyncHttpClient.java24
-rw-r--r--AndroidAsync/src/com/koushikdutta/async/http/AsyncHttpClientMiddleware.java29
-rw-r--r--AndroidAsync/src/com/koushikdutta/async/http/AsyncHttpResponseImpl.java3
-rw-r--r--AndroidAsync/src/com/koushikdutta/async/http/AsyncSocketMiddleware.java2
-rw-r--r--AndroidAsync/src/com/koushikdutta/async/http/Headers.java19
-rw-r--r--AndroidAsync/src/com/koushikdutta/async/http/HttpTransportMiddleware.java14
-rw-r--r--AndroidAsync/src/com/koushikdutta/async/http/SimpleMiddleware.java14
-rw-r--r--AndroidAsync/src/com/koushikdutta/async/http/body/MultipartFormDataBody.java6
-rw-r--r--AndroidAsync/src/com/koushikdutta/async/http/body/UrlEncodedFormBody.java1
-rw-r--r--AndroidAsync/src/com/koushikdutta/async/http/cache/ResponseCacheMiddleware.java4
-rw-r--r--AndroidAsync/src/com/koushikdutta/async/http/filter/ChunkedOutputFilter.java3
-rw-r--r--AndroidAsync/src/com/koushikdutta/async/http/server/BoundaryEmitter.java1
-rw-r--r--AndroidAsync/src/com/koushikdutta/async/http/spdy/AsyncSpdyConnection.java30
-rw-r--r--AndroidAsync/src/com/koushikdutta/async/http/spdy/Spdy3.java2
-rw-r--r--AndroidAsync/src/com/koushikdutta/async/http/spdy/SpdyMiddleware.java235
15 files changed, 236 insertions, 151 deletions
diff --git a/AndroidAsync/src/com/koushikdutta/async/http/AsyncHttpClient.java b/AndroidAsync/src/com/koushikdutta/async/http/AsyncHttpClient.java
index ee4f805..49c7de5 100644
--- a/AndroidAsync/src/com/koushikdutta/async/http/AsyncHttpClient.java
+++ b/AndroidAsync/src/com/koushikdutta/async/http/AsyncHttpClient.java
@@ -17,7 +17,6 @@ import com.koushikdutta.async.future.Cancellable;
import com.koushikdutta.async.future.Future;
import com.koushikdutta.async.future.FutureCallback;
import com.koushikdutta.async.future.SimpleFuture;
-import com.koushikdutta.async.http.AsyncHttpClientMiddleware.OnRequestCompleteData;
import com.koushikdutta.async.http.callback.HttpConnectCallback;
import com.koushikdutta.async.http.callback.RequestCallback;
import com.koushikdutta.async.parser.AsyncParser;
@@ -204,7 +203,7 @@ public class AsyncHttpClient {
return;
}
final Uri uri = request.getUri();
- final OnRequestCompleteData data = new OnRequestCompleteData();
+ final AsyncHttpClientMiddleware.OnResponseCompleteDataOnRequestSentData data = new AsyncHttpClientMiddleware.OnResponseCompleteDataOnRequestSentData();
request.executionTime = System.currentTimeMillis();
data.request = request;
@@ -273,6 +272,12 @@ public class AsyncHttpClient {
// set up the system default proxy and connect
setupAndroidProxy(request);
+ // set the implicit content type
+ if (request.getBody() != null) {
+ if (request.getHeaders().get("Content-Type") == null)
+ request.getHeaders().set("Content-Type", request.getBody().getContentType());
+ }
+
synchronized (mMiddleware) {
for (AsyncHttpClientMiddleware middleware: mMiddleware) {
Cancellable socketCancellable = middleware.getSocket(data);
@@ -288,13 +293,18 @@ public class AsyncHttpClient {
private void executeSocket(final AsyncHttpRequest request, final int redirectCount,
final FutureAsyncHttpResponse cancel, final HttpConnectCallback callback,
- final OnRequestCompleteData data) {
+ final AsyncHttpClientMiddleware.OnResponseCompleteDataOnRequestSentData data) {
// 4) wait for request to be sent fully
// and
// 6) wait for headers
final AsyncHttpResponseImpl ret = new AsyncHttpResponseImpl(request) {
@Override
protected void onRequestCompleted(Exception ex) {
+ if (ex != null) {
+ reportConnectedCompleted(cancel, ex, null, request, callback);
+ return;
+ }
+
request.logv("request completed");
if (cancel.isCancelled())
return;
@@ -303,6 +313,12 @@ public class AsyncHttpClient {
mServer.removeAllCallbacks(cancel.scheduled);
cancel.scheduled = mServer.postDelayed(cancel.timeoutRunnable, getTimeoutRemaining(request));
}
+
+ synchronized (mMiddleware) {
+ for (AsyncHttpClientMiddleware middleware: mMiddleware) {
+ middleware.onRequestSent(data);
+ }
+ }
}
@Override
@@ -402,7 +418,7 @@ public class AsyncHttpClient {
data.exception = ex;
synchronized (mMiddleware) {
for (AsyncHttpClientMiddleware middleware: mMiddleware) {
- middleware.onRequestComplete(data);
+ middleware.onResponseComplete(data);
}
}
}
diff --git a/AndroidAsync/src/com/koushikdutta/async/http/AsyncHttpClientMiddleware.java b/AndroidAsync/src/com/koushikdutta/async/http/AsyncHttpClientMiddleware.java
index edce25d..48be209 100644
--- a/AndroidAsync/src/com/koushikdutta/async/http/AsyncHttpClientMiddleware.java
+++ b/AndroidAsync/src/com/koushikdutta/async/http/AsyncHttpClientMiddleware.java
@@ -40,21 +40,24 @@ public interface AsyncHttpClientMiddleware {
public String protocol;
}
- public static class ExchangeHeaderData extends GetSocketData {
+ public static class OnExchangeHeaderData extends GetSocketData {
public AsyncSocket socket;
public ResponseHead response;
public CompletedCallback sendHeadersCallback;
public CompletedCallback receiveHeadersCallback;
}
- public static class OnHeadersReceivedData extends ExchangeHeaderData {
+ public static class OnRequestSentData extends OnExchangeHeaderData {
}
- public static class OnBodyData extends OnHeadersReceivedData {
+ public static class OnHeadersReceivedDataOnRequestSentData extends OnRequestSentData {
+ }
+
+ public static class OnBodyDataOnRequestSentData extends OnHeadersReceivedDataOnRequestSentData {
public DataEmitter bodyEmitter;
}
- public static class OnRequestCompleteData extends OnBodyData {
+ public static class OnResponseCompleteDataOnRequestSentData extends OnBodyDataOnRequestSentData {
public Exception exception;
}
@@ -77,23 +80,31 @@ public interface AsyncHttpClientMiddleware {
* @param data
* @return
*/
- public boolean exchangeHeaders(ExchangeHeaderData data);
+ public boolean exchangeHeaders(OnExchangeHeaderData data);
+
+ /**
+ * Called once the headers and any optional request body has
+ * been sent
+ * @param data
+ */
+ public void onRequestSent(OnRequestSentData data);
/**
* Called once the headers have been received via the socket
* @param data
*/
- public void onHeadersReceived(OnHeadersReceivedData data);
+ public void onHeadersReceived(OnHeadersReceivedDataOnRequestSentData data);
/**
* Called before the body is decoded
* @param data
*/
- public void onBodyDecoder(OnBodyData data);
+ public void onBodyDecoder(OnBodyDataOnRequestSentData data);
/**
- * Called once the request is complete
+ * Called once the request is complete and response has been received,
+ * or if an error occurred
* @param data
*/
- public void onRequestComplete(OnRequestCompleteData data);
+ public void onResponseComplete(OnResponseCompleteDataOnRequestSentData data);
}
diff --git a/AndroidAsync/src/com/koushikdutta/async/http/AsyncHttpResponseImpl.java b/AndroidAsync/src/com/koushikdutta/async/http/AsyncHttpResponseImpl.java
index 7938b93..cd6ffff 100644
--- a/AndroidAsync/src/com/koushikdutta/async/http/AsyncHttpResponseImpl.java
+++ b/AndroidAsync/src/com/koushikdutta/async/http/AsyncHttpResponseImpl.java
@@ -193,8 +193,7 @@ abstract class AsyncHttpResponseImpl extends FilteredDataEmitter implements Asyn
@Override
public void end() {
- if (mSink instanceof ChunkedOutputFilter)
- mSink.end();
+ throw new AssertionError("end called?");
}
@Override
diff --git a/AndroidAsync/src/com/koushikdutta/async/http/AsyncSocketMiddleware.java b/AndroidAsync/src/com/koushikdutta/async/http/AsyncSocketMiddleware.java
index 5c11684..35ce3dd 100644
--- a/AndroidAsync/src/com/koushikdutta/async/http/AsyncSocketMiddleware.java
+++ b/AndroidAsync/src/com/koushikdutta/async/http/AsyncSocketMiddleware.java
@@ -345,7 +345,7 @@ public class AsyncSocketMiddleware extends SimpleMiddleware {
}
@Override
- public void onRequestComplete(final OnRequestCompleteData data) {
+ public void onResponseComplete(final OnResponseCompleteDataOnRequestSentData data) {
if (!data.state.get(getClass().getCanonicalName() + ".owned", false)) {
return;
}
diff --git a/AndroidAsync/src/com/koushikdutta/async/http/Headers.java b/AndroidAsync/src/com/koushikdutta/async/http/Headers.java
index 8fb7025..1b4cdc2 100644
--- a/AndroidAsync/src/com/koushikdutta/async/http/Headers.java
+++ b/AndroidAsync/src/com/koushikdutta/async/http/Headers.java
@@ -29,20 +29,20 @@ public class Headers {
}
public List<String> getAll(String header) {
- return map.get(header);
+ return map.get(header.toLowerCase());
}
public String get(String header) {
- return map.getString(header);
+ return map.getString(header.toLowerCase());
}
public Headers set(String header, String value) {
- map.put(header, value);
+ map.put(header.toLowerCase(), value);
return this;
}
public Headers add(String header, String value) {
- map.add(header, value);
+ map.add(header.toLowerCase(), value);
return this;
}
@@ -66,21 +66,26 @@ public class Headers {
}
public Headers addAll(Map<String, List<String>> m) {
- map.putAll(m);
+ for (String key: m.keySet()) {
+ for (String value: m.get(key)) {
+ add(key, value);
+ }
+ }
return this;
}
public Headers addAll(Headers headers) {
+ // safe to addall since this is another Headers object
map.putAll(headers.map);
return this;
}
public List<String> removeAll(String header) {
- return map.remove(header);
+ return map.remove(header.toLowerCase());
}
public String remove(String header) {
- List<String> r = removeAll(header);
+ List<String> r = removeAll(header.toLowerCase());
if (r == null || r.size() == 0)
return null;
return r.get(0);
diff --git a/AndroidAsync/src/com/koushikdutta/async/http/HttpTransportMiddleware.java b/AndroidAsync/src/com/koushikdutta/async/http/HttpTransportMiddleware.java
index 837ca92..6659193 100644
--- a/AndroidAsync/src/com/koushikdutta/async/http/HttpTransportMiddleware.java
+++ b/AndroidAsync/src/com/koushikdutta/async/http/HttpTransportMiddleware.java
@@ -14,7 +14,7 @@ import java.io.IOException;
*/
public class HttpTransportMiddleware extends SimpleMiddleware {
@Override
- public boolean exchangeHeaders(final ExchangeHeaderData data) {
+ public boolean exchangeHeaders(final OnExchangeHeaderData data) {
Protocol p = Protocol.get(data.protocol);
if (p != null && p != Protocol.HTTP_1_0 && p != Protocol.HTTP_1_1)
return super.exchangeHeaders(data);
@@ -23,8 +23,6 @@ public class HttpTransportMiddleware extends SimpleMiddleware {
AsyncHttpRequestBody requestBody = data.request.getBody();
if (requestBody != null) {
- if (request.getHeaders().get("Content-Type") == null)
- request.getHeaders().set("Content-Type", requestBody.getContentType());
if (requestBody.length() >= 0) {
request.getHeaders().set("Content-Length", String.valueOf(requestBody.length()));
data.response.sink(data.socket);
@@ -92,4 +90,14 @@ public class HttpTransportMiddleware extends SimpleMiddleware {
liner.setLineCallback(headerCallback);
return true;
}
+
+ @Override
+ public void onRequestSent(OnRequestSentData data) {
+ Protocol p = Protocol.get(data.protocol);
+ if (p != null && p != Protocol.HTTP_1_0 && p != Protocol.HTTP_1_1)
+ return;
+
+ if (data.response.sink() instanceof ChunkedOutputFilter)
+ data.response.sink().end();
+ }
}
diff --git a/AndroidAsync/src/com/koushikdutta/async/http/SimpleMiddleware.java b/AndroidAsync/src/com/koushikdutta/async/http/SimpleMiddleware.java
index 242fdab..8b2998a 100644
--- a/AndroidAsync/src/com/koushikdutta/async/http/SimpleMiddleware.java
+++ b/AndroidAsync/src/com/koushikdutta/async/http/SimpleMiddleware.java
@@ -13,19 +13,23 @@ public class SimpleMiddleware implements AsyncHttpClientMiddleware {
}
@Override
- public void onHeadersReceived(OnHeadersReceivedData data) {
+ public boolean exchangeHeaders(OnExchangeHeaderData data) {
+ return false;
}
@Override
- public void onBodyDecoder(OnBodyData data) {
+ public void onRequestSent(OnRequestSentData data) {
}
@Override
- public void onRequestComplete(OnRequestCompleteData data) {
+ public void onHeadersReceived(OnHeadersReceivedDataOnRequestSentData data) {
}
@Override
- public boolean exchangeHeaders(ExchangeHeaderData data) {
- return false;
+ public void onBodyDecoder(OnBodyDataOnRequestSentData data) {
+ }
+
+ @Override
+ public void onResponseComplete(OnResponseCompleteDataOnRequestSentData data) {
}
}
diff --git a/AndroidAsync/src/com/koushikdutta/async/http/body/MultipartFormDataBody.java b/AndroidAsync/src/com/koushikdutta/async/http/body/MultipartFormDataBody.java
index 309d9c3..4cf41f2 100644
--- a/AndroidAsync/src/com/koushikdutta/async/http/body/MultipartFormDataBody.java
+++ b/AndroidAsync/src/com/koushikdutta/async/http/body/MultipartFormDataBody.java
@@ -126,11 +126,9 @@ public class MultipartFormDataBody extends BoundaryEmitter implements AsyncHttpR
int written;
@Override
public void write(AsyncHttpRequest request, final DataSink sink, final CompletedCallback completed) {
- if (mParts == null) {
- sink.end();
+ if (mParts == null)
return;
- }
-
+
Continuation c = new Continuation(new CompletedCallback() {
@Override
public void onCompleted(Exception ex) {
diff --git a/AndroidAsync/src/com/koushikdutta/async/http/body/UrlEncodedFormBody.java b/AndroidAsync/src/com/koushikdutta/async/http/body/UrlEncodedFormBody.java
index b50b7c7..b52fc75 100644
--- a/AndroidAsync/src/com/koushikdutta/async/http/body/UrlEncodedFormBody.java
+++ b/AndroidAsync/src/com/koushikdutta/async/http/body/UrlEncodedFormBody.java
@@ -45,6 +45,7 @@ public class UrlEncodedFormBody implements AsyncHttpRequestBody<Multimap> {
mBodyBytes = b.toString().getBytes("ISO-8859-1");
}
catch (UnsupportedEncodingException e) {
+ throw new AssertionError(e);
}
}
diff --git a/AndroidAsync/src/com/koushikdutta/async/http/cache/ResponseCacheMiddleware.java b/AndroidAsync/src/com/koushikdutta/async/http/cache/ResponseCacheMiddleware.java
index 57e3895..40aa530 100644
--- a/AndroidAsync/src/com/koushikdutta/async/http/cache/ResponseCacheMiddleware.java
+++ b/AndroidAsync/src/com/koushikdutta/async/http/cache/ResponseCacheMiddleware.java
@@ -213,7 +213,7 @@ public class ResponseCacheMiddleware extends SimpleMiddleware {
// step 2) 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) {
+ public void onBodyDecoder(OnBodyDataOnRequestSentData data) {
CachedSocket cached = com.koushikdutta.async.Util.getWrappedSocket(data.socket, CachedSocket.class);
if (cached != null) {
data.response.headers().set(SERVED_FROM, CACHE);
@@ -292,7 +292,7 @@ public class ResponseCacheMiddleware extends SimpleMiddleware {
// step 3: close up shop
@Override
- public void onRequestComplete(OnRequestCompleteData data) {
+ public void onResponseComplete(OnResponseCompleteDataOnRequestSentData data) {
CacheData cacheData = data.state.get("cache-data");
if (cacheData != null && cacheData.snapshot != null)
StreamUtility.closeQuietly(cacheData.snapshot);
diff --git a/AndroidAsync/src/com/koushikdutta/async/http/filter/ChunkedOutputFilter.java b/AndroidAsync/src/com/koushikdutta/async/http/filter/ChunkedOutputFilter.java
index f0f18d3..00d3f9e 100644
--- a/AndroidAsync/src/com/koushikdutta/async/http/filter/ChunkedOutputFilter.java
+++ b/AndroidAsync/src/com/koushikdutta/async/http/filter/ChunkedOutputFilter.java
@@ -25,6 +25,7 @@ public class ChunkedOutputFilter extends FilteredDataSink {
ByteBufferList fin = new ByteBufferList();
write(fin);
setMaxBuffer(0);
- super.end();
+ // do NOT call through to super.end, as chunking is a framing protocol.
+ // we don't want to close the underlying transport.
}
}
diff --git a/AndroidAsync/src/com/koushikdutta/async/http/server/BoundaryEmitter.java b/AndroidAsync/src/com/koushikdutta/async/http/server/BoundaryEmitter.java
index 3eab5e2..e642ba4 100644
--- a/AndroidAsync/src/com/koushikdutta/async/http/server/BoundaryEmitter.java
+++ b/AndroidAsync/src/com/koushikdutta/async/http/server/BoundaryEmitter.java
@@ -1,6 +1,5 @@
package com.koushikdutta.async.http.server;
-import android.util.Log;
import com.koushikdutta.async.ByteBufferList;
import com.koushikdutta.async.DataEmitter;
import com.koushikdutta.async.FilteredDataEmitter;
diff --git a/AndroidAsync/src/com/koushikdutta/async/http/spdy/AsyncSpdyConnection.java b/AndroidAsync/src/com/koushikdutta/async/http/spdy/AsyncSpdyConnection.java
index aca08f2..29b7fb8 100644
--- a/AndroidAsync/src/com/koushikdutta/async/http/spdy/AsyncSpdyConnection.java
+++ b/AndroidAsync/src/com/koushikdutta/async/http/spdy/AsyncSpdyConnection.java
@@ -94,7 +94,7 @@ public class AsyncSpdyConnection implements FrameReader.Handler {
}
public class SpdySocket implements AsyncSocket {
- long bytesLeftInWriteWindow;
+ long bytesLeftInWriteWindow = AsyncSpdyConnection.this.peerSettings.getInitialWindowSize(Settings.DEFAULT_INITIAL_WINDOW_SIZE);
WritableCallback writable;
final int id;
CompletedCallback closedCallback;
@@ -195,9 +195,29 @@ public class AsyncSpdyConnection implements FrameReader.Handler {
return null;
}
+ ByteBufferList writing = new ByteBufferList();
@Override
public void write(ByteBufferList bb) {
- System.out.println("writing!");
+ int canWrite = (int)Math.min(bytesLeftInWriteWindow, AsyncSpdyConnection.this.bytesLeftInWriteWindow);
+ canWrite = Math.min(bb.remaining(), canWrite);
+ if (canWrite == 0) {
+ System.out.println("derp");
+ return;
+ }
+ if (canWrite < bb.remaining()) {
+ if (writing.hasRemaining())
+ throw new AssertionError("wtf");
+ bb.get(writing, canWrite);
+ bb = writing;
+ }
+
+ try {
+ writer.data(false, id, bb);
+ bytesLeftInWriteWindow -= canWrite;
+ }
+ catch (IOException e) {
+ throw new AssertionError(e);
+ }
}
@Override
@@ -217,6 +237,12 @@ public class AsyncSpdyConnection implements FrameReader.Handler {
@Override
public void end() {
+ try {
+ writer.data(true, id, writing);
+ }
+ catch (IOException e) {
+ throw new AssertionError(e);
+ }
}
@Override
diff --git a/AndroidAsync/src/com/koushikdutta/async/http/spdy/Spdy3.java b/AndroidAsync/src/com/koushikdutta/async/http/spdy/Spdy3.java
index 35f4e6e..ddea2f2 100644
--- a/AndroidAsync/src/com/koushikdutta/async/http/spdy/Spdy3.java
+++ b/AndroidAsync/src/com/koushikdutta/async/http/spdy/Spdy3.java
@@ -167,12 +167,12 @@ final class Spdy3 implements Variant {
}
};
+ ByteBufferList partial = new ByteBufferList();
private final DataCallback onDataFrame = new DataCallback() {
@Override
public void onDataAvailable(DataEmitter emitter, ByteBufferList bb) {
int toRead = Math.min(bb.remaining(), length);
if (toRead < bb.remaining()) {
- ByteBufferList partial = new ByteBufferList();
bb.get(partial, toRead);
bb = partial;
}
diff --git a/AndroidAsync/src/com/koushikdutta/async/http/spdy/SpdyMiddleware.java b/AndroidAsync/src/com/koushikdutta/async/http/spdy/SpdyMiddleware.java
index 1ac43d5..b5a608c 100644
--- a/AndroidAsync/src/com/koushikdutta/async/http/spdy/SpdyMiddleware.java
+++ b/AndroidAsync/src/com/koushikdutta/async/http/spdy/SpdyMiddleware.java
@@ -16,6 +16,7 @@ import com.koushikdutta.async.http.AsyncSSLSocketMiddleware;
import com.koushikdutta.async.http.Headers;
import com.koushikdutta.async.http.Multimap;
import com.koushikdutta.async.http.Protocol;
+import com.koushikdutta.async.http.body.AsyncHttpRequestBody;
import com.koushikdutta.async.util.Charsets;
import java.lang.reflect.Field;
@@ -39,6 +40,94 @@ public class SpdyMiddleware extends AsyncSSLSocketMiddleware {
});
}
+ private void configure(SSLEngine engine, String host, int port) {
+ if (!initialized) {
+ initialized = true;
+ try {
+ peerHost = engine.getClass().getSuperclass().getDeclaredField("peerHost");
+ peerPort = engine.getClass().getSuperclass().getDeclaredField("peerPort");
+ sslParameters = engine.getClass().getDeclaredField("sslParameters");
+ npnProtocols = sslParameters.getType().getDeclaredField("npnProtocols");
+ alpnProtocols = sslParameters.getType().getDeclaredField("alpnProtocols");
+ useSni = sslParameters.getType().getDeclaredField("useSni");
+ sslNativePointer = engine.getClass().getDeclaredField("sslNativePointer");
+ String nativeCryptoName = sslParameters.getType().getPackage().getName() + ".NativeCrypto";
+ nativeGetNpnNegotiatedProtocol = Class.forName(nativeCryptoName, true, sslParameters.getType().getClassLoader())
+ .getDeclaredMethod("SSL_get_npn_negotiated_protocol", long.class);
+ nativeGetAlpnNegotiatedProtocol = Class.forName(nativeCryptoName, true, sslParameters.getType().getClassLoader())
+ .getDeclaredMethod("SSL_get0_alpn_selected", long.class);
+
+ peerHost.setAccessible(true);
+ peerPort.setAccessible(true);
+ sslParameters.setAccessible(true);
+ npnProtocols.setAccessible(true);
+ alpnProtocols.setAccessible(true);
+ useSni.setAccessible(true);
+ sslNativePointer.setAccessible(true);
+ nativeGetNpnNegotiatedProtocol.setAccessible(true);
+ nativeGetAlpnNegotiatedProtocol.setAccessible(true);
+ }
+ catch (Exception e) {
+ sslParameters = null;
+ npnProtocols = null;
+ alpnProtocols = null;
+ useSni = null;
+ sslNativePointer = null;
+ nativeGetNpnNegotiatedProtocol = null;
+ nativeGetAlpnNegotiatedProtocol = null;
+ }
+ }
+
+ if (sslParameters != null) {
+ try {
+ byte[] protocols = concatLengthPrefixed(
+ Protocol.HTTP_1_1,
+ Protocol.SPDY_3
+ );
+
+ peerHost.set(engine, host);
+ peerPort.set(engine, port);
+ Object sslp = sslParameters.get(engine);
+// npnProtocols.set(sslp, protocols);
+ alpnProtocols.set(sslp, protocols);
+ useSni.set(sslp, true);
+ }
+ catch (Exception e ) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ @Override
+ protected SSLEngine createConfiguredSSLEngine(String host, int port) {
+ SSLContext sslContext = getSSLContext();
+ SSLEngine sslEngine = sslContext.createSSLEngine();
+
+ for (AsyncSSLEngineConfigurator configurator : engineConfigurators) {
+ configurator.configureEngine(sslEngine, host, port);
+ }
+
+ return sslEngine;
+ }
+
+ boolean initialized;
+ Field peerHost;
+ Field peerPort;
+ Field sslParameters;
+ Field npnProtocols;
+ Field alpnProtocols;
+ Field sslNativePointer;
+ Field useSni;
+ Method nativeGetNpnNegotiatedProtocol;
+ Method nativeGetAlpnNegotiatedProtocol;
+ Hashtable<String, AsyncSpdyConnection> connections = new Hashtable<String, AsyncSpdyConnection>();
+
+ @Override
+ public void setSSLContext(SSLContext sslContext) {
+ super.setSSLContext(sslContext);
+ initialized = false;
+ }
+
static byte[] concatLengthPrefixed(Protocol... protocols) {
ByteBuffer result = ByteBuffer.allocate(8192);
for (Protocol protocol: protocols) {
@@ -80,6 +169,7 @@ public class SpdyMiddleware extends AsyncSSLSocketMiddleware {
callback.onConnectCompleted(null, socket);
return;
}
+ data.protocol = protoString;
final AsyncSpdyConnection connection = new AsyncSpdyConnection(socket, Protocol.get(protoString));
connection.sendConnectionPreface();
@@ -120,15 +210,44 @@ public class SpdyMiddleware extends AsyncSSLSocketMiddleware {
}
}
- AsyncSpdyConnection.SpdySocket spdy = connection.newStream(headers, false, true);
+ data.request.logv("\n" + data.request);
+ AsyncSpdyConnection.SpdySocket spdy = connection.newStream(headers, data.request.getBody() != null, true);
callback.onConnectCompleted(null, spdy);
}
@Override
- public boolean exchangeHeaders(final ExchangeHeaderData data) {
+ public Cancellable getSocket(GetSocketData data) {
+ final Uri uri = data.request.getUri();
+ final int port = getSchemePort(data.request.getUri());
+ if (port == -1) {
+ return null;
+ }
+
+ // can we use an existing connection to satisfy this, or do we need a new one?
+ String host = uri.getHost();
+ AsyncSpdyConnection conn = connections.get(host);
+ if (conn == null || !conn.socket.isOpen()) {
+ connections.remove(host);
+ return super.getSocket(data);
+ }
+
+ newSocket(data, conn, data.connectCallback);
+
+ SimpleCancellable ret = new SimpleCancellable();
+ ret.setComplete();
+ return ret;
+ }
+
+ @Override
+ public boolean exchangeHeaders(final OnExchangeHeaderData data) {
if (!(data.socket instanceof AsyncSpdyConnection.SpdySocket))
return false;
+ AsyncHttpRequestBody requestBody = data.request.getBody();
+ if (requestBody != null) {
+ data.response.sink(data.socket);
+ }
+
// headers were already sent as part of the socket being opened.
data.sendHeadersCallback.onCompleted(null);
@@ -162,114 +281,12 @@ public class SpdyMiddleware extends AsyncSSLSocketMiddleware {
return true;
}
- private void configure(SSLEngine engine, String host, int port) {
- if (!initialized) {
- initialized = true;
- try {
- peerHost = engine.getClass().getSuperclass().getDeclaredField("peerHost");
- peerPort = engine.getClass().getSuperclass().getDeclaredField("peerPort");
- sslParameters = engine.getClass().getDeclaredField("sslParameters");
- npnProtocols = sslParameters.getType().getDeclaredField("npnProtocols");
- alpnProtocols = sslParameters.getType().getDeclaredField("alpnProtocols");
- useSni = sslParameters.getType().getDeclaredField("useSni");
- sslNativePointer = engine.getClass().getDeclaredField("sslNativePointer");
- String nativeCryptoName = sslParameters.getType().getPackage().getName() + ".NativeCrypto";
- nativeGetNpnNegotiatedProtocol = Class.forName(nativeCryptoName, true, sslParameters.getType().getClassLoader())
- .getDeclaredMethod("SSL_get_npn_negotiated_protocol", long.class);
- nativeGetAlpnNegotiatedProtocol = Class.forName(nativeCryptoName, true, sslParameters.getType().getClassLoader())
- .getDeclaredMethod("SSL_get0_alpn_selected", long.class);
-
- peerHost.setAccessible(true);
- peerPort.setAccessible(true);
- sslParameters.setAccessible(true);
- npnProtocols.setAccessible(true);
- alpnProtocols.setAccessible(true);
- useSni.setAccessible(true);
- sslNativePointer.setAccessible(true);
- nativeGetNpnNegotiatedProtocol.setAccessible(true);
- nativeGetAlpnNegotiatedProtocol.setAccessible(true);
- }
- catch (Exception e) {
- sslParameters = null;
- npnProtocols = null;
- alpnProtocols = null;
- useSni = null;
- sslNativePointer = null;
- nativeGetNpnNegotiatedProtocol = null;
- nativeGetAlpnNegotiatedProtocol = null;
- }
- }
-
- if (sslParameters != null) {
- try {
- byte[] protocols = concatLengthPrefixed(
- Protocol.HTTP_1_1,
- Protocol.SPDY_3
- );
-
- peerHost.set(engine, host);
- peerPort.set(engine, port);
- Object sslp = sslParameters.get(engine);
-// npnProtocols.set(sslp, protocols);
- alpnProtocols.set(sslp, protocols);
- useSni.set(sslp, true);
- }
- catch (Exception e ) {
- e.printStackTrace();
- }
- }
- }
-
@Override
- protected SSLEngine createConfiguredSSLEngine(String host, int port) {
- SSLContext sslContext = getSSLContext();
- SSLEngine sslEngine = sslContext.createSSLEngine();
-
- for (AsyncSSLEngineConfigurator configurator : engineConfigurators) {
- configurator.configureEngine(sslEngine, host, port);
- }
-
- return sslEngine;
- }
-
- boolean initialized;
- Field peerHost;
- Field peerPort;
- Field sslParameters;
- Field npnProtocols;
- Field alpnProtocols;
- Field sslNativePointer;
- Field useSni;
- Method nativeGetNpnNegotiatedProtocol;
- Method nativeGetAlpnNegotiatedProtocol;
- Hashtable<String, AsyncSpdyConnection> connections = new Hashtable<String, AsyncSpdyConnection>();
-
- @Override
- public void setSSLContext(SSLContext sslContext) {
- super.setSSLContext(sslContext);
- initialized = false;
- }
-
- @Override
- public Cancellable getSocket(GetSocketData data) {
- final Uri uri = data.request.getUri();
- final int port = getSchemePort(data.request.getUri());
- if (port == -1) {
- return null;
- }
-
- // can we use an existing connection to satisfy this, or do we need a new one?
- String host = uri.getHost();
- AsyncSpdyConnection conn = connections.get(host);
- if (conn == null || !conn.socket.isOpen()) {
- connections.remove(host);
- return super.getSocket(data);
- }
-
- newSocket(data, conn, data.connectCallback);
+ public void onRequestSent(OnRequestSentData data) {
+ if (!(data.socket instanceof AsyncSpdyConnection.SpdySocket))
+ return;
- SimpleCancellable ret = new SimpleCancellable();
- ret.setComplete();
- return ret;
+ if (data.request.getBody() != null)
+ data.response.sink().end();
}
} \ No newline at end of file