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