diff options
author | Simone Bordet | 2014-04-23 19:26:08 +0000 |
---|---|---|
committer | Jesse McConnell | 2014-09-02 19:44:10 +0000 |
commit | cab425b479062d49d996272db0de13e23414d8fe (patch) | |
tree | 5c6a3aaa9a1e6af07427478fc1bfb708dd68a405 | |
parent | 224e85791ebd2eb3bb6ad4c2dfcb3315e899d17e (diff) | |
download | org.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.java | 28 | ||||
-rw-r--r-- | jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientDuplexTest.java | 61 |
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 |