mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-07-31 09:46:05 -04:00
add rust-url dependency and bindings for it
This commit is contained in:
28
src/html5ever/Cargo.lock
generated
28
src/html5ever/Cargo.lock
generated
@@ -62,6 +62,15 @@ version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ced73b1dacfc750a6db6c0a0c3a3853c8b41997e2e2c563dc90804ae6867959"
|
||||
|
||||
[[package]]
|
||||
name = "form_urlencoded"
|
||||
version = "1.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf"
|
||||
dependencies = [
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "html5ever"
|
||||
version = "0.39.0"
|
||||
@@ -192,6 +201,7 @@ dependencies = [
|
||||
"tikv-jemalloc-ctl",
|
||||
"tikv-jemallocator",
|
||||
"typed-arena",
|
||||
"url",
|
||||
"xml5ever",
|
||||
]
|
||||
|
||||
@@ -263,6 +273,12 @@ version = "1.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "2.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
|
||||
|
||||
[[package]]
|
||||
name = "phf"
|
||||
version = "0.13.1"
|
||||
@@ -504,6 +520,18 @@ version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
|
||||
|
||||
[[package]]
|
||||
name = "url"
|
||||
version = "2.5.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed"
|
||||
dependencies = [
|
||||
"form_urlencoded",
|
||||
"idna",
|
||||
"percent-encoding",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "utf-8"
|
||||
version = "0.7.6"
|
||||
|
||||
@@ -17,6 +17,7 @@ tikv-jemalloc-ctl = {version = "0.6.1", features = ["stats"]}
|
||||
xml5ever = "0.39.0"
|
||||
encoding_rs = "0.8"
|
||||
idna = "1.1.0"
|
||||
url = "2.5.8"
|
||||
|
||||
[profile.release]
|
||||
lto = true
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
// IDNA-2008 behavior diverged from the spec. Value-in / value-out: a UTF-8
|
||||
// host string becomes its punycode form, or an error.
|
||||
|
||||
use ::url::Url;
|
||||
use std::os::raw::c_uchar;
|
||||
use std::slice;
|
||||
|
||||
@@ -81,3 +82,357 @@ pub extern "C" fn lpurl_free(ptr: *mut c_uchar, len: usize) {
|
||||
drop(Box::from_raw(slice));
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn url_parse(ptr: *const c_uchar, len: usize, err: *mut i32) -> *mut Url {
|
||||
let slice = match str_from(ptr, len) {
|
||||
Some(s) => s,
|
||||
None => {
|
||||
*err = url::ParseError::EmptyHost as i32;
|
||||
return std::ptr::null_mut();
|
||||
}
|
||||
};
|
||||
|
||||
match Url::parse(slice) {
|
||||
Ok(url) => Box::into_raw(Box::new(url)),
|
||||
Err(e) => {
|
||||
*err = e as i32;
|
||||
std::ptr::null_mut()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn url_join(
|
||||
base: *const Url,
|
||||
ptr: *const c_uchar,
|
||||
len: usize,
|
||||
err: *mut i32,
|
||||
) -> *mut Url {
|
||||
let base = unsafe { &*base };
|
||||
let slice = match str_from(ptr, len) {
|
||||
Some(s) => s,
|
||||
None => {
|
||||
*err = url::ParseError::EmptyHost as i32;
|
||||
return std::ptr::null_mut();
|
||||
}
|
||||
};
|
||||
|
||||
match base.join(slice) {
|
||||
Ok(url) => Box::into_raw(Box::new(url)),
|
||||
Err(e) => {
|
||||
*err = e as i32;
|
||||
std::ptr::null_mut()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn url_can_parse(ptr: *const c_uchar, len: usize) -> bool {
|
||||
let slice = match str_from(ptr, len) {
|
||||
Some(s) => s,
|
||||
None => return false,
|
||||
};
|
||||
|
||||
Url::parse(slice).is_ok()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn url_can_parse_with_base(
|
||||
base_ptr: *const c_uchar,
|
||||
base_len: usize,
|
||||
ptr: *const c_uchar,
|
||||
len: usize,
|
||||
) -> bool {
|
||||
let base_slice = match str_from(base_ptr, base_len) {
|
||||
Some(s) => s,
|
||||
None => return false,
|
||||
};
|
||||
let slice = match str_from(ptr, len) {
|
||||
Some(s) => s,
|
||||
None => return false,
|
||||
};
|
||||
|
||||
match Url::parse(base_slice) {
|
||||
Ok(url) => url.join(slice).is_ok(),
|
||||
Err(_) => false,
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn url_free(url: *mut Url) {
|
||||
if url.is_null() {
|
||||
return;
|
||||
}
|
||||
drop(Box::from_raw(url));
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn url_to_string(
|
||||
url: *const Url,
|
||||
out_ptr: *mut *const c_uchar,
|
||||
out_len: *mut usize,
|
||||
) {
|
||||
let url = unsafe { &*url };
|
||||
let s = url.as_str();
|
||||
*out_ptr = s.as_ptr();
|
||||
*out_len = s.len();
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn url_set_username(url: *mut Url, ptr: *const c_uchar, len: usize) -> i32 {
|
||||
let url = unsafe { &mut *url };
|
||||
let slice = match str_from(ptr, len) {
|
||||
Some(s) => s,
|
||||
None => return -1,
|
||||
};
|
||||
|
||||
match url.set_username(slice) {
|
||||
Ok(()) => 0,
|
||||
Err(()) => -1,
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn url_get_username(
|
||||
url: *const Url,
|
||||
out_ptr: *mut *const c_uchar,
|
||||
out_len: *mut usize,
|
||||
) {
|
||||
let url = unsafe { &*url };
|
||||
let username = url.username();
|
||||
*out_ptr = username.as_ptr();
|
||||
*out_len = username.len();
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn url_set_password(url: *mut Url, ptr: *const c_uchar, len: usize) -> i32 {
|
||||
let url = unsafe { &mut *url };
|
||||
let slice = match str_from(ptr, len) {
|
||||
Some(s) => s,
|
||||
None => return -1,
|
||||
};
|
||||
|
||||
match url.set_password(Some(slice)) {
|
||||
Ok(()) => 0,
|
||||
Err(()) => -1,
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn url_get_password(
|
||||
url: *const Url,
|
||||
out_ptr: *mut *const c_uchar,
|
||||
out_len: *mut usize,
|
||||
) -> i32 {
|
||||
let url = unsafe { &*url };
|
||||
match url.password() {
|
||||
Some(password) => {
|
||||
*out_ptr = password.as_ptr();
|
||||
*out_len = password.len();
|
||||
0
|
||||
}
|
||||
None => -1,
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct OwnedString {
|
||||
pub ptr: *mut c_uchar,
|
||||
pub len: usize,
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn free_owned_string(owned: OwnedString) {
|
||||
if owned.ptr.is_null() || owned.len == 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
unsafe {
|
||||
let slice = std::ptr::slice_from_raw_parts_mut(owned.ptr, owned.len);
|
||||
drop(Box::from_raw(slice));
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn url_get_origin(url: *const Url) -> OwnedString {
|
||||
let url = unsafe { &*url };
|
||||
let origin = url.origin().ascii_serialization();
|
||||
let len = origin.len();
|
||||
let ptr = Box::into_raw(origin.into_bytes().into_boxed_slice()) as *mut c_uchar;
|
||||
OwnedString { ptr, len }
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn url_set_port(url: *mut Url, port: u16) -> i32 {
|
||||
let url = unsafe { &mut *url };
|
||||
match url.set_port(Some(port)) {
|
||||
Ok(()) => 0,
|
||||
Err(()) => -1,
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn url_get_port(url: *const Url) -> i32 {
|
||||
let url = unsafe { &*url };
|
||||
match url.port() {
|
||||
Some(port) => port as i32,
|
||||
None => -1,
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn url_set_host(url: *mut Url, ptr: *const c_uchar, len: usize) -> i32 {
|
||||
let url = unsafe { &mut *url };
|
||||
|
||||
let slice = match str_from(ptr, len) {
|
||||
Some(s) => s,
|
||||
None => return -1,
|
||||
};
|
||||
|
||||
match url.set_host(Some(slice)) {
|
||||
Ok(()) => 0,
|
||||
Err(_) => -1,
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn url_get_host(
|
||||
url: *const Url,
|
||||
out_ptr: *mut *const c_uchar,
|
||||
out_len: *mut usize,
|
||||
) -> i32 {
|
||||
let url = unsafe { &*url };
|
||||
|
||||
match url.host_str() {
|
||||
Some(h) => unsafe {
|
||||
*out_ptr = h.as_ptr();
|
||||
*out_len = h.len();
|
||||
0
|
||||
},
|
||||
None => unsafe {
|
||||
*out_len = 0;
|
||||
-1
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn url_set_scheme(url: *mut Url, ptr: *const c_uchar, len: usize) -> i32 {
|
||||
let url = unsafe { &mut *url };
|
||||
let slice = match str_from(ptr, len) {
|
||||
Some(s) => s,
|
||||
None => return -1,
|
||||
};
|
||||
|
||||
match url.set_scheme(slice) {
|
||||
Ok(()) => 0,
|
||||
Err(()) => -1,
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn url_get_scheme(
|
||||
url: *const Url,
|
||||
out_ptr: *mut *const c_uchar,
|
||||
out_len: *mut usize,
|
||||
) {
|
||||
let url = unsafe { &*url };
|
||||
let scheme = url.scheme();
|
||||
*out_ptr = scheme.as_ptr();
|
||||
*out_len = scheme.len();
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn url_set_path(url: *mut Url, ptr: *const c_uchar, len: usize) -> i32 {
|
||||
let url = unsafe { &mut *url };
|
||||
let slice = match str_from(ptr, len) {
|
||||
Some(s) => s,
|
||||
None => return -1,
|
||||
};
|
||||
|
||||
url.set_path(slice);
|
||||
0
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn url_get_path(
|
||||
url: *const Url,
|
||||
out_ptr: *mut *const c_uchar,
|
||||
out_len: *mut usize,
|
||||
) {
|
||||
let url = unsafe { &*url };
|
||||
let path = url.path();
|
||||
*out_ptr = path.as_ptr();
|
||||
*out_len = path.len();
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn url_set_query(url: *mut Url, ptr: *const c_uchar, len: usize) -> i32 {
|
||||
let url = unsafe { &mut *url };
|
||||
let slice = match str_from(ptr, len) {
|
||||
Some(s) => s,
|
||||
None => return -1,
|
||||
};
|
||||
|
||||
url.set_query(Some(slice));
|
||||
0
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn url_get_query(
|
||||
url: *const Url,
|
||||
out_ptr: *mut *const c_uchar,
|
||||
out_len: *mut usize,
|
||||
) -> i32 {
|
||||
let url = unsafe { &*url };
|
||||
match url.query() {
|
||||
Some(query) => {
|
||||
*out_ptr = query.as_ptr();
|
||||
*out_len = query.len();
|
||||
0
|
||||
}
|
||||
None => -1,
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn url_set_fragment(url: *mut Url, ptr: *const c_uchar, len: usize) -> i32 {
|
||||
let url = unsafe { &mut *url };
|
||||
let slice = match str_from(ptr, len) {
|
||||
Some(s) => s,
|
||||
None => return -1,
|
||||
};
|
||||
|
||||
url.set_fragment(Some(slice));
|
||||
0
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn url_get_fragment(
|
||||
url: *const Url,
|
||||
out_ptr: *mut *const c_uchar,
|
||||
out_len: *mut usize,
|
||||
) -> i32 {
|
||||
let url = unsafe { &*url };
|
||||
match url.fragment() {
|
||||
Some(fragment) => {
|
||||
*out_ptr = fragment.as_ptr();
|
||||
*out_len = fragment.len();
|
||||
0
|
||||
}
|
||||
None => -1,
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn url_get_href(
|
||||
url: *const Url,
|
||||
out_ptr: *mut *const c_uchar,
|
||||
out_len: *mut usize,
|
||||
) {
|
||||
let url = unsafe { &*url };
|
||||
let href = url.as_str();
|
||||
*out_ptr = href.as_ptr();
|
||||
*out_len = href.len();
|
||||
}
|
||||
|
||||
71
src/sys/url.zig
Normal file
71
src/sys/url.zig
Normal file
@@ -0,0 +1,71 @@
|
||||
// Copyright (C) 2023-2026 Lightpanda (Selecy SAS)
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
//! Bindings for Servo's rust-url (https://github.com/servo/rust-url).
|
||||
//! Check @src/html5ever/url.rs for Rust-side of the bindings.
|
||||
|
||||
const std = @import("std");
|
||||
const mem = std.mem;
|
||||
|
||||
pub const Url = anyopaque;
|
||||
|
||||
pub const OwnedString = extern struct {
|
||||
ptr: [*]const u8,
|
||||
len: usize,
|
||||
|
||||
pub inline fn deinit(self: OwnedString) void {
|
||||
return free_owned_string(self);
|
||||
}
|
||||
|
||||
pub inline fn slice(self: OwnedString) []const u8 {
|
||||
return self.ptr[0..self.len];
|
||||
}
|
||||
};
|
||||
|
||||
/// https://docs.rs/url/latest/url/enum.ParseError.html
|
||||
pub const ParseError = enum(i32) {
|
||||
EmptyHost,
|
||||
IdnaError,
|
||||
InvalidPort,
|
||||
InvalidIpv4Address,
|
||||
InvalidIpv6Address,
|
||||
InvalidDomainCharacter,
|
||||
RelativeUrlWithoutBase,
|
||||
RelativeUrlWithCannotBeABaseBase,
|
||||
SetHostOnCannotBeABaseUrl,
|
||||
Overflow,
|
||||
};
|
||||
|
||||
/// If return value is null, `err` indicates `ParseError`.
|
||||
pub extern "c" fn url_parse(ptr: [*]const u8, len: usize, err: *i32) ?*Url;
|
||||
/// If return value is null, `err` indicates `ParseError`.
|
||||
pub extern "c" fn url_join(base: *const Url, ptr: [*]const u8, len: usize, err: *i32) ?*Url;
|
||||
pub extern "c" fn url_free(url: *Url) void;
|
||||
pub extern "c" fn url_can_parse(ptr: [*]const u8, len: usize) bool;
|
||||
pub extern "c" fn url_can_parse_with_base(base_ptr: [*]const u8, base_len: usize, ptr: [*]const u8, len: usize) bool;
|
||||
pub extern "c" fn url_to_string(url: *const Url, out_ptr: *[*]const u8, out_len: *usize) void;
|
||||
pub extern "c" fn url_set_host(url: *Url, ptr: [*]const u8, len: usize) i32;
|
||||
pub extern "c" fn url_get_host(url: *const Url, out_ptr: *[*]const u8, out_len: *usize) void;
|
||||
/// This function allocates on Rust-side.
|
||||
pub extern "c" fn url_get_origin(url: *const Url) OwnedString;
|
||||
pub extern "c" fn free_owned_string(owned: OwnedString) void;
|
||||
pub extern "c" fn url_set_port(url: *Url, port: u16) i32;
|
||||
|
||||
extern "c" fn url_get_port(url: *const Url) i32;
|
||||
pub inline fn urlGetPort(url: *const Url) ?u16 {
|
||||
const result = url_get_port(url);
|
||||
if (result < 0) return null;
|
||||
return @intCast(result);
|
||||
}
|
||||
Reference in New Issue
Block a user