]> git.proxmox.com Git - mirror_qemu.git/blame - util/uri.c
iotests: add filter_qmp_generated_node_ids()
[mirror_qemu.git] / util / uri.c
CommitLineData
ca0defb9
PB
1/**
2 * uri.c: set of generic URI related routines
3 *
4 * Reference: RFCs 3986, 2732 and 2373
5 *
6 * Copyright (C) 1998-2003 Daniel Veillard. All Rights Reserved.
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 * of this software and associated documentation files (the "Software"), to deal
10 * in the Software without restriction, including without limitation the rights
11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 * copies of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 * DANIEL VEILLARD BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
22 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 *
25 * Except as contained in this notice, the name of Daniel Veillard shall not
26 * be used in advertising or otherwise to promote the sale, use or other
27 * dealings in this Software without prior written authorization from him.
28 *
29 * daniel@veillard.com
30 *
31 **
32 *
33 * Copyright (C) 2007, 2009-2010 Red Hat, Inc.
34 *
35 * This library is free software; you can redistribute it and/or
36 * modify it under the terms of the GNU Lesser General Public
37 * License as published by the Free Software Foundation; either
38 * version 2.1 of the License, or (at your option) any later version.
39 *
40 * This library is distributed in the hope that it will be useful,
41 * but WITHOUT ANY WARRANTY; without even the implied warranty of
42 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
43 * Lesser General Public License for more details.
44 *
45 * You should have received a copy of the GNU Lesser General Public
0c201cc1 46 * License along with this library. If not, see <https://www.gnu.org/licenses/>.
ca0defb9
PB
47 *
48 * Authors:
49 * Richard W.M. Jones <rjones@redhat.com>
50 *
51 */
52
aafd7584 53#include "qemu/osdep.h"
5c99fa37 54#include "qemu/cutils.h"
ca0defb9 55
1de7afc9 56#include "qemu/uri.h"
ca0defb9
PB
57
58static void uri_clean(URI *uri);
59
60/*
61 * Old rule from 2396 used in legacy handling code
62 * alpha = lowalpha | upalpha
63 */
64#define IS_ALPHA(x) (IS_LOWALPHA(x) || IS_UPALPHA(x))
65
ca0defb9
PB
66/*
67 * lowalpha = "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j" |
68 * "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" | "s" | "t" |
69 * "u" | "v" | "w" | "x" | "y" | "z"
70 */
71
72#define IS_LOWALPHA(x) (((x) >= 'a') && ((x) <= 'z'))
73
74/*
75 * upalpha = "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" | "J" |
76 * "K" | "L" | "M" | "N" | "O" | "P" | "Q" | "R" | "S" | "T" |
77 * "U" | "V" | "W" | "X" | "Y" | "Z"
78 */
79#define IS_UPALPHA(x) (((x) >= 'A') && ((x) <= 'Z'))
80
81#ifdef IS_DIGIT
82#undef IS_DIGIT
83#endif
84/*
85 * digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
86 */
87#define IS_DIGIT(x) (((x) >= '0') && ((x) <= '9'))
88
89/*
90 * alphanum = alpha | digit
91 */
92
93#define IS_ALPHANUM(x) (IS_ALPHA(x) || IS_DIGIT(x))
94
95/*
96 * mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")"
97 */
98
be95adaf
SH
99#define IS_MARK(x) (((x) == '-') || ((x) == '_') || ((x) == '.') || \
100 ((x) == '!') || ((x) == '~') || ((x) == '*') || ((x) == '\'') || \
ca0defb9
PB
101 ((x) == '(') || ((x) == ')'))
102
103/*
104 * unwise = "{" | "}" | "|" | "\" | "^" | "`"
105 */
106
be95adaf
SH
107#define IS_UNWISE(p) \
108 (((*(p) == '{')) || ((*(p) == '}')) || ((*(p) == '|')) || \
109 ((*(p) == '\\')) || ((*(p) == '^')) || ((*(p) == '[')) || \
110 ((*(p) == ']')) || ((*(p) == '`')))
ca0defb9
PB
111/*
112 * reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | "," |
113 * "[" | "]"
114 */
115
be95adaf
SH
116#define IS_RESERVED(x) (((x) == ';') || ((x) == '/') || ((x) == '?') || \
117 ((x) == ':') || ((x) == '@') || ((x) == '&') || ((x) == '=') || \
118 ((x) == '+') || ((x) == '$') || ((x) == ',') || ((x) == '[') || \
119 ((x) == ']'))
ca0defb9
PB
120
121/*
122 * unreserved = alphanum | mark
123 */
124
125#define IS_UNRESERVED(x) (IS_ALPHANUM(x) || IS_MARK(x))
126
127/*
128 * Skip to next pointer char, handle escaped sequences
129 */
130
be95adaf 131#define NEXT(p) ((*p == '%') ? p += 3 : p++)
ca0defb9
PB
132
133/*
134 * Productions from the spec.
135 *
136 * authority = server | reg_name
137 * reg_name = 1*( unreserved | escaped | "$" | "," |
138 * ";" | ":" | "@" | "&" | "=" | "+" )
139 *
140 * path = [ abs_path | opaque_part ]
141 */
142
ca0defb9 143/************************************************************************
be95adaf
SH
144 * *
145 * RFC 3986 parser *
146 * *
ca0defb9
PB
147 ************************************************************************/
148
149#define ISA_DIGIT(p) ((*(p) >= '0') && (*(p) <= '9'))
be95adaf 150#define ISA_ALPHA(p) (((*(p) >= 'a') && (*(p) <= 'z')) || \
ca0defb9 151 ((*(p) >= 'A') && (*(p) <= 'Z')))
be95adaf
SH
152#define ISA_HEXDIG(p) \
153 (ISA_DIGIT(p) || ((*(p) >= 'a') && (*(p) <= 'f')) || \
154 ((*(p) >= 'A') && (*(p) <= 'F')))
ca0defb9
PB
155
156/*
157 * sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
158 * / "*" / "+" / "," / ";" / "="
159 */
be95adaf
SH
160#define ISA_SUB_DELIM(p) \
161 (((*(p) == '!')) || ((*(p) == '$')) || ((*(p) == '&')) || \
162 ((*(p) == '(')) || ((*(p) == ')')) || ((*(p) == '*')) || \
163 ((*(p) == '+')) || ((*(p) == ',')) || ((*(p) == ';')) || \
164 ((*(p) == '=')) || ((*(p) == '\'')))
ca0defb9 165
ca0defb9
PB
166/*
167 * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
168 */
be95adaf
SH
169#define ISA_UNRESERVED(p) \
170 ((ISA_ALPHA(p)) || (ISA_DIGIT(p)) || ((*(p) == '-')) || \
171 ((*(p) == '.')) || ((*(p) == '_')) || ((*(p) == '~')))
ca0defb9
PB
172
173/*
174 * pct-encoded = "%" HEXDIG HEXDIG
175 */
be95adaf
SH
176#define ISA_PCT_ENCODED(p) \
177 ((*(p) == '%') && (ISA_HEXDIG(p + 1)) && (ISA_HEXDIG(p + 2)))
ca0defb9
PB
178
179/*
180 * pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
181 */
be95adaf
SH
182#define ISA_PCHAR(p) \
183 (ISA_UNRESERVED(p) || ISA_PCT_ENCODED(p) || ISA_SUB_DELIM(p) || \
184 ((*(p) == ':')) || ((*(p) == '@')))
ca0defb9
PB
185
186/**
187 * rfc3986_parse_scheme:
188 * @uri: pointer to an URI structure
189 * @str: pointer to the string to analyze
190 *
191 * Parse an URI scheme
192 *
193 * ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
194 *
195 * Returns 0 or the error code
196 */
be95adaf
SH
197static int rfc3986_parse_scheme(URI *uri, const char **str)
198{
ca0defb9
PB
199 const char *cur;
200
a1515161 201 if (str == NULL) {
42fa2725 202 return -1;
a1515161 203 }
ca0defb9
PB
204
205 cur = *str;
a1515161 206 if (!ISA_ALPHA(cur)) {
42fa2725 207 return 2;
a1515161 208 }
ca0defb9 209 cur++;
be95adaf 210 while (ISA_ALPHA(cur) || ISA_DIGIT(cur) || (*cur == '+') || (*cur == '-') ||
a1515161 211 (*cur == '.')) {
be95adaf 212 cur++;
a1515161 213 }
ca0defb9 214 if (uri != NULL) {
44c2286b 215 g_free(uri->scheme);
be95adaf 216 uri->scheme = g_strndup(*str, cur - *str);
ca0defb9
PB
217 }
218 *str = cur;
42fa2725 219 return 0;
ca0defb9
PB
220}
221
222/**
223 * rfc3986_parse_fragment:
224 * @uri: pointer to an URI structure
225 * @str: pointer to the string to analyze
226 *
227 * Parse the query part of an URI
228 *
229 * fragment = *( pchar / "/" / "?" )
230 * NOTE: the strict syntax as defined by 3986 does not allow '[' and ']'
231 * in the fragment identifier but this is used very broadly for
232 * xpointer scheme selection, so we are allowing it here to not break
233 * for example all the DocBook processing chains.
234 *
235 * Returns 0 or the error code
236 */
be95adaf 237static int rfc3986_parse_fragment(URI *uri, const char **str)
ca0defb9
PB
238{
239 const char *cur;
240
a1515161 241 if (str == NULL) {
42fa2725 242 return -1;
a1515161 243 }
ca0defb9
PB
244
245 cur = *str;
246
247 while ((ISA_PCHAR(cur)) || (*cur == '/') || (*cur == '?') ||
248 (*cur == '[') || (*cur == ']') ||
a1515161 249 ((uri != NULL) && (uri->cleanup & 1) && (IS_UNWISE(cur)))) {
ca0defb9 250 NEXT(cur);
a1515161 251 }
ca0defb9 252 if (uri != NULL) {
44c2286b 253 g_free(uri->fragment);
a1515161 254 if (uri->cleanup & 2) {
be95adaf 255 uri->fragment = g_strndup(*str, cur - *str);
a1515161 256 } else {
7536acb4 257 uri->fragment = g_uri_unescape_segment(*str, cur, NULL);
a1515161 258 }
ca0defb9
PB
259 }
260 *str = cur;
42fa2725 261 return 0;
ca0defb9
PB
262}
263
264/**
265 * rfc3986_parse_query:
266 * @uri: pointer to an URI structure
267 * @str: pointer to the string to analyze
268 *
269 * Parse the query part of an URI
270 *
271 * query = *uric
272 *
273 * Returns 0 or the error code
274 */
be95adaf 275static int rfc3986_parse_query(URI *uri, const char **str)
ca0defb9
PB
276{
277 const char *cur;
278
a1515161 279 if (str == NULL) {
42fa2725 280 return -1;
a1515161 281 }
ca0defb9
PB
282
283 cur = *str;
284
285 while ((ISA_PCHAR(cur)) || (*cur == '/') || (*cur == '?') ||
a1515161 286 ((uri != NULL) && (uri->cleanup & 1) && (IS_UNWISE(cur)))) {
ca0defb9 287 NEXT(cur);
a1515161 288 }
ca0defb9 289 if (uri != NULL) {
44c2286b 290 g_free(uri->query);
be95adaf 291 uri->query = g_strndup(*str, cur - *str);
ca0defb9
PB
292 }
293 *str = cur;
42fa2725 294 return 0;
ca0defb9
PB
295}
296
297/**
298 * rfc3986_parse_port:
299 * @uri: pointer to an URI structure
300 * @str: the string to analyze
301 *
302 * Parse a port part and fills in the appropriate fields
303 * of the @uri structure
304 *
305 * port = *DIGIT
306 *
307 * Returns 0 or the error code
308 */
be95adaf 309static int rfc3986_parse_port(URI *uri, const char **str)
ca0defb9
PB
310{
311 const char *cur = *str;
2b212330 312 int port = 0;
ca0defb9
PB
313
314 if (ISA_DIGIT(cur)) {
2b212330
HR
315 while (ISA_DIGIT(cur)) {
316 port = port * 10 + (*cur - '0');
317 if (port > 65535) {
318 return 1;
319 }
320 cur++;
321 }
322 if (uri) {
323 uri->port = port;
324 }
325 *str = cur;
326 return 0;
ca0defb9 327 }
2b212330 328 return 1;
ca0defb9
PB
329}
330
331/**
332 * rfc3986_parse_user_info:
333 * @uri: pointer to an URI structure
334 * @str: the string to analyze
335 *
736a83fa 336 * Parse a user information part and fill in the appropriate fields
ca0defb9
PB
337 * of the @uri structure
338 *
339 * userinfo = *( unreserved / pct-encoded / sub-delims / ":" )
340 *
341 * Returns 0 or the error code
342 */
be95adaf 343static int rfc3986_parse_user_info(URI *uri, const char **str)
ca0defb9
PB
344{
345 const char *cur;
346
347 cur = *str;
be95adaf 348 while (ISA_UNRESERVED(cur) || ISA_PCT_ENCODED(cur) || ISA_SUB_DELIM(cur) ||
a1515161 349 (*cur == ':')) {
be95adaf 350 NEXT(cur);
a1515161 351 }
ca0defb9 352 if (*cur == '@') {
be95adaf 353 if (uri != NULL) {
44c2286b 354 g_free(uri->user);
a1515161 355 if (uri->cleanup & 2) {
be95adaf 356 uri->user = g_strndup(*str, cur - *str);
a1515161 357 } else {
7536acb4 358 uri->user = g_uri_unescape_segment(*str, cur, NULL);
a1515161 359 }
be95adaf
SH
360 }
361 *str = cur;
42fa2725 362 return 0;
be95adaf 363 }
42fa2725 364 return 1;
ca0defb9
PB
365}
366
367/**
368 * rfc3986_parse_dec_octet:
369 * @str: the string to analyze
370 *
371 * dec-octet = DIGIT ; 0-9
372 * / %x31-39 DIGIT ; 10-99
373 * / "1" 2DIGIT ; 100-199
374 * / "2" %x30-34 DIGIT ; 200-249
375 * / "25" %x30-35 ; 250-255
376 *
377 * Skip a dec-octet.
378 *
379 * Returns 0 if found and skipped, 1 otherwise
380 */
be95adaf
SH
381static int rfc3986_parse_dec_octet(const char **str)
382{
ca0defb9
PB
383 const char *cur = *str;
384
a1515161 385 if (!(ISA_DIGIT(cur))) {
42fa2725 386 return 1;
a1515161
SH
387 }
388 if (!ISA_DIGIT(cur + 1)) {
be95adaf 389 cur++;
a1515161 390 } else if ((*cur != '0') && (ISA_DIGIT(cur + 1)) && (!ISA_DIGIT(cur + 2))) {
be95adaf 391 cur += 2;
a1515161 392 } else if ((*cur == '1') && (ISA_DIGIT(cur + 1)) && (ISA_DIGIT(cur + 2))) {
be95adaf 393 cur += 3;
a1515161
SH
394 } else if ((*cur == '2') && (*(cur + 1) >= '0') && (*(cur + 1) <= '4') &&
395 (ISA_DIGIT(cur + 2))) {
be95adaf 396 cur += 3;
a1515161
SH
397 } else if ((*cur == '2') && (*(cur + 1) == '5') && (*(cur + 2) >= '0') &&
398 (*(cur + 1) <= '5')) {
be95adaf 399 cur += 3;
a1515161 400 } else {
42fa2725 401 return 1;
a1515161 402 }
ca0defb9 403 *str = cur;
42fa2725 404 return 0;
ca0defb9
PB
405}
406/**
407 * rfc3986_parse_host:
408 * @uri: pointer to an URI structure
409 * @str: the string to analyze
410 *
411 * Parse an host part and fills in the appropriate fields
412 * of the @uri structure
413 *
414 * host = IP-literal / IPv4address / reg-name
415 * IP-literal = "[" ( IPv6address / IPvFuture ) "]"
416 * IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet
417 * reg-name = *( unreserved / pct-encoded / sub-delims )
418 *
419 * Returns 0 or the error code
420 */
be95adaf 421static int rfc3986_parse_host(URI *uri, const char **str)
ca0defb9
PB
422{
423 const char *cur = *str;
424 const char *host;
425
426 host = cur;
427 /*
a93cf9df 428 * IPv6 and future addressing scheme are enclosed between brackets
ca0defb9
PB
429 */
430 if (*cur == '[') {
431 cur++;
a1515161 432 while ((*cur != ']') && (*cur != 0)) {
be95adaf 433 cur++;
a1515161
SH
434 }
435 if (*cur != ']') {
42fa2725 436 return 1;
a1515161 437 }
be95adaf
SH
438 cur++;
439 goto found;
ca0defb9
PB
440 }
441 /*
442 * try to parse an IPv4
443 */
444 if (ISA_DIGIT(cur)) {
a1515161 445 if (rfc3986_parse_dec_octet(&cur) != 0) {
be95adaf 446 goto not_ipv4;
a1515161
SH
447 }
448 if (*cur != '.') {
be95adaf 449 goto not_ipv4;
a1515161 450 }
be95adaf 451 cur++;
a1515161 452 if (rfc3986_parse_dec_octet(&cur) != 0) {
be95adaf 453 goto not_ipv4;
a1515161
SH
454 }
455 if (*cur != '.') {
be95adaf 456 goto not_ipv4;
a1515161
SH
457 }
458 if (rfc3986_parse_dec_octet(&cur) != 0) {
be95adaf 459 goto not_ipv4;
a1515161
SH
460 }
461 if (*cur != '.') {
be95adaf 462 goto not_ipv4;
a1515161
SH
463 }
464 if (rfc3986_parse_dec_octet(&cur) != 0) {
be95adaf 465 goto not_ipv4;
a1515161 466 }
be95adaf
SH
467 goto found;
468 not_ipv4:
ca0defb9
PB
469 cur = *str;
470 }
471 /*
472 * then this should be a hostname which can be empty
473 */
a1515161 474 while (ISA_UNRESERVED(cur) || ISA_PCT_ENCODED(cur) || ISA_SUB_DELIM(cur)) {
ca0defb9 475 NEXT(cur);
a1515161 476 }
ca0defb9
PB
477found:
478 if (uri != NULL) {
44c2286b 479 g_free(uri->authority);
be95adaf 480 uri->authority = NULL;
44c2286b 481 g_free(uri->server);
be95adaf 482 if (cur != host) {
a1515161 483 if (uri->cleanup & 2) {
be95adaf 484 uri->server = g_strndup(host, cur - host);
a1515161 485 } else {
7536acb4 486 uri->server = g_uri_unescape_segment(host, cur, NULL);
a1515161
SH
487 }
488 } else {
be95adaf 489 uri->server = NULL;
a1515161 490 }
ca0defb9
PB
491 }
492 *str = cur;
42fa2725 493 return 0;
ca0defb9
PB
494}
495
496/**
497 * rfc3986_parse_authority:
498 * @uri: pointer to an URI structure
499 * @str: the string to analyze
500 *
501 * Parse an authority part and fills in the appropriate fields
502 * of the @uri structure
503 *
504 * authority = [ userinfo "@" ] host [ ":" port ]
505 *
506 * Returns 0 or the error code
507 */
be95adaf 508static int rfc3986_parse_authority(URI *uri, const char **str)
ca0defb9
PB
509{
510 const char *cur;
511 int ret;
512
513 cur = *str;
514 /*
736a83fa 515 * try to parse a userinfo and check for the trailing @
ca0defb9
PB
516 */
517 ret = rfc3986_parse_user_info(uri, &cur);
a1515161 518 if ((ret != 0) || (*cur != '@')) {
ca0defb9 519 cur = *str;
a1515161 520 } else {
ca0defb9 521 cur++;
a1515161 522 }
ca0defb9 523 ret = rfc3986_parse_host(uri, &cur);
a1515161 524 if (ret != 0) {
42fa2725 525 return ret;
a1515161 526 }
ca0defb9
PB
527 if (*cur == ':') {
528 cur++;
529 ret = rfc3986_parse_port(uri, &cur);
a1515161 530 if (ret != 0) {
42fa2725 531 return ret;
a1515161 532 }
ca0defb9
PB
533 }
534 *str = cur;
42fa2725 535 return 0;
ca0defb9
PB
536}
537
538/**
539 * rfc3986_parse_segment:
540 * @str: the string to analyze
541 * @forbid: an optional forbidden character
542 * @empty: allow an empty segment
543 *
544 * Parse a segment and fills in the appropriate fields
545 * of the @uri structure
546 *
547 * segment = *pchar
548 * segment-nz = 1*pchar
549 * segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" )
550 * ; non-zero-length segment without any colon ":"
551 *
552 * Returns 0 or the error code
553 */
be95adaf 554static int rfc3986_parse_segment(const char **str, char forbid, int empty)
ca0defb9
PB
555{
556 const char *cur;
557
558 cur = *str;
559 if (!ISA_PCHAR(cur)) {
a1515161 560 if (empty) {
42fa2725 561 return 0;
a1515161 562 }
42fa2725 563 return 1;
ca0defb9 564 }
a1515161 565 while (ISA_PCHAR(cur) && (*cur != forbid)) {
ca0defb9 566 NEXT(cur);
a1515161 567 }
ca0defb9 568 *str = cur;
42fa2725 569 return 0;
ca0defb9
PB
570}
571
572/**
573 * rfc3986_parse_path_ab_empty:
574 * @uri: pointer to an URI structure
575 * @str: the string to analyze
576 *
577 * Parse an path absolute or empty and fills in the appropriate fields
578 * of the @uri structure
579 *
580 * path-abempty = *( "/" segment )
581 *
582 * Returns 0 or the error code
583 */
be95adaf 584static int rfc3986_parse_path_ab_empty(URI *uri, const char **str)
ca0defb9
PB
585{
586 const char *cur;
587 int ret;
588
589 cur = *str;
590
591 while (*cur == '/') {
592 cur++;
be95adaf 593 ret = rfc3986_parse_segment(&cur, 0, 1);
a1515161 594 if (ret != 0) {
42fa2725 595 return ret;
a1515161 596 }
ca0defb9
PB
597 }
598 if (uri != NULL) {
44c2286b 599 g_free(uri->path);
ca0defb9 600 if (*str != cur) {
a1515161 601 if (uri->cleanup & 2) {
ca0defb9 602 uri->path = g_strndup(*str, cur - *str);
a1515161 603 } else {
7536acb4 604 uri->path = g_uri_unescape_segment(*str, cur, NULL);
a1515161 605 }
ca0defb9
PB
606 } else {
607 uri->path = NULL;
608 }
609 }
610 *str = cur;
42fa2725 611 return 0;
ca0defb9
PB
612}
613
614/**
615 * rfc3986_parse_path_absolute:
616 * @uri: pointer to an URI structure
617 * @str: the string to analyze
618 *
619 * Parse an path absolute and fills in the appropriate fields
620 * of the @uri structure
621 *
622 * path-absolute = "/" [ segment-nz *( "/" segment ) ]
623 *
624 * Returns 0 or the error code
625 */
be95adaf 626static int rfc3986_parse_path_absolute(URI *uri, const char **str)
ca0defb9
PB
627{
628 const char *cur;
629 int ret;
630
631 cur = *str;
632
a1515161 633 if (*cur != '/') {
42fa2725 634 return 1;
a1515161 635 }
ca0defb9
PB
636 cur++;
637 ret = rfc3986_parse_segment(&cur, 0, 0);
638 if (ret == 0) {
be95adaf
SH
639 while (*cur == '/') {
640 cur++;
641 ret = rfc3986_parse_segment(&cur, 0, 1);
a1515161 642 if (ret != 0) {
42fa2725 643 return ret;
a1515161 644 }
be95adaf 645 }
ca0defb9
PB
646 }
647 if (uri != NULL) {
44c2286b 648 g_free(uri->path);
ca0defb9 649 if (cur != *str) {
a1515161 650 if (uri->cleanup & 2) {
ca0defb9 651 uri->path = g_strndup(*str, cur - *str);
a1515161 652 } else {
7536acb4 653 uri->path = g_uri_unescape_segment(*str, cur, NULL);
a1515161 654 }
ca0defb9
PB
655 } else {
656 uri->path = NULL;
657 }
658 }
659 *str = cur;
42fa2725 660 return 0;
ca0defb9
PB
661}
662
663/**
664 * rfc3986_parse_path_rootless:
665 * @uri: pointer to an URI structure
666 * @str: the string to analyze
667 *
668 * Parse an path without root and fills in the appropriate fields
669 * of the @uri structure
670 *
671 * path-rootless = segment-nz *( "/" segment )
672 *
673 * Returns 0 or the error code
674 */
be95adaf 675static int rfc3986_parse_path_rootless(URI *uri, const char **str)
ca0defb9
PB
676{
677 const char *cur;
678 int ret;
679
680 cur = *str;
681
682 ret = rfc3986_parse_segment(&cur, 0, 0);
a1515161 683 if (ret != 0) {
42fa2725 684 return ret;
a1515161 685 }
ca0defb9
PB
686 while (*cur == '/') {
687 cur++;
be95adaf 688 ret = rfc3986_parse_segment(&cur, 0, 1);
a1515161 689 if (ret != 0) {
42fa2725 690 return ret;
a1515161 691 }
ca0defb9
PB
692 }
693 if (uri != NULL) {
44c2286b 694 g_free(uri->path);
ca0defb9 695 if (cur != *str) {
a1515161 696 if (uri->cleanup & 2) {
ca0defb9 697 uri->path = g_strndup(*str, cur - *str);
a1515161 698 } else {
7536acb4 699 uri->path = g_uri_unescape_segment(*str, cur, NULL);
a1515161 700 }
ca0defb9
PB
701 } else {
702 uri->path = NULL;
703 }
704 }
705 *str = cur;
42fa2725 706 return 0;
ca0defb9
PB
707}
708
709/**
710 * rfc3986_parse_path_no_scheme:
711 * @uri: pointer to an URI structure
712 * @str: the string to analyze
713 *
714 * Parse an path which is not a scheme and fills in the appropriate fields
715 * of the @uri structure
716 *
717 * path-noscheme = segment-nz-nc *( "/" segment )
718 *
719 * Returns 0 or the error code
720 */
be95adaf 721static int rfc3986_parse_path_no_scheme(URI *uri, const char **str)
ca0defb9
PB
722{
723 const char *cur;
724 int ret;
725
726 cur = *str;
727
728 ret = rfc3986_parse_segment(&cur, ':', 0);
a1515161 729 if (ret != 0) {
42fa2725 730 return ret;
a1515161 731 }
ca0defb9
PB
732 while (*cur == '/') {
733 cur++;
be95adaf 734 ret = rfc3986_parse_segment(&cur, 0, 1);
a1515161 735 if (ret != 0) {
42fa2725 736 return ret;
a1515161 737 }
ca0defb9
PB
738 }
739 if (uri != NULL) {
44c2286b 740 g_free(uri->path);
ca0defb9 741 if (cur != *str) {
a1515161 742 if (uri->cleanup & 2) {
ca0defb9 743 uri->path = g_strndup(*str, cur - *str);
a1515161 744 } else {
7536acb4 745 uri->path = g_uri_unescape_segment(*str, cur, NULL);
a1515161 746 }
ca0defb9
PB
747 } else {
748 uri->path = NULL;
749 }
750 }
751 *str = cur;
42fa2725 752 return 0;
ca0defb9
PB
753}
754
755/**
756 * rfc3986_parse_hier_part:
757 * @uri: pointer to an URI structure
758 * @str: the string to analyze
759 *
760 * Parse an hierarchical part and fills in the appropriate fields
761 * of the @uri structure
762 *
763 * hier-part = "//" authority path-abempty
764 * / path-absolute
765 * / path-rootless
766 * / path-empty
767 *
768 * Returns 0 or the error code
769 */
be95adaf 770static int rfc3986_parse_hier_part(URI *uri, const char **str)
ca0defb9
PB
771{
772 const char *cur;
773 int ret;
774
775 cur = *str;
776
777 if ((*cur == '/') && (*(cur + 1) == '/')) {
778 cur += 2;
be95adaf 779 ret = rfc3986_parse_authority(uri, &cur);
a1515161 780 if (ret != 0) {
42fa2725 781 return ret;
a1515161 782 }
be95adaf 783 ret = rfc3986_parse_path_ab_empty(uri, &cur);
a1515161 784 if (ret != 0) {
42fa2725 785 return ret;
a1515161 786 }
be95adaf 787 *str = cur;
42fa2725 788 return 0;
ca0defb9
PB
789 } else if (*cur == '/') {
790 ret = rfc3986_parse_path_absolute(uri, &cur);
a1515161 791 if (ret != 0) {
42fa2725 792 return ret;
a1515161 793 }
ca0defb9
PB
794 } else if (ISA_PCHAR(cur)) {
795 ret = rfc3986_parse_path_rootless(uri, &cur);
a1515161 796 if (ret != 0) {
42fa2725 797 return ret;
a1515161 798 }
ca0defb9 799 } else {
be95adaf
SH
800 /* path-empty is effectively empty */
801 if (uri != NULL) {
44c2286b 802 g_free(uri->path);
be95adaf
SH
803 uri->path = NULL;
804 }
ca0defb9
PB
805 }
806 *str = cur;
42fa2725 807 return 0;
ca0defb9
PB
808}
809
810/**
811 * rfc3986_parse_relative_ref:
812 * @uri: pointer to an URI structure
813 * @str: the string to analyze
814 *
815 * Parse an URI string and fills in the appropriate fields
816 * of the @uri structure
817 *
818 * relative-ref = relative-part [ "?" query ] [ "#" fragment ]
819 * relative-part = "//" authority path-abempty
820 * / path-absolute
821 * / path-noscheme
822 * / path-empty
823 *
824 * Returns 0 or the error code
825 */
be95adaf
SH
826static int rfc3986_parse_relative_ref(URI *uri, const char *str)
827{
ca0defb9
PB
828 int ret;
829
830 if ((*str == '/') && (*(str + 1) == '/')) {
831 str += 2;
be95adaf 832 ret = rfc3986_parse_authority(uri, &str);
a1515161 833 if (ret != 0) {
42fa2725 834 return ret;
a1515161 835 }
be95adaf 836 ret = rfc3986_parse_path_ab_empty(uri, &str);
a1515161 837 if (ret != 0) {
42fa2725 838 return ret;
a1515161 839 }
ca0defb9 840 } else if (*str == '/') {
be95adaf 841 ret = rfc3986_parse_path_absolute(uri, &str);
a1515161 842 if (ret != 0) {
42fa2725 843 return ret;
a1515161 844 }
ca0defb9
PB
845 } else if (ISA_PCHAR(str)) {
846 ret = rfc3986_parse_path_no_scheme(uri, &str);
a1515161 847 if (ret != 0) {
42fa2725 848 return ret;
a1515161 849 }
ca0defb9 850 } else {
be95adaf
SH
851 /* path-empty is effectively empty */
852 if (uri != NULL) {
44c2286b 853 g_free(uri->path);
be95adaf
SH
854 uri->path = NULL;
855 }
ca0defb9
PB
856 }
857
858 if (*str == '?') {
be95adaf
SH
859 str++;
860 ret = rfc3986_parse_query(uri, &str);
a1515161 861 if (ret != 0) {
42fa2725 862 return ret;
a1515161 863 }
ca0defb9
PB
864 }
865 if (*str == '#') {
be95adaf
SH
866 str++;
867 ret = rfc3986_parse_fragment(uri, &str);
a1515161 868 if (ret != 0) {
42fa2725 869 return ret;
a1515161 870 }
ca0defb9
PB
871 }
872 if (*str != 0) {
be95adaf 873 uri_clean(uri);
42fa2725 874 return 1;
ca0defb9 875 }
42fa2725 876 return 0;
ca0defb9
PB
877}
878
ca0defb9
PB
879/**
880 * rfc3986_parse:
881 * @uri: pointer to an URI structure
882 * @str: the string to analyze
883 *
884 * Parse an URI string and fills in the appropriate fields
885 * of the @uri structure
886 *
887 * scheme ":" hier-part [ "?" query ] [ "#" fragment ]
888 *
889 * Returns 0 or the error code
890 */
be95adaf
SH
891static int rfc3986_parse(URI *uri, const char *str)
892{
ca0defb9
PB
893 int ret;
894
895 ret = rfc3986_parse_scheme(uri, &str);
a1515161 896 if (ret != 0) {
42fa2725 897 return ret;
a1515161 898 }
ca0defb9 899 if (*str != ':') {
42fa2725 900 return 1;
ca0defb9
PB
901 }
902 str++;
903 ret = rfc3986_parse_hier_part(uri, &str);
a1515161 904 if (ret != 0) {
42fa2725 905 return ret;
a1515161 906 }
ca0defb9 907 if (*str == '?') {
be95adaf
SH
908 str++;
909 ret = rfc3986_parse_query(uri, &str);
a1515161 910 if (ret != 0) {
42fa2725 911 return ret;
a1515161 912 }
ca0defb9
PB
913 }
914 if (*str == '#') {
be95adaf
SH
915 str++;
916 ret = rfc3986_parse_fragment(uri, &str);
a1515161 917 if (ret != 0) {
42fa2725 918 return ret;
a1515161 919 }
ca0defb9
PB
920 }
921 if (*str != 0) {
be95adaf 922 uri_clean(uri);
42fa2725 923 return 1;
ca0defb9 924 }
42fa2725 925 return 0;
ca0defb9
PB
926}
927
928/**
929 * rfc3986_parse_uri_reference:
930 * @uri: pointer to an URI structure
931 * @str: the string to analyze
932 *
933 * Parse an URI reference string and fills in the appropriate fields
934 * of the @uri structure
935 *
936 * URI-reference = URI / relative-ref
937 *
938 * Returns 0 or the error code
939 */
be95adaf
SH
940static int rfc3986_parse_uri_reference(URI *uri, const char *str)
941{
ca0defb9
PB
942 int ret;
943
a1515161 944 if (str == NULL) {
42fa2725 945 return -1;
a1515161 946 }
ca0defb9
PB
947 uri_clean(uri);
948
949 /*
950 * Try first to parse absolute refs, then fallback to relative if
951 * it fails.
952 */
953 ret = rfc3986_parse(uri, str);
954 if (ret != 0) {
be95adaf 955 uri_clean(uri);
ca0defb9 956 ret = rfc3986_parse_relative_ref(uri, str);
be95adaf
SH
957 if (ret != 0) {
958 uri_clean(uri);
42fa2725 959 return ret;
be95adaf 960 }
ca0defb9 961 }
42fa2725 962 return 0;
ca0defb9
PB
963}
964
965/**
966 * uri_parse:
967 * @str: the URI string to analyze
968 *
969 * Parse an URI based on RFC 3986
970 *
971 * URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ]
972 *
973 * Returns a newly built URI or NULL in case of error
974 */
be95adaf
SH
975URI *uri_parse(const char *str)
976{
ca0defb9
PB
977 URI *uri;
978 int ret;
979
a1515161 980 if (str == NULL) {
42fa2725 981 return NULL;
a1515161 982 }
ca0defb9 983 uri = uri_new();
c89c6e80
MA
984 ret = rfc3986_parse_uri_reference(uri, str);
985 if (ret) {
986 uri_free(uri);
42fa2725 987 return NULL;
ca0defb9 988 }
42fa2725 989 return uri;
ca0defb9
PB
990}
991
992/**
993 * uri_parse_into:
994 * @uri: pointer to an URI structure
995 * @str: the string to analyze
996 *
997 * Parse an URI reference string based on RFC 3986 and fills in the
998 * appropriate fields of the @uri structure
999 *
1000 * URI-reference = URI / relative-ref
1001 *
1002 * Returns 0 or the error code
1003 */
be95adaf
SH
1004int uri_parse_into(URI *uri, const char *str)
1005{
42fa2725 1006 return rfc3986_parse_uri_reference(uri, str);
ca0defb9
PB
1007}
1008
1009/**
1010 * uri_parse_raw:
1011 * @str: the URI string to analyze
1012 * @raw: if 1 unescaping of URI pieces are disabled
1013 *
1014 * Parse an URI but allows to keep intact the original fragments.
1015 *
1016 * URI-reference = URI / relative-ref
1017 *
1018 * Returns a newly built URI or NULL in case of error
1019 */
be95adaf
SH
1020URI *uri_parse_raw(const char *str, int raw)
1021{
ca0defb9
PB
1022 URI *uri;
1023 int ret;
1024
a1515161 1025 if (str == NULL) {
42fa2725 1026 return NULL;
a1515161 1027 }
ca0defb9 1028 uri = uri_new();
c89c6e80
MA
1029 if (raw) {
1030 uri->cleanup |= 2;
1031 }
1032 ret = uri_parse_into(uri, str);
1033 if (ret) {
1034 uri_free(uri);
42fa2725 1035 return NULL;
ca0defb9 1036 }
42fa2725 1037 return uri;
ca0defb9
PB
1038}
1039
1040/************************************************************************
be95adaf
SH
1041 * *
1042 * Generic URI structure functions *
1043 * *
ca0defb9
PB
1044 ************************************************************************/
1045
1046/**
1047 * uri_new:
1048 *
1049 * Simply creates an empty URI
1050 *
1051 * Returns the new structure or NULL in case of error
1052 */
be95adaf
SH
1053URI *uri_new(void)
1054{
4a4ff4c5 1055 return g_new0(URI, 1);
ca0defb9
PB
1056}
1057
1058/**
1059 * realloc2n:
1060 *
1061 * Function to handle properly a reallocation when saving an URI
1062 * Also imposes some limit on the length of an URI string output
1063 */
be95adaf
SH
1064static char *realloc2n(char *ret, int *max)
1065{
ca0defb9
PB
1066 char *temp;
1067 int tmp;
1068
1069 tmp = *max * 2;
1070 temp = g_realloc(ret, (tmp + 1));
1071 *max = tmp;
42fa2725 1072 return temp;
ca0defb9
PB
1073}
1074
1075/**
1076 * uri_to_string:
1077 * @uri: pointer to an URI
1078 *
1079 * Save the URI as an escaped string
1080 *
1081 * Returns a new string (to be deallocated by caller)
1082 */
be95adaf
SH
1083char *uri_to_string(URI *uri)
1084{
ca0defb9
PB
1085 char *ret = NULL;
1086 char *temp;
1087 const char *p;
1088 int len;
1089 int max;
1090
a1515161 1091 if (uri == NULL) {
42fa2725 1092 return NULL;
a1515161 1093 }
ca0defb9
PB
1094
1095 max = 80;
1096 ret = g_malloc(max + 1);
1097 len = 0;
1098
1099 if (uri->scheme != NULL) {
be95adaf
SH
1100 p = uri->scheme;
1101 while (*p != 0) {
1102 if (len >= max) {
ca0defb9 1103 temp = realloc2n(ret, &max);
be95adaf
SH
1104 ret = temp;
1105 }
1106 ret[len++] = *p++;
1107 }
1108 if (len >= max) {
ca0defb9 1109 temp = realloc2n(ret, &max);
ca0defb9 1110 ret = temp;
be95adaf
SH
1111 }
1112 ret[len++] = ':';
ca0defb9
PB
1113 }
1114 if (uri->opaque != NULL) {
be95adaf
SH
1115 p = uri->opaque;
1116 while (*p != 0) {
1117 if (len + 3 >= max) {
ca0defb9 1118 temp = realloc2n(ret, &max);
ca0defb9 1119 ret = temp;
be95adaf 1120 }
a1515161 1121 if (IS_RESERVED(*(p)) || IS_UNRESERVED(*(p))) {
be95adaf 1122 ret[len++] = *p++;
a1515161 1123 } else {
be95adaf
SH
1124 int val = *(unsigned char *)p++;
1125 int hi = val / 0x10, lo = val % 0x10;
1126 ret[len++] = '%';
1127 ret[len++] = hi + (hi > 9 ? 'A' - 10 : '0');
1128 ret[len++] = lo + (lo > 9 ? 'A' - 10 : '0');
1129 }
1130 }
ca0defb9 1131 } else {
be95adaf
SH
1132 if (uri->server != NULL) {
1133 if (len + 3 >= max) {
ca0defb9 1134 temp = realloc2n(ret, &max);
ca0defb9 1135 ret = temp;
be95adaf
SH
1136 }
1137 ret[len++] = '/';
1138 ret[len++] = '/';
1139 if (uri->user != NULL) {
1140 p = uri->user;
1141 while (*p != 0) {
1142 if (len + 3 >= max) {
ca0defb9 1143 temp = realloc2n(ret, &max);
ca0defb9 1144 ret = temp;
be95adaf
SH
1145 }
1146 if ((IS_UNRESERVED(*(p))) || ((*(p) == ';')) ||
1147 ((*(p) == ':')) || ((*(p) == '&')) || ((*(p) == '=')) ||
a1515161 1148 ((*(p) == '+')) || ((*(p) == '$')) || ((*(p) == ','))) {
be95adaf 1149 ret[len++] = *p++;
a1515161 1150 } else {
be95adaf
SH
1151 int val = *(unsigned char *)p++;
1152 int hi = val / 0x10, lo = val % 0x10;
1153 ret[len++] = '%';
1154 ret[len++] = hi + (hi > 9 ? 'A' - 10 : '0');
1155 ret[len++] = lo + (lo > 9 ? 'A' - 10 : '0');
1156 }
1157 }
1158 if (len + 3 >= max) {
ca0defb9 1159 temp = realloc2n(ret, &max);
ca0defb9 1160 ret = temp;
be95adaf
SH
1161 }
1162 ret[len++] = '@';
1163 }
1164 p = uri->server;
1165 while (*p != 0) {
1166 if (len >= max) {
ca0defb9 1167 temp = realloc2n(ret, &max);
ca0defb9 1168 ret = temp;
be95adaf
SH
1169 }
1170 ret[len++] = *p++;
1171 }
1172 if (uri->port > 0) {
1173 if (len + 10 >= max) {
ca0defb9 1174 temp = realloc2n(ret, &max);
ca0defb9 1175 ret = temp;
be95adaf
SH
1176 }
1177 len += snprintf(&ret[len], max - len, ":%d", uri->port);
1178 }
1179 } else if (uri->authority != NULL) {
1180 if (len + 3 >= max) {
ca0defb9 1181 temp = realloc2n(ret, &max);
ca0defb9 1182 ret = temp;
be95adaf
SH
1183 }
1184 ret[len++] = '/';
1185 ret[len++] = '/';
1186 p = uri->authority;
1187 while (*p != 0) {
1188 if (len + 3 >= max) {
ca0defb9 1189 temp = realloc2n(ret, &max);
ca0defb9 1190 ret = temp;
be95adaf
SH
1191 }
1192 if ((IS_UNRESERVED(*(p))) || ((*(p) == '$')) ||
1193 ((*(p) == ',')) || ((*(p) == ';')) || ((*(p) == ':')) ||
1194 ((*(p) == '@')) || ((*(p) == '&')) || ((*(p) == '=')) ||
a1515161 1195 ((*(p) == '+'))) {
be95adaf 1196 ret[len++] = *p++;
a1515161 1197 } else {
be95adaf
SH
1198 int val = *(unsigned char *)p++;
1199 int hi = val / 0x10, lo = val % 0x10;
1200 ret[len++] = '%';
1201 ret[len++] = hi + (hi > 9 ? 'A' - 10 : '0');
1202 ret[len++] = lo + (lo > 9 ? 'A' - 10 : '0');
1203 }
1204 }
1205 } else if (uri->scheme != NULL) {
1206 if (len + 3 >= max) {
ca0defb9 1207 temp = realloc2n(ret, &max);
ca0defb9 1208 ret = temp;
be95adaf
SH
1209 }
1210 ret[len++] = '/';
1211 ret[len++] = '/';
1212 }
1213 if (uri->path != NULL) {
1214 p = uri->path;
1215 /*
1216 * the colon in file:///d: should not be escaped or
1217 * Windows accesses fail later.
1218 */
1219 if ((uri->scheme != NULL) && (p[0] == '/') &&
1220 (((p[1] >= 'a') && (p[1] <= 'z')) ||
1221 ((p[1] >= 'A') && (p[1] <= 'Z'))) &&
1222 (p[2] == ':') && (!strcmp(uri->scheme, "file"))) {
1223 if (len + 3 >= max) {
ca0defb9 1224 temp = realloc2n(ret, &max);
ca0defb9 1225 ret = temp;
be95adaf
SH
1226 }
1227 ret[len++] = *p++;
1228 ret[len++] = *p++;
1229 ret[len++] = *p++;
1230 }
1231 while (*p != 0) {
1232 if (len + 3 >= max) {
ca0defb9 1233 temp = realloc2n(ret, &max);
ca0defb9 1234 ret = temp;
be95adaf
SH
1235 }
1236 if ((IS_UNRESERVED(*(p))) || ((*(p) == '/')) ||
ca0defb9 1237 ((*(p) == ';')) || ((*(p) == '@')) || ((*(p) == '&')) ||
be95adaf 1238 ((*(p) == '=')) || ((*(p) == '+')) || ((*(p) == '$')) ||
a1515161 1239 ((*(p) == ','))) {
be95adaf 1240 ret[len++] = *p++;
a1515161 1241 } else {
be95adaf
SH
1242 int val = *(unsigned char *)p++;
1243 int hi = val / 0x10, lo = val % 0x10;
1244 ret[len++] = '%';
1245 ret[len++] = hi + (hi > 9 ? 'A' - 10 : '0');
1246 ret[len++] = lo + (lo > 9 ? 'A' - 10 : '0');
1247 }
1248 }
1249 }
1250 if (uri->query != NULL) {
1251 if (len + 1 >= max) {
ca0defb9 1252 temp = realloc2n(ret, &max);
ca0defb9 1253 ret = temp;
be95adaf
SH
1254 }
1255 ret[len++] = '?';
1256 p = uri->query;
1257 while (*p != 0) {
1258 if (len + 1 >= max) {
ca0defb9 1259 temp = realloc2n(ret, &max);
ca0defb9 1260 ret = temp;
be95adaf
SH
1261 }
1262 ret[len++] = *p++;
1263 }
1264 }
ca0defb9
PB
1265 }
1266 if (uri->fragment != NULL) {
be95adaf 1267 if (len + 3 >= max) {
ca0defb9 1268 temp = realloc2n(ret, &max);
ca0defb9 1269 ret = temp;
be95adaf
SH
1270 }
1271 ret[len++] = '#';
1272 p = uri->fragment;
1273 while (*p != 0) {
1274 if (len + 3 >= max) {
ca0defb9 1275 temp = realloc2n(ret, &max);
ca0defb9 1276 ret = temp;
be95adaf 1277 }
a1515161 1278 if ((IS_UNRESERVED(*(p))) || (IS_RESERVED(*(p)))) {
be95adaf 1279 ret[len++] = *p++;
a1515161 1280 } else {
be95adaf
SH
1281 int val = *(unsigned char *)p++;
1282 int hi = val / 0x10, lo = val % 0x10;
1283 ret[len++] = '%';
1284 ret[len++] = hi + (hi > 9 ? 'A' - 10 : '0');
1285 ret[len++] = lo + (lo > 9 ? 'A' - 10 : '0');
1286 }
1287 }
ca0defb9
PB
1288 }
1289 if (len >= max) {
1290 temp = realloc2n(ret, &max);
ca0defb9
PB
1291 ret = temp;
1292 }
1293 ret[len] = 0;
42fa2725 1294 return ret;
ca0defb9
PB
1295}
1296
1297/**
1298 * uri_clean:
1299 * @uri: pointer to an URI
1300 *
1301 * Make sure the URI struct is free of content
1302 */
be95adaf
SH
1303static void uri_clean(URI *uri)
1304{
a1515161 1305 if (uri == NULL) {
be95adaf 1306 return;
a1515161 1307 }
ca0defb9 1308
44c2286b 1309 g_free(uri->scheme);
ca0defb9 1310 uri->scheme = NULL;
44c2286b 1311 g_free(uri->server);
ca0defb9 1312 uri->server = NULL;
44c2286b 1313 g_free(uri->user);
ca0defb9 1314 uri->user = NULL;
44c2286b 1315 g_free(uri->path);
ca0defb9 1316 uri->path = NULL;
44c2286b 1317 g_free(uri->fragment);
ca0defb9 1318 uri->fragment = NULL;
44c2286b 1319 g_free(uri->opaque);
ca0defb9 1320 uri->opaque = NULL;
44c2286b 1321 g_free(uri->authority);
ca0defb9 1322 uri->authority = NULL;
44c2286b 1323 g_free(uri->query);
ca0defb9
PB
1324 uri->query = NULL;
1325}
1326
1327/**
1328 * uri_free:
c2615bdf 1329 * @uri: pointer to an URI, NULL is ignored
ca0defb9
PB
1330 *
1331 * Free up the URI struct
1332 */
be95adaf
SH
1333void uri_free(URI *uri)
1334{
ca0defb9
PB
1335 uri_clean(uri);
1336 g_free(uri);
1337}
1338
ca0defb9 1339/************************************************************************
be95adaf
SH
1340 * *
1341 * Public functions *
1342 * *
ca0defb9
PB
1343 ************************************************************************/
1344
ca0defb9
PB
1345/*
1346 * Utility functions to help parse and assemble query strings.
1347 */
1348
be95adaf 1349struct QueryParams *query_params_new(int init_alloc)
ca0defb9
PB
1350{
1351 struct QueryParams *ps;
1352
a1515161 1353 if (init_alloc <= 0) {
be95adaf 1354 init_alloc = 1;
a1515161 1355 }
ca0defb9
PB
1356
1357 ps = g_new(QueryParams, 1);
1358 ps->n = 0;
1359 ps->alloc = init_alloc;
1360 ps->p = g_new(QueryParam, ps->alloc);
1361
1362 return ps;
1363}
1364
1365/* Ensure there is space to store at least one more parameter
1366 * at the end of the set.
1367 */
be95adaf
SH
1368static int query_params_append(struct QueryParams *ps, const char *name,
1369 const char *value)
ca0defb9
PB
1370{
1371 if (ps->n >= ps->alloc) {
1372 ps->p = g_renew(QueryParam, ps->p, ps->alloc * 2);
1373 ps->alloc *= 2;
1374 }
1375
1376 ps->p[ps->n].name = g_strdup(name);
7f303adc 1377 ps->p[ps->n].value = g_strdup(value);
ca0defb9
PB
1378 ps->p[ps->n].ignore = 0;
1379 ps->n++;
1380
1381 return 0;
1382}
1383
be95adaf 1384void query_params_free(struct QueryParams *ps)
ca0defb9
PB
1385{
1386 int i;
1387
1388 for (i = 0; i < ps->n; ++i) {
be95adaf
SH
1389 g_free(ps->p[i].name);
1390 g_free(ps->p[i].value);
ca0defb9 1391 }
be95adaf
SH
1392 g_free(ps->p);
1393 g_free(ps);
ca0defb9
PB
1394}
1395
be95adaf 1396struct QueryParams *query_params_parse(const char *query)
ca0defb9
PB
1397{
1398 struct QueryParams *ps;
1399 const char *end, *eq;
1400
be95adaf 1401 ps = query_params_new(0);
a1515161 1402 if (!query || query[0] == '\0') {
be95adaf 1403 return ps;
a1515161 1404 }
ca0defb9
PB
1405
1406 while (*query) {
1407 char *name = NULL, *value = NULL;
1408
1409 /* Find the next separator, or end of the string. */
be95adaf 1410 end = strchr(query, '&');
a1515161 1411 if (!end) {
5c99fa37 1412 end = qemu_strchrnul(query, ';');
a1515161 1413 }
ca0defb9
PB
1414
1415 /* Find the first '=' character between here and end. */
be95adaf 1416 eq = strchr(query, '=');
a1515161 1417 if (eq && eq >= end) {
be95adaf 1418 eq = NULL;
a1515161 1419 }
ca0defb9
PB
1420
1421 /* Empty section (eg. "&&"). */
a1515161 1422 if (end == query) {
ca0defb9 1423 goto next;
a1515161 1424 }
ca0defb9
PB
1425
1426 /* If there is no '=' character, then we have just "name"
1427 * and consistent with CGI.pm we assume value is "".
1428 */
1429 else if (!eq) {
7536acb4 1430 name = g_uri_unescape_segment(query, end, NULL);
ca0defb9
PB
1431 value = NULL;
1432 }
1433 /* Or if we have "name=" here (works around annoying
1434 * problem when calling uri_string_unescape with len = 0).
1435 */
be95adaf 1436 else if (eq + 1 == end) {
7536acb4 1437 name = g_uri_unescape_segment(query, eq, NULL);
ca0defb9
PB
1438 value = g_new0(char, 1);
1439 }
1440 /* If the '=' character is at the beginning then we have
1441 * "=value" and consistent with CGI.pm we _ignore_ this.
1442 */
a1515161 1443 else if (query == eq) {
ca0defb9 1444 goto next;
a1515161 1445 }
ca0defb9
PB
1446
1447 /* Otherwise it's "name=value". */
1448 else {
7536acb4
TH
1449 name = g_uri_unescape_segment(query, eq, NULL);
1450 value = g_uri_unescape_segment(eq + 1, end, NULL);
ca0defb9
PB
1451 }
1452
1453 /* Append to the parameter set. */
be95adaf 1454 query_params_append(ps, name, value);
ca0defb9
PB
1455 g_free(name);
1456 g_free(value);
1457
1458 next:
1459 query = end;
a1515161 1460 if (*query) {
be95adaf 1461 query++; /* skip '&' separator */
a1515161 1462 }
ca0defb9
PB
1463 }
1464
1465 return ps;
1466}