From 2e85b3e169e30d604b1af11a7518086e5545b0ce Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Tue, 14 Apr 2020 11:44:58 +0200 Subject: [PATCH] Fixes #4764 - HTTP2 Jetty Server does not send back content-length. Updates after review. Now the Content-Length header is generated by HpackEncoder based on MetaData.contentLength, so that the MetaData.HttpFields are not modified. Signed-off-by: Simone Bordet --- .../java/org/eclipse/jetty/http/MetaData.java | 5 +++++ .../eclipse/jetty/http2/hpack/HpackEncoder.java | 14 +++++++++++++- .../http2/server/HttpTransportOverHTTP2.java | 16 ++++++++++++---- 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/MetaData.java b/jetty-http/src/main/java/org/eclipse/jetty/http/MetaData.java index 7591f62e291..8035b086b72 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/MetaData.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/MetaData.java @@ -119,6 +119,11 @@ public class MetaData implements Iterable return _contentLength; } + public void setContentLength(long contentLength) + { + _contentLength = contentLength; + } + /** * @return an iterator over the HTTP fields * @see #getFields() diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java index d71df43f044..0788806b34b 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java @@ -217,7 +217,8 @@ public class HpackEncoder // Remove fields as specified in RFC 7540, 8.1.2.2. if (fields != null) { - // For example: Connection: Close, TE, Upgrade, Custom. + // Remove the headers specified in the Connection header, + // for example: Connection: Close, TE, Upgrade, Custom. Set hopHeaders = null; for (String value : fields.getCSV(HttpHeader.CONNECTION, false)) { @@ -225,6 +226,8 @@ public class HpackEncoder hopHeaders = new HashSet<>(); hopHeaders.add(StringUtil.asciiToLowerCase(value)); } + + boolean contentLengthEncoded = false; for (HttpField field : fields) { HttpHeader header = field.getHeader(); @@ -239,8 +242,17 @@ public class HpackEncoder String name = field.getLowerCaseName(); if (hopHeaders != null && hopHeaders.contains(name)) continue; + if (header == HttpHeader.CONTENT_LENGTH) + contentLengthEncoded = true; encode(buffer, field); } + + if (!contentLengthEncoded) + { + long contentLength = metadata.getContentLength(); + if (contentLength >= 0) + encode(buffer, new HttpField(HttpHeader.CONTENT_LENGTH, String.valueOf(contentLength))); + } } // Check size diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java index a19a8fa071e..03a9812c588 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java @@ -22,8 +22,8 @@ import java.nio.ByteBuffer; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Supplier; +import org.eclipse.jetty.http.BadMessageException; import org.eclipse.jetty.http.HttpFields; -import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http.MetaData; @@ -113,9 +113,17 @@ public class HttpTransportOverHTTP2 implements HttpTransport { if (lastContent) { - HttpFields responseHeaders = info.getFields(); - if (!responseHeaders.contains(HttpHeader.CONTENT_LENGTH)) - responseHeaders.put(HttpHeader.CONTENT_LENGTH, String.valueOf(BufferUtil.length(content))); + long realContentLength = BufferUtil.length(content); + long contentLength = info.getContentLength(); + if (contentLength < 0) + { + info.setContentLength(realContentLength); + } + else if (contentLength != realContentLength) + { + callback.failed(new BadMessageException(HttpStatus.INTERNAL_SERVER_ERROR_500, String.format("Incorrect Content-Length %d!=%d", contentLength, realContentLength))); + return; + } } if (hasContent)