Ada 2.8.0
Fast spec-compliant URL parser
Loading...
Searching...
No Matches
url-setters.cpp
Go to the documentation of this file.
1
5#include "ada.h"
6#include "ada/helpers.h"
7
8#include <optional>
9#include <string>
10
11namespace ada {
12
13template <bool override_hostname>
14bool url::set_host_or_hostname(const std::string_view input) {
15 if (has_opaque_path) {
16 return false;
17 }
18
19 std::optional<std::string> previous_host = host;
20 std::optional<uint16_t> previous_port = port;
21
22 size_t host_end_pos = input.find('#');
23 std::string _host(input.data(), host_end_pos != std::string_view::npos
24 ? host_end_pos
25 : input.size());
26 helpers::remove_ascii_tab_or_newline(_host);
27 std::string_view new_host(_host);
28
29 // If url's scheme is "file", then set state to file host state, instead of
30 // host state.
31 if (type != ada::scheme::type::FILE) {
32 std::string_view host_view(_host.data(), _host.length());
33 auto [location, found_colon] =
34 helpers::get_host_delimiter_location(is_special(), host_view);
35
36 // Otherwise, if c is U+003A (:) and insideBrackets is false, then:
37 // Note: the 'found_colon' value is true if and only if a colon was
38 // encountered while not inside brackets.
39 if (found_colon) {
40 if (override_hostname) {
41 return false;
42 }
43 std::string_view buffer = new_host.substr(location + 1);
44 if (!buffer.empty()) {
45 set_port(buffer);
46 }
47 }
48 // If url is special and host_view is the empty string, validation error,
49 // return failure. Otherwise, if state override is given, host_view is the
50 // empty string, and either url includes credentials or url's port is
51 // non-null, return.
52 else if (host_view.empty() &&
53 (is_special() || has_credentials() || port.has_value())) {
54 return false;
55 }
56
57 // Let host be the result of host parsing host_view with url is not special.
58 if (host_view.empty() && !is_special()) {
59 host = "";
60 return true;
61 }
62
63 bool succeeded = parse_host(host_view);
64 if (!succeeded) {
65 host = previous_host;
66 update_base_port(previous_port);
67 }
68 return succeeded;
69 }
70
71 size_t location = new_host.find_first_of("/\\?");
72 if (location != std::string_view::npos) {
73 new_host.remove_suffix(new_host.length() - location);
74 }
75
76 if (new_host.empty()) {
77 // Set url's host to the empty string.
78 host = "";
79 } else {
80 // Let host be the result of host parsing buffer with url is not special.
81 if (!parse_host(new_host)) {
82 host = previous_host;
83 update_base_port(previous_port);
84 return false;
85 }
86
87 // If host is "localhost", then set host to the empty string.
88 if (host.has_value() && host.value() == "localhost") {
89 host = "";
90 }
91 }
92 return true;
93}
94
95bool url::set_host(const std::string_view input) {
96 return set_host_or_hostname<false>(input);
97}
98
99bool url::set_hostname(const std::string_view input) {
100 return set_host_or_hostname<true>(input);
101}
102
103bool url::set_username(const std::string_view input) {
104 if (cannot_have_credentials_or_port()) {
105 return false;
106 }
107 username = ada::unicode::percent_encode(
109 return true;
110}
111
112bool url::set_password(const std::string_view input) {
113 if (cannot_have_credentials_or_port()) {
114 return false;
115 }
116 password = ada::unicode::percent_encode(
118 return true;
119}
120
121bool url::set_port(const std::string_view input) {
122 if (cannot_have_credentials_or_port()) {
123 return false;
124 }
125 std::string trimmed(input);
126 helpers::remove_ascii_tab_or_newline(trimmed);
127 if (trimmed.empty()) {
128 port = std::nullopt;
129 return true;
130 }
131 // Input should not start with control characters.
132 if (ada::unicode::is_c0_control_or_space(trimmed.front())) {
133 return false;
134 }
135 // Input should contain at least one ascii digit.
136 if (input.find_first_of("0123456789") == std::string_view::npos) {
137 return false;
138 }
139
140 // Revert changes if parse_port fails.
141 std::optional<uint16_t> previous_port = port;
142 parse_port(trimmed);
143 if (is_valid) {
144 return true;
145 }
146 port = previous_port;
147 is_valid = true;
148 return false;
149}
150
151void url::set_hash(const std::string_view input) {
152 if (input.empty()) {
153 hash = std::nullopt;
154 helpers::strip_trailing_spaces_from_opaque_path(*this);
155 return;
156 }
157
158 std::string new_value;
159 new_value = input[0] == '#' ? input.substr(1) : input;
160 helpers::remove_ascii_tab_or_newline(new_value);
161 hash = unicode::percent_encode(new_value,
163}
164
165void url::set_search(const std::string_view input) {
166 if (input.empty()) {
167 query = std::nullopt;
168 helpers::strip_trailing_spaces_from_opaque_path(*this);
169 return;
170 }
171
172 std::string new_value;
173 new_value = input[0] == '?' ? input.substr(1) : input;
174 helpers::remove_ascii_tab_or_newline(new_value);
175
176 auto query_percent_encode_set =
179
180 query = ada::unicode::percent_encode(std::string_view(new_value),
181 query_percent_encode_set);
182}
183
184bool url::set_pathname(const std::string_view input) {
185 if (has_opaque_path) {
186 return false;
187 }
188 path = "";
189 parse_path(input);
190 return true;
191}
192
193bool url::set_protocol(const std::string_view input) {
194 std::string view(input);
195 helpers::remove_ascii_tab_or_newline(view);
196 if (view.empty()) {
197 return true;
198 }
199
200 // Schemes should start with alpha values.
201 if (!checkers::is_alpha(view[0])) {
202 return false;
203 }
204
205 view.append(":");
206
207 std::string::iterator pointer =
208 std::find_if_not(view.begin(), view.end(), unicode::is_alnum_plus);
209
210 if (pointer != view.end() && *pointer == ':') {
211 return parse_scheme<true>(
212 std::string_view(view.data(), pointer - view.begin()));
213 }
214 return false;
215}
216
217bool url::set_href(const std::string_view input) {
219
220 if (out) {
221 username = out->username;
222 password = out->password;
223 host = out->host;
224 port = out->port;
225 path = out->path;
226 query = out->query;
227 hash = out->hash;
228 type = out->type;
229 non_special_scheme = out->non_special_scheme;
230 has_opaque_path = out->has_opaque_path;
231 }
232
233 return out.has_value();
234}
235
236} // namespace ada
Includes all definitions for Ada.
Definitions for helper functions used within Ada.
constexpr uint8_t QUERY_PERCENT_ENCODE[32]
constexpr uint8_t SPECIAL_QUERY_PERCENT_ENCODE[32]
constexpr uint8_t USERINFO_PERCENT_ENCODE[32]
constexpr uint8_t FRAGMENT_PERCENT_ENCODE[32]
constexpr bool is_alpha(char x) noexcept
Definition ada_idna.h:13
tl::expected< result_type, ada::errors > result
ada_warn_unused ada::result< result_type > parse(std::string_view input, const result_type *base_url=nullptr)
ada_really_inline bool is_special() const noexcept
bool is_valid
Definition url_base.h:50
bool has_opaque_path
Definition url_base.h:55
void set_hash(std::string_view input)
bool set_hostname(std::string_view input)
bool set_host(std::string_view input)
ada_really_inline bool has_credentials() const noexcept
Definition url-inl.h:19
bool set_password(std::string_view input)
void set_search(std::string_view input)
bool set_href(std::string_view input)
bool set_username(std::string_view input)
bool set_pathname(std::string_view input)
bool set_protocol(std::string_view input)
bool set_port(std::string_view input)