Skip to content

Commit d82a993

Browse files
Jake ChampionJakeChampion
authored andcommitted
Ensure that the manual framing headers field is set correctly during Request construction
We add a new slot for FramingHeadersManuallyFromHeaders so that when we come to clone a request, we can read that slot and set the same value on the new request
1 parent 4638040 commit d82a993

File tree

5 files changed

+74
-40
lines changed

5 files changed

+74
-40
lines changed

integration-tests/js-compute/fixtures/app/fastly.toml.in

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ service_id = ""
2727
url = "https://httpbin.org"
2828
override_host = "httpbin.org"
2929

30+
[local_server.backends.httpme]
31+
url = "https://http-me.glitch.me"
32+
override_host = "http-me.glitch.me"
33+
3034
[local_server.config_stores]
3135
[local_server.config_stores.testconfig]
3236
format = "inline-toml"
@@ -105,6 +109,10 @@ service_id = ""
105109
address = "httpbin.org"
106110
port = 443
107111

112+
[setup.backends.httpme]
113+
address = "http-me.glitch.me"
114+
port = 443
115+
108116
[setup.backends.TheOrigin]
109117
address = "compute-sdk-test-backend.edgecompute.app"
110118
port = 443

integration-tests/js-compute/fixtures/app/src/override-content-length.js

Lines changed: 39 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -7,66 +7,77 @@ import { routes, isRunningLocally } from "./routes.js";
77
let error;
88

99
async function requestInitObjectLiteral(overrideContentLength) {
10-
let response = await fetch(new Request('https://httpbin.org/headers', {
11-
backend: 'httpbin',
10+
let request = new Request('https://http-me.glitch.me/anything', {
11+
backend: 'httpme',
12+
method: 'POST',
13+
body: 'meow',
1214
overrideContentLength,
1315
headers: {
14-
"Content-Length": "1"
16+
"content-length": "1"
1517
}
16-
}));
18+
});
19+
let response = await fetch(request);
1720
let body = await response.json()
18-
return body?.headers?.["Content-Length"];
21+
return body?.headers?.["content-length"];
1922
}
2023

