mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
* Re-implement readablestream: basics and default reader and controller --------- Co-authored-by: Jason Tsai <jason@pews.dev> Signed-off-by: Wu Wayne <yuweiwu@pm.me> Add remaining WebIDLs of ReadableStream (#32605) * Add Reader's WebIDL files * Add necessary methods in ReadableStream.webidl Signed-off-by: Wu Wayne <yuweiwu@pm.me> Create safe wrapper for JSFunctions (#32620) * Create safe wrapper for JSFunctions Signed-off-by: Bentaimia Haddadi <haddadi.taym@gmail.com> * Add assert to check if the name ends in a null character Signed-off-by: Bentaimia Haddadi <haddadi.taym@gmail.com> * Create macro to wrap unsafe extern "C" function calls Signed-off-by: Bentaimia Haddadi <haddadi.taym@gmail.com> * Remove WRAPPER_FN Signed-off-by: Bentaimia Haddadi <haddadi.taym@gmail.com> * Add macro example documentation Signed-off-by: Bentaimia Haddadi <haddadi.taym@gmail.com> * Use C-string literals Signed-off-by: Bentaimia Haddadi <haddadi.taym@gmail.com> * Ensure name is Cstr type Signed-off-by: Bentaimia Haddadi <haddadi.taym@gmail.com> * Scope #[allow(unsafe_code)] Signed-off-by: Bentaimia Haddadi <haddadi.taym@gmail.com> --------- Signed-off-by: Bentaimia Haddadi <haddadi.taym@gmail.com> Signed-off-by: Wu Wayne <yuweiwu@pm.me> Start implementation of default controller and reader Start implementation of default controller and reader * implement basic internal slots, with todos Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com> * enum for controller Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com> * re-implement native controller methods Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com> * add calling into pull algo Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com> * more details on chunk enqueuing Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com> * add fulfill read request, clean-up warnings Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com> * read request and reader typing Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com> * allow for more than one non-native underlying source type Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com> * add todo for should pull Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com> * add underlying source dom struct container Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com> * remove rc around source type * add default controller init in stream constructor * setup source container with prototype of source dict * clean-up docs, dispatch of controller in pull algo call * turn off SM streams * remove prototype setting on underlying source container * fix read request promise resolving * tidy * clean-up js conversions in read req handlers * add queue with sizes concept * use dom in pull promise handlers * Demonstrate using dictionary as callback this object. * move value with size to a struct * fmt * put readable stream state in a cell * nits in expectations * remove allow unroot by passing read result directly to promise resolving * tidy * root default controller inside call_pull_if_needed --------- Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com> Co-authored-by: Josh Matthews <josh@joshmatthews.net> Signed-off-by: Wu Wayne <yuweiwu@pm.me> ReadableStream: implement Cancel and Locked (#33136) * implement Locked * implement Cancel and close Signed-off-by: Wu Wayne <yuweiwu@pm.me> Add GetPromiseIsHandled and SetAnyPromiseIsHandled to Promise Signed-off-by: Taym <haddadi.taym@gmail.com> mach fmt Signed-off-by: Taym <haddadi.taym@gmail.com> Readablestream default controller: get desired size (#33497) Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com> stream: implement controller close (#33498) Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com> implement stream default controller error (#33503) Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com> Readablestream default controller: enqueue (#33528) * Implement ReadableStreamDefaultControllerMethods::Enqueue Signed-off-by: Wu Wayne <yuweiwu@pm.me> * Add spec comments Signed-off-by: Wu Wayne <yuweiwu@pm.me> --------- Signed-off-by: Wu Wayne <yuweiwu@pm.me> readablestream default controller: fulfill read requests (#33542) Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com> Fix extract_size_algorithm (#33561) Signed-off-by: Wu Wayne <yuweiwu@pm.me> Readablestream default controller: use strategy size (#33551) * readablestream default controller: use strategy size, fallible enqueue Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com> docs * readablestream default controller: clear strategy size Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com> * prevent potential re-borrow panics when calling into the strategy size Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com> * document readablestream constructor Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com> --------- Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com> Readablestream: impl default controller should pull, start algo (#33586) * implement should-pull algo for default controller Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com> * add start algorithm setup for default controller Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com> --------- Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com> implement promise native handling for start and pull algorithms (#33603) Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com> Implement ReadableStreamDefaultReader (#33160) * Implement ReadableStreamDefaultReader Make the stream mutable readable-stream-reader-generic-release Proper error types when releasing Closed Cancel Signed-off-by: Taym <haddadi.taym@gmail.com> * follow the spec more closely Signed-off-by: Taym <haddadi.taym@gmail.com> --------- Signed-off-by: Taym <haddadi.taym@gmail.com> Implement ReadableStreamDefaultReader read (#34007) * Implement ReadableStreamDefaultReader read Signed-off-by: Taym <haddadi.taym@gmail.com> * Perform readRequest’s error steps with stream.stored_error Signed-off-by: Taym <haddadi.taym@gmail.com> --------- Signed-off-by: Taym <haddadi.taym@gmail.com> Improve ReadableStreamDefaultReader close (#34014) * improve ReadableStreamDefaultReader close Signed-off-by: Taym <haddadi.taym@gmail.com> * remove resolve_closed_promise Signed-off-by: Taym <haddadi.taym@gmail.com> --------- Signed-off-by: Taym <haddadi.taym@gmail.com> Use Rc<Box<[u8]>> for queue to optimize get_in_memory_bytes Signed-off-by: Taym <haddadi.taym@gmail.com> Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com> Signed-off-by: Taym <haddadi.taym@gmail.com> * Improve read_a_chunk and stop_reading implemntation (#34077) Signed-off-by: Taym <haddadi.taym@gmail.com> Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com> Signed-off-by: Taym <haddadi.taym@gmail.com> Signed-off-by: Taym Haddadi <haddadi.taym@gmail.com> * Implement ReadableStreamDefaultReader::Constructor (#34056) * Implement ReadableStreamDefaultReader::Constructor Signed-off-by: Taym <haddadi.taym@gmail.com> * make start_reading returns ReadableStreamDefaultReader Signed-off-by: Taym <haddadi.taym@gmail.com> * Fix can_gc Signed-off-by: Taym <haddadi.taym@gmail.com> * Add canGc to ReadableStream::GetReader Signed-off-by: Taym <haddadi.taym@gmail.com> --------- Signed-off-by: Taym <haddadi.taym@gmail.com> Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com> Signed-off-by: Taym <haddadi.taym@gmail.com> Signed-off-by: Taym Haddadi <haddadi.taym@gmail.com> * Readablestream fix CanGc (#34080) Signed-off-by: Taym <haddadi.taym@gmail.com> Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com> Signed-off-by: Taym <haddadi.taym@gmail.com> Signed-off-by: Taym Haddadi <haddadi.taym@gmail.com> * correct ReadableStream::error_native implementation and fix clippy warnings (#34088) Signed-off-by: Taym <haddadi.taym@gmail.com> Signed-off-by: Taym Haddadi <haddadi.taym@gmail.com> * turn assertion of stream present on controller on a early return with false (#34097) Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com> Signed-off-by: Taym <haddadi.taym@gmail.com> Signed-off-by: Taym Haddadi <haddadi.taym@gmail.com> * Fix already mutably borrowed crash (#34105) Signed-off-by: Taym <haddadi.taym@gmail.com> Signed-off-by: Taym Haddadi <haddadi.taym@gmail.com> * Refactor `get_in_memory_bytes` to return `Option<Vec<u8>> and avoid `unreachable!` panic (#34123) Signed-off-by: Taym <haddadi.taym@gmail.com> Signed-off-by: Taym Haddadi <haddadi.taym@gmail.com> * Set ReadableStream ReadableStreamDefaultReader in start_reading (#34125) Signed-off-by: Taym <haddadi.taym@gmail.com> Signed-off-by: Taym Haddadi <haddadi.taym@gmail.com> * Fix Unhandled rejection with value: object `TypeError: stream is not locked` (#34204) Signed-off-by: Taym <haddadi.taym@gmail.com> Signed-off-by: Taym Haddadi <haddadi.taym@gmail.com> * Fix assert!(self.is_readable()) crash in ReadableStream::close (#34207) Signed-off-by: Taym <haddadi.taym@gmail.com> Signed-off-by: Taym Haddadi <haddadi.taym@gmail.com> * fix call to to_js_object in underlying source algos (#34098) Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com> Signed-off-by: Taym <haddadi.taym@gmail.com> Signed-off-by: Taym Haddadi <haddadi.taym@gmail.com> * do not assume presence of a stream when performing pull steps (#34244) * do not assume presence of a stream when performing pull steps Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com> * add doc comments Co-authored-by: Taym Haddadi <haddadi.taym@gmail.com> Signed-off-by: Gregory Terzian <2792687+gterzian@users.noreply.github.com> --------- Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com> Signed-off-by: Gregory Terzian <2792687+gterzian@users.noreply.github.com> Co-authored-by: Taym Haddadi <haddadi.taym@gmail.com> Signed-off-by: Taym <haddadi.taym@gmail.com> Signed-off-by: Taym Haddadi <haddadi.taym@gmail.com> * gracefully handle failure of underlying source algorithms (#34243) Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com> Signed-off-by: Taym <haddadi.taym@gmail.com> Signed-off-by: Taym Haddadi <haddadi.taym@gmail.com> * ensure result of calling start algo is an object (#34245) Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com> Signed-off-by: Taym <haddadi.taym@gmail.com> Signed-off-by: Taym Haddadi <haddadi.taym@gmail.com> * return js failed error if underlying source constructor threw (#34246) Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com> Signed-off-by: Taym <haddadi.taym@gmail.com> Signed-off-by: Taym Haddadi <haddadi.taym@gmail.com> * Use JSVal for ValueWithSize::value (#34259) Signed-off-by: Taym <haddadi.taym@gmail.com> Signed-off-by: Taym Haddadi <haddadi.taym@gmail.com> * fix release reader lock, (#34255) fix setting stream on controller in new, fix matching fallthrough, reduce visibility of controller error method Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com> Signed-off-by: Taym <haddadi.taym@gmail.com> Signed-off-by: Taym Haddadi <haddadi.taym@gmail.com> * in stream cancel, reject promist if locked (#34271) Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com> Signed-off-by: Taym <haddadi.taym@gmail.com> Signed-off-by: Taym Haddadi <haddadi.taym@gmail.com> * Fix UnderlyingSourceContainer::call_start_algorithm (#34277) Signed-off-by: Taym <haddadi.taym@gmail.com> Signed-off-by: Taym Haddadi <haddadi.taym@gmail.com> * implement controller cancel steps, fix stream cancel method (#34301) Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com> Signed-off-by: Taym <haddadi.taym@gmail.com> Signed-off-by: Taym Haddadi <haddadi.taym@gmail.com> * fix conditional in perform pull steps (#34324) Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com> Signed-off-by: Taym <haddadi.taym@gmail.com> Signed-off-by: Taym Haddadi <haddadi.taym@gmail.com> * set reader closed promise to one resolved with undefined if stream closed on init (#34321) Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com> Signed-off-by: Taym <haddadi.taym@gmail.com> Signed-off-by: Taym Haddadi <haddadi.taym@gmail.com> * fix init of stream and controller (#34323) Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com> Signed-off-by: Taym <haddadi.taym@gmail.com> Signed-off-by: Taym Haddadi <haddadi.taym@gmail.com> * Stream: Fix reborrow in controller enqueue, and fix error and exception handling. (#34338) * fix re-borrow in controller enqueue Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com> * do not call to_jsval on JSFailed error in enqueue Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com> * fix error and exception handling in controller enqueue Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com> * remove TODO about correctness of stored error, since this was done as part of the switch to a js val. Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com> --------- Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com> Signed-off-by: Taym <haddadi.taym@gmail.com> Signed-off-by: Taym Haddadi <haddadi.taym@gmail.com> * Stream: Fix incorrect "this" object in underlying source callbacks (#34368) * in controller close, throw type error if stream cannot be closed Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com> * store original js object for underlying source, for use as this object in callbacks Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com> --------- Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com> Signed-off-by: Taym <haddadi.taym@gmail.com> Signed-off-by: Taym Haddadi <haddadi.taym@gmail.com> * fix conditional logic in enqueue to ensure pull is called into (#34375) Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com> Signed-off-by: Taym <haddadi.taym@gmail.com> Signed-off-by: Taym Haddadi <haddadi.taym@gmail.com> * Stream: Fix bytelength queueing strategy (#34376) * fix handling of value that is not an object in bytelength queuing strategy Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com> * return type error if strategy size call fails, to prevent panic because no exception is pending Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com> --------- Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com> Signed-off-by: Taym <haddadi.taym@gmail.com> Signed-off-by: Taym Haddadi <haddadi.taym@gmail.com> * set correct default count queuing size strategy (#34389) Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com> Signed-off-by: Taym <haddadi.taym@gmail.com> Signed-off-by: Taym Haddadi <haddadi.taym@gmail.com> * use proto in stream constructor (#34441) Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com> Signed-off-by: Taym <haddadi.taym@gmail.com> Signed-off-by: Taym Haddadi <haddadi.taym@gmail.com> * fix edge cases in get_desired_size (#34440) Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com> Signed-off-by: Taym <haddadi.taym@gmail.com> Signed-off-by: Taym Haddadi <haddadi.taym@gmail.com> * Stream: fix algo and strategy calls error handling. (#34424) * fix error handling in cancel steps Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com> * in pull steps, reject promise if pull algo throws Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com> * if start algorithm fails, rethrow the error Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com> * when the strategy size fails, directly get the pending exception and use it to error the stream Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com> * add error handling to enqueue value with size Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com> * when enqueueing a value errors, ensure we error and stream with the same error used to throw an exception Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com> --------- Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com> Signed-off-by: Taym <haddadi.taym@gmail.com> Signed-off-by: Taym Haddadi <haddadi.taym@gmail.com> * fix native use of streams (#34468) Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com> Signed-off-by: Taym <haddadi.taym@gmail.com> Signed-off-by: Taym Haddadi <haddadi.taym@gmail.com> * Implement readablestreamdefaulttee (#34405) * Implement readablestreamdefaulttee Signed-off-by: Taym <haddadi.taym@gmail.com> * Create UnderlyingSourceType::Tee each stream Signed-off-by: Taym <haddadi.taym@gmail.com> * Use Dom instead of DomRoot Signed-off-by: Taym <haddadi.taym@gmail.com> * Queue a microtask for readRequest chunk steps Signed-off-by: Taym <haddadi.taym@gmail.com> * fix create_readable_stream Signed-off-by: Taym <haddadi.taym@gmail.com> * Remove unnecessary Rc Signed-off-by: Taym <haddadi.taym@gmail.com> * Use correct doc link Signed-off-by: Taym <haddadi.taym@gmail.com> * Add #[allow(crown::unrooted_must_root)] Signed-off-by: Taym <haddadi.taym@gmail.com> * Fix crash in ClosedPromiseRejectionHandler Signed-off-by: Taym <haddadi.taym@gmail.com> * reflect TeeReadRequest and TeeUnderlyingSource Signed-off-by: Taym <haddadi.taym@gmail.com> * fix can_gc Signed-off-by: Taym <haddadi.taym@gmail.com> * reflect tee source, and fix use of mutable dom for tee source and request Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com> * Fix typo that resolves multiple test failures in 'Tee' tests Signed-off-by: Taym <haddadi.taym@gmail.com> * Fix readable-streams/tee.any.js test Signed-off-by: Taym <haddadi.taym@gmail.com> --------- Signed-off-by: Taym <haddadi.taym@gmail.com> Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com> Co-authored-by: gterzian <2792687+gterzian@users.noreply.github.com> Signed-off-by: Taym <haddadi.taym@gmail.com> Signed-off-by: Taym Haddadi <haddadi.taym@gmail.com> * Align ReadableStreamDefaultReader with spec and fix additional tests in default-reader.any.js (#34531) And fix crate::DomTypeHolder usage * Align ReadableStreamDefaultReader with spec and fix additional tests in default-reader.any.js Signed-off-by: Taym <haddadi.taym@gmail.com> * make reader rooted in Constructor and acquire_default_reader Signed-off-by: Taym <haddadi.taym@gmail.com> * Remove spaces Signed-off-by: Taym <haddadi.taym@gmail.com> --------- Signed-off-by: Taym <haddadi.taym@gmail.com> Signed-off-by: Taym Haddadi <haddadi.taym@gmail.com> * Streams: fetch stream chunks should be uint8 arrays (#34553) * fetch stream chunks should be uint8 arrays Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com> * fix clippy Signed-off-by: Taym Haddadi <haddadi.taym@gmail.com> --------- Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com> Signed-off-by: Taym Haddadi <haddadi.taym@gmail.com> Co-authored-by: Taym Haddadi <haddadi.taym@gmail.com> Signed-off-by: Taym <haddadi.taym@gmail.com> Signed-off-by: Taym Haddadi <haddadi.taym@gmail.com> * Update wpt test for ReadableStream reimplementation (#34579) Signed-off-by: Taym <haddadi.taym@gmail.com> Signed-off-by: Taym Haddadi <haddadi.taym@gmail.com> * Fix ignore_malloc_size_of in readablestream tee (#34578) Signed-off-by: Taym <haddadi.taym@gmail.com> Signed-off-by: Taym Haddadi <haddadi.taym@gmail.com> * Remove incorrect use of handle array, fail test safely by giving only one reason (#34560) Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com> Signed-off-by: Taym <haddadi.taym@gmail.com> Signed-off-by: Taym Haddadi <haddadi.taym@gmail.com> * Update more wpt test for ReadableStream reimplementation (#34598) Signed-off-by: Taym <haddadi.taym@gmail.com> Signed-off-by: Taym Haddadi <haddadi.taym@gmail.com> * Fix doc and rename Tee to DefaultTee (#34612) Signed-off-by: Taym <haddadi.taym@gmail.com> Signed-off-by: Taym Haddadi <haddadi.taym@gmail.com> * fix: Address review comments Signed-off-by: Taym <haddadi.taym@gmail.com> Signed-off-by: Taym Haddadi <haddadi.taym@gmail.com> * Update response-stream-with-broken-then.any.js.ini test expectation Signed-off-by: Taym Haddadi <haddadi.taym@gmail.com> * fix reflect_dom_object can_gc Signed-off-by: Taym Haddadi <haddadi.taym@gmail.com> * Fix compositeReason for DefaultTeeUnderlyingSource (#34627) * Fix compositeReason for DefaultTeeUnderlyingSource Signed-off-by: Taym Haddadi <haddadi.taym@gmail.com> * Update test Signed-off-by: Taym Haddadi <haddadi.taym@gmail.com> --------- Signed-off-by: Taym Haddadi <haddadi.taym@gmail.com> * Last fixes stream (#34636) * remove now unsused from_js method of readable stream * fix documenation of error steps * return type error instread of panicking on a todo, when trying to construct a stream of type bytes Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com> --------- Signed-off-by: Gregory Terzian <2792687+gterzian@users.noreply.github.com> * fix crown rooting related errors (#34662) Signed-off-by: Gregory Terzian <2792687+gterzian@users.noreply.github.com> --------- Signed-off-by: Taym <haddadi.taym@gmail.com> Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com> Signed-off-by: Taym Haddadi <haddadi.taym@gmail.com> Signed-off-by: Gregory Terzian <2792687+gterzian@users.noreply.github.com> Co-authored-by: Wu Wayne <yuweiwu@pm.me> Co-authored-by: Taym Haddadi <haddadi.taym@gmail.com>
401 lines
14 KiB
Rust
401 lines
14 KiB
Rust
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||
|
||
use std::rc::Rc;
|
||
use std::sync::{Arc, Mutex};
|
||
|
||
use ipc_channel::ipc;
|
||
use net_traits::policy_container::RequestPolicyContainer;
|
||
use net_traits::request::{
|
||
CorsSettings, CredentialsMode, Destination, Referrer, Request as NetTraitsRequest,
|
||
RequestBuilder, RequestId, RequestMode, ServiceWorkersMode,
|
||
};
|
||
use net_traits::{
|
||
CoreResourceMsg, CoreResourceThread, FetchChannels, FetchMetadata, FetchResponseListener,
|
||
FetchResponseMsg, FilteredMetadata, Metadata, NetworkError, ResourceFetchTiming,
|
||
ResourceTimingType,
|
||
};
|
||
use servo_url::ServoUrl;
|
||
|
||
use crate::dom::bindings::codegen::Bindings::RequestBinding::{
|
||
RequestInfo, RequestInit, RequestMethods,
|
||
};
|
||
use crate::dom::bindings::codegen::Bindings::ResponseBinding::ResponseType as DOMResponseType;
|
||
use crate::dom::bindings::codegen::Bindings::ResponseBinding::Response_Binding::ResponseMethods;
|
||
use crate::dom::bindings::error::Error;
|
||
use crate::dom::bindings::inheritance::Castable;
|
||
use crate::dom::bindings::refcounted::{Trusted, TrustedPromise};
|
||
use crate::dom::bindings::reflector::DomObject;
|
||
use crate::dom::bindings::root::DomRoot;
|
||
use crate::dom::bindings::trace::RootedTraceableBox;
|
||
use crate::dom::globalscope::GlobalScope;
|
||
use crate::dom::headers::Guard;
|
||
use crate::dom::performanceresourcetiming::InitiatorType;
|
||
use crate::dom::promise::Promise;
|
||
use crate::dom::request::Request;
|
||
use crate::dom::response::Response;
|
||
use crate::dom::serviceworkerglobalscope::ServiceWorkerGlobalScope;
|
||
use crate::network_listener::{self, submit_timing_data, PreInvoke, ResourceTimingListener};
|
||
use crate::realms::{enter_realm, InRealm};
|
||
use crate::script_runtime::CanGc;
|
||
|
||
struct FetchContext {
|
||
fetch_promise: Option<TrustedPromise>,
|
||
response_object: Trusted<Response>,
|
||
resource_timing: ResourceFetchTiming,
|
||
}
|
||
|
||
/// RAII fetch canceller object. By default initialized to not having a canceller
|
||
/// in it, however you can ask it for a cancellation receiver to send to Fetch
|
||
/// in which case it will store the sender. You can manually cancel it
|
||
/// or let it cancel on Drop in that case.
|
||
#[derive(Default, JSTraceable, MallocSizeOf)]
|
||
pub struct FetchCanceller {
|
||
#[ignore_malloc_size_of = "channels are hard"]
|
||
#[no_trace]
|
||
cancel_chan: Option<ipc::IpcSender<()>>,
|
||
}
|
||
|
||
impl FetchCanceller {
|
||
/// Create an empty FetchCanceller
|
||
pub fn new() -> Self {
|
||
Default::default()
|
||
}
|
||
|
||
/// Obtain an IpcReceiver to send over to Fetch, and initialize
|
||
/// the internal sender
|
||
pub fn initialize(&mut self) -> ipc::IpcReceiver<()> {
|
||
// cancel previous fetch
|
||
self.cancel();
|
||
let (rx, tx) = ipc::channel().unwrap();
|
||
self.cancel_chan = Some(rx);
|
||
tx
|
||
}
|
||
|
||
/// Cancel a fetch if it is ongoing
|
||
pub fn cancel(&mut self) {
|
||
if let Some(chan) = self.cancel_chan.take() {
|
||
// stop trying to make fetch happen
|
||
// it's not going to happen
|
||
|
||
// The receiver will be destroyed if the request has already completed;
|
||
// so we throw away the error. Cancellation is a courtesy call,
|
||
// we don't actually care if the other side heard.
|
||
let _ = chan.send(());
|
||
}
|
||
}
|
||
|
||
/// Use this if you don't want it to send a cancellation request
|
||
/// on drop (e.g. if the fetch completes)
|
||
pub fn ignore(&mut self) {
|
||
let _ = self.cancel_chan.take();
|
||
}
|
||
}
|
||
|
||
impl Drop for FetchCanceller {
|
||
fn drop(&mut self) {
|
||
self.cancel()
|
||
}
|
||
}
|
||
|
||
fn request_init_from_request(request: NetTraitsRequest) -> RequestBuilder {
|
||
RequestBuilder {
|
||
id: request.id,
|
||
method: request.method.clone(),
|
||
url: request.url(),
|
||
headers: request.headers.clone(),
|
||
unsafe_request: request.unsafe_request,
|
||
body: request.body.clone(),
|
||
service_workers_mode: ServiceWorkersMode::All,
|
||
destination: request.destination,
|
||
synchronous: request.synchronous,
|
||
mode: request.mode.clone(),
|
||
cache_mode: request.cache_mode,
|
||
use_cors_preflight: request.use_cors_preflight,
|
||
credentials_mode: request.credentials_mode,
|
||
use_url_credentials: request.use_url_credentials,
|
||
origin: GlobalScope::current()
|
||
.expect("No current global object")
|
||
.origin()
|
||
.immutable()
|
||
.clone(),
|
||
referrer: request.referrer.clone(),
|
||
referrer_policy: request.referrer_policy,
|
||
pipeline_id: request.pipeline_id,
|
||
redirect_mode: request.redirect_mode,
|
||
integrity_metadata: request.integrity_metadata.clone(),
|
||
url_list: vec![],
|
||
parser_metadata: request.parser_metadata,
|
||
initiator: request.initiator,
|
||
policy_container: request.policy_container,
|
||
https_state: request.https_state,
|
||
response_tainting: request.response_tainting,
|
||
crash: None,
|
||
}
|
||
}
|
||
|
||
/// <https://fetch.spec.whatwg.org/#fetch-method>
|
||
#[allow(crown::unrooted_must_root, non_snake_case)]
|
||
pub fn Fetch(
|
||
global: &GlobalScope,
|
||
input: RequestInfo,
|
||
init: RootedTraceableBox<RequestInit>,
|
||
comp: InRealm,
|
||
can_gc: CanGc,
|
||
) -> Rc<Promise> {
|
||
// Step 1. Let p be a new promise.
|
||
let promise = Promise::new_in_current_realm(comp, can_gc);
|
||
|
||
// Step 7. Let responseObject be null.
|
||
// NOTE: We do initialize the object earlier earlier so we can use it to track errors
|
||
let response = Response::new(global, can_gc);
|
||
response.Headers(can_gc).set_guard(Guard::Immutable);
|
||
|
||
// Step 2. Let requestObject be the result of invoking the initial value of Request as constructor
|
||
// with input and init as arguments. If this throws an exception, reject p with it and return p.
|
||
let request = match Request::Constructor(global, None, can_gc, input, init) {
|
||
Err(e) => {
|
||
response.error_stream(e.clone());
|
||
promise.reject_error(e);
|
||
return promise;
|
||
},
|
||
Ok(r) => {
|
||
// Step 3. Let request be requestObject’s request.
|
||
r.get_request()
|
||
},
|
||
};
|
||
let timing_type = request.timing_type();
|
||
|
||
let mut request_init = request_init_from_request(request);
|
||
request_init.policy_container =
|
||
RequestPolicyContainer::PolicyContainer(global.policy_container());
|
||
|
||
// TODO: Step 4. If requestObject’s signal is aborted, then: [..]
|
||
|
||
// Step 5. Let globalObject be request’s client’s global object.
|
||
// NOTE: We already get the global object as an argument
|
||
|
||
// Step 6. If globalObject is a ServiceWorkerGlobalScope object, then set request’s
|
||
// service-workers mode to "none".
|
||
if global.is::<ServiceWorkerGlobalScope>() {
|
||
request_init.service_workers_mode = ServiceWorkersMode::None;
|
||
}
|
||
|
||
// TODO: Steps 8-11, abortcontroller stuff
|
||
|
||
// Step 12. Set controller to the result of calling fetch given request and
|
||
// processResponse given response being these steps: [..]
|
||
let fetch_context = Arc::new(Mutex::new(FetchContext {
|
||
fetch_promise: Some(TrustedPromise::new(promise.clone())),
|
||
response_object: Trusted::new(&*response),
|
||
resource_timing: ResourceFetchTiming::new(timing_type),
|
||
}));
|
||
|
||
global.fetch(
|
||
request_init,
|
||
fetch_context,
|
||
global.networking_task_source(),
|
||
None,
|
||
);
|
||
|
||
// Step 13. Return p.
|
||
promise
|
||
}
|
||
|
||
impl PreInvoke for FetchContext {}
|
||
|
||
impl FetchResponseListener for FetchContext {
|
||
fn process_request_body(&mut self, _: RequestId) {
|
||
// TODO
|
||
}
|
||
|
||
fn process_request_eof(&mut self, _: RequestId) {
|
||
// TODO
|
||
}
|
||
|
||
#[allow(crown::unrooted_must_root)]
|
||
fn process_response(
|
||
&mut self,
|
||
_: RequestId,
|
||
fetch_metadata: Result<FetchMetadata, NetworkError>,
|
||
) {
|
||
let promise = self
|
||
.fetch_promise
|
||
.take()
|
||
.expect("fetch promise is missing")
|
||
.root();
|
||
|
||
let _ac = enter_realm(&*promise);
|
||
match fetch_metadata {
|
||
// Step 4.1
|
||
Err(_) => {
|
||
promise.reject_error(Error::Type("Network error occurred".to_string()));
|
||
self.fetch_promise = Some(TrustedPromise::new(promise));
|
||
let response = self.response_object.root();
|
||
response.set_type(DOMResponseType::Error, CanGc::note());
|
||
response.error_stream(Error::Type("Network error occurred".to_string()));
|
||
return;
|
||
},
|
||
// Step 4.2
|
||
Ok(metadata) => match metadata {
|
||
FetchMetadata::Unfiltered(m) => {
|
||
fill_headers_with_metadata(self.response_object.root(), m, CanGc::note());
|
||
self.response_object
|
||
.root()
|
||
.set_type(DOMResponseType::Default, CanGc::note());
|
||
},
|
||
FetchMetadata::Filtered { filtered, .. } => match filtered {
|
||
FilteredMetadata::Basic(m) => {
|
||
fill_headers_with_metadata(self.response_object.root(), m, CanGc::note());
|
||
self.response_object
|
||
.root()
|
||
.set_type(DOMResponseType::Basic, CanGc::note());
|
||
},
|
||
FilteredMetadata::Cors(m) => {
|
||
fill_headers_with_metadata(self.response_object.root(), m, CanGc::note());
|
||
self.response_object
|
||
.root()
|
||
.set_type(DOMResponseType::Cors, CanGc::note());
|
||
},
|
||
FilteredMetadata::Opaque => {
|
||
self.response_object
|
||
.root()
|
||
.set_type(DOMResponseType::Opaque, CanGc::note());
|
||
},
|
||
FilteredMetadata::OpaqueRedirect(url) => {
|
||
let r = self.response_object.root();
|
||
r.set_type(DOMResponseType::Opaqueredirect, CanGc::note());
|
||
r.set_final_url(url);
|
||
},
|
||
},
|
||
},
|
||
}
|
||
|
||
// Step 4.3
|
||
promise.resolve_native(&self.response_object.root());
|
||
self.fetch_promise = Some(TrustedPromise::new(promise));
|
||
}
|
||
|
||
fn process_response_chunk(&mut self, _: RequestId, chunk: Vec<u8>) {
|
||
let response = self.response_object.root();
|
||
response.stream_chunk(chunk);
|
||
}
|
||
|
||
fn process_response_eof(
|
||
&mut self,
|
||
_: RequestId,
|
||
_response: Result<ResourceFetchTiming, NetworkError>,
|
||
) {
|
||
let response = self.response_object.root();
|
||
let _ac = enter_realm(&*response);
|
||
response.finish();
|
||
// TODO
|
||
// ... trailerObject is not supported in Servo yet.
|
||
}
|
||
|
||
fn resource_timing_mut(&mut self) -> &mut ResourceFetchTiming {
|
||
&mut self.resource_timing
|
||
}
|
||
|
||
fn resource_timing(&self) -> &ResourceFetchTiming {
|
||
&self.resource_timing
|
||
}
|
||
|
||
fn submit_resource_timing(&mut self) {
|
||
// navigation submission is handled in servoparser/mod.rs
|
||
if self.resource_timing.timing_type == ResourceTimingType::Resource {
|
||
network_listener::submit_timing(self, CanGc::note())
|
||
}
|
||
}
|
||
}
|
||
|
||
impl ResourceTimingListener for FetchContext {
|
||
fn resource_timing_information(&self) -> (InitiatorType, ServoUrl) {
|
||
(
|
||
InitiatorType::Fetch,
|
||
self.resource_timing_global().get_url().clone(),
|
||
)
|
||
}
|
||
|
||
fn resource_timing_global(&self) -> DomRoot<GlobalScope> {
|
||
self.response_object.root().global()
|
||
}
|
||
}
|
||
|
||
fn fill_headers_with_metadata(r: DomRoot<Response>, m: Metadata, can_gc: CanGc) {
|
||
r.set_headers(m.headers, can_gc);
|
||
r.set_status(&m.status);
|
||
r.set_final_url(m.final_url);
|
||
r.set_redirected(m.redirected);
|
||
}
|
||
|
||
/// Convenience function for synchronously loading a whole resource.
|
||
pub fn load_whole_resource(
|
||
request: RequestBuilder,
|
||
core_resource_thread: &CoreResourceThread,
|
||
global: &GlobalScope,
|
||
can_gc: CanGc,
|
||
) -> Result<(Metadata, Vec<u8>), NetworkError> {
|
||
let request = request.https_state(global.get_https_state());
|
||
let (action_sender, action_receiver) = ipc::channel().unwrap();
|
||
let url = request.url.clone();
|
||
core_resource_thread
|
||
.send(CoreResourceMsg::Fetch(
|
||
request,
|
||
FetchChannels::ResponseMsg(action_sender, None),
|
||
))
|
||
.unwrap();
|
||
|
||
let mut buf = vec![];
|
||
let mut metadata = None;
|
||
loop {
|
||
match action_receiver.recv().unwrap() {
|
||
FetchResponseMsg::ProcessRequestBody(..) | FetchResponseMsg::ProcessRequestEOF(..) => {
|
||
},
|
||
FetchResponseMsg::ProcessResponse(_, Ok(m)) => {
|
||
metadata = Some(match m {
|
||
FetchMetadata::Unfiltered(m) => m,
|
||
FetchMetadata::Filtered { unsafe_, .. } => unsafe_,
|
||
})
|
||
},
|
||
FetchResponseMsg::ProcessResponseChunk(_, data) => buf.extend_from_slice(&data),
|
||
FetchResponseMsg::ProcessResponseEOF(_, Ok(_)) => {
|
||
let metadata = metadata.unwrap();
|
||
if let Some(timing) = &metadata.timing {
|
||
submit_timing_data(global, url, InitiatorType::Other, timing, can_gc);
|
||
}
|
||
return Ok((metadata, buf));
|
||
},
|
||
FetchResponseMsg::ProcessResponse(_, Err(e)) |
|
||
FetchResponseMsg::ProcessResponseEOF(_, Err(e)) => return Err(e),
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <https://html.spec.whatwg.org/multipage/#create-a-potential-cors-request>
|
||
pub(crate) fn create_a_potential_cors_request(
|
||
url: ServoUrl,
|
||
destination: Destination,
|
||
cors_setting: Option<CorsSettings>,
|
||
same_origin_fallback: Option<bool>,
|
||
referrer: Referrer,
|
||
) -> RequestBuilder {
|
||
RequestBuilder::new(url, referrer)
|
||
// https://html.spec.whatwg.org/multipage/#create-a-potential-cors-request
|
||
// Step 1
|
||
.mode(match cors_setting {
|
||
Some(_) => RequestMode::CorsMode,
|
||
None if same_origin_fallback == Some(true) => RequestMode::SameOrigin,
|
||
None => RequestMode::NoCors,
|
||
})
|
||
// https://html.spec.whatwg.org/multipage/#create-a-potential-cors-request
|
||
// Step 3-4
|
||
.credentials_mode(match cors_setting {
|
||
Some(CorsSettings::Anonymous) => CredentialsMode::CredentialsSameOrigin,
|
||
_ => CredentialsMode::Include,
|
||
})
|
||
// Step 5
|
||
.destination(destination)
|
||
.use_url_credentials(true)
|
||
}
|