Skip to content
File

Blob: src/workerd/api/node/url.c++

2.7 KB
1// Copyright (c) 2017-2022 Cloudflare, Inc.
2// Licensed under the Apache 2.0 license found in the LICENSE file or at:
3// https://opensource.org/licenses/Apache-2.0
4#include "url.h"
5 
6#include "ada.h"
7 
8#include <workerd/rust/net/lib.rs.h>
9 
10#include <kj-rs/kj-rs.h>
11 
12using namespace kj_rs;
13 
14namespace workerd::api::node {
15 
16namespace {
17 
18// Implementation is used by `domainToASCII` and `domainToUnicode`
19kj::Maybe<std::string> GetHostName(kj::StringPtr domain) {
20 if (domain.size() == 0) {
21 return kj::none;
22 }
23 
24 // It is important to have an initial value that contains a special scheme.
25 // Since it will change the implementation of `set_hostname` according to URL
26 // spec.
27 auto out = ada::parse<ada::url>("ws://x");
28 JSG_REQUIRE(out.has_value(), Error, "URL parsing failed"_kj);
29 if (!out->set_hostname({domain.begin(), domain.size()})) {
30 return kj::none;
31 }
32 return out->get_hostname();
33}
34 
35} // namespace
36 
37jsg::JsString UrlUtil::domainToASCII(jsg::Lock& js, kj::String domain) {
38 KJ_IF_SOME(hostname, GetHostName(domain)) {
39 return js.str(kj::StringPtr(hostname.data(), hostname.size()));
40 }
41 return js.str(""_kj);
42}
43 
44jsg::JsString UrlUtil::domainToUnicode(jsg::Lock& js, kj::String domain) {
45 KJ_IF_SOME(hostname, GetHostName(domain)) {
46 auto result = ada::idna::to_unicode(hostname);
47 return js.str(kj::StringPtr(result.data(), result.size()));
48 }
49 
50 return js.str(""_kj);
51}
52 
53jsg::JsString UrlUtil::toASCII(jsg::Lock& js, kj::String url) {
54 auto out = ada::idna::to_ascii({url.begin(), url.size()});
55 return js.str(kj::StringPtr(out.data(), out.size()));
56}
57 
58jsg::JsString UrlUtil::format(
59 jsg::Lock& js, kj::String input, bool hash, bool unicode, bool search, bool auth) {
60 // We deliberately use `ada::url` rather than `ada::url_aggregator` because
61 // ada::url is faster on setting fields. Since we don't need individual components
62 // there is no need to use url_aggregator.
63 auto out = ada::parse<ada::url>({input.begin(), input.size()}, nullptr);
64 
65 JSG_REQUIRE(out.has_value(), Error, "Failed to parse URL"_kj);
66 
67 if (!hash) {
68 out->hash = std::nullopt;
69 }
70 
71 if (unicode && out->has_hostname()) {
72 out->host = ada::idna::to_unicode(out->get_hostname());
73 }
74 
75 if (!search) {
76 out->query = std::nullopt;
77 }
78 
79 if (!auth) {
80 out->username = "";
81 out->password = "";
82 }
83 
84 auto href = out->get_href();
85 return js.str(kj::StringPtr(href.data(), href.size()));
86}
87 
88// We return empty string if the input is not a valid IP address.
89jsg::JsString UrlUtil::canonicalizeIp(jsg::Lock& js, kj::String input) {
90 auto out = rust::net::canonicalize_ip({input.begin(), input.size()});
91 return js.str(kj::StringPtr(out.c_str(), out.size()));
92}
93 
94} // namespace workerd::api::node