feat(fetch): Add Response.redirect() and Response.json() statics#5044
feat(fetch): Add Response.redirect() and Response.json() statics#5044RajdeepKushwaha5 wants to merge 6 commits intoboa-dev:mainfrom
Conversation
Implements proper iterator support for Headers.prototype.entries(), keys(), and values() methods following the WHATWG Fetch specification. Changes: - Created HeadersIterator struct to manage iteration state - Implements entries(), keys(), and values() as proper iterator methods using #[boa(method)] - Fixed Symbol.iterator binding to call entries() method dynamically - Headers iterators now properly return [Symbol.iterator] result objects with done/value properties - Removed invalid downcast pattern from Symbol.iterator handler Fixes: #4989
This resolves issue #5042. - Implemented Response.redirect(url, status). Default status is 302. Throws RangeError on invalid status code according to spec. - Implemented Response.json(data, init). It converts data to JSON using engine's JSON.stringify, and constructs a new Response. Enforces Content-Type: application/json unless overridden in init.headers. - Added unit tests to core/runtime/src/fetch/tests/response.rs to validate behaviors.
There was a problem hiding this comment.
Pull request overview
Adds missing Fetch Response static constructors to the runtime, extending the existing fetch implementation and its JS interop tests.
Changes:
- Implement
Response.redirect(url, status)andResponse.json(data, init)statics onResponse. - Update
Headersiteration to return iterator objects forentries()/keys()/values()and adjust[Symbol.iterator]wiring. - Add a runtime loop-iteration limit guard to
String.prototype.repeat, plus a regression test.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| core/runtime/src/fetch/response.rs | Adds Response.redirect() and Response.json() static constructors. |
| core/runtime/src/fetch/tests/response.rs | Adds JS-level tests for Response.redirect() and Response.json(). |
| core/runtime/src/fetch/mod.rs | Changes Headers.prototype[Symbol.iterator] implementation to call entries() via JS property access. |
| core/runtime/src/fetch/headers.rs | Reworks Headers.entries()/keys()/values() to return iterator objects; adds iterator plumbing. |
| core/engine/src/builtins/string/mod.rs | Adds runtime loop-iteration limit guarding to String.prototype.repeat. |
| core/engine/src/builtins/string/tests.rs | Adds a test ensuring repeat() respects the loop runtime limit. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // Runtime limit guard for native loops inside this builtin. | ||
| let previous_iteration_count = context.vm.frame().loop_iteration_count; | ||
| let max_iteration_count = context.vm.runtime_limits.loop_iteration_limit(); | ||
| let loop_iteration_count = previous_iteration_count.saturating_add(n); | ||
|
|
| #[boa(method)] | ||
| pub fn entries(this: JsClass<Self>, context: &mut Context) -> JsValue { | ||
| let iterator = HeadersIterator::new(this.clone_inner(), HeadersIteratorKind::Entries); | ||
| create_headers_iterator_object(iterator, context) | ||
| } |
| fn redirect(url: JsString, status: Option<u16>, _context: &mut Context) -> JsResult<Self> { | ||
| let status = status.unwrap_or(302); | ||
|
|
||
| if !matches!(status, 301 | 302 | 303 | 307 | 308) { | ||
| return Err(JsNativeError::range() |
core/runtime/src/fetch/response.rs
Outdated
| let json = context.global_object().get(js_string!("JSON"), context)?; | ||
| let stringify = json | ||
| .as_object() | ||
| .ok_or_else(|| JsNativeError::typ().with_message("JSON is not an object"))? | ||
| .get(js_string!("stringify"), context)?; | ||
|
|
||
| let text = stringify | ||
| .as_callable() | ||
| .ok_or_else(|| JsNativeError::typ().with_message("stringify is not a function"))? | ||
| .call(&json, &[data], context)?; |
core/runtime/src/fetch/mod.rs
Outdated
| // Get the entries method from the prototype and call it | ||
| let entries_fn = this_object | ||
| .get(js_string!("entries"), context)?; | ||
|
|
||
| entries_fn.as_function() |
core/runtime/src/fetch/headers.rs
Outdated
| #[allow(let_underscore_drop)] | ||
| let _ = iterator_obj.define_property_or_throw( | ||
| js_string!("next"), | ||
| PropertyDescriptor::builder() | ||
| .value(next_fn) | ||
| .writable(true) | ||
| .enumerable(false) | ||
| .configurable(true), | ||
| context, | ||
| ); |
core/runtime/src/fetch/headers.rs
Outdated
| fn next(&mut self, context: &mut Context) -> JsResult<JsValue> { | ||
| let headers_data = self.headers.headers.borrow(); | ||
| let headers_vec: Vec<_> = headers_data.iter().collect(); | ||
|
|
Test262 conformance changes
Tested main commit: |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #5044 +/- ##
===========================================
+ Coverage 47.24% 59.31% +12.06%
===========================================
Files 476 563 +87
Lines 46892 62612 +15720
===========================================
+ Hits 22154 37136 +14982
- Misses 24738 25476 +738 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Resolves #5042
Description:
This PR implements the missing static properties on the
Responsefetch object (Response.redirect()andResponse.json()).Response.redirect(url, status): Maps the arguments directly. Validates standard HTTP status bounds handling301,302,303,307, and308, defaulting dynamically to302. Adds the necessaryLocationassignment directly onto the payload mapping ofJsHeaders. Throws an engineRangeErrorif the status code isn't supported.Response.json(data, init): Evaluates JSON parsing intrinsically through JS usingstringify.call(...)directly interfacing theContextnamespace. Ensures that the static wrapper safely binds the payload type of"application/json"unless explicitly manipulated through HTTP arguments internally!Coverage: Evaluated
core/runtime/src/fetch/teststesting both.json(data, init)overriding states alongside validating JS.redirect()responses againstRangeErrorfailures safely.Signed-off-by: Rajdeep Singh youremail@example.com
Checklist:
-Passed cargo fmt --all and cargo clippy --all --all-features.
-Conforms to ECMAScript and WHATWG Fetch spec implementations.
-Passes native component testing via cargo test -p boa_runtime.