Issue #525 fix blockForContent spin

Improved test
This commit is contained in:
Greg Wilkins 2016-05-18 12:53:44 +10:00
parent 0193532748
commit 49ec41f600
2 changed files with 77 additions and 47 deletions

View File

@ -361,7 +361,11 @@ public class HttpChannelOverHttp extends HttpChannel implements HttpParser.Reque
// Should we delay dispatch until we have some content?
// We should not delay if there is no content expect or client is expecting 100 or the response is already committed or the request buffer already has something in it to parse
_delayedForContent = (getHttpConfiguration().isDelayDispatchUntilContent() && _httpConnection.getParser().getContentLength()>0 && !isExpecting100Continue() && !isCommitted() && _httpConnection.isRequestBufferEmpty());
_delayedForContent = (getHttpConfiguration().isDelayDispatchUntilContent()
&& (_httpConnection.getParser().getContentLength()>0 || _httpConnection.getParser().isChunking() )
&& !isExpecting100Continue()
&& !isCommitted()
&& _httpConnection.isRequestBufferEmpty());
return !_delayedForContent;
}

View File

@ -18,12 +18,15 @@
package org.eclipse.jetty.servlet;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.server.HttpChannel;
import org.eclipse.jetty.server.LocalConnector;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.util.log.Log;
@ -35,32 +38,41 @@ import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.assertThat;
public class PostServletTest
{
private static final Logger LOG = Log.getLogger(PostServletTest.class);
private static final AtomicReference<Throwable> ex0=new AtomicReference<>();
private static final AtomicReference<Throwable> ex1=new AtomicReference<>();
public static class BasicReadPostServlet extends HttpServlet
{
protected void doPost(HttpServletRequest request, HttpServletResponse response)
{
byte[] buffer = new byte[1024];
try
{
response.flushBuffer();
request.getInputStream().read();
int len=request.getInputStream().read(buffer);
while(len>0)
{
response.getOutputStream().println("read "+len);
response.getOutputStream().flush();
len = request.getInputStream().read(buffer);
}
}
catch (Exception e0)
{
ex0.set(e0);
try
{
// this read-call should fail immediately
request.getInputStream().read();
request.getInputStream().read(buffer);
}
catch (Exception e1)
{
ex1.set(e1);
LOG.warn(e1.toString());
}
}
@ -73,6 +85,8 @@ public class PostServletTest
@Before
public void startServer() throws Exception
{
ex0.set(null);
ex1.set(null);
server = new Server();
connector = new LocalConnector(server);
server.addConnector(connector);
@ -98,21 +112,27 @@ public class PostServletTest
StringBuilder req = new StringBuilder();
req.append("POST /post HTTP/1.1\r\n");
req.append("Host: localhost\r\n");
req.append("Connection: close\r\n");
req.append("Transfer-Encoding: chunked\r\n");
req.append("\r\n");
req.append("6\r\n");
req.append("Hello ");
req.append("\r\n");
req.append("6\r\n");
req.append("World\n");
req.append("7\r\n");
req.append("World!\n");
req.append("\r\n");
req.append("0\r\n");
req.append("\r\n");
String resp = connector.getResponses(req.toString());
String resp = connector.getResponses(req.toString(),1,TimeUnit.SECONDS);
assertThat("resp", resp, Matchers.containsString("HTTP/1.1 200 OK"));
assertThat("resp", resp, containsString("HTTP/1.1 200 OK"));
assertThat("resp", resp, containsString("chunked"));
assertThat("resp", resp, containsString("read 6"));
assertThat("resp", resp, containsString("read 7"));
assertThat("resp", resp, containsString("\r\n0\r\n"));
assertThat(ex0.get(),nullValue());
assertThat(ex1.get(),nullValue());
}
@Test
@ -132,12 +152,47 @@ public class PostServletTest
try (StacklessLogging scope = new StacklessLogging(ServletHandler.class))
{
String resp = connector.getResponses(req.toString());
assertThat("resp", resp, Matchers.containsString("HTTP/1.1 200 "));
assertThat("resp", resp, Matchers.containsString("chunked"));
assertThat("resp", resp, not(containsString("\r\n0\r\n")));
assertThat(resp,is("")); // Aborted before response committed
}
assertThat(ex0.get(),not(nullValue()));
assertThat(ex1.get(),not(nullValue()));
}
@Test
public void testDeferredBadPost() throws Exception
{
StringBuilder req = new StringBuilder(16*1024);
req.append("POST /post HTTP/1.1\r\n");
req.append("Host: localhost\r\n");
req.append("Transfer-Encoding: chunked\r\n");
req.append("\r\n");
try (StacklessLogging scope = new StacklessLogging(ServletHandler.class))
{
LocalConnector.LocalEndPoint endp=connector.executeRequest(req.toString());
Thread.sleep(1000);
req.setLength(0);
// intentionally bad (not a valid chunked char here)
for (int i=1024;i-->0;)
req.append("xxxxxxxxxxxx");
req.append("\r\n");
req.append("\r\n");
endp.addInput(req.toString());
endp.waitUntilClosedOrIdleFor(1,TimeUnit.SECONDS);
String resp = endp.takeOutputString();
assertThat("resp", resp, containsString("HTTP/1.1 400 "));
}
// null because it was never dispatched!
assertThat(ex0.get(),nullValue());
assertThat(ex1.get(),nullValue());
}
@Test
public void testBadSplitPost() throws Exception
{
@ -166,40 +221,11 @@ public class PostServletTest
endp.waitUntilClosedOrIdleFor(1,TimeUnit.SECONDS);
String resp = endp.takeOutputString();
assertThat("resp", resp, Matchers.containsString("HTTP/1.1 400 "));
assertThat("resp", resp, containsString("HTTP/1.1 200 "));
assertThat("resp", resp, not(containsString("\r\n0\r\n"))); // aborted
}
assertThat(ex0.get(),not(nullValue()));
assertThat(ex1.get(),not(nullValue()));
}
@Test
public void testBadFlushedPost() throws Exception
{
StringBuilder req = new StringBuilder();
req.append("POST /post HTTP/1.1\r\n");
req.append("Host: localhost\r\n");
req.append("Transfer-Encoding: chunked\r\n");
req.append("\r\n");
req.append("6\r\n");
req.append("Flush ");
req.append("\r\n");
try (StacklessLogging scope = new StacklessLogging(ServletHandler.class))
{
LocalConnector.LocalEndPoint endp=connector.executeRequest(req.toString());
req.setLength(0);
Thread.sleep(1000);
req.append("x\r\n");
req.append("World\n");
req.append("\r\n");
req.append("0\r\n");
req.append("\r\n");
endp.addInput(req.toString());
endp.waitUntilClosedOrIdleFor(1,TimeUnit.SECONDS);
String resp = endp.takeOutputString();
assertThat("resp", resp, Matchers.containsString("HTTP/1.1 200 "));
assertThat("resp", resp, Matchers.containsString("Transfer-Encoding: chunked"));
assertThat("resp", resp, not(Matchers.containsString("\r\n0\r\n")));
}
}
}