/*************************************************************************** * _ _ ____ _ * 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) { 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 }, { "file:foo", NULL, FALSE }, { "file:./", NULL, FALSE }, { "file:?q", NULL, FALSE }, { "file:#f", NULL, 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 }