summaryrefslogtreecommitdiff
path: root/op_crates/url/lib.rs
diff options
context:
space:
mode:
authorLuca Casonato <lucacasonato@yahoo.com>2021-03-12 16:17:18 +0100
committerGitHub <noreply@github.com>2021-03-12 16:17:18 +0100
commite83ff62ccbe33ad9c19cb9cab9154b6767d6d74b (patch)
tree9b37e4ff189e3c3aa4b454c9835b892fb0a9723a /op_crates/url/lib.rs
parent2f9d7c02dc87cfc57a6d37dc27bb0680b9ac7128 (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.rs155
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")
+}