17
17
#include " js/JSON.h"
18
18
#include " js/Stream.h"
19
19
#include < algorithm>
20
+ #include < iostream>
20
21
#include < vector>
21
22
22
23
#pragma clang diagnostic push
@@ -2236,6 +2237,14 @@ bool Response::type_get(JSContext *cx, unsigned argc, JS::Value *vp) {
2236
2237
return true ;
2237
2238
}
2238
2239
2240
+ bool Response::redirected_get (JSContext *cx, unsigned argc, JS::Value *vp) {
2241
+ METHOD_HEADER (0 )
2242
+
2243
+ args.rval ().setBoolean (
2244
+ JS::GetReservedSlot (self, static_cast <uint32_t >(Slots::Redirected)).toBoolean ());
2245
+ return true ;
2246
+ }
2247
+
2239
2248
bool Response::headers_get (JSContext *cx, unsigned argc, JS::Value *vp) {
2240
2249
METHOD_HEADER (0 )
2241
2250
@@ -2265,7 +2274,118 @@ bool Response::bodyUsed_get(JSContext *cx, unsigned argc, JS::Value *vp) {
2265
2274
return true ;
2266
2275
}
2267
2276
2277
+ // https://fetch.spec.whatwg.org/#dom-response-redirect
2278
+ // [NewObject] static Response redirect(USVString url, optional unsigned short status = 302);
2279
+ bool Response::redirect (JSContext *cx, unsigned argc, JS::Value *vp) {
2280
+ JS::CallArgs args = JS::CallArgsFromVp (argc, vp);
2281
+ if (!args.requireAtLeast (cx, " redirect" , 1 )) {
2282
+ return false ;
2283
+ }
2284
+ auto url = args.get (0 );
2285
+ // 1. Let parsedURL be the result of parsing url with current settings object’s API base URL.
2286
+ JS::RootedObject urlInstance (
2287
+ cx, JS_NewObjectWithGivenProto (cx, &builtins::URL::class_, builtins::URL::proto_obj));
2288
+ if (!urlInstance) {
2289
+ return false ;
2290
+ }
2291
+ JS::RootedObject parsedURL (
2292
+ cx, builtins::URL::create (cx, urlInstance, url, builtins::Fastly::baseURL));
2293
+ // 2. If parsedURL is failure, then throw a TypeError.
2294
+ if (!parsedURL) {
2295
+ JS_ReportErrorNumberASCII (cx, GetErrorMessage, nullptr , JSMSG_RESPONSE_REDIRECT_INVALID_URI);
2296
+ return false ;
2297
+ }
2298
+ JS::RootedValue url_val (cx, JS::ObjectValue (*parsedURL));
2299
+ size_t length;
2300
+ auto url_str = encode (cx, url_val, &length);
2301
+ if (!url_str) {
2302
+ return false ;
2303
+ }
2304
+ auto value = url_str.get ();
2305
+ // 3. If status is not a redirect status, then throw a RangeError.
2306
+ // A redirect status is a status that is 301, 302, 303, 307, or 308.
2307
+ auto statusVal = args.get (1 );
2308
+ uint16_t status;
2309
+ if (statusVal.isUndefined ()) {
2310
+ status = 302 ;
2311
+ } else {
2312
+ if (!JS::ToUint16 (cx, statusVal, &status)) {
2313
+ return false ;
2314
+ }
2315
+ }
2316
+ if (status != 301 && status != 302 && status != 303 && status != 307 && status != 308 ) {
2317
+ JS_ReportErrorNumberASCII (cx, GetErrorMessage, nullptr , JSMSG_RESPONSE_REDIRECT_INVALID_STATUS);
2318
+ return false ;
2319
+ }
2320
+ // 4. Let responseObject be the result of creating a Response object, given a new response,
2321
+ // "immutable", and this’s relevant Realm.
2322
+ fastly_response_handle_t response_handle = INVALID_HANDLE;
2323
+ fastly_error_t err;
2324
+ if (!fastly_http_resp_new (&response_handle, &err)) {
2325
+ HANDLE_ERROR (cx, err);
2326
+ return false ;
2327
+ }
2328
+ if (response_handle == INVALID_HANDLE) {
2329
+ return false ;
2330
+ }
2331
+
2332
+ auto make_res = HttpBody::make ();
2333
+ if (auto *err = make_res.to_err ()) {
2334
+ HANDLE_ERROR (cx, *err);
2335
+ return false ;
2336
+ }
2337
+
2338
+ auto body = make_res.unwrap ();
2339
+ JS::RootedObject response_instance (cx, JS_NewObjectWithGivenProto (cx, &builtins::Response::class_,
2340
+ builtins::Response::proto_obj));
2341
+ if (!response_instance) {
2342
+ return false ;
2343
+ }
2344
+ JS::RootedObject response (cx, create (cx, response_instance, response_handle, body.handle , false ));
2345
+ if (!response) {
2346
+ return false ;
2347
+ }
2348
+
2349
+ // 5. Set responseObject’s response’s status to status.
2350
+ if (!fastly_http_resp_status_set (response_handle, status, &err)) {
2351
+ HANDLE_ERROR (cx, err);
2352
+ return false ;
2353
+ }
2354
+ // To ensure that we really have the same status value as the host,
2355
+ // we always read it back here.
2356
+ if (!fastly_http_resp_status_get (response_handle, &status, &err)) {
2357
+ HANDLE_ERROR (cx, err);
2358
+ return false ;
2359
+ }
2360
+ JS::SetReservedSlot (response, static_cast <uint32_t >(Slots::Status), JS::Int32Value (status));
2361
+ JS::SetReservedSlot (response, static_cast <uint32_t >(Slots::StatusMessage),
2362
+ JS::StringValue (JS_GetEmptyString (cx)));
2363
+ // 6. Let value be parsedURL, serialized and isomorphic encoded.
2364
+ // 7. Append (`Location`, value) to responseObject’s response’s header list.
2365
+ JS::RootedObject headers (cx);
2366
+ JS::RootedObject headersInstance (
2367
+ cx, JS_NewObjectWithGivenProto (cx, &builtins::Headers::class_, builtins::Headers::proto_obj));
2368
+ if (!headersInstance)
2369
+ return false ;
2370
+
2371
+ headers = builtins::Headers::create (cx, headersInstance, builtins::Headers::Mode::ProxyToResponse,
2372
+ response);
2373
+ if (!headers) {
2374
+ return false ;
2375
+ }
2376
+ if (!builtins::Headers::maybe_add (cx, headers, " Location" , value)) {
2377
+ return false ;
2378
+ }
2379
+ JS::SetReservedSlot (response, static_cast <uint32_t >(Slots::Headers), JS::ObjectValue (*headers));
2380
+ JS::SetReservedSlot (response, static_cast <uint32_t >(Slots::Redirected), JS::FalseValue ());
2381
+ // 8. Return responseObject.
2382
+
2383
+ args.rval ().setObjectOrNull (response);
2384
+ return true ;
2385
+ }
2386
+
2268
2387
const JSFunctionSpec Response::static_methods[] = {
2388
+ JS_FN (" redirect" , redirect, 1 , JSPROP_ENUMERATE),
2269
2389
JS_FS_END,
2270
2390
};
2271
2391
@@ -2282,6 +2402,7 @@ const JSFunctionSpec Response::methods[] = {
2282
2402
};
2283
2403
2284
2404
const JSPropertySpec Response::properties[] = {
2405
+ JS_PSG (" redirected" , redirected_get, JSPROP_ENUMERATE),
2285
2406
JS_PSG (" type" , type_get, JSPROP_ENUMERATE),
2286
2407
JS_PSG (" url" , url_get, JSPROP_ENUMERATE),
2287
2408
JS_PSG (" status" , status_get, JSPROP_ENUMERATE),
@@ -2458,13 +2579,18 @@ bool Response::init_class(JSContext *cx, JS::HandleObject global) {
2458
2579
JSObject *Response::create (JSContext *cx, JS::HandleObject response,
2459
2580
fastly_response_handle_t response_handle,
2460
2581
fastly_body_handle_t body_handle, bool is_upstream) {
2582
+ // MOZ_ASSERT(cx);
2583
+ // MOZ_ASSERT(is_instance(response));
2584
+ // MOZ_ASSERT(response_handle);
2585
+ // MOZ_ASSERT(body_handle);
2461
2586
JS::SetReservedSlot (response, static_cast <uint32_t >(Slots::Response),
2462
2587
JS::Int32Value (response_handle));
2463
2588
JS::SetReservedSlot (response, static_cast <uint32_t >(Slots::Headers), JS::NullValue ());
2464
2589
JS::SetReservedSlot (response, static_cast <uint32_t >(Slots::Body), JS::Int32Value (body_handle));
2465
2590
JS::SetReservedSlot (response, static_cast <uint32_t >(Slots::BodyStream), JS::NullValue ());
2466
2591
JS::SetReservedSlot (response, static_cast <uint32_t >(Slots::HasBody), JS::FalseValue ());
2467
2592
JS::SetReservedSlot (response, static_cast <uint32_t >(Slots::BodyUsed), JS::FalseValue ());
2593
+ JS::SetReservedSlot (response, static_cast <uint32_t >(Slots::Redirected), JS::FalseValue ());
2468
2594
JS::SetReservedSlot (response, static_cast <uint32_t >(Slots::IsUpstream),
2469
2595
JS::BooleanValue (is_upstream));
2470
2596
0 commit comments