summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuca Casonato <hello@lcas.dev>2021-07-16 16:31:16 +0200
committerGitHub <noreply@github.com>2021-07-16 16:31:16 +0200
commit91bbd1a6d5ec21595efe790ff482c7a96b7fafb4 (patch)
treeadc03226d56ffa498e8b744b79ddbde354c59e64
parent2e57476fbbed240d9636561a05e53d454f232aa0 (diff)
fix(ext/http): correctly concat cookie headers (#11422)
Cookie headers should not be concatenated by commas, rather by semicolons.
-rw-r--r--cli/tests/unit/http_test.ts27
-rw-r--r--extensions/http/lib.rs37
2 files changed, 60 insertions, 4 deletions
diff --git a/cli/tests/unit/http_test.ts b/cli/tests/unit/http_test.ts
index 21325ff77..bf351cd48 100644
--- a/cli/tests/unit/http_test.ts
+++ b/cli/tests/unit/http_test.ts
@@ -662,3 +662,30 @@ unitTest({ perms: { net: true } }, async function httpServerWebSocket() {
await def;
await promise;
});
+
+unitTest({ perms: { net: true } }, async function httpCookieConcatenation() {
+ const promise = (async () => {
+ const listener = Deno.listen({ port: 4501 });
+ for await (const conn of listener) {
+ const httpConn = Deno.serveHttp(conn);
+ for await (const { request, respondWith } of httpConn) {
+ assertEquals(new URL(request.url).href, "http://127.0.0.1:4501/");
+ assertEquals(await request.text(), "");
+ assertEquals(request.headers.get("cookie"), "foo=bar; bar=foo");
+ respondWith(new Response("ok"));
+ }
+ break;
+ }
+ })();
+
+ const resp = await fetch("http://127.0.0.1:4501/", {
+ headers: [
+ ["connection", "close"],
+ ["cookie", "foo=bar"],
+ ["cookie", "bar=foo"],
+ ],
+ });
+ const text = await resp.text();
+ assertEquals(text, "ok");
+ await promise;
+});
diff --git a/extensions/http/lib.rs b/extensions/http/lib.rs
index a8d92ab46..a20e74c03 100644
--- a/extensions/http/lib.rs
+++ b/extensions/http/lib.rs
@@ -217,12 +217,41 @@ async fn op_http_request_next(
let req = request_resource.request;
let method = req.method().to_string();
+ // We treat cookies specially, because we don't want them to get them
+ // mangled by the `Headers` object in JS. What we do is take all cookie
+ // headers and concat them into a single cookie header, seperated by
+ // semicolons.
+ let mut total_cookie_length = 0;
+ let mut cookies = vec![];
+
let mut headers = Vec::with_capacity(req.headers().len());
for (name, value) in req.headers().iter() {
- let name: &[u8] = name.as_ref();
- let value = value.as_bytes();
- headers
- .push((ByteString(name.to_owned()), ByteString(value.to_owned())));
+ if name == hyper::header::COOKIE {
+ let bytes = value.as_bytes();
+ total_cookie_length += bytes.len();
+ cookies.push(bytes);
+ } else {
+ let name: &[u8] = name.as_ref();
+ let value = value.as_bytes();
+ headers
+ .push((ByteString(name.to_owned()), ByteString(value.to_owned())));
+ }
+ }
+
+ if !cookies.is_empty() {
+ let cookie_count = cookies.len();
+ total_cookie_length += (cookie_count * 2) - 2;
+ let mut bytes = Vec::with_capacity(total_cookie_length);
+ for (i, cookie) in cookies.into_iter().enumerate() {
+ bytes.extend(cookie);
+ if i != cookie_count - 1 {
+ bytes.extend("; ".as_bytes());
+ }
+ }
+ headers.push((
+ ByteString("cookie".as_bytes().to_owned()),
+ ByteString(bytes),
+ ));
}
let url = {