/
githubmirror
/
deno
Обзор
Документация
Войти
/
githubmirror
/
deno
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
runtime/ops/web_worker/sync_fetch.rs
231 строка
7 KB
em
fix(runtime): capture blob worker roots before revocation (#35128)
24 июн 2026, 09:10
Не верифицирован
24 июн 2026, 09:10
118b787
Код
Авторство
О чём код?
// Copyright 2018-2026 the Deno authors. MIT license. use std::sync::Arc; use boxed_error::Boxed; use deno_core::OpState; use deno_core::ToV8; use deno_core::futures::StreamExt; use deno_core::op2; use deno_core::url::Url; use deno_fetch::FetchError; use deno_fetch::data_url::DataUrl; use deno_web::BlobStoreTrait; use http_body_util::BodyExt; use hyper::body::Bytes; use crate::web_worker::WebWorkerInternalHandle; use crate::web_worker::WorkerThreadType; // TODO(andreubotella) Properly parse the MIME type fn mime_type_essence(mime_type: &str) -> String { let essence = match mime_type.split_once(';') { Some((essence, _)) => essence, None => mime_type, }; essence.trim().to_ascii_lowercase() } #[derive(Debug, Boxed, deno_error::JsError)] pub struct SyncFetchError(pub Box<SyncFetchErrorKind>); #[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum SyncFetchErrorKind { #[class(type)] #[error("Blob URLs are not supported in this context.")] BlobUrlsNotSupportedInContext, #[class(inherit)] #[error("{0}")] Io( #[from] #[inherit] std::io::Error, ), #[class(type)] #[error("Invalid script URL")] InvalidScriptUrl, #[class(type)] #[error("http status error: {0}")] InvalidStatusCode(http::StatusCode), #[class(type)] #[error("Classic scripts with scheme {0}: are not supported in workers")] ClassicScriptSchemeUnsupportedInWorkers(String), #[class(generic)] #[error("{0}")] InvalidUri(#[from] http::uri::InvalidUri), #[class("DOMExceptionNetworkError")] #[error("Invalid MIME type {0:?}.")] InvalidMimeType(String), #[class("DOMExceptionNetworkError")] #[error("Missing MIME type.")] MissingMimeType, #[class(inherit)] #[error(transparent)] Fetch( #[from] #[inherit] FetchError, ), #[class(inherit)] #[error(transparent)] Join( #[from] #[inherit] tokio::task::JoinError, ), #[class(inherit)] #[error(transparent)] Other(#[inherit] deno_error::JsErrorBox), } #[derive(ToV8)] pub struct SyncFetchScript { url: String, script: String, } #[op2] pub fn op_worker_sync_fetch( state: &mut OpState, #[scoped] scripts: Vec<String>, loose_mime_checks: bool, ) -> Result<Vec<SyncFetchScript>, SyncFetchError> { let handle = state.borrow::<WebWorkerInternalHandle>().clone(); assert_eq!(handle.worker_type, WorkerThreadType::Classic); let client = deno_fetch::get_or_create_client_from_state(state) .map_err(FetchError::ClientCreate)?; // TODO(andreubotella) It's not good to throw an exception related to blob // URLs when none of the script URLs use the blob scheme. // Also, in which contexts are blob URLs not supported? let blob_store = state .try_borrow::<Arc<dyn BlobStoreTrait>>() .ok_or(SyncFetchErrorKind::BlobUrlsNotSupportedInContext)? .clone(); // TODO(andreubotella): make the below thread into a resource that can be // re-used. This would allow parallel fetching of multiple scripts. let thread = std::thread::spawn(move || { let runtime = tokio::runtime::Builder::new_current_thread() .enable_io() .enable_time() .build()?; runtime.block_on(async move { let mut futures = scripts .into_iter() .map(|script| { let client = client.clone(); let blob_store = blob_store.clone(); let maybe_main_module_blob = handle.maybe_main_module_blob.clone(); deno_core::unsync::spawn(async move { let script_url = Url::parse(&script) .map_err(|_| SyncFetchErrorKind::InvalidScriptUrl)?; let mut loose_mime_checks = loose_mime_checks; let (body, mime_type, res_url) = match script_url.scheme() { "http" | "https" => { let mut req = http::Request::new(deno_fetch::ReqBody::empty()); *req.uri_mut() = script_url.as_str().parse()?; let resp = client.send(req).await.map_err(FetchError::ClientSend)?; if resp.status().is_client_error() || resp.status().is_server_error() { return Err(SyncFetchErrorKind::InvalidStatusCode( resp.status(), )); } // TODO(andreubotella) Properly run fetch's "extract a MIME type". let mime_type = resp .headers() .get("Content-Type") .and_then(|v| v.to_str().ok()) .map(mime_type_essence); // Always check the MIME type with HTTP(S). loose_mime_checks = false; let body = resp .collect() .await .map_err(SyncFetchErrorKind::Other)? .to_bytes(); (body, mime_type, script) } "data" => { let data_url = DataUrl::process(&script).map_err(FetchError::DataUrl)?; let mime_type = { let mime = data_url.mime_type(); format!("{}/{}", mime.type_, mime.subtype) }; let (body, _) = data_url.decode_to_vec().map_err(FetchError::Base64)?; (Bytes::from(body), Some(mime_type), script) } "blob" => { let blob = maybe_main_module_blob .as_ref() .filter(|(blob_specifier, _)| *blob_specifier == script_url) .map(|(_, blob)| blob.clone()) .or_else(|| blob_store.get_object_url(script_url)) .ok_or(FetchError::BlobNotFound)?; let mime_type = mime_type_essence(&blob.media_type); let body = blob.read_all().await; (Bytes::from(body), Some(mime_type), script) } _ => { return Err( SyncFetchErrorKind::ClassicScriptSchemeUnsupportedInWorkers( script_url.scheme().to_string(), ), ); } }; if !loose_mime_checks { // TODO(andreubotella) Check properly for a Javascript MIME type. match mime_type.as_deref() { Some("application/javascript" | "text/javascript") => {} Some(mime_type) => { return Err(SyncFetchErrorKind::InvalidMimeType( mime_type.to_string(), )); } None => return Err(SyncFetchErrorKind::MissingMimeType), } } let (text, _) = encoding_rs::UTF_8.decode_with_bom_removal(&body); Ok(SyncFetchScript { url: res_url, script: text.into_owned(), }) }) }) .collect::<deno_core::futures::stream::FuturesUnordered<_>>(); let mut ret = Vec::with_capacity(futures.len()); while let Some(result) = futures.next().await { let script = result??; ret.push(script); } Ok(ret) }) }); thread.join().unwrap() }