mirror of
https://github.com/denoland/deno.git
synced 2025-03-03 09:31:22 -05:00
feat: data URL support in fetch (#10054)
This commit adds data URL support in `fetch`. Tested via wpt.
This commit is contained in:
parent
8d55d8b6be
commit
3ab94983b4
4 changed files with 82 additions and 37 deletions
11
Cargo.lock
generated
11
Cargo.lock
generated
|
@ -498,6 +498,15 @@ version = "2.3.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3ee2393c4a91429dffb4bedf19f4d6abf27d8a732c8ce4980305d782e5426d57"
|
||||
|
||||
[[package]]
|
||||
name = "data-url"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d33fe99ccedd6e84bc035f1931bb2e6be79739d6242bd895e7311c886c50dc9c"
|
||||
dependencies = [
|
||||
"matches",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deno"
|
||||
version = "1.8.3"
|
||||
|
@ -615,7 +624,9 @@ name = "deno_fetch"
|
|||
version = "0.24.1"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"data-url",
|
||||
"deno_core",
|
||||
"http",
|
||||
"reqwest",
|
||||
"serde",
|
||||
"tokio",
|
||||
|
|
|
@ -15,7 +15,9 @@ path = "lib.rs"
|
|||
|
||||
[dependencies]
|
||||
bytes = "1.0.1"
|
||||
data-url = "0.1.0"
|
||||
deno_core = { version = "0.83.0", path = "../../core" }
|
||||
http = "0.2.3"
|
||||
reqwest = { version = "0.11.2", default-features = false, features = ["rustls-tls", "stream", "gzip", "brotli"] }
|
||||
serde = { version = "1.0.125", features = ["derive"] }
|
||||
tokio = { version = "1.4.0", features = ["full"] }
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#![deny(warnings)]
|
||||
|
||||
use data_url::DataUrl;
|
||||
use deno_core::error::bad_resource_id;
|
||||
use deno_core::error::generic_error;
|
||||
use deno_core::error::null_opbuf;
|
||||
|
@ -157,52 +158,76 @@ where
|
|||
|
||||
// Check scheme before asking for net permission
|
||||
let scheme = url.scheme();
|
||||
if scheme != "http" && scheme != "https" {
|
||||
return Err(type_error(format!("scheme '{}' not supported", scheme)));
|
||||
}
|
||||
let (request_rid, request_body_rid) = match scheme {
|
||||
"http" | "https" => {
|
||||
let permissions = state.borrow::<FP>();
|
||||
permissions.check_net_url(&url)?;
|
||||
|
||||
let permissions = state.borrow::<FP>();
|
||||
permissions.check_net_url(&url)?;
|
||||
let mut request = client.request(method, url);
|
||||
|
||||
let mut request = client.request(method, url);
|
||||
let request_body_rid = if args.has_body {
|
||||
match data {
|
||||
None => {
|
||||
// If no body is passed, we return a writer for streaming the body.
|
||||
let (tx, rx) = mpsc::channel::<std::io::Result<Vec<u8>>>(1);
|
||||
request = request.body(Body::wrap_stream(ReceiverStream::new(rx)));
|
||||
|
||||
let request_body_rid = if args.has_body {
|
||||
match data {
|
||||
None => {
|
||||
// If no body is passed, we return a writer for streaming the body.
|
||||
let (tx, rx) = mpsc::channel::<std::io::Result<Vec<u8>>>(1);
|
||||
request = request.body(Body::wrap_stream(ReceiverStream::new(rx)));
|
||||
let request_body_rid =
|
||||
state.resource_table.add(FetchRequestBodyResource {
|
||||
body: AsyncRefCell::new(tx),
|
||||
cancel: CancelHandle::default(),
|
||||
});
|
||||
|
||||
let request_body_rid =
|
||||
state.resource_table.add(FetchRequestBodyResource {
|
||||
body: AsyncRefCell::new(tx),
|
||||
cancel: CancelHandle::default(),
|
||||
});
|
||||
|
||||
Some(request_body_rid)
|
||||
}
|
||||
Some(data) => {
|
||||
// If a body is passed, we use it, and don't return a body for streaming.
|
||||
request = request.body(Vec::from(&*data));
|
||||
Some(request_body_rid)
|
||||
}
|
||||
Some(data) => {
|
||||
// If a body is passed, we use it, and don't return a body for streaming.
|
||||
request = request.body(Vec::from(&*data));
|
||||
None
|
||||
}
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
for (key, value) in args.headers {
|
||||
let name = HeaderName::from_bytes(key.as_bytes()).unwrap();
|
||||
let v = HeaderValue::from_str(&value).unwrap();
|
||||
request = request.header(name, v);
|
||||
}
|
||||
|
||||
let fut = request.send();
|
||||
|
||||
let request_rid = state
|
||||
.resource_table
|
||||
.add(FetchRequestResource(Box::pin(fut)));
|
||||
|
||||
(request_rid, request_body_rid)
|
||||
}
|
||||
} else {
|
||||
None
|
||||
"data" => {
|
||||
let data_url = DataUrl::process(url.as_str())
|
||||
.map_err(|e| type_error(format!("{:?}", e)))?;
|
||||
|
||||
let (body, _) = data_url
|
||||
.decode_to_vec()
|
||||
.map_err(|e| type_error(format!("{:?}", e)))?;
|
||||
|
||||
let response = http::Response::builder()
|
||||
.status(http::StatusCode::OK)
|
||||
.header(http::header::CONTENT_TYPE, data_url.mime_type().to_string())
|
||||
.body(reqwest::Body::from(body))?;
|
||||
|
||||
let fut = async move { Ok(Response::from(response)) };
|
||||
|
||||
let request_rid = state
|
||||
.resource_table
|
||||
.add(FetchRequestResource(Box::pin(fut)));
|
||||
|
||||
(request_rid, None)
|
||||
}
|
||||
_ => return Err(type_error(format!("scheme '{}' not supported", scheme))),
|
||||
};
|
||||
|
||||
for (key, value) in args.headers {
|
||||
let name = HeaderName::from_bytes(key.as_bytes()).unwrap();
|
||||
let v = HeaderValue::from_str(&value).unwrap();
|
||||
request = request.header(name, v);
|
||||
}
|
||||
|
||||
let fut = request.send();
|
||||
|
||||
let request_rid = state
|
||||
.resource_table
|
||||
.add(FetchRequestResource(Box::pin(fut)));
|
||||
|
||||
Ok(FetchReturn {
|
||||
request_rid,
|
||||
request_body_rid,
|
||||
|
|
|
@ -768,6 +768,13 @@
|
|||
"Check isHistoryNavigation attribute"
|
||||
]
|
||||
}
|
||||
},
|
||||
"data-urls": {
|
||||
"base64.any.js": true,
|
||||
"processing.any.js": [
|
||||
"\"data://test:test/,X\"",
|
||||
"\"data:text/plain;a=\\\",\\\",X\""
|
||||
]
|
||||
}
|
||||
},
|
||||
"FileAPI": {
|
||||
|
|
Loading…
Add table
Reference in a new issue