mirror of
https://github.com/denoland/deno.git
synced 2025-03-03 17:34:47 -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"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3ee2393c4a91429dffb4bedf19f4d6abf27d8a732c8ce4980305d782e5426d57"
|
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]]
|
[[package]]
|
||||||
name = "deno"
|
name = "deno"
|
||||||
version = "1.8.3"
|
version = "1.8.3"
|
||||||
|
@ -615,7 +624,9 @@ name = "deno_fetch"
|
||||||
version = "0.24.1"
|
version = "0.24.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
|
"data-url",
|
||||||
"deno_core",
|
"deno_core",
|
||||||
|
"http",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"serde",
|
"serde",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
|
|
@ -15,7 +15,9 @@ path = "lib.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bytes = "1.0.1"
|
bytes = "1.0.1"
|
||||||
|
data-url = "0.1.0"
|
||||||
deno_core = { version = "0.83.0", path = "../../core" }
|
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"] }
|
reqwest = { version = "0.11.2", default-features = false, features = ["rustls-tls", "stream", "gzip", "brotli"] }
|
||||||
serde = { version = "1.0.125", features = ["derive"] }
|
serde = { version = "1.0.125", features = ["derive"] }
|
||||||
tokio = { version = "1.4.0", features = ["full"] }
|
tokio = { version = "1.4.0", features = ["full"] }
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#![deny(warnings)]
|
#![deny(warnings)]
|
||||||
|
|
||||||
|
use data_url::DataUrl;
|
||||||
use deno_core::error::bad_resource_id;
|
use deno_core::error::bad_resource_id;
|
||||||
use deno_core::error::generic_error;
|
use deno_core::error::generic_error;
|
||||||
use deno_core::error::null_opbuf;
|
use deno_core::error::null_opbuf;
|
||||||
|
@ -157,52 +158,76 @@ where
|
||||||
|
|
||||||
// Check scheme before asking for net permission
|
// Check scheme before asking for net permission
|
||||||
let scheme = url.scheme();
|
let scheme = url.scheme();
|
||||||
if scheme != "http" && scheme != "https" {
|
let (request_rid, request_body_rid) = match scheme {
|
||||||
return Err(type_error(format!("scheme '{}' not supported", scheme)));
|
"http" | "https" => {
|
||||||
}
|
let permissions = state.borrow::<FP>();
|
||||||
|
permissions.check_net_url(&url)?;
|
||||||
|
|
||||||
let permissions = state.borrow::<FP>();
|
let mut request = client.request(method, url);
|
||||||
permissions.check_net_url(&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 {
|
let request_body_rid =
|
||||||
match data {
|
state.resource_table.add(FetchRequestBodyResource {
|
||||||
None => {
|
body: AsyncRefCell::new(tx),
|
||||||
// If no body is passed, we return a writer for streaming the body.
|
cancel: CancelHandle::default(),
|
||||||
let (tx, rx) = mpsc::channel::<std::io::Result<Vec<u8>>>(1);
|
});
|
||||||
request = request.body(Body::wrap_stream(ReceiverStream::new(rx)));
|
|
||||||
|
|
||||||
let request_body_rid =
|
Some(request_body_rid)
|
||||||
state.resource_table.add(FetchRequestBodyResource {
|
}
|
||||||
body: AsyncRefCell::new(tx),
|
Some(data) => {
|
||||||
cancel: CancelHandle::default(),
|
// If a body is passed, we use it, and don't return a body for streaming.
|
||||||
});
|
request = request.body(Vec::from(&*data));
|
||||||
|
None
|
||||||
Some(request_body_rid)
|
}
|
||||||
}
|
}
|
||||||
Some(data) => {
|
} else {
|
||||||
// If a body is passed, we use it, and don't return a body for streaming.
|
|
||||||
request = request.body(Vec::from(&*data));
|
|
||||||
None
|
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 {
|
"data" => {
|
||||||
None
|
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 {
|
Ok(FetchReturn {
|
||||||
request_rid,
|
request_rid,
|
||||||
request_body_rid,
|
request_body_rid,
|
||||||
|
|
|
@ -768,6 +768,13 @@
|
||||||
"Check isHistoryNavigation attribute"
|
"Check isHistoryNavigation attribute"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"data-urls": {
|
||||||
|
"base64.any.js": true,
|
||||||
|
"processing.any.js": [
|
||||||
|
"\"data://test:test/,X\"",
|
||||||
|
"\"data:text/plain;a=\\\",\\\",X\""
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"FileAPI": {
|
"FileAPI": {
|
||||||
|
|
Loading…
Add table
Reference in a new issue