Line data Source code
1 : // Copyright (c) 2011-2024 Made to Order Software Corp. All Rights Reserved
2 : //
3 : // https://snapwebsites.org/project/edhttp
4 : // contact@m2osw.com
5 : //
6 : // This program is free software: you can redistribute it and/or modify
7 : // it under the terms of the GNU General Public License as published by
8 : // the Free Software Foundation, either version 3 of the License, or
9 : // (at your option) any later version.
10 : //
11 : // This program is distributed in the hope that it will be useful,
12 : // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : // GNU General Public License for more details.
15 : //
16 : // You should have received a copy of the GNU General Public License
17 : // along with this program. If not, see <https://www.gnu.org/licenses/>.
18 :
19 : /** \file
20 : * \brief Verify the uri class.
21 : *
22 : * This file implements tests to verify that the uri class functions.
23 : */
24 :
25 : // edhttp
26 : //
27 : #include <edhttp/uri.h>
28 :
29 : #include <edhttp/exception.h>
30 :
31 :
32 : // self
33 : //
34 : #include "catch_main.h"
35 :
36 :
37 : // snapdev
38 : //
39 : #include <snapdev/tokenize_string.h>
40 :
41 :
42 : // snaplogger
43 : //
44 : #include <snaplogger/message.h>
45 :
46 :
47 : // C
48 : //
49 : #include <string.h>
50 :
51 :
52 :
53 7 : CATCH_TEST_CASE("uri", "[domain]")
54 : {
55 7 : CATCH_START_SECTION("uri: verify already canonicalized URI")
56 : {
57 3 : edhttp::uri uri("http://snap.website/");
58 :
59 1 : CATCH_REQUIRE(uri.domain() == "snap");
60 1 : CATCH_REQUIRE(uri.top_level_domain() == ".website");
61 1 : }
62 7 : CATCH_END_SECTION()
63 :
64 7 : CATCH_START_SECTION("uri: verify URI without '/' after domain name")
65 : {
66 3 : edhttp::uri uri("http://snap.website");
67 :
68 1 : CATCH_REQUIRE(uri.domain() == "snap");
69 1 : CATCH_REQUIRE(uri.top_level_domain() == ".website");
70 1 : CATCH_REQUIRE(uri.get_original_uri() == "http://snap.website");
71 1 : CATCH_REQUIRE(uri.get_uri() == "http://snap.website/");
72 1 : }
73 7 : CATCH_END_SECTION()
74 :
75 7 : CATCH_START_SECTION("uri: verify URI with two slashes")
76 : {
77 3 : edhttp::uri uri("http://snap.website//");
78 :
79 1 : CATCH_REQUIRE(uri.domain() == "snap");
80 1 : CATCH_REQUIRE(uri.top_level_domain() == ".website");
81 1 : CATCH_REQUIRE(uri.get_original_uri() == "http://snap.website//");
82 1 : CATCH_REQUIRE(uri.get_uri() == "http://snap.website/");
83 1 : }
84 7 : CATCH_END_SECTION()
85 :
86 7 : CATCH_START_SECTION("uri: verify URI with multiple slashes and a path")
87 : {
88 3 : edhttp::uri uri("http://snap.website///and/a/path");
89 :
90 1 : CATCH_REQUIRE(uri.domain() == "snap");
91 1 : CATCH_REQUIRE(uri.top_level_domain() == ".website");
92 1 : CATCH_REQUIRE(uri.path() == "and/a/path");
93 1 : CATCH_REQUIRE(uri.get_original_uri() == "http://snap.website///and/a/path");
94 1 : CATCH_REQUIRE(uri.get_uri() == "http://snap.website/and/a/path");
95 1 : }
96 7 : CATCH_END_SECTION()
97 :
98 7 : CATCH_START_SECTION("uri: verify credentials")
99 : {
100 1 : char const * ptr = nullptr;
101 :
102 : {
103 3 : edhttp::uri uri("http://explicit:credentials@snapwebsites.org:8888/and-port");
104 :
105 1 : CATCH_REQUIRE(uri.domain() == "snapwebsites");
106 1 : CATCH_REQUIRE(uri.top_level_domain() == ".org");
107 1 : CATCH_REQUIRE(uri.path() == "and-port");
108 1 : CATCH_REQUIRE(uri.get_username() == "explicit");
109 1 : CATCH_REQUIRE(uri.get_password() == "credentials");
110 :
111 : // check the string buffer is still saying "credentials
112 : //
113 1 : std::string const & p(uri.get_password());
114 1 : ptr = reinterpret_cast<char const *>(p.data());
115 1 : CATCH_REQUIRE(strncmp(ptr, "credentials", 11) == 0);
116 1 : }
117 :
118 : // after destruction, the buffer should not have the password anymore
119 : //
120 : // avoid that test when the sanitizer is active, it will detect that
121 : // we're accessing memory that was deallocated
122 : //
123 : #ifndef __SANITIZE_ADDRESS__
124 : CATCH_REQUIRE(strncmp(ptr, "credentials", 11) != 0);
125 : #endif
126 : }
127 7 : CATCH_END_SECTION()
128 :
129 7 : CATCH_START_SECTION("uri: use set_uri() to test valid URIs")
130 : {
131 : struct uri_test
132 : {
133 : char const * f_original_uri = nullptr; // set_uri() with original
134 : char const * f_uri = nullptr; // canonicalized
135 : char const * f_redacted_uri = nullptr; // canonicalized & password redacted
136 : char const * f_hash_bang_uri = nullptr; // canonicalized & keep hash bang if defined
137 : char const * f_website_uri = nullptr; // scheme + full domain
138 : char const * f_website_uri_with_port = nullptr; // scheme + full domain + port
139 : char const * f_domain = nullptr; // domain name only (no sub-domain or TLD)
140 : char const * f_full_domain = nullptr; // full domain
141 : char const * f_top_level_domain = nullptr; // the TLD of the domain
142 : char const * f_sub_domains = nullptr; // complete list of sub-domains
143 : char const * f_username = nullptr; // the user name
144 : char const * f_password = nullptr; // the password
145 : char const * f_scheme = nullptr; // scheme name
146 : char const * f_path = nullptr; // complete path
147 : int f_path_count = 0; // number of segments in the complete path
148 : int f_port = 0; // the expected port
149 : bool f_is_unix = false; // whether the input URI is a Unix path
150 : char const * f_query_string = nullptr; // the query string
151 : char const * f_anchor = nullptr; // the string after the '#"
152 : char const * f_hash_bang_path = nullptr; // path defined after '#!'
153 : };
154 :
155 1 : uri_test uris[] =
156 : {
157 : {
158 : .f_original_uri = "https://me:p1@test.this.domain.net///with///a///path?var=value&other_var=more%20data#hello",
159 : .f_uri = "https://me:p1@test.this.domain.net/with/a/path?other_var=more%20data&var=value#hello",
160 : .f_redacted_uri = "https://me:%2A%2A%2A@test.this.domain.net/with/a/path?other_var=more%20data&var=value#hello",
161 : .f_hash_bang_uri = nullptr,
162 : .f_website_uri = "https://test.this.domain.net/",
163 : .f_website_uri_with_port = "https://test.this.domain.net/",
164 : .f_domain = "domain",
165 : .f_full_domain = "test.this.domain.net",
166 : .f_top_level_domain = ".net",
167 : .f_sub_domains = "test.this",
168 : .f_username = "me",
169 : .f_password = "p1",
170 : .f_scheme = "https",
171 : .f_path = "with/a/path",
172 : .f_path_count = 3,
173 : .f_port = 443,
174 : .f_is_unix = false,
175 : .f_query_string = "other_var=more%20data&var=value",
176 : .f_anchor = "hello",
177 : .f_hash_bang_path = "",
178 : },
179 : {
180 : .f_original_uri = "http://you:p2%5D@sub.test.this.domain.cloud///with///a///path?var=value&other_var=more%20data#!/extra/path",
181 : .f_uri = "http://you:p2%5D@sub.test.this.domain.cloud/with/a/path?other_var=more%20data&var=value",
182 : .f_redacted_uri = "http://you:%2A%2A%2A@sub.test.this.domain.cloud/with/a/path?other_var=more%20data&var=value",
183 : .f_hash_bang_uri = "http://you:p2%5D@sub.test.this.domain.cloud/with/a/path?other_var=more%20data&var=value#!/extra/path",
184 : .f_website_uri = "http://sub.test.this.domain.cloud/",
185 : .f_website_uri_with_port = "http://sub.test.this.domain.cloud/",
186 : .f_domain = "domain",
187 : .f_full_domain = "sub.test.this.domain.cloud",
188 : .f_top_level_domain = ".cloud",
189 : .f_sub_domains = "sub.test.this",
190 : .f_username = "you",
191 : .f_password = "p2]",
192 : .f_scheme = "http",
193 : .f_path = "with/a/path",
194 : .f_path_count = 3,
195 : .f_port = 80,
196 : .f_is_unix = false,
197 : .f_query_string = "other_var=more%20data&var=value",
198 : .f_anchor = "",
199 : .f_hash_bang_path = "extra/path",
200 : },
201 : {
202 : .f_original_uri = "ftp://you:p2%5B@sub.test.this.domain.cloud///with///a///path?var=value&other_var=more%20data#hello",
203 : .f_uri = "ftp://you:p2%5B@sub.test.this.domain.cloud/with/a/path?other_var=more%20data&var=value#hello",
204 : .f_redacted_uri = "ftp://you:%2A%2A%2A@sub.test.this.domain.cloud/with/a/path?other_var=more%20data&var=value#hello",
205 : .f_hash_bang_uri = nullptr,
206 : .f_website_uri = "ftp://sub.test.this.domain.cloud/",
207 : .f_website_uri_with_port = "ftp://sub.test.this.domain.cloud/",
208 : .f_domain = "domain",
209 : .f_full_domain = "sub.test.this.domain.cloud",
210 : .f_top_level_domain = ".cloud",
211 : .f_sub_domains = "sub.test.this",
212 : .f_username = "you",
213 : .f_password = "p2[",
214 : .f_scheme = "ftp",
215 : .f_path = "with/a/path",
216 : .f_path_count = 3,
217 : .f_port = 21,
218 : .f_is_unix = false,
219 : .f_query_string = "other_var=more%20data&var=value",
220 : .f_anchor = "hello",
221 : .f_hash_bang_path = "",
222 : },
223 : {
224 : .f_original_uri = "ssh://agent:secret@console.example.website///packages?PATH=/usr/bin",
225 : .f_uri = "ssh://agent:secret@console.example.website/packages?PATH=%2Fusr%2Fbin",
226 : .f_redacted_uri = "ssh://agent:%2A%2A%2A@console.example.website/packages?PATH=%2Fusr%2Fbin",
227 : .f_hash_bang_uri = nullptr,
228 : .f_website_uri = "ssh://console.example.website/",
229 : .f_website_uri_with_port = "ssh://console.example.website/",
230 : .f_domain = "example",
231 : .f_full_domain = "console.example.website",
232 : .f_top_level_domain = ".website",
233 : .f_sub_domains = "console",
234 : .f_username = "agent",
235 : .f_password = "secret",
236 : .f_scheme = "ssh",
237 : .f_path = "packages",
238 : .f_path_count = 1,
239 : .f_port = 22,
240 : .f_is_unix = false,
241 : .f_query_string = "PATH=/usr/bin",
242 : .f_anchor = "",
243 : .f_hash_bang_path = "",
244 : },
245 : {
246 : .f_original_uri = "telnet://user:password1@shell.example.org///packages?PATH=/usr/bin%3A/usr/sbin&=no-name",
247 : .f_uri = "telnet://user:password1@shell.example.org/packages?%2A=no-name&PATH=%2Fusr%2Fbin%3A%2Fusr%2Fsbin",
248 : .f_redacted_uri = "telnet://user:%2A%2A%2A@shell.example.org/packages?%2A=no-name&PATH=%2Fusr%2Fbin%3A%2Fusr%2Fsbin",
249 : .f_hash_bang_uri = nullptr,
250 : .f_website_uri = "telnet://shell.example.org/",
251 : .f_website_uri_with_port = "telnet://shell.example.org/",
252 : .f_domain = "example",
253 : .f_full_domain = "shell.example.org",
254 : .f_top_level_domain = ".org",
255 : .f_sub_domains = "shell",
256 : .f_username = "user",
257 : .f_password = "password1",
258 : .f_scheme = "telnet",
259 : .f_path = "packages",
260 : .f_path_count = 1,
261 : .f_port = 23,
262 : .f_is_unix = false,
263 : .f_query_string = "%2A=no-name&PATH=/usr/bin:/usr/sbin",
264 : .f_anchor = "",
265 : .f_hash_bang_path = "",
266 : },
267 : {
268 : .f_original_uri = "smtp://user:password1@mail.abc123.info///var/mail-boxes/user?PATH=/usr/bin%3A/usr/sbin#latest",
269 : .f_uri = "smtp://user:password1@mail.abc123.info/var/mail-boxes/user?PATH=%2Fusr%2Fbin%3A%2Fusr%2Fsbin#latest",
270 : .f_redacted_uri = "smtp://user:%2A%2A%2A@mail.abc123.info/var/mail-boxes/user?PATH=%2Fusr%2Fbin%3A%2Fusr%2Fsbin#latest",
271 : .f_hash_bang_uri = nullptr,
272 : .f_website_uri = "smtp://mail.abc123.info/",
273 : .f_website_uri_with_port = "smtp://mail.abc123.info/",
274 : .f_domain = "abc123",
275 : .f_full_domain = "mail.abc123.info",
276 : .f_top_level_domain = ".info",
277 : .f_sub_domains = "mail",
278 : .f_username = "user",
279 : .f_password = "password1",
280 : .f_scheme = "smtp",
281 : .f_path = "var/mail-boxes/user",
282 : .f_path_count = 3,
283 : .f_port = 25,
284 : .f_is_unix = false,
285 : .f_query_string = "PATH=/usr/bin:/usr/sbin",
286 : .f_anchor = "latest",
287 : .f_hash_bang_path = "",
288 : },
289 : {
290 : .f_original_uri = "gopher://gofer:yes%3Ano@gopher.wall.alexis.museum///gopher",
291 : .f_uri = "gopher://gofer:yes%3Ano@gopher.wall.alexis.museum/gopher",
292 : .f_redacted_uri = "gopher://gofer:%2A%2A%2A@gopher.wall.alexis.museum/gopher",
293 : .f_hash_bang_uri = nullptr,
294 : .f_website_uri = "gopher://gopher.wall.alexis.museum/",
295 : .f_website_uri_with_port = "gopher://gopher.wall.alexis.museum/",
296 : .f_domain = "alexis",
297 : .f_full_domain = "gopher.wall.alexis.museum",
298 : .f_top_level_domain = ".museum",
299 : .f_sub_domains = "gopher.wall",
300 : .f_username = "gofer",
301 : .f_password = "yes:no",
302 : .f_scheme = "gopher",
303 : .f_path = "gopher",
304 : .f_path_count = 1,
305 : .f_port = 70,
306 : .f_is_unix = false,
307 : .f_query_string = "",
308 : .f_anchor = "",
309 : .f_hash_bang_path = "",
310 : },
311 : {
312 : .f_original_uri = "time://realtime.atomic.cl/utc?leap-seconds=separate",
313 : .f_uri = "time://realtime.atomic.cl/utc?leap-seconds=separate",
314 : .f_redacted_uri = "time://realtime.atomic.cl/utc?leap-seconds=separate",
315 : .f_hash_bang_uri = nullptr,
316 : .f_website_uri = "time://realtime.atomic.cl/",
317 : .f_website_uri_with_port = "time://realtime.atomic.cl/",
318 : .f_domain = "atomic",
319 : .f_full_domain = "realtime.atomic.cl",
320 : .f_top_level_domain = ".cl",
321 : .f_sub_domains = "realtime",
322 : .f_username = "",
323 : .f_password = "",
324 : .f_scheme = "time",
325 : .f_path = "utc",
326 : .f_path_count = 1,
327 : .f_port = 37,
328 : .f_is_unix = false,
329 : .f_query_string = "leap-second=separate",
330 : .f_anchor = "",
331 : .f_hash_bang_path = "",
332 : },
333 : {
334 : .f_original_uri = "snapwebsites://@parlement.co.uk/////folder/electric/bill?line%5B3%5D=129.07#quantity",
335 : .f_uri = "snapwebsites://parlement.co.uk:80/folder/electric/bill?line%5B3%5D=129.07#quantity",
336 : .f_redacted_uri = "snapwebsites://parlement.co.uk:80/folder/electric/bill?line%5B3%5D=129.07#quantity",
337 : .f_hash_bang_uri = nullptr,
338 : .f_website_uri = "snapwebsites://parlement.co.uk/",
339 : .f_website_uri_with_port = "snapwebsites://parlement.co.uk:80/",
340 : .f_domain = "parlement",
341 : .f_full_domain = "parlement.co.uk",
342 : .f_top_level_domain = ".co.uk",
343 : .f_sub_domains = "",
344 : .f_username = "",
345 : .f_password = "",
346 : .f_scheme = "snapwebsites",
347 : .f_path = "folder/electric/bill",
348 : .f_path_count = 3,
349 : .f_port = 80,
350 : .f_is_unix = false,
351 : .f_query_string = "line[3]=129.07",
352 : .f_anchor = "quantity",
353 : .f_hash_bang_path = "",
354 : },
355 : };
356 :
357 : // query string handling
358 : //void set_query_option(std::string const & name, std::string const & value);
359 : //void unset_query_option(std::string const & name);
360 : //void set_query_string(std::string const & uri_query_string);
361 : //std::string query_string() const;
362 : //bool has_query_option(std::string const & name) const;
363 : //void clear_query_options();
364 : //std::string query_option(std::string const & name) const;
365 : //int query_option_count() const;
366 : //std::string query_option(int part, std::string & name) const;
367 : //uri_options_t const & query_string_list() const;
368 :
369 1 : int part(0);
370 10 : for(auto t : uris)
371 : {
372 27 : edhttp::uri uri(t.f_original_uri);
373 :
374 : // sub-domains
375 : //
376 9 : std::list<std::string> sub_domains;
377 9 : snapdev::tokenize_string(sub_domains, t.f_sub_domains, {"."}, true);
378 :
379 : // path segments
380 : //
381 9 : std::list<std::string> segments;
382 9 : snapdev::tokenize_string(segments, t.f_path, {"/"}, true);
383 :
384 : // verify each value for each original
385 : //
386 9 : CATCH_REQUIRE(uri.get_original_uri() == t.f_original_uri);
387 9 : CATCH_REQUIRE(uri.get_uri() == t.f_uri);
388 9 : CATCH_REQUIRE(uri.get_uri(false, "***") == t.f_redacted_uri);
389 9 : if(t.f_hash_bang_uri != nullptr)
390 : {
391 1 : CATCH_REQUIRE(uri.get_uri(true) == t.f_hash_bang_uri);
392 : }
393 9 : CATCH_REQUIRE(uri.get_website_uri() == t.f_website_uri);
394 9 : CATCH_REQUIRE(uri.get_website_uri(true) == t.f_website_uri_with_port);
395 9 : CATCH_REQUIRE(uri.domain() == t.f_domain);
396 9 : CATCH_REQUIRE(uri.sub_domains() == t.f_sub_domains);
397 9 : CATCH_REQUIRE(uri.sub_domain_count() == static_cast<int>(sub_domains.size()));
398 9 : CATCH_REQUIRE(uri.full_domain() == t.f_full_domain);
399 9 : CATCH_REQUIRE(uri.top_level_domain() == t.f_top_level_domain);
400 9 : CATCH_REQUIRE(uri.get_username() == t.f_username);
401 9 : CATCH_REQUIRE(uri.get_password() == t.f_password);
402 9 : CATCH_REQUIRE(uri.scheme() == t.f_scheme);
403 9 : CATCH_REQUIRE(uri.path() == t.f_path);
404 9 : CATCH_REQUIRE(uri.path_count() == t.f_path_count);
405 9 : CATCH_REQUIRE(uri.get_port() == t.f_port);
406 9 : CATCH_REQUIRE(uri.is_unix() == t.f_is_unix);
407 9 : CATCH_REQUIRE(uri.get_str_port() == std::to_string(t.f_port));
408 9 : CATCH_REQUIRE(uri.anchor() == t.f_anchor);
409 9 : CATCH_REQUIRE(uri.hash_bang_path() == t.f_hash_bang_path);
410 :
411 9 : advgetopt::string_list_t const & sub_domain_list(uri.sub_domains_list());
412 9 : CATCH_REQUIRE(sub_domain_list.size() == sub_domains.size());
413 9 : auto sub_domain_it(sub_domain_list.begin());
414 9 : part = 0;
415 23 : for(auto const & s : sub_domains)
416 : {
417 14 : CATCH_REQUIRE(uri.sub_domain(part) == s);
418 14 : CATCH_REQUIRE(*sub_domain_it == s);
419 14 : CATCH_REQUIRE(uri.get_part("sub-domain", part) == s);
420 14 : ++sub_domain_it;
421 14 : ++part;
422 : }
423 :
424 9 : advgetopt::string_list_t const & path_list(uri.path_list());
425 9 : CATCH_REQUIRE(path_list.size() == segments.size());
426 9 : auto path_it(path_list.begin());
427 9 : part = 0;
428 28 : for(auto const & s : segments)
429 : {
430 19 : CATCH_REQUIRE(uri.path_folder_name(part) == s);
431 19 : CATCH_REQUIRE(*path_it == s);
432 19 : CATCH_REQUIRE(uri.get_part("path", part) == s);
433 19 : ++path_it;
434 19 : ++part;
435 : }
436 :
437 : // try again with the get_part() function
438 : //
439 9 : CATCH_REQUIRE(uri.get_part("anchor") == t.f_anchor);
440 9 : CATCH_REQUIRE(uri.get_part("domain") == t.f_domain);
441 9 : CATCH_REQUIRE(uri.get_part("full-domain") == t.f_full_domain);
442 9 : CATCH_REQUIRE(uri.get_part("is-unix") == (t.f_is_unix ? "unix" : "inet"));
443 9 : CATCH_REQUIRE(uri.get_part("original") == t.f_original_uri);
444 9 : CATCH_REQUIRE(uri.get_part("password") == t.f_password);
445 9 : CATCH_REQUIRE(uri.get_part("path-count") == std::to_string(t.f_path_count));
446 9 : CATCH_REQUIRE(uri.get_part("port") == std::to_string(t.f_port));
447 9 : CATCH_REQUIRE(uri.get_part("scheme") == t.f_scheme);
448 9 : CATCH_REQUIRE(uri.get_part("tld") == t.f_top_level_domain);
449 9 : CATCH_REQUIRE(uri.get_part("top-level-domain") == t.f_top_level_domain);
450 9 : CATCH_REQUIRE(uri.get_part("uri") == t.f_uri);
451 9 : CATCH_REQUIRE(uri.get_part("username") == t.f_username);
452 :
453 : // unknown parts are accepted and the function returns an empty string
454 : //
455 9 : CATCH_REQUIRE(uri.get_part("anything-else-is-empty") == std::string());
456 9 : }
457 : }
458 7 : CATCH_END_SECTION()
459 :
460 7 : CATCH_START_SECTION("uri: use set_uri() to test invalid URIs")
461 : {
462 : struct uri_test
463 : {
464 : char const * f_uri = nullptr; // some invalid URI
465 : char const * f_error_message = nullptr; // the expected error message
466 : };
467 :
468 1 : uri_test uris[] =
469 : {
470 : {
471 : .f_uri = "https",
472 : .f_error_message = "scheme not followed by \"://\".",
473 : },
474 : {
475 : .f_uri = "https://@m2osw.com:80:80/",
476 : .f_error_message = "more than one ':' in the domain name segment (after the '@') [1].",
477 : },
478 : {
479 : .f_uri = "https:///this.domain.net///with///a///path?var=value&other_var=more%20data#hello",
480 : .f_error_message = "a domain name is required.",
481 : },
482 : {
483 : .f_uri = "https://top:secret:password@m2osw.com:80:80/",
484 : .f_error_message = "more than one ':' in the login info segment (before the '@').",
485 : },
486 : {
487 : .f_uri = "https://top:secret@password@m2osw.com:80:80/",
488 : .f_error_message = "more than one '@' character found.",
489 : },
490 : {
491 : .f_uri = "https://my:password@m2osw.com:80:80/",
492 : .f_error_message = "more than one ':' in the domain name segment (after the '@') [2].",
493 : },
494 : {
495 : .f_uri = "https://empty:port@m2osw.com:/",
496 : .f_error_message = "port cannot be an empty string.",
497 : },
498 : {
499 : .f_uri = "https://empty:port@m2osw.com:http/",
500 : .f_error_message = "port must be a valid decimal number ('http' unexpected).",
501 : },
502 : {
503 : .f_uri = "https://big:port@m2osw.com:65536/",
504 : .f_error_message = "port must be between 0 and 65536.",
505 : },
506 : {
507 : .f_uri = "https://no:domain@:65535/no/domain",
508 : .f_error_message = "a domain name is required.",
509 : },
510 : {
511 : .f_uri = "https://empty:@password.m2osw.com:1001/",
512 : .f_error_message = "username and password must both be defined (or define neither).",
513 : },
514 : {
515 : .f_uri = "https://:empty@password.m2osw.com:1001/",
516 : .f_error_message = "username and password must both be defined (or define neither).",
517 : },
518 : {
519 : .f_uri = "https://utc.m2osw.clock/",
520 : .f_error_message = "could not verify domain name \"utc.m2osw.clock\".",
521 : },
522 : {
523 : .f_uri = "https://utc.m2osw.co/?a=1&a=3",
524 : .f_error_message = "query string \"a\" found more than once.",
525 : },
526 : {
527 : .f_uri = "https://parent.m2osw.co/..",
528 : .f_error_message = "found \"..\" at the beginning of your path.",
529 : },
530 : {
531 : .f_uri = "https://parent.m2osw.co/../none",
532 : .f_error_message = "found \"..\" at the beginning of your path.",
533 : },
534 : {
535 : .f_uri = "https://parent.m2osw.co/./../sub-domain",
536 : .f_error_message = "found \"..\" at the beginning of your path.",
537 : },
538 : };
539 :
540 18 : for(auto t : uris)
541 : {
542 17 : edhttp::uri uri;
543 :
544 17 : CATCH_REQUIRE_FALSE(uri.set_uri(t.f_uri));
545 17 : CATCH_REQUIRE(uri.get_last_error_message() == t.f_error_message);
546 17 : uri.clear_last_error_message();
547 17 : CATCH_REQUIRE(uri.get_last_error_message().empty());
548 17 : }
549 : }
550 7 : CATCH_END_SECTION()
551 7 : }
552 :
553 :
554 1 : CATCH_TEST_CASE("uri_error", "[domain][error]")
555 : {
556 1 : CATCH_START_SECTION("uri_error: create uri with an invalid string")
557 : {
558 5 : CATCH_REQUIRE_THROWS_MATCHES(
559 : edhttp::uri("bad_URI")
560 : , edhttp::invalid_uri
561 : , Catch::Matchers::ExceptionMessage(
562 : "edhttp_exception: URI \"bad_URI\" is considered invalid."));
563 : }
564 1 : CATCH_END_SECTION()
565 1 : }
566 :
567 :
568 : // vim: ts=4 sw=4 et
|