diff options
author | Koushik Dutta <koushd@gmail.com> | 2013-09-01 10:12:30 -0700 |
---|---|---|
committer | Koushik Dutta <koushd@gmail.com> | 2013-09-01 12:06:13 -0700 |
commit | 00878f8111d1255278dc984266f8664d2573e553 (patch) | |
tree | 75644ee4242593346f71f2754f4db23dc9cd780c | |
parent | 5e7f1df069c288a32a5910fc147919bffe264100 (diff) | |
download | AndroidAsync-00878f8111d1255278dc984266f8664d2573e553.tar.gz AndroidAsync-00878f8111d1255278dc984266f8664d2573e553.tar.bz2 AndroidAsync-00878f8111d1255278dc984266f8664d2573e553.zip |
Fix up keep-alive handling.
Fix up Range/Content-Length calculations.
Fix up header logging. (TODO: dont call toHeaderString)
Change-Id: I3cdcdca179a5b7ddcbdaa582590e60f52cd5c515
8 files changed, 61 insertions, 31 deletions
diff --git a/AndroidAsync/src/com/koushikdutta/async/http/AsyncHttpClient.java b/AndroidAsync/src/com/koushikdutta/async/http/AsyncHttpClient.java index d5df003..0989fe8 100644 --- a/AndroidAsync/src/com/koushikdutta/async/http/AsyncHttpClient.java +++ b/AndroidAsync/src/com/koushikdutta/async/http/AsyncHttpClient.java @@ -255,7 +255,7 @@ public class AsyncHttpClient { return; } - request.logv("Final (post cache response) headers: " + mHeaders.getHeaders().toHeaderString()); + request.logv("Final (post cache response) headers:\n" + mHeaders.getHeaders().toHeaderString()); // at this point the headers are done being modified reportConnectedCompleted(cancel, null, this, request, callback); @@ -271,7 +271,7 @@ public class AsyncHttpClient { mServer.removeAllCallbacks(cancel.scheduled); // allow the middleware to massage the headers before the body is decoded - request.logv("Received headers: " + mHeaders.getHeaders().toHeaderString()); + request.logv("Received headers:\n" + mHeaders.getHeaders().toHeaderString()); data.headers = mHeaders; synchronized (mMiddleware) { diff --git a/AndroidAsync/src/com/koushikdutta/async/http/AsyncHttpRequest.java b/AndroidAsync/src/com/koushikdutta/async/http/AsyncHttpRequest.java index 37957ae..2c77a0e 100644 --- a/AndroidAsync/src/com/koushikdutta/async/http/AsyncHttpRequest.java +++ b/AndroidAsync/src/com/koushikdutta/async/http/AsyncHttpRequest.java @@ -71,7 +71,7 @@ public class AsyncHttpRequest { }; } - protected final String getDefaultUserAgent() { + protected static String getDefaultUserAgent() { String agent = System.getProperty("http.agent"); return agent != null ? agent : ("Java" + System.getProperty("java.version")); } @@ -93,23 +93,28 @@ public class AsyncHttpRequest { this(uri, method, null); } + public static void setDefaultHeaders(RawHeaders ret, URI uri) { + String host = uri.getHost(); + if (uri.getPort() != -1) + host = host + ":" + uri.getPort(); + ret.set("Host", host); + ret.set("User-Agent", getDefaultUserAgent()); + ret.set("Accept-Encoding", "gzip, deflate"); + ret.set("Connection", "keep-alive"); + ret.set("Accept", "*/*"); + } + public AsyncHttpRequest(URI uri, String method, RawHeaders headers) { assert uri != null; mMethod = method; if (headers == null) - headers = new RawHeaders(); - mRawHeaders = headers; + mRawHeaders = new RawHeaders(); + else + mRawHeaders = headers; + if (headers == null) + setDefaultHeaders(mRawHeaders, uri); mHeaders = new RequestHeaders(uri, mRawHeaders); mRawHeaders.setStatusLine(getRequestLine().toString()); - String host = uri.getHost(); - if (uri.getPort() != -1) - host = host + ":" + uri.getPort(); - mHeaders.setHost(host); - if (mHeaders.getUserAgent() == null) - mHeaders.setUserAgent(getDefaultUserAgent()); - mHeaders.setAcceptEncoding("gzip, deflate"); - mHeaders.setConnection("keep-alive"); - mHeaders.getHeaders().set("Accept", "*/*"); } public URI getUri() { diff --git a/AndroidAsync/src/com/koushikdutta/async/http/AsyncHttpResponseImpl.java b/AndroidAsync/src/com/koushikdutta/async/http/AsyncHttpResponseImpl.java index 17593e2..192b5fb 100644 --- a/AndroidAsync/src/com/koushikdutta/async/http/AsyncHttpResponseImpl.java +++ b/AndroidAsync/src/com/koushikdutta/async/http/AsyncHttpResponseImpl.java @@ -38,7 +38,8 @@ abstract class AsyncHttpResponseImpl extends FilteredDataEmitter implements Asyn mWriter = mRequest.getBody(); if (mWriter != null) { - mRequest.getHeaders().setContentType(mWriter.getContentType()); + if (mRequest.getHeaders().getContentType() == null) + mRequest.getHeaders().setContentType(mWriter.getContentType()); if (mWriter.length() != -1) { mRequest.getHeaders().setContentLength(mWriter.length()); mSink = mSocket; @@ -61,7 +62,7 @@ abstract class AsyncHttpResponseImpl extends FilteredDataEmitter implements Asyn }); String rs = mRequest.getRequestString(); - mRequest.logv(rs); + mRequest.logv("\n" + rs); com.koushikdutta.async.Util.writeAll(exchange, rs.getBytes(), new CompletedCallback() { @Override public void onCompleted(Exception ex) { diff --git a/AndroidAsync/src/com/koushikdutta/async/http/AsyncSocketMiddleware.java b/AndroidAsync/src/com/koushikdutta/async/http/AsyncSocketMiddleware.java index bced70e..ea63a7d 100644 --- a/AndroidAsync/src/com/koushikdutta/async/http/AsyncSocketMiddleware.java +++ b/AndroidAsync/src/com/koushikdutta/async/http/AsyncSocketMiddleware.java @@ -267,15 +267,15 @@ public class AsyncSocketMiddleware extends SimpleMiddleware { idleSocket(data.socket); if (data.exception != null || !data.socket.isOpen()) { + data.request.logv("closing out socket (exception)"); data.socket.close(); return; } - String kas = data.headers.getConnection(); - if (kas == null || !"keep-alive".toLowerCase().equals(kas.toLowerCase())) { + if (!HttpUtil.isKeepAlive(data.headers.getHeaders())) { + data.request.logv("closing out socket (not keep alive)"); data.socket.close(); return; } - data.request.logd("Recycling keep-alive socket"); recycleSocket(data.socket, data.request); } diff --git a/AndroidAsync/src/com/koushikdutta/async/http/HttpUtil.java b/AndroidAsync/src/com/koushikdutta/async/http/HttpUtil.java index 09926ef..9e6cd9c 100644 --- a/AndroidAsync/src/com/koushikdutta/async/http/HttpUtil.java +++ b/AndroidAsync/src/com/koushikdutta/async/http/HttpUtil.java @@ -117,4 +117,17 @@ public class HttpUtil { // the close/end event until the server actually closes the connection. return emitter; } + + public static boolean isKeepAlive(RawHeaders headers) { + boolean keepAlive; + String connection = headers.get("Connection"); + if (connection != null) { + keepAlive = "keep-alive".equalsIgnoreCase(connection); + } + else { + keepAlive = headers.getHttpMinorVersion() >= 1; + } + + return keepAlive; + } } diff --git a/AndroidAsync/src/com/koushikdutta/async/http/server/AsyncHttpServer.java b/AndroidAsync/src/com/koushikdutta/async/http/server/AsyncHttpServer.java index 8964e8a..08ff1b1 100644 --- a/AndroidAsync/src/com/koushikdutta/async/http/server/AsyncHttpServer.java +++ b/AndroidAsync/src/com/koushikdutta/async/http/server/AsyncHttpServer.java @@ -15,6 +15,7 @@ import com.koushikdutta.async.callback.CompletedCallback; import com.koushikdutta.async.callback.ListenCallback; import com.koushikdutta.async.http.AsyncHttpGet; import com.koushikdutta.async.http.AsyncHttpPost; +import com.koushikdutta.async.http.HttpUtil; import com.koushikdutta.async.http.Multimap; import com.koushikdutta.async.http.WebSocket; import com.koushikdutta.async.http.WebSocketImpl; @@ -155,7 +156,12 @@ public class AsyncHttpServer { private void handleOnCompleted() { if (requestComplete && responseComplete) { - onAccepted(socket); + if (HttpUtil.isKeepAlive(getHeaders().getHeaders())) { + onAccepted(socket); + } + else { + socket.close(); + } } } diff --git a/AndroidAsync/src/com/koushikdutta/async/http/server/AsyncHttpServerResponseImpl.java b/AndroidAsync/src/com/koushikdutta/async/http/server/AsyncHttpServerResponseImpl.java index 9fd6737..afc0fee 100644 --- a/AndroidAsync/src/com/koushikdutta/async/http/server/AsyncHttpServerResponseImpl.java +++ b/AndroidAsync/src/com/koushikdutta/async/http/server/AsyncHttpServerResponseImpl.java @@ -2,21 +2,24 @@ package com.koushikdutta.async.http.server; import android.text.TextUtils; -import com.koushikdutta.async.*; +import com.koushikdutta.async.AsyncServer; +import com.koushikdutta.async.AsyncSocket; +import com.koushikdutta.async.ByteBufferList; +import com.koushikdutta.async.DataSink; +import com.koushikdutta.async.Util; import com.koushikdutta.async.callback.CompletedCallback; import com.koushikdutta.async.callback.WritableCallback; +import com.koushikdutta.async.http.HttpUtil; import com.koushikdutta.async.http.filter.ChunkedOutputFilter; import com.koushikdutta.async.http.libcore.RawHeaders; import com.koushikdutta.async.http.libcore.ResponseHeaders; + import org.json.JSONObject; import java.io.File; import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; import java.io.UnsupportedEncodingException; import java.nio.ByteBuffer; -import java.sql.Connection; public class AsyncHttpServerResponseImpl implements AsyncHttpServerResponse { private RawHeaders mRawHeaders = new RawHeaders(); @@ -37,7 +40,7 @@ public class AsyncHttpServerResponseImpl implements AsyncHttpServerResponse { AsyncHttpServerResponseImpl(AsyncSocket socket, AsyncHttpServerRequestImpl req) { mSocket = socket; mRequest = req; - if ("Keep-Alive".equalsIgnoreCase(req.getHeaders().getHeaders().get(" Connection "))) + if (HttpUtil.isKeepAlive(req.getHeaders().getHeaders())) mRawHeaders.set("Connection", "Keep-Alive"); } @@ -189,7 +192,7 @@ public class AsyncHttpServerResponseImpl implements AsyncHttpServerResponse { public void sendFile(File file) { int start = 0; - int end = (int)file.length(); + int end = (int)file.length() - 1; String range = mRequest.getHeaders().getHeaders().get("Range"); if (range != null) { @@ -210,12 +213,12 @@ public class AsyncHttpServerResponseImpl implements AsyncHttpServerResponse { if (parts.length == 2 && !TextUtils.isEmpty(parts[1])) end = Integer.parseInt(parts[1]); else if (start != 0) - end = (int)file.length(); + end = (int)file.length() - 1; else - end = Math.min((int)file.length(), start + 50000); + end = Math.min((int)file.length() - 1, 50000); responseCode(206); - getHeaders().getHeaders().set("Content-Range", String.format("bytes %d-%d/%d", start, end - 1, file.length())); + getHeaders().getHeaders().set("Content-Range", String.format("bytes %d-%d/%d", start, end, file.length())); } catch (Exception e) { responseCode(416); @@ -228,11 +231,11 @@ public class AsyncHttpServerResponseImpl implements AsyncHttpServerResponse { if (start != fin.skip(start)) throw new Exception("skip failed to skip requested amount"); mRawHeaders.set("Content-Type", AsyncHttpServer.getContentType(file.getAbsolutePath())); - mContentLength = end - start; + mContentLength = end - start + 1; mRawHeaders.set("Content-Length", "" + mContentLength); if (getHeaders().getHeaders().getStatusLine() == null) responseCode(200); - Util.pump(fin, end - start, this, new CompletedCallback() { + Util.pump(fin, mContentLength, this, new CompletedCallback() { @Override public void onCompleted(Exception ex) { onEnd(); diff --git a/AndroidAsyncTest/src/com/koushikdutta/async/test/HttpServerTests.java b/AndroidAsyncTest/src/com/koushikdutta/async/test/HttpServerTests.java index d0cab89..3d6ca3c 100644 --- a/AndroidAsyncTest/src/com/koushikdutta/async/test/HttpServerTests.java +++ b/AndroidAsyncTest/src/com/koushikdutta/async/test/HttpServerTests.java @@ -48,6 +48,7 @@ public class HttpServerTests extends TestCase { httpServer.get("/hello", new HttpServerRequestCallback() { @Override public void onRequest(AsyncHttpServerRequest request, AsyncHttpServerResponse response) { + assertNotNull(request.getHeaders().getHost()); response.send("hello"); } }); @@ -56,6 +57,7 @@ public class HttpServerTests extends TestCase { @Override public void onRequest(AsyncHttpServerRequest request, final AsyncHttpServerResponse response) { try { + assertNotNull(request.getHeaders().getHost()); JSONObject json = new JSONObject(); if (request.getBody() instanceof UrlEncodedFormBody) { UrlEncodedFormBody body = (UrlEncodedFormBody)request.getBody(); |