Skip to content

Commit

Permalink
LibWeb: Implement URL.parse
Browse files Browse the repository at this point in the history
This was an addition to the URL spec, see:

whatwg/url@58acb0
  • Loading branch information
shannonbooth committed May 13, 2024
1 parent 9e62e34 commit 7c935d6
Show file tree
Hide file tree
Showing 5 changed files with 123 additions and 10 deletions.
81 changes: 81 additions & 0 deletions Tests/LibWeb/Text/expected/URL/url.txt
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,84 @@ port => ''
pathname => '/d:/'
search => ''
hash => ''
=========================================
URL.parse('ftp://serenityos.org:21', undefined)
protocol => 'ftp:'
username => ''
password => ''
host => 'serenityos.org'
hostname => 'serenityos.org'
port => ''
pathname => '/'
search => ''
hash => ''
URL.parse('http://[0:1:0:1:0:1:0:1]', undefined)
protocol => 'http:'
username => ''
password => ''
host => '[0:1:0:1:0:1:0:1]'
hostname => '[0:1:0:1:0:1:0:1]'
port => ''
pathname => '/'
search => ''
hash => ''
URL.parse('http://[1:0:1:0:1:0:1:0]', undefined)
protocol => 'http:'
username => ''
password => ''
host => '[1:0:1:0:1:0:1:0]'
hostname => '[1:0:1:0:1:0:1:0]'
port => ''
pathname => '/'
search => ''
hash => ''
URL.parse('http://[1:1:0:0:1:0:0:0]/', undefined)
protocol => 'http:'
username => ''
password => ''
host => '[1:1:0:0:1::]'
hostname => '[1:1:0:0:1::]'
port => ''
pathname => '/'
search => ''
hash => ''
URL.parse('unknown://serenityos.org:0', undefined)
protocol => 'unknown:'
username => ''
password => ''
host => 'serenityos.org:0'
hostname => 'serenityos.org'
port => '0'
pathname => ''
search => ''
hash => ''
URL.parse('http://serenityos.org/cat?dog#meow"woof', undefined)
protocol => 'http:'
username => ''
password => ''
host => 'serenityos.org'
hostname => 'serenityos.org'
port => ''
pathname => '/cat'
search => '?dog'
hash => '#meow%22woof'
URL.parse('/hello', 'file://friends/')
protocol => 'file:'
username => ''
password => ''
host => 'friends'
hostname => 'friends'
port => ''
pathname => '/hello'
search => ''
hash => ''
URL.parse('//d:/..', 'file:///C:/a/b')
protocol => 'file:'
username => ''
password => ''
host => ''
hostname => ''
port => ''
pathname => '/d:/'
search => ''
hash => ''
32 changes: 22 additions & 10 deletions Tests/LibWeb/Text/input/URL/url.html
Original file line number Diff line number Diff line change
@@ -1,13 +1,7 @@
<script src="../include.js"></script>
<script>
test(() => {
function printURL(input, base) {
if (base === undefined)
println(`new URL('${input}', ${base})`);
else
println(`new URL('${input}', '${base}')`);

const url = new URL(input, base);
function printURL(url) {
println(`protocol => '${url.protocol}'`);
println(`username => '${url.username}'`);
println(`password => '${url.password}'`);
Expand All @@ -19,7 +13,7 @@
println(`hash => '${url.hash}'`);
}

for (url of [
const urls = [
{ input: 'ftp://serenityos.org:21' },
{ input: 'http://[0:1:0:1:0:1:0:1]' },
{ input: 'http://[1:0:1:0:1:0:1:0]' },
Expand All @@ -28,8 +22,26 @@
{ input: 'http://serenityos.org/cat?dog#meow"woof' },
{ input: '/hello', base: 'file://friends/' },
{ input: '//d:/..', base: 'file:///C:/a/b' },
]) {
printURL(url.input, url.base);
];

for (url of urls) {
if (url.base === undefined)
println(`new URL('${url.input}', ${url.base})`);
else
println(`new URL('${url.input}', '${url.base}')`);

printURL(new URL(url.input, url.base));
}

println('=========================================');

for (url of urls) {
if (url.base === undefined)
println(`URL.parse('${url.input}', ${url.base})`);
else
println(`URL.parse('${url.input}', '${url.base}')`);

printURL(URL.parse(url.input, url.base));
}
});
</script>
18 changes: 18 additions & 0 deletions Userland/Libraries/LibWeb/DOMURL/DOMURL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,24 @@ JS::NonnullGCPtr<DOMURL> DOMURL::initialize_a_url(JS::Realm& realm, URL::URL con
return result_url;
}

// https://url.spec.whatwg.org/#dom-url-parse
JS::GCPtr<DOMURL> DOMURL::parse_for_bindings(JS::VM& vm, String const& url, Optional<String> const& base)
{
auto& realm = *vm.current_realm();

// 1. Let parsedURL be the result of running the API URL parser on url with base, if given.
auto parsed_url = parse_api_url(url, base);

// 2. If parsedURL is failure, then return null.
if (!parsed_url.has_value())
return nullptr;

// 3. Let url be a new URL object.
// 4. Initialize url with parsedURL.
// 5. Return url.
return initialize_a_url(realm, parsed_url.value());
}

// https://url.spec.whatwg.org/#dom-url-url
WebIDL::ExceptionOr<JS::NonnullGCPtr<DOMURL>> DOMURL::construct_impl(JS::Realm& realm, String const& url, Optional<String> const& base)
{
Expand Down
1 change: 1 addition & 0 deletions Userland/Libraries/LibWeb/DOMURL/DOMURL.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ class DOMURL : public Bindings::PlatformObject {
static WebIDL::ExceptionOr<String> create_object_url(JS::VM&, JS::NonnullGCPtr<FileAPI::Blob> object);
static WebIDL::ExceptionOr<void> revoke_object_url(JS::VM&, StringView url);

static JS::GCPtr<DOMURL> parse_for_bindings(JS::VM&, String const& url, Optional<String> const& base = {});
static bool can_parse(JS::VM&, String const& url, Optional<String> const& base = {});

WebIDL::ExceptionOr<String> href() const;
Expand Down
1 change: 1 addition & 0 deletions Userland/Libraries/LibWeb/DOMURL/DOMURL.idl
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
interface URL {
constructor(USVString url, optional USVString base);

[ImplementedAs=parse_for_bindings] static DOMURL? parse(USVString url, optional USVString base);
static boolean canParse(USVString url, optional USVString base);

stringifier attribute USVString href;
Expand Down

0 comments on commit 7c935d6

Please sign in to comment.