deno.land / x / deno@v1.28.2 / ext / url / lib.rs
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
mod urlpattern;
use deno_core::error::type_error;use deno_core::error::AnyError;use deno_core::include_js_files;use deno_core::op;use deno_core::url::form_urlencoded;use deno_core::url::quirks;use deno_core::url::Url;use deno_core::Extension;use deno_core::OpState;use deno_core::ZeroCopyBuf;use std::path::PathBuf;
use crate::urlpattern::op_urlpattern_parse;use crate::urlpattern::op_urlpattern_process_match_input;
pub fn init() -> Extension { Extension::builder() .js(include_js_files!( prefix "deno:ext/url", "00_url.js", "01_urlpattern.js", )) .ops(vec![ op_url_reparse::decl(), op_url_parse::decl(), op_url_get_serialization::decl(), op_url_parse_with_base::decl(), op_url_parse_search_params::decl(), op_url_stringify_search_params::decl(), op_urlpattern_parse::decl(), op_urlpattern_process_match_input::decl(), ]) .build()}
/// Parse `href` with a `base_href`. Fills the out `buf` with URL components.#[op]pub fn op_url_parse_with_base( state: &mut OpState, href: String, base_href: String, buf: &mut [u8],) -> u32 { let base_url = match Url::parse(&base_href) { Ok(url) => url, Err(_) => return ParseStatus::Err as u32, }; parse_url(state, href, Some(&base_url), buf)}
#[repr(u32)]pub enum ParseStatus { Ok = 0, OkSerialization = 1, Err,}
struct UrlSerialization(String);
#[op]pub fn op_url_get_serialization(state: &mut OpState) -> String { state.take::<UrlSerialization>().0}
/// Parse `href` without a `base_url`. Fills the out `buf` with URL components.#[op]pub fn op_url_parse(state: &mut OpState, href: String, buf: &mut [u8]) -> u32 { parse_url(state, href, None, buf)}
/// `op_url_parse` and `op_url_parse_with_base` share the same implementation.////// This function is used to parse the URL and fill the `buf` with internal/// offset values of the URL components.////// If the serialized URL is the same as the input URL, then `UrlSerialization` is/// not set and returns `ParseStatus::Ok`.////// If the serialized URL is different from the input URL, then `UrlSerialization` is/// set and returns `ParseStatus::OkSerialization`. JS side should check status and/// use `op_url_get_serialization` to get the serialized URL.////// If the URL is invalid, then `UrlSerialization` is not set and returns `ParseStatus::Err`.////// ```js/// const buf = new Uint32Array(8);/// const status = op_url_parse("http://example.com", buf.buffer);/// let serializedUrl = "";/// if (status === ParseStatus.Ok) {/// serializedUrl = "http://example.com";/// } else if (status === ParseStatus.OkSerialization) {/// serializedUrl = op_url_get_serialization();/// }/// ```#[inline]fn parse_url( state: &mut OpState, href: String, base_href: Option<&Url>, buf: &mut [u8],) -> u32 { match Url::options().base_url(base_href).parse(&href) { Ok(url) => { let inner_url = quirks::internal_components(&url);
let buf: &mut [u32] = as_u32_slice(buf); buf[0] = inner_url.scheme_end; buf[1] = inner_url.username_end; buf[2] = inner_url.host_start; buf[3] = inner_url.host_end; buf[4] = inner_url.port.unwrap_or(0) as u32; buf[5] = inner_url.path_start; buf[6] = inner_url.query_start.unwrap_or(0); buf[7] = inner_url.fragment_start.unwrap_or(0); let serialization: String = url.into(); if serialization != href { state.put(UrlSerialization(serialization)); ParseStatus::OkSerialization as u32 } else { ParseStatus::Ok as u32 } } Err(_) => ParseStatus::Err as u32, }}
#[derive(Eq, PartialEq, Debug)]#[repr(u8)]pub enum UrlSetter { Hash = 0, Host = 1, Hostname = 2, Password = 3, Pathname = 4, Port = 5, Protocol = 6, Search = 7, Username = 8,}
const NO_PORT: u32 = 65536;
fn as_u32_slice(slice: &mut [u8]) -> &mut [u32] { assert_eq!(slice.len() % std::mem::size_of::<u32>(), 0); // SAFETY: size is multiple of 4 unsafe { std::slice::from_raw_parts_mut( slice.as_mut_ptr() as *mut u32, slice.len() / std::mem::size_of::<u32>(), ) }}
#[op]pub fn op_url_reparse( state: &mut OpState, href: String, setter: u8, setter_value: String, buf: &mut [u8],) -> u32 { let mut url = match Url::options().parse(&href) { Ok(url) => url, Err(_) => return ParseStatus::Err as u32, };
if setter > 8 { return ParseStatus::Err as u32; } // SAFETY: checked to be less than 9. let setter = unsafe { std::mem::transmute::<u8, UrlSetter>(setter) }; let value = setter_value.as_ref(); let e = match setter { UrlSetter::Hash => { quirks::set_hash(&mut url, value); Ok(()) } UrlSetter::Host => quirks::set_host(&mut url, value),
UrlSetter::Hostname => quirks::set_hostname(&mut url, value),
UrlSetter::Password => quirks::set_password(&mut url, value),
UrlSetter::Pathname => { quirks::set_pathname(&mut url, value); Ok(()) } UrlSetter::Port => quirks::set_port(&mut url, value),
UrlSetter::Protocol => quirks::set_protocol(&mut url, value), UrlSetter::Search => { quirks::set_search(&mut url, value); Ok(()) } UrlSetter::Username => quirks::set_username(&mut url, value), };
match e { Ok(_) => { let inner_url = quirks::internal_components(&url);
let buf: &mut [u32] = as_u32_slice(buf); buf[0] = inner_url.scheme_end; buf[1] = inner_url.username_end; buf[2] = inner_url.host_start; buf[3] = inner_url.host_end; buf[4] = inner_url.port.map(|p| p as u32).unwrap_or(NO_PORT); buf[5] = inner_url.path_start; buf[6] = inner_url.query_start.unwrap_or(0); buf[7] = inner_url.fragment_start.unwrap_or(0); let serialization: String = url.into(); if serialization != href { state.put(UrlSerialization(serialization)); ParseStatus::OkSerialization as u32 } else { ParseStatus::Ok as u32 } } Err(_) => ParseStatus::Err as u32, }}
#[op]pub fn op_url_parse_search_params( args: Option<String>, zero_copy: Option<ZeroCopyBuf>,) -> Result<Vec<(String, String)>, AnyError> { let params = match (args, zero_copy) { (None, Some(zero_copy)) => form_urlencoded::parse(&zero_copy) .into_iter() .map(|(k, v)| (k.as_ref().to_owned(), v.as_ref().to_owned())) .collect(), (Some(args), None) => form_urlencoded::parse(args.as_bytes()) .into_iter() .map(|(k, v)| (k.as_ref().to_owned(), v.as_ref().to_owned())) .collect(), _ => return Err(type_error("invalid parameters")), }; Ok(params)}
#[op]pub fn op_url_stringify_search_params(args: Vec<(String, String)>) -> String { let search = form_urlencoded::Serializer::new(String::new()) .extend_pairs(args) .finish(); search}
pub fn get_declaration() -> PathBuf { PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("lib.deno_url.d.ts")}
Version Info