Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimone Bordet2016-01-20 14:13:31 +0000
committerSimone Bordet2016-01-20 14:13:31 +0000
commit07904e2fbe398b5b31e31c93f3bc6c91caebacab (patch)
tree93c47cfb560e3a75a398531015c03d1fd20645c0
parentf07d7d0117f1ea86af7a880b1e06b07043a0f274 (diff)
downloadorg.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.
-rw-r--r--jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java2
-rw-r--r--jetty-server/src/main/java/org/eclipse/jetty/server/AbstractHttpConnection.java48
-rw-r--r--jetty-server/src/test/java/org/eclipse/jetty/server/HttpServerTestBase.java99
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

Back to the top