summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreu Botella <abb@randomunok.com>2021-06-27 02:29:01 +0200
committerGitHub <noreply@github.com>2021-06-27 02:29:01 +0200
commit5bf7da91f178067c62d07f0220c99ba27791d206 (patch)
tree327224bc4c7783b34bbaefd0af0c731fed25c382
parent7b9737b9f4c25e1d25bfb352198cf24a50ceb2de (diff)
fix(runtime/http): Encode and decode headers as byte strings in the HTTP server (#11144)
-rw-r--r--cli/tests/unit/http_test.ts43
-rw-r--r--runtime/ops/http.rs16
2 files changed, 53 insertions, 6 deletions
diff --git a/cli/tests/unit/http_test.ts b/cli/tests/unit/http_test.ts
index c94e8bef1..0c7aec155 100644
--- a/cli/tests/unit/http_test.ts
+++ b/cli/tests/unit/http_test.ts
@@ -543,3 +543,46 @@ unitTest(
listener.close();
},
);
+
+unitTest({ perms: { net: true } }, async function httpRequestLatin1Headers() {
+ 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(request.headers.get("X-Header-Test"), "á");
+ await respondWith(
+ new Response("", { headers: { "X-Header-Test": "Æ" } }),
+ );
+ httpConn.close();
+ }
+ break;
+ }
+ })();
+
+ const clientConn = await Deno.connect({ port: 4501 });
+ const requestText =
+ "GET / HTTP/1.1\r\nHost: 127.0.0.1:4501\r\nX-Header-Test: á\r\n\r\n";
+ const requestBytes = new Uint8Array(requestText.length);
+ for (let i = 0; i < requestText.length; i++) {
+ requestBytes[i] = requestText.charCodeAt(i);
+ }
+ let written = 0;
+ while (written < requestBytes.byteLength) {
+ written += await clientConn.write(requestBytes.slice(written));
+ }
+
+ let responseText = "";
+ const buf = new Uint8Array(1024);
+ let read;
+ while ((read = await clientConn.read(buf)) !== null) {
+ for (let i = 0; i < read; i++) {
+ responseText += String.fromCharCode(buf[i]);
+ }
+ }
+ clientConn.close();
+
+ assert(/\r\n[Xx]-[Hh]eader-[Tt]est: Æ\r\n/.test(responseText));
+
+ await promise;
+});
diff --git a/runtime/ops/http.rs b/runtime/ops/http.rs
index 3e8a4ada7..cd1ac9242 100644
--- a/runtime/ops/http.rs
+++ b/runtime/ops/http.rs
@@ -14,6 +14,7 @@ use deno_core::futures::StreamExt;
use deno_core::op_async;
use deno_core::op_sync;
use deno_core::AsyncRefCell;
+use deno_core::ByteString;
use deno_core::CancelHandle;
use deno_core::CancelTryFuture;
use deno_core::Extension;
@@ -140,9 +141,11 @@ struct NextRequestResponse(
// response_sender_rid:
ResourceId,
// method:
+ // This is a String rather than a ByteString because reqwest will only return
+ // the method as a str which is guaranteed to be ASCII-only.
String,
// headers:
- Vec<(String, String)>,
+ Vec<(ByteString, ByteString)>,
// url:
String,
);
@@ -199,9 +202,10 @@ async fn op_http_request_next(
let mut headers = Vec::with_capacity(req.headers().len());
for (name, value) in req.headers().iter() {
- let name = name.to_string();
- let value = value.to_str().unwrap_or("").to_string();
- headers.push((name, value));
+ let name: &[u8] = name.as_ref();
+ let value = value.as_bytes();
+ headers
+ .push((ByteString(name.to_owned()), ByteString(value.to_owned())));
}
let url = {
@@ -346,7 +350,7 @@ struct RespondArgs(
// status:
u16,
// headers:
- Vec<(String, String)>,
+ Vec<(ByteString, ByteString)>,
);
async fn op_http_response(
@@ -375,7 +379,7 @@ async fn op_http_response(
builder.headers_mut().unwrap().reserve(headers.len());
for (key, value) in &headers {
- builder = builder.header(key, value);
+ builder = builder.header(key.as_ref(), value.as_ref());
}
let res;