/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * * SPDX-License-Identifier: curl * ***************************************************************************/ #include "unitcheck.h" #include "urlapi-int.h" #include "curlx/dynbuf.h" static CURLcode test_unit1675(const char *arg) { (void)arg; UNITTEST_BEGIN_SIMPLE /* Test ipv4_normalize */ { struct dynbuf host; int fails = 0; unsigned int i; struct ipv4_test { const char *in; const char *out; }; const struct ipv4_test tests[] = { {"0x.0x.0x.0x", NULL}, /* invalid hex */ {"0x.0x.0x", NULL}, /* invalid hex */ {"0x.0x", NULL}, /* invalid hex */ {"0x", NULL}, /* invalid hex */ {"0", "0.0.0.0"}, {"00", "0.0.0.0"}, {"00000000000", "0.0.0.0"}, {"127.0.0.1", "127.0.0.1"}, {"0177.0.0.1", "127.0.0.1"}, {"00177.0.0.1", "127.0.0.1"}, {"0x7f.0.0.1", "127.0.0.1"}, {"0x07f.0.0.1", "127.0.0.1"}, {"1", "0.0.0.1"}, {"010", "0.0.0.8"}, {"001", "0.0.0.1"}, {"127", "0.0.0.127"}, {"127.1", "127.0.0.1"}, {"127.0.1", "127.0.0.1"}, {"1.16777215", "1.255.255.255"}, {"1.16777216", NULL}, /* overflow */ {"1.1.65535", "1.1.255.255"}, {"1.1.65536", NULL}, /* overflow */ {"0x7f000001", "127.0.0.1"}, {"0x7F000001", "127.0.0.1"}, {"0x7g000001", NULL}, /* bad hex */ {"2130706433", "127.0.0.1"}, {"017700000001", "127.0.0.1"}, {"000000000017700000001", "127.0.0.1"}, {"192.168.0.1", "192.168.0.1"}, {"0300.0250.0000.0001", "192.168.0.1"}, {"0xc0.0xa8.0.1", "192.168.0.1"}, {"0xc0a80001", "192.168.0.1"}, {"3232235521", "192.168.0.1"}, {"4294967294", "255.255.255.254"}, {"4294967295", "255.255.255.255"}, {"037777777777", "255.255.255.255"}, {"0xFFFFFFFF", "255.255.255.255"}, {"0xFFFFFfff", "255.255.255.255"}, {"1.2.3.4.5", NULL}, /* too many parts */ {"256.0.0.1", NULL}, /* overflow */ {"1.256.0.1", NULL}, /* overflow */ {"1.1.256.1", NULL}, /* overflow */ {"1.0.0.256", NULL}, /* overflow */ {"0x100.0.0.1", NULL}, /* overflow */ {"1.0x100.0.1", NULL}, /* overflow */ {"1.1.0x100.1", NULL}, /* overflow */ {"1.1.1.0x100", NULL}, /* overflow */ {"0400.0.0.1", NULL}, /* overflow */ {"4.0400.0.1", NULL}, /* overflow */ {"4.4.0400.1", NULL}, /* overflow */ {"4.4.4.0400", NULL}, /* overflow */ {"4294967296", NULL}, /* overflow */ {"040000000000", NULL}, /* overflow */ {"0x100000000", NULL}, /* overflow */ {"1.2.3.-4", NULL}, /* negative */ {"1.2.-3.4", NULL}, /* negative */ {"1.-2.3.4", NULL}, /* negative */ {"-1.2.3.4", NULL}, /* negative */ {"-12", NULL}, /* negative */ {"-12.1", NULL}, /* negative */ {"-12.2.3", NULL}, /* negative */ {" 1.2.3.4", NULL}, /* space */ {"1. 2.3.4", NULL}, /* space */ {"1.2. 3.4", NULL}, /* space */ {"1.2.3. 4", NULL}, /* space */ }; curlx_dyn_init(&host, 256); for(i = 0; i < CURL_ARRAYSIZE(tests); i++) { int rc; curlx_dyn_reset(&host); if(curlx_dyn_add(&host, tests[i].in)) { return CURLE_OUT_OF_MEMORY; } rc = ipv4_normalize(&host); if(tests[i].out) { if((rc != HOST_IPV4) || strcmp(curlx_dyn_ptr(&host), tests[i].out)) { curl_mfprintf(stderr, "ipv4_normalize('%s') failed: " "expected '%s', got '%s'\n", tests[i].in, tests[i].out, curlx_dyn_ptr(&host)); fails++; } } else { if(rc == HOST_IPV4) { curl_mfprintf(stderr, "ipv4_normalize('%s') succeeded unexpectedly:" " got '%s'\n", tests[i].in, curlx_dyn_ptr(&host)); fails++; } } } curlx_dyn_free(&host); abort_if(fails, "ipv4_normalize tests failed"); } /* Test urlencode_str */ { struct dynbuf out; int fails = 0; unsigned int i; struct urlencode_test { const char *in; bool relative; unsigned int query; const char *out; }; const struct urlencode_test tests[] = { {"http://leave\x01/hello\x01world", FALSE, QUERY_NO, "http://leave\x01/hello%01world"}, {"http://leave/hello\x01world", FALSE, QUERY_NO, "http://leave/hello%01world"}, {"http://le ave/hello\x01world", FALSE, QUERY_NO, "http://le ave/hello%01world"}, {"hello\x01world", TRUE, QUERY_NO, "hello%01world"}, {"hello\xf0world", TRUE, QUERY_NO, "hello%F0world"}, {"hello world", TRUE, QUERY_NO, "hello%20world"}, {"hello%20world", TRUE, QUERY_NO, "hello%20world"}, {"hello world", TRUE, QUERY_YES, "hello+world"}, {"a+b c", TRUE, QUERY_NO, "a+b%20c"}, {"a%20b%20c", TRUE, QUERY_NO, "a%20b%20c"}, {"a%aab%aac", TRUE, QUERY_NO, "a%AAb%AAc"}, {"a%aab%AAc", TRUE, QUERY_NO, "a%AAb%AAc"}, {"w%w%x", TRUE, QUERY_NO, "w%w%x"}, {"w%wf%xf", TRUE, QUERY_NO, "w%wf%xf"}, {"w%fw%fw", TRUE, QUERY_NO, "w%fw%fw"}, {"a+b c", TRUE, QUERY_YES, "a+b+c"}, {"/foo/bar", TRUE, QUERY_NO, "/foo/bar"}, {"/foo/bar", TRUE, QUERY_YES, "/foo/bar"}, {"/foo/ bar", TRUE, QUERY_NO, "/foo/%20bar"}, {"/foo/ bar", TRUE, QUERY_YES, "/foo/+bar"}, {"~-._", TRUE, QUERY_NO, "~-._"}, {"~-._", TRUE, QUERY_YES, "~-._"}, {"foo bar?foo bar", TRUE, QUERY_NO, "foo%20bar?foo%20bar"}, {"foo bar?foo bar", TRUE, QUERY_NOT_YET, "foo%20bar?foo+bar"}, }; curlx_dyn_init(&out, 256); for(i = 0; i < CURL_ARRAYSIZE(tests); i++) { CURLUcode uc; curlx_dyn_reset(&out); uc = urlencode_str(&out, tests[i].in, strlen(tests[i].in), tests[i].relative, tests[i].query); if(uc || strcmp(curlx_dyn_ptr(&out), tests[i].out)) { curl_mfprintf(stderr, "urlencode_str('%s', query=%u) failed:" " expected '%s', got '%s'\n", tests[i].in, tests[i].query, tests[i].out, uc ? "error" : curlx_dyn_ptr(&out)); fails++; } } curlx_dyn_free(&out); abort_if(fails, "urlencode_str tests failed"); } /* Test ipv6_parse */ { struct Curl_URL u; int fails = 0; unsigned int i; struct ipv6_test { const char *in; const char *out_host; const char *out_zone; }; const struct ipv6_test tests[] = { {"[::1]", "[::1]", NULL}, {"[fe80::1%eth0]", "[fe80::1]", "eth0"}, {"[fe80::1%25eth0]", "[fe80::1]", "eth0"}, {"[::1", NULL, NULL}, /* missing bracket */ {"[]", NULL, NULL}, /* empty */ }; for(i = 0; i < CURL_ARRAYSIZE(tests); i++) { CURLUcode uc; char hostname[256]; memset(&u, 0, sizeof(u)); curlx_strcopy(hostname, sizeof(hostname), tests[i].in, strlen(tests[i].in)); uc = ipv6_parse(&u, hostname, strlen(hostname)); if(tests[i].out_host) { if(uc || strcmp(hostname, tests[i].out_host)) { curl_mfprintf(stderr, "ipv6_parse('%s') host failed:" " expected '%s', got '%s'\n", tests[i].in, tests[i].out_host, uc ? "error" : hostname); fails++; } if(!uc && tests[i].out_zone) { if(!u.zoneid || strcmp(u.zoneid, tests[i].out_zone)) { curl_mfprintf(stderr, "ipv6_parse('%s') zone failed:" " expected '%s', got '%s'\n", tests[i].in, tests[i].out_zone, u.zoneid ? u.zoneid : "(null)"); fails++; } } } else { if(!uc) { curl_mfprintf(stderr, "ipv6_parse('%s') succeeded unexpectedly\n", tests[i].in); fails++; } } curlx_free(u.host); curlx_free(u.zoneid); } abort_if(fails, "ipv6_parse tests failed"); } /* Test parse_file */ { CURLU *u; const char *path; size_t pathlen; int fails = 0; unsigned int i; struct file_test { const char *in; const char *out_path; bool fine; }; const struct file_test tests[] = { {"file:///etc/hosts", "/etc/hosts", TRUE}, {"file://localhost/etc/hosts", "/etc/hosts", TRUE}, {"file://apple/etc/hosts", "/etc/hosts", FALSE}, #ifdef _WIN32 {"file:///c:/windows/system32", "c:/windows/system32", TRUE}, {"file://localhost/c:/windows/system32", "c:/windows/system32", TRUE}, #endif }; for(i = 0; i < CURL_ARRAYSIZE(tests); i++) { CURLUcode uc; u = curl_url(); if(!u) return CURLE_OUT_OF_MEMORY; uc = parse_file(tests[i].in, strlen(tests[i].in), u, &path, &pathlen); if(!tests[i].fine && !uc) { curl_mfprintf(stderr, "Unexpectedly fine for input '%s'\n", tests[i].in); fails++; } if(tests[i].fine && (uc || strncmp(path, tests[i].out_path, pathlen) || strlen(tests[i].out_path) != pathlen)) { curl_mfprintf(stderr, "parse_file('%s') failed:" " expected path '%s'; got path '%.*s'\n", tests[i].in, tests[i].out_path, (int)pathlen, path); fails++; } curl_url_cleanup(u); } abort_if(fails, "parse_file tests failed"); } /* Test same origin check. For now, we can only do that when * schemes are supported by libcurl. */ #ifndef CURL_DISABLE_HTTP { CURLU *base, *href; int fails = 0; unsigned int i; bool match; struct origin_test { const char *base; const char *scheme; const char *host; const char *port; const char *path; bool expect_match; }; const struct origin_test tests[] = { {"http://host:123/x", "http", "host", "123", "/y", TRUE}, {"http://host:123/x", NULL, "host", "123", "/y", TRUE}, {"http://host:123/x", NULL, NULL, NULL, "/y", TRUE}, {"http://host:80/x", "http", "host", "123", "/y", FALSE}, {"http://host:80/x", "http", "host", NULL, "/y", TRUE}, {"http://host/x", "http", "host", "80", "/y", TRUE}, #ifdef USE_SSL {"http://host:123/x", "https", "host", "123", "/y", FALSE}, {"https://host/x", "http", "host", "443", "/y", FALSE}, {"https://host/x", "https", "host", "443", "/y", TRUE}, #endif }; for(i = 0; i < CURL_ARRAYSIZE(tests); i++) { CURLUcode uc; base = curl_url(); href = curl_url(); if(!base || !href) { curl_mfprintf(stderr, "%u: failed to allocate memory\n", i); fails++; goto loop_end; } uc = curl_url_set(base, CURLUPART_URL, tests[i].base, 0); if(uc) { curl_mfprintf(stderr, "failed to parse %u base %s -> %d\n", i, tests[i].base, uc); fails++; goto loop_end; } if(tests[i].scheme) uc = curl_url_set(href, CURLUPART_SCHEME, tests[i].scheme, 0); if(!uc && tests[i].host) uc = curl_url_set(href, CURLUPART_HOST, tests[i].host, 0); if(!uc && tests[i].port) uc = curl_url_set(href, CURLUPART_PORT, tests[i].port, 0); if(!uc && tests[i].path) uc = curl_url_set(href, CURLUPART_PATH, tests[i].path, 0); if(uc) { curl_mfprintf(stderr, "failed to parse %u href %s://%s:%s%s -> %d\n", i, tests[i].scheme, tests[i].host, tests[i].port, tests[i].path, uc); fails++; goto loop_end; } match = Curl_url_same_origin(base, href); if(match != tests[i].expect_match) { curl_mfprintf(stderr, "ERROR: %u base %s and href %s://%s:%s%s %s\n", i, tests[i].base, tests[i].scheme, tests[i].host, tests[i].port, tests[i].path, match ? "matched" : "did not match"); fails++; } loop_end: curl_url_cleanup(base); curl_url_cleanup(href); } abort_if(fails, "same_origin tests failed"); } #endif /* !CURL_DISABLE_HTTP */ UNITTEST_END_SIMPLE }