aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Becker2012-10-19 12:17:04 (EDT)
committerThomas Becker2012-10-19 12:17:29 (EDT)
commit8c3642754e1354e8e8fb2b521681391e5e529cf6 (patch)
tree93b6d044f51dbbdcd25792386dcca460b193ad3f
parentaa1a6347c1611c303025869309fcf6eed1cebbb3 (diff)
downloadorg.eclipse.jetty.project-8c3642754e1354e8e8fb2b521681391e5e529cf6.zip
org.eclipse.jetty.project-8c3642754e1354e8e8fb2b521681391e5e529cf6.tar.gz
org.eclipse.jetty.project-8c3642754e1354e8e8fb2b521681391e5e529cf6.tar.bz2
392470: Fix problem in suspend, expire cycle when HttpChannel.run() is called multiple times (happens for SPDY). Add test cases. Remove unused argument from HttpHandler.messageComplete() interface and it's implementations.
-rw-r--r--jetty-client/src/main/java/org/eclipse/jetty/client/HttpReceiver.java2
-rw-r--r--jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java28
-rw-r--r--jetty-http/src/main/java/org/eclipse/jetty/http/HttpTester.java2
-rw-r--r--jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorServerTest.java2
-rw-r--r--jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java2
-rw-r--r--jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java2
-rw-r--r--jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelState.java7
-rw-r--r--jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpChannelOverSPDY.java4
-rw-r--r--jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/ProxyHTTPSPDYConnection.java2
-rw-r--r--jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/ServerHTTPSPDYTest.java234
-rw-r--r--test-jetty-webapp/src/main/webapp/chat/index.html249
11 files changed, 327 insertions, 207 deletions
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpReceiver.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpReceiver.java
index 724c376..deb7c4d 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpReceiver.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpReceiver.java
@@ -216,7 +216,7 @@ public class HttpReceiver implements HttpParser.ResponseHandler<ByteBuffer>
}
@Override
- public boolean messageComplete(long contentLength)
+ public boolean messageComplete()
{
HttpExchange exchange = connection.getExchange();
// The exchange may be null if it was failed before
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java
index af2091f..960ab49 100644
--- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java
@@ -405,7 +405,7 @@ public class HttpParser
setState(State.END);
BufferUtil.clear(buffer);
return_from_parse|=_handler.headerComplete();
- return_from_parse|=_handler.messageComplete(_contentPosition);
+ return_from_parse|=_handler.messageComplete();
}
else
_utf8.append(ch);
@@ -455,7 +455,7 @@ public class HttpParser
setState(State.END);
BufferUtil.clear(buffer);
return_from_parse|=_handler.headerComplete();
- return_from_parse|=_handler.messageComplete(_contentPosition);
+ return_from_parse|=_handler.messageComplete();
}
}
break;
@@ -685,7 +685,7 @@ public class HttpParser
case NO_CONTENT:
return_from_parse|=_handler.headerComplete();
setState(State.END);
- return_from_parse|=_handler.messageComplete(_contentPosition);
+ return_from_parse|=_handler.messageComplete();
break;
default:
@@ -920,7 +920,7 @@ public class HttpParser
if (_contentPosition==_contentLength)
{
setState(State.END);
- if(_handler.messageComplete(_contentPosition))
+ if(_handler.messageComplete())
return true;
}
break;
@@ -958,7 +958,7 @@ public class HttpParser
if (_responseStatus>0 && _headResponse)
{
setState(State.END);
- if (_handler.messageComplete(_contentLength))
+ if (_handler.messageComplete())
return true;
}
@@ -990,7 +990,7 @@ public class HttpParser
if (remaining == 0)
{
setState(State.END);
- if (_handler.messageComplete(_contentPosition))
+ if (_handler.messageComplete())
return true;
}
else
@@ -1014,7 +1014,7 @@ public class HttpParser
if(_contentPosition == _contentLength)
{
setState(State.END);
- if (_handler.messageComplete(_contentPosition))
+ if (_handler.messageComplete())
return true;
}
}
@@ -1049,7 +1049,7 @@ public class HttpParser
if (_eol==HttpTokens.CARRIAGE_RETURN && buffer.hasRemaining() && buffer.get(buffer.position())==HttpTokens.LINE_FEED)
_eol=buffer.get();
setState(State.END);
- if (_handler.messageComplete(_contentPosition))
+ if (_handler.messageComplete())
return true;
}
else
@@ -1079,7 +1079,7 @@ public class HttpParser
if (_eol==HttpTokens.CARRIAGE_RETURN && buffer.hasRemaining() && buffer.get(buffer.position())==HttpTokens.LINE_FEED)
_eol=buffer.get();
setState(State.END);
- if (_handler.messageComplete(_contentPosition))
+ if (_handler.messageComplete())
return true;
}
else
@@ -1149,12 +1149,12 @@ public class HttpParser
/**
* Notifies this parser that I/O code read a -1 and therefore no more data will arrive to be parsed.
- * Calling this method may result in an invocation to {@link HttpHandler#messageComplete(long)}, for
+ * Calling this method may result in an invocation to {@link HttpHandler#messageComplete()}, for
* example when the content is delimited by the close of the connection.
* If the parser is already in a state that does not need data (for example, it is idle waiting for
* a request/response to be parsed), then calling this method is a no-operation.
*
- * @return the result of the invocation to {@link HttpHandler#messageComplete(long)} if there has been
+ * @return the result of the invocation to {@link HttpHandler#messageComplete()} if there has been
* one, or false otherwise.
*/
public boolean shutdownInput()
@@ -1170,7 +1170,7 @@ public class HttpParser
case EOF_CONTENT:
setState(State.END);
- return _handler.messageComplete(_contentPosition);
+ return _handler.messageComplete();
case CLOSED:
break;
@@ -1179,7 +1179,7 @@ public class HttpParser
setState(State.END);
if (!_headResponse)
_handler.earlyEOF();
- return _handler.messageComplete(_contentPosition);
+ return _handler.messageComplete();
}
return false;
@@ -1250,7 +1250,7 @@ public class HttpParser
public boolean headerComplete();
- public boolean messageComplete(long contentLength);
+ public boolean messageComplete();
/**
* This is the method called by parser when a HTTP Header name and value is found
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpTester.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpTester.java
index c557ef4..908ba46 100644
--- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpTester.java
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpTester.java
@@ -126,7 +126,7 @@ public class HttpTester
}
@Override
- public boolean messageComplete(long contentLength)
+ public boolean messageComplete()
{
return true;
}
diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorServerTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorServerTest.java
index 38df347..967ccf0 100644
--- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorServerTest.java
+++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorServerTest.java
@@ -64,7 +64,7 @@ public class HttpGeneratorServerTest
}
@Override
- public boolean messageComplete(long contentLength)
+ public boolean messageComplete()
{
return true;
}
diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java
index e04a091..c0861fa 100644
--- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java
+++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java
@@ -763,7 +763,7 @@ public class HttpParserTest
}
@Override
- public boolean messageComplete(long contentLength)
+ public boolean messageComplete()
{
//System.err.println("messageComplete");
_messageCompleted = true;
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java
index 126131d..9da482a 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java
@@ -521,7 +521,7 @@ public class HttpChannel<T> implements HttpParser.RequestHandler<T>, Runnable
}
@Override
- public boolean messageComplete(long contentLength)
+ public boolean messageComplete()
{
_request.getHttpInput().shutdown();
return true;
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelState.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelState.java
index 9bf5520..04f3f83 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelState.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelState.java
@@ -302,12 +302,11 @@ public class HttpChannelState implements AsyncContext, Continuation
{
synchronized (this)
{
- _continuation=false;
- _responseWrapped=false;
-
switch(_state)
{
case IDLE:
+ _continuation=false;
+ _responseWrapped=false;
_initial=true;
_state=State.DISPATCHED;
if (_lastAsyncListeners!=null)
@@ -331,6 +330,8 @@ public class HttpChannelState implements AsyncContext, Continuation
return false;
case REDISPATCH:
+ _continuation=false;
+ _responseWrapped=false;
_state=State.REDISPATCHED;
return true;
diff --git a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpChannelOverSPDY.java b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpChannelOverSPDY.java
index 90dc33f..fb5a245 100644
--- a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpChannelOverSPDY.java
+++ b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpChannelOverSPDY.java
@@ -115,7 +115,7 @@ public class HttpChannelOverSPDY extends HttpChannel<DataInfo>
{
if (headerComplete())
post(this);
- if (messageComplete(-1))
+ if (messageComplete())
post(this);
}
}
@@ -150,7 +150,7 @@ public class HttpChannelOverSPDY extends HttpChannel<DataInfo>
if (endRequest)
{
- if (messageComplete(-1))
+ if (messageComplete())
post(this);
}
}
diff --git a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/ProxyHTTPSPDYConnection.java b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/ProxyHTTPSPDYConnection.java
index 478fca7..817e437 100644
--- a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/ProxyHTTPSPDYConnection.java
+++ b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/ProxyHTTPSPDYConnection.java
@@ -132,7 +132,7 @@ public class ProxyHTTPSPDYConnection extends HttpConnection implements HttpParse
}
@Override
- public boolean messageComplete(long contentLength)
+ public boolean messageComplete()
{
if (stream == null)
{
diff --git a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/ServerHTTPSPDYTest.java b/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/ServerHTTPSPDYTest.java
index 39cf294..b448240 100644
--- a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/ServerHTTPSPDYTest.java
+++ b/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/ServerHTTPSPDYTest.java
@@ -354,12 +354,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest
}
}), null);
- Fields headers = new Fields();
- headers.put(HTTPSPDYHeader.METHOD.name(version), "GET");
- headers.put(HTTPSPDYHeader.URI.name(version), "/foo");
- headers.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1");
- headers.put(HTTPSPDYHeader.SCHEME.name(version), "http");
- headers.put(HTTPSPDYHeader.HOST.name(version), "localhost:" + connector.getLocalPort());
+ Fields headers = createHeaders("GET");
final CountDownLatch replyLatch = new CountDownLatch(1);
final CountDownLatch dataLatch = new CountDownLatch(1);
session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter()
@@ -405,12 +400,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest
}
}), null);
- Fields headers = new Fields();
- headers.put(HTTPSPDYHeader.METHOD.name(version), "GET");
- headers.put(HTTPSPDYHeader.URI.name(version), "/foo");
- headers.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1");
- headers.put(HTTPSPDYHeader.SCHEME.name(version), "http");
- headers.put(HTTPSPDYHeader.HOST.name(version), "localhost:" + connector.getLocalPort());
+ Fields headers = createHeaders("GET");
final CountDownLatch replyLatch = new CountDownLatch(1);
final CountDownLatch dataLatch = new CountDownLatch(1);
session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter()
@@ -461,12 +451,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest
}
}), null);
- Fields headers = new Fields();
- headers.put(HTTPSPDYHeader.METHOD.name(version), "GET");
- headers.put(HTTPSPDYHeader.URI.name(version), "/foo");
- headers.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1");
- headers.put(HTTPSPDYHeader.SCHEME.name(version), "http");
- headers.put(HTTPSPDYHeader.HOST.name(version), "localhost:" + connector.getLocalPort());
+ Fields headers = createHeaders("GET");
final CountDownLatch replyLatch = new CountDownLatch(1);
final CountDownLatch dataLatch = new CountDownLatch(2);
session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter()
@@ -521,12 +506,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest
}
}), null);
- Fields headers = new Fields();
- headers.put(HTTPSPDYHeader.METHOD.name(version), "GET");
- headers.put(HTTPSPDYHeader.URI.name(version), "/foo");
- headers.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1");
- headers.put(HTTPSPDYHeader.SCHEME.name(version), "http");
- headers.put(HTTPSPDYHeader.HOST.name(version), "localhost:" + connector.getLocalPort());
+ Fields headers = createHeaders("GET");
final CountDownLatch replyLatch = new CountDownLatch(1);
final CountDownLatch dataLatch = new CountDownLatch(1);
session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter()
@@ -579,12 +559,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest
}
}), null);
- Fields headers = new Fields();
- headers.put(HTTPSPDYHeader.METHOD.name(version), "GET");
- headers.put(HTTPSPDYHeader.URI.name(version), "/foo");
- headers.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1");
- headers.put(HTTPSPDYHeader.SCHEME.name(version), "http");
- headers.put(HTTPSPDYHeader.HOST.name(version), "localhost:" + connector.getLocalPort());
+ Fields headers = createHeaders("GET");
final CountDownLatch replyLatch = new CountDownLatch(1);
final CountDownLatch dataLatch = new CountDownLatch(1);
session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter()
@@ -637,12 +612,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest
}
}), null);
- Fields headers = new Fields();
- headers.put(HTTPSPDYHeader.METHOD.name(version), "GET");
- headers.put(HTTPSPDYHeader.URI.name(version), "/foo");
- headers.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1");
- headers.put(HTTPSPDYHeader.SCHEME.name(version), "http");
- headers.put(HTTPSPDYHeader.HOST.name(version), "localhost:" + connector.getLocalPort());
+ Fields headers = createHeaders("GET");
final CountDownLatch replyLatch = new CountDownLatch(1);
final CountDownLatch dataLatch = new CountDownLatch(1);
session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter()
@@ -700,12 +670,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest
}
}), null);
- Fields headers = new Fields();
- headers.put(HTTPSPDYHeader.METHOD.name(version), "GET");
- headers.put(HTTPSPDYHeader.URI.name(version), "/foo");
- headers.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1");
- headers.put(HTTPSPDYHeader.SCHEME.name(version), "http");
- headers.put(HTTPSPDYHeader.HOST.name(version), "localhost:" + connector.getLocalPort());
+ Fields headers = createHeaders("GET");
final CountDownLatch replyLatch = new CountDownLatch(1);
final CountDownLatch dataLatch = new CountDownLatch(1);
session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter()
@@ -758,12 +723,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest
}
}), null);
- Fields headers = new Fields();
- headers.put(HTTPSPDYHeader.METHOD.name(version), "GET");
- headers.put(HTTPSPDYHeader.URI.name(version), "/foo");
- headers.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1");
- headers.put(HTTPSPDYHeader.SCHEME.name(version), "http");
- headers.put(HTTPSPDYHeader.HOST.name(version), "localhost:" + connector.getLocalPort());
+ Fields headers = createHeaders("GET");
final CountDownLatch replyLatch = new CountDownLatch(1);
session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter()
{
@@ -800,12 +760,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest
}
}), null);
- Fields headers = new Fields();
- headers.put(HTTPSPDYHeader.METHOD.name(version), "GET");
- headers.put(HTTPSPDYHeader.URI.name(version), "/foo");
- headers.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1");
- headers.put(HTTPSPDYHeader.SCHEME.name(version), "http");
- headers.put(HTTPSPDYHeader.HOST.name(version), "localhost:" + connector.getLocalPort());
+ Fields headers = createHeaders("GET");
final CountDownLatch replyLatch = new CountDownLatch(1);
final CountDownLatch dataLatch = new CountDownLatch(1);
session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter()
@@ -848,12 +803,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest
}
}), null);
- Fields headers = new Fields();
- headers.put(HTTPSPDYHeader.METHOD.name(version), "GET");
- headers.put(HTTPSPDYHeader.URI.name(version), "/foo");
- headers.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1");
- headers.put(HTTPSPDYHeader.SCHEME.name(version), "http");
- headers.put(HTTPSPDYHeader.HOST.name(version), "localhost:" + connector.getLocalPort());
+ Fields headers = createHeaders("GET");
final CountDownLatch replyLatch = new CountDownLatch(1);
final CountDownLatch latch = new CountDownLatch(1);
session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter()
@@ -905,12 +855,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest
}
}), null);
- Fields headers = new Fields();
- headers.put(HTTPSPDYHeader.METHOD.name(version), "GET");
- headers.put(HTTPSPDYHeader.URI.name(version), "/foo");
- headers.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1");
- headers.put(HTTPSPDYHeader.SCHEME.name(version), "http");
- headers.put(HTTPSPDYHeader.HOST.name(version), "localhost:" + connector.getLocalPort());
+ Fields headers = createHeaders("GET");
final CountDownLatch replyLatch = new CountDownLatch(1);
final CountDownLatch dataLatch = new CountDownLatch(2);
session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter()
@@ -992,12 +937,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest
}
}), null);
- Fields headers = new Fields();
- headers.put(HTTPSPDYHeader.METHOD.name(version), "GET");
- headers.put(HTTPSPDYHeader.URI.name(version), "/foo");
- headers.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1");
- headers.put(HTTPSPDYHeader.SCHEME.name(version), "http");
- headers.put(HTTPSPDYHeader.HOST.name(version), "localhost:" + connector.getLocalPort());
+ Fields headers = createHeaders("GET");
final CountDownLatch replyLatch = new CountDownLatch(1);
final CountDownLatch dataLatch = new CountDownLatch(1);
session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter()
@@ -1053,12 +993,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest
}
}), null);
- Fields headers = new Fields();
- headers.put(HTTPSPDYHeader.METHOD.name(version), "GET");
- headers.put(HTTPSPDYHeader.URI.name(version), "/foo");
- headers.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1");
- headers.put(HTTPSPDYHeader.SCHEME.name(version), "http");
- headers.put(HTTPSPDYHeader.HOST.name(version), "localhost:" + connector.getLocalPort());
+ Fields headers = createHeaders("GET");
final CountDownLatch replyLatch = new CountDownLatch(1);
final CountDownLatch dataLatch = new CountDownLatch(1);
final AtomicInteger contentLength = new AtomicInteger();
@@ -1109,11 +1044,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest
{
try
{
- InputStream input = request.getInputStream();
- byte[] buffer = new byte[512];
- int read = 0;
- while (read < data.length)
- read += input.read(buffer);
+ readRequestData(request, data.length);
continuation.complete();
latch.countDown();
}
@@ -1126,12 +1057,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest
}
}), null);
- Fields headers = new Fields();
- headers.put(HTTPSPDYHeader.METHOD.name(version), "POST");
- headers.put(HTTPSPDYHeader.URI.name(version), "/foo");
- headers.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1");
- headers.put(HTTPSPDYHeader.SCHEME.name(version), "http");
- headers.put(HTTPSPDYHeader.HOST.name(version), "localhost:" + connector.getLocalPort());
+ Fields headers = createHeaders("POST");
final CountDownLatch replyLatch = new CountDownLatch(1);
Stream stream = session.syn(new SynInfo(headers, false), new StreamFrameListener.Adapter()
{
@@ -1150,6 +1076,104 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest
}
@Test
+ public void testPOSTThenSuspendExpire() throws Exception
+ {
+ final CountDownLatch dispatchedAgainAfterExpire = new CountDownLatch(1);
+ Session session = startClient(version, startHTTPServer(version, new AbstractHandler()
+ {
+ @Override
+ public void handle(String target, final Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse)
+ throws IOException, ServletException
+ {
+ request.setHandled(true);
+ final Continuation continuation = ContinuationSupport.getContinuation(request);
+ if (continuation.isInitial())
+ {
+ continuation.setTimeout(1000);
+ continuation.suspend();
+ }
+ else
+ {
+ dispatchedAgainAfterExpire.countDown();
+ }
+
+ }
+ }), null);
+
+ Fields headers = createHeaders("POST");
+ final CountDownLatch replyLatch = new CountDownLatch(1);
+ session.syn(new SynInfo(headers, false), new StreamFrameListener.Adapter()
+ {
+ @Override
+ public void onReply(Stream stream, ReplyInfo replyInfo)
+ {
+ Fields replyHeaders = replyInfo.getHeaders();
+ Assert.assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).value().contains("200"));
+ replyLatch.countDown();
+ }
+ }).get(5, TimeUnit.SECONDS);
+
+ Assert.assertTrue("Not dispatched again after expire", dispatchedAgainAfterExpire.await(5,
+ TimeUnit.SECONDS));
+ Assert.assertTrue("Reply not sent", replyLatch.await(5, TimeUnit.SECONDS));
+ }
+
+ @Test
+ public void testPOSTThenSuspendExpireWithRequestData() throws Exception
+ {
+ final byte[] data = new byte[2000];
+ final CountDownLatch dispatchedAgainAfterExpire = new CountDownLatch(1);
+ Session session = startClient(version, startHTTPServer(version, new AbstractHandler()
+ {
+ @Override
+ public void handle(String target, final Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse)
+ throws IOException, ServletException
+ {
+ request.setHandled(true);
+ final Continuation continuation = ContinuationSupport.getContinuation(request);
+ if (continuation.isInitial())
+ {
+ readRequestData(request, data.length);
+ continuation.setTimeout(1000);
+ continuation.suspend();
+ }
+ else
+ {
+ dispatchedAgainAfterExpire.countDown();
+ }
+
+ }
+ }), null);
+
+ Fields headers = createHeaders("POST");
+ final CountDownLatch replyLatch = new CountDownLatch(1);
+ Stream stream = session.syn(new SynInfo(headers, false), new StreamFrameListener.Adapter()
+ {
+ @Override
+ public void onReply(Stream stream, ReplyInfo replyInfo)
+ {
+ Fields replyHeaders = replyInfo.getHeaders();
+ Assert.assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).value().contains("200"));
+ replyLatch.countDown();
+ }
+ }).get(5, TimeUnit.SECONDS);
+ stream.data(new BytesDataInfo(data, true));
+
+ Assert.assertTrue("Not dispatched again after expire", dispatchedAgainAfterExpire.await(5,
+ TimeUnit.SECONDS));
+ Assert.assertTrue("Reply not sent", replyLatch.await(5, TimeUnit.SECONDS));
+ }
+
+ private void readRequestData(Request request, int expectedDataLength) throws IOException
+ {
+ InputStream input = request.getInputStream();
+ byte[] buffer = new byte[512];
+ int read = 0;
+ while (read < expectedDataLength)
+ read += input.read(buffer);
+ }
+
+ @Test
public void testPOSTThenSuspendRequestThenReadTwoChunksThenComplete() throws Exception
{
final byte[] data = new byte[2000];
@@ -1189,12 +1213,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest
}
}), null);
- Fields headers = new Fields();
- headers.put(HTTPSPDYHeader.METHOD.name(version), "POST");
- headers.put(HTTPSPDYHeader.URI.name(version), "/foo");
- headers.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1");
- headers.put(HTTPSPDYHeader.SCHEME.name(version), "http");
- headers.put(HTTPSPDYHeader.HOST.name(version), "localhost:" + connector.getLocalPort());
+ Fields headers = createHeaders("POST");
final CountDownLatch replyLatch = new CountDownLatch(1);
Stream stream = session.syn(new SynInfo(headers, false), new StreamFrameListener.Adapter()
{
@@ -1262,12 +1281,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest
}
}), null);
- Fields headers = new Fields();
- headers.put(HTTPSPDYHeader.METHOD.name(version), "POST");
- headers.put(HTTPSPDYHeader.URI.name(version), "/foo");
- headers.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1");
- headers.put(HTTPSPDYHeader.SCHEME.name(version), "http");
- headers.put(HTTPSPDYHeader.HOST.name(version), "localhost:" + connector.getLocalPort());
+ Fields headers = createHeaders("POST");
final CountDownLatch responseLatch = new CountDownLatch(2);
Stream stream = session.syn(new SynInfo(headers, false), new StreamFrameListener.Adapter()
{
@@ -1308,12 +1322,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest
}
}), null);
- Fields headers = new Fields();
- headers.put(HTTPSPDYHeader.METHOD.name(version), "POST");
- headers.put(HTTPSPDYHeader.URI.name(version), "/foo");
- headers.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1");
- headers.put(HTTPSPDYHeader.SCHEME.name(version), "http");
- headers.put(HTTPSPDYHeader.HOST.name(version), "localhost:" + connector.getLocalPort());
+ Fields headers = createHeaders("POST");
final CountDownLatch responseLatch = new CountDownLatch(1);
Stream stream = session.syn(new SynInfo(headers, false), new StreamFrameListener.Adapter()
{
@@ -1331,4 +1340,15 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest
Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
Assert.assertTrue(responseLatch.await(5, TimeUnit.SECONDS));
}
+
+ private Fields createHeaders(String httpMethod)
+ {
+ Fields headers = new Fields();
+ headers.put(HTTPSPDYHeader.METHOD.name(version), httpMethod);
+ headers.put(HTTPSPDYHeader.URI.name(version), "/foo");
+ headers.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1");
+ headers.put(HTTPSPDYHeader.SCHEME.name(version), "http");
+ headers.put(HTTPSPDYHeader.HOST.name(version), "localhost:" + connector.getLocalPort());
+ return headers;
+ }
}
diff --git a/test-jetty-webapp/src/main/webapp/chat/index.html b/test-jetty-webapp/src/main/webapp/chat/index.html
index adc33ef..cc8f833 100644
--- a/test-jetty-webapp/src/main/webapp/chat/index.html
+++ b/test-jetty-webapp/src/main/webapp/chat/index.html
@@ -1,85 +1,184 @@
-<html><head>
+<html>
+<head>
<title>Async Chat</title>
<script type='text/javascript'>
- function $() { return document.getElementById(arguments[0]); }
- function $F() { return document.getElementById(arguments[0]).value; }
- function getKeyCode(ev) { if (window.event) return window.event.keyCode; return ev.keyCode; }
- function xhr(method,uri,body,handler) {
- var req=(window.XMLHttpRequest)?new XMLHttpRequest():new ActiveXObject('Microsoft.XMLHTTP');
- req.onreadystatechange=function() { if (req.readyState==4 && handler) { eval('var o='+req.responseText);handler(o);} }
- req.open(method,uri,true);
- req.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
- req.send(body);
- };
- function send(action,user,message,handler){
- if (message) message=message.replace('%','%25').replace('&','%26').replace('=','%3D');
- if (user) user=user.replace('%','%25').replace('&','%26').replace('=','%3D');
- xhr('POST','chat','action='+action+'&user='+user+'&message='+message,handler);
- };
-
- var room = {
- join: function(name) {
- this._username=name;
- $('join').className='hidden';
- $('joined').className='';
- $('phrase').focus();
- send('join', room._username,null);
- send('chat', room._username,'has joined!');
- send('poll', room._username,null, room._poll);
- },
- chat: function(text) {
- if (text != null && text.length>0 )
- send('chat',room._username,text);
- },
- _poll: function(m) {
- //console.debug(m);
- if (m.chat){
- var chat=document.getElementById('chat');
- var spanFrom = document.createElement('span');
- spanFrom.className='from';
- spanFrom.innerHTML=m.from+':&nbsp;';
- var spanText = document.createElement('span');
- spanText.className='text';
- spanText.innerHTML=m.chat;
- var lineBreak = document.createElement('br');
- chat.appendChild(spanFrom);
- chat.appendChild(spanText);
- chat.appendChild(lineBreak);
- chat.scrollTop = chat.scrollHeight - chat.clientHeight;
- }
- if (m.action=='poll')
- send('poll', room._username,null, room._poll);
- },
- _end:''
- };
+ function $()
+ {
+ return document.getElementById(arguments[0]);
+ }
+ function $F()
+ {
+ return document.getElementById(arguments[0]).value;
+ }
+ function getKeyCode(ev)
+ {
+ if (window.event) return window.event.keyCode;
+ return ev.keyCode;
+ }
+ function xhr(method, uri, body, handler)
+ {
+ var req = (window.XMLHttpRequest) ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP');
+ req.onreadystatechange = function ()
+ {
+ if (req.readyState == 4 && handler)
+ {
+ eval('var o=' + req.responseText);
+ handler(o);
+ }
+ }
+ req.open(method, uri, true);
+ req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
+ req.send(body);
+ }
+ ;
+ function send(action, user, message, handler)
+ {
+ if (message) message = message.replace('%', '%25').replace('&', '%26').replace('=', '%3D');
+ if (user) user = user.replace('%', '%25').replace('&', '%26').replace('=', '%3D');
+ xhr('POST', 'chat', 'action=' + action + '&user=' + user + '&message=' + message, handler);
+ }
+ ;
+
+ var room = {
+ join:function (name)
+ {
+ this._username = name;
+ $('join').className = 'hidden';
+ $('joined').className = '';
+ $('phrase').focus();
+ send('join', room._username, null, room._joined);
+ },
+ _joined:function ()
+ {
+ send('chat', room._username, 'has joined!', room._startPolling);
+ },
+ _startPolling:function ()
+ {
+ send('poll', room._username, null, room._poll);
+ },
+ chat:function (text)
+ {
+ if (text != null && text.length > 0)
+ send('chat', room._username, text);
+ },
+ _poll:function (m)
+ {
+ //console.debug(m);
+ if (m.chat)
+ {
+ var chat = document.getElementById('chat');
+ var spanFrom = document.createElement('span');
+ spanFrom.className = 'from';
+ spanFrom.innerHTML = m.from + ':&nbsp;';
+ var spanText = document.createElement('span');
+ spanText.className = 'text';
+ spanText.innerHTML = m.chat;
+ var lineBreak = document.createElement('br');
+ chat.appendChild(spanFrom);
+ chat.appendChild(spanText);
+ chat.appendChild(lineBreak);
+ chat.scrollTop = chat.scrollHeight - chat.clientHeight;
+ }
+ if (m.action == 'poll')
+ send('poll', room._username, null, room._poll);
+ },
+ _end:''
+ };
</script>
<style type='text/css'>
- div { border: 0px solid black; }
- div#chat { clear: both; width: 40em; height: 20ex; overflow: auto; background-color: #f0f0f0; padding: 4px; border: 1px solid black; }
- div#input { clear: both; width: 40em; padding: 4px; background-color: #e0e0e0; border: 1px solid black; border-top: 0px }
- input#phrase { width:30em; background-color: #e0f0f0; }
- input#username { width:14em; background-color: #e0f0f0; }
- div.hidden { display: none; }
- span.from { font-weight: bold; }
- span.alert { font-style: italic; }
+ div {
+ border: 0px solid black;
+ }
+
+ div#chat {
+ clear: both;
+ width: 40em;
+ height: 20ex;
+ overflow: auto;
+ background-color: #f0f0f0;
+ padding: 4px;
+ border: 1px solid black;
+ }
+
+ div#input {
+ clear: both;
+ width: 40em;
+ padding: 4px;
+ background-color: #e0e0e0;
+ border: 1px solid black;
+ border-top: 0px
+ }
+
+ input#phrase {
+ width: 30em;
+ background-color: #e0f0f0;
+ }
+
+ input#username {
+ width: 14em;
+ background-color: #e0f0f0;
+ }
+
+ div.hidden {
+ display: none;
+ }
+
+ span.from {
+ font-weight: bold;
+ }
+
+ span.alert {
+ font-style: italic;
+ }
</style>
-</head><body>
+</head>
+<body>
<div id='chat'></div>
<div id='input'>
- <div id='join' >
- Username:&nbsp;<input id='username' type='text'/><input id='joinB' class='button' type='submit' name='join' value='Join'/>
- </div>
- <div id='joined' class='hidden'>
- Chat:&nbsp;<input id='phrase' type='text'/>
- <input id='sendB' class='button' type='submit' name='join' value='Send'/>
- </div>
+ <div id='join'>
+ Username:&nbsp;<input id='username' type='text'/><input id='joinB' class='button' type='submit' name='join'
+ value='Join'/>
+ </div>
+ <div id='joined' class='hidden'>
+ Chat:&nbsp;<input id='phrase' type='text'/>
+ <input id='sendB' class='button' type='submit' name='join' value='Send'/>
+ </div>
</div>
<script type='text/javascript'>
-$('username').setAttribute('autocomplete','OFF');
-$('username').onkeyup = function(ev) { var keyc=getKeyCode(ev); if (keyc==13 || keyc==10) { room.join($F('username')); return false; } return true; } ;
-$('joinB').onclick = function(event) { room.join($F('username')); return false; };
-$('phrase').setAttribute('autocomplete','OFF');
-$('phrase').onkeyup = function(ev) { var keyc=getKeyCode(ev); if (keyc==13 || keyc==10) { room.chat($F('phrase')); $('phrase').value=''; return false; } return true; };
-$('sendB').onclick = function(event) { room.chat($F('phrase')); $('phrase').value=''; return false; };
+ $('username').setAttribute('autocomplete', 'OFF');
+ $('username').onkeyup = function (ev)
+ {
+ var keyc = getKeyCode(ev);
+ if (keyc == 13 || keyc == 10)
+ {
+ room.join($F('username'));
+ return false;
+ }
+ return true;
+ };
+ $('joinB').onclick = function (event)
+ {
+ room.join($F('username'));
+ return false;
+ };
+ $('phrase').setAttribute('autocomplete', 'OFF');
+ $('phrase').onkeyup = function (ev)
+ {
+ var keyc = getKeyCode(ev);
+ if (keyc == 13 || keyc == 10)
+ {
+ room.chat($F('phrase'));
+ $('phrase').value = '';
+ return false;
+ }
+ return true;
+ };
+ $('sendB').onclick = function (event)
+ {
+ room.chat($F('phrase'));
+ $('phrase').value = '';
+ return false;
+ };
</script>
-</body></html>
+</body>
+</html>