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