Repository: servo/servo
File: components/script/fetch.rs (Rust)

Code before:

    // Step 9. Let locallyAborted be false.
    // Step 10. Let controller be null.
    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),
        locally_aborted: false,
    }));

    // Step 11. Add the following abort steps to requestObject’s signal:
    signal.add(&AbortAlgorithm::Fetch(fetch_context.clone()));

    // Step 12. Set controller to the result of calling fetch given request and
    // processResponse given response being these steps:
    global.fetch(
        request_init,
        fetch_context,
        global.task_manager().networking_task_source().to_sendable(),
    );

    // Step 13. Return p.
    promise
}

#[derive(Clone, JSTraceable, MallocSizeOf)]
pub(crate) struct FetchContext {
    #[ignore_malloc_size_of = "unclear ownership semantics"]
    fetch_promise: Option<TrustedPromise>,
    response_object: Trusted<Response>,
    resource_timing: ResourceFetchTiming,
    locally_aborted: bool,
}

impl PreInvoke for FetchContext {}

impl FetchContext {
    /// Step 11 of <https://fetch.spec.whatwg.org/#dom-global-fetch>
    pub(crate) fn abort_fetch(&mut self, reason: HandleValue) {
        // Step 11.1. Set locallyAborted to true.
        self.locally_aborted = true;
        // Step 11.2. Assert: controller is non-null.
        //
        // N/a, that's self

        // Step 11.3. Abort controller with requestObject’s signal’s abort reason.
        // TODO

        // Step 11.4. Abort the fetch() call with p, request, responseObject,
        // and requestObject’s signal’s abort reason.
    }

Review comment (suggestion):
Basically none of these derives suit. Clone doesn't work for `fetch_promise`, JSTraceable doesn't work for `resource_timing`. MallocSizeOf doesn't work for `fetch_promise`, but we can suppress that.

Code after:
    let mut request_init = request_init_from_request(request);
    request_init.policy_container =
        RequestPolicyContainer::PolicyContainer(global.policy_container());

    // 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;
    }

    // Step 8. Let relevantRealm be this’s relevant realm.
    //
    // Is `comp` as argument

    // Step 9. Let locallyAborted be false.
    // Step 10. Let controller be null.
    let fetch_context = Arc::new(Mutex::new(FetchContext {
        fetch_promise: Some(TrustedPromise::new(promise.clone())),
        response_object: Trusted::new(&*response),
        request: Trusted::new(&*request_object),
        global: Trusted::new(global),
        resource_timing: ResourceFetchTiming::new(timing_type),
        locally_aborted: false,
        canceller: FetchCanceller::new(request_id, global.core_resource_thread()),
    }));

    // Step 11. Add the following abort steps to requestObject’s signal:
    signal.add(&AbortAlgorithm::Fetch(fetch_context.clone()));

    // Step 12. Set controller to the result of calling fetch given request and
    // processResponse given response being these steps:
    global.fetch(
        request_init,
        fetch_context,
        global.task_manager().networking_task_source().to_sendable(),
    );

    // Step 13. Return p.
    promise
}

#[derive(JSTraceable, MallocSizeOf)]
pub(crate) struct FetchContext {
    #[ignore_malloc_size_of = "unclear ownership semantics"]
    fetch_promise: Option<TrustedPromise>,
    response_object: Trusted<Response>,
    request: Trusted<Request>,
    global: Trusted<GlobalScope>,
    #[no_trace]
    resource_timing: ResourceFetchTiming,
    locally_aborted: bool,