[io/http] Don't add zero-valued content-length header on GET, HEAD, DELETE, CONNECT requests.
Per https://tools.ietf.org/html/rfc7230#section-3.3.2:
"... A user agent SHOULD NOT send a
Content-Length header field when the request message does not contain
a payload body and the method semantics do not anticipate such a
body."
Fixes https://github.com/dart-lang/sdk/issues/45139
Change-Id: I96b735c06038eb3d12a303ee5329228a9b594726
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/194881
Commit-Queue: Alexander Aprelev <aam@google.com>
Reviewed-by: Siva Annamalai <asiva@google.com>
Reviewed-by: Lasse R.H. Nielsen <lrn@google.com>
diff --git a/sdk/lib/_http/http_headers.dart b/sdk/lib/_http/http_headers.dart
index 7d87b88..77b9c22 100644
--- a/sdk/lib/_http/http_headers.dart
+++ b/sdk/lib/_http/http_headers.dart
@@ -503,8 +503,19 @@
_mutable = false;
}
- void _build(BytesBuilder builder) {
+ void _build(BytesBuilder builder, {bool skipZeroContentLength = false}) {
+ // per https://tools.ietf.org/html/rfc7230#section-3.3.2
+ // A user agent SHOULD NOT send a
+ // Content-Length header field when the request message does not
+ // contain a payload body and the method semantics do not anticipate
+ // such a body.
+ String? ignoreHeader = _contentLength == 0 && skipZeroContentLength
+ ? HttpHeaders.contentLengthHeader
+ : null;
_headers.forEach((String name, List<String> values) {
+ if (ignoreHeader == name) {
+ return;
+ }
String originalName = _originalHeaderName(name);
bool fold = _foldHeader(name);
var nameData = originalName.codeUnits;
diff --git a/sdk/lib/_http/http_impl.dart b/sdk/lib/_http/http_impl.dart
index b61f273..6c7b768 100644
--- a/sdk/lib/_http/http_impl.dart
+++ b/sdk/lib/_http/http_impl.dart
@@ -1583,7 +1583,11 @@
headers._finalize();
// Write headers.
- headers._build(buffer);
+ headers._build(buffer,
+ skipZeroContentLength: method == "CONNECT" ||
+ method == "DELETE" ||
+ method == "GET" ||
+ method == "HEAD");
buffer.addByte(_CharCode.CR);
buffer.addByte(_CharCode.LF);
Uint8List headerBytes = buffer.takeBytes();
diff --git a/tests/standalone/io/http_content_length_test.dart b/tests/standalone/io/http_content_length_test.dart
index 15d6520..12e1e99 100644
--- a/tests/standalone/io/http_content_length_test.dart
+++ b/tests/standalone/io/http_content_length_test.dart
@@ -16,8 +16,8 @@
int count = 0;
HttpServer.bind("127.0.0.1", 0, backlog: totalConnections).then((server) {
server.listen((HttpRequest request) {
- Expect.equals("0", request.headers.value('content-length'));
- Expect.equals(0, request.contentLength);
+ Expect.equals(null, request.headers.value('content-length'));
+ Expect.equals(-1, request.contentLength);
var response = request.response;
response.contentLength = 0;
response.done.then((_) {
diff --git a/tests/standalone/io/http_detach_socket_test.dart b/tests/standalone/io/http_detach_socket_test.dart
index fdbc257..480c88d 100644
--- a/tests/standalone/io/http_detach_socket_test.dart
+++ b/tests/standalone/io/http_detach_socket_test.dart
@@ -110,14 +110,13 @@
socket.listen((data) => body.write(new String.fromCharCodes(data)),
onDone: () {
List<String> lines = body.toString().split("\r\n");
- Expect.equals(6, lines.length);
+ Expect.equals(5, lines.length);
Expect.equals("GET / HTTP/1.1", lines[0]);
- Expect.equals("", lines[4]);
- Expect.equals("Some data", lines[5]);
- lines.sort(); // Lines 1-3 becomes 3-5 in a fixed order.
+ Expect.equals("", lines[3]);
+ Expect.equals("Some data", lines[4]);
+ lines.sort(); // Lines 1-2 becomes 3-4 in a fixed order.
Expect.equals("accept-encoding: gzip", lines[3]);
- Expect.equals("content-length: 0", lines[4]);
- Expect.equals("host: 127.0.0.1:${port}", lines[5]);
+ Expect.equals("host: 127.0.0.1:${port}", lines[4]);
socket.close();
});
server.close();
diff --git a/tests/standalone_2/io/http_content_length_test.dart b/tests/standalone_2/io/http_content_length_test.dart
index 7b81398..708a7c1 100644
--- a/tests/standalone_2/io/http_content_length_test.dart
+++ b/tests/standalone_2/io/http_content_length_test.dart
@@ -18,8 +18,8 @@
int count = 0;
HttpServer.bind("127.0.0.1", 0, backlog: totalConnections).then((server) {
server.listen((HttpRequest request) {
- Expect.equals("0", request.headers.value('content-length'));
- Expect.equals(0, request.contentLength);
+ Expect.equals(null, request.headers.value('content-length'));
+ Expect.equals(-1, request.contentLength);
var response = request.response;
response.contentLength = 0;
response.done.then((_) {
diff --git a/tests/standalone_2/io/http_detach_socket_test.dart b/tests/standalone_2/io/http_detach_socket_test.dart
index bb33690..1613ace 100644
--- a/tests/standalone_2/io/http_detach_socket_test.dart
+++ b/tests/standalone_2/io/http_detach_socket_test.dart
@@ -112,14 +112,13 @@
socket.listen((data) => body.write(new String.fromCharCodes(data)),
onDone: () {
List<String> lines = body.toString().split("\r\n");
- Expect.equals(6, lines.length);
+ Expect.equals(5, lines.length);
Expect.equals("GET / HTTP/1.1", lines[0]);
- Expect.equals("", lines[4]);
- Expect.equals("Some data", lines[5]);
- lines.sort(); // Lines 1-3 becomes 3-5 in a fixed order.
+ Expect.equals("", lines[3]);
+ Expect.equals("Some data", lines[4]);
+ lines.sort(); // Lines 1-2 becomes 3-4 in a fixed order.
Expect.equals("accept-encoding: gzip", lines[3]);
- Expect.equals("content-length: 0", lines[4]);
- Expect.equals("host: 127.0.0.1:${port}", lines[5]);
+ Expect.equals("host: 127.0.0.1:${port}", lines[4]);
socket.close();
});
server.close();