From f68c6230d6c3b66a855ca6b3ff45c2eaf47a7921 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Wed, 19 Oct 2016 18:37:05 +0530 Subject: [PATCH] Bug 1151899 - Include rust-url-capi (leave-open); r=valentin,ted MozReview-Commit-ID: 1ITlPLvwzF4 --- browser/confvars.sh | 1 + netwerk/base/nsStandardURL.cpp | 13 + netwerk/base/rust-url-capi/.gitignore | 2 + netwerk/base/rust-url-capi/Cargo.toml | 19 + .../base/rust-url-capi/src/error_mapping.rs | 68 +++ netwerk/base/rust-url-capi/src/lib.rs | 477 ++++++++++++++++++ .../base/rust-url-capi/src/rust-url-capi.h | 45 ++ .../base/rust-url-capi/src/string_utils.rs | 57 +++ netwerk/base/rust-url-capi/test/Makefile | 4 + netwerk/base/rust-url-capi/test/test.cpp | 141 ++++++ old-configure.in | 3 + toolkit/library/gtest/rust/Cargo.lock | 57 +++ toolkit/library/rust/Cargo.lock | 57 +++ toolkit/library/rust/shared/Cargo.toml | 1 + toolkit/library/rust/shared/lib.rs | 1 + 15 files changed, 946 insertions(+) create mode 100644 netwerk/base/rust-url-capi/.gitignore create mode 100644 netwerk/base/rust-url-capi/Cargo.toml create mode 100644 netwerk/base/rust-url-capi/src/error_mapping.rs create mode 100644 netwerk/base/rust-url-capi/src/lib.rs create mode 100644 netwerk/base/rust-url-capi/src/rust-url-capi.h create mode 100644 netwerk/base/rust-url-capi/src/string_utils.rs create mode 100644 netwerk/base/rust-url-capi/test/Makefile create mode 100644 netwerk/base/rust-url-capi/test/test.cpp diff --git a/browser/confvars.sh b/browser/confvars.sh index be550e7382cd..d45b9221fe4b 100755 --- a/browser/confvars.sh +++ b/browser/confvars.sh @@ -55,6 +55,7 @@ MOZ_APP_STATIC_INI=1 MOZ_WEBGL_CONFORMANT=1 MOZ_JSDOWNLOADS=1 MOZ_RUST_MP4PARSE=1 +MOZ_RUST_URLPARSE=1 # Enable checking that add-ons are signed by the trusted root MOZ_ADDON_SIGNING=1 diff --git a/netwerk/base/nsStandardURL.cpp b/netwerk/base/nsStandardURL.cpp index f14846a441bf..27a0c1042da1 100644 --- a/netwerk/base/nsStandardURL.cpp +++ b/netwerk/base/nsStandardURL.cpp @@ -65,6 +65,19 @@ static LazyLogModule gStandardURLLog("nsStandardURL"); //---------------------------------------------------------------------------- +#ifdef MOZ_RUST_URLPARSE +extern "C" int32_t c_fn_set_size(void * container, size_t size) +{ + ((nsACString *) container)->SetLength(size); + return 0; +} + +extern "C" char * c_fn_get_buffer(void * container) +{ + return ((nsACString *) container)->BeginWriting(); +} +#endif + static nsresult EncodeString(nsIUnicodeEncoder *encoder, const nsAFlatString &str, nsACString &result) { diff --git a/netwerk/base/rust-url-capi/.gitignore b/netwerk/base/rust-url-capi/.gitignore new file mode 100644 index 000000000000..4fffb2f89cbd --- /dev/null +++ b/netwerk/base/rust-url-capi/.gitignore @@ -0,0 +1,2 @@ +/target +/Cargo.lock diff --git a/netwerk/base/rust-url-capi/Cargo.toml b/netwerk/base/rust-url-capi/Cargo.toml new file mode 100644 index 000000000000..ecdb53058a10 --- /dev/null +++ b/netwerk/base/rust-url-capi/Cargo.toml @@ -0,0 +1,19 @@ +[package] + +name = "rust_url_capi" +version = "0.0.1" +authors = ["Valentin Gosu "] + +[profile.dev] +opt-level = 3 +debug = true +rpath = true +lto = true + +[lib] +name = "rust_url_capi" + + +[dependencies] +libc = "0.2.0" +url = "1.2.1" diff --git a/netwerk/base/rust-url-capi/src/error_mapping.rs b/netwerk/base/rust-url-capi/src/error_mapping.rs new file mode 100644 index 000000000000..f20afb263c5f --- /dev/null +++ b/netwerk/base/rust-url-capi/src/error_mapping.rs @@ -0,0 +1,68 @@ +use url::ParseError; + +pub trait ErrorCode { + fn error_code(&self) -> i32; +} + +impl ErrorCode for Result<(), T> { + fn error_code(&self) -> i32 { + match *self { + Ok(_) => 0, + Err(ref error) => error.error_code(), + } + } +} + +impl ErrorCode for () { + fn error_code(&self) -> i32 { + return -1; + } +} +impl ErrorCode for ParseError { + fn error_code(&self) -> i32 { + return -1; +// match *self { +// ParseError::EmptyHost => -1, +// ParseError::InvalidScheme => -2, +// ParseError::InvalidPort => -3, +// ParseError::InvalidIpv6Address => -4, +// ParseError::InvalidDomainCharacter => -5, +// ParseError::InvalidCharacter => -6, +// ParseError::InvalidBackslash => -7, +// ParseError::InvalidPercentEncoded => -8, +// ParseError::InvalidAtSymbolInUser => -9, +// ParseError::ExpectedTwoSlashes => -10, +// ParseError::ExpectedInitialSlash => -11, +// ParseError::NonUrlCodePoint => -12, +// ParseError::RelativeUrlWithScheme => -13, +// ParseError::RelativeUrlWithoutBase => -14, +// ParseError::RelativeUrlWithNonRelativeBase => -15, +// ParseError::NonAsciiDomainsNotSupportedYet => -16, +// ParseError::CannotSetJavascriptFragment => -17, +// ParseError::CannotSetPortWithFileLikeScheme => -18, +// ParseError::CannotSetUsernameWithNonRelativeScheme => -19, +// ParseError::CannotSetPasswordWithNonRelativeScheme => -20, +// ParseError::CannotSetHostPortWithNonRelativeScheme => -21, +// ParseError::CannotSetHostWithNonRelativeScheme => -22, +// ParseError::CannotSetPortWithNonRelativeScheme => -23, +// ParseError::CannotSetPathWithNonRelativeScheme => -24, +// } + } +} + +pub enum NSError { + OK, + InvalidArg, + Failure, +} + +impl ErrorCode for NSError { + #[allow(overflowing_literals)] + fn error_code(&self) -> i32 { + match *self { + NSError::OK => 0, + NSError::InvalidArg => 0x80070057, + NSError::Failure => 0x80004005 + } + } +} diff --git a/netwerk/base/rust-url-capi/src/lib.rs b/netwerk/base/rust-url-capi/src/lib.rs new file mode 100644 index 000000000000..e2997ce46997 --- /dev/null +++ b/netwerk/base/rust-url-capi/src/lib.rs @@ -0,0 +1,477 @@ +extern crate url; +use url::{Url, ParseError, ParseOptions}; +use url::quirks; +extern crate libc; +use libc::size_t; + + +use std::mem; +use std::str; + +#[allow(non_camel_case_types)] +pub type rusturl_ptr = *const libc::c_void; + +mod string_utils; +pub use string_utils::*; + +mod error_mapping; +use error_mapping::*; + +fn parser<'a>() -> ParseOptions<'a> { + Url::options() +} + +fn default_port(scheme: &str) -> Option { + match scheme { + "ftp" => Some(21), + "gopher" => Some(70), + "http" => Some(80), + "https" => Some(443), + "ws" => Some(80), + "wss" => Some(443), + "rtsp" => Some(443), + "moz-anno" => Some(443), + "android" => Some(443), + _ => None, + } +} + +#[no_mangle] +pub unsafe extern "C" fn rusturl_new(spec: *mut libc::c_char, len: size_t) -> rusturl_ptr { + let slice = std::slice::from_raw_parts(spec as *const libc::c_uchar, len as usize); + let url_spec = match str::from_utf8(slice) { + Ok(spec) => spec, + Err(_) => return 0 as rusturl_ptr + }; + + let url = match parser().parse(url_spec) { + Ok(url) => url, + Err(_) => return 0 as rusturl_ptr + }; + + let url = Box::new(url); + Box::into_raw(url) as rusturl_ptr +} + +#[no_mangle] +pub unsafe extern "C" fn rusturl_free(urlptr: rusturl_ptr) { + if urlptr.is_null() { + return (); + } + let url: Box = Box::from_raw(urlptr as *mut url::Url); + drop(url); +} + +#[no_mangle] +pub unsafe extern "C" fn rusturl_get_spec(urlptr: rusturl_ptr, cont: *mut libc::c_void) -> i32 { + if urlptr.is_null() { + return NSError::InvalidArg.error_code(); + } + let url: &Url = mem::transmute(urlptr); + cont.assign(&url.to_string()) +} + +#[no_mangle] +pub unsafe extern "C" fn rusturl_get_scheme(urlptr: rusturl_ptr, cont: *mut libc::c_void) -> i32 { + if urlptr.is_null() { + return NSError::InvalidArg.error_code(); + } + let url: &Url = mem::transmute(urlptr); + cont.assign(&url.scheme()) +} + +#[no_mangle] +pub unsafe extern "C" fn rusturl_get_username(urlptr: rusturl_ptr, cont: *mut libc::c_void) -> i32 { + if urlptr.is_null() { + return NSError::InvalidArg.error_code(); + } + let url: &Url = mem::transmute(urlptr); + if url.cannot_be_a_base() { + cont.set_size(0) + } else { + cont.assign(url.username()) + } +} + +#[no_mangle] +pub unsafe extern "C" fn rusturl_get_password(urlptr: rusturl_ptr, cont: *mut libc::c_void) -> i32 { + if urlptr.is_null() { + return NSError::InvalidArg.error_code(); + } + let url: &Url = mem::transmute(urlptr); + match url.password() { + Some(p) => cont.assign(&p.to_string()), + None => cont.set_size(0) + } +} + +#[no_mangle] +pub unsafe extern "C" fn rusturl_get_host(urlptr: rusturl_ptr, cont: *mut libc::c_void) -> i32 { + if urlptr.is_null() { + return NSError::InvalidArg.error_code(); + } + let url: &Url = mem::transmute(urlptr); + + match url.host() { + Some(h) => cont.assign(&h.to_string()), + None => cont.set_size(0) + } +} + +#[no_mangle] +pub unsafe extern "C" fn rusturl_get_port(urlptr: rusturl_ptr) -> i32 { + if urlptr.is_null() { + return NSError::InvalidArg.error_code(); + } + let url: &Url = mem::transmute(urlptr); + + match url.port() { + Some(port) => port as i32, + None => -1 + } +} + +#[no_mangle] +pub unsafe extern "C" fn rusturl_get_path(urlptr: rusturl_ptr, cont: *mut libc::c_void) -> i32 { + if urlptr.is_null() { + return NSError::InvalidArg.error_code(); + } + let url: &Url = mem::transmute(urlptr); + if url.cannot_be_a_base() { + cont.set_size(0) + } else { + cont.assign(url.path()) + } +} + +#[no_mangle] +pub unsafe extern "C" fn rusturl_get_query(urlptr: rusturl_ptr, cont: *mut libc::c_void) -> i32 { + if urlptr.is_null() { + return NSError::InvalidArg.error_code(); + } + let url: &Url = mem::transmute(urlptr); + match url.query() { + Some(ref s) => cont.assign(s), + None => cont.set_size(0) + } +} + +#[no_mangle] +pub unsafe extern "C" fn rusturl_get_fragment(urlptr: rusturl_ptr, cont: *mut libc::c_void) -> i32 { + if urlptr.is_null() { + return NSError::InvalidArg.error_code(); + } + let url: &Url = mem::transmute(urlptr); + + match url.fragment() { + Some(ref fragment) => cont.assign(fragment), + None => cont.set_size(0) + } +} + +#[no_mangle] +pub unsafe extern "C" fn rusturl_has_fragment(urlptr: rusturl_ptr) -> i32 { + if urlptr.is_null() { + return NSError::InvalidArg.error_code(); + } + let url: &Url = mem::transmute(urlptr); + + match url.fragment() { + Some(_) => return 1, + None => return 0 + } +} + +#[no_mangle] +pub unsafe extern "C" fn rusturl_set_scheme(urlptr: rusturl_ptr, scheme: *mut libc::c_char, len: size_t) -> i32 { + if urlptr.is_null() { + return NSError::InvalidArg.error_code(); + } + let mut url: &mut Url = mem::transmute(urlptr); + let slice = std::slice::from_raw_parts(scheme as *const libc::c_uchar, len as usize); + + let scheme_ = match str::from_utf8(slice).ok() { + Some(p) => p, + None => return ParseError::InvalidDomainCharacter.error_code() // utf-8 failed + }; + + quirks::set_protocol(url, scheme_).error_code() +} + + +#[no_mangle] +pub unsafe extern "C" fn rusturl_set_username(urlptr: rusturl_ptr, username: *mut libc::c_char, len: size_t) -> i32 { + if urlptr.is_null() { + return NSError::InvalidArg.error_code(); + } + let mut url: &mut Url = mem::transmute(urlptr); + let slice = std::slice::from_raw_parts(username as *const libc::c_uchar, len as usize); + + let username_ = match str::from_utf8(slice).ok() { + Some(p) => p, + None => return ParseError::InvalidDomainCharacter.error_code() // utf-8 failed + }; + + quirks::set_username(url, username_).error_code() +} + +#[no_mangle] +pub unsafe extern "C" fn rusturl_set_password(urlptr: rusturl_ptr, password: *mut libc::c_char, len: size_t) -> i32 { + if urlptr.is_null() { + return NSError::InvalidArg.error_code(); + } + let mut url: &mut Url = mem::transmute(urlptr); + let slice = std::slice::from_raw_parts(password as *const libc::c_uchar, len as usize); + + let password_ = match str::from_utf8(slice).ok() { + Some(p) => p, + None => return ParseError::InvalidDomainCharacter.error_code() // utf-8 failed + }; + + quirks::set_password(url, password_).error_code() +} + +#[no_mangle] +pub unsafe extern "C" fn rusturl_set_host_and_port(urlptr: rusturl_ptr, host_and_port: *mut libc::c_char, len: size_t) -> i32 { + if urlptr.is_null() { + return NSError::InvalidArg.error_code(); + } + let mut url: &mut Url = mem::transmute(urlptr); + let slice = std::slice::from_raw_parts(host_and_port as *const libc::c_uchar, len as usize); + + let host_and_port_ = match str::from_utf8(slice).ok() { + Some(p) => p, + None => return ParseError::InvalidDomainCharacter.error_code() // utf-8 failed + }; + + quirks::set_host(url, host_and_port_).error_code() +} + +#[no_mangle] +pub unsafe extern "C" fn rusturl_set_host(urlptr: rusturl_ptr, host: *mut libc::c_char, len: size_t) -> i32 { + if urlptr.is_null() { + return NSError::InvalidArg.error_code(); + } + let mut url: &mut Url = mem::transmute(urlptr); + let slice = std::slice::from_raw_parts(host as *const libc::c_uchar, len as usize); + + let hostname = match str::from_utf8(slice).ok() { + Some(h) => h, + None => return ParseError::InvalidDomainCharacter.error_code() // utf-8 failed + }; + + quirks::set_hostname(url, hostname).error_code() +} + +#[no_mangle] +pub unsafe extern "C" fn rusturl_set_port(urlptr: rusturl_ptr, port: *mut libc::c_char, len: size_t) -> i32 { + if urlptr.is_null() { + return NSError::InvalidArg.error_code(); + } + let mut url: &mut Url = mem::transmute(urlptr); + let slice = std::slice::from_raw_parts(port as *const libc::c_uchar, len as usize); + + let port_ = match str::from_utf8(slice).ok() { + Some(p) => p, + None => return ParseError::InvalidDomainCharacter.error_code() // utf-8 failed + }; + + quirks::set_port(url, port_).error_code() +} + +#[no_mangle] +pub unsafe extern "C" fn rusturl_set_port_no(urlptr: rusturl_ptr, new_port: i32) -> i32 { + if urlptr.is_null() { + return NSError::InvalidArg.error_code(); + } + let mut url: &mut Url = mem::transmute(urlptr); + if url.cannot_be_a_base() { + -100 + } else { + if url.scheme() == "file" { + return -100; + } + match default_port(url.scheme()) { + Some(def_port) => if new_port == def_port as i32 { + let _ = url.set_port(None); + return NSError::OK.error_code(); + }, + None => {} + }; + if new_port > std::u16::MAX as i32 || new_port < 0 { + let _ = url.set_port(None); + } else { + let _ = url.set_port(Some(new_port as u16)); + } + NSError::OK.error_code() + } +} + +#[no_mangle] +pub unsafe extern "C" fn rusturl_set_path(urlptr: rusturl_ptr, path: *mut libc::c_char, len: size_t) -> i32 { + if urlptr.is_null() { + return NSError::InvalidArg.error_code(); + } + let mut url: &mut Url = mem::transmute(urlptr); + let slice = std::slice::from_raw_parts(path as *const libc::c_uchar, len as usize); + + let path_ = match str::from_utf8(slice).ok() { + Some(p) => p, + None => return ParseError::InvalidDomainCharacter.error_code() // utf-8 failed + }; + + quirks::set_pathname(url, path_).error_code() +} + +#[no_mangle] +pub unsafe extern "C" fn rusturl_set_query(urlptr: rusturl_ptr, query: *mut libc::c_char, len: size_t) -> i32 { + if urlptr.is_null() { + return NSError::InvalidArg.error_code(); + } + let mut url: &mut Url = mem::transmute(urlptr); + let slice = std::slice::from_raw_parts(query as *const libc::c_uchar, len as usize); + + let query_ = match str::from_utf8(slice).ok() { + Some(p) => p, + None => return ParseError::InvalidDomainCharacter.error_code() // utf-8 failed + }; + + quirks::set_search(url, query_).error_code() +} + +#[no_mangle] +pub unsafe extern "C" fn rusturl_set_fragment(urlptr: rusturl_ptr, fragment: *mut libc::c_char, len: size_t) -> i32 { + if urlptr.is_null() { + return NSError::InvalidArg.error_code(); + } + let mut url: &mut Url = mem::transmute(urlptr); + let slice = std::slice::from_raw_parts(fragment as *const libc::c_uchar, len as usize); + + let fragment_ = match str::from_utf8(slice).ok() { + Some(p) => p, + None => return ParseError::InvalidDomainCharacter.error_code() // utf-8 failed + }; + + quirks::set_hash(url, fragment_).error_code() +} + +#[no_mangle] +pub unsafe extern "C" fn rusturl_resolve(urlptr: rusturl_ptr, resolve: *mut libc::c_char, len: size_t, cont: *mut libc::c_void) -> i32 { + if urlptr.is_null() { + return NSError::InvalidArg.error_code(); + } + let url: &mut Url = mem::transmute(urlptr); + + let slice = std::slice::from_raw_parts(resolve as *const libc::c_uchar, len as usize); + + let resolve_ = match str::from_utf8(slice).ok() { + Some(p) => p, + None => return NSError::Failure.error_code() + }; + + match parser().base_url(Some(&url)).parse(resolve_).ok() { + Some(u) => cont.assign(&u.to_string()), + None => cont.set_size(0) + } +} + +#[no_mangle] +pub unsafe extern "C" fn rusturl_common_base_spec(urlptr1: rusturl_ptr, urlptr2: rusturl_ptr, cont: *mut libc::c_void) -> i32 { + if urlptr1.is_null() || urlptr2.is_null() { + return NSError::InvalidArg.error_code(); + } + let url1: &Url = mem::transmute(urlptr1); + let url2: &Url = mem::transmute(urlptr2); + + if url1 == url2 { + return cont.assign(&url1.to_string()); + } + + if url1.scheme() != url2.scheme() || + url1.host() != url2.host() || + url1.username() != url2.username() || + url1.password() != url2.password() || + url1.port() != url2.port() { + return cont.set_size(0); + } + + let path1 = match url1.path_segments() { + Some(path) => path, + None => return cont.set_size(0) + }; + let path2 = match url2.path_segments() { + Some(path) => path, + None => return cont.set_size(0) + }; + + let mut url = url1.clone(); + url.set_query(None); + let _ = url.set_host(None); + { + let mut new_segments = if let Ok(segments) = url.path_segments_mut() { + segments + } else { + return cont.set_size(0) + }; + + for (p1, p2) in path1.zip(path2) { + if p1 != p2 { + break; + } else { + new_segments.push(p1); + } + } + } + + cont.assign(&url.to_string()) +} + +#[no_mangle] +pub unsafe extern "C" fn rusturl_relative_spec(urlptr1: rusturl_ptr, urlptr2: rusturl_ptr, cont: *mut libc::c_void) -> i32 { + if urlptr1.is_null() || urlptr2.is_null() { + return NSError::InvalidArg.error_code(); + } + let url1: &Url = mem::transmute(urlptr1); + let url2: &Url = mem::transmute(urlptr2); + + if url1 == url2 { + return cont.set_size(0); + } + + if url1.scheme() != url2.scheme() || + url1.host() != url2.host() || + url1.username() != url2.username() || + url1.password() != url2.password() || + url1.port() != url2.port() { + return cont.assign(&url2.to_string()); + } + + let mut path1 = match url1.path_segments() { + Some(path) => path, + None => return cont.assign(&url2.to_string()) + }; + let mut path2 = match url2.path_segments() { + Some(path) => path, + None => return cont.assign(&url2.to_string()) + }; + + // TODO: file:// on WIN? + + // Exhaust the part of the iterators that match + while let (Some(ref p1), Some(ref p2)) = (path1.next(), path2.next()) { + if p1 != p2 { + break; + } + } + + let mut buffer: String = "".to_string(); + for _ in path1 { + buffer = buffer + "../"; + } + for p2 in path2 { + buffer = buffer + p2 + "/"; + } + + return cont.assign(&buffer); +} + diff --git a/netwerk/base/rust-url-capi/src/rust-url-capi.h b/netwerk/base/rust-url-capi/src/rust-url-capi.h new file mode 100644 index 000000000000..8d7a05aedcc7 --- /dev/null +++ b/netwerk/base/rust-url-capi/src/rust-url-capi.h @@ -0,0 +1,45 @@ +#ifndef __RUST_URL_CAPI +#define __RUST_URL_CAPI +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct rusturl; +typedef struct rusturl* rusturl_ptr; + +rusturl_ptr rusturl_new(const char *spec, size_t src_len); +void rusturl_free(rusturl_ptr url); + +int32_t rusturl_get_spec(rusturl_ptr url, void*); +int32_t rusturl_get_scheme(rusturl_ptr url, void*); +int32_t rusturl_get_username(rusturl_ptr url, void*); +int32_t rusturl_get_password(rusturl_ptr url, void*); +int32_t rusturl_get_host(rusturl_ptr url, void*); +int32_t rusturl_get_port(rusturl_ptr url); // returns port or -1 +int32_t rusturl_get_path(rusturl_ptr url, void*); +int32_t rusturl_get_query(rusturl_ptr url, void*); +int32_t rusturl_get_fragment(rusturl_ptr url, void*); +int32_t rusturl_has_fragment(rusturl_ptr url); // 1 true, 0 false, < 0 error + +int32_t rusturl_set_scheme(rusturl_ptr url, const char *scheme, size_t len); +int32_t rusturl_set_username(rusturl_ptr url, const char *user, size_t len); +int32_t rusturl_set_password(rusturl_ptr url, const char *pass, size_t len); +int32_t rusturl_set_host_and_port(rusturl_ptr url, const char *hostport, size_t len); +int32_t rusturl_set_host(rusturl_ptr url, const char *host, size_t len); +int32_t rusturl_set_port(rusturl_ptr url, const char *port, size_t len); +int32_t rusturl_set_port_no(rusturl_ptr url, const int32_t port); +int32_t rusturl_set_path(rusturl_ptr url, const char *path, size_t len); +int32_t rusturl_set_query(rusturl_ptr url, const char *path, size_t len); +int32_t rusturl_set_fragment(rusturl_ptr url, const char *path, size_t len); + +int32_t rusturl_resolve(rusturl_ptr url, const char *relative, size_t len, void*); +int32_t rusturl_common_base_spec(rusturl_ptr url1, rusturl_ptr url2, void*); +int32_t rusturl_relative_spec(rusturl_ptr url1, rusturl_ptr url2, void*); + +#ifdef __cplusplus +} +#endif + +#endif // __RUST_URL_CAPI \ No newline at end of file diff --git a/netwerk/base/rust-url-capi/src/string_utils.rs b/netwerk/base/rust-url-capi/src/string_utils.rs new file mode 100644 index 000000000000..ae68a60dc3d2 --- /dev/null +++ b/netwerk/base/rust-url-capi/src/string_utils.rs @@ -0,0 +1,57 @@ +extern crate libc; +use libc::size_t; + +extern crate std; +use std::ptr; + +use error_mapping::*; + +extern "C" { + fn c_fn_set_size(user: *mut libc::c_void, size: size_t) -> i32; + fn c_fn_get_buffer(user: *mut libc::c_void) -> *mut libc::c_char; +} + +pub trait StringContainer { + fn set_size(&self, size_t) -> i32; + fn get_buffer(&self) -> *mut libc::c_char; + fn assign(&self, content: &str) -> i32; +} + +impl StringContainer for *mut libc::c_void { + fn set_size(&self, size: size_t) -> i32 { + if (*self).is_null() { + return NSError::InvalidArg.error_code(); + } + unsafe { + c_fn_set_size(*self, size); + } + + return NSError::OK.error_code(); + } + fn get_buffer(&self) -> *mut libc::c_char { + if (*self).is_null() { + return 0 as *mut libc::c_char; + } + unsafe { + c_fn_get_buffer(*self) + } + } + fn assign(&self, content: &str) -> i32 { + if (*self).is_null() { + return NSError::InvalidArg.error_code(); + } + + unsafe { + let slice = content.as_bytes(); + c_fn_set_size(*self, slice.len()); + let buf = c_fn_get_buffer(*self); + if buf.is_null() { + return NSError::Failure.error_code(); + } + + ptr::copy(slice.as_ptr(), buf as *mut u8, slice.len()); + } + + NSError::OK.error_code() + } +} diff --git a/netwerk/base/rust-url-capi/test/Makefile b/netwerk/base/rust-url-capi/test/Makefile new file mode 100644 index 000000000000..a4e2fd0cfaa4 --- /dev/null +++ b/netwerk/base/rust-url-capi/test/Makefile @@ -0,0 +1,4 @@ +all: + cd .. && cargo build + g++ -Wall -o test test.cpp ../target/debug/librust*.a -ldl -lpthread -lrt -lgcc_s -lpthread -lc -lm -std=c++0x + ./test diff --git a/netwerk/base/rust-url-capi/test/test.cpp b/netwerk/base/rust-url-capi/test/test.cpp new file mode 100644 index 000000000000..6e90ea43b0cd --- /dev/null +++ b/netwerk/base/rust-url-capi/test/test.cpp @@ -0,0 +1,141 @@ +#include +#include +#include +#include "../src/rust-url-capi.h" + +class StringContainer +{ +public: + StringContainer() + { + mBuffer = nullptr; + mLength = 0; + } + + ~StringContainer() + { + free(mBuffer); + mBuffer = nullptr; + } + + void SetSize(size_t size) + { + mLength = size; + if (mBuffer) { + mBuffer = (char *)realloc(mBuffer, size); + return; + } + mBuffer = (char *)malloc(size); + } + + char * GetBuffer() + { + return mBuffer; + } + + void CheckEquals(const char * ref) { + int32_t refLen = strlen(ref); + printf("CheckEquals: %s (len:%d)\n", ref, refLen); + if (refLen != mLength || strncmp(mBuffer, ref, mLength)) { + printf("\t--- ERROR ---\n"); + printf("Got : "); + fwrite(mBuffer, mLength, 1, stdout); + printf(" (len:%d)\n", mLength); + exit(-1); + } + printf("-> OK\n"); + } +private: + int32_t mLength; + char * mBuffer; +}; + +extern "C" int32_t c_fn_set_size(void * container, size_t size) +{ + ((StringContainer *) container)->SetSize(size); + return 0; +} + +extern "C" char * c_fn_get_buffer(void * container) +{ + return ((StringContainer *) container)->GetBuffer(); +} + +#define TEST_CALL(func, expected) \ +{ \ + int32_t code = func; \ + printf("%s -> code %d\n", #func, code); \ + assert(code == expected); \ + printf("-> OK\n"); \ +} \ + + +int main() { + // Create URL + rusturl_ptr url = rusturl_new("http://example.com/path/some/file.txt", + strlen("http://example.com/path/some/file.txt")); + assert(url); // Check we have a URL + + StringContainer container; + + TEST_CALL(rusturl_get_spec(url, &container), 0); + container.CheckEquals("http://example.com/path/some/file.txt"); + TEST_CALL(rusturl_set_host(url, "test.com", strlen("test.com")), 0); + TEST_CALL(rusturl_get_host(url, &container), 0); + container.CheckEquals("test.com"); + TEST_CALL(rusturl_get_path(url, &container), 0); + container.CheckEquals("/path/some/file.txt"); + TEST_CALL(rusturl_set_path(url, "hello/../else.txt", strlen("hello/../else.txt")), 0); + TEST_CALL(rusturl_get_path(url, &container), 0); + container.CheckEquals("/else.txt"); + TEST_CALL(rusturl_resolve(url, "./bla/file.txt", strlen("./bla/file.txt"), &container), 0); + container.CheckEquals("http://test.com/bla/file.txt"); + TEST_CALL(rusturl_get_scheme(url, &container), 0); + container.CheckEquals("http"); + TEST_CALL(rusturl_set_username(url, "user", strlen("user")), 0); + TEST_CALL(rusturl_get_username(url, &container), 0); + container.CheckEquals("user"); + TEST_CALL(rusturl_get_spec(url, &container), 0); + container.CheckEquals("http://user@test.com/else.txt"); + TEST_CALL(rusturl_set_password(url, "pass", strlen("pass")), 0); + TEST_CALL(rusturl_get_password(url, &container), 0); + container.CheckEquals("pass"); + TEST_CALL(rusturl_get_spec(url, &container), 0); + container.CheckEquals("http://user:pass@test.com/else.txt"); + TEST_CALL(rusturl_set_username(url, "", strlen("")), 0); + TEST_CALL(rusturl_set_password(url, "", strlen("")), 0); + TEST_CALL(rusturl_get_spec(url, &container), 0); + container.CheckEquals("http://test.com/else.txt"); + TEST_CALL(rusturl_set_host_and_port(url, "example.org:1234", strlen("example.org:1234")), 0); + TEST_CALL(rusturl_get_host(url, &container), 0); + container.CheckEquals("example.org"); + assert(rusturl_get_port(url) == 1234); + TEST_CALL(rusturl_set_port(url, "9090", strlen("9090")), 0); + assert(rusturl_get_port(url) == 9090); + TEST_CALL(rusturl_set_query(url, "x=1", strlen("x=1")), 0); + TEST_CALL(rusturl_get_query(url, &container), 0); + container.CheckEquals("x=1"); + TEST_CALL(rusturl_set_fragment(url, "fragment", strlen("fragment")), 0); + TEST_CALL(rusturl_get_fragment(url, &container), 0); + container.CheckEquals("fragment"); + TEST_CALL(rusturl_get_spec(url, &container), 0); + container.CheckEquals("http://example.org:9090/else.txt?x=1#fragment"); + + // Free the URL + rusturl_free(url); + + url = rusturl_new("http://example.com/#", + strlen("http://example.com/#")); + assert(url); // Check we have a URL + + assert(rusturl_has_fragment(url) == 1); + TEST_CALL(rusturl_set_fragment(url, "", 0), 0); + assert(rusturl_has_fragment(url) == 0); + TEST_CALL(rusturl_get_spec(url, &container), 0); + container.CheckEquals("http://example.com/"); + + rusturl_free(url); + + printf("SUCCESS\n"); + return 0; +} \ No newline at end of file diff --git a/old-configure.in b/old-configure.in index 82a145408df8..802c03c2004c 100644 --- a/old-configure.in +++ b/old-configure.in @@ -2448,6 +2448,9 @@ if test -n "$MOZ_RUST"; then if test -n "$MOZ_RUST_MP4PARSE"; then AC_DEFINE(MOZ_RUST_MP4PARSE) fi + if test -n "$MOZ_RUST_URLPARSE"; then + AC_DEFINE(MOZ_RUST_URLPARSE) + fi fi AC_SUBST(MOZ_PHOENIX) diff --git a/toolkit/library/gtest/rust/Cargo.lock b/toolkit/library/gtest/rust/Cargo.lock index 8a901478ad7e..1a6b50548f9a 100644 --- a/toolkit/library/gtest/rust/Cargo.lock +++ b/toolkit/library/gtest/rust/Cargo.lock @@ -18,8 +18,29 @@ version = "0.1.0" dependencies = [ "mp4parse_capi 0.5.1", "nsstring 0.1.0", + "rust_url_capi 0.0.1", ] +[[package]] +name = "idna" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "matches 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-bidi 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-normalization 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "libc" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "matches" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "mp4parse" version = "0.5.1" @@ -49,5 +70,41 @@ dependencies = [ "nsstring 0.1.0", ] +[[package]] +name = "rust_url_capi" +version = "0.0.1" +dependencies = [ + "libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unicode-bidi" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "matches 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unicode-normalization" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "url" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "idna 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "matches 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + [metadata] "checksum byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855" +"checksum idna 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1053236e00ce4f668aeca4a769a09b3bf5a682d802abd6f3cb39374f6b162c11" +"checksum libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)" = "408014cace30ee0f767b1c4517980646a573ec61a57957aeeabcac8ac0a02e8d" +"checksum matches 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bcc3ad8109fa4b522f9b0cd81440422781f564aaf8c195de6b9d6642177ad0dd" +"checksum unicode-bidi 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c1f7ceb96afdfeedee42bade65a0d585a6a0106f681b6749c8ff4daa8df30b3f" +"checksum unicode-normalization 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "26643a2f83bac55f1976fb716c10234485f9202dcd65cfbdf9da49867b271172" +"checksum url 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8527c62d9869a08325c38272b3f85668df22a65890c61a639d233dc0ed0b23a2" diff --git a/toolkit/library/rust/Cargo.lock b/toolkit/library/rust/Cargo.lock index ef1090eb6b4d..cbe5d7fb0366 100644 --- a/toolkit/library/rust/Cargo.lock +++ b/toolkit/library/rust/Cargo.lock @@ -16,8 +16,29 @@ version = "0.1.0" dependencies = [ "mp4parse_capi 0.5.1", "nsstring 0.1.0", + "rust_url_capi 0.0.1", ] +[[package]] +name = "idna" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "matches 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-bidi 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-normalization 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "libc" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "matches" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "mp4parse" version = "0.5.1" @@ -36,5 +57,41 @@ dependencies = [ name = "nsstring" version = "0.1.0" +[[package]] +name = "rust_url_capi" +version = "0.0.1" +dependencies = [ + "libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unicode-bidi" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "matches 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unicode-normalization" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "url" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "idna 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "matches 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + [metadata] "checksum byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855" +"checksum idna 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1053236e00ce4f668aeca4a769a09b3bf5a682d802abd6f3cb39374f6b162c11" +"checksum libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)" = "408014cace30ee0f767b1c4517980646a573ec61a57957aeeabcac8ac0a02e8d" +"checksum matches 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bcc3ad8109fa4b522f9b0cd81440422781f564aaf8c195de6b9d6642177ad0dd" +"checksum unicode-bidi 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c1f7ceb96afdfeedee42bade65a0d585a6a0106f681b6749c8ff4daa8df30b3f" +"checksum unicode-normalization 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "26643a2f83bac55f1976fb716c10234485f9202dcd65cfbdf9da49867b271172" +"checksum url 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8527c62d9869a08325c38272b3f85668df22a65890c61a639d233dc0ed0b23a2" diff --git a/toolkit/library/rust/shared/Cargo.toml b/toolkit/library/rust/shared/Cargo.toml index e4e301a89e02..07e735755d5c 100644 --- a/toolkit/library/rust/shared/Cargo.toml +++ b/toolkit/library/rust/shared/Cargo.toml @@ -8,6 +8,7 @@ description = "Shared Rust code for libxul" [dependencies] mp4parse_capi = { path = "../../../../media/libstagefright/binding/mp4parse_capi" } nsstring = { path = "../../../../xpcom/rust/nsstring" } +rust_url_capi = { path = "../../../../netwerk/base/rust-url-capi" } [lib] path = "lib.rs" diff --git a/toolkit/library/rust/shared/lib.rs b/toolkit/library/rust/shared/lib.rs index 007c5159c41c..838b9f379d5b 100644 --- a/toolkit/library/rust/shared/lib.rs +++ b/toolkit/library/rust/shared/lib.rs @@ -4,3 +4,4 @@ extern crate mp4parse_capi; extern crate nsstring; +extern crate rust_url_capi;