1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-11-25 15:29:32 -05:00

fix(ext/flash): use utf8 length as Content-Length (#15793)

This commit is contained in:
Divy Srivastava 2022-09-07 16:21:30 +05:30 committed by GitHub
parent 7f4b043f32
commit d57f9d560d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 68 additions and 3 deletions

View file

@ -495,6 +495,43 @@ Deno.test(
},
);
Deno.test(
{ permissions: { net: true } },
async function httpServerCorrectLengthForUnicodeString() {
const ac = new AbortController();
const listeningPromise = deferred();
const server = Deno.serve({
handler: () => new Response("韓國".repeat(10)),
port: 4503,
signal: ac.signal,
onListen: onListen(listeningPromise),
onError: createOnErrorCb(ac),
});
await listeningPromise;
const conn = await Deno.connect({ port: 4503 });
const encoder = new TextEncoder();
const decoder = new TextDecoder();
const body =
`GET / HTTP/1.1\r\nHost: example.domain\r\nConnection: close\r\n\r\n`;
const writeResult = await conn.write(encoder.encode(body));
assertEquals(body.length, writeResult);
const buf = new Uint8Array(1024);
const readResult = await conn.read(buf);
assert(readResult);
const msg = decoder.decode(buf.subarray(0, readResult));
conn.close();
ac.abort();
await server;
assert(msg.includes("Content-Length: 60"));
},
);
Deno.test({ permissions: { net: true } }, async function httpServerWebSocket() {
const ac = new AbortController();
const listeningPromise = deferred();

View file

@ -323,6 +323,7 @@
opNames: () => ops.op_op_names(),
eventLoopHasMoreWork: () => ops.op_event_loop_has_more_work(),
setPromiseRejectCallback: (fn) => ops.op_set_promise_reject_callback(fn),
byteLength: (str) => ops.op_str_byte_length(str),
});
ObjectAssign(globalThis.__bootstrap, { core });

View file

@ -39,6 +39,7 @@ pub(crate) fn init_builtins() -> Extension {
op_metrics::decl(),
op_format_file_name::decl(),
op_is_proxy::decl(),
op_str_byte_length::decl(),
])
.ops(crate::ops_builtin_v8::init_builtins_v8())
.build()
@ -195,3 +196,15 @@ fn op_format_file_name(file_name: String) -> String {
fn op_is_proxy(value: serde_v8::Value) -> bool {
value.v8_value.is_proxy()
}
#[op(v8)]
fn op_str_byte_length(
scope: &mut v8::HandleScope,
value: serde_v8::Value,
) -> u32 {
if let Ok(string) = v8::Local::<v8::String>::try_from(value.v8_value) {
string.utf8_length(scope) as u32
} else {
0
}
}

View file

@ -122,7 +122,14 @@
// CRLF
// [ message-body ]
//
function http1Response(method, status, headerList, body, earlyEnd = false) {
function http1Response(
method,
status,
headerList,
body,
bodyLen,
earlyEnd = false,
) {
// HTTP uses a "<major>.<minor>" numbering scheme
// HTTP-version = HTTP-name "/" DIGIT "." DIGIT
// HTTP-name = %x48.54.54.50 ; "HTTP", case-sensitive
@ -155,7 +162,7 @@
// null body status is validated by inititalizeAResponse in ext/fetch
if (body !== null && body !== undefined) {
str += `Content-Length: ${body.length}\r\n\r\n`;
str += `Content-Length: ${bodyLen}\r\n\r\n`;
} else {
str += "Transfer-Encoding: chunked\r\n\r\n";
return str;
@ -192,6 +199,7 @@
server,
requestId,
response,
responseLen,
end,
respondFast,
) {
@ -215,7 +223,7 @@
}
}
if (nwritten < response.length) {
if (nwritten < responseLen) {
core.opAsync(
"op_flash_respond_async",
server,
@ -421,16 +429,19 @@
const ws = resp[_ws];
if (isStreamingResponseBody === false) {
const length = respBody.byteLength || core.byteLength(respBody);
const responseStr = http1Response(
method,
innerResp.status ?? 200,
innerResp.headerList,
respBody,
length,
);
writeFixedResponse(
serverId,
i,
responseStr,
length,
!ws, // Don't close socket if there is a deferred websocket upgrade.
respondFast,
);
@ -460,6 +471,7 @@
method,
innerResp.status ?? 200,
innerResp.headerList,
0, // Content-Length will be set by the op.
null,
true,
),
@ -483,8 +495,10 @@
method,
innerResp.status ?? 200,
innerResp.headerList,
respBody.byteLength,
null,
),
respBody.byteLength,
false,
respondFast,
);