Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimone Bordet2014-04-23 19:26:08 +0000
committerJesse McConnell2014-09-02 19:44:10 +0000
commitcab425b479062d49d996272db0de13e23414d8fe (patch)
tree5c6a3aaa9a1e6af07427478fc1bfb708dd68a405
parent224e85791ebd2eb3bb6ad4c2dfcb3315e899d17e (diff)
downloadorg.eclipse.jetty.project-cab425b479062d49d996272db0de13e23414d8fe.tar.gz
org.eclipse.jetty.project-cab425b479062d49d996272db0de13e23414d8fe.tar.xz
org.eclipse.jetty.project-cab425b479062d49d996272db0de13e23414d8fe.zip
409788 - Large POST body causes java.lang.IllegalStateException: SENDING => HEADERS.
Fixed case where the response completes before the request.
-rw-r--r--jetty-client/src/main/java/org/eclipse/jetty/client/HttpExchange.java28
-rw-r--r--jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientDuplexTest.java61
2 files changed, 87 insertions, 2 deletions
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpExchange.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpExchange.java
index 3930c78849..e694182d40 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpExchange.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpExchange.java
@@ -325,10 +325,22 @@ public class HttpExchange
switch (newStatus)
{
case STATUS_START:
- case STATUS_EXCEPTED:
- case STATUS_WAITING_FOR_RESPONSE:
set = _status.compareAndSet(oldStatus,newStatus);
break;
+ case STATUS_WAITING_FOR_RESPONSE:
+ if (isResponseCompleted())
+ {
+ // Don't change the status, it's too late.
+ ignored = true;
+ getEventListener().onRequestCommitted();
+ }
+ else
+ {
+ // The 1xx cases go from COMPLETED => WAITING again.
+ set = _status.compareAndSet(oldStatus,newStatus);
+ }
+ break;
+ case STATUS_EXCEPTED:
case STATUS_CANCELLING:
case STATUS_EXPIRED:
// Don't change the status, it's too late
@@ -396,6 +408,10 @@ public class HttpExchange
if (set = _status.compareAndSet(oldStatus,STATUS_PARSING_CONTENT))
getEventListener().onRequestCommitted();
break;
+ case STATUS_COMPLETED:
+ if (set = _status.compareAndSet(oldStatus,newStatus))
+ getEventListener().onResponseComplete();
+ break;
case STATUS_CANCELLING:
case STATUS_EXCEPTED:
set = _status.compareAndSet(oldStatus,newStatus);
@@ -423,6 +439,14 @@ public class HttpExchange
return set;
}
+ private boolean isResponseCompleted()
+ {
+ synchronized (this)
+ {
+ return _onResponseCompleteDone;
+ }
+ }
+
private boolean setStatusExpired(int newStatus, int oldStatus)
{
boolean set;
diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientDuplexTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientDuplexTest.java
index 57b9086610..96c4f2e95e 100644
--- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientDuplexTest.java
+++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientDuplexTest.java
@@ -28,6 +28,7 @@ import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
import org.eclipse.jetty.io.Buffer;
import org.eclipse.jetty.io.ByteArrayBuffer;
@@ -301,6 +302,66 @@ public class HttpClientDuplexTest
socket.close();
}
+
+ @Test
+ public void testResponseCompleteBeforeRequestContent() throws Exception
+ {
+ // Must be greater than 2 to stay in "sending"
+ // state and trigger the condition of this test.
+ int contentLength = 16;
+ final byte[] chunk = new byte[]{'A'};
+ final AtomicInteger requestContent = new AtomicInteger(contentLength);
+ ContentExchange exchange = new ContentExchange(true)
+ {
+ @Override
+ public Buffer getRequestContentChunk(Buffer buffer) throws IOException
+ {
+ if (requestContent.decrementAndGet() > 0)
+ return new ByteArrayBuffer(chunk);
+ return null;
+ }
+ };
+ exchange.setURL("http://localhost:" + server.getLocalPort());
+ // The test needs a fake content source to invoke
+ // getRequestContentChunk() which will provide the content.
+ exchange.setRequestContentSource(new ClosedInputStream());
+ exchange.setRequestHeader("Content-Length", String.valueOf(contentLength));
+ client.send(exchange);
+
+ Socket socket = server.accept();
+ BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));
+ OutputStream output = socket.getOutputStream();
+
+ // Read headers.
+ while (true)
+ {
+ String line = input.readLine();
+ Assert.assertNotNull(line);
+ if (line.length() == 0)
+ break;
+ }
+
+ // Send the whole response.
+ String responseHeaders = "" +
+ "HTTP/1.1 200 OK\r\n" +
+ "Content-Length: 0\r\n" +
+ "\r\n";
+ output.write(responseHeaders.getBytes("UTF-8"));
+ output.flush();
+
+ // Read request content on server.
+ while (true)
+ {
+ if (input.read() < 0)
+ break;
+ }
+
+ Assert.assertEquals(HttpExchange.STATUS_COMPLETED, exchange.waitForDone());
+ Assert.assertEquals(200, exchange.getResponseStatus());
+
+ socket.close();
+ }
+
private boolean await(CountDownLatch latch, long millis) throws InterruptedIOException
{
try

Back to the top