From aa85d85510cd55ec002bcd649cb9008a9ed87609 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Wed, 25 Nov 2015 14:15:14 +1100 Subject: [PATCH] 482855 - Content-Length omitted for POST requests with empty body An ineligant fix. Will improve in 9.3.x/9.4.x without HTTP 0.9 support. --- .../org/eclipse/jetty/http/HttpGenerator.java | 25 ++++++++---- .../jetty/http/HttpGeneratorClientTest.java | 38 ++++++++++++++++++- 2 files changed, 54 insertions(+), 9 deletions(-) diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpGenerator.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpGenerator.java index a4e30379db4..520822637ba 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpGenerator.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpGenerator.java @@ -23,6 +23,8 @@ import java.nio.BufferOverflowException; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; import org.eclipse.jetty.http.HttpTokens.EndOfContent; import org.eclipse.jetty.util.BufferUtil; @@ -70,8 +72,8 @@ public class HttpGenerator private final int _send; private final static int SEND_SERVER = 0x01; private final static int SEND_XPOWEREDBY = 0x02; - - + private final static Set __assumedContentMethods = new HashSet<>(Arrays.asList(new String[]{HttpMethod.POST.asString(),HttpMethod.PUT.asString()})); + /* ------------------------------------------------------------------------------- */ public static void setJettyVersion(String serverVersion) { @@ -745,12 +747,17 @@ public class HttpGenerator long content_length = _contentPrepared+BufferUtil.length(content); // Do we need to tell the headers about it - if ((response!=null || content_length>0 || content_type ) && !_noContent) + if (content_length>0) { header.put(HttpHeader.CONTENT_LENGTH.getBytesColonSpace()); BufferUtil.putDecLong(header, content_length); header.put(HttpTokens.CRLF); } + else if (!_noContent) + { + if (content_type || response!=null || (request!=null && __assumedContentMethods.contains(request.getMethod()))) + header.put(CONTENT_LENGTH_0); + } } else { @@ -767,19 +774,21 @@ public class HttpGenerator case CONTENT_LENGTH: long content_length = _info.getContentLength(); - if ((response!=null || content_length>0 || content_type ) && !_noContent) + if (content_length>0) { - // known length but not actually set. header.put(HttpHeader.CONTENT_LENGTH.getBytesColonSpace()); BufferUtil.putDecLong(header, content_length); header.put(HttpTokens.CRLF); } + else if (!_noContent) + { + if (content_type || response!=null || (request!=null && __assumedContentMethods.contains(request.getMethod()))) + header.put(CONTENT_LENGTH_0); + } break; case NO_CONTENT: - if (response!=null && status >= 200 && status != 204 && status != 304) - header.put(CONTENT_LENGTH_0); - break; + throw new IllegalStateException(); case EOF_CONTENT: _persistent = request!=null; diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorClientTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorClientTest.java index 0fc87e1d2f0..d387fa7655f 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorClientTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorClientTest.java @@ -43,7 +43,7 @@ public class HttpGeneratorClientTest } @Test - public void testRequestNoContent() throws Exception + public void testGETRequestNoContent() throws Exception { ByteBuffer header=BufferUtil.allocate(2048); HttpGenerator gen = new HttpGenerator(); @@ -77,7 +77,43 @@ public class HttpGeneratorClientTest Assert.assertEquals(0, gen.getContentPrepared()); Assert.assertThat(out, Matchers.containsString("GET /index.html HTTP/1.1")); Assert.assertThat(out, Matchers.not(Matchers.containsString("Content-Length"))); + } + @Test + public void testPOSTRequestNoContent() throws Exception + { + ByteBuffer header=BufferUtil.allocate(2048); + HttpGenerator gen = new HttpGenerator(); + + HttpGenerator.Result + result=gen.generateRequest(null,null,null,null, true); + Assert.assertEquals(HttpGenerator.Result.NEED_INFO, result); + Assert.assertEquals(HttpGenerator.State.START, gen.getState()); + + Info info = new Info("POST","/index.html"); + info.getHttpFields().add("Host","something"); + info.getHttpFields().add("User-Agent","test"); + Assert.assertTrue(!gen.isChunking()); + + result=gen.generateRequest(info,null,null,null, true); + Assert.assertEquals(HttpGenerator.Result.NEED_HEADER, result); + Assert.assertEquals(HttpGenerator.State.START, gen.getState()); + + result=gen.generateRequest(info,header,null,null, true); + Assert.assertEquals(HttpGenerator.Result.FLUSH, result); + Assert.assertEquals(HttpGenerator.State.COMPLETING, gen.getState()); + Assert.assertTrue(!gen.isChunking()); + String out = BufferUtil.toString(header); + BufferUtil.clear(header); + + result=gen.generateResponse(null,null,null,null, false); + Assert.assertEquals(HttpGenerator.Result.DONE, result); + Assert.assertEquals(HttpGenerator.State.END, gen.getState()); + Assert.assertTrue(!gen.isChunking()); + + Assert.assertEquals(0, gen.getContentPrepared()); + Assert.assertThat(out, Matchers.containsString("POST /index.html HTTP/1.1")); + Assert.assertThat(out, Matchers.containsString("Content-Length: 0")); } @Test