diff options
author | Simone Bordet | 2016-01-20 14:13:31 +0000 |
---|---|---|
committer | Simone Bordet | 2016-01-20 14:13:31 +0000 |
commit | 07904e2fbe398b5b31e31c93f3bc6c91caebacab (patch) | |
tree | 93c47cfb560e3a75a398531015c03d1fd20645c0 | |
parent | f07d7d0117f1ea86af7a880b1e06b07043a0f274 (diff) | |
download | org.eclipse.jetty.project-07904e2fbe398b5b31e31c93f3bc6c91caebacab.tar.gz org.eclipse.jetty.project-07904e2fbe398b5b31e31c93f3bc6c91caebacab.tar.xz org.eclipse.jetty.project-07904e2fbe398b5b31e31c93f3bc6c91caebacab.zip |
486167 - ServletInputStream.available() broken for pipelined requests.
Fixed by updating the parser state before calling the parser callbacks
in case of a request without content. All other places correctly had
the state change already before the invocation of the parser callbacks.
3 files changed, 86 insertions, 63 deletions
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 5a60e8da6b..bc7725dc31 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 @@ -637,8 +637,8 @@ public class HttpParser implements Parser break; case HttpTokens.NO_CONTENT: - _handler.headerComplete(); _state=_persistent||(_responseStatus>=100&&_responseStatus<200)?STATE_END:STATE_SEEKING_EOF; + _handler.headerComplete(); _handler.messageComplete(_contentPosition); return 1; diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractHttpConnection.java b/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractHttpConnection.java index 2ea76972cf..f740180d3f 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractHttpConnection.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractHttpConnection.java @@ -18,39 +18,10 @@ package org.eclipse.jetty.server; -import java.io.IOException; -import java.io.InputStream; -import java.io.PrintWriter; -import javax.servlet.ServletInputStream; -import javax.servlet.ServletOutputStream; -import javax.servlet.http.HttpServletResponse; - import org.eclipse.jetty.continuation.ContinuationThrowable; -import org.eclipse.jetty.http.EncodedHttpURI; -import org.eclipse.jetty.http.Generator; -import org.eclipse.jetty.http.HttpBuffers; -import org.eclipse.jetty.http.HttpContent; -import org.eclipse.jetty.http.HttpException; -import org.eclipse.jetty.http.HttpFields; -import org.eclipse.jetty.http.HttpGenerator; -import org.eclipse.jetty.http.HttpHeaderValues; -import org.eclipse.jetty.http.HttpHeaders; -import org.eclipse.jetty.http.HttpMethods; -import org.eclipse.jetty.http.HttpParser; -import org.eclipse.jetty.http.HttpStatus; -import org.eclipse.jetty.http.HttpURI; -import org.eclipse.jetty.http.HttpVersions; -import org.eclipse.jetty.http.MimeTypes; -import org.eclipse.jetty.http.Parser; -import org.eclipse.jetty.io.AbstractConnection; -import org.eclipse.jetty.io.Buffer; +import org.eclipse.jetty.http.*; +import org.eclipse.jetty.io.*; import org.eclipse.jetty.io.BufferCache.CachedBuffer; -import org.eclipse.jetty.io.Buffers; -import org.eclipse.jetty.io.Connection; -import org.eclipse.jetty.io.EndPoint; -import org.eclipse.jetty.io.EofException; -import org.eclipse.jetty.io.RuntimeIOException; -import org.eclipse.jetty.io.UncheckedPrintWriter; import org.eclipse.jetty.server.nio.NIOConnector; import org.eclipse.jetty.server.ssl.SslConnector; import org.eclipse.jetty.util.QuotedStringTokenizer; @@ -60,6 +31,13 @@ import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.resource.Resource; +import javax.servlet.ServletInputStream; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintWriter; + /** * <p>A HttpConnection represents the connection of a HTTP client to the server * and is created by an instance of a {@link Connector}. It's prime function is @@ -866,7 +844,7 @@ public abstract class AbstractHttpConnection extends AbstractConnection _endp.close(); return; } - + _requests++; _generator.setVersion(_version); switch (_version) @@ -884,6 +862,8 @@ public abstract class AbstractHttpConnection extends AbstractConnection { _generator.setPersistent(true); _parser.setPersistent(true); + if (_parser instanceof HttpParser) + ((HttpParser)_parser).setState(HttpParser.STATE_END); } if (_server.getSendDateHeader()) @@ -1158,12 +1138,12 @@ public abstract class AbstractHttpConnection extends AbstractConnection if (lml!=-1) _responseFields.putDateField(HttpHeaders.LAST_MODIFIED_BUFFER, lml); } - + Buffer etag=httpContent.getETag(); if (etag!=null) _responseFields.put(HttpHeaders.ETAG_BUFFER,etag); - + boolean direct=_connector instanceof NIOConnector && ((NIOConnector)_connector).getUseDirectBuffers() && !(_connector instanceof SslConnector); content = direct?httpContent.getDirectBuffer():httpContent.getIndirectBuffer(); if (content==null) diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpServerTestBase.java b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpServerTestBase.java index cf600e6ef4..aa54371e8f 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpServerTestBase.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpServerTestBase.java @@ -18,26 +18,6 @@ package org.eclipse.jetty.server; -import java.io.BufferedReader; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.LineNumberReader; -import java.io.OutputStream; -import java.net.Socket; -import java.net.SocketException; -import java.net.URL; -import java.util.Arrays; -import java.util.Random; -import java.util.concurrent.Exchanger; -import java.util.concurrent.atomic.AtomicBoolean; -import javax.servlet.ServletException; -import javax.servlet.ServletInputStream; -import javax.servlet.ServletOutputStream; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.io.EofException; import org.eclipse.jetty.server.handler.AbstractHandler; @@ -50,12 +30,23 @@ import org.junit.Assert; import org.junit.Test; import org.junit.matchers.JUnitMatchers; +import javax.servlet.ServletException; +import javax.servlet.ServletInputStream; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.*; +import java.net.Socket; +import java.net.SocketException; +import java.net.URL; +import java.util.Arrays; +import java.util.Random; +import java.util.concurrent.Exchanger; +import java.util.concurrent.atomic.AtomicBoolean; + import static org.hamcrest.Matchers.greaterThanOrEqualTo; import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotSame; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.*; /** * @@ -1231,6 +1222,58 @@ public abstract class HttpServerTestBase extends HttpServerTestFixture } } + @Test + public void testAvailableForPipelinedRequests() throws Exception + { + configureServer(new AbstractHandler() + { + public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + { + baseRequest.setHandled(true); + int available = request.getInputStream().available(); + ServletOutputStream output = response.getOutputStream(); + output.println(target); + output.println(String.valueOf(available)); + } + }); + + Socket client = newSocket(HOST,_connector.getLocalPort()); + try + { + OutputStream output = client.getOutputStream(); + InputStream input = client.getInputStream(); + + output.write(( + "GET /one HTTP/1.1\r\n"+ + "host: "+HOST+":"+_connector.getLocalPort()+"\r\n"+ + "\r\n"+ + "GET /two HTTP/1.1\r\n"+ + "host: "+HOST+":"+_connector.getLocalPort()+"\r\n"+ + "\r\n" + ).getBytes()); + output.flush(); + + BufferedReader reader = new BufferedReader(new InputStreamReader(input, "UTF-8")); + + while(reader.readLine().length() > 0) + { + // Skip response headers. + } + assertEquals("/one", reader.readLine()); + assertEquals(0, Integer.parseInt(reader.readLine())); + + while(reader.readLine().length() > 0) + { + // Skip response headers. + } + assertEquals("/two", reader.readLine()); + assertEquals(0, Integer.parseInt(reader.readLine())); + } + finally + { + client.close(); + } + } @Test public void testDualRequest1() throws Exception @@ -1419,9 +1462,9 @@ public abstract class HttpServerTestBase extends HttpServerTestFixture "\r\n" ).getBytes()); os.flush(); - + Thread.sleep(200); - + // write an pipelined request os.write(( "GET / HTTP/1.1\r\n"+ @@ -1430,11 +1473,11 @@ public abstract class HttpServerTestBase extends HttpServerTestFixture "\r\n" ).getBytes()); os.flush(); - + String response=readResponse(client); assertThat(response,JUnitMatchers.containsString("RESUMEDHTTP/1.1 200 OK")); assertThat((System.currentTimeMillis()-start),greaterThanOrEqualTo(1999L)); - + // TODO This test should also check that that the CPU did not spin during the suspend. } finally |