1 /***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2020, 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 ***************************************************************************/
22
23 /*
24 * Note:
25 *
26 * Since the URL parser by default only accepts schemes that *this instance*
27 * of libcurl supports, make sure that the test1560 file lists all the schemes
28 * that this test will assume to be present!
29 */
30
31 #include "test.h"
32
33 #include "testutil.h"
34 #include "warnless.h"
35 #include "memdebug.h" /* LAST include file */
36
37 struct part {
38 CURLUPart part;
39 const char *name;
40 };
41
42
checkparts(CURLU * u,const char * in,const char * wanted,unsigned int getflags)43 static int checkparts(CURLU *u, const char *in, const char *wanted,
44 unsigned int getflags)
45 {
46 int i;
47 CURLUcode rc;
48 char buf[256];
49 char *bufp = &buf[0];
50 size_t len = sizeof(buf);
51 struct part parts[] = {
52 {CURLUPART_SCHEME, "scheme"},
53 {CURLUPART_USER, "user"},
54 {CURLUPART_PASSWORD, "password"},
55 {CURLUPART_OPTIONS, "options"},
56 {CURLUPART_HOST, "host"},
57 {CURLUPART_PORT, "port"},
58 {CURLUPART_PATH, "path"},
59 {CURLUPART_QUERY, "query"},
60 {CURLUPART_FRAGMENT, "fragment"},
61 {0, NULL}
62 };
63 memset(buf, 0, sizeof(buf));
64
65 for(i = 0; parts[i].name; i++) {
66 char *p = NULL;
67 size_t n;
68 rc = curl_url_get(u, parts[i].part, &p, getflags);
69 if(!rc && p) {
70 msnprintf(bufp, len, "%s%s", buf[0]?" | ":"", p);
71 }
72 else
73 msnprintf(bufp, len, "%s[%d]", buf[0]?" | ":"", (int)rc);
74
75 n = strlen(bufp);
76 bufp += n;
77 len -= n;
78 curl_free(p);
79 }
80 if(strcmp(buf, wanted)) {
81 fprintf(stderr, "in: %s\nwanted: %s\ngot: %s\n", in, wanted, buf);
82 return 1;
83 }
84 return 0;
85 }
86
87 struct redircase {
88 const char *in;
89 const char *set;
90 const char *out;
91 unsigned int urlflags;
92 unsigned int setflags;
93 CURLUcode ucode;
94 };
95
96 struct setcase {
97 const char *in;
98 const char *set;
99 const char *out;
100 unsigned int urlflags;
101 unsigned int setflags;
102 CURLUcode ucode; /* for the main URL set */
103 CURLUcode pcode; /* for updating parts */
104 };
105
106 struct testcase {
107 const char *in;
108 const char *out;
109 unsigned int urlflags;
110 unsigned int getflags;
111 CURLUcode ucode;
112 };
113
114 struct urltestcase {
115 const char *in;
116 const char *out;
117 unsigned int urlflags; /* pass to curl_url() */
118 unsigned int getflags; /* pass to curl_url_get() */
119 CURLUcode ucode;
120 };
121
122 struct querycase {
123 const char *in;
124 const char *q;
125 const char *out;
126 unsigned int urlflags; /* pass to curl_url() */
127 unsigned int qflags; /* pass to curl_url_get() */
128 CURLUcode ucode;
129 };
130
131 static struct testcase get_parts_list[] ={
132 {"[::1]",
133 "http | [11] | [12] | [13] | [::1] | [15] | / | [16] | [17]",
134 CURLU_GUESS_SCHEME, 0, CURLUE_OK },
135 {"[::]",
136 "http | [11] | [12] | [13] | [::] | [15] | / | [16] | [17]",
137 CURLU_GUESS_SCHEME, 0, CURLUE_OK },
138 {"https://[::1]",
139 "https | [11] | [12] | [13] | [::1] | [15] | / | [16] | [17]",
140 0, 0, CURLUE_OK },
141 {"user:moo@ftp.example.com/color/#green?no-red",
142 "ftp | user | moo | [13] | ftp.example.com | [15] | /color/ | [16] | "
143 "green?no-red",
144 CURLU_GUESS_SCHEME, 0, CURLUE_OK },
145 {"ftp.user:moo@example.com/color/#green?no-red",
146 "http | ftp.user | moo | [13] | example.com | [15] | /color/ | [16] | "
147 "green?no-red",
148 CURLU_GUESS_SCHEME, 0, CURLUE_OK },
149 #ifdef WIN32
150 {"file:/C:\\programs\\foo",
151 "file | [11] | [12] | [13] | [14] | [15] | C:\\programs\\foo | [16] | [17]",
152 CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
153 {"file://C:\\programs\\foo",
154 "file | [11] | [12] | [13] | [14] | [15] | C:\\programs\\foo | [16] | [17]",
155 CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
156 {"file:///C:\\programs\\foo",
157 "file | [11] | [12] | [13] | [14] | [15] | C:\\programs\\foo | [16] | [17]",
158 CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
159 #endif
160 {"https://example.com/color/#green?no-red",
161 "https | [11] | [12] | [13] | example.com | [15] | /color/ | [16] | "
162 "green?no-red",
163 CURLU_DEFAULT_SCHEME, 0, CURLUE_OK },
164 {"https://example.com/color/#green#no-red",
165 "https | [11] | [12] | [13] | example.com | [15] | /color/ | [16] | "
166 "green#no-red",
167 CURLU_DEFAULT_SCHEME, 0, CURLUE_OK },
168 {"https://example.com/color/?green#no-red",
169 "https | [11] | [12] | [13] | example.com | [15] | /color/ | green | "
170 "no-red",
171 CURLU_DEFAULT_SCHEME, 0, CURLUE_OK },
172 {"https://example.com/#color/?green#no-red",
173 "https | [11] | [12] | [13] | example.com | [15] | / | [16] | "
174 "color/?green#no-red",
175 CURLU_DEFAULT_SCHEME, 0, CURLUE_OK },
176 {"https://example.#com/color/?green#no-red",
177 "https | [11] | [12] | [13] | example. | [15] | / | [16] | "
178 "com/color/?green#no-red",
179 CURLU_DEFAULT_SCHEME, 0, CURLUE_OK },
180 {"http://[ab.be:1]/x", "",
181 CURLU_DEFAULT_SCHEME, 0, CURLUE_MALFORMED_INPUT},
182 {"http://[ab.be]/x", "",
183 CURLU_DEFAULT_SCHEME, 0, CURLUE_MALFORMED_INPUT},
184 /* URL without host name */
185 {"http://a:b@/x", "",
186 CURLU_DEFAULT_SCHEME, 0, CURLUE_NO_HOST},
187 {"boing:80",
188 "https | [11] | [12] | [13] | boing | 80 | / | [16] | [17]",
189 CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
190 {"http://[fd00:a41::50]:8080",
191 "http | [11] | [12] | [13] | [fd00:a41::50] | 8080 | / | [16] | [17]",
192 CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
193 {"http://[fd00:a41::50]/",
194 "http | [11] | [12] | [13] | [fd00:a41::50] | [15] | / | [16] | [17]",
195 CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
196 {"http://[fd00:a41::50]",
197 "http | [11] | [12] | [13] | [fd00:a41::50] | [15] | / | [16] | [17]",
198 CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
199 {"https://[::1%252]:1234",
200 "https | [11] | [12] | [13] | [::1] | 1234 | / | [16] | [17]",
201 CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
202
203 /* here's "bad" zone id */
204 {"https://[fe80::20c:29ff:fe9c:409b%eth0]:1234",
205 "https | [11] | [12] | [13] | [fe80::20c:29ff:fe9c:409b] | 1234 "
206 "| / | [16] | [17]",
207 CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
208 {"https://127.0.0.1:443",
209 "https | [11] | [12] | [13] | 127.0.0.1 | [15] | / | [16] | [17]",
210 0, CURLU_NO_DEFAULT_PORT, CURLUE_OK},
211 {"http://%3a:%3a@ex%0ample/%3f+?+%3f+%23#+%23%3f%g7",
212 "http | : | : | [13] | [6] | [15] | /?+ | ? # | +#?%g7",
213 0, CURLU_URLDECODE, CURLUE_OK},
214 {"http://%3a:%3a@ex%0ample/%3f?%3f%35#%35%3f%g7",
215 "http | %3a | %3a | [13] | ex%0ample | [15] | /%3f | %3f%35 | %35%3f%g7",
216 0, 0, CURLUE_OK},
217 {"http://HO0_-st%41/",
218 "http | [11] | [12] | [13] | HO0_-st%41 | [15] | / | [16] | [17]",
219 0, 0, CURLUE_OK},
220 {"file://hello.html",
221 "",
222 0, 0, CURLUE_MALFORMED_INPUT},
223 {"http://HO0_-st/",
224 "http | [11] | [12] | [13] | HO0_-st | [15] | / | [16] | [17]",
225 0, 0, CURLUE_OK},
226 {"imap://user:pass;option@server/path",
227 "imap | user | pass | option | server | [15] | /path | [16] | [17]",
228 0, 0, CURLUE_OK},
229 {"http://user:pass;option@server/path",
230 "http | user | pass;option | [13] | server | [15] | /path | [16] | [17]",
231 0, 0, CURLUE_OK},
232 {"file:/hello.html",
233 "file | [11] | [12] | [13] | [14] | [15] | /hello.html | [16] | [17]",
234 0, 0, CURLUE_OK},
235 {"file://127.0.0.1/hello.html",
236 "file | [11] | [12] | [13] | [14] | [15] | /hello.html | [16] | [17]",
237 0, 0, CURLUE_OK},
238 {"file:////hello.html",
239 "file | [11] | [12] | [13] | [14] | [15] | //hello.html | [16] | [17]",
240 0, 0, CURLUE_OK},
241 {"file:///hello.html",
242 "file | [11] | [12] | [13] | [14] | [15] | /hello.html | [16] | [17]",
243 0, 0, CURLUE_OK},
244 {"https://127.0.0.1",
245 "https | [11] | [12] | [13] | 127.0.0.1 | 443 | / | [16] | [17]",
246 0, CURLU_DEFAULT_PORT, CURLUE_OK},
247 {"https://127.0.0.1",
248 "https | [11] | [12] | [13] | 127.0.0.1 | [15] | / | [16] | [17]",
249 CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
250 {"https://[::1]:1234",
251 "https | [11] | [12] | [13] | [::1] | 1234 | / | [16] | [17]",
252 CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
253 {"https://127abc.com",
254 "https | [11] | [12] | [13] | 127abc.com | [15] | / | [16] | [17]",
255 CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
256 {"https:// example.com?check",
257 "",
258 CURLU_DEFAULT_SCHEME, 0, CURLUE_MALFORMED_INPUT},
259 {"https://e x a m p l e.com?check",
260 "",
261 CURLU_DEFAULT_SCHEME, 0, CURLUE_MALFORMED_INPUT},
262 {"https://example.com?check",
263 "https | [11] | [12] | [13] | example.com | [15] | / | check | [17]",
264 CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
265 {"https://example.com:65536",
266 "",
267 CURLU_DEFAULT_SCHEME, 0, CURLUE_BAD_PORT_NUMBER},
268 {"https://example.com:0#moo",
269 "",
270 CURLU_DEFAULT_SCHEME, 0, CURLUE_BAD_PORT_NUMBER},
271 {"https://example.com:01#moo",
272 "https | [11] | [12] | [13] | example.com | 1 | / | "
273 "[16] | moo",
274 CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
275 {"https://example.com:1#moo",
276 "https | [11] | [12] | [13] | example.com | 1 | / | "
277 "[16] | moo",
278 CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
279 {"http://example.com#moo",
280 "http | [11] | [12] | [13] | example.com | [15] | / | "
281 "[16] | moo",
282 CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
283 {"http://example.com",
284 "http | [11] | [12] | [13] | example.com | [15] | / | "
285 "[16] | [17]",
286 CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
287 {"http://example.com/path/html",
288 "http | [11] | [12] | [13] | example.com | [15] | /path/html | "
289 "[16] | [17]",
290 CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
291 {"http://example.com/path/html?query=name",
292 "http | [11] | [12] | [13] | example.com | [15] | /path/html | "
293 "query=name | [17]",
294 CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
295 {"http://example.com/path/html?query=name#anchor",
296 "http | [11] | [12] | [13] | example.com | [15] | /path/html | "
297 "query=name | anchor",
298 CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
299 {"http://example.com:1234/path/html?query=name#anchor",
300 "http | [11] | [12] | [13] | example.com | 1234 | /path/html | "
301 "query=name | anchor",
302 CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
303 {"http:///user:password@example.com:1234/path/html?query=name#anchor",
304 "http | user | password | [13] | example.com | 1234 | /path/html | "
305 "query=name | anchor",
306 CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
307 {"https://user:password@example.com:1234/path/html?query=name#anchor",
308 "https | user | password | [13] | example.com | 1234 | /path/html | "
309 "query=name | anchor",
310 CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
311 {"http://user:password@example.com:1234/path/html?query=name#anchor",
312 "http | user | password | [13] | example.com | 1234 | /path/html | "
313 "query=name | anchor",
314 CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
315 {"http:/user:password@example.com:1234/path/html?query=name#anchor",
316 "http | user | password | [13] | example.com | 1234 | /path/html | "
317 "query=name | anchor",
318 CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
319 {"http:////user:password@example.com:1234/path/html?query=name#anchor",
320 "",
321 CURLU_DEFAULT_SCHEME, 0, CURLUE_MALFORMED_INPUT},
322 {NULL, NULL, 0, 0, CURLUE_OK},
323 };
324
325 static struct urltestcase get_url_list[] = {
326 /* 40 bytes scheme is the max allowed */
327 {"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA://hostname/path",
328 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa://hostname/path",
329 CURLU_NON_SUPPORT_SCHEME, 0, CURLUE_OK},
330 /* 41 bytes scheme is not allowed */
331 {"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA://hostname/path",
332 "",
333 CURLU_NON_SUPPORT_SCHEME, 0, CURLUE_MALFORMED_INPUT},
334 {"https://[fe80::20c:29ff:fe9c:409b%]:1234",
335 "",
336 0, 0, CURLUE_MALFORMED_INPUT},
337 {"https://[fe80::20c:29ff:fe9c:409b%25]:1234",
338 "https://[fe80::20c:29ff:fe9c:409b%2525]:1234/",
339 0, 0, CURLUE_OK},
340 {"https://[fe80::20c:29ff:fe9c:409b%eth0]:1234",
341 "https://[fe80::20c:29ff:fe9c:409b%25eth0]:1234/",
342 0, 0, CURLUE_OK},
343 {"https://[::%25fakeit]/moo",
344 "https://[::%25fakeit]/moo",
345 0, 0, CURLUE_OK},
346 {"smtp.example.com/path/html",
347 "smtp://smtp.example.com/path/html",
348 CURLU_GUESS_SCHEME, 0, CURLUE_OK},
349 {"https.example.com/path/html",
350 "http://https.example.com/path/html",
351 CURLU_GUESS_SCHEME, 0, CURLUE_OK},
352 {"dict.example.com/path/html",
353 "dict://dict.example.com/path/html",
354 CURLU_GUESS_SCHEME, 0, CURLUE_OK},
355 {"pop3.example.com/path/html",
356 "pop3://pop3.example.com/path/html",
357 CURLU_GUESS_SCHEME, 0, CURLUE_OK},
358 {"ldap.example.com/path/html",
359 "ldap://ldap.example.com/path/html",
360 CURLU_GUESS_SCHEME, 0, CURLUE_OK},
361 {"imap.example.com/path/html",
362 "imap://imap.example.com/path/html",
363 CURLU_GUESS_SCHEME, 0, CURLUE_OK},
364 {"ftp.example.com/path/html",
365 "ftp://ftp.example.com/path/html",
366 CURLU_GUESS_SCHEME, 0, CURLUE_OK},
367 {"example.com/path/html",
368 "http://example.com/path/html",
369 CURLU_GUESS_SCHEME, 0, CURLUE_OK},
370 {"HTTP://test/", "http://test/", 0, 0, CURLUE_OK},
371 {"http://HO0_-st..~./", "http://HO0_-st..~./", 0, 0, CURLUE_OK},
372 {"http:/@example.com: 123/", "", 0, 0, CURLUE_BAD_PORT_NUMBER},
373 {"http:/@example.com:123 /", "", 0, 0, CURLUE_BAD_PORT_NUMBER},
374 {"http:/@example.com:123a/", "", 0, 0, CURLUE_BAD_PORT_NUMBER},
375 {"http://host/file\r", "", 0, 0, CURLUE_MALFORMED_INPUT},
376 {"http://host/file\n\x03", "", 0, 0, CURLUE_MALFORMED_INPUT},
377 {"htt\x02://host/file", "",
378 CURLU_NON_SUPPORT_SCHEME, 0, CURLUE_MALFORMED_INPUT},
379 {" http://host/file", "", 0, 0, CURLUE_MALFORMED_INPUT},
380 /* here the password ends at the semicolon and options is 'word' */
381 {"imap://user:pass;word@host/file",
382 "imap://user:pass;word@host/file",
383 0, 0, CURLUE_OK},
384 /* here the password has the semicolon */
385 {"http://user:pass;word@host/file",
386 "http://user:pass;word@host/file",
387 0, 0, CURLUE_OK},
388 {"file:///file.txt#moo",
389 "file:///file.txt#moo",
390 0, 0, CURLUE_OK},
391 {"file:////file.txt",
392 "file:////file.txt",
393 0, 0, CURLUE_OK},
394 {"file:///file.txt",
395 "file:///file.txt",
396 0, 0, CURLUE_OK},
397 {"file:./",
398 "file://",
399 0, 0, CURLUE_MALFORMED_INPUT},
400 {"http://example.com/hello/../here",
401 "http://example.com/hello/../here",
402 CURLU_PATH_AS_IS, 0, CURLUE_OK},
403 {"http://example.com/hello/../here",
404 "http://example.com/here",
405 0, 0, CURLUE_OK},
406 {"http://example.com:80",
407 "http://example.com/",
408 0, CURLU_NO_DEFAULT_PORT, CURLUE_OK},
409 {"tp://example.com/path/html",
410 "",
411 0, 0, CURLUE_UNSUPPORTED_SCHEME},
412 {"http://hello:fool@example.com",
413 "",
414 CURLU_DISALLOW_USER, 0, CURLUE_USER_NOT_ALLOWED},
415 {"http:/@example.com:123",
416 "http://example.com:123/",
417 0, 0, CURLUE_OK},
418 {"http:/:password@example.com",
419 "http://:password@example.com/",
420 0, 0, CURLUE_OK},
421 {"http://user@example.com?#",
422 "http://user@example.com/",
423 0, 0, CURLUE_OK},
424 {"http://user@example.com?",
425 "http://user@example.com/",
426 0, 0, CURLUE_OK},
427 {"http://user@example.com#anchor",
428 "http://user@example.com/#anchor",
429 0, 0, CURLUE_OK},
430 {"example.com/path/html",
431 "https://example.com/path/html",
432 CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
433 {"example.com/path/html",
434 "",
435 0, 0, CURLUE_MALFORMED_INPUT},
436 {"http://user:password@example.com:1234/path/html?query=name#anchor",
437 "http://user:password@example.com:1234/path/html?query=name#anchor",
438 0, 0, CURLUE_OK},
439 {"http://example.com:1234/path/html?query=name#anchor",
440 "http://example.com:1234/path/html?query=name#anchor",
441 0, 0, CURLUE_OK},
442 {"http://example.com/path/html?query=name#anchor",
443 "http://example.com/path/html?query=name#anchor",
444 0, 0, CURLUE_OK},
445 {"http://example.com/path/html?query=name",
446 "http://example.com/path/html?query=name",
447 0, 0, CURLUE_OK},
448 {"http://example.com/path/html",
449 "http://example.com/path/html",
450 0, 0, CURLUE_OK},
451 {"tp://example.com/path/html",
452 "tp://example.com/path/html",
453 CURLU_NON_SUPPORT_SCHEME, 0, CURLUE_OK},
454 {"custom-scheme://host?expected=test-good",
455 "custom-scheme://host/?expected=test-good",
456 CURLU_NON_SUPPORT_SCHEME, 0, CURLUE_OK},
457 {"custom-scheme://?expected=test-bad",
458 "",
459 CURLU_NON_SUPPORT_SCHEME, 0, CURLUE_MALFORMED_INPUT},
460 {"custom-scheme://?expected=test-new-good",
461 "custom-scheme:///?expected=test-new-good",
462 CURLU_NON_SUPPORT_SCHEME | CURLU_NO_AUTHORITY, 0, CURLUE_OK},
463 {"custom-scheme://host?expected=test-still-good",
464 "custom-scheme://host/?expected=test-still-good",
465 CURLU_NON_SUPPORT_SCHEME | CURLU_NO_AUTHORITY, 0, CURLUE_OK},
466 {NULL, NULL, 0, 0, 0}
467 };
468
checkurl(const char * url,const char * out)469 static int checkurl(const char *url, const char *out)
470 {
471 if(strcmp(out, url)) {
472 fprintf(stderr, "Wanted: %s\nGot : %s\n",
473 out, url);
474 return 1;
475 }
476 return 0;
477 }
478
479 /* !checksrc! disable SPACEBEFORECOMMA 1 */
480 static struct setcase set_parts_list[] = {
481 {"https://example.com/",
482 "query=Al2cO3tDkcDZ3EWE5Lh+LX8TPHs,", /* contains '+' */
483 "https://example.com/?Al2cO3tDkcDZ3EWE5Lh%2bLX8TPHs",
484 CURLU_URLDECODE, /* decode on get */
485 CURLU_URLENCODE, /* encode on set */
486 CURLUE_OK, CURLUE_OK},
487
488 {"https://example.com/",
489 /* Set a 41 bytes scheme. That's too long so the old scheme remains set. */
490 "scheme=bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbc,",
491 "https://example.com/",
492 0, CURLU_NON_SUPPORT_SCHEME, CURLUE_OK, CURLUE_MALFORMED_INPUT},
493 {"https://example.com/",
494 /* set a 40 bytes scheme */
495 "scheme=bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb,",
496 "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb://example.com/",
497 0, CURLU_NON_SUPPORT_SCHEME, CURLUE_OK, CURLUE_OK},
498 {"https://[::1%25fake]:1234/",
499 "zoneid=NULL,",
500 "https://[::1]:1234/",
501 0, 0, CURLUE_OK, CURLUE_OK},
502 {"https://host:1234/",
503 "port=NULL,",
504 "https://host/",
505 0, 0, CURLUE_OK, CURLUE_OK},
506 {"https://host:1234/",
507 "port=\"\",",
508 "https://host:1234/",
509 0, 0, CURLUE_OK, CURLUE_BAD_PORT_NUMBER},
510 {"https://host:1234/",
511 "port=56 78,",
512 "https://host:1234/",
513 0, 0, CURLUE_OK, CURLUE_MALFORMED_INPUT},
514 {"https://host:1234/",
515 "port=0,",
516 "https://host:1234/",
517 0, 0, CURLUE_OK, CURLUE_BAD_PORT_NUMBER},
518 {"https://host:1234/",
519 "port=65535,",
520 "https://host:65535/",
521 0, 0, CURLUE_OK, CURLUE_OK},
522 {"https://host:1234/",
523 "port=65536,",
524 "https://host:1234/",
525 0, 0, CURLUE_OK, CURLUE_BAD_PORT_NUMBER},
526 {"https://host/",
527 "path=%4A%4B%4C,",
528 "https://host/%4a%4b%4c",
529 0, 0, CURLUE_OK, CURLUE_OK},
530 {"https://host/mooo?q#f",
531 "path=NULL,query=NULL,fragment=NULL,",
532 "https://host/",
533 0, 0, CURLUE_OK, CURLUE_OK},
534 {"https://user:secret@host/",
535 "user=NULL,password=NULL,",
536 "https://host/",
537 0, 0, CURLUE_OK, CURLUE_OK},
538 {NULL,
539 "scheme=https,user= @:,host=foobar,",
540 "https://%20%20%20%40%3a@foobar/",
541 0, CURLU_URLENCODE, CURLUE_OK, CURLUE_OK},
542 {NULL,
543 "scheme=https,host= ,path= ,user= ,password= ,query= ,fragment= ,",
544 "https://%20:%20@%20%20/%20?+#%20",
545 0, CURLU_URLENCODE, CURLUE_OK, CURLUE_OK},
546 {NULL,
547 "scheme=https,host=foobar,path=/this /path /is /here,",
548 "https://foobar/this%20/path%20/is%20/here",
549 0, CURLU_URLENCODE, CURLUE_OK, CURLUE_OK},
550 {NULL,
551 "scheme=https,host=foobar,path=\xc3\xa4\xc3\xb6\xc3\xbc,",
552 "https://foobar/%c3%a4%c3%b6%c3%bc",
553 0, CURLU_URLENCODE, CURLUE_OK, CURLUE_OK},
554 {"imap://user:secret;opt@host/",
555 "options=updated,scheme=imaps,password=p4ssw0rd,",
556 "imaps://user:p4ssw0rd;updated@host/",
557 0, 0, CURLUE_NO_HOST, CURLUE_OK},
558 {"imap://user:secret;optit@host/",
559 "scheme=https,",
560 "https://user:secret@host/",
561 0, 0, CURLUE_NO_HOST, CURLUE_OK},
562 {"file:///file#anchor",
563 "scheme=https,host=example,",
564 "https://example/file#anchor",
565 0, 0, CURLUE_NO_HOST, CURLUE_OK},
566 {NULL, /* start fresh! */
567 "scheme=file,host=127.0.0.1,path=/no,user=anonymous,",
568 "file:///no",
569 0, 0, CURLUE_OK, CURLUE_OK},
570 {NULL, /* start fresh! */
571 "scheme=ftp,host=127.0.0.1,path=/no,user=anonymous,",
572 "ftp://anonymous@127.0.0.1/no",
573 0, 0, CURLUE_OK, CURLUE_OK},
574 {NULL, /* start fresh! */
575 "scheme=https,host=example.com,",
576 "https://example.com/",
577 0, CURLU_NON_SUPPORT_SCHEME, CURLUE_OK, CURLUE_OK},
578 {"http://user:foo@example.com/path?query#frag",
579 "fragment=changed,",
580 "http://user:foo@example.com/path?query#changed",
581 0, CURLU_NON_SUPPORT_SCHEME, CURLUE_OK, CURLUE_OK},
582 {"http://example.com/",
583 "scheme=foo,", /* not accepted */
584 "http://example.com/",
585 0, 0, CURLUE_OK, CURLUE_UNSUPPORTED_SCHEME},
586 {"http://example.com/",
587 "scheme=https,path=/hello,fragment=snippet,",
588 "https://example.com/hello#snippet",
589 0, 0, CURLUE_OK, CURLUE_OK},
590 {"http://example.com:80",
591 "user=foo,port=1922,",
592 "http://foo@example.com:1922/",
593 0, 0, CURLUE_OK, CURLUE_OK},
594 {"http://example.com:80",
595 "user=foo,password=bar,",
596 "http://foo:bar@example.com:80/",
597 0, 0, CURLUE_OK, CURLUE_OK},
598 {"http://example.com:80",
599 "user=foo,",
600 "http://foo@example.com:80/",
601 0, 0, CURLUE_OK, CURLUE_OK},
602 {"http://example.com",
603 "host=www.example.com,",
604 "http://www.example.com/",
605 0, 0, CURLUE_OK, CURLUE_OK},
606 {"http://example.com:80",
607 "scheme=ftp,",
608 "ftp://example.com:80/",
609 0, 0, CURLUE_OK, CURLUE_OK},
610 {"custom-scheme://host",
611 "host=\"\",",
612 "custom-scheme://host/",
613 CURLU_NON_SUPPORT_SCHEME, CURLU_NON_SUPPORT_SCHEME, CURLUE_OK,
614 CURLUE_MALFORMED_INPUT},
615 {"custom-scheme://host",
616 "host=\"\",",
617 "custom-scheme:///",
618 CURLU_NON_SUPPORT_SCHEME, CURLU_NON_SUPPORT_SCHEME | CURLU_NO_AUTHORITY,
619 CURLUE_OK, CURLUE_OK},
620
621 {NULL, NULL, NULL, 0, 0, 0, 0}
622 };
623
part2id(char * part)624 static CURLUPart part2id(char *part)
625 {
626 if(!strcmp("url", part))
627 return CURLUPART_URL;
628 if(!strcmp("scheme", part))
629 return CURLUPART_SCHEME;
630 if(!strcmp("user", part))
631 return CURLUPART_USER;
632 if(!strcmp("password", part))
633 return CURLUPART_PASSWORD;
634 if(!strcmp("options", part))
635 return CURLUPART_OPTIONS;
636 if(!strcmp("host", part))
637 return CURLUPART_HOST;
638 if(!strcmp("port", part))
639 return CURLUPART_PORT;
640 if(!strcmp("path", part))
641 return CURLUPART_PATH;
642 if(!strcmp("query", part))
643 return CURLUPART_QUERY;
644 if(!strcmp("fragment", part))
645 return CURLUPART_FRAGMENT;
646 if(!strcmp("zoneid", part))
647 return CURLUPART_ZONEID;
648 return (CURLUPart)9999; /* bad input => bad output */
649 }
650
updateurl(CURLU * u,const char * cmd,unsigned int setflags)651 static CURLUcode updateurl(CURLU *u, const char *cmd, unsigned int setflags)
652 {
653 const char *p = cmd;
654 CURLUcode uc;
655
656 /* make sure the last command ends with a comma too! */
657 while(p) {
658 char *e = strchr(p, ',');
659 if(e) {
660 size_t n = e-p;
661 char buf[80];
662 char part[80];
663 char value[80];
664
665 memset(part, 0, sizeof(part)); /* Avoid valgrind false positive. */
666 memset(value, 0, sizeof(value)); /* Avoid valgrind false positive. */
667 memcpy(buf, p, n);
668 buf[n] = 0;
669 if(2 == sscanf(buf, "%79[^=]=%79[^,]", part, value)) {
670 CURLUPart what = part2id(part);
671 #if 0
672 /* for debugging this */
673 fprintf(stderr, "%s = %s [%d]\n", part, value, (int)what);
674 #endif
675 if(what > CURLUPART_ZONEID)
676 fprintf(stderr, "UNKNOWN part '%s'\n", part);
677
678 if(!strcmp("NULL", value))
679 uc = curl_url_set(u, what, NULL, setflags);
680 else if(!strcmp("\"\"", value))
681 uc = curl_url_set(u, what, "", setflags);
682 else
683 uc = curl_url_set(u, what, value, setflags);
684 if(uc)
685 return uc;
686 }
687 p = e + 1;
688 continue;
689 }
690 break;
691 }
692 return CURLUE_OK;
693 }
694
695 static struct redircase set_url_list[] = {
696 {"http://example.org/static/favicon/wikipedia.ico",
697 "//fake.example.com/licenses/by-sa/3.0/",
698 "http://fake.example.com/licenses/by-sa/3.0/",
699 0, 0, 0},
700 {"https://example.org/static/favicon/wikipedia.ico",
701 "//fake.example.com/licenses/by-sa/3.0/",
702 "https://fake.example.com/licenses/by-sa/3.0/",
703 0, 0, 0},
704 {"file://localhost/path?query#frag",
705 "foo#another",
706 "file:///foo#another",
707 0, 0, 0},
708 {"http://example.com/path?query#frag",
709 "https://two.example.com/bradnew",
710 "https://two.example.com/bradnew",
711 0, 0, 0},
712 {"http://example.com/path?query#frag",
713 "../../newpage#foo",
714 "http://example.com/newpage#foo",
715 0, 0, 0},
716 {"http://user:foo@example.com/path?query#frag",
717 "../../newpage",
718 "http://user:foo@example.com/newpage",
719 0, 0, 0},
720 {"http://user:foo@example.com/path?query#frag",
721 "../newpage",
722 "http://user:foo@example.com/newpage",
723 0, 0, 0},
724 {NULL, NULL, NULL, 0, 0, 0}
725 };
726
set_url(void)727 static int set_url(void)
728 {
729 int i;
730 int error = 0;
731
732 for(i = 0; set_url_list[i].in && !error; i++) {
733 CURLUcode rc;
734 CURLU *urlp = curl_url();
735 if(!urlp)
736 break;
737 rc = curl_url_set(urlp, CURLUPART_URL, set_url_list[i].in,
738 set_url_list[i].urlflags);
739 if(!rc) {
740 rc = curl_url_set(urlp, CURLUPART_URL, set_url_list[i].set,
741 set_url_list[i].setflags);
742 if(rc) {
743 fprintf(stderr, "%s:%d Set URL %s returned %d\n",
744 __FILE__, __LINE__, set_url_list[i].set,
745 (int)rc);
746 error++;
747 }
748 else {
749 char *url = NULL;
750 rc = curl_url_get(urlp, CURLUPART_URL, &url, 0);
751 if(rc) {
752 fprintf(stderr, "%s:%d Get URL returned %d\n",
753 __FILE__, __LINE__, (int)rc);
754 error++;
755 }
756 else {
757 if(checkurl(url, set_url_list[i].out)) {
758 error++;
759 }
760 }
761 curl_free(url);
762 }
763 }
764 else if(rc != set_url_list[i].ucode) {
765 fprintf(stderr, "Set URL\nin: %s\nreturned %d (expected %d)\n",
766 set_url_list[i].in, (int)rc, set_url_list[i].ucode);
767 error++;
768 }
769 curl_url_cleanup(urlp);
770 }
771 return error;
772 }
773
set_parts(void)774 static int set_parts(void)
775 {
776 int i;
777 int error = 0;
778
779 for(i = 0; set_parts_list[i].set && !error; i++) {
780 CURLUcode rc;
781 CURLU *urlp = curl_url();
782 if(!urlp) {
783 error++;
784 break;
785 }
786 if(set_parts_list[i].in)
787 rc = curl_url_set(urlp, CURLUPART_URL, set_parts_list[i].in,
788 set_parts_list[i].urlflags);
789 else
790 rc = CURLUE_OK;
791 if(!rc) {
792 char *url = NULL;
793 CURLUcode uc = updateurl(urlp, set_parts_list[i].set,
794 set_parts_list[i].setflags);
795
796 if(uc != set_parts_list[i].pcode) {
797 fprintf(stderr, "updateurl\nin: %s\nreturned %d (expected %d)\n",
798 set_parts_list[i].set, (int)uc, set_parts_list[i].pcode);
799 error++;
800 }
801
802 rc = curl_url_get(urlp, CURLUPART_URL, &url, 0);
803
804 if(rc) {
805 fprintf(stderr, "%s:%d Get URL returned %d\n",
806 __FILE__, __LINE__, (int)rc);
807 error++;
808 }
809 else if(checkurl(url, set_parts_list[i].out)) {
810 error++;
811 }
812 curl_free(url);
813 }
814 else if(rc != set_parts_list[i].ucode) {
815 fprintf(stderr, "Set parts\nin: %s\nreturned %d (expected %d)\n",
816 set_parts_list[i].in, (int)rc, set_parts_list[i].ucode);
817 error++;
818 }
819 curl_url_cleanup(urlp);
820 }
821 return error;
822 }
823
get_url(void)824 static int get_url(void)
825 {
826 int i;
827 int error = 0;
828 for(i = 0; get_url_list[i].in && !error; i++) {
829 CURLUcode rc;
830 CURLU *urlp = curl_url();
831 if(!urlp) {
832 error++;
833 break;
834 }
835 rc = curl_url_set(urlp, CURLUPART_URL, get_url_list[i].in,
836 get_url_list[i].urlflags);
837 if(!rc) {
838 char *url = NULL;
839 rc = curl_url_get(urlp, CURLUPART_URL, &url, get_url_list[i].getflags);
840
841 if(rc) {
842 fprintf(stderr, "%s:%d returned %d\n",
843 __FILE__, __LINE__, (int)rc);
844 error++;
845 }
846 else {
847 if(checkurl(url, get_url_list[i].out)) {
848 error++;
849 }
850 }
851 curl_free(url);
852 }
853 else if(rc != get_url_list[i].ucode) {
854 fprintf(stderr, "Get URL\nin: %s\nreturned %d (expected %d)\n",
855 get_url_list[i].in, (int)rc, get_url_list[i].ucode);
856 error++;
857 }
858 curl_url_cleanup(urlp);
859 }
860 return error;
861 }
862
get_parts(void)863 static int get_parts(void)
864 {
865 int i;
866 int error = 0;
867 for(i = 0; get_parts_list[i].in && !error; i++) {
868 CURLUcode rc;
869 CURLU *urlp = curl_url();
870 if(!urlp) {
871 error++;
872 break;
873 }
874 rc = curl_url_set(urlp, CURLUPART_URL,
875 get_parts_list[i].in,
876 get_parts_list[i].urlflags);
877 if(rc != get_parts_list[i].ucode) {
878 fprintf(stderr, "Get parts\nin: %s\nreturned %d (expected %d)\n",
879 get_parts_list[i].in, (int)rc, get_parts_list[i].ucode);
880 error++;
881 }
882 else if(get_parts_list[i].ucode) {
883 /* the expected error happened */
884 }
885 else if(checkparts(urlp, get_parts_list[i].in, get_parts_list[i].out,
886 get_parts_list[i].getflags))
887 error++;
888 curl_url_cleanup(urlp);
889 }
890 return error;
891 }
892
893 static struct querycase append_list[] = {
894 {"HTTP://test/?s", "name=joe\x02", "http://test/?s&name=joe%02",
895 0, CURLU_URLENCODE, CURLUE_OK},
896 {"HTTP://test/?size=2#f", "name=joe=", "http://test/?size=2&name=joe%3d#f",
897 0, CURLU_URLENCODE, CURLUE_OK},
898 {"HTTP://test/?size=2#f", "name=joe doe",
899 "http://test/?size=2&name=joe+doe#f",
900 0, CURLU_URLENCODE, CURLUE_OK},
901 {"HTTP://test/", "name=joe", "http://test/?name=joe", 0, 0, CURLUE_OK},
902 {"HTTP://test/?size=2", "name=joe", "http://test/?size=2&name=joe",
903 0, 0, CURLUE_OK},
904 {"HTTP://test/?size=2&", "name=joe", "http://test/?size=2&name=joe",
905 0, 0, CURLUE_OK},
906 {"HTTP://test/?size=2#f", "name=joe", "http://test/?size=2&name=joe#f",
907 0, 0, CURLUE_OK},
908 {NULL, NULL, NULL, 0, 0, 0}
909 };
910
append(void)911 static int append(void)
912 {
913 int i;
914 int error = 0;
915 for(i = 0; append_list[i].in && !error; i++) {
916 CURLUcode rc;
917 CURLU *urlp = curl_url();
918 if(!urlp) {
919 error++;
920 break;
921 }
922 rc = curl_url_set(urlp, CURLUPART_URL,
923 append_list[i].in,
924 append_list[i].urlflags);
925 if(rc)
926 error++;
927 else
928 rc = curl_url_set(urlp, CURLUPART_QUERY,
929 append_list[i].q,
930 append_list[i].qflags | CURLU_APPENDQUERY);
931 if(error)
932 ;
933 else if(rc != append_list[i].ucode) {
934 fprintf(stderr, "Append\nin: %s\nreturned %d (expected %d)\n",
935 append_list[i].in, (int)rc, append_list[i].ucode);
936 error++;
937 }
938 else if(append_list[i].ucode) {
939 /* the expected error happened */
940 }
941 else {
942 char *url;
943 rc = curl_url_get(urlp, CURLUPART_URL, &url, 0);
944 if(rc) {
945 fprintf(stderr, "%s:%d Get URL returned %d\n",
946 __FILE__, __LINE__, (int)rc);
947 error++;
948 }
949 else {
950 if(checkurl(url, append_list[i].out)) {
951 error++;
952 }
953 curl_free(url);
954 }
955 }
956 curl_url_cleanup(urlp);
957 }
958 return error;
959 }
960
scopeid(void)961 static int scopeid(void)
962 {
963 CURLU *u = curl_url();
964 int error = 0;
965 CURLUcode rc;
966 char *url;
967
968 rc = curl_url_set(u, CURLUPART_URL,
969 "https://[fe80::20c:29ff:fe9c:409b%25eth0]/hello.html", 0);
970 if(rc != CURLUE_OK) {
971 fprintf(stderr, "%s:%d curl_url_set returned %d\n",
972 __FILE__, __LINE__, (int)rc);
973 error++;
974 }
975
976 rc = curl_url_get(u, CURLUPART_HOST, &url, 0);
977 if(rc != CURLUE_OK) {
978 fprintf(stderr, "%s:%d curl_url_get CURLUPART_HOST returned %d\n",
979 __FILE__, __LINE__, (int)rc);
980 error++;
981 }
982 else {
983 printf("we got %s\n", url);
984 curl_free(url);
985 }
986
987 rc = curl_url_set(u, CURLUPART_HOST, "[::1]", 0);
988 if(rc != CURLUE_OK) {
989 fprintf(stderr, "%s:%d curl_url_set CURLUPART_HOST returned %d\n",
990 __FILE__, __LINE__, (int)rc);
991 error++;
992 }
993
994 rc = curl_url_get(u, CURLUPART_URL, &url, 0);
995 if(rc != CURLUE_OK) {
996 fprintf(stderr, "%s:%d curl_url_get CURLUPART_URL returned %d\n",
997 __FILE__, __LINE__, (int)rc);
998 error++;
999 }
1000 else {
1001 printf("we got %s\n", url);
1002 curl_free(url);
1003 }
1004
1005 rc = curl_url_set(u, CURLUPART_HOST, "example.com", 0);
1006 if(rc != CURLUE_OK) {
1007 fprintf(stderr, "%s:%d curl_url_set CURLUPART_HOST returned %d\n",
1008 __FILE__, __LINE__, (int)rc);
1009 error++;
1010 }
1011
1012 rc = curl_url_get(u, CURLUPART_URL, &url, 0);
1013 if(rc != CURLUE_OK) {
1014 fprintf(stderr, "%s:%d curl_url_get CURLUPART_URL returned %d\n",
1015 __FILE__, __LINE__, (int)rc);
1016 error++;
1017 }
1018 else {
1019 printf("we got %s\n", url);
1020 curl_free(url);
1021 }
1022
1023 rc = curl_url_set(u, CURLUPART_HOST,
1024 "[fe80::20c:29ff:fe9c:409b%25eth0]", 0);
1025 if(rc != CURLUE_OK) {
1026 fprintf(stderr, "%s:%d curl_url_set CURLUPART_HOST returned %d\n",
1027 __FILE__, __LINE__, (int)rc);
1028 error++;
1029 }
1030
1031 rc = curl_url_get(u, CURLUPART_URL, &url, 0);
1032 if(rc != CURLUE_OK) {
1033 fprintf(stderr, "%s:%d curl_url_get CURLUPART_URL returned %d\n",
1034 __FILE__, __LINE__, (int)rc);
1035 error++;
1036 }
1037 else {
1038 printf("we got %s\n", url);
1039 curl_free(url);
1040 }
1041
1042 rc = curl_url_get(u, CURLUPART_HOST, &url, 0);
1043 if(rc != CURLUE_OK) {
1044 fprintf(stderr, "%s:%d curl_url_get CURLUPART_HOST returned %d\n",
1045 __FILE__, __LINE__, (int)rc);
1046 error++;
1047 }
1048 else {
1049 printf("we got %s\n", url);
1050 curl_free(url);
1051 }
1052
1053 rc = curl_url_get(u, CURLUPART_ZONEID, &url, 0);
1054 if(rc != CURLUE_OK) {
1055 fprintf(stderr, "%s:%d curl_url_get CURLUPART_ZONEID returned %d\n",
1056 __FILE__, __LINE__, (int)rc);
1057 error++;
1058 }
1059 else {
1060 printf("we got %s\n", url);
1061 curl_free(url);
1062 }
1063
1064 rc = curl_url_set(u, CURLUPART_ZONEID, "clown", 0);
1065 if(rc != CURLUE_OK) {
1066 fprintf(stderr, "%s:%d curl_url_set CURLUPART_ZONEID returned %d\n",
1067 __FILE__, __LINE__, (int)rc);
1068 error++;
1069 }
1070
1071 rc = curl_url_get(u, CURLUPART_URL, &url, 0);
1072 if(rc != CURLUE_OK) {
1073 fprintf(stderr, "%s:%d curl_url_get CURLUPART_URL returned %d\n",
1074 __FILE__, __LINE__, (int)rc);
1075 error++;
1076 }
1077 else {
1078 printf("we got %s\n", url);
1079 curl_free(url);
1080 }
1081
1082 curl_url_cleanup(u);
1083
1084 return error;
1085 }
1086
test(char * URL)1087 int test(char *URL)
1088 {
1089 (void)URL; /* not used */
1090
1091 if(scopeid())
1092 return 6;
1093
1094 if(append())
1095 return 5;
1096
1097 if(set_url())
1098 return 1;
1099
1100 if(set_parts())
1101 return 2;
1102
1103 if(get_url())
1104 return 3;
1105
1106 if(get_parts())
1107 return 4;
1108
1109 printf("success\n");
1110 return 0;
1111 }
1112