quickjs-tart

quickjs-based runtime for wallet-core logic
Log | Files | Refs | README | LICENSE

lib1560.c (70541B)


      1 /***************************************************************************
      2  *                                  _   _ ____  _
      3  *  Project                     ___| | | |  _ \| |
      4  *                             / __| | | | |_) | |
      5  *                            | (__| |_| |  _ <| |___
      6  *                             \___|\___/|_| \_\_____|
      7  *
      8  * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
      9  *
     10  * This software is licensed as described in the file COPYING, which
     11  * you should have received as part of this distribution. The terms
     12  * are also available at https://curl.se/docs/copyright.html.
     13  *
     14  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
     15  * copies of the Software, and permit persons to whom the Software is
     16  * furnished to do so, under the terms of the COPYING file.
     17  *
     18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
     19  * KIND, either express or implied.
     20  *
     21  * SPDX-License-Identifier: curl
     22  *
     23  ***************************************************************************/
     24 
     25 /*
     26  * Note:
     27  *
     28  * Since the URL parser by default only accepts schemes that *this instance*
     29  * of libcurl supports, make sure that the test1560 file lists all the schemes
     30  * that this test will assume to be present!
     31  */
     32 
     33 #include "first.h"
     34 #if defined(USE_LIBIDN2) || defined(USE_WIN32_IDN) || defined(USE_APPLE_IDN)
     35 #define USE_IDN
     36 #endif
     37 
     38 #include "memdebug.h" /* LAST include file */
     39 
     40 static int checkparts(CURLU *u, const char *in, const char *wanted,
     41                       unsigned int getflags)
     42 {
     43   int i;
     44   CURLUcode rc;
     45   char buf[256];
     46   char *bufp = &buf[0];
     47   size_t len = sizeof(buf);
     48 
     49   struct part {
     50     CURLUPart part;
     51     const char *name;
     52   };
     53 
     54   struct part parts[] = {
     55     {CURLUPART_SCHEME, "scheme"},
     56     {CURLUPART_USER, "user"},
     57     {CURLUPART_PASSWORD, "password"},
     58     {CURLUPART_OPTIONS, "options"},
     59     {CURLUPART_HOST, "host"},
     60     {CURLUPART_PORT, "port"},
     61     {CURLUPART_PATH, "path"},
     62     {CURLUPART_QUERY, "query"},
     63     {CURLUPART_FRAGMENT, "fragment"},
     64     {CURLUPART_URL, NULL}
     65   };
     66   memset(buf, 0, sizeof(buf));
     67 
     68   for(i = 0; parts[i].name; i++) {
     69     char *p = NULL;
     70     size_t n;
     71     rc = curl_url_get(u, parts[i].part, &p, getflags);
     72     if(!rc && p) {
     73       curl_msnprintf(bufp, len, "%s%s", buf[0]?" | ":"", p);
     74     }
     75     else
     76       curl_msnprintf(bufp, len, "%s[%d]", buf[0]?" | ":"", (int)rc);
     77 
     78     n = strlen(bufp);
     79     bufp += n;
     80     len -= n;
     81     curl_free(p);
     82   }
     83   if(strcmp(buf, wanted)) {
     84     curl_mfprintf(stderr, "in: %s\nwanted: %s\ngot:    %s\n", in, wanted, buf);
     85     return 1;
     86   }
     87   return 0;
     88 }
     89 
     90 struct redircase {
     91   const char *in;
     92   const char *set;
     93   const char *out;
     94   unsigned int urlflags;
     95   unsigned int setflags;
     96   CURLUcode ucode;
     97 };
     98 
     99 struct setcase {
    100   const char *in;
    101   const char *set;
    102   const char *out;
    103   unsigned int urlflags;
    104   unsigned int setflags;
    105   CURLUcode ucode; /* for the main URL set */
    106   CURLUcode pcode; /* for updating parts */
    107 };
    108 
    109 struct setgetcase {
    110   const char *in;
    111   const char *set;
    112   const char *out;
    113   unsigned int urlflags; /* for setting the URL */
    114   unsigned int setflags; /* for updating parts */
    115   unsigned int getflags; /* for getting parts */
    116   CURLUcode pcode; /* for updating parts */
    117 };
    118 
    119 struct testcase {
    120   const char *in;
    121   const char *out;
    122   unsigned int urlflags;
    123   unsigned int getflags;
    124   CURLUcode ucode;
    125 };
    126 
    127 struct urltestcase {
    128   const char *in;
    129   const char *out;
    130   unsigned int urlflags; /* pass to curl_url() */
    131   unsigned int getflags; /* pass to curl_url_get() */
    132   CURLUcode ucode;
    133 };
    134 
    135 struct querycase {
    136   const char *in;
    137   const char *q;
    138   const char *out;
    139   unsigned int urlflags; /* pass to curl_url() */
    140   unsigned int qflags; /* pass to curl_url_get() */
    141   CURLUcode ucode;
    142 };
    143 
    144 struct clearurlcase {
    145   CURLUPart part;
    146   const char *in;
    147   const char *out;
    148   CURLUcode ucode;
    149 };
    150 
    151 static const struct testcase get_parts_list[] ={
    152   {"curl.se",
    153    "[10] | [11] | [12] | [13] | curl.se | [15] | / | [16] | [17]",
    154    CURLU_GUESS_SCHEME, CURLU_NO_GUESS_SCHEME, CURLUE_OK},
    155   {"https://curl.se:0/#",
    156    "https | [11] | [12] | [13] | curl.se | 0 | / | [16] | ",
    157    0, CURLU_GET_EMPTY, CURLUE_OK},
    158   {"https://curl.se/#",
    159    "https | [11] | [12] | [13] | curl.se | [15] | / | [16] | ",
    160    0, CURLU_GET_EMPTY, CURLUE_OK},
    161   {"https://curl.se/?#",
    162    "https | [11] | [12] | [13] | curl.se | [15] | / |  | ",
    163    0, CURLU_GET_EMPTY, CURLUE_OK},
    164   {"https://curl.se/?",
    165    "https | [11] | [12] | [13] | curl.se | [15] | / |  | [17]",
    166    0, CURLU_GET_EMPTY, CURLUE_OK},
    167   {"https://curl.se/?",
    168    "https | [11] | [12] | [13] | curl.se | [15] | / | [16] | [17]",
    169    0, 0, CURLUE_OK},
    170   {"https://curl.se/?#",
    171    "https | [11] | [12] | [13] | curl.se | [15] | / | [16] | [17]",
    172    0, 0, CURLUE_OK},
    173   {"https://curl.se/#  ",
    174    "https | [11] | [12] | [13] | curl.se | [15] | / | [16] | %20%20",
    175    CURLU_URLENCODE|CURLU_ALLOW_SPACE, 0, CURLUE_OK},
    176   {"", "", 0, 0, CURLUE_MALFORMED_INPUT},
    177   {" ", "", 0, 0, CURLUE_MALFORMED_INPUT},
    178   {"1h://example.net", "", 0, 0, CURLUE_BAD_SCHEME},
    179   {"..://example.net", "", 0, 0, CURLUE_BAD_SCHEME},
    180   {"-ht://example.net", "", 0, 0, CURLUE_BAD_SCHEME},
    181   {"+ftp://example.net", "", 0, 0, CURLUE_BAD_SCHEME},
    182   {"hej.hej://example.net",
    183    "hej.hej | [11] | [12] | [13] | example.net | [15] | / | [16] | [17]",
    184    CURLU_NON_SUPPORT_SCHEME, 0, CURLUE_OK},
    185   {"ht-tp://example.net",
    186    "ht-tp | [11] | [12] | [13] | example.net | [15] | / | [16] | [17]",
    187    CURLU_NON_SUPPORT_SCHEME, 0, CURLUE_OK},
    188   {"ftp+more://example.net",
    189    "ftp+more | [11] | [12] | [13] | example.net | [15] | / | [16] | [17]",
    190    CURLU_NON_SUPPORT_SCHEME, 0, CURLUE_OK},
    191   {"f1337://example.net",
    192    "f1337 | [11] | [12] | [13] | example.net | [15] | / | [16] | [17]",
    193    CURLU_NON_SUPPORT_SCHEME, 0, CURLUE_OK},
    194   {"https://user@example.net?hello# space ",
    195    "https | user | [12] | [13] | example.net | [15] | / | hello | %20space%20",
    196    CURLU_ALLOW_SPACE|CURLU_URLENCODE, 0, CURLUE_OK},
    197   {"https://test%test", "", 0, 0, CURLUE_BAD_HOSTNAME},
    198   {"https://example.com%252f%40@example.net",
    199    "https | example.com%2f@ | [12] | [13] | example.net | [15] | / "
    200    "| [16] | [17]",
    201    0, CURLU_URLDECODE, CURLUE_OK },
    202 #ifdef USE_IDN
    203   /*
    204     https://sv.wikipedia.org/wiki/R%c3%a4ksm%c3%b6rg%c3%a5s
    205     https://codepoints.net/U+00E4 Latin Small Letter A with Diaeresis
    206     https://codepoints.net/U+00F6 Latin Small Letter O with Diaeresis
    207     https://codepoints.net/U+00E5 Latin Small Letter A with Ring Above
    208   */
    209   {"https://r\xc3\xa4ksm\xc3\xb6rg\xc3\xa5s.se",
    210    "https | [11] | [12] | [13] | xn--rksmrgs-5wao1o.se | "
    211    "[15] | / | [16] | [17]", 0, CURLU_PUNYCODE, CURLUE_OK},
    212   {"https://xn--rksmrgs-5wao1o.se",
    213    "https | [11] | [12] | [13] | r\xc3\xa4ksm\xc3\xb6rg\xc3\xa5s.se | "
    214    "[15] | / | [16] | [17]", 0, CURLU_PUNY2IDN, CURLUE_OK},
    215   {"https://www.xn--rksmrgs-5wao1o.se",
    216    "https | [11] | [12] | [13] | www.r\xc3\xa4ksm\xc3\xb6rg\xc3\xa5s.se | "
    217    "[15] | / | [16] | [17]", 0, CURLU_PUNY2IDN, CURLUE_OK},
    218   {"https://www.r\xc3\xa4ksm\xc3\xb6rg\xc3\xa5s.se",
    219    "https | [11] | [12] | [13] | www.r\xc3\xa4ksm\xc3\xb6rg\xc3\xa5s.se | "
    220    "[15] | / | [16] | [17]", 0, CURLU_PUNY2IDN, CURLUE_OK},
    221 #else
    222   {"https://r\xc3\xa4ksm\xc3\xb6rg\xc3\xa5s.se",
    223    "https | [11] | [12] | [13] | [30] | [15] | / | [16] | [17]",
    224    0, CURLU_PUNYCODE, CURLUE_OK},
    225 #endif
    226   /*
    227     https://codepoints.net/U+2102  Double-Struck Capital C
    228     https://codepoints.net/U+1d64  Latin Subscript Small Letter U
    229     https://codepoints.net/U+24c7  Circled Latin Capital Letter R
    230     https://codepoints.net/U+2112  Script Capital L
    231     https://codepoints.net/U+3002  Ideographic Full Stop
    232     https://codepoints.net/U+1d412 Mathematical Bold Capital S
    233     https://codepoints.net/U+1f134 Squared Latin Capital Letter E
    234   */
    235   {"https://"
    236    "%e2%84%82%e1%b5%a4%e2%93%87%e2%84%92%e3%80%82%f0%9d%90%92%f0%9f%84%b4",
    237    "https | [11] | [12] | [13] | "
    238    "\xe2\x84\x82\xe1\xb5\xa4\xe2\x93\x87\xe2\x84\x92"
    239    "\xe3\x80\x82\xf0\x9d\x90\x92\xf0\x9f\x84\xb4"
    240    " | [15] | / | [16] | [17]",
    241    0, 0, CURLUE_OK},
    242   {"https://"
    243    "%e2%84%82%e1%b5%a4%e2%93%87%e2%84%92%e3%80%82%f0%9d%90%92%f0%9f%84%b4",
    244    "https | [11] | [12] | [13] | "
    245    "%E2%84%82%E1%B5%A4%E2%93%87%E2%84%92%E3%80%82%F0%9D%90%92%F0%9F%84%B4 "
    246    "| [15] | / | [16] | [17]",
    247    0, CURLU_URLENCODE, CURLUE_OK},
    248   {"https://"
    249    "\xe2\x84\x82\xe1\xb5\xa4\xe2\x93\x87\xe2\x84\x92"
    250    "\xe3\x80\x82\xf0\x9d\x90\x92\xf0\x9f\x84\xb4",
    251    "https | [11] | [12] | [13] | "
    252    "%E2%84%82%E1%B5%A4%E2%93%87%E2%84%92%E3%80%82%F0%9D%90%92%F0%9F%84%B4 "
    253    "| [15] | / | [16] | [17]",
    254    0, CURLU_URLENCODE, CURLUE_OK},
    255   {"https://user@example.net?he l lo",
    256    "https | user | [12] | [13] | example.net | [15] | / | he+l+lo | [17]",
    257    CURLU_ALLOW_SPACE, CURLU_URLENCODE, CURLUE_OK},
    258   {"https://user@example.net?he l lo",
    259    "https | user | [12] | [13] | example.net | [15] | / | he l lo | [17]",
    260    CURLU_ALLOW_SPACE, 0, CURLUE_OK},
    261   {"https://exam{}[]ple.net", "", 0, 0, CURLUE_BAD_HOSTNAME},
    262   {"https://exam{ple.net", "", 0, 0, CURLUE_BAD_HOSTNAME},
    263   {"https://exam}ple.net", "", 0, 0, CURLUE_BAD_HOSTNAME},
    264   {"https://exam]ple.net", "", 0, 0, CURLUE_BAD_HOSTNAME},
    265   {"https://exam\\ple.net", "", 0, 0, CURLUE_BAD_HOSTNAME},
    266   {"https://exam$ple.net", "", 0, 0, CURLUE_BAD_HOSTNAME},
    267   {"https://exam'ple.net", "", 0, 0, CURLUE_BAD_HOSTNAME},
    268   {"https://exam\"ple.net", "", 0, 0, CURLUE_BAD_HOSTNAME},
    269   {"https://exam^ple.net", "", 0, 0, CURLUE_BAD_HOSTNAME},
    270   {"https://exam`ple.net", "", 0, 0, CURLUE_BAD_HOSTNAME},
    271   {"https://exam*ple.net", "", 0, 0, CURLUE_BAD_HOSTNAME},
    272   {"https://exam<ple.net", "", 0, 0, CURLUE_BAD_HOSTNAME},
    273   {"https://exam>ple.net", "", 0, 0, CURLUE_BAD_HOSTNAME},
    274   {"https://exam=ple.net", "", 0, 0, CURLUE_BAD_HOSTNAME},
    275   {"https://exam;ple.net", "", 0, 0, CURLUE_BAD_HOSTNAME},
    276   {"https://example,net", "", 0, 0, CURLUE_BAD_HOSTNAME},
    277   {"https://example&net", "", 0, 0, CURLUE_BAD_HOSTNAME},
    278   {"https://example+net", "", 0, 0, CURLUE_BAD_HOSTNAME},
    279   {"https://example(net", "", 0, 0, CURLUE_BAD_HOSTNAME},
    280   {"https://example)net", "", 0, 0, CURLUE_BAD_HOSTNAME},
    281   {"https://example.net/}",
    282    "https | [11] | [12] | [13] | example.net | [15] | /} | [16] | [17]",
    283    0, 0, CURLUE_OK},
    284 
    285   /* blank user is blank */
    286   {"https://:password@example.net",
    287    "https |  | password | [13] | example.net | [15] | / | [16] | [17]",
    288    0, 0, CURLUE_OK},
    289   /* blank user + blank password */
    290   {"https://:@example.net",
    291    "https |  |  | [13] | example.net | [15] | / | [16] | [17]",
    292    0, 0, CURLUE_OK},
    293   /* user-only (no password) */
    294   {"https://user@example.net",
    295    "https | user | [12] | [13] | example.net | [15] | / | [16] | [17]",
    296    0, 0, CURLUE_OK},
    297 #ifndef CURL_DISABLE_WEBSOCKETS
    298   {"ws://example.com/color/?green",
    299    "ws | [11] | [12] | [13] | example.com | [15] | /color/ | green |"
    300    " [17]",
    301    CURLU_DEFAULT_SCHEME, 0, CURLUE_OK },
    302   {"wss://example.com/color/?green",
    303    "wss | [11] | [12] | [13] | example.com | [15] | /color/ | green |"
    304    " [17]",
    305    CURLU_DEFAULT_SCHEME, 0, CURLUE_OK },
    306 #endif
    307 
    308   {"https://user:password@example.net/get?this=and#but frag then", "",
    309    CURLU_DEFAULT_SCHEME, 0, CURLUE_MALFORMED_INPUT},
    310   {"https://user:password@example.net/get?this=and what", "",
    311    CURLU_DEFAULT_SCHEME, 0, CURLUE_MALFORMED_INPUT},
    312   {"https://user:password@example.net/ge t?this=and-what", "",
    313    CURLU_DEFAULT_SCHEME, 0, CURLUE_MALFORMED_INPUT},
    314   {"https://user:pass word@example.net/get?this=and-what", "",
    315    CURLU_DEFAULT_SCHEME, 0, CURLUE_MALFORMED_INPUT},
    316   {"https://u ser:password@example.net/get?this=and-what", "",
    317    CURLU_DEFAULT_SCHEME, 0, CURLUE_MALFORMED_INPUT},
    318   {"imap://user:pass;opt ion@server/path", "",
    319    CURLU_DEFAULT_SCHEME, 0, CURLUE_MALFORMED_INPUT},
    320   /* no space allowed in scheme */
    321   {"htt ps://user:password@example.net/get?this=and-what", "",
    322    CURLU_NON_SUPPORT_SCHEME|CURLU_ALLOW_SPACE, 0, CURLUE_BAD_SCHEME},
    323   {"https://user:password@example.net/get?this=and what",
    324    "https | user | password | [13] | example.net | [15] | /get | "
    325    "this=and what | [17]",
    326    CURLU_ALLOW_SPACE, 0, CURLUE_OK},
    327   {"https://user:password@example.net/ge t?this=and-what",
    328    "https | user | password | [13] | example.net | [15] | /ge t | "
    329    "this=and-what | [17]",
    330    CURLU_ALLOW_SPACE, 0, CURLUE_OK},
    331   {"https://user:pass word@example.net/get?this=and-what",
    332    "https | user | pass word | [13] | example.net | [15] | /get | "
    333    "this=and-what | [17]",
    334    CURLU_ALLOW_SPACE, 0, CURLUE_OK},
    335   {"https://u ser:password@example.net/get?this=and-what",
    336    "https | u ser | password | [13] | example.net | [15] | /get | "
    337    "this=and-what | [17]",
    338    CURLU_ALLOW_SPACE, 0, CURLUE_OK},
    339   {"https://user:password@example.net/ge t?this=and-what",
    340    "https | user | password | [13] | example.net | [15] | /ge%20t | "
    341    "this=and-what | [17]",
    342    CURLU_ALLOW_SPACE | CURLU_URLENCODE, 0, CURLUE_OK},
    343   {"[0:0:0:0:0:0:0:1]",
    344    "http | [11] | [12] | [13] | [::1] | [15] | / | [16] | [17]",
    345    CURLU_GUESS_SCHEME, 0, CURLUE_OK },
    346   {"[::1]",
    347    "http | [11] | [12] | [13] | [::1] | [15] | / | [16] | [17]",
    348    CURLU_GUESS_SCHEME, 0, CURLUE_OK },
    349   {"[::]",
    350    "http | [11] | [12] | [13] | [::] | [15] | / | [16] | [17]",
    351    CURLU_GUESS_SCHEME, 0, CURLUE_OK },
    352   {"https://[::1]",
    353    "https | [11] | [12] | [13] | [::1] | [15] | / | [16] | [17]",
    354    0, 0, CURLUE_OK },
    355   {"user:moo@ftp.example.com/color/#green?no-red",
    356    "ftp | user | moo | [13] | ftp.example.com | [15] | /color/ | [16] | "
    357    "green?no-red",
    358    CURLU_GUESS_SCHEME, 0, CURLUE_OK },
    359   {"ftp.user:moo@example.com/color/#green?no-red",
    360    "http | ftp.user | moo | [13] | example.com | [15] | /color/ | [16] | "
    361    "green?no-red",
    362    CURLU_GUESS_SCHEME, 0, CURLUE_OK },
    363 #ifdef _WIN32
    364   {"file:/C:\\programs\\foo",
    365    "file | [11] | [12] | [13] | [14] | [15] | C:\\programs\\foo | [16] | [17]",
    366    CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
    367   {"file://C:\\programs\\foo",
    368    "file | [11] | [12] | [13] | [14] | [15] | C:\\programs\\foo | [16] | [17]",
    369    CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
    370   {"file:///C:\\programs\\foo",
    371    "file | [11] | [12] | [13] | [14] | [15] | C:\\programs\\foo | [16] | [17]",
    372    CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
    373   {"file://host.example.com/Share/path/to/file.txt",
    374    "file | [11] | [12] | [13] | host.example.com | [15] | "
    375    "//host.example.com/Share/path/to/file.txt | [16] | [17]",
    376    CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
    377 #endif
    378   {"https://example.com/color/#green?no-red",
    379    "https | [11] | [12] | [13] | example.com | [15] | /color/ | [16] | "
    380    "green?no-red",
    381    CURLU_DEFAULT_SCHEME, 0, CURLUE_OK },
    382   {"https://example.com/color/#green#no-red",
    383    "https | [11] | [12] | [13] | example.com | [15] | /color/ | [16] | "
    384    "green#no-red",
    385    CURLU_DEFAULT_SCHEME, 0, CURLUE_OK },
    386   {"https://example.com/color/?green#no-red",
    387    "https | [11] | [12] | [13] | example.com | [15] | /color/ | green | "
    388    "no-red",
    389    CURLU_DEFAULT_SCHEME, 0, CURLUE_OK },
    390   {"https://example.com/#color/?green#no-red",
    391    "https | [11] | [12] | [13] | example.com | [15] | / | [16] | "
    392    "color/?green#no-red",
    393    CURLU_DEFAULT_SCHEME, 0, CURLUE_OK },
    394   {"https://example.#com/color/?green#no-red",
    395    "https | [11] | [12] | [13] | example. | [15] | / | [16] | "
    396    "com/color/?green#no-red",
    397    CURLU_DEFAULT_SCHEME, 0, CURLUE_OK },
    398   {"http://[ab.be:1]/x", "",
    399    CURLU_DEFAULT_SCHEME, 0, CURLUE_BAD_IPV6},
    400   {"http://[ab.be]/x", "",
    401    CURLU_DEFAULT_SCHEME, 0, CURLUE_BAD_IPV6},
    402   /* URL without host name */
    403   {"http://a:b@/x", "",
    404    CURLU_DEFAULT_SCHEME, 0, CURLUE_NO_HOST},
    405   {"boing:80",
    406    "https | [11] | [12] | [13] | boing | 80 | / | [16] | [17]",
    407    CURLU_DEFAULT_SCHEME|CURLU_GUESS_SCHEME, 0, CURLUE_OK},
    408   {"http://[fd00:a41::50]:8080",
    409    "http | [11] | [12] | [13] | [fd00:a41::50] | 8080 | / | [16] | [17]",
    410    CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
    411   {"http://[fd00:a41::50]/",
    412    "http | [11] | [12] | [13] | [fd00:a41::50] | [15] | / | [16] | [17]",
    413    CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
    414   {"http://[fd00:a41::50]",
    415    "http | [11] | [12] | [13] | [fd00:a41::50] | [15] | / | [16] | [17]",
    416    CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
    417   {"https://[::1%252]:1234",
    418    "https | [11] | [12] | [13] | [::1] | 1234 | / | [16] | [17]",
    419    CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
    420 
    421   /* here's "bad" zone id */
    422   {"https://[fe80::20c:29ff:fe9c:409b%eth0]:1234",
    423    "https | [11] | [12] | [13] | [fe80::20c:29ff:fe9c:409b] | 1234 "
    424    "| / | [16] | [17]",
    425    CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
    426   {"https://127.0.0.1:443",
    427    "https | [11] | [12] | [13] | 127.0.0.1 | [15] | / | [16] | [17]",
    428    0, CURLU_NO_DEFAULT_PORT, CURLUE_OK},
    429   {"http://%3a:%3a@ex4mple/%3f+?+%3f+%23#+%23%3f%g7",
    430    "http | : | : | [13] | ex4mple | [15] | /?+ |  ? # | +#?%g7",
    431    0, CURLU_URLDECODE, CURLUE_OK},
    432   {"http://%3a:%3a@ex4mple/%3f?%3f%35#%35%3f%g7",
    433    "http | %3a | %3a | [13] | ex4mple | [15] | /%3f | %3f%35 | %35%3f%g7",
    434    0, 0, CURLUE_OK},
    435   {"http://HO0_-st%41/",
    436    "http | [11] | [12] | [13] | HO0_-stA | [15] | / | [16] | [17]",
    437    0, 0, CURLUE_OK},
    438   {"file://hello.html",
    439    "",
    440    0, 0, CURLUE_BAD_FILE_URL},
    441   {"http://HO0_-st/",
    442    "http | [11] | [12] | [13] | HO0_-st | [15] | / | [16] | [17]",
    443    0, 0, CURLUE_OK},
    444   {"imap://user:pass;option@server/path",
    445    "imap | user | pass | option | server | [15] | /path | [16] | [17]",
    446    0, 0, CURLUE_OK},
    447   {"http://user:pass;option@server/path",
    448    "http | user | pass;option | [13] | server | [15] | /path | [16] | [17]",
    449    0, 0, CURLUE_OK},
    450   {"file:/hello.html",
    451    "file | [11] | [12] | [13] | [14] | [15] | /hello.html | [16] | [17]",
    452    0, 0, CURLUE_OK},
    453   {"file:/h",
    454    "file | [11] | [12] | [13] | [14] | [15] | /h | [16] | [17]",
    455    0, 0, CURLUE_OK},
    456   {"file:/",
    457    "file | [11] | [12] | [13] | [14] | [15] | | [16] | [17]",
    458    0, 0, CURLUE_BAD_FILE_URL},
    459   {"file://127.0.0.1/hello.html",
    460    "file | [11] | [12] | [13] | [14] | [15] | /hello.html | [16] | [17]",
    461    0, 0, CURLUE_OK},
    462   {"file:////hello.html",
    463    "file | [11] | [12] | [13] | [14] | [15] | //hello.html | [16] | [17]",
    464    0, 0, CURLUE_OK},
    465   {"file:///hello.html",
    466    "file | [11] | [12] | [13] | [14] | [15] | /hello.html | [16] | [17]",
    467    0, 0, CURLUE_OK},
    468   {"https://127.0.0.1",
    469    "https | [11] | [12] | [13] | 127.0.0.1 | 443 | / | [16] | [17]",
    470    0, CURLU_DEFAULT_PORT, CURLUE_OK},
    471   {"https://127.0.0.1",
    472    "https | [11] | [12] | [13] | 127.0.0.1 | [15] | / | [16] | [17]",
    473    CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
    474   {"https://[::1]:1234",
    475    "https | [11] | [12] | [13] | [::1] | 1234 | / | [16] | [17]",
    476    CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
    477   {"https://127abc.com",
    478    "https | [11] | [12] | [13] | 127abc.com | [15] | / | [16] | [17]",
    479    CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
    480   {"https:// example.com?check", "",
    481    CURLU_DEFAULT_SCHEME, 0, CURLUE_MALFORMED_INPUT},
    482   {"https://e x a m p l e.com?check", "",
    483    CURLU_DEFAULT_SCHEME, 0, CURLUE_MALFORMED_INPUT},
    484   {"https://example.com?check",
    485    "https | [11] | [12] | [13] | example.com | [15] | / | check | [17]",
    486    CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
    487   {"https://example.com:65536",
    488    "",
    489    CURLU_DEFAULT_SCHEME, 0, CURLUE_BAD_PORT_NUMBER},
    490   {"https://example.com:-1#moo",
    491    "",
    492    CURLU_DEFAULT_SCHEME, 0, CURLUE_BAD_PORT_NUMBER},
    493   {"https://example.com:0#moo",
    494    "https | [11] | [12] | [13] | example.com | 0 | / | "
    495    "[16] | moo",
    496    CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
    497   {"https://example.com:01#moo",
    498    "https | [11] | [12] | [13] | example.com | 1 | / | "
    499    "[16] | moo",
    500    CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
    501   {"https://example.com:1#moo",
    502    "https | [11] | [12] | [13] | example.com | 1 | / | "
    503    "[16] | moo",
    504    CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
    505   {"http://example.com#moo",
    506    "http | [11] | [12] | [13] | example.com | [15] | / | "
    507    "[16] | moo",
    508    CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
    509   {"http://example.com",
    510    "http | [11] | [12] | [13] | example.com | [15] | / | "
    511    "[16] | [17]",
    512    CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
    513   {"http://example.com/path/html",
    514    "http | [11] | [12] | [13] | example.com | [15] | /path/html | "
    515    "[16] | [17]",
    516    CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
    517   {"http://example.com/path/html?query=name",
    518    "http | [11] | [12] | [13] | example.com | [15] | /path/html | "
    519    "query=name | [17]",
    520    CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
    521   {"http://example.com/path/html?query=name#anchor",
    522    "http | [11] | [12] | [13] | example.com | [15] | /path/html | "
    523    "query=name | anchor",
    524    CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
    525   {"http://example.com:1234/path/html?query=name#anchor",
    526    "http | [11] | [12] | [13] | example.com | 1234 | /path/html | "
    527    "query=name | anchor",
    528    CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
    529   {"http:///user:password@example.com:1234/path/html?query=name#anchor",
    530    "http | user | password | [13] | example.com | 1234 | /path/html | "
    531    "query=name | anchor",
    532    CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
    533   {"https://user:password@example.com:1234/path/html?query=name#anchor",
    534    "https | user | password | [13] | example.com | 1234 | /path/html | "
    535    "query=name | anchor",
    536    CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
    537   {"http://user:password@example.com:1234/path/html?query=name#anchor",
    538    "http | user | password | [13] | example.com | 1234 | /path/html | "
    539    "query=name | anchor",
    540    CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
    541   {"http:/user:password@example.com:1234/path/html?query=name#anchor",
    542    "http | user | password | [13] | example.com | 1234 | /path/html | "
    543    "query=name | anchor",
    544    CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
    545   {"http:////user:password@example.com:1234/path/html?query=name#anchor",
    546    "",
    547    CURLU_DEFAULT_SCHEME, 0, CURLUE_BAD_SLASHES},
    548   {NULL, NULL, 0, 0, CURLUE_OK},
    549 };
    550 
    551 static const struct urltestcase get_url_list[] = {
    552   {"018.0.0.0", "http://018.0.0.0/", CURLU_GUESS_SCHEME, 0, CURLUE_OK},
    553   {"08", "http://08/", CURLU_GUESS_SCHEME, 0, CURLUE_OK},
    554   {"0", "http://0.0.0.0/", CURLU_GUESS_SCHEME, 0, CURLUE_OK},
    555   {"01", "http://0.0.0.1/", CURLU_GUESS_SCHEME, 0, CURLUE_OK},
    556   {"02", "http://0.0.0.2/", CURLU_GUESS_SCHEME, 0, CURLUE_OK},
    557   {"03", "http://0.0.0.3/", CURLU_GUESS_SCHEME, 0, CURLUE_OK},
    558   {"04", "http://0.0.0.4/", CURLU_GUESS_SCHEME, 0, CURLUE_OK},
    559   {"05", "http://0.0.0.5/", CURLU_GUESS_SCHEME, 0, CURLUE_OK},
    560   {"06", "http://0.0.0.6/", CURLU_GUESS_SCHEME, 0, CURLUE_OK},
    561   {"07", "http://0.0.0.7/", CURLU_GUESS_SCHEME, 0, CURLUE_OK},
    562   {"07.1", "http://7.0.0.1/", CURLU_GUESS_SCHEME, 0, CURLUE_OK},
    563   {"7.1", "http://7.0.0.1/", CURLU_GUESS_SCHEME, 0, CURLUE_OK},
    564   {"0x7.1", "http://7.0.0.1/", CURLU_GUESS_SCHEME, 0, CURLUE_OK},
    565   {"0x", "http://0x/", CURLU_GUESS_SCHEME, 0, CURLUE_OK},
    566   {"0x1", "http://0.0.0.1/", CURLU_GUESS_SCHEME, 0, CURLUE_OK},
    567   {"0x2", "http://0.0.0.2/", CURLU_GUESS_SCHEME, 0, CURLUE_OK},
    568   {"0x3", "http://0.0.0.3/", CURLU_GUESS_SCHEME, 0, CURLUE_OK},
    569   {"0x4", "http://0.0.0.4/", CURLU_GUESS_SCHEME, 0, CURLUE_OK},
    570   {"0x5", "http://0.0.0.5/", CURLU_GUESS_SCHEME, 0, CURLUE_OK},
    571   {"0x6", "http://0.0.0.6/", CURLU_GUESS_SCHEME, 0, CURLUE_OK},
    572   {"0x7", "http://0.0.0.7/", CURLU_GUESS_SCHEME, 0, CURLUE_OK},
    573   {"0x8", "http://0.0.0.8/", CURLU_GUESS_SCHEME, 0, CURLUE_OK},
    574   {"0x9", "http://0.0.0.9/", CURLU_GUESS_SCHEME, 0, CURLUE_OK},
    575   {"0xa", "http://0.0.0.10/", CURLU_GUESS_SCHEME, 0, CURLUE_OK},
    576   {"0xb", "http://0.0.0.11/", CURLU_GUESS_SCHEME, 0, CURLUE_OK},
    577   {"0xc", "http://0.0.0.12/", CURLU_GUESS_SCHEME, 0, CURLUE_OK},
    578   {"0xd", "http://0.0.0.13/", CURLU_GUESS_SCHEME, 0, CURLUE_OK},
    579   {"0xe", "http://0.0.0.14/", CURLU_GUESS_SCHEME, 0, CURLUE_OK},
    580   {"0xf", "http://0.0.0.15/", CURLU_GUESS_SCHEME, 0, CURLUE_OK},
    581   {"0xg", "http://0xg/", CURLU_GUESS_SCHEME, 0, CURLUE_OK},
    582   {"https://0/", "https://0.0.0.0/", 0, 0, CURLUE_OK},
    583   {"https://0.0x0/", "https://0.0.0.0/", 0, 0, CURLUE_OK},
    584   {"https://0.000/", "https://0.0.0.0/", 0, 0, CURLUE_OK},
    585   {"example.com",
    586    "example.com/",
    587    CURLU_GUESS_SCHEME, CURLU_NO_GUESS_SCHEME, CURLUE_OK},
    588   {"http://user@example.com?#",
    589    "http://user@example.com/?#",
    590    0, CURLU_GET_EMPTY, CURLUE_OK},
    591   /* WHATWG disgrees, it wants "https:/0.0.0.0/" */
    592   {"https://0x.0x.0", "https://0x.0x.0/", 0, 0, CURLUE_OK},
    593 
    594   {"https://example.com:000000000000000000000443/foo",
    595    "https://example.com/foo",
    596    0, CURLU_NO_DEFAULT_PORT, CURLUE_OK},
    597   {"https://example.com:000000000000000000000/foo",
    598    "https://example.com:0/foo",
    599    0, CURLU_NO_DEFAULT_PORT, CURLUE_OK},
    600   {"https://192.0x0000A80001", "https://192.168.0.1/", 0, 0, CURLUE_OK},
    601   {"https://0xffffffff", "https://255.255.255.255/", 0, 0, CURLUE_OK},
    602   {"https://1.0x1000000", "https://1.0x1000000/", 0, 0, CURLUE_OK},
    603   {"https://0x7f.1", "https://127.0.0.1/", 0, 0, CURLUE_OK},
    604   {"https://1.2.3.256.com", "https://1.2.3.256.com/", 0, 0, CURLUE_OK},
    605   {"https://10.com", "https://10.com/", 0, 0, CURLUE_OK},
    606   {"https://1.2.com", "https://1.2.com/", 0, 0, CURLUE_OK},
    607   {"https://1.2.3.com", "https://1.2.3.com/", 0, 0, CURLUE_OK},
    608   {"https://1.2.com.99", "https://1.2.com.99/", 0, 0, CURLUE_OK},
    609   {"https://[fe80::0000:20c:29ff:fe9c:409b]:80/moo",
    610    "https://[fe80::20c:29ff:fe9c:409b]:80/moo",
    611    0, 0, CURLUE_OK},
    612   {"https://[fe80::020c:29ff:fe9c:409b]:80/moo",
    613    "https://[fe80::20c:29ff:fe9c:409b]:80/moo",
    614    0, 0, CURLUE_OK},
    615   {"https://[fe80:0000:0000:0000:020c:29ff:fe9c:409b]:80/moo",
    616    "https://[fe80::20c:29ff:fe9c:409b]:80/moo",
    617    0, 0, CURLUE_OK},
    618   {"https://[fe80:0:0:0:409b::]:80/moo",
    619    "https://[fe80::409b:0:0:0]:80/moo",
    620    0, 0, CURLUE_OK},
    621   /* normalize to lower case */
    622   {"https://[FE80:0:A:0:409B:0:0:0]:80/moo",
    623    "https://[fe80:0:a:0:409b::]:80/moo",
    624    0, 0, CURLUE_OK},
    625   {"https://[::%25fakeit];80/moo",
    626    "",
    627    0, 0, CURLUE_BAD_PORT_NUMBER},
    628   {"https://[fe80::20c:29ff:fe9c:409b]-80/moo",
    629    "",
    630    0, 0, CURLUE_BAD_PORT_NUMBER},
    631 #ifdef USE_IDN
    632   {"https://r\xc3\xa4ksm\xc3\xb6rg\xc3\xa5s.se/path?q#frag",
    633    "https://xn--rksmrgs-5wao1o.se/path?q#frag", 0, CURLU_PUNYCODE, CURLUE_OK},
    634 #endif
    635   /* unsupported schemes with no guessing enabled */
    636   {"data:text/html;charset=utf-8;base64,PCFET0NUWVBFIEhUTUw+PG1ldGEgY",
    637    "", 0, 0, CURLUE_UNSUPPORTED_SCHEME},
    638   {"d:anything-really", "", 0, 0, CURLUE_UNSUPPORTED_SCHEME},
    639   {"about:config", "", 0, 0, CURLUE_UNSUPPORTED_SCHEME},
    640   {"example://foo", "", 0, 0, CURLUE_UNSUPPORTED_SCHEME},
    641   {"mailto:infobot@example.com?body=send%20current-issue", "", 0, 0,
    642    CURLUE_UNSUPPORTED_SCHEME},
    643   {"about:80", "https://about:80/", CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
    644   /* percent encoded host names */
    645   {"http://example.com%40127.0.0.1/", "", 0, 0, CURLUE_BAD_HOSTNAME},
    646   {"http://example.com%21127.0.0.1/", "", 0, 0, CURLUE_BAD_HOSTNAME},
    647   {"http://example.com%3f127.0.0.1/", "", 0, 0, CURLUE_BAD_HOSTNAME},
    648   {"http://example.com%23127.0.0.1/", "", 0, 0, CURLUE_BAD_HOSTNAME},
    649   {"http://example.com%3a127.0.0.1/", "", 0, 0, CURLUE_BAD_HOSTNAME},
    650   {"http://example.com%09127.0.0.1/", "", 0, 0, CURLUE_BAD_HOSTNAME},
    651   {"http://example.com%2F127.0.0.1/", "", 0, 0, CURLUE_BAD_HOSTNAME},
    652   {"https://%41", "https://A/", 0, 0, CURLUE_OK},
    653   {"https://%20", "", 0, 0, CURLUE_BAD_HOSTNAME},
    654   {"https://%41%0D", "", 0, 0, CURLUE_BAD_HOSTNAME},
    655   {"https://%25", "", 0, 0, CURLUE_BAD_HOSTNAME},
    656   {"https://_%c0_", "https://_\xC0_/", 0, 0, CURLUE_OK},
    657   {"https://_%c0_", "https://_%C0_/", 0, CURLU_URLENCODE, CURLUE_OK},
    658 
    659   /* IPv4 trickeries */
    660   {"https://16843009", "https://1.1.1.1/", 0, 0, CURLUE_OK},
    661   {"https://0177.1", "https://127.0.0.1/", 0, 0, CURLUE_OK},
    662   {"https://0111.02.0x3", "https://73.2.0.3/", 0, 0, CURLUE_OK},
    663   {"https://0111.02.0x3.", "https://0111.02.0x3./", 0, 0, CURLUE_OK},
    664   {"https://0111.02.030", "https://73.2.0.24/", 0, 0, CURLUE_OK},
    665   {"https://0111.02.030.", "https://0111.02.030./", 0, 0, CURLUE_OK},
    666   {"https://0xff.0xff.0377.255", "https://255.255.255.255/", 0, 0, CURLUE_OK},
    667   {"https://1.0xffffff", "https://1.255.255.255/", 0, 0, CURLUE_OK},
    668   /* IPv4 numerical overflows or syntax errors will not normalize */
    669   {"https://a127.0.0.1", "https://a127.0.0.1/", 0, 0, CURLUE_OK},
    670   {"https://\xff.127.0.0.1", "https://%FF.127.0.0.1/", 0, CURLU_URLENCODE,
    671    CURLUE_OK},
    672   {"https://127.-0.0.1", "https://127.-0.0.1/", 0, 0, CURLUE_OK},
    673   {"https://127.0. 1", "https://127.0.0.1/", 0, 0, CURLUE_MALFORMED_INPUT},
    674   {"https://1.2.3.256", "https://1.2.3.256/", 0, 0, CURLUE_OK},
    675   {"https://1.2.3.256.", "https://1.2.3.256./", 0, 0, CURLUE_OK},
    676   {"https://1.2.3.4.5", "https://1.2.3.4.5/", 0, 0, CURLUE_OK},
    677   {"https://1.2.0x100.3", "https://1.2.0x100.3/", 0, 0, CURLUE_OK},
    678   {"https://4294967296", "https://4294967296/", 0, 0, CURLUE_OK},
    679   {"https://123host", "https://123host/", 0, 0, CURLUE_OK},
    680   /* 40 bytes scheme is the max allowed */
    681   {"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA://hostname/path",
    682    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa://hostname/path",
    683    CURLU_NON_SUPPORT_SCHEME, 0, CURLUE_OK},
    684   /* 41 bytes scheme is not allowed */
    685   {"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA://hostname/path",
    686    "",
    687    CURLU_NON_SUPPORT_SCHEME, 0, CURLUE_BAD_SCHEME},
    688   {"https://[fe80::20c:29ff:fe9c:409b%]:1234",
    689    "",
    690    0, 0, CURLUE_BAD_IPV6},
    691   {"https://[fe80::20c:29ff:fe9c:409b%25]:1234",
    692    "https://[fe80::20c:29ff:fe9c:409b%2525]:1234/",
    693    0, 0, CURLUE_OK},
    694   {"https://[fe80::20c:29ff:fe9c:409b%eth0]:1234",
    695    "https://[fe80::20c:29ff:fe9c:409b%25eth0]:1234/",
    696    0, 0, CURLUE_OK},
    697   {"https://[::%25fakeit]/moo",
    698    "https://[::%25fakeit]/moo",
    699    0, 0, CURLUE_OK},
    700   {"smtp.example.com/path/html",
    701    "smtp://smtp.example.com/path/html",
    702    CURLU_GUESS_SCHEME, 0, CURLUE_OK},
    703   {"https.example.com/path/html",
    704    "http://https.example.com/path/html",
    705    CURLU_GUESS_SCHEME, 0, CURLUE_OK},
    706   {"dict.example.com/path/html",
    707    "dict://dict.example.com/path/html",
    708    CURLU_GUESS_SCHEME, 0, CURLUE_OK},
    709   {"pop3.example.com/path/html",
    710    "pop3://pop3.example.com/path/html",
    711    CURLU_GUESS_SCHEME, 0, CURLUE_OK},
    712   {"ldap.example.com/path/html",
    713    "ldap://ldap.example.com/path/html",
    714    CURLU_GUESS_SCHEME, 0, CURLUE_OK},
    715   {"imap.example.com/path/html",
    716    "imap://imap.example.com/path/html",
    717    CURLU_GUESS_SCHEME, 0, CURLUE_OK},
    718   {"ftp.example.com/path/html",
    719    "ftp://ftp.example.com/path/html",
    720    CURLU_GUESS_SCHEME, 0, CURLUE_OK},
    721   {"example.com/path/html",
    722    "http://example.com/path/html",
    723    CURLU_GUESS_SCHEME, 0, CURLUE_OK},
    724   {"smtp.com/path/html",
    725    "smtp://smtp.com/path/html",
    726    CURLU_GUESS_SCHEME, 0, CURLUE_OK},
    727   {"dict.com/path/html",
    728    "dict://dict.com/path/html",
    729    CURLU_GUESS_SCHEME, 0, CURLUE_OK},
    730   {"pop3.com/path/html",
    731    "pop3://pop3.com/path/html",
    732    CURLU_GUESS_SCHEME, 0, CURLUE_OK},
    733   {"ldap.com/path/html",
    734    "ldap://ldap.com/path/html",
    735    CURLU_GUESS_SCHEME, 0, CURLUE_OK},
    736   {"imap.com/path/html",
    737    "imap://imap.com/path/html",
    738    CURLU_GUESS_SCHEME, 0, CURLUE_OK},
    739   {"ftp.com/path/html",
    740    "ftp://ftp.com/path/html",
    741    CURLU_GUESS_SCHEME, 0, CURLUE_OK},
    742   {"smtp/path/html",
    743    "http://smtp/path/html",
    744    CURLU_GUESS_SCHEME, 0, CURLUE_OK},
    745   {"dict/path/html",
    746    "http://dict/path/html",
    747    CURLU_GUESS_SCHEME, 0, CURLUE_OK},
    748   {"pop3/path/html",
    749    "http://pop3/path/html",
    750    CURLU_GUESS_SCHEME, 0, CURLUE_OK},
    751   {"ldap/path/html",
    752    "http://ldap/path/html",
    753    CURLU_GUESS_SCHEME, 0, CURLUE_OK},
    754   {"imap/path/html",
    755    "http://imap/path/html",
    756    CURLU_GUESS_SCHEME, 0, CURLUE_OK},
    757   {"ftp/path/html",
    758    "http://ftp/path/html",
    759    CURLU_GUESS_SCHEME, 0, CURLUE_OK},
    760   {"HTTP://test/", "http://test/", 0, 0, CURLUE_OK},
    761   {"http://HO0_-st..~./", "http://HO0_-st..~./", 0, 0, CURLUE_OK},
    762   {"http:/@example.com: 123/", "", 0, 0, CURLUE_MALFORMED_INPUT},
    763   {"http:/@example.com:123 /", "", 0, 0, CURLUE_MALFORMED_INPUT},
    764   {"http:/@example.com:123a/", "", 0, 0, CURLUE_BAD_PORT_NUMBER},
    765   {"http://host/file\r", "", 0, 0, CURLUE_MALFORMED_INPUT},
    766   {"http://host/file\n\x03", "", 0, 0, CURLUE_MALFORMED_INPUT},
    767   {"htt\x02://host/file", "",
    768    CURLU_NON_SUPPORT_SCHEME, 0, CURLUE_MALFORMED_INPUT},
    769   {" http://host/file", "", 0, 0, CURLUE_MALFORMED_INPUT},
    770   /* here the password ends at the semicolon and options is 'word' */
    771   {"imap://user:pass;word@host/file",
    772    "imap://user:pass;word@host/file",
    773    0, 0, CURLUE_OK},
    774   /* here the password has the semicolon */
    775   {"http://user:pass;word@host/file",
    776    "http://user:pass;word@host/file", 0, 0, CURLUE_OK},
    777   {"file:///file.txt#moo", "file:///file.txt#moo", 0, 0, CURLUE_OK},
    778   {"file:////file.txt", "file:////file.txt", 0, 0, CURLUE_OK},
    779   {"file:///file.txt", "file:///file.txt", 0, 0, CURLUE_OK},
    780   {"file:./", "file://", 0, 0, CURLUE_OK},
    781   {"http://example.com/hello/../here",
    782    "http://example.com/hello/../here",
    783    CURLU_PATH_AS_IS, 0, CURLUE_OK},
    784   {"http://example.com/hello/../here",
    785    "http://example.com/here",
    786    0, 0, CURLUE_OK},
    787   {"http://example.com:80",
    788    "http://example.com/",
    789    0, CURLU_NO_DEFAULT_PORT, CURLUE_OK},
    790   {"tp://example.com/path/html",
    791    "",
    792    0, 0, CURLUE_UNSUPPORTED_SCHEME},
    793   {"http://hello:fool@example.com",
    794    "",
    795    CURLU_DISALLOW_USER, 0, CURLUE_USER_NOT_ALLOWED},
    796   {"http:/@example.com:123",
    797    "http://@example.com:123/",
    798    0, 0, CURLUE_OK},
    799   {"http:/:password@example.com",
    800    "http://:password@example.com/",
    801    0, 0, CURLUE_OK},
    802   {"http://user@example.com?#",
    803    "http://user@example.com/",
    804    0, 0, CURLUE_OK},
    805   {"http://user@example.com?",
    806    "http://user@example.com/",
    807    0, 0, CURLUE_OK},
    808   {"http://user@example.com#anchor",
    809    "http://user@example.com/#anchor",
    810    0, 0, CURLUE_OK},
    811   {"example.com/path/html",
    812    "https://example.com/path/html",
    813    CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
    814   {"example.com/path/html",
    815    "",
    816    0, 0, CURLUE_BAD_SCHEME},
    817   {"http://user:password@example.com:1234/path/html?query=name#anchor",
    818    "http://user:password@example.com:1234/path/html?query=name#anchor",
    819    0, 0, CURLUE_OK},
    820   {"http://example.com:1234/path/html?query=name#anchor",
    821    "http://example.com:1234/path/html?query=name#anchor",
    822    0, 0, CURLUE_OK},
    823   {"http://example.com/path/html?query=name#anchor",
    824    "http://example.com/path/html?query=name#anchor",
    825    0, 0, CURLUE_OK},
    826   {"http://example.com/path/html?query=name",
    827    "http://example.com/path/html?query=name",
    828    0, 0, CURLUE_OK},
    829   {"http://example.com/path/html",
    830    "http://example.com/path/html",
    831    0, 0, CURLUE_OK},
    832   {"tp://example.com/path/html",
    833    "tp://example.com/path/html",
    834    CURLU_NON_SUPPORT_SCHEME, 0, CURLUE_OK},
    835   {"custom-scheme://host?expected=test-good",
    836    "custom-scheme://host/?expected=test-good",
    837    CURLU_NON_SUPPORT_SCHEME, 0, CURLUE_OK},
    838   {"custom-scheme://?expected=test-bad",
    839    "",
    840    CURLU_NON_SUPPORT_SCHEME, 0, CURLUE_NO_HOST},
    841   {"custom-scheme://?expected=test-new-good",
    842    "custom-scheme:///?expected=test-new-good",
    843    CURLU_NON_SUPPORT_SCHEME | CURLU_NO_AUTHORITY, 0, CURLUE_OK},
    844   {"custom-scheme://host?expected=test-still-good",
    845    "custom-scheme://host/?expected=test-still-good",
    846    CURLU_NON_SUPPORT_SCHEME | CURLU_NO_AUTHORITY, 0, CURLUE_OK},
    847   {NULL, NULL, 0, 0, CURLUE_OK}
    848 };
    849 
    850 static int checkurl(const char *org, const char *url, const char *out)
    851 {
    852   if(strcmp(out, url)) {
    853     curl_mfprintf(stderr,
    854                   "Org:    %s\n"
    855                   "Wanted: %s\n"
    856                   "Got   : %s\n",
    857                   org, out, url);
    858     return 1;
    859   }
    860   return 0;
    861 }
    862 
    863 /* 1. Set the URL
    864    2. Set components
    865    3. Extract all components (not URL)
    866 */
    867 static const struct setgetcase setget_parts_list[] = {
    868   {"https://example.com/",
    869    "query=\"\",",
    870    "https | [11] | [12] | [13] | example.com | [15] | / |  | [17]",
    871    0, 0, CURLU_GET_EMPTY, CURLUE_OK},
    872   {"https://example.com/",
    873    "fragment=\"\",",
    874    "https | [11] | [12] | [13] | example.com | [15] | / | [16] | ",
    875    0, 0, CURLU_GET_EMPTY, CURLUE_OK},
    876   {"https://example.com/",
    877    "query=\"\",",
    878    "https | [11] | [12] | [13] | example.com | [15] | / | [16] | [17]",
    879    0, 0, 0, CURLUE_OK},
    880   {"https://example.com",
    881    "path=get,",
    882    "https | [11] | [12] | [13] | example.com | [15] | /get | [16] | [17]",
    883    0, 0, 0, CURLUE_OK},
    884   {"https://example.com",
    885    "path=/get,",
    886    "https | [11] | [12] | [13] | example.com | [15] | /get | [16] | [17]",
    887    0, 0, 0, CURLUE_OK},
    888   {"https://example.com",
    889    "path=g e t,",
    890    "https | [11] | [12] | [13] | example.com | [15] | /g%20e%20t | "
    891    "[16] | [17]",
    892    0, CURLU_URLENCODE, 0, CURLUE_OK},
    893   {NULL, NULL, NULL, 0, 0, 0, CURLUE_OK}
    894 };
    895 
    896 /* !checksrc! disable SPACEBEFORECOMMA 1 */
    897 static const struct setcase set_parts_list[] = {
    898   {NULL, /* start fresh! */
    899    "scheme=https,path=/,url=\"\",", /* incomplete url, redirect to "" */
    900    "https://example.com/",
    901    0, 0, CURLUE_OK, CURLUE_MALFORMED_INPUT},
    902   {NULL, /* start fresh! */
    903    "scheme=https,host=example.com,path=/,url=\"\",", /* redirect to "" */
    904    "https://example.com/",
    905    0, 0, CURLUE_OK, CURLUE_OK},
    906   {"https://example.com/",
    907    "path=one\ntwo,",
    908    "https://example.com/one\ntwo",
    909    0, 0, CURLUE_OK, CURLUE_OK},
    910   {"https://example.com/",
    911    "path=one\rtwo,",
    912    "https://example.com/one\rtwo",
    913    0, 0, CURLUE_OK, CURLUE_OK},
    914   {"https://example.com/",
    915    "path=one\ntwo,",
    916    "https://example.com/one%0Atwo",
    917    0, CURLU_URLENCODE, CURLUE_OK, CURLUE_OK},
    918   {"https://example.com/",
    919    "path=one\rtwo,",
    920    "https://example.com/one%0Dtwo",
    921    0, CURLU_URLENCODE, CURLUE_OK, CURLUE_OK},
    922   {"https://example.com/",
    923    "host=%43url.se,",
    924    "https://%43url.se/",
    925    0, 0, CURLUE_OK, CURLUE_OK},
    926   {"https://example.com/",
    927    "host=%25url.se,",
    928    "",
    929    0, 0, CURLUE_OK, CURLUE_BAD_HOSTNAME},
    930   {"https://example.com/?param=value",
    931    "query=\"\",",
    932    "https://example.com/",
    933    0, CURLU_APPENDQUERY | CURLU_URLENCODE, CURLUE_OK, CURLUE_OK},
    934   {"https://example.com/",
    935    "host=\"\",",
    936    "https://example.com/",
    937    0, CURLU_URLENCODE, CURLUE_OK, CURLUE_BAD_HOSTNAME},
    938   {"https://example.com/",
    939    "host=\"\",",
    940    "https://example.com/",
    941    0, 0, CURLUE_OK, CURLUE_BAD_HOSTNAME},
    942   {"https://example.com",
    943    "path=get,",
    944    "https://example.com/get",
    945    0, 0, CURLUE_OK, CURLUE_OK},
    946   {"https://example.com/",
    947    "scheme=ftp+-.123,",
    948    "ftp+-.123://example.com/",
    949    0, CURLU_NON_SUPPORT_SCHEME, CURLUE_OK, CURLUE_OK},
    950   {"https://example.com/",
    951    "scheme=1234,",
    952    "https://example.com/",
    953    0, CURLU_NON_SUPPORT_SCHEME, CURLUE_OK, CURLUE_BAD_SCHEME},
    954   {"https://example.com/",
    955    "scheme=1http,",
    956    "https://example.com/",
    957    0, CURLU_NON_SUPPORT_SCHEME, CURLUE_OK, CURLUE_BAD_SCHEME},
    958   {"https://example.com/",
    959    "scheme=-ftp,",
    960    "https://example.com/",
    961    0, CURLU_NON_SUPPORT_SCHEME, CURLUE_OK, CURLUE_BAD_SCHEME},
    962   {"https://example.com/",
    963    "scheme=+ftp,",
    964    "https://example.com/",
    965    0, CURLU_NON_SUPPORT_SCHEME, CURLUE_OK, CURLUE_BAD_SCHEME},
    966   {"https://example.com/",
    967    "scheme=.ftp,",
    968    "https://example.com/",
    969    0, CURLU_NON_SUPPORT_SCHEME, CURLUE_OK, CURLUE_BAD_SCHEME},
    970   {"https://example.com/",
    971    "host=example.com%2fmoo,",
    972    "",
    973    0, /* get */
    974    0, /* set */
    975    CURLUE_OK, CURLUE_BAD_HOSTNAME},
    976   {"https://example.com/",
    977    "host=http://fake,",
    978    "",
    979    0, /* get */
    980    0, /* set */
    981    CURLUE_OK, CURLUE_BAD_HOSTNAME},
    982   {"https://example.com/",
    983    "host=test%,",
    984    "",
    985    0, /* get */
    986    0, /* set */
    987    CURLUE_OK, CURLUE_BAD_HOSTNAME},
    988   {"https://example.com/",
    989    "host=te st,",
    990    "",
    991    0, /* get */
    992    0, /* set */
    993    CURLUE_OK, CURLUE_BAD_HOSTNAME},
    994   {"https://example.com/",
    995    "host=0xff,", /* '++' there's no automatic URL decode when setting this
    996                   part */
    997    "https://0xff/",
    998    0, /* get */
    999    0, /* set */
   1000    CURLUE_OK, CURLUE_OK},
   1001 
   1002   {"https://example.com/",
   1003    "query=Al2cO3tDkcDZ3EWE5Lh+LX8TPHs,", /* contains '+' */
   1004    "https://example.com/?Al2cO3tDkcDZ3EWE5Lh%2BLX8TPHs",
   1005    CURLU_URLDECODE, /* decode on get */
   1006    CURLU_URLENCODE, /* encode on set */
   1007    CURLUE_OK, CURLUE_OK},
   1008 
   1009   {"https://example.com/",
   1010    /* Set a bad scheme *including* :// */
   1011    "scheme=https://,",
   1012    "https://example.com/",
   1013    0, CURLU_NON_SUPPORT_SCHEME, CURLUE_OK, CURLUE_BAD_SCHEME},
   1014   {"https://example.com/",
   1015    /* Set a 41 bytes scheme. That's too long so the old scheme remains set. */
   1016    "scheme=bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbc,",
   1017    "https://example.com/",
   1018    0, CURLU_NON_SUPPORT_SCHEME, CURLUE_OK, CURLUE_BAD_SCHEME},
   1019   {"https://example.com/",
   1020    /* set a 40 bytes scheme */
   1021    "scheme=bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb,",
   1022    "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb://example.com/",
   1023    0, CURLU_NON_SUPPORT_SCHEME, CURLUE_OK, CURLUE_OK},
   1024   {"https://[::1%25fake]:1234/",
   1025    "zoneid=NULL,",
   1026    "https://[::1]:1234/",
   1027    0, 0, CURLUE_OK, CURLUE_OK},
   1028   {"https://host:1234/",
   1029    "port=NULL,",
   1030    "https://host/",
   1031    0, 0, CURLUE_OK, CURLUE_OK},
   1032   {"https://host:1234/",
   1033    "port=\"\",",
   1034    "https://host:1234/",
   1035    0, 0, CURLUE_OK, CURLUE_BAD_PORT_NUMBER},
   1036   {"https://host:1234/",
   1037    "port=56 78,",
   1038    "https://host:1234/",
   1039    0, 0, CURLUE_OK, CURLUE_BAD_PORT_NUMBER},
   1040   {"https://host:1234/",
   1041    "port=0,",
   1042    "https://host:0/",
   1043    0, 0, CURLUE_OK, CURLUE_OK},
   1044   {"https://host:1234/",
   1045    "port=65535,",
   1046    "https://host:65535/",
   1047    0, 0, CURLUE_OK, CURLUE_OK},
   1048   {"https://host:1234/",
   1049    "port=65536,",
   1050    "https://host:1234/",
   1051    0, 0, CURLUE_OK, CURLUE_BAD_PORT_NUMBER},
   1052   {"https://host/",
   1053    "path=%4A%4B%4C,",
   1054    "https://host/%4a%4b%4c",
   1055    0, 0, CURLUE_OK, CURLUE_OK},
   1056   {"https://host/mooo?q#f",
   1057    "path=NULL,query=NULL,fragment=NULL,",
   1058    "https://host/",
   1059    0, 0, CURLUE_OK, CURLUE_OK},
   1060   {"https://user:secret@host/",
   1061    "user=NULL,password=NULL,",
   1062    "https://host/",
   1063    0, 0, CURLUE_OK, CURLUE_OK},
   1064   {NULL,
   1065    "scheme=https,user=   @:,host=foobar,",
   1066    "https://%20%20%20%40%3A@foobar/",
   1067    0, CURLU_URLENCODE, CURLUE_OK, CURLUE_OK},
   1068   /* Setting a host name with spaces is not OK: */
   1069   {NULL,
   1070    "scheme=https,host=  ,path= ,user= ,password= ,query= ,fragment= ,",
   1071    "[nothing]",
   1072    0, CURLU_URLENCODE, CURLUE_OK, CURLUE_BAD_HOSTNAME},
   1073   {NULL,
   1074    "scheme=https,host=foobar,path=/this /path /is /here,",
   1075    "https://foobar/this%20/path%20/is%20/here",
   1076    0, CURLU_URLENCODE, CURLUE_OK, CURLUE_OK},
   1077   {NULL,
   1078    "scheme=https,host=foobar,path=\xc3\xa4\xc3\xb6\xc3\xbc,",
   1079    "https://foobar/%C3%A4%C3%B6%C3%BC",
   1080    0, CURLU_URLENCODE, CURLUE_OK, CURLUE_OK},
   1081   {"imap://user:secret;opt@host/",
   1082    "options=updated,scheme=imaps,password=p4ssw0rd,",
   1083    "imaps://user:p4ssw0rd;updated@host/",
   1084    0, 0, CURLUE_NO_HOST, CURLUE_OK},
   1085   {"imap://user:secret;optit@host/",
   1086    "scheme=https,",
   1087    "https://user:secret@host/",
   1088    0, 0, CURLUE_NO_HOST, CURLUE_OK},
   1089   {"file:///file#anchor",
   1090    "scheme=https,host=example,",
   1091    "https://example/file#anchor",
   1092    0, 0, CURLUE_NO_HOST, CURLUE_OK},
   1093   {NULL, /* start fresh! */
   1094    "scheme=file,host=127.0.0.1,path=/no,user=anonymous,",
   1095    "file:///no",
   1096    0, 0, CURLUE_OK, CURLUE_OK},
   1097   {NULL, /* start fresh! */
   1098    "scheme=ftp,host=127.0.0.1,path=/no,user=anonymous,",
   1099    "ftp://anonymous@127.0.0.1/no",
   1100    0, 0, CURLUE_OK, CURLUE_OK},
   1101   {NULL, /* start fresh! */
   1102    "scheme=https,host=example.com,",
   1103    "https://example.com/",
   1104    0, CURLU_NON_SUPPORT_SCHEME, CURLUE_OK, CURLUE_OK},
   1105   {"http://user:foo@example.com/path?query#frag",
   1106    "fragment=changed,",
   1107    "http://user:foo@example.com/path?query#changed",
   1108    0, CURLU_NON_SUPPORT_SCHEME, CURLUE_OK, CURLUE_OK},
   1109   {"http://example.com/",
   1110    "scheme=foo,", /* not accepted */
   1111    "http://example.com/",
   1112    0, 0, CURLUE_OK, CURLUE_UNSUPPORTED_SCHEME},
   1113   {"http://example.com/",
   1114    "scheme=https,path=/hello,fragment=snippet,",
   1115    "https://example.com/hello#snippet",
   1116    0, 0, CURLUE_OK, CURLUE_OK},
   1117   {"http://example.com:80",
   1118    "user=foo,port=1922,",
   1119    "http://foo@example.com:1922/",
   1120    0, 0, CURLUE_OK, CURLUE_OK},
   1121   {"http://example.com:80",
   1122    "user=foo,password=bar,",
   1123    "http://foo:bar@example.com:80/",
   1124    0, 0, CURLUE_OK, CURLUE_OK},
   1125   {"http://example.com:80",
   1126    "user=foo,",
   1127    "http://foo@example.com:80/",
   1128    0, 0, CURLUE_OK, CURLUE_OK},
   1129   {"http://example.com",
   1130    "host=www.example.com,",
   1131    "http://www.example.com/",
   1132    0, 0, CURLUE_OK, CURLUE_OK},
   1133   {"http://example.com:80",
   1134    "scheme=ftp,",
   1135    "ftp://example.com:80/",
   1136    0, 0, CURLUE_OK, CURLUE_OK},
   1137   {"custom-scheme://host",
   1138    "host=\"\",",
   1139    "custom-scheme://host/",
   1140    CURLU_NON_SUPPORT_SCHEME, CURLU_NON_SUPPORT_SCHEME, CURLUE_OK,
   1141    CURLUE_BAD_HOSTNAME},
   1142   {"custom-scheme://host",
   1143    "host=\"\",",
   1144    "custom-scheme:///",
   1145    CURLU_NON_SUPPORT_SCHEME, CURLU_NON_SUPPORT_SCHEME | CURLU_NO_AUTHORITY,
   1146    CURLUE_OK, CURLUE_OK},
   1147 
   1148   {NULL, NULL, NULL, 0, 0, CURLUE_OK, CURLUE_OK}
   1149 };
   1150 
   1151 static CURLUPart part2id(char *part)
   1152 {
   1153   if(!strcmp("url", part))
   1154     return CURLUPART_URL;
   1155   if(!strcmp("scheme", part))
   1156     return CURLUPART_SCHEME;
   1157   if(!strcmp("user", part))
   1158     return CURLUPART_USER;
   1159   if(!strcmp("password", part))
   1160     return CURLUPART_PASSWORD;
   1161   if(!strcmp("options", part))
   1162     return CURLUPART_OPTIONS;
   1163   if(!strcmp("host", part))
   1164     return CURLUPART_HOST;
   1165   if(!strcmp("port", part))
   1166     return CURLUPART_PORT;
   1167   if(!strcmp("path", part))
   1168     return CURLUPART_PATH;
   1169   if(!strcmp("query", part))
   1170     return CURLUPART_QUERY;
   1171   if(!strcmp("fragment", part))
   1172     return CURLUPART_FRAGMENT;
   1173   if(!strcmp("zoneid", part))
   1174     return CURLUPART_ZONEID;
   1175   /* NOLINTNEXTLINE(clang-analyzer-optin.core.EnumCastOutOfRange) */
   1176   return (CURLUPart)9999; /* bad input => bad output */
   1177 }
   1178 
   1179 static CURLUcode updateurl(CURLU *u, const char *cmd, unsigned int setflags)
   1180 {
   1181   const char *p = cmd;
   1182   CURLUcode uc;
   1183 
   1184   /* make sure the last command ends with a comma too! */
   1185   while(p) {
   1186     char *e = strchr(p, ',');
   1187     if(e) {
   1188       size_t n = (size_t)(e - p);
   1189       char buf[80];
   1190       char part[80];
   1191       char value[80];
   1192 
   1193       memset(part, 0, sizeof(part)); /* Avoid valgrind false positive. */
   1194       memset(value, 0, sizeof(value)); /* Avoid valgrind false positive. */
   1195       memcpy(buf, p, n);
   1196       buf[n] = 0;
   1197       if(2 == sscanf(buf, "%79[^=]=%79[^,]", part, value)) {
   1198         CURLUPart what = part2id(part);
   1199 #if 0
   1200         /* for debugging this */
   1201         curl_mfprintf(stderr, "%s = \"%s\" [%d]\n", part, value, (int)what);
   1202 #endif
   1203         if(what > CURLUPART_ZONEID)
   1204           curl_mfprintf(stderr, "UNKNOWN part '%s'\n", part);
   1205 
   1206         if(!strcmp("NULL", value))
   1207           uc = curl_url_set(u, what, NULL, setflags);
   1208         else if(!strcmp("\"\"", value))
   1209           uc = curl_url_set(u, what, "", setflags);
   1210         else
   1211           uc = curl_url_set(u, what, value, setflags);
   1212         if(uc)
   1213           return uc;
   1214       }
   1215       p = e + 1;
   1216       continue;
   1217     }
   1218     break;
   1219   }
   1220   return CURLUE_OK;
   1221 }
   1222 
   1223 static const struct redircase set_url_list[] = {
   1224   {"https://example.com",
   1225    "", /* blank redirect */
   1226    "https://example.com/",
   1227    0, 0, CURLUE_OK },
   1228   {"http://firstplace.example.com/want/1314",
   1229    "//somewhere.example.com/reply/1314",
   1230    "http://somewhere.example.com/reply/1314",
   1231    0, 0, CURLUE_OK },
   1232   {"http://127.0.0.1:46383/want?uri=http://anything/276?secondq/276",
   1233    "data/2760002.txt?coolsite=http://anotherurl/?a_second/2760002",
   1234    "http://127.0.0.1:46383/"
   1235    "data/2760002.txt?coolsite=http://anotherurl/?a_second/2760002",
   1236    0, 0, CURLUE_OK },
   1237   {"file:///basic#", "#yay",
   1238    "file:///basic#yay", 0, 0, CURLUE_OK},
   1239   {"file:///basic", "?yay",
   1240    "file:///basic?yay", 0, 0, CURLUE_OK},
   1241   {"file:///basic?", "?yay",
   1242    "file:///basic?yay", 0, 0, CURLUE_OK},
   1243   {"file:///basic?hello", "#frag",
   1244    "file:///basic?hello#frag", 0, 0, CURLUE_OK},
   1245   {"file:///basic?hello", "?q",
   1246    "file:///basic?q", 0, 0, CURLUE_OK},
   1247   {"http://example.org#withs/ash", "/moo#frag",
   1248    "http://example.org/moo#frag",
   1249    0, 0, CURLUE_OK},
   1250   {"http://example.org/", "../path/././../././../moo",
   1251    "http://example.org/moo",
   1252    0, 0, CURLUE_OK},
   1253   {"http://example.org/", ".%2e/path/././../%2E/./../moo",
   1254    "http://example.org/moo",
   1255    0, 0, CURLUE_OK},
   1256   {"http://example.org/", ".%2e/path/./%2e/.%2E/%2E/./%2e%2E/moo",
   1257    "http://example.org/moo",
   1258    0, 0, CURLUE_OK},
   1259 
   1260   {"http://example.org?bar/moo", "?weird",
   1261    "http://example.org/?weird", 0, 0, CURLUE_OK},
   1262   {"http://example.org/foo?bar", "?weird",
   1263    "http://example.org/foo?weird", 0, 0, CURLUE_OK},
   1264   {"http://example.org/foo", "?weird",
   1265    "http://example.org/foo?weird", 0, 0, CURLUE_OK},
   1266   {"http://example.org", "?weird",
   1267    "http://example.org/?weird", 0, 0, CURLUE_OK},
   1268   {"http://example.org/#original", "?weird#moo",
   1269    "http://example.org/?weird#moo", 0, 0, CURLUE_OK},
   1270 
   1271   {"http://example.org?bar/moo#yes/path", "#new/slash",
   1272    "http://example.org/?bar/moo#new/slash", 0, 0, CURLUE_OK},
   1273   {"http://example.org/foo?bar", "#weird",
   1274    "http://example.org/foo?bar#weird", 0, 0, CURLUE_OK},
   1275   {"http://example.org/foo?bar#original", "#weird",
   1276    "http://example.org/foo?bar#weird", 0, 0, CURLUE_OK},
   1277   {"http://example.org/foo#original", "#weird",
   1278    "http://example.org/foo#weird", 0, 0, CURLUE_OK},
   1279   {"http://example.org/#original", "#weird",
   1280    "http://example.org/#weird", 0, 0, CURLUE_OK},
   1281   {"http://example.org#original", "#weird",
   1282    "http://example.org/#weird", 0, 0, CURLUE_OK},
   1283   {"http://example.org/foo?bar", "moo?hey#weird",
   1284    "http://example.org/moo?hey#weird", 0, 0, CURLUE_OK},
   1285   {"http://example.org/",
   1286    "../path/././../../moo",
   1287    "http://example.org/moo",
   1288    0, 0, CURLUE_OK},
   1289   {"http://example.org/",
   1290    "//example.org/../path/../../",
   1291    "http://example.org/",
   1292    0, 0, CURLUE_OK},
   1293   {"http://example.org/",
   1294    "///example.org/../path/../../",
   1295    "http://example.org/",
   1296    0, 0, CURLUE_OK},
   1297   {"http://example.org/foo/bar",
   1298    ":23",
   1299    "http://example.org/foo/:23",
   1300    0, 0, CURLUE_OK},
   1301   {"http://example.org/foo/bar",
   1302    "\\x",
   1303    "http://example.org/foo/\\x",
   1304    /* WHATWG disagrees */
   1305    0, 0, CURLUE_OK},
   1306   {"http://example.org/foo/bar",
   1307    "#/",
   1308    "http://example.org/foo/bar#/",
   1309    0, 0, CURLUE_OK},
   1310   {"http://example.org/foo/bar",
   1311    "?/",
   1312    "http://example.org/foo/bar?/",
   1313    0, 0, CURLUE_OK},
   1314   {"http://example.org/foo/bar",
   1315    "#;?",
   1316    "http://example.org/foo/bar#;?",
   1317    0, 0, CURLUE_OK},
   1318   {"http://example.org/foo/bar",
   1319    "#",
   1320    "http://example.org/foo/bar",
   1321    /* This happens because the parser removes empty fragments */
   1322    0, 0, CURLUE_OK},
   1323   {"http://example.org/foo/bar",
   1324    "?",
   1325    "http://example.org/foo/bar",
   1326    /* This happens because the parser removes empty queries */
   1327    0, 0, CURLUE_OK},
   1328   {"http://example.org/foo/bar",
   1329    "?#",
   1330    "http://example.org/foo/bar",
   1331    /* This happens because the parser removes empty queries and fragments */
   1332    0, 0, CURLUE_OK},
   1333   {"http://example.com/please/../gimme/%TESTNUMBER?foobar#hello",
   1334    "http://example.net/there/it/is/../../tes t case=/%TESTNUMBER0002? yes no",
   1335    "http://example.net/there/tes%20t%20case=/%TESTNUMBER0002?+yes+no",
   1336    0, CURLU_URLENCODE|CURLU_ALLOW_SPACE, CURLUE_OK},
   1337   {"http://local.test?redirect=http://local.test:80?-321",
   1338    "http://local.test:80?-123",
   1339    "http://local.test:80/?-123",
   1340    0, CURLU_URLENCODE|CURLU_ALLOW_SPACE, CURLUE_OK},
   1341   {"http://local.test?redirect=http://local.test:80?-321",
   1342    "http://local.test:80?-123",
   1343    "http://local.test:80/?-123",
   1344    0, 0, CURLUE_OK},
   1345   {"http://example.org/static/favicon/wikipedia.ico",
   1346    "//fake.example.com/licenses/by-sa/3.0/",
   1347    "http://fake.example.com/licenses/by-sa/3.0/",
   1348    0, 0, CURLUE_OK},
   1349   {"https://example.org/static/favicon/wikipedia.ico",
   1350    "//fake.example.com/licenses/by-sa/3.0/",
   1351    "https://fake.example.com/licenses/by-sa/3.0/",
   1352    0, 0, CURLUE_OK},
   1353   {"file://localhost/path?query#frag",
   1354    "foo#another",
   1355    "file:///foo#another",
   1356    0, 0, CURLUE_OK},
   1357   {"http://example.com/path?query#frag",
   1358    "https://two.example.com/bradnew",
   1359    "https://two.example.com/bradnew",
   1360    0, 0, CURLUE_OK},
   1361   {"http://example.com/path?query#frag",
   1362    "../../newpage#foo",
   1363    "http://example.com/newpage#foo",
   1364    0, 0, CURLUE_OK},
   1365   {"http://user:foo@example.com/path?query#frag",
   1366    "../../newpage",
   1367    "http://user:foo@example.com/newpage",
   1368    0, 0, CURLUE_OK},
   1369   {"http://user:foo@example.com/path?query#frag",
   1370    "../newpage",
   1371    "http://user:foo@example.com/newpage",
   1372    0, 0, CURLUE_OK},
   1373   {"http://user:foo@example.com/path?query#frag",
   1374    "http://?hi",
   1375    "http:///?hi",
   1376    0, CURLU_NO_AUTHORITY, CURLUE_OK},
   1377   {NULL, NULL, NULL, 0, 0, CURLUE_OK}
   1378 };
   1379 
   1380 static int set_url(void)
   1381 {
   1382   int i;
   1383   int error = 0;
   1384 
   1385   for(i = 0; set_url_list[i].in && !error; i++) {
   1386     CURLUcode rc;
   1387     CURLU *urlp = curl_url();
   1388     if(!urlp)
   1389       break;
   1390     rc = curl_url_set(urlp, CURLUPART_URL, set_url_list[i].in,
   1391                       set_url_list[i].urlflags);
   1392     if(!rc) {
   1393       rc = curl_url_set(urlp, CURLUPART_URL, set_url_list[i].set,
   1394                         set_url_list[i].setflags);
   1395       if(rc) {
   1396         curl_mfprintf(stderr, "%s:%d Set URL %s returned %d (%s)\n",
   1397                       __FILE__, __LINE__, set_url_list[i].set,
   1398                       (int)rc, curl_url_strerror(rc));
   1399         error++;
   1400       }
   1401       else {
   1402         char *url = NULL;
   1403         rc = curl_url_get(urlp, CURLUPART_URL, &url, 0);
   1404         if(rc) {
   1405           curl_mfprintf(stderr, "%s:%d Get URL returned %d (%s)\n",
   1406                         __FILE__, __LINE__, (int)rc, curl_url_strerror(rc));
   1407           error++;
   1408         }
   1409         else {
   1410           if(checkurl(set_url_list[i].in, url, set_url_list[i].out)) {
   1411             error++;
   1412           }
   1413         }
   1414         curl_free(url);
   1415       }
   1416     }
   1417     else if(rc != set_url_list[i].ucode) {
   1418       curl_mfprintf(stderr, "Set URL\nin: %s\nreturned %d (expected %d)\n",
   1419                     set_url_list[i].in, (int)rc, set_url_list[i].ucode);
   1420       error++;
   1421     }
   1422     curl_url_cleanup(urlp);
   1423   }
   1424   return error;
   1425 }
   1426 
   1427 /* 1. Set a URL
   1428    2. Set one or more parts
   1429    3. Extract and compare all parts - not the URL
   1430 */
   1431 static int setget_parts(void)
   1432 {
   1433   int i;
   1434   int error = 0;
   1435 
   1436   for(i = 0; setget_parts_list[i].set && !error; i++) {
   1437     CURLUcode rc;
   1438     CURLU *urlp = curl_url();
   1439     if(!urlp) {
   1440       error++;
   1441       break;
   1442     }
   1443     if(setget_parts_list[i].in)
   1444       rc = curl_url_set(urlp, CURLUPART_URL, setget_parts_list[i].in,
   1445                         setget_parts_list[i].urlflags);
   1446     else
   1447       rc = CURLUE_OK;
   1448     if(!rc) {
   1449       char *url = NULL;
   1450       CURLUcode uc = updateurl(urlp, setget_parts_list[i].set,
   1451                                setget_parts_list[i].setflags);
   1452 
   1453       if(uc != setget_parts_list[i].pcode) {
   1454         curl_mfprintf(stderr, "updateurl\nin: %s\nreturned %d (expected %d)\n",
   1455                       setget_parts_list[i].set,
   1456                       (int)uc, setget_parts_list[i].pcode);
   1457         error++;
   1458       }
   1459       if(!uc) {
   1460         if(checkparts(urlp, setget_parts_list[i].set, setget_parts_list[i].out,
   1461                       setget_parts_list[i].getflags))
   1462           error++;        /* add */
   1463       }
   1464       curl_free(url);
   1465     }
   1466     else if(rc != CURLUE_OK) {
   1467       curl_mfprintf(stderr, "Set parts\nin: %s\nreturned %d (expected %d)\n",
   1468                     setget_parts_list[i].in, (int)rc, 0);
   1469       error++;
   1470     }
   1471     curl_url_cleanup(urlp);
   1472   }
   1473   return error;
   1474 }
   1475 
   1476 static int set_parts(void)
   1477 {
   1478   int i;
   1479   int error = 0;
   1480 
   1481   for(i = 0; set_parts_list[i].set && !error; i++) {
   1482     CURLUcode rc;
   1483     CURLU *urlp = curl_url();
   1484     if(!urlp) {
   1485       error++;
   1486       break;
   1487     }
   1488     if(set_parts_list[i].in)
   1489       rc = curl_url_set(urlp, CURLUPART_URL, set_parts_list[i].in,
   1490                         set_parts_list[i].urlflags);
   1491     else
   1492       rc = CURLUE_OK;
   1493     if(!rc) {
   1494       char *url = NULL;
   1495       CURLUcode uc = updateurl(urlp, set_parts_list[i].set,
   1496                                set_parts_list[i].setflags);
   1497 
   1498       if(uc != set_parts_list[i].pcode) {
   1499         curl_mfprintf(stderr, "updateurl\nin: %s\nreturned %d (expected %d)\n",
   1500                       set_parts_list[i].set, (int)uc, set_parts_list[i].pcode);
   1501         error++;
   1502       }
   1503       if(!uc) {
   1504         /* only do this if it worked */
   1505         rc = curl_url_get(urlp, CURLUPART_URL, &url, 0);
   1506 
   1507         if(rc) {
   1508           curl_mfprintf(stderr, "%s:%d Get URL returned %d (%s)\n",
   1509                         __FILE__, __LINE__, (int)rc, curl_url_strerror(rc));
   1510           error++;
   1511         }
   1512         else if(checkurl(set_parts_list[i].in, url, set_parts_list[i].out)) {
   1513           error++;
   1514         }
   1515       }
   1516       curl_free(url);
   1517     }
   1518     else if(rc != set_parts_list[i].ucode) {
   1519       curl_mfprintf(stderr, "Set parts\nin: %s\nreturned %d (expected %d)\n",
   1520                     set_parts_list[i].in, (int)rc, set_parts_list[i].ucode);
   1521       error++;
   1522     }
   1523     curl_url_cleanup(urlp);
   1524   }
   1525   return error;
   1526 }
   1527 
   1528 static int get_url(void)
   1529 {
   1530   int i;
   1531   int error = 0;
   1532   for(i = 0; get_url_list[i].in && !error; i++) {
   1533     CURLUcode rc;
   1534     CURLU *urlp = curl_url();
   1535     if(!urlp) {
   1536       error++;
   1537       break;
   1538     }
   1539     rc = curl_url_set(urlp, CURLUPART_URL, get_url_list[i].in,
   1540                       get_url_list[i].urlflags);
   1541     if(!rc) {
   1542       char *url = NULL;
   1543       rc = curl_url_get(urlp, CURLUPART_URL, &url, get_url_list[i].getflags);
   1544 
   1545       if(rc) {
   1546         curl_mfprintf(stderr, "%s:%d returned %d (%s). URL: '%s'\n",
   1547                       __FILE__, __LINE__, (int)rc, curl_url_strerror(rc),
   1548                       get_url_list[i].in);
   1549         error++;
   1550       }
   1551       else {
   1552         if(checkurl(get_url_list[i].in, url, get_url_list[i].out)) {
   1553           error++;
   1554         }
   1555       }
   1556       curl_free(url);
   1557     }
   1558     if(rc != get_url_list[i].ucode) {
   1559       curl_mfprintf(stderr, "Get URL\nin: %s\nreturned %d (expected %d)\n",
   1560                     get_url_list[i].in, (int)rc, get_url_list[i].ucode);
   1561       error++;
   1562     }
   1563     curl_url_cleanup(urlp);
   1564   }
   1565   return error;
   1566 }
   1567 
   1568 static int get_parts(void)
   1569 {
   1570   int i;
   1571   int error = 0;
   1572   for(i = 0; get_parts_list[i].in && !error; i++) {
   1573     CURLUcode rc;
   1574     CURLU *urlp = curl_url();
   1575     if(!urlp) {
   1576       error++;
   1577       break;
   1578     }
   1579     rc = curl_url_set(urlp, CURLUPART_URL,
   1580                       get_parts_list[i].in,
   1581                       get_parts_list[i].urlflags);
   1582     if(rc != get_parts_list[i].ucode) {
   1583       curl_mfprintf(stderr, "Get parts\nin: %s\nreturned %d (expected %d)\n",
   1584                     get_parts_list[i].in, (int)rc, get_parts_list[i].ucode);
   1585       error++;
   1586     }
   1587     else if(get_parts_list[i].ucode) {
   1588       /* the expected error happened */
   1589     }
   1590     else if(checkparts(urlp, get_parts_list[i].in, get_parts_list[i].out,
   1591                        get_parts_list[i].getflags))
   1592       error++;
   1593     curl_url_cleanup(urlp);
   1594   }
   1595   return error;
   1596 }
   1597 
   1598 static const struct querycase append_list[] = {
   1599   {"HTTP://test/?s", "name=joe\x02", "http://test/?s&name=joe%02",
   1600    0, CURLU_URLENCODE, CURLUE_OK},
   1601   {"HTTP://test/?size=2#f", "name=joe=", "http://test/?size=2&name=joe%3D#f",
   1602    0, CURLU_URLENCODE, CURLUE_OK},
   1603   {"HTTP://test/?size=2#f", "name=joe doe",
   1604    "http://test/?size=2&name=joe+doe#f",
   1605    0, CURLU_URLENCODE, CURLUE_OK},
   1606   {"HTTP://test/", "name=joe", "http://test/?name=joe", 0, 0, CURLUE_OK},
   1607   {"HTTP://test/?size=2", "name=joe", "http://test/?size=2&name=joe",
   1608    0, 0, CURLUE_OK},
   1609   {"HTTP://test/?size=2&", "name=joe", "http://test/?size=2&name=joe",
   1610    0, 0, CURLUE_OK},
   1611   {"HTTP://test/?size=2#f", "name=joe", "http://test/?size=2&name=joe#f",
   1612    0, 0, CURLUE_OK},
   1613   {NULL, NULL, NULL, 0, 0, CURLUE_OK}
   1614 };
   1615 
   1616 static int append(void)
   1617 {
   1618   int i;
   1619   int error = 0;
   1620   for(i = 0; append_list[i].in && !error; i++) {
   1621     CURLUcode rc;
   1622     CURLU *urlp = curl_url();
   1623     if(!urlp) {
   1624       error++;
   1625       break;
   1626     }
   1627     rc = curl_url_set(urlp, CURLUPART_URL,
   1628                       append_list[i].in,
   1629                       append_list[i].urlflags);
   1630     if(rc)
   1631       error++;
   1632     else
   1633       rc = curl_url_set(urlp, CURLUPART_QUERY,
   1634                         append_list[i].q,
   1635                         append_list[i].qflags | CURLU_APPENDQUERY);
   1636     if(error)
   1637       ;
   1638     else if(rc != append_list[i].ucode) {
   1639       curl_mfprintf(stderr, "Append\nin: %s\nreturned %d (expected %d)\n",
   1640                     append_list[i].in, (int)rc, append_list[i].ucode);
   1641       error++;
   1642     }
   1643     else if(append_list[i].ucode) {
   1644       /* the expected error happened */
   1645     }
   1646     else {
   1647       char *url;
   1648       rc = curl_url_get(urlp, CURLUPART_URL, &url, 0);
   1649       if(rc) {
   1650         curl_mfprintf(stderr, "%s:%d Get URL returned %d (%s)\n",
   1651                       __FILE__, __LINE__, (int)rc, curl_url_strerror(rc));
   1652         error++;
   1653       }
   1654       else {
   1655         if(checkurl(append_list[i].in, url, append_list[i].out)) {
   1656           error++;
   1657         }
   1658         curl_free(url);
   1659       }
   1660     }
   1661     curl_url_cleanup(urlp);
   1662   }
   1663   return error;
   1664 }
   1665 
   1666 static int scopeid(void)
   1667 {
   1668   CURLU *u = curl_url();
   1669   int error = 0;
   1670   CURLUcode rc;
   1671   char *url;
   1672 
   1673   rc = curl_url_set(u, CURLUPART_URL,
   1674                     "https://[fe80::20c:29ff:fe9c:409b%25eth0]/hello.html", 0);
   1675   if(rc != CURLUE_OK) {
   1676     curl_mfprintf(stderr, "%s:%d curl_url_set returned %d (%s)\n",
   1677                   __FILE__, __LINE__, (int)rc, curl_url_strerror(rc));
   1678     error++;
   1679   }
   1680 
   1681   rc = curl_url_get(u, CURLUPART_HOST, &url, 0);
   1682   if(rc != CURLUE_OK) {
   1683     curl_mfprintf(stderr,
   1684                   "%s:%d curl_url_get CURLUPART_HOST returned %d (%s)\n",
   1685                   __FILE__, __LINE__, (int)rc, curl_url_strerror(rc));
   1686     error++;
   1687   }
   1688   else {
   1689     curl_free(url);
   1690   }
   1691 
   1692   rc = curl_url_set(u, CURLUPART_HOST, "[::1]", 0);
   1693   if(rc != CURLUE_OK) {
   1694     curl_mfprintf(stderr,
   1695                   "%s:%d curl_url_set CURLUPART_HOST returned %d (%s)\n",
   1696                   __FILE__, __LINE__, (int)rc, curl_url_strerror(rc));
   1697     error++;
   1698   }
   1699 
   1700   rc = curl_url_get(u, CURLUPART_URL, &url, 0);
   1701   if(rc != CURLUE_OK) {
   1702     curl_mfprintf(stderr,
   1703                   "%s:%d curl_url_get CURLUPART_URL returned %d (%s)\n",
   1704                   __FILE__, __LINE__, (int)rc, curl_url_strerror(rc));
   1705     error++;
   1706   }
   1707   else {
   1708     curl_free(url);
   1709   }
   1710 
   1711   rc = curl_url_set(u, CURLUPART_HOST, "example.com", 0);
   1712   if(rc != CURLUE_OK) {
   1713     curl_mfprintf(stderr,
   1714                   "%s:%d curl_url_set CURLUPART_HOST returned %d (%s)\n",
   1715                   __FILE__, __LINE__, (int)rc, curl_url_strerror(rc));
   1716     error++;
   1717   }
   1718 
   1719   rc = curl_url_get(u, CURLUPART_URL, &url, 0);
   1720   if(rc != CURLUE_OK) {
   1721     curl_mfprintf(stderr,
   1722                   "%s:%d curl_url_get CURLUPART_URL returned %d (%s)\n",
   1723                   __FILE__, __LINE__, (int)rc, curl_url_strerror(rc));
   1724     error++;
   1725   }
   1726   else {
   1727     curl_free(url);
   1728   }
   1729 
   1730   rc = curl_url_set(u, CURLUPART_HOST,
   1731                     "[fe80::20c:29ff:fe9c:409b%25eth0]", 0);
   1732   if(rc != CURLUE_OK) {
   1733     curl_mfprintf(stderr,
   1734                   "%s:%d curl_url_set CURLUPART_HOST returned %d (%s)\n",
   1735                   __FILE__, __LINE__, (int)rc, curl_url_strerror(rc));
   1736     error++;
   1737   }
   1738 
   1739   rc = curl_url_get(u, CURLUPART_URL, &url, 0);
   1740   if(rc != CURLUE_OK) {
   1741     curl_mfprintf(stderr,
   1742                   "%s:%d curl_url_get CURLUPART_URL returned %d (%s)\n",
   1743                   __FILE__, __LINE__, (int)rc, curl_url_strerror(rc));
   1744     error++;
   1745   }
   1746   else {
   1747     curl_free(url);
   1748   }
   1749 
   1750   rc = curl_url_get(u, CURLUPART_HOST, &url, 0);
   1751   if(rc != CURLUE_OK) {
   1752     curl_mfprintf(stderr,
   1753                   "%s:%d curl_url_get CURLUPART_HOST returned %d (%s)\n",
   1754                   __FILE__, __LINE__, (int)rc, curl_url_strerror(rc));
   1755     error++;
   1756   }
   1757   else {
   1758     curl_free(url);
   1759   }
   1760 
   1761   rc = curl_url_get(u, CURLUPART_ZONEID, &url, 0);
   1762   if(rc != CURLUE_OK) {
   1763     curl_mfprintf(stderr,
   1764                   "%s:%d curl_url_get CURLUPART_ZONEID returned %d (%s)\n",
   1765                   __FILE__, __LINE__, (int)rc, curl_url_strerror(rc));
   1766     error++;
   1767   }
   1768   else {
   1769     curl_free(url);
   1770   }
   1771 
   1772   rc = curl_url_set(u, CURLUPART_ZONEID, "clown", 0);
   1773   if(rc != CURLUE_OK) {
   1774     curl_mfprintf(stderr,
   1775                   "%s:%d curl_url_set CURLUPART_ZONEID returned %d (%s)\n",
   1776                   __FILE__, __LINE__, (int)rc, curl_url_strerror(rc));
   1777     error++;
   1778   }
   1779 
   1780   rc = curl_url_get(u, CURLUPART_URL, &url, 0);
   1781   if(rc != CURLUE_OK) {
   1782     curl_mfprintf(stderr,
   1783                   "%s:%d curl_url_get CURLUPART_URL returned %d (%s)\n",
   1784                   __FILE__, __LINE__, (int)rc, curl_url_strerror(rc));
   1785     error++;
   1786   }
   1787   else {
   1788     curl_free(url);
   1789   }
   1790 
   1791   curl_url_cleanup(u);
   1792 
   1793   return error;
   1794 }
   1795 
   1796 static int get_nothing(void)
   1797 {
   1798   CURLU *u = curl_url();
   1799   if(u) {
   1800     char *p;
   1801     CURLUcode rc;
   1802 
   1803     rc = curl_url_get(u, CURLUPART_SCHEME, &p, 0);
   1804     if(rc != CURLUE_NO_SCHEME)
   1805       curl_mfprintf(stderr, "unexpected return code line %u\n", __LINE__);
   1806 
   1807     rc = curl_url_get(u, CURLUPART_HOST, &p, 0);
   1808     if(rc != CURLUE_NO_HOST)
   1809       curl_mfprintf(stderr, "unexpected return code line %u\n", __LINE__);
   1810 
   1811     rc = curl_url_get(u, CURLUPART_USER, &p, 0);
   1812     if(rc != CURLUE_NO_USER)
   1813       curl_mfprintf(stderr, "unexpected return code line %u\n", __LINE__);
   1814 
   1815     rc = curl_url_get(u, CURLUPART_PASSWORD, &p, 0);
   1816     if(rc != CURLUE_NO_PASSWORD)
   1817       curl_mfprintf(stderr, "unexpected return code line %u\n", __LINE__);
   1818 
   1819     rc = curl_url_get(u, CURLUPART_OPTIONS, &p, 0);
   1820     if(rc != CURLUE_NO_OPTIONS)
   1821       curl_mfprintf(stderr, "unexpected return code line %u\n", __LINE__);
   1822 
   1823     rc = curl_url_get(u, CURLUPART_PATH, &p, 0);
   1824     if(rc != CURLUE_OK)
   1825       curl_mfprintf(stderr, "unexpected return code line %u\n", __LINE__);
   1826     else
   1827       curl_free(p);
   1828 
   1829     rc = curl_url_get(u, CURLUPART_QUERY, &p, 0);
   1830     if(rc != CURLUE_NO_QUERY)
   1831       curl_mfprintf(stderr, "unexpected return code line %u\n", __LINE__);
   1832 
   1833     rc = curl_url_get(u, CURLUPART_FRAGMENT, &p, 0);
   1834     if(rc != CURLUE_NO_FRAGMENT)
   1835       curl_mfprintf(stderr, "unexpected return code line %u\n", __LINE__);
   1836 
   1837     rc = curl_url_get(u, CURLUPART_ZONEID, &p, 0);
   1838     if(rc != CURLUE_NO_ZONEID)
   1839       curl_mfprintf(stderr, "unexpected return code %u on line %u\n", (int)rc,
   1840                     __LINE__);
   1841 
   1842     curl_url_cleanup(u);
   1843   }
   1844   return 0;
   1845 }
   1846 
   1847 static const struct clearurlcase clear_url_list[] ={
   1848   {CURLUPART_SCHEME, "http", NULL, CURLUE_NO_SCHEME},
   1849   {CURLUPART_USER, "user", NULL, CURLUE_NO_USER},
   1850   {CURLUPART_PASSWORD, "password", NULL, CURLUE_NO_PASSWORD},
   1851   {CURLUPART_OPTIONS, "options", NULL, CURLUE_NO_OPTIONS},
   1852   {CURLUPART_HOST, "host", NULL, CURLUE_NO_HOST},
   1853   {CURLUPART_ZONEID, "eth0", NULL, CURLUE_NO_ZONEID},
   1854   {CURLUPART_PORT, "1234", NULL, CURLUE_NO_PORT},
   1855   {CURLUPART_PATH, "/hello", "/", CURLUE_OK},
   1856   {CURLUPART_QUERY, "a=b", NULL, CURLUE_NO_QUERY},
   1857   {CURLUPART_FRAGMENT, "anchor", NULL, CURLUE_NO_FRAGMENT},
   1858   {CURLUPART_URL, NULL, NULL, CURLUE_OK},
   1859 };
   1860 
   1861 static int clear_url(void)
   1862 {
   1863   CURLU *u = curl_url();
   1864   int i, error = 0;
   1865   if(u) {
   1866     char *p = NULL;
   1867     CURLUcode rc;
   1868 
   1869     for(i = 0; clear_url_list[i].in && !error; i++) {
   1870       rc = curl_url_set(u, clear_url_list[i].part, clear_url_list[i].in, 0);
   1871       if(rc != CURLUE_OK)
   1872         curl_mfprintf(stderr, "unexpected return code line %u\n", __LINE__);
   1873 
   1874       rc = curl_url_set(u, CURLUPART_URL, NULL, 0);
   1875       if(rc != CURLUE_OK)
   1876         curl_mfprintf(stderr, "unexpected return code line %u\n", __LINE__);
   1877 
   1878       rc = curl_url_get(u, clear_url_list[i].part, &p, 0);
   1879       if(rc != clear_url_list[i].ucode || (clear_url_list[i].out &&
   1880          0 != strcmp(p, clear_url_list[i].out))) {
   1881 
   1882         curl_mfprintf(stderr, "unexpected return code line %u\n", __LINE__);
   1883         error++;
   1884       }
   1885       if(rc == CURLUE_OK)
   1886         curl_free(p);
   1887     }
   1888   }
   1889 
   1890   curl_url_cleanup(u);
   1891 
   1892   return error;
   1893 }
   1894 
   1895 static char total[128000];
   1896 static char bigpart[120000];
   1897 
   1898 /*
   1899  * verify ridiculous URL part sizes
   1900  */
   1901 static int huge(void)
   1902 {
   1903   static const char *smallpart = "c";
   1904   int i;
   1905   CURLU *urlp = curl_url();
   1906   CURLUcode rc;
   1907   CURLUPart part[] = {
   1908     CURLUPART_SCHEME,
   1909     CURLUPART_USER,
   1910     CURLUPART_PASSWORD,
   1911     CURLUPART_HOST,
   1912     CURLUPART_PATH,
   1913     CURLUPART_QUERY,
   1914     CURLUPART_FRAGMENT
   1915   };
   1916   int error = 0;
   1917   if(!urlp)
   1918     return 1;
   1919   bigpart[0] = '/'; /* for the path */
   1920   memset(&bigpart[1], 'a', sizeof(bigpart) - 2);
   1921   bigpart[sizeof(bigpart) - 1] = 0;
   1922 
   1923   for(i = 0; i <  7; i++) {
   1924     char *partp;
   1925     curl_msnprintf(total, sizeof(total),
   1926                    "%s://%s:%s@%s/%s?%s#%s",
   1927                    (i == 0) ? &bigpart[1] : smallpart,
   1928                    (i == 1) ? &bigpart[1] : smallpart,
   1929                    (i == 2) ? &bigpart[1] : smallpart,
   1930                    (i == 3) ? &bigpart[1] : smallpart,
   1931                    (i == 4) ? &bigpart[1] : smallpart,
   1932                    (i == 5) ? &bigpart[1] : smallpart,
   1933                    (i == 6) ? &bigpart[1] : smallpart);
   1934     rc = curl_url_set(urlp, CURLUPART_URL, total, CURLU_NON_SUPPORT_SCHEME);
   1935     if((!i && (rc != CURLUE_BAD_SCHEME)) ||
   1936        (i && rc)) {
   1937       curl_mprintf("URL %u: failed to parse [%s]\n", i, total);
   1938       error++;
   1939     }
   1940 
   1941     /* only extract if the parse worked */
   1942     if(!rc) {
   1943       curl_url_get(urlp, part[i], &partp, 0);
   1944       if(!partp || strcmp(partp, &bigpart[1 - (i == 4)])) {
   1945         curl_mprintf("URL %u part %u: failure\n", i, part[i]);
   1946         error++;
   1947       }
   1948       curl_free(partp);
   1949     }
   1950   }
   1951   curl_url_cleanup(urlp);
   1952   return error;
   1953 }
   1954 
   1955 static int urldup(void)
   1956 {
   1957   static const char *url[] = {
   1958     "http://"
   1959     "user:pwd@"
   1960     "[2a04:4e42:e00::347%25eth0]"
   1961     ":80"
   1962     "/path"
   1963     "?query"
   1964     "#fraggie",
   1965     "https://example.com",
   1966     "https://user@example.com",
   1967     "https://user.pwd@example.com",
   1968     "https://user.pwd@example.com:1234",
   1969     "https://example.com:1234",
   1970     "example.com:1234",
   1971     "https://user.pwd@example.com:1234/path?query#frag",
   1972     NULL
   1973   };
   1974   CURLU *copy = NULL;
   1975   char *h_str = NULL, *copy_str = NULL;
   1976   CURLU *h = curl_url();
   1977   int i;
   1978 
   1979   if(!h)
   1980     goto err;
   1981 
   1982   for(i = 0; url[i]; i++) {
   1983     CURLUcode rc = curl_url_set(h, CURLUPART_URL, url[i],
   1984                                 CURLU_GUESS_SCHEME);
   1985     if(rc)
   1986       goto err;
   1987     copy = curl_url_dup(h);
   1988 
   1989     rc = curl_url_get(h, CURLUPART_URL, &h_str, 0);
   1990     if(rc)
   1991       goto err;
   1992 
   1993     rc = curl_url_get(copy, CURLUPART_URL, &copy_str, 0);
   1994     if(rc)
   1995       goto err;
   1996 
   1997     if(strcmp(h_str, copy_str)) {
   1998       curl_mprintf("Original:  %s\nParsed:    %s\nCopy:      %s\n",
   1999                    url[i], h_str, copy_str);
   2000       goto err;
   2001     }
   2002     curl_free(copy_str);
   2003     curl_free(h_str);
   2004     curl_url_cleanup(copy);
   2005     copy_str = NULL;
   2006     h_str = NULL;
   2007     copy = NULL;
   2008   }
   2009   curl_url_cleanup(h);
   2010   return 0;
   2011 err:
   2012   curl_free(copy_str);
   2013   curl_free(h_str);
   2014   curl_url_cleanup(copy);
   2015   curl_url_cleanup(h);
   2016   return 1;
   2017 }
   2018 
   2019 static CURLcode test_lib1560(char *URL)
   2020 {
   2021   (void)URL; /* not used */
   2022 
   2023   if(urldup())
   2024     return (CURLcode)11;
   2025 
   2026   if(setget_parts())
   2027     return (CURLcode)10;
   2028 
   2029   if(get_url())
   2030     return (CURLcode)3;
   2031 
   2032   if(huge())
   2033     return (CURLcode)9;
   2034 
   2035   if(get_nothing())
   2036     return (CURLcode)7;
   2037 
   2038   if(scopeid())
   2039     return (CURLcode)6;
   2040 
   2041   if(append())
   2042     return (CURLcode)5;
   2043 
   2044   if(set_url())
   2045     return (CURLcode)1;
   2046 
   2047   if(set_parts())
   2048     return (CURLcode)2;
   2049 
   2050   if(get_parts())
   2051     return (CURLcode)4;
   2052 
   2053   if(clear_url())
   2054     return (CURLcode)8;
   2055 
   2056   curl_mprintf("success\n");
   2057   return CURLE_OK;
   2058 }