summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuca Casonato <hello@lcas.dev>2021-11-09 12:10:40 +0100
committerGitHub <noreply@github.com>2021-11-09 12:10:40 +0100
commit0de6d1edc4c902044744cdf832113f9aeb167fc5 (patch)
treeac2868ec27baac149e067c2a7a3d044657f63e9f
parent75793baae83123f890442c5d32e3dd38eb18ce1c (diff)
fix(fetch): set content-length for empty POST/PUT (#12703)
This commit changes `fetch` to set `content-length: 0` on POST and PUT requests with no body.
-rw-r--r--cli/tests/unit/fetch_test.ts58
-rw-r--r--ext/fetch/lib.rs7
-rw-r--r--test_util/src/lib.rs4
3 files changed, 68 insertions, 1 deletions
diff --git a/cli/tests/unit/fetch_test.ts b/cli/tests/unit/fetch_test.ts
index 98134728e..8fe8db17e 100644
--- a/cli/tests/unit/fetch_test.ts
+++ b/cli/tests/unit/fetch_test.ts
@@ -640,6 +640,7 @@ unitTest(
const actual = new TextDecoder().decode((await bufPromise).bytes());
const expected = [
"POST /blah HTTP/1.1\r\n",
+ "content-length: 0\r\n",
"hello: World\r\n",
"foo: Bar\r\n",
"accept: */*\r\n",
@@ -1416,3 +1417,60 @@ unitTest(
assertEquals(await res.text(), fixture);
},
);
+
+unitTest(
+ { permissions: { net: true } },
+ async function fetchContentLengthPost() {
+ const response = await fetch("http://localhost:4545/content_length", {
+ method: "POST",
+ });
+ const length = await response.text();
+ assertEquals(length, 'Some("0")');
+ },
+);
+
+unitTest(
+ { permissions: { net: true } },
+ async function fetchContentLengthPut() {
+ const response = await fetch("http://localhost:4545/content_length", {
+ method: "PUT",
+ });
+ const length = await response.text();
+ assertEquals(length, 'Some("0")');
+ },
+);
+
+unitTest(
+ { permissions: { net: true } },
+ async function fetchContentLengthPatch() {
+ const response = await fetch("http://localhost:4545/content_length", {
+ method: "PATCH",
+ });
+ const length = await response.text();
+ assertEquals(length, "None");
+ },
+);
+
+unitTest(
+ { permissions: { net: true } },
+ async function fetchContentLengthPostWithStringBody() {
+ const response = await fetch("http://localhost:4545/content_length", {
+ method: "POST",
+ body: "Hey!",
+ });
+ const length = await response.text();
+ assertEquals(length, 'Some("4")');
+ },
+);
+
+unitTest(
+ { permissions: { net: true } },
+ async function fetchContentLengthPostWithBufferBody() {
+ const response = await fetch("http://localhost:4545/content_length", {
+ method: "POST",
+ body: new TextEncoder().encode("Hey!"),
+ });
+ const length = await response.text();
+ assertEquals(length, 'Some("4")');
+ },
+);
diff --git a/ext/fetch/lib.rs b/ext/fetch/lib.rs
index b4bffb6de..4bd62cd7c 100644
--- a/ext/fetch/lib.rs
+++ b/ext/fetch/lib.rs
@@ -246,7 +246,7 @@ where
let permissions = state.borrow_mut::<FP>();
permissions.check_net_url(&url)?;
- let mut request = client.request(method, url);
+ let mut request = client.request(method.clone(), url);
let request_body_rid = if args.has_body {
match data {
@@ -278,6 +278,11 @@ where
}
}
} else {
+ // POST and PUT requests should always have a 0 length content-length,
+ // if there is no body. https://fetch.spec.whatwg.org/#http-network-or-cache-fetch
+ if matches!(method, Method::POST | Method::PUT) {
+ request = request.header(CONTENT_LENGTH, HeaderValue::from(0));
+ }
None
};
diff --git a/test_util/src/lib.rs b/test_util/src/lib.rs
index e57f55f1e..06ca6464d 100644
--- a/test_util/src/lib.rs
+++ b/test_util/src/lib.rs
@@ -851,6 +851,10 @@ async fn main_server(
let version = format!("{:?}", req.version());
Ok(Response::new(version.into()))
}
+ (_, "/content_length") => {
+ let content_length = format!("{:?}", req.headers().get("content-length"));
+ Ok(Response::new(content_length.into()))
+ }
(_, "/jsx/jsx-runtime") | (_, "/jsx/jsx-dev-runtime") => {
let mut res = Response::new(Body::from(
r#"export function jsx(