2124
async function requestInitRequestInstance(overrideContentLength) {
22-
let request = new Request('https://httpbin.org/headers', {
23-
backend: 'httpbin',
25+
let request = new Request('https://http-me.glitch.me/anything', {
26+
backend: 'httpme',
27+
method: 'POST',
28+
body: 'meow',
2429
overrideContentLength,
2530
headers: {
26-
"Content-Length": "1"
31+
"content-length": "1"
2732
}
2833
});
29-
let response = await fetch(new Request('https://httpbin.org/headers', request));
34+
let response = await fetch(new Request('https://http-me.glitch.me/anything', request));
3035
let body = await response.json()
31-
return body?.headers?.["Content-Length"];
36+
return body?.headers?.["content-length"];
3237
}
3338

3439
async function requestClone(overrideContentLength) {
35-
let request = new Request('https://httpbin.org/headers', {
36-
backend: 'httpbin',
40+
let request = new Request('https://http-me.glitch.me/anything', {
41+
backend: 'httpme',
42+
method: 'POST',
43+
body: 'meow',
3744
overrideContentLength,
3845
headers: {
39-
"Content-Length": "1"
46+
"content-length": "1"
4047
}
4148
});
4249
let response = await fetch(request.clone());
4350
let body = await response.json()
44-
return body?.headers?.["Content-Length"];
51+
return body?.headers?.["content-length"];
4552
}
4653

4754
async function fetchInitObjectLiteral(overrideContentLength) {
48-
let response = await fetch('https://httpbin.org/headers', {
49-
backend: 'httpbin',
55+
let response = await fetch('https://http-me.glitch.me/anything', {
56+
backend: 'httpme',
57+
method: 'POST',
58+
body: 'meow',
5059
overrideContentLength,
5160
headers: {
52-
"Content-Length": "1"
61+
"content-length": "1"
5362
}
5463
});
5564
let body = await response.json()
56-
return body?.headers?.["Content-Length"];
65+
return body?.headers?.["content-length"];
5766
}
5867

5968
async function fetchInitRequestInstance(overrideContentLength) {
60-
let request = new Request('https://httpbin.org/headers', {
61-
backend: 'httpbin',
69+
let request = new Request('https://http-me.glitch.me/anything', {
70+
backend: 'httpme',
71+
method: 'POST',
72+
body: 'meow',
6273
overrideContentLength,
6374
headers: {
64-
"Content-Length": "1"
75+
"content-length": "1"
6576
}
6677
});
67-
let response = await fetch('https://httpbin.org/headers', request);
78+
let response = await fetch('https://http-me.glitch.me/anything', request);
6879
let body = await response.json()
69-
return body?.headers?.["Content-Length"];
80+
return body?.headers?.["content-length"];
7081
}
7182

7283
routes.set("/override-content-length/request/init/object-literal/true", async () => {
@@ -85,7 +96,7 @@ routes.set("/override-content-length/request/init/object-literal/true", async ()
8596

8697
routes.set("/override-content-length/request/init/object-literal/false", async () => {
8798
let actual = await requestInitObjectLiteral(false);
88-
let expected = "0"
99+
let expected = "4"
89100
error = assert(actual, expected, `await requestInitObjectLiteral(false)`)
90101
if (error) { return error }
91102

@@ -108,7 +119,7 @@ routes.set("/override-content-length/request/init/request-instance/true", async
108119

109120
routes.set("/override-content-length/request/init/request-instance/false", async () => {
110121
let actual = await requestInitRequestInstance(false);
111-
let expected = "0"
122+
let expected = "4"
112123
error = assert(actual, expected, `await requestInitRequestInstance(false)`)
113124
if (error) { return error }
114125

@@ -131,7 +142,7 @@ routes.set("/override-content-length/request/clone/true", async () => {
131142

132143
routes.set("/override-content-length/request/clone/false", async () => {
133144
let actual = await requestClone(false);
134-
let expected = "0"
145+
let expected = "4"
135146
error = assert(actual, expected, `await requestClone(false)`)
136147
if (error) { return error }
137148

@@ -154,7 +165,7 @@ routes.set("/override-content-length/fetch/init/object-literal/true", async () =
154165

155166
routes.set("/override-content-length/fetch/init/object-literal/false", async () => {
156167
let actual = await fetchInitObjectLiteral(false);
157-
let expected = "0"
168+
let expected = "4"
158169
error = assert(actual, expected, `await fetchInitObjectLiteral(false)`)
159170
if (error) { return error }
160171

@@ -177,7 +188,7 @@ routes.set("/override-content-length/fetch/init/request-instance/true", async ()
177188

178189
routes.set("/override-content-length/fetch/init/request-instance/false", async () => {
179190
let actual = await fetchInitRequestInstance(false);
180-
let expected = "0"
191+
let expected = "4"
181192
error = assert(actual, expected, `await fetchInitRequestInstance(false)`)
182193
if (error) { return error }
183194

runtime/js-compute-runtime/builtins/request-response.cpp

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1673,28 +1673,20 @@ JSObject *Request::create(JSContext *cx, JS::HandleObject requestInstance, JS::H
16731673
JS::RootedValue backend_val(cx);
16741674
JS::RootedValue cache_override(cx);
16751675
JS::RootedValue fastly_val(cx);
1676+
JS::RootedValue overrideContentLength(cx);
1677+
bool hasOverrideContentLength;
16761678
if (init_val.isObject()) {
16771679
JS::RootedObject init(cx, init_val.toObjectOrNull());
1678-
JS::RootedValue overrideContentLength(cx);
16791680
if (!JS_GetProperty(cx, init, "method", &method_val) ||
16801681
!JS_GetProperty(cx, init, "headers", &headers_val) ||
16811682
!JS_GetProperty(cx, init, "body", &body_val) ||
16821683
!JS_GetProperty(cx, init, "backend", &backend_val) ||
16831684
!JS_GetProperty(cx, init, "cacheOverride", &cache_override) ||
16841685
!JS_GetProperty(cx, init, "fastly", &fastly_val) ||
1686+
!JS_HasOwnProperty(cx, init, "overrideContentLength", &hasOverrideContentLength) ||
16851687
!JS_GetProperty(cx, init, "overrideContentLength", &overrideContentLength)) {
16861688
return nullptr;
16871689
}
1688-
1689-
if (JS::ToBoolean(overrideContentLength)) {
1690-
auto res = request_handle.set_framing_headers_mode(
1691-
host_api::FramingHeadersMode::ManuallyFromHeaders);
1692-
if (auto *err = res.to_err()) {
1693-
HANDLE_ERROR(cx, *err);
1694-
return nullptr;
1695-
}
1696-
}
1697-
16981690
} else if (!init_val.isNullOrUndefined()) {
16991691
JS_ReportErrorLatin1(cx, "Request constructor: |init| parameter can't be converted to "
17001692
"a dictionary");
@@ -2004,6 +1996,25 @@ JSObject *Request::create(JSContext *cx, JS::HandleObject requestInstance, JS::H
20041996
JS::BooleanValue(false));
20051997
}
20061998

1999+
if (!hasOverrideContentLength) {
2000+
if (input_request) {
2001+
overrideContentLength.set(JS::GetReservedSlot(input_request, static_cast<uint32_t>(Slots::FramingHeadersManuallyFromHeaders)));
2002+
} else {
2003+
overrideContentLength.setBoolean(false);
2004+
}
2005+
}
2006+
JS::SetReservedSlot(request, static_cast<uint32_t>(Slots::FramingHeadersManuallyFromHeaders),
2007+
JS::BooleanValue(JS::ToBoolean(overrideContentLength)));
2008+
2009+
if (JS::ToBoolean(overrideContentLength)) {
2010+
auto res = request_handle.set_framing_headers_mode(
2011+
host_api::FramingHeadersMode::ManuallyFromHeaders);
2012+
if (auto *err = res.to_err()) {
2013+
HANDLE_ERROR(cx, *err);
2014+
return nullptr;
2015+
}
2016+
}
2017+
20072018
return request;
20082019
}
20092020

runtime/js-compute-runtime/builtins/request-response.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ class RequestOrResponse final {
1818
BodyUsed,
1919
Headers,
2020
URL,
21+
FramingHeadersManuallyFromHeaders,
2122
Count,
2223
};
2324

@@ -126,6 +127,7 @@ class Request final : public BuiltinImpl<Request> {
126127
BodyUsed = static_cast<int>(RequestOrResponse::Slots::BodyUsed),
127128
Headers = static_cast<int>(RequestOrResponse::Slots::Headers),
128129
URL = static_cast<int>(RequestOrResponse::Slots::URL),
130+
FramingHeadersManuallyFromHeaders = static_cast<int>(RequestOrResponse::Slots::FramingHeadersManuallyFromHeaders),
129131
Backend = static_cast<int>(RequestOrResponse::Slots::Count),
130132
Method,
131133
CacheOverride,
@@ -196,6 +198,7 @@ class Response final : public BuiltinImpl<Response> {
196198
HasBody = static_cast<int>(RequestOrResponse::Slots::HasBody),
197199
BodyUsed = static_cast<int>(RequestOrResponse::Slots::BodyUsed),
198200
Headers = static_cast<int>(RequestOrResponse::Slots::Headers),
201+
FramingHeadersManuallyFromHeaders = static_cast<int>(RequestOrResponse::Slots::FramingHeadersManuallyFromHeaders),
199202
IsUpstream = static_cast<int>(RequestOrResponse::Slots::Count),
200203
Status,
201204
StatusMessage,

runtime/js-compute-runtime/js-compute-builtins.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -631,8 +631,9 @@ bool fetch(JSContext *cx, unsigned argc, Value *vp) {
631631

632632
RootedObject requestInstance(
633633
cx, JS_NewObjectWithGivenProto(cx, &builtins::Request::class_, builtins::Request::proto_obj));
634-
if (!requestInstance)
634+
if (!requestInstance) {
635635
return false;
636+
}
636637

637638
RootedObject request(cx, builtins::Request::create(cx, requestInstance, args[0], args.get(1)));
638639
if (!request) {

0 commit comments

Comments
 (0)