diff options
author | Luca Casonato <lucacasonato@yahoo.com> | 2021-03-12 16:17:18 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-03-12 16:17:18 +0100 |
commit | e83ff62ccbe33ad9c19cb9cab9154b6767d6d74b (patch) | |
tree | 9b37e4ff189e3c3aa4b454c9835b892fb0a9723a /op_crates/url/lib.rs | |
parent | 2f9d7c02dc87cfc57a6d37dc27bb0680b9ac7128 (diff) |
chore: split web op crate (#9635)
This commit starts splitting out the deno_web op crate into multiple
smaller crates. This commit splits out WebIDL and URL API, but in the
future I want to split out each spec into its own crate. That means we
will have (in rough order of loading): `webidl`, `dom`, `streams`,
`console`, `encoding`, `url`, `file`, `fetch`, `websocket`, and
`webgpu` crates.
Diffstat (limited to 'op_crates/url/lib.rs')
-rw-r--r-- | op_crates/url/lib.rs | 155 |
1 files changed, 155 insertions, 0 deletions
diff --git a/op_crates/url/lib.rs b/op_crates/url/lib.rs new file mode 100644 index 000000000..a655d8c34 --- /dev/null +++ b/op_crates/url/lib.rs @@ -0,0 +1,155 @@ +// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. + +use deno_core::error::generic_error; +use deno_core::error::type_error; +use deno_core::error::uri_error; +use deno_core::error::AnyError; +use deno_core::serde_json; +use deno_core::serde_json::json; +use deno_core::serde_json::Value; +use deno_core::url::form_urlencoded; +use deno_core::url::quirks; +use deno_core::url::Url; +use deno_core::JsRuntime; +use deno_core::ZeroCopyBuf; +use serde::Deserialize; +use serde::Serialize; +use std::panic::catch_unwind; +use std::path::PathBuf; + +/// Parse `UrlParseArgs::href` with an optional `UrlParseArgs::base_href`, or an +/// optional part to "set" after parsing. Return `UrlParts`. +pub fn op_url_parse( + _state: &mut deno_core::OpState, + args: Value, + _zero_copy: &mut [ZeroCopyBuf], +) -> Result<Value, AnyError> { + #[derive(Deserialize)] + #[serde(rename_all = "camelCase")] + struct UrlParseArgs { + href: String, + base_href: Option<String>, + // If one of the following are present, this is a setter call. Apply the + // proper `Url::set_*()` method after (re)parsing `href`. + set_hash: Option<String>, + set_host: Option<String>, + set_hostname: Option<String>, + set_password: Option<String>, + set_pathname: Option<String>, + set_port: Option<String>, + set_protocol: Option<String>, + set_search: Option<String>, + set_username: Option<String>, + } + let args: UrlParseArgs = serde_json::from_value(args)?; + let base_url = args + .base_href + .as_ref() + .map(|b| Url::parse(b).map_err(|_| type_error("Invalid base URL"))) + .transpose()?; + let mut url = Url::options() + .base_url(base_url.as_ref()) + .parse(&args.href) + .map_err(|_| type_error("Invalid URL"))?; + + if let Some(hash) = args.set_hash.as_ref() { + quirks::set_hash(&mut url, hash); + } else if let Some(host) = args.set_host.as_ref() { + quirks::set_host(&mut url, host).map_err(|_| uri_error("Invalid host"))?; + } else if let Some(hostname) = args.set_hostname.as_ref() { + quirks::set_hostname(&mut url, hostname) + .map_err(|_| uri_error("Invalid hostname"))?; + } else if let Some(password) = args.set_password.as_ref() { + quirks::set_password(&mut url, password) + .map_err(|_| uri_error("Invalid password"))?; + } else if let Some(pathname) = args.set_pathname.as_ref() { + quirks::set_pathname(&mut url, pathname); + } else if let Some(port) = args.set_port.as_ref() { + quirks::set_port(&mut url, port).map_err(|_| uri_error("Invalid port"))?; + } else if let Some(protocol) = args.set_protocol.as_ref() { + quirks::set_protocol(&mut url, protocol) + .map_err(|_| uri_error("Invalid protocol"))?; + } else if let Some(search) = args.set_search.as_ref() { + quirks::set_search(&mut url, search); + } else if let Some(username) = args.set_username.as_ref() { + quirks::set_username(&mut url, username) + .map_err(|_| uri_error("Invalid username"))?; + } + + #[derive(Serialize)] + struct UrlParts<'a> { + href: &'a str, + hash: &'a str, + host: &'a str, + hostname: &'a str, + origin: &'a str, + password: &'a str, + pathname: &'a str, + port: &'a str, + protocol: &'a str, + search: &'a str, + username: &'a str, + } + // TODO(nayeemrmn): Panic that occurs in rust-url for the `non-spec:` + // url-constructor wpt tests: https://github.com/servo/rust-url/issues/670. + let username = catch_unwind(|| quirks::username(&url)).map_err(|_| { + generic_error(format!( + "Internal error while parsing \"{}\"{}, \ + see https://github.com/servo/rust-url/issues/670", + args.href, + args + .base_href + .map(|b| format!(" against \"{}\"", b)) + .unwrap_or_default() + )) + })?; + Ok(json!(UrlParts { + href: quirks::href(&url), + hash: quirks::hash(&url), + host: quirks::host(&url), + hostname: quirks::hostname(&url), + origin: &quirks::origin(&url), + password: quirks::password(&url), + pathname: quirks::pathname(&url), + port: quirks::port(&url), + protocol: quirks::protocol(&url), + search: quirks::search(&url), + username, + })) +} + +pub fn op_url_parse_search_params( + _state: &mut deno_core::OpState, + args: Value, + _zero_copy: &mut [ZeroCopyBuf], +) -> Result<Value, AnyError> { + let search: String = serde_json::from_value(args)?; + let search_params: Vec<_> = form_urlencoded::parse(search.as_bytes()) + .into_iter() + .collect(); + Ok(json!(search_params)) +} + +pub fn op_url_stringify_search_params( + _state: &mut deno_core::OpState, + args: Value, + _zero_copy: &mut [ZeroCopyBuf], +) -> Result<Value, AnyError> { + let search_params: Vec<(String, String)> = serde_json::from_value(args)?; + let search = form_urlencoded::Serializer::new(String::new()) + .extend_pairs(search_params) + .finish(); + Ok(json!(search)) +} + +/// Load and execute the javascript code. +pub fn init(isolate: &mut JsRuntime) { + let files = vec![("deno:op_crates/url/00_url.js", include_str!("00_url.js"))]; + for (url, source_code) in files { + isolate.execute(url, source_code).unwrap(); + } +} + +pub fn get_declaration() -> PathBuf { + PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("lib.deno_url.d.ts") +} |