Statistics
| Branch: | Revision:

root / util / uri.c @ 01207d0b

History | View | Annotate | Download (56.4 kB)

1 ca0defb9 Paolo Bonzini
/**
2 ca0defb9 Paolo Bonzini
 * uri.c: set of generic URI related routines
3 ca0defb9 Paolo Bonzini
 *
4 ca0defb9 Paolo Bonzini
 * Reference: RFCs 3986, 2732 and 2373
5 ca0defb9 Paolo Bonzini
 *
6 ca0defb9 Paolo Bonzini
 * Copyright (C) 1998-2003 Daniel Veillard.  All Rights Reserved.
7 ca0defb9 Paolo Bonzini
 *
8 ca0defb9 Paolo Bonzini
 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 ca0defb9 Paolo Bonzini
 * of this software and associated documentation files (the "Software"), to deal
10 ca0defb9 Paolo Bonzini
 * in the Software without restriction, including without limitation the rights
11 ca0defb9 Paolo Bonzini
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 ca0defb9 Paolo Bonzini
 * copies of the Software, and to permit persons to whom the Software is
13 ca0defb9 Paolo Bonzini
 * furnished to do so, subject to the following conditions:
14 ca0defb9 Paolo Bonzini
 *
15 ca0defb9 Paolo Bonzini
 * The above copyright notice and this permission notice shall be included in
16 ca0defb9 Paolo Bonzini
 * all copies or substantial portions of the Software.
17 ca0defb9 Paolo Bonzini
 *
18 ca0defb9 Paolo Bonzini
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 ca0defb9 Paolo Bonzini
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 ca0defb9 Paolo Bonzini
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
21 ca0defb9 Paolo Bonzini
 * DANIEL VEILLARD BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
22 ca0defb9 Paolo Bonzini
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 ca0defb9 Paolo Bonzini
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 ca0defb9 Paolo Bonzini
 *
25 ca0defb9 Paolo Bonzini
 * Except as contained in this notice, the name of Daniel Veillard shall not
26 ca0defb9 Paolo Bonzini
 * be used in advertising or otherwise to promote the sale, use or other
27 ca0defb9 Paolo Bonzini
 * dealings in this Software without prior written authorization from him.
28 ca0defb9 Paolo Bonzini
 *
29 ca0defb9 Paolo Bonzini
 * daniel@veillard.com
30 ca0defb9 Paolo Bonzini
 *
31 ca0defb9 Paolo Bonzini
 **
32 ca0defb9 Paolo Bonzini
 *
33 ca0defb9 Paolo Bonzini
 * Copyright (C) 2007, 2009-2010 Red Hat, Inc.
34 ca0defb9 Paolo Bonzini
 *
35 ca0defb9 Paolo Bonzini
 * This library is free software; you can redistribute it and/or
36 ca0defb9 Paolo Bonzini
 * modify it under the terms of the GNU Lesser General Public
37 ca0defb9 Paolo Bonzini
 * License as published by the Free Software Foundation; either
38 ca0defb9 Paolo Bonzini
 * version 2.1 of the License, or (at your option) any later version.
39 ca0defb9 Paolo Bonzini
 *
40 ca0defb9 Paolo Bonzini
 * This library is distributed in the hope that it will be useful,
41 ca0defb9 Paolo Bonzini
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
42 ca0defb9 Paolo Bonzini
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
43 ca0defb9 Paolo Bonzini
 * Lesser General Public License for more details.
44 ca0defb9 Paolo Bonzini
 *
45 ca0defb9 Paolo Bonzini
 * You should have received a copy of the GNU Lesser General Public
46 ca0defb9 Paolo Bonzini
 * License along with this library; if not, write to the Free Software
47 ca0defb9 Paolo Bonzini
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
48 ca0defb9 Paolo Bonzini
 *
49 ca0defb9 Paolo Bonzini
 * Authors:
50 ca0defb9 Paolo Bonzini
 *    Richard W.M. Jones <rjones@redhat.com>
51 ca0defb9 Paolo Bonzini
 *
52 ca0defb9 Paolo Bonzini
 */
53 ca0defb9 Paolo Bonzini
54 ca0defb9 Paolo Bonzini
#include <glib.h>
55 ca0defb9 Paolo Bonzini
#include <string.h>
56 ca0defb9 Paolo Bonzini
#include <stdio.h>
57 ca0defb9 Paolo Bonzini
58 1de7afc9 Paolo Bonzini
#include "qemu/uri.h"
59 ca0defb9 Paolo Bonzini
60 ca0defb9 Paolo Bonzini
static void uri_clean(URI *uri);
61 ca0defb9 Paolo Bonzini
62 ca0defb9 Paolo Bonzini
/*
63 ca0defb9 Paolo Bonzini
 * Old rule from 2396 used in legacy handling code
64 ca0defb9 Paolo Bonzini
 * alpha    = lowalpha | upalpha
65 ca0defb9 Paolo Bonzini
 */
66 ca0defb9 Paolo Bonzini
#define IS_ALPHA(x) (IS_LOWALPHA(x) || IS_UPALPHA(x))
67 ca0defb9 Paolo Bonzini
68 ca0defb9 Paolo Bonzini
69 ca0defb9 Paolo Bonzini
/*
70 ca0defb9 Paolo Bonzini
 * lowalpha = "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j" |
71 ca0defb9 Paolo Bonzini
 *            "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" | "s" | "t" |
72 ca0defb9 Paolo Bonzini
 *            "u" | "v" | "w" | "x" | "y" | "z"
73 ca0defb9 Paolo Bonzini
 */
74 ca0defb9 Paolo Bonzini
75 ca0defb9 Paolo Bonzini
#define IS_LOWALPHA(x) (((x) >= 'a') && ((x) <= 'z'))
76 ca0defb9 Paolo Bonzini
77 ca0defb9 Paolo Bonzini
/*
78 ca0defb9 Paolo Bonzini
 * upalpha = "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" | "J" |
79 ca0defb9 Paolo Bonzini
 *           "K" | "L" | "M" | "N" | "O" | "P" | "Q" | "R" | "S" | "T" |
80 ca0defb9 Paolo Bonzini
 *           "U" | "V" | "W" | "X" | "Y" | "Z"
81 ca0defb9 Paolo Bonzini
 */
82 ca0defb9 Paolo Bonzini
#define IS_UPALPHA(x) (((x) >= 'A') && ((x) <= 'Z'))
83 ca0defb9 Paolo Bonzini
84 ca0defb9 Paolo Bonzini
#ifdef IS_DIGIT
85 ca0defb9 Paolo Bonzini
#undef IS_DIGIT
86 ca0defb9 Paolo Bonzini
#endif
87 ca0defb9 Paolo Bonzini
/*
88 ca0defb9 Paolo Bonzini
 * digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
89 ca0defb9 Paolo Bonzini
 */
90 ca0defb9 Paolo Bonzini
#define IS_DIGIT(x) (((x) >= '0') && ((x) <= '9'))
91 ca0defb9 Paolo Bonzini
92 ca0defb9 Paolo Bonzini
/*
93 ca0defb9 Paolo Bonzini
 * alphanum = alpha | digit
94 ca0defb9 Paolo Bonzini
 */
95 ca0defb9 Paolo Bonzini
96 ca0defb9 Paolo Bonzini
#define IS_ALPHANUM(x) (IS_ALPHA(x) || IS_DIGIT(x))
97 ca0defb9 Paolo Bonzini
98 ca0defb9 Paolo Bonzini
/*
99 ca0defb9 Paolo Bonzini
 * mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")"
100 ca0defb9 Paolo Bonzini
 */
101 ca0defb9 Paolo Bonzini
102 ca0defb9 Paolo Bonzini
#define IS_MARK(x) (((x) == '-') || ((x) == '_') || ((x) == '.') ||     \
103 ca0defb9 Paolo Bonzini
    ((x) == '!') || ((x) == '~') || ((x) == '*') || ((x) == '\'') ||    \
104 ca0defb9 Paolo Bonzini
    ((x) == '(') || ((x) == ')'))
105 ca0defb9 Paolo Bonzini
106 ca0defb9 Paolo Bonzini
/*
107 ca0defb9 Paolo Bonzini
 * unwise = "{" | "}" | "|" | "\" | "^" | "`"
108 ca0defb9 Paolo Bonzini
 */
109 ca0defb9 Paolo Bonzini
110 ca0defb9 Paolo Bonzini
#define IS_UNWISE(p)                                                    \
111 ca0defb9 Paolo Bonzini
      (((*(p) == '{')) || ((*(p) == '}')) || ((*(p) == '|')) ||         \
112 ca0defb9 Paolo Bonzini
       ((*(p) == '\\')) || ((*(p) == '^')) || ((*(p) == '[')) ||        \
113 ca0defb9 Paolo Bonzini
       ((*(p) == ']')) || ((*(p) == '`')))
114 ca0defb9 Paolo Bonzini
/*
115 ca0defb9 Paolo Bonzini
 * reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | "," |
116 ca0defb9 Paolo Bonzini
 *            "[" | "]"
117 ca0defb9 Paolo Bonzini
 */
118 ca0defb9 Paolo Bonzini
119 ca0defb9 Paolo Bonzini
#define IS_RESERVED(x) (((x) == ';') || ((x) == '/') || ((x) == '?') || \
120 ca0defb9 Paolo Bonzini
        ((x) == ':') || ((x) == '@') || ((x) == '&') || ((x) == '=') || \
121 ca0defb9 Paolo Bonzini
        ((x) == '+') || ((x) == '$') || ((x) == ',') || ((x) == '[') || \
122 ca0defb9 Paolo Bonzini
        ((x) == ']'))
123 ca0defb9 Paolo Bonzini
124 ca0defb9 Paolo Bonzini
/*
125 ca0defb9 Paolo Bonzini
 * unreserved = alphanum | mark
126 ca0defb9 Paolo Bonzini
 */
127 ca0defb9 Paolo Bonzini
128 ca0defb9 Paolo Bonzini
#define IS_UNRESERVED(x) (IS_ALPHANUM(x) || IS_MARK(x))
129 ca0defb9 Paolo Bonzini
130 ca0defb9 Paolo Bonzini
/*
131 ca0defb9 Paolo Bonzini
 * Skip to next pointer char, handle escaped sequences
132 ca0defb9 Paolo Bonzini
 */
133 ca0defb9 Paolo Bonzini
134 ca0defb9 Paolo Bonzini
#define NEXT(p) ((*p == '%')? p += 3 : p++)
135 ca0defb9 Paolo Bonzini
136 ca0defb9 Paolo Bonzini
/*
137 ca0defb9 Paolo Bonzini
 * Productions from the spec.
138 ca0defb9 Paolo Bonzini
 *
139 ca0defb9 Paolo Bonzini
 *    authority     = server | reg_name
140 ca0defb9 Paolo Bonzini
 *    reg_name      = 1*( unreserved | escaped | "$" | "," |
141 ca0defb9 Paolo Bonzini
 *                        ";" | ":" | "@" | "&" | "=" | "+" )
142 ca0defb9 Paolo Bonzini
 *
143 ca0defb9 Paolo Bonzini
 * path          = [ abs_path | opaque_part ]
144 ca0defb9 Paolo Bonzini
 */
145 ca0defb9 Paolo Bonzini
146 ca0defb9 Paolo Bonzini
147 ca0defb9 Paolo Bonzini
/************************************************************************
148 ca0defb9 Paolo Bonzini
 *                                                                        *
149 ca0defb9 Paolo Bonzini
 *                         RFC 3986 parser                                *
150 ca0defb9 Paolo Bonzini
 *                                                                        *
151 ca0defb9 Paolo Bonzini
 ************************************************************************/
152 ca0defb9 Paolo Bonzini
153 ca0defb9 Paolo Bonzini
#define ISA_DIGIT(p) ((*(p) >= '0') && (*(p) <= '9'))
154 ca0defb9 Paolo Bonzini
#define ISA_ALPHA(p) (((*(p) >= 'a') && (*(p) <= 'z')) ||                \
155 ca0defb9 Paolo Bonzini
                      ((*(p) >= 'A') && (*(p) <= 'Z')))
156 ca0defb9 Paolo Bonzini
#define ISA_HEXDIG(p)                                                        \
157 ca0defb9 Paolo Bonzini
       (ISA_DIGIT(p) || ((*(p) >= 'a') && (*(p) <= 'f')) ||                \
158 ca0defb9 Paolo Bonzini
        ((*(p) >= 'A') && (*(p) <= 'F')))
159 ca0defb9 Paolo Bonzini
160 ca0defb9 Paolo Bonzini
/*
161 ca0defb9 Paolo Bonzini
 *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
162 ca0defb9 Paolo Bonzini
 *                     / "*" / "+" / "," / ";" / "="
163 ca0defb9 Paolo Bonzini
 */
164 ca0defb9 Paolo Bonzini
#define ISA_SUB_DELIM(p)                                                \
165 ca0defb9 Paolo Bonzini
      (((*(p) == '!')) || ((*(p) == '$')) || ((*(p) == '&')) ||                \
166 ca0defb9 Paolo Bonzini
       ((*(p) == '(')) || ((*(p) == ')')) || ((*(p) == '*')) ||                \
167 ca0defb9 Paolo Bonzini
       ((*(p) == '+')) || ((*(p) == ',')) || ((*(p) == ';')) ||                \
168 ca0defb9 Paolo Bonzini
       ((*(p) == '=')) || ((*(p) == '\'')))
169 ca0defb9 Paolo Bonzini
170 ca0defb9 Paolo Bonzini
/*
171 ca0defb9 Paolo Bonzini
 *    gen-delims    = ":" / "/" / "?" / "#" / "[" / "]" / "@"
172 ca0defb9 Paolo Bonzini
 */
173 ca0defb9 Paolo Bonzini
#define ISA_GEN_DELIM(p)                                                \
174 ca0defb9 Paolo Bonzini
      (((*(p) == ':')) || ((*(p) == '/')) || ((*(p) == '?')) ||         \
175 ca0defb9 Paolo Bonzini
       ((*(p) == '#')) || ((*(p) == '[')) || ((*(p) == ']')) ||         \
176 ca0defb9 Paolo Bonzini
       ((*(p) == '@')))
177 ca0defb9 Paolo Bonzini
178 ca0defb9 Paolo Bonzini
/*
179 ca0defb9 Paolo Bonzini
 *    reserved      = gen-delims / sub-delims
180 ca0defb9 Paolo Bonzini
 */
181 ca0defb9 Paolo Bonzini
#define ISA_RESERVED(p) (ISA_GEN_DELIM(p) || (ISA_SUB_DELIM(p)))
182 ca0defb9 Paolo Bonzini
183 ca0defb9 Paolo Bonzini
/*
184 ca0defb9 Paolo Bonzini
 *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
185 ca0defb9 Paolo Bonzini
 */
186 ca0defb9 Paolo Bonzini
#define ISA_UNRESERVED(p)                                                \
187 ca0defb9 Paolo Bonzini
      ((ISA_ALPHA(p)) || (ISA_DIGIT(p)) || ((*(p) == '-')) ||                \
188 ca0defb9 Paolo Bonzini
       ((*(p) == '.')) || ((*(p) == '_')) || ((*(p) == '~')))
189 ca0defb9 Paolo Bonzini
190 ca0defb9 Paolo Bonzini
/*
191 ca0defb9 Paolo Bonzini
 *    pct-encoded   = "%" HEXDIG HEXDIG
192 ca0defb9 Paolo Bonzini
 */
193 ca0defb9 Paolo Bonzini
#define ISA_PCT_ENCODED(p)                                                \
194 ca0defb9 Paolo Bonzini
     ((*(p) == '%') && (ISA_HEXDIG(p + 1)) && (ISA_HEXDIG(p + 2)))
195 ca0defb9 Paolo Bonzini
196 ca0defb9 Paolo Bonzini
/*
197 ca0defb9 Paolo Bonzini
 *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
198 ca0defb9 Paolo Bonzini
 */
199 ca0defb9 Paolo Bonzini
#define ISA_PCHAR(p)                                                        \
200 ca0defb9 Paolo Bonzini
     (ISA_UNRESERVED(p) || ISA_PCT_ENCODED(p) || ISA_SUB_DELIM(p) ||        \
201 ca0defb9 Paolo Bonzini
      ((*(p) == ':')) || ((*(p) == '@')))
202 ca0defb9 Paolo Bonzini
203 ca0defb9 Paolo Bonzini
/**
204 ca0defb9 Paolo Bonzini
 * rfc3986_parse_scheme:
205 ca0defb9 Paolo Bonzini
 * @uri:  pointer to an URI structure
206 ca0defb9 Paolo Bonzini
 * @str:  pointer to the string to analyze
207 ca0defb9 Paolo Bonzini
 *
208 ca0defb9 Paolo Bonzini
 * Parse an URI scheme
209 ca0defb9 Paolo Bonzini
 *
210 ca0defb9 Paolo Bonzini
 * ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
211 ca0defb9 Paolo Bonzini
 *
212 ca0defb9 Paolo Bonzini
 * Returns 0 or the error code
213 ca0defb9 Paolo Bonzini
 */
214 ca0defb9 Paolo Bonzini
static int
215 ca0defb9 Paolo Bonzini
rfc3986_parse_scheme(URI *uri, const char **str) {
216 ca0defb9 Paolo Bonzini
    const char *cur;
217 ca0defb9 Paolo Bonzini
218 ca0defb9 Paolo Bonzini
    if (str == NULL)
219 ca0defb9 Paolo Bonzini
        return(-1);
220 ca0defb9 Paolo Bonzini
221 ca0defb9 Paolo Bonzini
    cur = *str;
222 ca0defb9 Paolo Bonzini
    if (!ISA_ALPHA(cur))
223 ca0defb9 Paolo Bonzini
        return(2);
224 ca0defb9 Paolo Bonzini
    cur++;
225 ca0defb9 Paolo Bonzini
    while (ISA_ALPHA(cur) || ISA_DIGIT(cur) ||
226 ca0defb9 Paolo Bonzini
           (*cur == '+') || (*cur == '-') || (*cur == '.')) cur++;
227 ca0defb9 Paolo Bonzini
    if (uri != NULL) {
228 ca0defb9 Paolo Bonzini
        if (uri->scheme != NULL) g_free(uri->scheme);
229 ca0defb9 Paolo Bonzini
        uri->scheme = g_strndup(*str, cur - *str);
230 ca0defb9 Paolo Bonzini
    }
231 ca0defb9 Paolo Bonzini
    *str = cur;
232 ca0defb9 Paolo Bonzini
    return(0);
233 ca0defb9 Paolo Bonzini
}
234 ca0defb9 Paolo Bonzini
235 ca0defb9 Paolo Bonzini
/**
236 ca0defb9 Paolo Bonzini
 * rfc3986_parse_fragment:
237 ca0defb9 Paolo Bonzini
 * @uri:  pointer to an URI structure
238 ca0defb9 Paolo Bonzini
 * @str:  pointer to the string to analyze
239 ca0defb9 Paolo Bonzini
 *
240 ca0defb9 Paolo Bonzini
 * Parse the query part of an URI
241 ca0defb9 Paolo Bonzini
 *
242 ca0defb9 Paolo Bonzini
 * fragment      = *( pchar / "/" / "?" )
243 ca0defb9 Paolo Bonzini
 * NOTE: the strict syntax as defined by 3986 does not allow '[' and ']'
244 ca0defb9 Paolo Bonzini
 *       in the fragment identifier but this is used very broadly for
245 ca0defb9 Paolo Bonzini
 *       xpointer scheme selection, so we are allowing it here to not break
246 ca0defb9 Paolo Bonzini
 *       for example all the DocBook processing chains.
247 ca0defb9 Paolo Bonzini
 *
248 ca0defb9 Paolo Bonzini
 * Returns 0 or the error code
249 ca0defb9 Paolo Bonzini
 */
250 ca0defb9 Paolo Bonzini
static int
251 ca0defb9 Paolo Bonzini
rfc3986_parse_fragment(URI *uri, const char **str)
252 ca0defb9 Paolo Bonzini
{
253 ca0defb9 Paolo Bonzini
    const char *cur;
254 ca0defb9 Paolo Bonzini
255 ca0defb9 Paolo Bonzini
    if (str == NULL)
256 ca0defb9 Paolo Bonzini
        return (-1);
257 ca0defb9 Paolo Bonzini
258 ca0defb9 Paolo Bonzini
    cur = *str;
259 ca0defb9 Paolo Bonzini
260 ca0defb9 Paolo Bonzini
    while ((ISA_PCHAR(cur)) || (*cur == '/') || (*cur == '?') ||
261 ca0defb9 Paolo Bonzini
           (*cur == '[') || (*cur == ']') ||
262 ca0defb9 Paolo Bonzini
           ((uri != NULL) && (uri->cleanup & 1) && (IS_UNWISE(cur))))
263 ca0defb9 Paolo Bonzini
        NEXT(cur);
264 ca0defb9 Paolo Bonzini
    if (uri != NULL) {
265 ca0defb9 Paolo Bonzini
        if (uri->fragment != NULL)
266 ca0defb9 Paolo Bonzini
            g_free(uri->fragment);
267 ca0defb9 Paolo Bonzini
        if (uri->cleanup & 2)
268 ca0defb9 Paolo Bonzini
            uri->fragment = g_strndup(*str, cur - *str);
269 ca0defb9 Paolo Bonzini
        else
270 ca0defb9 Paolo Bonzini
            uri->fragment = uri_string_unescape(*str, cur - *str, NULL);
271 ca0defb9 Paolo Bonzini
    }
272 ca0defb9 Paolo Bonzini
    *str = cur;
273 ca0defb9 Paolo Bonzini
    return (0);
274 ca0defb9 Paolo Bonzini
}
275 ca0defb9 Paolo Bonzini
276 ca0defb9 Paolo Bonzini
/**
277 ca0defb9 Paolo Bonzini
 * rfc3986_parse_query:
278 ca0defb9 Paolo Bonzini
 * @uri:  pointer to an URI structure
279 ca0defb9 Paolo Bonzini
 * @str:  pointer to the string to analyze
280 ca0defb9 Paolo Bonzini
 *
281 ca0defb9 Paolo Bonzini
 * Parse the query part of an URI
282 ca0defb9 Paolo Bonzini
 *
283 ca0defb9 Paolo Bonzini
 * query = *uric
284 ca0defb9 Paolo Bonzini
 *
285 ca0defb9 Paolo Bonzini
 * Returns 0 or the error code
286 ca0defb9 Paolo Bonzini
 */
287 ca0defb9 Paolo Bonzini
static int
288 ca0defb9 Paolo Bonzini
rfc3986_parse_query(URI *uri, const char **str)
289 ca0defb9 Paolo Bonzini
{
290 ca0defb9 Paolo Bonzini
    const char *cur;
291 ca0defb9 Paolo Bonzini
292 ca0defb9 Paolo Bonzini
    if (str == NULL)
293 ca0defb9 Paolo Bonzini
        return (-1);
294 ca0defb9 Paolo Bonzini
295 ca0defb9 Paolo Bonzini
    cur = *str;
296 ca0defb9 Paolo Bonzini
297 ca0defb9 Paolo Bonzini
    while ((ISA_PCHAR(cur)) || (*cur == '/') || (*cur == '?') ||
298 ca0defb9 Paolo Bonzini
           ((uri != NULL) && (uri->cleanup & 1) && (IS_UNWISE(cur))))
299 ca0defb9 Paolo Bonzini
        NEXT(cur);
300 ca0defb9 Paolo Bonzini
    if (uri != NULL) {
301 ca0defb9 Paolo Bonzini
        if (uri->query != NULL)
302 ca0defb9 Paolo Bonzini
            g_free (uri->query);
303 ca0defb9 Paolo Bonzini
        uri->query = g_strndup (*str, cur - *str);
304 ca0defb9 Paolo Bonzini
    }
305 ca0defb9 Paolo Bonzini
    *str = cur;
306 ca0defb9 Paolo Bonzini
    return (0);
307 ca0defb9 Paolo Bonzini
}
308 ca0defb9 Paolo Bonzini
309 ca0defb9 Paolo Bonzini
/**
310 ca0defb9 Paolo Bonzini
 * rfc3986_parse_port:
311 ca0defb9 Paolo Bonzini
 * @uri:  pointer to an URI structure
312 ca0defb9 Paolo Bonzini
 * @str:  the string to analyze
313 ca0defb9 Paolo Bonzini
 *
314 ca0defb9 Paolo Bonzini
 * Parse a port  part and fills in the appropriate fields
315 ca0defb9 Paolo Bonzini
 * of the @uri structure
316 ca0defb9 Paolo Bonzini
 *
317 ca0defb9 Paolo Bonzini
 * port          = *DIGIT
318 ca0defb9 Paolo Bonzini
 *
319 ca0defb9 Paolo Bonzini
 * Returns 0 or the error code
320 ca0defb9 Paolo Bonzini
 */
321 ca0defb9 Paolo Bonzini
static int
322 ca0defb9 Paolo Bonzini
rfc3986_parse_port(URI *uri, const char **str)
323 ca0defb9 Paolo Bonzini
{
324 ca0defb9 Paolo Bonzini
    const char *cur = *str;
325 ca0defb9 Paolo Bonzini
326 ca0defb9 Paolo Bonzini
    if (ISA_DIGIT(cur)) {
327 ca0defb9 Paolo Bonzini
        if (uri != NULL)
328 ca0defb9 Paolo Bonzini
            uri->port = 0;
329 ca0defb9 Paolo Bonzini
        while (ISA_DIGIT(cur)) {
330 ca0defb9 Paolo Bonzini
            if (uri != NULL)
331 ca0defb9 Paolo Bonzini
                uri->port = uri->port * 10 + (*cur - '0');
332 ca0defb9 Paolo Bonzini
            cur++;
333 ca0defb9 Paolo Bonzini
        }
334 ca0defb9 Paolo Bonzini
        *str = cur;
335 ca0defb9 Paolo Bonzini
        return(0);
336 ca0defb9 Paolo Bonzini
    }
337 ca0defb9 Paolo Bonzini
    return(1);
338 ca0defb9 Paolo Bonzini
}
339 ca0defb9 Paolo Bonzini
340 ca0defb9 Paolo Bonzini
/**
341 ca0defb9 Paolo Bonzini
 * rfc3986_parse_user_info:
342 ca0defb9 Paolo Bonzini
 * @uri:  pointer to an URI structure
343 ca0defb9 Paolo Bonzini
 * @str:  the string to analyze
344 ca0defb9 Paolo Bonzini
 *
345 ca0defb9 Paolo Bonzini
 * Parse an user informations part and fills in the appropriate fields
346 ca0defb9 Paolo Bonzini
 * of the @uri structure
347 ca0defb9 Paolo Bonzini
 *
348 ca0defb9 Paolo Bonzini
 * userinfo      = *( unreserved / pct-encoded / sub-delims / ":" )
349 ca0defb9 Paolo Bonzini
 *
350 ca0defb9 Paolo Bonzini
 * Returns 0 or the error code
351 ca0defb9 Paolo Bonzini
 */
352 ca0defb9 Paolo Bonzini
static int
353 ca0defb9 Paolo Bonzini
rfc3986_parse_user_info(URI *uri, const char **str)
354 ca0defb9 Paolo Bonzini
{
355 ca0defb9 Paolo Bonzini
    const char *cur;
356 ca0defb9 Paolo Bonzini
357 ca0defb9 Paolo Bonzini
    cur = *str;
358 ca0defb9 Paolo Bonzini
    while (ISA_UNRESERVED(cur) || ISA_PCT_ENCODED(cur) ||
359 ca0defb9 Paolo Bonzini
           ISA_SUB_DELIM(cur) || (*cur == ':'))
360 ca0defb9 Paolo Bonzini
        NEXT(cur);
361 ca0defb9 Paolo Bonzini
    if (*cur == '@') {
362 ca0defb9 Paolo Bonzini
        if (uri != NULL) {
363 ca0defb9 Paolo Bonzini
            if (uri->user != NULL) g_free(uri->user);
364 ca0defb9 Paolo Bonzini
            if (uri->cleanup & 2)
365 ca0defb9 Paolo Bonzini
                uri->user = g_strndup(*str, cur - *str);
366 ca0defb9 Paolo Bonzini
            else
367 ca0defb9 Paolo Bonzini
                uri->user = uri_string_unescape(*str, cur - *str, NULL);
368 ca0defb9 Paolo Bonzini
        }
369 ca0defb9 Paolo Bonzini
        *str = cur;
370 ca0defb9 Paolo Bonzini
        return(0);
371 ca0defb9 Paolo Bonzini
    }
372 ca0defb9 Paolo Bonzini
    return(1);
373 ca0defb9 Paolo Bonzini
}
374 ca0defb9 Paolo Bonzini
375 ca0defb9 Paolo Bonzini
/**
376 ca0defb9 Paolo Bonzini
 * rfc3986_parse_dec_octet:
377 ca0defb9 Paolo Bonzini
 * @str:  the string to analyze
378 ca0defb9 Paolo Bonzini
 *
379 ca0defb9 Paolo Bonzini
 *    dec-octet     = DIGIT                 ; 0-9
380 ca0defb9 Paolo Bonzini
 *                  / %x31-39 DIGIT         ; 10-99
381 ca0defb9 Paolo Bonzini
 *                  / "1" 2DIGIT            ; 100-199
382 ca0defb9 Paolo Bonzini
 *                  / "2" %x30-34 DIGIT     ; 200-249
383 ca0defb9 Paolo Bonzini
 *                  / "25" %x30-35          ; 250-255
384 ca0defb9 Paolo Bonzini
 *
385 ca0defb9 Paolo Bonzini
 * Skip a dec-octet.
386 ca0defb9 Paolo Bonzini
 *
387 ca0defb9 Paolo Bonzini
 * Returns 0 if found and skipped, 1 otherwise
388 ca0defb9 Paolo Bonzini
 */
389 ca0defb9 Paolo Bonzini
static int
390 ca0defb9 Paolo Bonzini
rfc3986_parse_dec_octet(const char **str) {
391 ca0defb9 Paolo Bonzini
    const char *cur = *str;
392 ca0defb9 Paolo Bonzini
393 ca0defb9 Paolo Bonzini
    if (!(ISA_DIGIT(cur)))
394 ca0defb9 Paolo Bonzini
        return(1);
395 ca0defb9 Paolo Bonzini
    if (!ISA_DIGIT(cur+1))
396 ca0defb9 Paolo Bonzini
        cur++;
397 ca0defb9 Paolo Bonzini
    else if ((*cur != '0') && (ISA_DIGIT(cur + 1)) && (!ISA_DIGIT(cur+2)))
398 ca0defb9 Paolo Bonzini
        cur += 2;
399 ca0defb9 Paolo Bonzini
    else if ((*cur == '1') && (ISA_DIGIT(cur + 1)) && (ISA_DIGIT(cur + 2)))
400 ca0defb9 Paolo Bonzini
        cur += 3;
401 ca0defb9 Paolo Bonzini
    else if ((*cur == '2') && (*(cur + 1) >= '0') &&
402 ca0defb9 Paolo Bonzini
             (*(cur + 1) <= '4') && (ISA_DIGIT(cur + 2)))
403 ca0defb9 Paolo Bonzini
        cur += 3;
404 ca0defb9 Paolo Bonzini
    else if ((*cur == '2') && (*(cur + 1) == '5') &&
405 ca0defb9 Paolo Bonzini
             (*(cur + 2) >= '0') && (*(cur + 1) <= '5'))
406 ca0defb9 Paolo Bonzini
        cur += 3;
407 ca0defb9 Paolo Bonzini
    else
408 ca0defb9 Paolo Bonzini
        return(1);
409 ca0defb9 Paolo Bonzini
    *str = cur;
410 ca0defb9 Paolo Bonzini
    return(0);
411 ca0defb9 Paolo Bonzini
}
412 ca0defb9 Paolo Bonzini
/**
413 ca0defb9 Paolo Bonzini
 * rfc3986_parse_host:
414 ca0defb9 Paolo Bonzini
 * @uri:  pointer to an URI structure
415 ca0defb9 Paolo Bonzini
 * @str:  the string to analyze
416 ca0defb9 Paolo Bonzini
 *
417 ca0defb9 Paolo Bonzini
 * Parse an host part and fills in the appropriate fields
418 ca0defb9 Paolo Bonzini
 * of the @uri structure
419 ca0defb9 Paolo Bonzini
 *
420 ca0defb9 Paolo Bonzini
 * host          = IP-literal / IPv4address / reg-name
421 ca0defb9 Paolo Bonzini
 * IP-literal    = "[" ( IPv6address / IPvFuture  ) "]"
422 ca0defb9 Paolo Bonzini
 * IPv4address   = dec-octet "." dec-octet "." dec-octet "." dec-octet
423 ca0defb9 Paolo Bonzini
 * reg-name      = *( unreserved / pct-encoded / sub-delims )
424 ca0defb9 Paolo Bonzini
 *
425 ca0defb9 Paolo Bonzini
 * Returns 0 or the error code
426 ca0defb9 Paolo Bonzini
 */
427 ca0defb9 Paolo Bonzini
static int
428 ca0defb9 Paolo Bonzini
rfc3986_parse_host(URI *uri, const char **str)
429 ca0defb9 Paolo Bonzini
{
430 ca0defb9 Paolo Bonzini
    const char *cur = *str;
431 ca0defb9 Paolo Bonzini
    const char *host;
432 ca0defb9 Paolo Bonzini
433 ca0defb9 Paolo Bonzini
    host = cur;
434 ca0defb9 Paolo Bonzini
    /*
435 a93cf9df Stefan Weil
     * IPv6 and future addressing scheme are enclosed between brackets
436 ca0defb9 Paolo Bonzini
     */
437 ca0defb9 Paolo Bonzini
    if (*cur == '[') {
438 ca0defb9 Paolo Bonzini
        cur++;
439 ca0defb9 Paolo Bonzini
        while ((*cur != ']') && (*cur != 0))
440 ca0defb9 Paolo Bonzini
            cur++;
441 ca0defb9 Paolo Bonzini
        if (*cur != ']')
442 ca0defb9 Paolo Bonzini
            return(1);
443 ca0defb9 Paolo Bonzini
        cur++;
444 ca0defb9 Paolo Bonzini
        goto found;
445 ca0defb9 Paolo Bonzini
    }
446 ca0defb9 Paolo Bonzini
    /*
447 ca0defb9 Paolo Bonzini
     * try to parse an IPv4
448 ca0defb9 Paolo Bonzini
     */
449 ca0defb9 Paolo Bonzini
    if (ISA_DIGIT(cur)) {
450 ca0defb9 Paolo Bonzini
        if (rfc3986_parse_dec_octet(&cur) != 0)
451 ca0defb9 Paolo Bonzini
            goto not_ipv4;
452 ca0defb9 Paolo Bonzini
        if (*cur != '.')
453 ca0defb9 Paolo Bonzini
            goto not_ipv4;
454 ca0defb9 Paolo Bonzini
        cur++;
455 ca0defb9 Paolo Bonzini
        if (rfc3986_parse_dec_octet(&cur) != 0)
456 ca0defb9 Paolo Bonzini
            goto not_ipv4;
457 ca0defb9 Paolo Bonzini
        if (*cur != '.')
458 ca0defb9 Paolo Bonzini
            goto not_ipv4;
459 ca0defb9 Paolo Bonzini
        if (rfc3986_parse_dec_octet(&cur) != 0)
460 ca0defb9 Paolo Bonzini
            goto not_ipv4;
461 ca0defb9 Paolo Bonzini
        if (*cur != '.')
462 ca0defb9 Paolo Bonzini
            goto not_ipv4;
463 ca0defb9 Paolo Bonzini
        if (rfc3986_parse_dec_octet(&cur) != 0)
464 ca0defb9 Paolo Bonzini
            goto not_ipv4;
465 ca0defb9 Paolo Bonzini
        goto found;
466 ca0defb9 Paolo Bonzini
not_ipv4:
467 ca0defb9 Paolo Bonzini
        cur = *str;
468 ca0defb9 Paolo Bonzini
    }
469 ca0defb9 Paolo Bonzini
    /*
470 ca0defb9 Paolo Bonzini
     * then this should be a hostname which can be empty
471 ca0defb9 Paolo Bonzini
     */
472 ca0defb9 Paolo Bonzini
    while (ISA_UNRESERVED(cur) || ISA_PCT_ENCODED(cur) || ISA_SUB_DELIM(cur))
473 ca0defb9 Paolo Bonzini
        NEXT(cur);
474 ca0defb9 Paolo Bonzini
found:
475 ca0defb9 Paolo Bonzini
    if (uri != NULL) {
476 ca0defb9 Paolo Bonzini
        if (uri->authority != NULL) g_free(uri->authority);
477 ca0defb9 Paolo Bonzini
        uri->authority = NULL;
478 ca0defb9 Paolo Bonzini
        if (uri->server != NULL) g_free(uri->server);
479 ca0defb9 Paolo Bonzini
        if (cur != host) {
480 ca0defb9 Paolo Bonzini
            if (uri->cleanup & 2)
481 ca0defb9 Paolo Bonzini
                uri->server = g_strndup(host, cur - host);
482 ca0defb9 Paolo Bonzini
            else
483 ca0defb9 Paolo Bonzini
                uri->server = uri_string_unescape(host, cur - host, NULL);
484 ca0defb9 Paolo Bonzini
        } else
485 ca0defb9 Paolo Bonzini
            uri->server = NULL;
486 ca0defb9 Paolo Bonzini
    }
487 ca0defb9 Paolo Bonzini
    *str = cur;
488 ca0defb9 Paolo Bonzini
    return(0);
489 ca0defb9 Paolo Bonzini
}
490 ca0defb9 Paolo Bonzini
491 ca0defb9 Paolo Bonzini
/**
492 ca0defb9 Paolo Bonzini
 * rfc3986_parse_authority:
493 ca0defb9 Paolo Bonzini
 * @uri:  pointer to an URI structure
494 ca0defb9 Paolo Bonzini
 * @str:  the string to analyze
495 ca0defb9 Paolo Bonzini
 *
496 ca0defb9 Paolo Bonzini
 * Parse an authority part and fills in the appropriate fields
497 ca0defb9 Paolo Bonzini
 * of the @uri structure
498 ca0defb9 Paolo Bonzini
 *
499 ca0defb9 Paolo Bonzini
 * authority     = [ userinfo "@" ] host [ ":" port ]
500 ca0defb9 Paolo Bonzini
 *
501 ca0defb9 Paolo Bonzini
 * Returns 0 or the error code
502 ca0defb9 Paolo Bonzini
 */
503 ca0defb9 Paolo Bonzini
static int
504 ca0defb9 Paolo Bonzini
rfc3986_parse_authority(URI *uri, const char **str)
505 ca0defb9 Paolo Bonzini
{
506 ca0defb9 Paolo Bonzini
    const char *cur;
507 ca0defb9 Paolo Bonzini
    int ret;
508 ca0defb9 Paolo Bonzini
509 ca0defb9 Paolo Bonzini
    cur = *str;
510 ca0defb9 Paolo Bonzini
    /*
511 ca0defb9 Paolo Bonzini
     * try to parse an userinfo and check for the trailing @
512 ca0defb9 Paolo Bonzini
     */
513 ca0defb9 Paolo Bonzini
    ret = rfc3986_parse_user_info(uri, &cur);
514 ca0defb9 Paolo Bonzini
    if ((ret != 0) || (*cur != '@'))
515 ca0defb9 Paolo Bonzini
        cur = *str;
516 ca0defb9 Paolo Bonzini
    else
517 ca0defb9 Paolo Bonzini
        cur++;
518 ca0defb9 Paolo Bonzini
    ret = rfc3986_parse_host(uri, &cur);
519 ca0defb9 Paolo Bonzini
    if (ret != 0) return(ret);
520 ca0defb9 Paolo Bonzini
    if (*cur == ':') {
521 ca0defb9 Paolo Bonzini
        cur++;
522 ca0defb9 Paolo Bonzini
        ret = rfc3986_parse_port(uri, &cur);
523 ca0defb9 Paolo Bonzini
        if (ret != 0) return(ret);
524 ca0defb9 Paolo Bonzini
    }
525 ca0defb9 Paolo Bonzini
    *str = cur;
526 ca0defb9 Paolo Bonzini
    return(0);
527 ca0defb9 Paolo Bonzini
}
528 ca0defb9 Paolo Bonzini
529 ca0defb9 Paolo Bonzini
/**
530 ca0defb9 Paolo Bonzini
 * rfc3986_parse_segment:
531 ca0defb9 Paolo Bonzini
 * @str:  the string to analyze
532 ca0defb9 Paolo Bonzini
 * @forbid: an optional forbidden character
533 ca0defb9 Paolo Bonzini
 * @empty: allow an empty segment
534 ca0defb9 Paolo Bonzini
 *
535 ca0defb9 Paolo Bonzini
 * Parse a segment and fills in the appropriate fields
536 ca0defb9 Paolo Bonzini
 * of the @uri structure
537 ca0defb9 Paolo Bonzini
 *
538 ca0defb9 Paolo Bonzini
 * segment       = *pchar
539 ca0defb9 Paolo Bonzini
 * segment-nz    = 1*pchar
540 ca0defb9 Paolo Bonzini
 * segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" )
541 ca0defb9 Paolo Bonzini
 *               ; non-zero-length segment without any colon ":"
542 ca0defb9 Paolo Bonzini
 *
543 ca0defb9 Paolo Bonzini
 * Returns 0 or the error code
544 ca0defb9 Paolo Bonzini
 */
545 ca0defb9 Paolo Bonzini
static int
546 ca0defb9 Paolo Bonzini
rfc3986_parse_segment(const char **str, char forbid, int empty)
547 ca0defb9 Paolo Bonzini
{
548 ca0defb9 Paolo Bonzini
    const char *cur;
549 ca0defb9 Paolo Bonzini
550 ca0defb9 Paolo Bonzini
    cur = *str;
551 ca0defb9 Paolo Bonzini
    if (!ISA_PCHAR(cur)) {
552 ca0defb9 Paolo Bonzini
        if (empty)
553 ca0defb9 Paolo Bonzini
            return(0);
554 ca0defb9 Paolo Bonzini
        return(1);
555 ca0defb9 Paolo Bonzini
    }
556 ca0defb9 Paolo Bonzini
    while (ISA_PCHAR(cur) && (*cur != forbid))
557 ca0defb9 Paolo Bonzini
        NEXT(cur);
558 ca0defb9 Paolo Bonzini
    *str = cur;
559 ca0defb9 Paolo Bonzini
    return (0);
560 ca0defb9 Paolo Bonzini
}
561 ca0defb9 Paolo Bonzini
562 ca0defb9 Paolo Bonzini
/**
563 ca0defb9 Paolo Bonzini
 * rfc3986_parse_path_ab_empty:
564 ca0defb9 Paolo Bonzini
 * @uri:  pointer to an URI structure
565 ca0defb9 Paolo Bonzini
 * @str:  the string to analyze
566 ca0defb9 Paolo Bonzini
 *
567 ca0defb9 Paolo Bonzini
 * Parse an path absolute or empty and fills in the appropriate fields
568 ca0defb9 Paolo Bonzini
 * of the @uri structure
569 ca0defb9 Paolo Bonzini
 *
570 ca0defb9 Paolo Bonzini
 * path-abempty  = *( "/" segment )
571 ca0defb9 Paolo Bonzini
 *
572 ca0defb9 Paolo Bonzini
 * Returns 0 or the error code
573 ca0defb9 Paolo Bonzini
 */
574 ca0defb9 Paolo Bonzini
static int
575 ca0defb9 Paolo Bonzini
rfc3986_parse_path_ab_empty(URI *uri, const char **str)
576 ca0defb9 Paolo Bonzini
{
577 ca0defb9 Paolo Bonzini
    const char *cur;
578 ca0defb9 Paolo Bonzini
    int ret;
579 ca0defb9 Paolo Bonzini
580 ca0defb9 Paolo Bonzini
    cur = *str;
581 ca0defb9 Paolo Bonzini
582 ca0defb9 Paolo Bonzini
    while (*cur == '/') {
583 ca0defb9 Paolo Bonzini
        cur++;
584 ca0defb9 Paolo Bonzini
        ret = rfc3986_parse_segment(&cur, 0, 1);
585 ca0defb9 Paolo Bonzini
        if (ret != 0) return(ret);
586 ca0defb9 Paolo Bonzini
    }
587 ca0defb9 Paolo Bonzini
    if (uri != NULL) {
588 ca0defb9 Paolo Bonzini
        if (uri->path != NULL) g_free(uri->path);
589 ca0defb9 Paolo Bonzini
        if (*str != cur) {
590 ca0defb9 Paolo Bonzini
            if (uri->cleanup & 2)
591 ca0defb9 Paolo Bonzini
                uri->path = g_strndup(*str, cur - *str);
592 ca0defb9 Paolo Bonzini
            else
593 ca0defb9 Paolo Bonzini
                uri->path = uri_string_unescape(*str, cur - *str, NULL);
594 ca0defb9 Paolo Bonzini
        } else {
595 ca0defb9 Paolo Bonzini
            uri->path = NULL;
596 ca0defb9 Paolo Bonzini
        }
597 ca0defb9 Paolo Bonzini
    }
598 ca0defb9 Paolo Bonzini
    *str = cur;
599 ca0defb9 Paolo Bonzini
    return (0);
600 ca0defb9 Paolo Bonzini
}
601 ca0defb9 Paolo Bonzini
602 ca0defb9 Paolo Bonzini
/**
603 ca0defb9 Paolo Bonzini
 * rfc3986_parse_path_absolute:
604 ca0defb9 Paolo Bonzini
 * @uri:  pointer to an URI structure
605 ca0defb9 Paolo Bonzini
 * @str:  the string to analyze
606 ca0defb9 Paolo Bonzini
 *
607 ca0defb9 Paolo Bonzini
 * Parse an path absolute and fills in the appropriate fields
608 ca0defb9 Paolo Bonzini
 * of the @uri structure
609 ca0defb9 Paolo Bonzini
 *
610 ca0defb9 Paolo Bonzini
 * path-absolute = "/" [ segment-nz *( "/" segment ) ]
611 ca0defb9 Paolo Bonzini
 *
612 ca0defb9 Paolo Bonzini
 * Returns 0 or the error code
613 ca0defb9 Paolo Bonzini
 */
614 ca0defb9 Paolo Bonzini
static int
615 ca0defb9 Paolo Bonzini
rfc3986_parse_path_absolute(URI *uri, const char **str)
616 ca0defb9 Paolo Bonzini
{
617 ca0defb9 Paolo Bonzini
    const char *cur;
618 ca0defb9 Paolo Bonzini
    int ret;
619 ca0defb9 Paolo Bonzini
620 ca0defb9 Paolo Bonzini
    cur = *str;
621 ca0defb9 Paolo Bonzini
622 ca0defb9 Paolo Bonzini
    if (*cur != '/')
623 ca0defb9 Paolo Bonzini
        return(1);
624 ca0defb9 Paolo Bonzini
    cur++;
625 ca0defb9 Paolo Bonzini
    ret = rfc3986_parse_segment(&cur, 0, 0);
626 ca0defb9 Paolo Bonzini
    if (ret == 0) {
627 ca0defb9 Paolo Bonzini
        while (*cur == '/') {
628 ca0defb9 Paolo Bonzini
            cur++;
629 ca0defb9 Paolo Bonzini
            ret = rfc3986_parse_segment(&cur, 0, 1);
630 ca0defb9 Paolo Bonzini
            if (ret != 0) return(ret);
631 ca0defb9 Paolo Bonzini
        }
632 ca0defb9 Paolo Bonzini
    }
633 ca0defb9 Paolo Bonzini
    if (uri != NULL) {
634 ca0defb9 Paolo Bonzini
        if (uri->path != NULL) g_free(uri->path);
635 ca0defb9 Paolo Bonzini
        if (cur != *str) {
636 ca0defb9 Paolo Bonzini
            if (uri->cleanup & 2)
637 ca0defb9 Paolo Bonzini
                uri->path = g_strndup(*str, cur - *str);
638 ca0defb9 Paolo Bonzini
            else
639 ca0defb9 Paolo Bonzini
                uri->path = uri_string_unescape(*str, cur - *str, NULL);
640 ca0defb9 Paolo Bonzini
        } else {
641 ca0defb9 Paolo Bonzini
            uri->path = NULL;
642 ca0defb9 Paolo Bonzini
        }
643 ca0defb9 Paolo Bonzini
    }
644 ca0defb9 Paolo Bonzini
    *str = cur;
645 ca0defb9 Paolo Bonzini
    return (0);
646 ca0defb9 Paolo Bonzini
}
647 ca0defb9 Paolo Bonzini
648 ca0defb9 Paolo Bonzini
/**
649 ca0defb9 Paolo Bonzini
 * rfc3986_parse_path_rootless:
650 ca0defb9 Paolo Bonzini
 * @uri:  pointer to an URI structure
651 ca0defb9 Paolo Bonzini
 * @str:  the string to analyze
652 ca0defb9 Paolo Bonzini
 *
653 ca0defb9 Paolo Bonzini
 * Parse an path without root and fills in the appropriate fields
654 ca0defb9 Paolo Bonzini
 * of the @uri structure
655 ca0defb9 Paolo Bonzini
 *
656 ca0defb9 Paolo Bonzini
 * path-rootless = segment-nz *( "/" segment )
657 ca0defb9 Paolo Bonzini
 *
658 ca0defb9 Paolo Bonzini
 * Returns 0 or the error code
659 ca0defb9 Paolo Bonzini
 */
660 ca0defb9 Paolo Bonzini
static int
661 ca0defb9 Paolo Bonzini
rfc3986_parse_path_rootless(URI *uri, const char **str)
662 ca0defb9 Paolo Bonzini
{
663 ca0defb9 Paolo Bonzini
    const char *cur;
664 ca0defb9 Paolo Bonzini
    int ret;
665 ca0defb9 Paolo Bonzini
666 ca0defb9 Paolo Bonzini
    cur = *str;
667 ca0defb9 Paolo Bonzini
668 ca0defb9 Paolo Bonzini
    ret = rfc3986_parse_segment(&cur, 0, 0);
669 ca0defb9 Paolo Bonzini
    if (ret != 0) return(ret);
670 ca0defb9 Paolo Bonzini
    while (*cur == '/') {
671 ca0defb9 Paolo Bonzini
        cur++;
672 ca0defb9 Paolo Bonzini
        ret = rfc3986_parse_segment(&cur, 0, 1);
673 ca0defb9 Paolo Bonzini
        if (ret != 0) return(ret);
674 ca0defb9 Paolo Bonzini
    }
675 ca0defb9 Paolo Bonzini
    if (uri != NULL) {
676 ca0defb9 Paolo Bonzini
        if (uri->path != NULL) g_free(uri->path);
677 ca0defb9 Paolo Bonzini
        if (cur != *str) {
678 ca0defb9 Paolo Bonzini
            if (uri->cleanup & 2)
679 ca0defb9 Paolo Bonzini
                uri->path = g_strndup(*str, cur - *str);
680 ca0defb9 Paolo Bonzini
            else
681 ca0defb9 Paolo Bonzini
                uri->path = uri_string_unescape(*str, cur - *str, NULL);
682 ca0defb9 Paolo Bonzini
        } else {
683 ca0defb9 Paolo Bonzini
            uri->path = NULL;
684 ca0defb9 Paolo Bonzini
        }
685 ca0defb9 Paolo Bonzini
    }
686 ca0defb9 Paolo Bonzini
    *str = cur;
687 ca0defb9 Paolo Bonzini
    return (0);
688 ca0defb9 Paolo Bonzini
}
689 ca0defb9 Paolo Bonzini
690 ca0defb9 Paolo Bonzini
/**
691 ca0defb9 Paolo Bonzini
 * rfc3986_parse_path_no_scheme:
692 ca0defb9 Paolo Bonzini
 * @uri:  pointer to an URI structure
693 ca0defb9 Paolo Bonzini
 * @str:  the string to analyze
694 ca0defb9 Paolo Bonzini
 *
695 ca0defb9 Paolo Bonzini
 * Parse an path which is not a scheme and fills in the appropriate fields
696 ca0defb9 Paolo Bonzini
 * of the @uri structure
697 ca0defb9 Paolo Bonzini
 *
698 ca0defb9 Paolo Bonzini
 * path-noscheme = segment-nz-nc *( "/" segment )
699 ca0defb9 Paolo Bonzini
 *
700 ca0defb9 Paolo Bonzini
 * Returns 0 or the error code
701 ca0defb9 Paolo Bonzini
 */
702 ca0defb9 Paolo Bonzini
static int
703 ca0defb9 Paolo Bonzini
rfc3986_parse_path_no_scheme(URI *uri, const char **str)
704 ca0defb9 Paolo Bonzini
{
705 ca0defb9 Paolo Bonzini
    const char *cur;
706 ca0defb9 Paolo Bonzini
    int ret;
707 ca0defb9 Paolo Bonzini
708 ca0defb9 Paolo Bonzini
    cur = *str;
709 ca0defb9 Paolo Bonzini
710 ca0defb9 Paolo Bonzini
    ret = rfc3986_parse_segment(&cur, ':', 0);
711 ca0defb9 Paolo Bonzini
    if (ret != 0) return(ret);
712 ca0defb9 Paolo Bonzini
    while (*cur == '/') {
713 ca0defb9 Paolo Bonzini
        cur++;
714 ca0defb9 Paolo Bonzini
        ret = rfc3986_parse_segment(&cur, 0, 1);
715 ca0defb9 Paolo Bonzini
        if (ret != 0) return(ret);
716 ca0defb9 Paolo Bonzini
    }
717 ca0defb9 Paolo Bonzini
    if (uri != NULL) {
718 ca0defb9 Paolo Bonzini
        if (uri->path != NULL) g_free(uri->path);
719 ca0defb9 Paolo Bonzini
        if (cur != *str) {
720 ca0defb9 Paolo Bonzini
            if (uri->cleanup & 2)
721 ca0defb9 Paolo Bonzini
                uri->path = g_strndup(*str, cur - *str);
722 ca0defb9 Paolo Bonzini
            else
723 ca0defb9 Paolo Bonzini
                uri->path = uri_string_unescape(*str, cur - *str, NULL);
724 ca0defb9 Paolo Bonzini
        } else {
725 ca0defb9 Paolo Bonzini
            uri->path = NULL;
726 ca0defb9 Paolo Bonzini
        }
727 ca0defb9 Paolo Bonzini
    }
728 ca0defb9 Paolo Bonzini
    *str = cur;
729 ca0defb9 Paolo Bonzini
    return (0);
730 ca0defb9 Paolo Bonzini
}
731 ca0defb9 Paolo Bonzini
732 ca0defb9 Paolo Bonzini
/**
733 ca0defb9 Paolo Bonzini
 * rfc3986_parse_hier_part:
734 ca0defb9 Paolo Bonzini
 * @uri:  pointer to an URI structure
735 ca0defb9 Paolo Bonzini
 * @str:  the string to analyze
736 ca0defb9 Paolo Bonzini
 *
737 ca0defb9 Paolo Bonzini
 * Parse an hierarchical part and fills in the appropriate fields
738 ca0defb9 Paolo Bonzini
 * of the @uri structure
739 ca0defb9 Paolo Bonzini
 *
740 ca0defb9 Paolo Bonzini
 * hier-part     = "//" authority path-abempty
741 ca0defb9 Paolo Bonzini
 *                / path-absolute
742 ca0defb9 Paolo Bonzini
 *                / path-rootless
743 ca0defb9 Paolo Bonzini
 *                / path-empty
744 ca0defb9 Paolo Bonzini
 *
745 ca0defb9 Paolo Bonzini
 * Returns 0 or the error code
746 ca0defb9 Paolo Bonzini
 */
747 ca0defb9 Paolo Bonzini
static int
748 ca0defb9 Paolo Bonzini
rfc3986_parse_hier_part(URI *uri, const char **str)
749 ca0defb9 Paolo Bonzini
{
750 ca0defb9 Paolo Bonzini
    const char *cur;
751 ca0defb9 Paolo Bonzini
    int ret;
752 ca0defb9 Paolo Bonzini
753 ca0defb9 Paolo Bonzini
    cur = *str;
754 ca0defb9 Paolo Bonzini
755 ca0defb9 Paolo Bonzini
    if ((*cur == '/') && (*(cur + 1) == '/')) {
756 ca0defb9 Paolo Bonzini
        cur += 2;
757 ca0defb9 Paolo Bonzini
        ret = rfc3986_parse_authority(uri, &cur);
758 ca0defb9 Paolo Bonzini
        if (ret != 0) return(ret);
759 ca0defb9 Paolo Bonzini
        ret = rfc3986_parse_path_ab_empty(uri, &cur);
760 ca0defb9 Paolo Bonzini
        if (ret != 0) return(ret);
761 ca0defb9 Paolo Bonzini
        *str = cur;
762 ca0defb9 Paolo Bonzini
        return(0);
763 ca0defb9 Paolo Bonzini
    } else if (*cur == '/') {
764 ca0defb9 Paolo Bonzini
        ret = rfc3986_parse_path_absolute(uri, &cur);
765 ca0defb9 Paolo Bonzini
        if (ret != 0) return(ret);
766 ca0defb9 Paolo Bonzini
    } else if (ISA_PCHAR(cur)) {
767 ca0defb9 Paolo Bonzini
        ret = rfc3986_parse_path_rootless(uri, &cur);
768 ca0defb9 Paolo Bonzini
        if (ret != 0) return(ret);
769 ca0defb9 Paolo Bonzini
    } else {
770 ca0defb9 Paolo Bonzini
        /* path-empty is effectively empty */
771 ca0defb9 Paolo Bonzini
        if (uri != NULL) {
772 ca0defb9 Paolo Bonzini
            if (uri->path != NULL) g_free(uri->path);
773 ca0defb9 Paolo Bonzini
            uri->path = NULL;
774 ca0defb9 Paolo Bonzini
        }
775 ca0defb9 Paolo Bonzini
    }
776 ca0defb9 Paolo Bonzini
    *str = cur;
777 ca0defb9 Paolo Bonzini
    return (0);
778 ca0defb9 Paolo Bonzini
}
779 ca0defb9 Paolo Bonzini
780 ca0defb9 Paolo Bonzini
/**
781 ca0defb9 Paolo Bonzini
 * rfc3986_parse_relative_ref:
782 ca0defb9 Paolo Bonzini
 * @uri:  pointer to an URI structure
783 ca0defb9 Paolo Bonzini
 * @str:  the string to analyze
784 ca0defb9 Paolo Bonzini
 *
785 ca0defb9 Paolo Bonzini
 * Parse an URI string and fills in the appropriate fields
786 ca0defb9 Paolo Bonzini
 * of the @uri structure
787 ca0defb9 Paolo Bonzini
 *
788 ca0defb9 Paolo Bonzini
 * relative-ref  = relative-part [ "?" query ] [ "#" fragment ]
789 ca0defb9 Paolo Bonzini
 * relative-part = "//" authority path-abempty
790 ca0defb9 Paolo Bonzini
 *               / path-absolute
791 ca0defb9 Paolo Bonzini
 *               / path-noscheme
792 ca0defb9 Paolo Bonzini
 *               / path-empty
793 ca0defb9 Paolo Bonzini
 *
794 ca0defb9 Paolo Bonzini
 * Returns 0 or the error code
795 ca0defb9 Paolo Bonzini
 */
796 ca0defb9 Paolo Bonzini
static int
797 ca0defb9 Paolo Bonzini
rfc3986_parse_relative_ref(URI *uri, const char *str) {
798 ca0defb9 Paolo Bonzini
    int ret;
799 ca0defb9 Paolo Bonzini
800 ca0defb9 Paolo Bonzini
    if ((*str == '/') && (*(str + 1) == '/')) {
801 ca0defb9 Paolo Bonzini
        str += 2;
802 ca0defb9 Paolo Bonzini
        ret = rfc3986_parse_authority(uri, &str);
803 ca0defb9 Paolo Bonzini
        if (ret != 0) return(ret);
804 ca0defb9 Paolo Bonzini
        ret = rfc3986_parse_path_ab_empty(uri, &str);
805 ca0defb9 Paolo Bonzini
        if (ret != 0) return(ret);
806 ca0defb9 Paolo Bonzini
    } else if (*str == '/') {
807 ca0defb9 Paolo Bonzini
        ret = rfc3986_parse_path_absolute(uri, &str);
808 ca0defb9 Paolo Bonzini
        if (ret != 0) return(ret);
809 ca0defb9 Paolo Bonzini
    } else if (ISA_PCHAR(str)) {
810 ca0defb9 Paolo Bonzini
        ret = rfc3986_parse_path_no_scheme(uri, &str);
811 ca0defb9 Paolo Bonzini
        if (ret != 0) return(ret);
812 ca0defb9 Paolo Bonzini
    } else {
813 ca0defb9 Paolo Bonzini
        /* path-empty is effectively empty */
814 ca0defb9 Paolo Bonzini
        if (uri != NULL) {
815 ca0defb9 Paolo Bonzini
            if (uri->path != NULL) g_free(uri->path);
816 ca0defb9 Paolo Bonzini
            uri->path = NULL;
817 ca0defb9 Paolo Bonzini
        }
818 ca0defb9 Paolo Bonzini
    }
819 ca0defb9 Paolo Bonzini
820 ca0defb9 Paolo Bonzini
    if (*str == '?') {
821 ca0defb9 Paolo Bonzini
        str++;
822 ca0defb9 Paolo Bonzini
        ret = rfc3986_parse_query(uri, &str);
823 ca0defb9 Paolo Bonzini
        if (ret != 0) return(ret);
824 ca0defb9 Paolo Bonzini
    }
825 ca0defb9 Paolo Bonzini
    if (*str == '#') {
826 ca0defb9 Paolo Bonzini
        str++;
827 ca0defb9 Paolo Bonzini
        ret = rfc3986_parse_fragment(uri, &str);
828 ca0defb9 Paolo Bonzini
        if (ret != 0) return(ret);
829 ca0defb9 Paolo Bonzini
    }
830 ca0defb9 Paolo Bonzini
    if (*str != 0) {
831 ca0defb9 Paolo Bonzini
        uri_clean(uri);
832 ca0defb9 Paolo Bonzini
        return(1);
833 ca0defb9 Paolo Bonzini
    }
834 ca0defb9 Paolo Bonzini
    return(0);
835 ca0defb9 Paolo Bonzini
}
836 ca0defb9 Paolo Bonzini
837 ca0defb9 Paolo Bonzini
838 ca0defb9 Paolo Bonzini
/**
839 ca0defb9 Paolo Bonzini
 * rfc3986_parse:
840 ca0defb9 Paolo Bonzini
 * @uri:  pointer to an URI structure
841 ca0defb9 Paolo Bonzini
 * @str:  the string to analyze
842 ca0defb9 Paolo Bonzini
 *
843 ca0defb9 Paolo Bonzini
 * Parse an URI string and fills in the appropriate fields
844 ca0defb9 Paolo Bonzini
 * of the @uri structure
845 ca0defb9 Paolo Bonzini
 *
846 ca0defb9 Paolo Bonzini
 * scheme ":" hier-part [ "?" query ] [ "#" fragment ]
847 ca0defb9 Paolo Bonzini
 *
848 ca0defb9 Paolo Bonzini
 * Returns 0 or the error code
849 ca0defb9 Paolo Bonzini
 */
850 ca0defb9 Paolo Bonzini
static int
851 ca0defb9 Paolo Bonzini
rfc3986_parse(URI *uri, const char *str) {
852 ca0defb9 Paolo Bonzini
    int ret;
853 ca0defb9 Paolo Bonzini
854 ca0defb9 Paolo Bonzini
    ret = rfc3986_parse_scheme(uri, &str);
855 ca0defb9 Paolo Bonzini
    if (ret != 0) return(ret);
856 ca0defb9 Paolo Bonzini
    if (*str != ':') {
857 ca0defb9 Paolo Bonzini
        return(1);
858 ca0defb9 Paolo Bonzini
    }
859 ca0defb9 Paolo Bonzini
    str++;
860 ca0defb9 Paolo Bonzini
    ret = rfc3986_parse_hier_part(uri, &str);
861 ca0defb9 Paolo Bonzini
    if (ret != 0) return(ret);
862 ca0defb9 Paolo Bonzini
    if (*str == '?') {
863 ca0defb9 Paolo Bonzini
        str++;
864 ca0defb9 Paolo Bonzini
        ret = rfc3986_parse_query(uri, &str);
865 ca0defb9 Paolo Bonzini
        if (ret != 0) return(ret);
866 ca0defb9 Paolo Bonzini
    }
867 ca0defb9 Paolo Bonzini
    if (*str == '#') {
868 ca0defb9 Paolo Bonzini
        str++;
869 ca0defb9 Paolo Bonzini
        ret = rfc3986_parse_fragment(uri, &str);
870 ca0defb9 Paolo Bonzini
        if (ret != 0) return(ret);
871 ca0defb9 Paolo Bonzini
    }
872 ca0defb9 Paolo Bonzini
    if (*str != 0) {
873 ca0defb9 Paolo Bonzini
        uri_clean(uri);
874 ca0defb9 Paolo Bonzini
        return(1);
875 ca0defb9 Paolo Bonzini
    }
876 ca0defb9 Paolo Bonzini
    return(0);
877 ca0defb9 Paolo Bonzini
}
878 ca0defb9 Paolo Bonzini
879 ca0defb9 Paolo Bonzini
/**
880 ca0defb9 Paolo Bonzini
 * rfc3986_parse_uri_reference:
881 ca0defb9 Paolo Bonzini
 * @uri:  pointer to an URI structure
882 ca0defb9 Paolo Bonzini
 * @str:  the string to analyze
883 ca0defb9 Paolo Bonzini
 *
884 ca0defb9 Paolo Bonzini
 * Parse an URI reference string and fills in the appropriate fields
885 ca0defb9 Paolo Bonzini
 * of the @uri structure
886 ca0defb9 Paolo Bonzini
 *
887 ca0defb9 Paolo Bonzini
 * URI-reference = URI / relative-ref
888 ca0defb9 Paolo Bonzini
 *
889 ca0defb9 Paolo Bonzini
 * Returns 0 or the error code
890 ca0defb9 Paolo Bonzini
 */
891 ca0defb9 Paolo Bonzini
static int
892 ca0defb9 Paolo Bonzini
rfc3986_parse_uri_reference(URI *uri, const char *str) {
893 ca0defb9 Paolo Bonzini
    int ret;
894 ca0defb9 Paolo Bonzini
895 ca0defb9 Paolo Bonzini
    if (str == NULL)
896 ca0defb9 Paolo Bonzini
        return(-1);
897 ca0defb9 Paolo Bonzini
    uri_clean(uri);
898 ca0defb9 Paolo Bonzini
899 ca0defb9 Paolo Bonzini
    /*
900 ca0defb9 Paolo Bonzini
     * Try first to parse absolute refs, then fallback to relative if
901 ca0defb9 Paolo Bonzini
     * it fails.
902 ca0defb9 Paolo Bonzini
     */
903 ca0defb9 Paolo Bonzini
    ret = rfc3986_parse(uri, str);
904 ca0defb9 Paolo Bonzini
    if (ret != 0) {
905 ca0defb9 Paolo Bonzini
        uri_clean(uri);
906 ca0defb9 Paolo Bonzini
        ret = rfc3986_parse_relative_ref(uri, str);
907 ca0defb9 Paolo Bonzini
        if (ret != 0) {
908 ca0defb9 Paolo Bonzini
            uri_clean(uri);
909 ca0defb9 Paolo Bonzini
            return(ret);
910 ca0defb9 Paolo Bonzini
        }
911 ca0defb9 Paolo Bonzini
    }
912 ca0defb9 Paolo Bonzini
    return(0);
913 ca0defb9 Paolo Bonzini
}
914 ca0defb9 Paolo Bonzini
915 ca0defb9 Paolo Bonzini
/**
916 ca0defb9 Paolo Bonzini
 * uri_parse:
917 ca0defb9 Paolo Bonzini
 * @str:  the URI string to analyze
918 ca0defb9 Paolo Bonzini
 *
919 ca0defb9 Paolo Bonzini
 * Parse an URI based on RFC 3986
920 ca0defb9 Paolo Bonzini
 *
921 ca0defb9 Paolo Bonzini
 * URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ]
922 ca0defb9 Paolo Bonzini
 *
923 ca0defb9 Paolo Bonzini
 * Returns a newly built URI or NULL in case of error
924 ca0defb9 Paolo Bonzini
 */
925 ca0defb9 Paolo Bonzini
URI *
926 ca0defb9 Paolo Bonzini
uri_parse(const char *str) {
927 ca0defb9 Paolo Bonzini
    URI *uri;
928 ca0defb9 Paolo Bonzini
    int ret;
929 ca0defb9 Paolo Bonzini
930 ca0defb9 Paolo Bonzini
    if (str == NULL)
931 ca0defb9 Paolo Bonzini
        return(NULL);
932 ca0defb9 Paolo Bonzini
    uri = uri_new();
933 ca0defb9 Paolo Bonzini
    if (uri != NULL) {
934 ca0defb9 Paolo Bonzini
        ret = rfc3986_parse_uri_reference(uri, str);
935 ca0defb9 Paolo Bonzini
        if (ret) {
936 ca0defb9 Paolo Bonzini
            uri_free(uri);
937 ca0defb9 Paolo Bonzini
            return(NULL);
938 ca0defb9 Paolo Bonzini
        }
939 ca0defb9 Paolo Bonzini
    }
940 ca0defb9 Paolo Bonzini
    return(uri);
941 ca0defb9 Paolo Bonzini
}
942 ca0defb9 Paolo Bonzini
943 ca0defb9 Paolo Bonzini
/**
944 ca0defb9 Paolo Bonzini
 * uri_parse_into:
945 ca0defb9 Paolo Bonzini
 * @uri:  pointer to an URI structure
946 ca0defb9 Paolo Bonzini
 * @str:  the string to analyze
947 ca0defb9 Paolo Bonzini
 *
948 ca0defb9 Paolo Bonzini
 * Parse an URI reference string based on RFC 3986 and fills in the
949 ca0defb9 Paolo Bonzini
 * appropriate fields of the @uri structure
950 ca0defb9 Paolo Bonzini
 *
951 ca0defb9 Paolo Bonzini
 * URI-reference = URI / relative-ref
952 ca0defb9 Paolo Bonzini
 *
953 ca0defb9 Paolo Bonzini
 * Returns 0 or the error code
954 ca0defb9 Paolo Bonzini
 */
955 ca0defb9 Paolo Bonzini
int
956 ca0defb9 Paolo Bonzini
uri_parse_into(URI *uri, const char *str) {
957 ca0defb9 Paolo Bonzini
    return(rfc3986_parse_uri_reference(uri, str));
958 ca0defb9 Paolo Bonzini
}
959 ca0defb9 Paolo Bonzini
960 ca0defb9 Paolo Bonzini
/**
961 ca0defb9 Paolo Bonzini
 * uri_parse_raw:
962 ca0defb9 Paolo Bonzini
 * @str:  the URI string to analyze
963 ca0defb9 Paolo Bonzini
 * @raw:  if 1 unescaping of URI pieces are disabled
964 ca0defb9 Paolo Bonzini
 *
965 ca0defb9 Paolo Bonzini
 * Parse an URI but allows to keep intact the original fragments.
966 ca0defb9 Paolo Bonzini
 *
967 ca0defb9 Paolo Bonzini
 * URI-reference = URI / relative-ref
968 ca0defb9 Paolo Bonzini
 *
969 ca0defb9 Paolo Bonzini
 * Returns a newly built URI or NULL in case of error
970 ca0defb9 Paolo Bonzini
 */
971 ca0defb9 Paolo Bonzini
URI *
972 ca0defb9 Paolo Bonzini
uri_parse_raw(const char *str, int raw) {
973 ca0defb9 Paolo Bonzini
    URI *uri;
974 ca0defb9 Paolo Bonzini
    int ret;
975 ca0defb9 Paolo Bonzini
976 ca0defb9 Paolo Bonzini
    if (str == NULL)
977 ca0defb9 Paolo Bonzini
        return(NULL);
978 ca0defb9 Paolo Bonzini
    uri = uri_new();
979 ca0defb9 Paolo Bonzini
    if (uri != NULL) {
980 ca0defb9 Paolo Bonzini
        if (raw) {
981 ca0defb9 Paolo Bonzini
            uri->cleanup |= 2;
982 ca0defb9 Paolo Bonzini
        }
983 ca0defb9 Paolo Bonzini
        ret = uri_parse_into(uri, str);
984 ca0defb9 Paolo Bonzini
        if (ret) {
985 ca0defb9 Paolo Bonzini
            uri_free(uri);
986 ca0defb9 Paolo Bonzini
            return(NULL);
987 ca0defb9 Paolo Bonzini
        }
988 ca0defb9 Paolo Bonzini
    }
989 ca0defb9 Paolo Bonzini
    return(uri);
990 ca0defb9 Paolo Bonzini
}
991 ca0defb9 Paolo Bonzini
992 ca0defb9 Paolo Bonzini
/************************************************************************
993 ca0defb9 Paolo Bonzini
 *                                                                        *
994 ca0defb9 Paolo Bonzini
 *                        Generic URI structure functions                        *
995 ca0defb9 Paolo Bonzini
 *                                                                        *
996 ca0defb9 Paolo Bonzini
 ************************************************************************/
997 ca0defb9 Paolo Bonzini
998 ca0defb9 Paolo Bonzini
/**
999 ca0defb9 Paolo Bonzini
 * uri_new:
1000 ca0defb9 Paolo Bonzini
 *
1001 ca0defb9 Paolo Bonzini
 * Simply creates an empty URI
1002 ca0defb9 Paolo Bonzini
 *
1003 ca0defb9 Paolo Bonzini
 * Returns the new structure or NULL in case of error
1004 ca0defb9 Paolo Bonzini
 */
1005 ca0defb9 Paolo Bonzini
URI *
1006 ca0defb9 Paolo Bonzini
uri_new(void) {
1007 ca0defb9 Paolo Bonzini
    URI *ret;
1008 ca0defb9 Paolo Bonzini
1009 ca0defb9 Paolo Bonzini
    ret = (URI *) g_malloc(sizeof(URI));
1010 ca0defb9 Paolo Bonzini
    memset(ret, 0, sizeof(URI));
1011 ca0defb9 Paolo Bonzini
    return(ret);
1012 ca0defb9 Paolo Bonzini
}
1013 ca0defb9 Paolo Bonzini
1014 ca0defb9 Paolo Bonzini
/**
1015 ca0defb9 Paolo Bonzini
 * realloc2n:
1016 ca0defb9 Paolo Bonzini
 *
1017 ca0defb9 Paolo Bonzini
 * Function to handle properly a reallocation when saving an URI
1018 ca0defb9 Paolo Bonzini
 * Also imposes some limit on the length of an URI string output
1019 ca0defb9 Paolo Bonzini
 */
1020 ca0defb9 Paolo Bonzini
static char *
1021 ca0defb9 Paolo Bonzini
realloc2n(char *ret, int *max) {
1022 ca0defb9 Paolo Bonzini
    char *temp;
1023 ca0defb9 Paolo Bonzini
    int tmp;
1024 ca0defb9 Paolo Bonzini
1025 ca0defb9 Paolo Bonzini
    tmp = *max * 2;
1026 ca0defb9 Paolo Bonzini
    temp = g_realloc(ret, (tmp + 1));
1027 ca0defb9 Paolo Bonzini
    *max = tmp;
1028 ca0defb9 Paolo Bonzini
    return(temp);
1029 ca0defb9 Paolo Bonzini
}
1030 ca0defb9 Paolo Bonzini
1031 ca0defb9 Paolo Bonzini
/**
1032 ca0defb9 Paolo Bonzini
 * uri_to_string:
1033 ca0defb9 Paolo Bonzini
 * @uri:  pointer to an URI
1034 ca0defb9 Paolo Bonzini
 *
1035 ca0defb9 Paolo Bonzini
 * Save the URI as an escaped string
1036 ca0defb9 Paolo Bonzini
 *
1037 ca0defb9 Paolo Bonzini
 * Returns a new string (to be deallocated by caller)
1038 ca0defb9 Paolo Bonzini
 */
1039 ca0defb9 Paolo Bonzini
char *
1040 ca0defb9 Paolo Bonzini
uri_to_string(URI *uri) {
1041 ca0defb9 Paolo Bonzini
    char *ret = NULL;
1042 ca0defb9 Paolo Bonzini
    char *temp;
1043 ca0defb9 Paolo Bonzini
    const char *p;
1044 ca0defb9 Paolo Bonzini
    int len;
1045 ca0defb9 Paolo Bonzini
    int max;
1046 ca0defb9 Paolo Bonzini
1047 ca0defb9 Paolo Bonzini
    if (uri == NULL) return(NULL);
1048 ca0defb9 Paolo Bonzini
1049 ca0defb9 Paolo Bonzini
1050 ca0defb9 Paolo Bonzini
    max = 80;
1051 ca0defb9 Paolo Bonzini
    ret = g_malloc(max + 1);
1052 ca0defb9 Paolo Bonzini
    len = 0;
1053 ca0defb9 Paolo Bonzini
1054 ca0defb9 Paolo Bonzini
    if (uri->scheme != NULL) {
1055 ca0defb9 Paolo Bonzini
        p = uri->scheme;
1056 ca0defb9 Paolo Bonzini
        while (*p != 0) {
1057 ca0defb9 Paolo Bonzini
            if (len >= max) {
1058 ca0defb9 Paolo Bonzini
                temp = realloc2n(ret, &max);
1059 ca0defb9 Paolo Bonzini
                if (temp == NULL) goto mem_error;
1060 ca0defb9 Paolo Bonzini
                ret = temp;
1061 ca0defb9 Paolo Bonzini
            }
1062 ca0defb9 Paolo Bonzini
            ret[len++] = *p++;
1063 ca0defb9 Paolo Bonzini
        }
1064 ca0defb9 Paolo Bonzini
        if (len >= max) {
1065 ca0defb9 Paolo Bonzini
            temp = realloc2n(ret, &max);
1066 ca0defb9 Paolo Bonzini
            if (temp == NULL) goto mem_error;
1067 ca0defb9 Paolo Bonzini
            ret = temp;
1068 ca0defb9 Paolo Bonzini
        }
1069 ca0defb9 Paolo Bonzini
        ret[len++] = ':';
1070 ca0defb9 Paolo Bonzini
    }
1071 ca0defb9 Paolo Bonzini
    if (uri->opaque != NULL) {
1072 ca0defb9 Paolo Bonzini
        p = uri->opaque;
1073 ca0defb9 Paolo Bonzini
        while (*p != 0) {
1074 ca0defb9 Paolo Bonzini
            if (len + 3 >= max) {
1075 ca0defb9 Paolo Bonzini
                temp = realloc2n(ret, &max);
1076 ca0defb9 Paolo Bonzini
                if (temp == NULL) goto mem_error;
1077 ca0defb9 Paolo Bonzini
                ret = temp;
1078 ca0defb9 Paolo Bonzini
            }
1079 ca0defb9 Paolo Bonzini
            if (IS_RESERVED(*(p)) || IS_UNRESERVED(*(p)))
1080 ca0defb9 Paolo Bonzini
                ret[len++] = *p++;
1081 ca0defb9 Paolo Bonzini
            else {
1082 ca0defb9 Paolo Bonzini
                int val = *(unsigned char *)p++;
1083 ca0defb9 Paolo Bonzini
                int hi = val / 0x10, lo = val % 0x10;
1084 ca0defb9 Paolo Bonzini
                ret[len++] = '%';
1085 ca0defb9 Paolo Bonzini
                ret[len++] = hi + (hi > 9? 'A'-10 : '0');
1086 ca0defb9 Paolo Bonzini
                ret[len++] = lo + (lo > 9? 'A'-10 : '0');
1087 ca0defb9 Paolo Bonzini
            }
1088 ca0defb9 Paolo Bonzini
        }
1089 ca0defb9 Paolo Bonzini
    } else {
1090 ca0defb9 Paolo Bonzini
        if (uri->server != NULL) {
1091 ca0defb9 Paolo Bonzini
            if (len + 3 >= max) {
1092 ca0defb9 Paolo Bonzini
                temp = realloc2n(ret, &max);
1093 ca0defb9 Paolo Bonzini
                if (temp == NULL) goto mem_error;
1094 ca0defb9 Paolo Bonzini
                ret = temp;
1095 ca0defb9 Paolo Bonzini
            }
1096 ca0defb9 Paolo Bonzini
            ret[len++] = '/';
1097 ca0defb9 Paolo Bonzini
            ret[len++] = '/';
1098 ca0defb9 Paolo Bonzini
            if (uri->user != NULL) {
1099 ca0defb9 Paolo Bonzini
                p = uri->user;
1100 ca0defb9 Paolo Bonzini
                while (*p != 0) {
1101 ca0defb9 Paolo Bonzini
                    if (len + 3 >= max) {
1102 ca0defb9 Paolo Bonzini
                        temp = realloc2n(ret, &max);
1103 ca0defb9 Paolo Bonzini
                        if (temp == NULL) goto mem_error;
1104 ca0defb9 Paolo Bonzini
                        ret = temp;
1105 ca0defb9 Paolo Bonzini
                    }
1106 ca0defb9 Paolo Bonzini
                    if ((IS_UNRESERVED(*(p))) ||
1107 ca0defb9 Paolo Bonzini
                        ((*(p) == ';')) || ((*(p) == ':')) ||
1108 ca0defb9 Paolo Bonzini
                        ((*(p) == '&')) || ((*(p) == '=')) ||
1109 ca0defb9 Paolo Bonzini
                        ((*(p) == '+')) || ((*(p) == '$')) ||
1110 ca0defb9 Paolo Bonzini
                        ((*(p) == ',')))
1111 ca0defb9 Paolo Bonzini
                        ret[len++] = *p++;
1112 ca0defb9 Paolo Bonzini
                    else {
1113 ca0defb9 Paolo Bonzini
                        int val = *(unsigned char *)p++;
1114 ca0defb9 Paolo Bonzini
                        int hi = val / 0x10, lo = val % 0x10;
1115 ca0defb9 Paolo Bonzini
                        ret[len++] = '%';
1116 ca0defb9 Paolo Bonzini
                        ret[len++] = hi + (hi > 9? 'A'-10 : '0');
1117 ca0defb9 Paolo Bonzini
                        ret[len++] = lo + (lo > 9? 'A'-10 : '0');
1118 ca0defb9 Paolo Bonzini
                    }
1119 ca0defb9 Paolo Bonzini
                }
1120 ca0defb9 Paolo Bonzini
                if (len + 3 >= max) {
1121 ca0defb9 Paolo Bonzini
                    temp = realloc2n(ret, &max);
1122 ca0defb9 Paolo Bonzini
                    if (temp == NULL) goto mem_error;
1123 ca0defb9 Paolo Bonzini
                    ret = temp;
1124 ca0defb9 Paolo Bonzini
                }
1125 ca0defb9 Paolo Bonzini
                ret[len++] = '@';
1126 ca0defb9 Paolo Bonzini
            }
1127 ca0defb9 Paolo Bonzini
            p = uri->server;
1128 ca0defb9 Paolo Bonzini
            while (*p != 0) {
1129 ca0defb9 Paolo Bonzini
                if (len >= max) {
1130 ca0defb9 Paolo Bonzini
                    temp = realloc2n(ret, &max);
1131 ca0defb9 Paolo Bonzini
                    if (temp == NULL) goto mem_error;
1132 ca0defb9 Paolo Bonzini
                    ret = temp;
1133 ca0defb9 Paolo Bonzini
                }
1134 ca0defb9 Paolo Bonzini
                ret[len++] = *p++;
1135 ca0defb9 Paolo Bonzini
            }
1136 ca0defb9 Paolo Bonzini
            if (uri->port > 0) {
1137 ca0defb9 Paolo Bonzini
                if (len + 10 >= max) {
1138 ca0defb9 Paolo Bonzini
                    temp = realloc2n(ret, &max);
1139 ca0defb9 Paolo Bonzini
                    if (temp == NULL) goto mem_error;
1140 ca0defb9 Paolo Bonzini
                    ret = temp;
1141 ca0defb9 Paolo Bonzini
                }
1142 ca0defb9 Paolo Bonzini
                len += snprintf(&ret[len], max - len, ":%d", uri->port);
1143 ca0defb9 Paolo Bonzini
            }
1144 ca0defb9 Paolo Bonzini
        } else if (uri->authority != NULL) {
1145 ca0defb9 Paolo Bonzini
            if (len + 3 >= max) {
1146 ca0defb9 Paolo Bonzini
                temp = realloc2n(ret, &max);
1147 ca0defb9 Paolo Bonzini
                if (temp == NULL) goto mem_error;
1148 ca0defb9 Paolo Bonzini
                ret = temp;
1149 ca0defb9 Paolo Bonzini
            }
1150 ca0defb9 Paolo Bonzini
            ret[len++] = '/';
1151 ca0defb9 Paolo Bonzini
            ret[len++] = '/';
1152 ca0defb9 Paolo Bonzini
            p = uri->authority;
1153 ca0defb9 Paolo Bonzini
            while (*p != 0) {
1154 ca0defb9 Paolo Bonzini
                if (len + 3 >= max) {
1155 ca0defb9 Paolo Bonzini
                    temp = realloc2n(ret, &max);
1156 ca0defb9 Paolo Bonzini
                    if (temp == NULL) goto mem_error;
1157 ca0defb9 Paolo Bonzini
                    ret = temp;
1158 ca0defb9 Paolo Bonzini
                }
1159 ca0defb9 Paolo Bonzini
                if ((IS_UNRESERVED(*(p))) ||
1160 ca0defb9 Paolo Bonzini
                    ((*(p) == '$')) || ((*(p) == ',')) || ((*(p) == ';')) ||
1161 ca0defb9 Paolo Bonzini
                    ((*(p) == ':')) || ((*(p) == '@')) || ((*(p) == '&')) ||
1162 ca0defb9 Paolo Bonzini
                    ((*(p) == '=')) || ((*(p) == '+')))
1163 ca0defb9 Paolo Bonzini
                    ret[len++] = *p++;
1164 ca0defb9 Paolo Bonzini
                else {
1165 ca0defb9 Paolo Bonzini
                    int val = *(unsigned char *)p++;
1166 ca0defb9 Paolo Bonzini
                    int hi = val / 0x10, lo = val % 0x10;
1167 ca0defb9 Paolo Bonzini
                    ret[len++] = '%';
1168 ca0defb9 Paolo Bonzini
                    ret[len++] = hi + (hi > 9? 'A'-10 : '0');
1169 ca0defb9 Paolo Bonzini
                    ret[len++] = lo + (lo > 9? 'A'-10 : '0');
1170 ca0defb9 Paolo Bonzini
                }
1171 ca0defb9 Paolo Bonzini
            }
1172 ca0defb9 Paolo Bonzini
        } else if (uri->scheme != NULL) {
1173 ca0defb9 Paolo Bonzini
            if (len + 3 >= max) {
1174 ca0defb9 Paolo Bonzini
                temp = realloc2n(ret, &max);
1175 ca0defb9 Paolo Bonzini
                if (temp == NULL) goto mem_error;
1176 ca0defb9 Paolo Bonzini
                ret = temp;
1177 ca0defb9 Paolo Bonzini
            }
1178 ca0defb9 Paolo Bonzini
            ret[len++] = '/';
1179 ca0defb9 Paolo Bonzini
            ret[len++] = '/';
1180 ca0defb9 Paolo Bonzini
        }
1181 ca0defb9 Paolo Bonzini
        if (uri->path != NULL) {
1182 ca0defb9 Paolo Bonzini
            p = uri->path;
1183 ca0defb9 Paolo Bonzini
            /*
1184 ca0defb9 Paolo Bonzini
             * the colon in file:///d: should not be escaped or
1185 ca0defb9 Paolo Bonzini
             * Windows accesses fail later.
1186 ca0defb9 Paolo Bonzini
             */
1187 ca0defb9 Paolo Bonzini
            if ((uri->scheme != NULL) &&
1188 ca0defb9 Paolo Bonzini
                (p[0] == '/') &&
1189 ca0defb9 Paolo Bonzini
                (((p[1] >= 'a') && (p[1] <= 'z')) ||
1190 ca0defb9 Paolo Bonzini
                 ((p[1] >= 'A') && (p[1] <= 'Z'))) &&
1191 ca0defb9 Paolo Bonzini
                (p[2] == ':') &&
1192 ca0defb9 Paolo Bonzini
                (!strcmp(uri->scheme, "file"))) {
1193 ca0defb9 Paolo Bonzini
                if (len + 3 >= max) {
1194 ca0defb9 Paolo Bonzini
                    temp = realloc2n(ret, &max);
1195 ca0defb9 Paolo Bonzini
                    if (temp == NULL) goto mem_error;
1196 ca0defb9 Paolo Bonzini
                    ret = temp;
1197 ca0defb9 Paolo Bonzini
                }
1198 ca0defb9 Paolo Bonzini
                ret[len++] = *p++;
1199 ca0defb9 Paolo Bonzini
                ret[len++] = *p++;
1200 ca0defb9 Paolo Bonzini
                ret[len++] = *p++;
1201 ca0defb9 Paolo Bonzini
            }
1202 ca0defb9 Paolo Bonzini
            while (*p != 0) {
1203 ca0defb9 Paolo Bonzini
                if (len + 3 >= max) {
1204 ca0defb9 Paolo Bonzini
                    temp = realloc2n(ret, &max);
1205 ca0defb9 Paolo Bonzini
                    if (temp == NULL) goto mem_error;
1206 ca0defb9 Paolo Bonzini
                    ret = temp;
1207 ca0defb9 Paolo Bonzini
                }
1208 ca0defb9 Paolo Bonzini
                if ((IS_UNRESERVED(*(p))) || ((*(p) == '/')) ||
1209 ca0defb9 Paolo Bonzini
                    ((*(p) == ';')) || ((*(p) == '@')) || ((*(p) == '&')) ||
1210 ca0defb9 Paolo Bonzini
                    ((*(p) == '=')) || ((*(p) == '+')) || ((*(p) == '$')) ||
1211 ca0defb9 Paolo Bonzini
                    ((*(p) == ',')))
1212 ca0defb9 Paolo Bonzini
                    ret[len++] = *p++;
1213 ca0defb9 Paolo Bonzini
                else {
1214 ca0defb9 Paolo Bonzini
                    int val = *(unsigned char *)p++;
1215 ca0defb9 Paolo Bonzini
                    int hi = val / 0x10, lo = val % 0x10;
1216 ca0defb9 Paolo Bonzini
                    ret[len++] = '%';
1217 ca0defb9 Paolo Bonzini
                    ret[len++] = hi + (hi > 9? 'A'-10 : '0');
1218 ca0defb9 Paolo Bonzini
                    ret[len++] = lo + (lo > 9? 'A'-10 : '0');
1219 ca0defb9 Paolo Bonzini
                }
1220 ca0defb9 Paolo Bonzini
            }
1221 ca0defb9 Paolo Bonzini
        }
1222 ca0defb9 Paolo Bonzini
        if (uri->query != NULL) {
1223 ca0defb9 Paolo Bonzini
            if (len + 1 >= max) {
1224 ca0defb9 Paolo Bonzini
                temp = realloc2n(ret, &max);
1225 ca0defb9 Paolo Bonzini
                if (temp == NULL) goto mem_error;
1226 ca0defb9 Paolo Bonzini
                ret = temp;
1227 ca0defb9 Paolo Bonzini
            }
1228 ca0defb9 Paolo Bonzini
            ret[len++] = '?';
1229 ca0defb9 Paolo Bonzini
            p = uri->query;
1230 ca0defb9 Paolo Bonzini
            while (*p != 0) {
1231 ca0defb9 Paolo Bonzini
                if (len + 1 >= max) {
1232 ca0defb9 Paolo Bonzini
                    temp = realloc2n(ret, &max);
1233 ca0defb9 Paolo Bonzini
                    if (temp == NULL) goto mem_error;
1234 ca0defb9 Paolo Bonzini
                    ret = temp;
1235 ca0defb9 Paolo Bonzini
                }
1236 ca0defb9 Paolo Bonzini
                ret[len++] = *p++;
1237 ca0defb9 Paolo Bonzini
            }
1238 ca0defb9 Paolo Bonzini
        }
1239 ca0defb9 Paolo Bonzini
    }
1240 ca0defb9 Paolo Bonzini
    if (uri->fragment != NULL) {
1241 ca0defb9 Paolo Bonzini
        if (len + 3 >= max) {
1242 ca0defb9 Paolo Bonzini
            temp = realloc2n(ret, &max);
1243 ca0defb9 Paolo Bonzini
            if (temp == NULL) goto mem_error;
1244 ca0defb9 Paolo Bonzini
            ret = temp;
1245 ca0defb9 Paolo Bonzini
        }
1246 ca0defb9 Paolo Bonzini
        ret[len++] = '#';
1247 ca0defb9 Paolo Bonzini
        p = uri->fragment;
1248 ca0defb9 Paolo Bonzini
        while (*p != 0) {
1249 ca0defb9 Paolo Bonzini
            if (len + 3 >= max) {
1250 ca0defb9 Paolo Bonzini
                temp = realloc2n(ret, &max);
1251 ca0defb9 Paolo Bonzini
                if (temp == NULL) goto mem_error;
1252 ca0defb9 Paolo Bonzini
                ret = temp;
1253 ca0defb9 Paolo Bonzini
            }
1254 ca0defb9 Paolo Bonzini
            if ((IS_UNRESERVED(*(p))) || (IS_RESERVED(*(p))))
1255 ca0defb9 Paolo Bonzini
                ret[len++] = *p++;
1256 ca0defb9 Paolo Bonzini
            else {
1257 ca0defb9 Paolo Bonzini
                int val = *(unsigned char *)p++;
1258 ca0defb9 Paolo Bonzini
                int hi = val / 0x10, lo = val % 0x10;
1259 ca0defb9 Paolo Bonzini
                ret[len++] = '%';
1260 ca0defb9 Paolo Bonzini
                ret[len++] = hi + (hi > 9? 'A'-10 : '0');
1261 ca0defb9 Paolo Bonzini
                ret[len++] = lo + (lo > 9? 'A'-10 : '0');
1262 ca0defb9 Paolo Bonzini
            }
1263 ca0defb9 Paolo Bonzini
        }
1264 ca0defb9 Paolo Bonzini
    }
1265 ca0defb9 Paolo Bonzini
    if (len >= max) {
1266 ca0defb9 Paolo Bonzini
        temp = realloc2n(ret, &max);
1267 ca0defb9 Paolo Bonzini
        if (temp == NULL) goto mem_error;
1268 ca0defb9 Paolo Bonzini
        ret = temp;
1269 ca0defb9 Paolo Bonzini
    }
1270 ca0defb9 Paolo Bonzini
    ret[len] = 0;
1271 ca0defb9 Paolo Bonzini
    return(ret);
1272 ca0defb9 Paolo Bonzini
1273 ca0defb9 Paolo Bonzini
mem_error:
1274 ca0defb9 Paolo Bonzini
    g_free(ret);
1275 ca0defb9 Paolo Bonzini
    return(NULL);
1276 ca0defb9 Paolo Bonzini
}
1277 ca0defb9 Paolo Bonzini
1278 ca0defb9 Paolo Bonzini
/**
1279 ca0defb9 Paolo Bonzini
 * uri_clean:
1280 ca0defb9 Paolo Bonzini
 * @uri:  pointer to an URI
1281 ca0defb9 Paolo Bonzini
 *
1282 ca0defb9 Paolo Bonzini
 * Make sure the URI struct is free of content
1283 ca0defb9 Paolo Bonzini
 */
1284 ca0defb9 Paolo Bonzini
static void
1285 ca0defb9 Paolo Bonzini
uri_clean(URI *uri) {
1286 ca0defb9 Paolo Bonzini
    if (uri == NULL) return;
1287 ca0defb9 Paolo Bonzini
1288 ca0defb9 Paolo Bonzini
    if (uri->scheme != NULL) g_free(uri->scheme);
1289 ca0defb9 Paolo Bonzini
    uri->scheme = NULL;
1290 ca0defb9 Paolo Bonzini
    if (uri->server != NULL) g_free(uri->server);
1291 ca0defb9 Paolo Bonzini
    uri->server = NULL;
1292 ca0defb9 Paolo Bonzini
    if (uri->user != NULL) g_free(uri->user);
1293 ca0defb9 Paolo Bonzini
    uri->user = NULL;
1294 ca0defb9 Paolo Bonzini
    if (uri->path != NULL) g_free(uri->path);
1295 ca0defb9 Paolo Bonzini
    uri->path = NULL;
1296 ca0defb9 Paolo Bonzini
    if (uri->fragment != NULL) g_free(uri->fragment);
1297 ca0defb9 Paolo Bonzini
    uri->fragment = NULL;
1298 ca0defb9 Paolo Bonzini
    if (uri->opaque != NULL) g_free(uri->opaque);
1299 ca0defb9 Paolo Bonzini
    uri->opaque = NULL;
1300 ca0defb9 Paolo Bonzini
    if (uri->authority != NULL) g_free(uri->authority);
1301 ca0defb9 Paolo Bonzini
    uri->authority = NULL;
1302 ca0defb9 Paolo Bonzini
    if (uri->query != NULL) g_free(uri->query);
1303 ca0defb9 Paolo Bonzini
    uri->query = NULL;
1304 ca0defb9 Paolo Bonzini
}
1305 ca0defb9 Paolo Bonzini
1306 ca0defb9 Paolo Bonzini
/**
1307 ca0defb9 Paolo Bonzini
 * uri_free:
1308 ca0defb9 Paolo Bonzini
 * @uri:  pointer to an URI
1309 ca0defb9 Paolo Bonzini
 *
1310 ca0defb9 Paolo Bonzini
 * Free up the URI struct
1311 ca0defb9 Paolo Bonzini
 */
1312 ca0defb9 Paolo Bonzini
void
1313 ca0defb9 Paolo Bonzini
uri_free(URI *uri) {
1314 ca0defb9 Paolo Bonzini
    uri_clean(uri);
1315 ca0defb9 Paolo Bonzini
    g_free(uri);
1316 ca0defb9 Paolo Bonzini
}
1317 ca0defb9 Paolo Bonzini
1318 ca0defb9 Paolo Bonzini
/************************************************************************
1319 ca0defb9 Paolo Bonzini
 *                                                                        *
1320 ca0defb9 Paolo Bonzini
 *                        Helper functions                                *
1321 ca0defb9 Paolo Bonzini
 *                                                                        *
1322 ca0defb9 Paolo Bonzini
 ************************************************************************/
1323 ca0defb9 Paolo Bonzini
1324 ca0defb9 Paolo Bonzini
/**
1325 ca0defb9 Paolo Bonzini
 * normalize_uri_path:
1326 ca0defb9 Paolo Bonzini
 * @path:  pointer to the path string
1327 ca0defb9 Paolo Bonzini
 *
1328 ca0defb9 Paolo Bonzini
 * Applies the 5 normalization steps to a path string--that is, RFC 2396
1329 ca0defb9 Paolo Bonzini
 * Section 5.2, steps 6.c through 6.g.
1330 ca0defb9 Paolo Bonzini
 *
1331 ca0defb9 Paolo Bonzini
 * Normalization occurs directly on the string, no new allocation is done
1332 ca0defb9 Paolo Bonzini
 *
1333 ca0defb9 Paolo Bonzini
 * Returns 0 or an error code
1334 ca0defb9 Paolo Bonzini
 */
1335 ca0defb9 Paolo Bonzini
static int
1336 ca0defb9 Paolo Bonzini
normalize_uri_path(char *path) {
1337 ca0defb9 Paolo Bonzini
    char *cur, *out;
1338 ca0defb9 Paolo Bonzini
1339 ca0defb9 Paolo Bonzini
    if (path == NULL)
1340 ca0defb9 Paolo Bonzini
        return(-1);
1341 ca0defb9 Paolo Bonzini
1342 ca0defb9 Paolo Bonzini
    /* Skip all initial "/" chars.  We want to get to the beginning of the
1343 ca0defb9 Paolo Bonzini
     * first non-empty segment.
1344 ca0defb9 Paolo Bonzini
     */
1345 ca0defb9 Paolo Bonzini
    cur = path;
1346 ca0defb9 Paolo Bonzini
    while (cur[0] == '/')
1347 ca0defb9 Paolo Bonzini
      ++cur;
1348 ca0defb9 Paolo Bonzini
    if (cur[0] == '\0')
1349 ca0defb9 Paolo Bonzini
      return(0);
1350 ca0defb9 Paolo Bonzini
1351 ca0defb9 Paolo Bonzini
    /* Keep everything we've seen so far.  */
1352 ca0defb9 Paolo Bonzini
    out = cur;
1353 ca0defb9 Paolo Bonzini
1354 ca0defb9 Paolo Bonzini
    /*
1355 ca0defb9 Paolo Bonzini
     * Analyze each segment in sequence for cases (c) and (d).
1356 ca0defb9 Paolo Bonzini
     */
1357 ca0defb9 Paolo Bonzini
    while (cur[0] != '\0') {
1358 ca0defb9 Paolo Bonzini
        /*
1359 ca0defb9 Paolo Bonzini
         * c) All occurrences of "./", where "." is a complete path segment,
1360 ca0defb9 Paolo Bonzini
         *    are removed from the buffer string.
1361 ca0defb9 Paolo Bonzini
         */
1362 ca0defb9 Paolo Bonzini
        if ((cur[0] == '.') && (cur[1] == '/')) {
1363 ca0defb9 Paolo Bonzini
            cur += 2;
1364 ca0defb9 Paolo Bonzini
            /* '//' normalization should be done at this point too */
1365 ca0defb9 Paolo Bonzini
            while (cur[0] == '/')
1366 ca0defb9 Paolo Bonzini
                cur++;
1367 ca0defb9 Paolo Bonzini
            continue;
1368 ca0defb9 Paolo Bonzini
        }
1369 ca0defb9 Paolo Bonzini
1370 ca0defb9 Paolo Bonzini
        /*
1371 ca0defb9 Paolo Bonzini
         * d) If the buffer string ends with "." as a complete path segment,
1372 ca0defb9 Paolo Bonzini
         *    that "." is removed.
1373 ca0defb9 Paolo Bonzini
         */
1374 ca0defb9 Paolo Bonzini
        if ((cur[0] == '.') && (cur[1] == '\0'))
1375 ca0defb9 Paolo Bonzini
            break;
1376 ca0defb9 Paolo Bonzini
1377 ca0defb9 Paolo Bonzini
        /* Otherwise keep the segment.  */
1378 ca0defb9 Paolo Bonzini
        while (cur[0] != '/') {
1379 ca0defb9 Paolo Bonzini
            if (cur[0] == '\0')
1380 ca0defb9 Paolo Bonzini
              goto done_cd;
1381 ca0defb9 Paolo Bonzini
            (out++)[0] = (cur++)[0];
1382 ca0defb9 Paolo Bonzini
        }
1383 ca0defb9 Paolo Bonzini
        /* nomalize // */
1384 ca0defb9 Paolo Bonzini
        while ((cur[0] == '/') && (cur[1] == '/'))
1385 ca0defb9 Paolo Bonzini
            cur++;
1386 ca0defb9 Paolo Bonzini
1387 ca0defb9 Paolo Bonzini
        (out++)[0] = (cur++)[0];
1388 ca0defb9 Paolo Bonzini
    }
1389 ca0defb9 Paolo Bonzini
 done_cd:
1390 ca0defb9 Paolo Bonzini
    out[0] = '\0';
1391 ca0defb9 Paolo Bonzini
1392 ca0defb9 Paolo Bonzini
    /* Reset to the beginning of the first segment for the next sequence.  */
1393 ca0defb9 Paolo Bonzini
    cur = path;
1394 ca0defb9 Paolo Bonzini
    while (cur[0] == '/')
1395 ca0defb9 Paolo Bonzini
      ++cur;
1396 ca0defb9 Paolo Bonzini
    if (cur[0] == '\0')
1397 ca0defb9 Paolo Bonzini
        return(0);
1398 ca0defb9 Paolo Bonzini
1399 ca0defb9 Paolo Bonzini
    /*
1400 ca0defb9 Paolo Bonzini
     * Analyze each segment in sequence for cases (e) and (f).
1401 ca0defb9 Paolo Bonzini
     *
1402 ca0defb9 Paolo Bonzini
     * e) All occurrences of "<segment>/../", where <segment> is a
1403 ca0defb9 Paolo Bonzini
     *    complete path segment not equal to "..", are removed from the
1404 ca0defb9 Paolo Bonzini
     *    buffer string.  Removal of these path segments is performed
1405 ca0defb9 Paolo Bonzini
     *    iteratively, removing the leftmost matching pattern on each
1406 ca0defb9 Paolo Bonzini
     *    iteration, until no matching pattern remains.
1407 ca0defb9 Paolo Bonzini
     *
1408 ca0defb9 Paolo Bonzini
     * f) If the buffer string ends with "<segment>/..", where <segment>
1409 ca0defb9 Paolo Bonzini
     *    is a complete path segment not equal to "..", that
1410 ca0defb9 Paolo Bonzini
     *    "<segment>/.." is removed.
1411 ca0defb9 Paolo Bonzini
     *
1412 ca0defb9 Paolo Bonzini
     * To satisfy the "iterative" clause in (e), we need to collapse the
1413 ca0defb9 Paolo Bonzini
     * string every time we find something that needs to be removed.  Thus,
1414 ca0defb9 Paolo Bonzini
     * we don't need to keep two pointers into the string: we only need a
1415 ca0defb9 Paolo Bonzini
     * "current position" pointer.
1416 ca0defb9 Paolo Bonzini
     */
1417 ca0defb9 Paolo Bonzini
    while (1) {
1418 ca0defb9 Paolo Bonzini
        char *segp, *tmp;
1419 ca0defb9 Paolo Bonzini
1420 ca0defb9 Paolo Bonzini
        /* At the beginning of each iteration of this loop, "cur" points to
1421 ca0defb9 Paolo Bonzini
         * the first character of the segment we want to examine.
1422 ca0defb9 Paolo Bonzini
         */
1423 ca0defb9 Paolo Bonzini
1424 ca0defb9 Paolo Bonzini
        /* Find the end of the current segment.  */
1425 ca0defb9 Paolo Bonzini
        segp = cur;
1426 ca0defb9 Paolo Bonzini
        while ((segp[0] != '/') && (segp[0] != '\0'))
1427 ca0defb9 Paolo Bonzini
          ++segp;
1428 ca0defb9 Paolo Bonzini
1429 ca0defb9 Paolo Bonzini
        /* If this is the last segment, we're done (we need at least two
1430 ca0defb9 Paolo Bonzini
         * segments to meet the criteria for the (e) and (f) cases).
1431 ca0defb9 Paolo Bonzini
         */
1432 ca0defb9 Paolo Bonzini
        if (segp[0] == '\0')
1433 ca0defb9 Paolo Bonzini
          break;
1434 ca0defb9 Paolo Bonzini
1435 ca0defb9 Paolo Bonzini
        /* If the first segment is "..", or if the next segment _isn't_ "..",
1436 ca0defb9 Paolo Bonzini
         * keep this segment and try the next one.
1437 ca0defb9 Paolo Bonzini
         */
1438 ca0defb9 Paolo Bonzini
        ++segp;
1439 ca0defb9 Paolo Bonzini
        if (((cur[0] == '.') && (cur[1] == '.') && (segp == cur+3))
1440 ca0defb9 Paolo Bonzini
            || ((segp[0] != '.') || (segp[1] != '.')
1441 ca0defb9 Paolo Bonzini
                || ((segp[2] != '/') && (segp[2] != '\0')))) {
1442 ca0defb9 Paolo Bonzini
          cur = segp;
1443 ca0defb9 Paolo Bonzini
          continue;
1444 ca0defb9 Paolo Bonzini
        }
1445 ca0defb9 Paolo Bonzini
1446 ca0defb9 Paolo Bonzini
        /* If we get here, remove this segment and the next one and back up
1447 ca0defb9 Paolo Bonzini
         * to the previous segment (if there is one), to implement the
1448 ca0defb9 Paolo Bonzini
         * "iteratively" clause.  It's pretty much impossible to back up
1449 ca0defb9 Paolo Bonzini
         * while maintaining two pointers into the buffer, so just compact
1450 ca0defb9 Paolo Bonzini
         * the whole buffer now.
1451 ca0defb9 Paolo Bonzini
         */
1452 ca0defb9 Paolo Bonzini
1453 ca0defb9 Paolo Bonzini
        /* If this is the end of the buffer, we're done.  */
1454 ca0defb9 Paolo Bonzini
        if (segp[2] == '\0') {
1455 ca0defb9 Paolo Bonzini
          cur[0] = '\0';
1456 ca0defb9 Paolo Bonzini
          break;
1457 ca0defb9 Paolo Bonzini
        }
1458 ca0defb9 Paolo Bonzini
        /* Valgrind complained, strcpy(cur, segp + 3); */
1459 ca0defb9 Paolo Bonzini
        /* string will overlap, do not use strcpy */
1460 ca0defb9 Paolo Bonzini
        tmp = cur;
1461 ca0defb9 Paolo Bonzini
        segp += 3;
1462 ca0defb9 Paolo Bonzini
        while ((*tmp++ = *segp++) != 0)
1463 ca0defb9 Paolo Bonzini
          ;
1464 ca0defb9 Paolo Bonzini
1465 ca0defb9 Paolo Bonzini
        /* If there are no previous segments, then keep going from here.  */
1466 ca0defb9 Paolo Bonzini
        segp = cur;
1467 ca0defb9 Paolo Bonzini
        while ((segp > path) && ((--segp)[0] == '/'))
1468 ca0defb9 Paolo Bonzini
          ;
1469 ca0defb9 Paolo Bonzini
        if (segp == path)
1470 ca0defb9 Paolo Bonzini
          continue;
1471 ca0defb9 Paolo Bonzini
1472 ca0defb9 Paolo Bonzini
        /* "segp" is pointing to the end of a previous segment; find it's
1473 ca0defb9 Paolo Bonzini
         * start.  We need to back up to the previous segment and start
1474 ca0defb9 Paolo Bonzini
         * over with that to handle things like "foo/bar/../..".  If we
1475 ca0defb9 Paolo Bonzini
         * don't do this, then on the first pass we'll remove the "bar/..",
1476 ca0defb9 Paolo Bonzini
         * but be pointing at the second ".." so we won't realize we can also
1477 ca0defb9 Paolo Bonzini
         * remove the "foo/..".
1478 ca0defb9 Paolo Bonzini
         */
1479 ca0defb9 Paolo Bonzini
        cur = segp;
1480 ca0defb9 Paolo Bonzini
        while ((cur > path) && (cur[-1] != '/'))
1481 ca0defb9 Paolo Bonzini
          --cur;
1482 ca0defb9 Paolo Bonzini
    }
1483 ca0defb9 Paolo Bonzini
    out[0] = '\0';
1484 ca0defb9 Paolo Bonzini
1485 ca0defb9 Paolo Bonzini
    /*
1486 ca0defb9 Paolo Bonzini
     * g) If the resulting buffer string still begins with one or more
1487 ca0defb9 Paolo Bonzini
     *    complete path segments of "..", then the reference is
1488 ca0defb9 Paolo Bonzini
     *    considered to be in error. Implementations may handle this
1489 ca0defb9 Paolo Bonzini
     *    error by retaining these components in the resolved path (i.e.,
1490 ca0defb9 Paolo Bonzini
     *    treating them as part of the final URI), by removing them from
1491 ca0defb9 Paolo Bonzini
     *    the resolved path (i.e., discarding relative levels above the
1492 ca0defb9 Paolo Bonzini
     *    root), or by avoiding traversal of the reference.
1493 ca0defb9 Paolo Bonzini
     *
1494 ca0defb9 Paolo Bonzini
     * We discard them from the final path.
1495 ca0defb9 Paolo Bonzini
     */
1496 ca0defb9 Paolo Bonzini
    if (path[0] == '/') {
1497 ca0defb9 Paolo Bonzini
      cur = path;
1498 ca0defb9 Paolo Bonzini
      while ((cur[0] == '/') && (cur[1] == '.') && (cur[2] == '.')
1499 ca0defb9 Paolo Bonzini
             && ((cur[3] == '/') || (cur[3] == '\0')))
1500 ca0defb9 Paolo Bonzini
        cur += 3;
1501 ca0defb9 Paolo Bonzini
1502 ca0defb9 Paolo Bonzini
      if (cur != path) {
1503 ca0defb9 Paolo Bonzini
        out = path;
1504 ca0defb9 Paolo Bonzini
        while (cur[0] != '\0')
1505 ca0defb9 Paolo Bonzini
          (out++)[0] = (cur++)[0];
1506 ca0defb9 Paolo Bonzini
        out[0] = 0;
1507 ca0defb9 Paolo Bonzini
      }
1508 ca0defb9 Paolo Bonzini
    }
1509 ca0defb9 Paolo Bonzini
1510 ca0defb9 Paolo Bonzini
    return(0);
1511 ca0defb9 Paolo Bonzini
}
1512 ca0defb9 Paolo Bonzini
1513 ca0defb9 Paolo Bonzini
static int is_hex(char c) {
1514 ca0defb9 Paolo Bonzini
    if (((c >= '0') && (c <= '9')) ||
1515 ca0defb9 Paolo Bonzini
        ((c >= 'a') && (c <= 'f')) ||
1516 ca0defb9 Paolo Bonzini
        ((c >= 'A') && (c <= 'F')))
1517 ca0defb9 Paolo Bonzini
        return(1);
1518 ca0defb9 Paolo Bonzini
    return(0);
1519 ca0defb9 Paolo Bonzini
}
1520 ca0defb9 Paolo Bonzini
1521 ca0defb9 Paolo Bonzini
1522 ca0defb9 Paolo Bonzini
/**
1523 ca0defb9 Paolo Bonzini
 * uri_string_unescape:
1524 ca0defb9 Paolo Bonzini
 * @str:  the string to unescape
1525 ca0defb9 Paolo Bonzini
 * @len:   the length in bytes to unescape (or <= 0 to indicate full string)
1526 ca0defb9 Paolo Bonzini
 * @target:  optional destination buffer
1527 ca0defb9 Paolo Bonzini
 *
1528 ca0defb9 Paolo Bonzini
 * Unescaping routine, but does not check that the string is an URI. The
1529 ca0defb9 Paolo Bonzini
 * output is a direct unsigned char translation of %XX values (no encoding)
1530 ca0defb9 Paolo Bonzini
 * Note that the length of the result can only be smaller or same size as
1531 ca0defb9 Paolo Bonzini
 * the input string.
1532 ca0defb9 Paolo Bonzini
 *
1533 ca0defb9 Paolo Bonzini
 * Returns a copy of the string, but unescaped, will return NULL only in case
1534 ca0defb9 Paolo Bonzini
 * of error
1535 ca0defb9 Paolo Bonzini
 */
1536 ca0defb9 Paolo Bonzini
char *
1537 ca0defb9 Paolo Bonzini
uri_string_unescape(const char *str, int len, char *target) {
1538 ca0defb9 Paolo Bonzini
    char *ret, *out;
1539 ca0defb9 Paolo Bonzini
    const char *in;
1540 ca0defb9 Paolo Bonzini
1541 ca0defb9 Paolo Bonzini
    if (str == NULL)
1542 ca0defb9 Paolo Bonzini
        return(NULL);
1543 ca0defb9 Paolo Bonzini
    if (len <= 0) len = strlen(str);
1544 ca0defb9 Paolo Bonzini
    if (len < 0) return(NULL);
1545 ca0defb9 Paolo Bonzini
1546 ca0defb9 Paolo Bonzini
    if (target == NULL) {
1547 ca0defb9 Paolo Bonzini
        ret = g_malloc(len + 1);
1548 ca0defb9 Paolo Bonzini
    } else
1549 ca0defb9 Paolo Bonzini
        ret = target;
1550 ca0defb9 Paolo Bonzini
    in = str;
1551 ca0defb9 Paolo Bonzini
    out = ret;
1552 ca0defb9 Paolo Bonzini
    while(len > 0) {
1553 ca0defb9 Paolo Bonzini
        if ((len > 2) && (*in == '%') && (is_hex(in[1])) && (is_hex(in[2]))) {
1554 ca0defb9 Paolo Bonzini
            in++;
1555 ca0defb9 Paolo Bonzini
            if ((*in >= '0') && (*in <= '9'))
1556 ca0defb9 Paolo Bonzini
                *out = (*in - '0');
1557 ca0defb9 Paolo Bonzini
            else if ((*in >= 'a') && (*in <= 'f'))
1558 ca0defb9 Paolo Bonzini
                *out = (*in - 'a') + 10;
1559 ca0defb9 Paolo Bonzini
            else if ((*in >= 'A') && (*in <= 'F'))
1560 ca0defb9 Paolo Bonzini
                *out = (*in - 'A') + 10;
1561 ca0defb9 Paolo Bonzini
            in++;
1562 ca0defb9 Paolo Bonzini
            if ((*in >= '0') && (*in <= '9'))
1563 ca0defb9 Paolo Bonzini
                *out = *out * 16 + (*in - '0');
1564 ca0defb9 Paolo Bonzini
            else if ((*in >= 'a') && (*in <= 'f'))
1565 ca0defb9 Paolo Bonzini
                *out = *out * 16 + (*in - 'a') + 10;
1566 ca0defb9 Paolo Bonzini
            else if ((*in >= 'A') && (*in <= 'F'))
1567 ca0defb9 Paolo Bonzini
                *out = *out * 16 + (*in - 'A') + 10;
1568 ca0defb9 Paolo Bonzini
            in++;
1569 ca0defb9 Paolo Bonzini
            len -= 3;
1570 ca0defb9 Paolo Bonzini
            out++;
1571 ca0defb9 Paolo Bonzini
        } else {
1572 ca0defb9 Paolo Bonzini
            *out++ = *in++;
1573 ca0defb9 Paolo Bonzini
            len--;
1574 ca0defb9 Paolo Bonzini
        }
1575 ca0defb9 Paolo Bonzini
    }
1576 ca0defb9 Paolo Bonzini
    *out = 0;
1577 ca0defb9 Paolo Bonzini
    return(ret);
1578 ca0defb9 Paolo Bonzini
}
1579 ca0defb9 Paolo Bonzini
1580 ca0defb9 Paolo Bonzini
/**
1581 ca0defb9 Paolo Bonzini
 * uri_string_escape:
1582 ca0defb9 Paolo Bonzini
 * @str:  string to escape
1583 ca0defb9 Paolo Bonzini
 * @list: exception list string of chars not to escape
1584 ca0defb9 Paolo Bonzini
 *
1585 ca0defb9 Paolo Bonzini
 * This routine escapes a string to hex, ignoring reserved characters (a-z)
1586 ca0defb9 Paolo Bonzini
 * and the characters in the exception list.
1587 ca0defb9 Paolo Bonzini
 *
1588 ca0defb9 Paolo Bonzini
 * Returns a new escaped string or NULL in case of error.
1589 ca0defb9 Paolo Bonzini
 */
1590 ca0defb9 Paolo Bonzini
char *
1591 ca0defb9 Paolo Bonzini
uri_string_escape(const char *str, const char *list) {
1592 ca0defb9 Paolo Bonzini
    char *ret, ch;
1593 ca0defb9 Paolo Bonzini
    char *temp;
1594 ca0defb9 Paolo Bonzini
    const char *in;
1595 ca0defb9 Paolo Bonzini
    int len, out;
1596 ca0defb9 Paolo Bonzini
1597 ca0defb9 Paolo Bonzini
    if (str == NULL)
1598 ca0defb9 Paolo Bonzini
        return(NULL);
1599 ca0defb9 Paolo Bonzini
    if (str[0] == 0)
1600 ca0defb9 Paolo Bonzini
        return(g_strdup(str));
1601 ca0defb9 Paolo Bonzini
    len = strlen(str);
1602 ca0defb9 Paolo Bonzini
    if (!(len > 0)) return(NULL);
1603 ca0defb9 Paolo Bonzini
1604 ca0defb9 Paolo Bonzini
    len += 20;
1605 ca0defb9 Paolo Bonzini
    ret = g_malloc(len);
1606 ca0defb9 Paolo Bonzini
    in = str;
1607 ca0defb9 Paolo Bonzini
    out = 0;
1608 ca0defb9 Paolo Bonzini
    while(*in != 0) {
1609 ca0defb9 Paolo Bonzini
        if (len - out <= 3) {
1610 ca0defb9 Paolo Bonzini
            temp = realloc2n(ret, &len);
1611 ca0defb9 Paolo Bonzini
            ret = temp;
1612 ca0defb9 Paolo Bonzini
        }
1613 ca0defb9 Paolo Bonzini
1614 ca0defb9 Paolo Bonzini
        ch = *in;
1615 ca0defb9 Paolo Bonzini
1616 ca0defb9 Paolo Bonzini
        if ((ch != '@') && (!IS_UNRESERVED(ch)) && (!strchr(list, ch))) {
1617 ca0defb9 Paolo Bonzini
            unsigned char val;
1618 ca0defb9 Paolo Bonzini
            ret[out++] = '%';
1619 ca0defb9 Paolo Bonzini
            val = ch >> 4;
1620 ca0defb9 Paolo Bonzini
            if (val <= 9)
1621 ca0defb9 Paolo Bonzini
                ret[out++] = '0' + val;
1622 ca0defb9 Paolo Bonzini
            else
1623 ca0defb9 Paolo Bonzini
                ret[out++] = 'A' + val - 0xA;
1624 ca0defb9 Paolo Bonzini
            val = ch & 0xF;
1625 ca0defb9 Paolo Bonzini
            if (val <= 9)
1626 ca0defb9 Paolo Bonzini
                ret[out++] = '0' + val;
1627 ca0defb9 Paolo Bonzini
            else
1628 ca0defb9 Paolo Bonzini
                ret[out++] = 'A' + val - 0xA;
1629 ca0defb9 Paolo Bonzini
            in++;
1630 ca0defb9 Paolo Bonzini
        } else {
1631 ca0defb9 Paolo Bonzini
            ret[out++] = *in++;
1632 ca0defb9 Paolo Bonzini
        }
1633 ca0defb9 Paolo Bonzini
1634 ca0defb9 Paolo Bonzini
    }
1635 ca0defb9 Paolo Bonzini
    ret[out] = 0;
1636 ca0defb9 Paolo Bonzini
    return(ret);
1637 ca0defb9 Paolo Bonzini
}
1638 ca0defb9 Paolo Bonzini
1639 ca0defb9 Paolo Bonzini
/************************************************************************
1640 ca0defb9 Paolo Bonzini
 *                                                                        *
1641 ca0defb9 Paolo Bonzini
 *                        Public functions                                *
1642 ca0defb9 Paolo Bonzini
 *                                                                        *
1643 ca0defb9 Paolo Bonzini
 ************************************************************************/
1644 ca0defb9 Paolo Bonzini
1645 ca0defb9 Paolo Bonzini
/**
1646 ca0defb9 Paolo Bonzini
 * uri_resolve:
1647 ca0defb9 Paolo Bonzini
 * @URI:  the URI instance found in the document
1648 ca0defb9 Paolo Bonzini
 * @base:  the base value
1649 ca0defb9 Paolo Bonzini
 *
1650 ca0defb9 Paolo Bonzini
 * Computes he final URI of the reference done by checking that
1651 ca0defb9 Paolo Bonzini
 * the given URI is valid, and building the final URI using the
1652 ca0defb9 Paolo Bonzini
 * base URI. This is processed according to section 5.2 of the
1653 ca0defb9 Paolo Bonzini
 * RFC 2396
1654 ca0defb9 Paolo Bonzini
 *
1655 ca0defb9 Paolo Bonzini
 * 5.2. Resolving Relative References to Absolute Form
1656 ca0defb9 Paolo Bonzini
 *
1657 ca0defb9 Paolo Bonzini
 * Returns a new URI string (to be freed by the caller) or NULL in case
1658 ca0defb9 Paolo Bonzini
 *         of error.
1659 ca0defb9 Paolo Bonzini
 */
1660 ca0defb9 Paolo Bonzini
char *
1661 ca0defb9 Paolo Bonzini
uri_resolve(const char *uri, const char *base) {
1662 ca0defb9 Paolo Bonzini
    char *val = NULL;
1663 ca0defb9 Paolo Bonzini
    int ret, len, indx, cur, out;
1664 ca0defb9 Paolo Bonzini
    URI *ref = NULL;
1665 ca0defb9 Paolo Bonzini
    URI *bas = NULL;
1666 ca0defb9 Paolo Bonzini
    URI *res = NULL;
1667 ca0defb9 Paolo Bonzini
1668 ca0defb9 Paolo Bonzini
    /*
1669 ca0defb9 Paolo Bonzini
     * 1) The URI reference is parsed into the potential four components and
1670 ca0defb9 Paolo Bonzini
     *    fragment identifier, as described in Section 4.3.
1671 ca0defb9 Paolo Bonzini
     *
1672 ca0defb9 Paolo Bonzini
     *    NOTE that a completely empty URI is treated by modern browsers
1673 ca0defb9 Paolo Bonzini
     *    as a reference to "." rather than as a synonym for the current
1674 ca0defb9 Paolo Bonzini
     *    URI.  Should we do that here?
1675 ca0defb9 Paolo Bonzini
     */
1676 ca0defb9 Paolo Bonzini
    if (uri == NULL)
1677 ca0defb9 Paolo Bonzini
        ret = -1;
1678 ca0defb9 Paolo Bonzini
    else {
1679 ca0defb9 Paolo Bonzini
        if (*uri) {
1680 ca0defb9 Paolo Bonzini
            ref = uri_new();
1681 ca0defb9 Paolo Bonzini
            if (ref == NULL)
1682 ca0defb9 Paolo Bonzini
                goto done;
1683 ca0defb9 Paolo Bonzini
            ret = uri_parse_into(ref, uri);
1684 ca0defb9 Paolo Bonzini
        }
1685 ca0defb9 Paolo Bonzini
        else
1686 ca0defb9 Paolo Bonzini
            ret = 0;
1687 ca0defb9 Paolo Bonzini
    }
1688 ca0defb9 Paolo Bonzini
    if (ret != 0)
1689 ca0defb9 Paolo Bonzini
        goto done;
1690 ca0defb9 Paolo Bonzini
    if ((ref != NULL) && (ref->scheme != NULL)) {
1691 ca0defb9 Paolo Bonzini
        /*
1692 ca0defb9 Paolo Bonzini
         * The URI is absolute don't modify.
1693 ca0defb9 Paolo Bonzini
         */
1694 ca0defb9 Paolo Bonzini
        val = g_strdup(uri);
1695 ca0defb9 Paolo Bonzini
        goto done;
1696 ca0defb9 Paolo Bonzini
    }
1697 ca0defb9 Paolo Bonzini
    if (base == NULL)
1698 ca0defb9 Paolo Bonzini
        ret = -1;
1699 ca0defb9 Paolo Bonzini
    else {
1700 ca0defb9 Paolo Bonzini
        bas = uri_new();
1701 ca0defb9 Paolo Bonzini
        if (bas == NULL)
1702 ca0defb9 Paolo Bonzini
            goto done;
1703 ca0defb9 Paolo Bonzini
        ret = uri_parse_into(bas, base);
1704 ca0defb9 Paolo Bonzini
    }
1705 ca0defb9 Paolo Bonzini
    if (ret != 0) {
1706 ca0defb9 Paolo Bonzini
        if (ref)
1707 ca0defb9 Paolo Bonzini
            val = uri_to_string(ref);
1708 ca0defb9 Paolo Bonzini
        goto done;
1709 ca0defb9 Paolo Bonzini
    }
1710 ca0defb9 Paolo Bonzini
    if (ref == NULL) {
1711 ca0defb9 Paolo Bonzini
        /*
1712 ca0defb9 Paolo Bonzini
         * the base fragment must be ignored
1713 ca0defb9 Paolo Bonzini
         */
1714 ca0defb9 Paolo Bonzini
        if (bas->fragment != NULL) {
1715 ca0defb9 Paolo Bonzini
            g_free(bas->fragment);
1716 ca0defb9 Paolo Bonzini
            bas->fragment = NULL;
1717 ca0defb9 Paolo Bonzini
        }
1718 ca0defb9 Paolo Bonzini
        val = uri_to_string(bas);
1719 ca0defb9 Paolo Bonzini
        goto done;
1720 ca0defb9 Paolo Bonzini
    }
1721 ca0defb9 Paolo Bonzini
1722 ca0defb9 Paolo Bonzini
    /*
1723 ca0defb9 Paolo Bonzini
     * 2) If the path component is empty and the scheme, authority, and
1724 ca0defb9 Paolo Bonzini
     *    query components are undefined, then it is a reference to the
1725 ca0defb9 Paolo Bonzini
     *    current document and we are done.  Otherwise, the reference URI's
1726 ca0defb9 Paolo Bonzini
     *    query and fragment components are defined as found (or not found)
1727 ca0defb9 Paolo Bonzini
     *    within the URI reference and not inherited from the base URI.
1728 ca0defb9 Paolo Bonzini
     *
1729 ca0defb9 Paolo Bonzini
     *    NOTE that in modern browsers, the parsing differs from the above
1730 ca0defb9 Paolo Bonzini
     *    in the following aspect:  the query component is allowed to be
1731 ca0defb9 Paolo Bonzini
     *    defined while still treating this as a reference to the current
1732 ca0defb9 Paolo Bonzini
     *    document.
1733 ca0defb9 Paolo Bonzini
     */
1734 ca0defb9 Paolo Bonzini
    res = uri_new();
1735 ca0defb9 Paolo Bonzini
    if (res == NULL)
1736 ca0defb9 Paolo Bonzini
        goto done;
1737 ca0defb9 Paolo Bonzini
    if ((ref->scheme == NULL) && (ref->path == NULL) &&
1738 ca0defb9 Paolo Bonzini
        ((ref->authority == NULL) && (ref->server == NULL))) {
1739 ca0defb9 Paolo Bonzini
        if (bas->scheme != NULL)
1740 ca0defb9 Paolo Bonzini
            res->scheme = g_strdup(bas->scheme);
1741 ca0defb9 Paolo Bonzini
        if (bas->authority != NULL)
1742 ca0defb9 Paolo Bonzini
            res->authority = g_strdup(bas->authority);
1743 ca0defb9 Paolo Bonzini
        else if (bas->server != NULL) {
1744 ca0defb9 Paolo Bonzini
            res->server = g_strdup(bas->server);
1745 ca0defb9 Paolo Bonzini
            if (bas->user != NULL)
1746 ca0defb9 Paolo Bonzini
                res->user = g_strdup(bas->user);
1747 ca0defb9 Paolo Bonzini
            res->port = bas->port;
1748 ca0defb9 Paolo Bonzini
        }
1749 ca0defb9 Paolo Bonzini
        if (bas->path != NULL)
1750 ca0defb9 Paolo Bonzini
            res->path = g_strdup(bas->path);
1751 ca0defb9 Paolo Bonzini
        if (ref->query != NULL)
1752 ca0defb9 Paolo Bonzini
            res->query = g_strdup (ref->query);
1753 ca0defb9 Paolo Bonzini
        else if (bas->query != NULL)
1754 ca0defb9 Paolo Bonzini
            res->query = g_strdup(bas->query);
1755 ca0defb9 Paolo Bonzini
        if (ref->fragment != NULL)
1756 ca0defb9 Paolo Bonzini
            res->fragment = g_strdup(ref->fragment);
1757 ca0defb9 Paolo Bonzini
        goto step_7;
1758 ca0defb9 Paolo Bonzini
    }
1759 ca0defb9 Paolo Bonzini
1760 ca0defb9 Paolo Bonzini
    /*
1761 ca0defb9 Paolo Bonzini
     * 3) If the scheme component is defined, indicating that the reference
1762 ca0defb9 Paolo Bonzini
     *    starts with a scheme name, then the reference is interpreted as an
1763 ca0defb9 Paolo Bonzini
     *    absolute URI and we are done.  Otherwise, the reference URI's
1764 ca0defb9 Paolo Bonzini
     *    scheme is inherited from the base URI's scheme component.
1765 ca0defb9 Paolo Bonzini
     */
1766 ca0defb9 Paolo Bonzini
    if (ref->scheme != NULL) {
1767 ca0defb9 Paolo Bonzini
        val = uri_to_string(ref);
1768 ca0defb9 Paolo Bonzini
        goto done;
1769 ca0defb9 Paolo Bonzini
    }
1770 ca0defb9 Paolo Bonzini
    if (bas->scheme != NULL)
1771 ca0defb9 Paolo Bonzini
        res->scheme = g_strdup(bas->scheme);
1772 ca0defb9 Paolo Bonzini
1773 ca0defb9 Paolo Bonzini
    if (ref->query != NULL)
1774 ca0defb9 Paolo Bonzini
        res->query = g_strdup(ref->query);
1775 ca0defb9 Paolo Bonzini
    if (ref->fragment != NULL)
1776 ca0defb9 Paolo Bonzini
        res->fragment = g_strdup(ref->fragment);
1777 ca0defb9 Paolo Bonzini
1778 ca0defb9 Paolo Bonzini
    /*
1779 ca0defb9 Paolo Bonzini
     * 4) If the authority component is defined, then the reference is a
1780 ca0defb9 Paolo Bonzini
     *    network-path and we skip to step 7.  Otherwise, the reference
1781 ca0defb9 Paolo Bonzini
     *    URI's authority is inherited from the base URI's authority
1782 ca0defb9 Paolo Bonzini
     *    component, which will also be undefined if the URI scheme does not
1783 ca0defb9 Paolo Bonzini
     *    use an authority component.
1784 ca0defb9 Paolo Bonzini
     */
1785 ca0defb9 Paolo Bonzini
    if ((ref->authority != NULL) || (ref->server != NULL)) {
1786 ca0defb9 Paolo Bonzini
        if (ref->authority != NULL)
1787 ca0defb9 Paolo Bonzini
            res->authority = g_strdup(ref->authority);
1788 ca0defb9 Paolo Bonzini
        else {
1789 ca0defb9 Paolo Bonzini
            res->server = g_strdup(ref->server);
1790 ca0defb9 Paolo Bonzini
            if (ref->user != NULL)
1791 ca0defb9 Paolo Bonzini
                res->user = g_strdup(ref->user);
1792 ca0defb9 Paolo Bonzini
            res->port = ref->port;
1793 ca0defb9 Paolo Bonzini
        }
1794 ca0defb9 Paolo Bonzini
        if (ref->path != NULL)
1795 ca0defb9 Paolo Bonzini
            res->path = g_strdup(ref->path);
1796 ca0defb9 Paolo Bonzini
        goto step_7;
1797 ca0defb9 Paolo Bonzini
    }
1798 ca0defb9 Paolo Bonzini
    if (bas->authority != NULL)
1799 ca0defb9 Paolo Bonzini
        res->authority = g_strdup(bas->authority);
1800 ca0defb9 Paolo Bonzini
    else if (bas->server != NULL) {
1801 ca0defb9 Paolo Bonzini
        res->server = g_strdup(bas->server);
1802 ca0defb9 Paolo Bonzini
        if (bas->user != NULL)
1803 ca0defb9 Paolo Bonzini
            res->user = g_strdup(bas->user);
1804 ca0defb9 Paolo Bonzini
        res->port = bas->port;
1805 ca0defb9 Paolo Bonzini
    }
1806 ca0defb9 Paolo Bonzini
1807 ca0defb9 Paolo Bonzini
    /*
1808 ca0defb9 Paolo Bonzini
     * 5) If the path component begins with a slash character ("/"), then
1809 ca0defb9 Paolo Bonzini
     *    the reference is an absolute-path and we skip to step 7.
1810 ca0defb9 Paolo Bonzini
     */
1811 ca0defb9 Paolo Bonzini
    if ((ref->path != NULL) && (ref->path[0] == '/')) {
1812 ca0defb9 Paolo Bonzini
        res->path = g_strdup(ref->path);
1813 ca0defb9 Paolo Bonzini
        goto step_7;
1814 ca0defb9 Paolo Bonzini
    }
1815 ca0defb9 Paolo Bonzini
1816 ca0defb9 Paolo Bonzini
1817 ca0defb9 Paolo Bonzini
    /*
1818 ca0defb9 Paolo Bonzini
     * 6) If this step is reached, then we are resolving a relative-path
1819 ca0defb9 Paolo Bonzini
     *    reference.  The relative path needs to be merged with the base
1820 ca0defb9 Paolo Bonzini
     *    URI's path.  Although there are many ways to do this, we will
1821 ca0defb9 Paolo Bonzini
     *    describe a simple method using a separate string buffer.
1822 ca0defb9 Paolo Bonzini
     *
1823 ca0defb9 Paolo Bonzini
     * Allocate a buffer large enough for the result string.
1824 ca0defb9 Paolo Bonzini
     */
1825 ca0defb9 Paolo Bonzini
    len = 2; /* extra / and 0 */
1826 ca0defb9 Paolo Bonzini
    if (ref->path != NULL)
1827 ca0defb9 Paolo Bonzini
        len += strlen(ref->path);
1828 ca0defb9 Paolo Bonzini
    if (bas->path != NULL)
1829 ca0defb9 Paolo Bonzini
        len += strlen(bas->path);
1830 ca0defb9 Paolo Bonzini
    res->path = g_malloc(len);
1831 ca0defb9 Paolo Bonzini
    res->path[0] = 0;
1832 ca0defb9 Paolo Bonzini
1833 ca0defb9 Paolo Bonzini
    /*
1834 ca0defb9 Paolo Bonzini
     * a) All but the last segment of the base URI's path component is
1835 ca0defb9 Paolo Bonzini
     *    copied to the buffer.  In other words, any characters after the
1836 ca0defb9 Paolo Bonzini
     *    last (right-most) slash character, if any, are excluded.
1837 ca0defb9 Paolo Bonzini
     */
1838 ca0defb9 Paolo Bonzini
    cur = 0;
1839 ca0defb9 Paolo Bonzini
    out = 0;
1840 ca0defb9 Paolo Bonzini
    if (bas->path != NULL) {
1841 ca0defb9 Paolo Bonzini
        while (bas->path[cur] != 0) {
1842 ca0defb9 Paolo Bonzini
            while ((bas->path[cur] != 0) && (bas->path[cur] != '/'))
1843 ca0defb9 Paolo Bonzini
                cur++;
1844 ca0defb9 Paolo Bonzini
            if (bas->path[cur] == 0)
1845 ca0defb9 Paolo Bonzini
                break;
1846 ca0defb9 Paolo Bonzini
1847 ca0defb9 Paolo Bonzini
            cur++;
1848 ca0defb9 Paolo Bonzini
            while (out < cur) {
1849 ca0defb9 Paolo Bonzini
                res->path[out] = bas->path[out];
1850 ca0defb9 Paolo Bonzini
                out++;
1851 ca0defb9 Paolo Bonzini
            }
1852 ca0defb9 Paolo Bonzini
        }
1853 ca0defb9 Paolo Bonzini
    }
1854 ca0defb9 Paolo Bonzini
    res->path[out] = 0;
1855 ca0defb9 Paolo Bonzini
1856 ca0defb9 Paolo Bonzini
    /*
1857 ca0defb9 Paolo Bonzini
     * b) The reference's path component is appended to the buffer
1858 ca0defb9 Paolo Bonzini
     *    string.
1859 ca0defb9 Paolo Bonzini
     */
1860 ca0defb9 Paolo Bonzini
    if (ref->path != NULL && ref->path[0] != 0) {
1861 ca0defb9 Paolo Bonzini
        indx = 0;
1862 ca0defb9 Paolo Bonzini
        /*
1863 ca0defb9 Paolo Bonzini
         * Ensure the path includes a '/'
1864 ca0defb9 Paolo Bonzini
         */
1865 ca0defb9 Paolo Bonzini
        if ((out == 0) && (bas->server != NULL))
1866 ca0defb9 Paolo Bonzini
            res->path[out++] = '/';
1867 ca0defb9 Paolo Bonzini
        while (ref->path[indx] != 0) {
1868 ca0defb9 Paolo Bonzini
            res->path[out++] = ref->path[indx++];
1869 ca0defb9 Paolo Bonzini
        }
1870 ca0defb9 Paolo Bonzini
    }
1871 ca0defb9 Paolo Bonzini
    res->path[out] = 0;
1872 ca0defb9 Paolo Bonzini
1873 ca0defb9 Paolo Bonzini
    /*
1874 ca0defb9 Paolo Bonzini
     * Steps c) to h) are really path normalization steps
1875 ca0defb9 Paolo Bonzini
     */
1876 ca0defb9 Paolo Bonzini
    normalize_uri_path(res->path);
1877 ca0defb9 Paolo Bonzini
1878 ca0defb9 Paolo Bonzini
step_7:
1879 ca0defb9 Paolo Bonzini
1880 ca0defb9 Paolo Bonzini
    /*
1881 ca0defb9 Paolo Bonzini
     * 7) The resulting URI components, including any inherited from the
1882 ca0defb9 Paolo Bonzini
     *    base URI, are recombined to give the absolute form of the URI
1883 ca0defb9 Paolo Bonzini
     *    reference.
1884 ca0defb9 Paolo Bonzini
     */
1885 ca0defb9 Paolo Bonzini
    val = uri_to_string(res);
1886 ca0defb9 Paolo Bonzini
1887 ca0defb9 Paolo Bonzini
done:
1888 ca0defb9 Paolo Bonzini
    if (ref != NULL)
1889 ca0defb9 Paolo Bonzini
        uri_free(ref);
1890 ca0defb9 Paolo Bonzini
    if (bas != NULL)
1891 ca0defb9 Paolo Bonzini
        uri_free(bas);
1892 ca0defb9 Paolo Bonzini
    if (res != NULL)
1893 ca0defb9 Paolo Bonzini
        uri_free(res);
1894 ca0defb9 Paolo Bonzini
    return(val);
1895 ca0defb9 Paolo Bonzini
}
1896 ca0defb9 Paolo Bonzini
1897 ca0defb9 Paolo Bonzini
/**
1898 ca0defb9 Paolo Bonzini
 * uri_resolve_relative:
1899 ca0defb9 Paolo Bonzini
 * @URI:  the URI reference under consideration
1900 ca0defb9 Paolo Bonzini
 * @base:  the base value
1901 ca0defb9 Paolo Bonzini
 *
1902 ca0defb9 Paolo Bonzini
 * Expresses the URI of the reference in terms relative to the
1903 ca0defb9 Paolo Bonzini
 * base.  Some examples of this operation include:
1904 ca0defb9 Paolo Bonzini
 *     base = "http://site1.com/docs/book1.html"
1905 ca0defb9 Paolo Bonzini
 *        URI input                        URI returned
1906 ca0defb9 Paolo Bonzini
 *     docs/pic1.gif                    pic1.gif
1907 ca0defb9 Paolo Bonzini
 *     docs/img/pic1.gif                img/pic1.gif
1908 ca0defb9 Paolo Bonzini
 *     img/pic1.gif                     ../img/pic1.gif
1909 ca0defb9 Paolo Bonzini
 *     http://site1.com/docs/pic1.gif   pic1.gif
1910 ca0defb9 Paolo Bonzini
 *     http://site2.com/docs/pic1.gif   http://site2.com/docs/pic1.gif
1911 ca0defb9 Paolo Bonzini
 *
1912 ca0defb9 Paolo Bonzini
 *     base = "docs/book1.html"
1913 ca0defb9 Paolo Bonzini
 *        URI input                        URI returned
1914 ca0defb9 Paolo Bonzini
 *     docs/pic1.gif                    pic1.gif
1915 ca0defb9 Paolo Bonzini
 *     docs/img/pic1.gif                img/pic1.gif
1916 ca0defb9 Paolo Bonzini
 *     img/pic1.gif                     ../img/pic1.gif
1917 ca0defb9 Paolo Bonzini
 *     http://site1.com/docs/pic1.gif   http://site1.com/docs/pic1.gif
1918 ca0defb9 Paolo Bonzini
 *
1919 ca0defb9 Paolo Bonzini
 *
1920 a93cf9df Stefan Weil
 * Note: if the URI reference is really weird or complicated, it may be
1921 ca0defb9 Paolo Bonzini
 *       worthwhile to first convert it into a "nice" one by calling
1922 ca0defb9 Paolo Bonzini
 *       uri_resolve (using 'base') before calling this routine,
1923 ca0defb9 Paolo Bonzini
 *       since this routine (for reasonable efficiency) assumes URI has
1924 ca0defb9 Paolo Bonzini
 *       already been through some validation.
1925 ca0defb9 Paolo Bonzini
 *
1926 ca0defb9 Paolo Bonzini
 * Returns a new URI string (to be freed by the caller) or NULL in case
1927 ca0defb9 Paolo Bonzini
 * error.
1928 ca0defb9 Paolo Bonzini
 */
1929 ca0defb9 Paolo Bonzini
char *
1930 ca0defb9 Paolo Bonzini
uri_resolve_relative (const char *uri, const char * base)
1931 ca0defb9 Paolo Bonzini
{
1932 ca0defb9 Paolo Bonzini
    char *val = NULL;
1933 ca0defb9 Paolo Bonzini
    int ret;
1934 ca0defb9 Paolo Bonzini
    int ix;
1935 ca0defb9 Paolo Bonzini
    int pos = 0;
1936 ca0defb9 Paolo Bonzini
    int nbslash = 0;
1937 ca0defb9 Paolo Bonzini
    int len;
1938 ca0defb9 Paolo Bonzini
    URI *ref = NULL;
1939 ca0defb9 Paolo Bonzini
    URI *bas = NULL;
1940 ca0defb9 Paolo Bonzini
    char *bptr, *uptr, *vptr;
1941 ca0defb9 Paolo Bonzini
    int remove_path = 0;
1942 ca0defb9 Paolo Bonzini
1943 ca0defb9 Paolo Bonzini
    if ((uri == NULL) || (*uri == 0))
1944 ca0defb9 Paolo Bonzini
        return NULL;
1945 ca0defb9 Paolo Bonzini
1946 ca0defb9 Paolo Bonzini
    /*
1947 ca0defb9 Paolo Bonzini
     * First parse URI into a standard form
1948 ca0defb9 Paolo Bonzini
     */
1949 ca0defb9 Paolo Bonzini
    ref = uri_new ();
1950 ca0defb9 Paolo Bonzini
    if (ref == NULL)
1951 ca0defb9 Paolo Bonzini
        return NULL;
1952 ca0defb9 Paolo Bonzini
    /* If URI not already in "relative" form */
1953 ca0defb9 Paolo Bonzini
    if (uri[0] != '.') {
1954 ca0defb9 Paolo Bonzini
        ret = uri_parse_into (ref, uri);
1955 ca0defb9 Paolo Bonzini
        if (ret != 0)
1956 ca0defb9 Paolo Bonzini
            goto done;                /* Error in URI, return NULL */
1957 ca0defb9 Paolo Bonzini
    } else
1958 ca0defb9 Paolo Bonzini
        ref->path = g_strdup(uri);
1959 ca0defb9 Paolo Bonzini
1960 ca0defb9 Paolo Bonzini
    /*
1961 ca0defb9 Paolo Bonzini
     * Next parse base into the same standard form
1962 ca0defb9 Paolo Bonzini
     */
1963 ca0defb9 Paolo Bonzini
    if ((base == NULL) || (*base == 0)) {
1964 ca0defb9 Paolo Bonzini
        val = g_strdup (uri);
1965 ca0defb9 Paolo Bonzini
        goto done;
1966 ca0defb9 Paolo Bonzini
    }
1967 ca0defb9 Paolo Bonzini
    bas = uri_new ();
1968 ca0defb9 Paolo Bonzini
    if (bas == NULL)
1969 ca0defb9 Paolo Bonzini
        goto done;
1970 ca0defb9 Paolo Bonzini
    if (base[0] != '.') {
1971 ca0defb9 Paolo Bonzini
        ret = uri_parse_into (bas, base);
1972 ca0defb9 Paolo Bonzini
        if (ret != 0)
1973 ca0defb9 Paolo Bonzini
            goto done;                /* Error in base, return NULL */
1974 ca0defb9 Paolo Bonzini
    } else
1975 ca0defb9 Paolo Bonzini
        bas->path = g_strdup(base);
1976 ca0defb9 Paolo Bonzini
1977 ca0defb9 Paolo Bonzini
    /*
1978 ca0defb9 Paolo Bonzini
     * If the scheme / server on the URI differs from the base,
1979 ca0defb9 Paolo Bonzini
     * just return the URI
1980 ca0defb9 Paolo Bonzini
     */
1981 ca0defb9 Paolo Bonzini
    if ((ref->scheme != NULL) &&
1982 ca0defb9 Paolo Bonzini
        ((bas->scheme == NULL) ||
1983 ca0defb9 Paolo Bonzini
         (strcmp (bas->scheme, ref->scheme)) ||
1984 ca0defb9 Paolo Bonzini
         (strcmp (bas->server, ref->server)))) {
1985 ca0defb9 Paolo Bonzini
        val = g_strdup (uri);
1986 ca0defb9 Paolo Bonzini
        goto done;
1987 ca0defb9 Paolo Bonzini
    }
1988 ca0defb9 Paolo Bonzini
    if (!strcmp(bas->path, ref->path)) {
1989 ca0defb9 Paolo Bonzini
        val = g_strdup("");
1990 ca0defb9 Paolo Bonzini
        goto done;
1991 ca0defb9 Paolo Bonzini
    }
1992 ca0defb9 Paolo Bonzini
    if (bas->path == NULL) {
1993 ca0defb9 Paolo Bonzini
        val = g_strdup(ref->path);
1994 ca0defb9 Paolo Bonzini
        goto done;
1995 ca0defb9 Paolo Bonzini
    }
1996 ca0defb9 Paolo Bonzini
    if (ref->path == NULL) {
1997 ca0defb9 Paolo Bonzini
        ref->path = (char *) "/";
1998 ca0defb9 Paolo Bonzini
        remove_path = 1;
1999 ca0defb9 Paolo Bonzini
    }
2000 ca0defb9 Paolo Bonzini
2001 ca0defb9 Paolo Bonzini
    /*
2002 ca0defb9 Paolo Bonzini
     * At this point (at last!) we can compare the two paths
2003 ca0defb9 Paolo Bonzini
     *
2004 ca0defb9 Paolo Bonzini
     * First we take care of the special case where either of the
2005 ca0defb9 Paolo Bonzini
     * two path components may be missing (bug 316224)
2006 ca0defb9 Paolo Bonzini
     */
2007 ca0defb9 Paolo Bonzini
    if (bas->path == NULL) {
2008 ca0defb9 Paolo Bonzini
        if (ref->path != NULL) {
2009 ca0defb9 Paolo Bonzini
            uptr = ref->path;
2010 ca0defb9 Paolo Bonzini
            if (*uptr == '/')
2011 ca0defb9 Paolo Bonzini
                uptr++;
2012 ca0defb9 Paolo Bonzini
            /* exception characters from uri_to_string */
2013 ca0defb9 Paolo Bonzini
            val = uri_string_escape(uptr, "/;&=+$,");
2014 ca0defb9 Paolo Bonzini
        }
2015 ca0defb9 Paolo Bonzini
        goto done;
2016 ca0defb9 Paolo Bonzini
    }
2017 ca0defb9 Paolo Bonzini
    bptr = bas->path;
2018 ca0defb9 Paolo Bonzini
    if (ref->path == NULL) {
2019 ca0defb9 Paolo Bonzini
        for (ix = 0; bptr[ix] != 0; ix++) {
2020 ca0defb9 Paolo Bonzini
            if (bptr[ix] == '/')
2021 ca0defb9 Paolo Bonzini
                nbslash++;
2022 ca0defb9 Paolo Bonzini
        }
2023 ca0defb9 Paolo Bonzini
        uptr = NULL;
2024 ca0defb9 Paolo Bonzini
        len = 1;        /* this is for a string terminator only */
2025 ca0defb9 Paolo Bonzini
    } else {
2026 ca0defb9 Paolo Bonzini
    /*
2027 ca0defb9 Paolo Bonzini
     * Next we compare the two strings and find where they first differ
2028 ca0defb9 Paolo Bonzini
     */
2029 ca0defb9 Paolo Bonzini
        if ((ref->path[pos] == '.') && (ref->path[pos+1] == '/'))
2030 ca0defb9 Paolo Bonzini
            pos += 2;
2031 ca0defb9 Paolo Bonzini
        if ((*bptr == '.') && (bptr[1] == '/'))
2032 ca0defb9 Paolo Bonzini
            bptr += 2;
2033 ca0defb9 Paolo Bonzini
        else if ((*bptr == '/') && (ref->path[pos] != '/'))
2034 ca0defb9 Paolo Bonzini
            bptr++;
2035 ca0defb9 Paolo Bonzini
        while ((bptr[pos] == ref->path[pos]) && (bptr[pos] != 0))
2036 ca0defb9 Paolo Bonzini
            pos++;
2037 ca0defb9 Paolo Bonzini
2038 ca0defb9 Paolo Bonzini
        if (bptr[pos] == ref->path[pos]) {
2039 ca0defb9 Paolo Bonzini
            val = g_strdup("");
2040 ca0defb9 Paolo Bonzini
            goto done;                /* (I can't imagine why anyone would do this) */
2041 ca0defb9 Paolo Bonzini
        }
2042 ca0defb9 Paolo Bonzini
2043 ca0defb9 Paolo Bonzini
        /*
2044 ca0defb9 Paolo Bonzini
         * In URI, "back up" to the last '/' encountered.  This will be the
2045 ca0defb9 Paolo Bonzini
         * beginning of the "unique" suffix of URI
2046 ca0defb9 Paolo Bonzini
         */
2047 ca0defb9 Paolo Bonzini
        ix = pos;
2048 ca0defb9 Paolo Bonzini
        if ((ref->path[ix] == '/') && (ix > 0))
2049 ca0defb9 Paolo Bonzini
            ix--;
2050 ca0defb9 Paolo Bonzini
        else if ((ref->path[ix] == 0) && (ix > 1) && (ref->path[ix - 1] == '/'))
2051 ca0defb9 Paolo Bonzini
            ix -= 2;
2052 ca0defb9 Paolo Bonzini
        for (; ix > 0; ix--) {
2053 ca0defb9 Paolo Bonzini
            if (ref->path[ix] == '/')
2054 ca0defb9 Paolo Bonzini
                break;
2055 ca0defb9 Paolo Bonzini
        }
2056 ca0defb9 Paolo Bonzini
        if (ix == 0) {
2057 ca0defb9 Paolo Bonzini
            uptr = ref->path;
2058 ca0defb9 Paolo Bonzini
        } else {
2059 ca0defb9 Paolo Bonzini
            ix++;
2060 ca0defb9 Paolo Bonzini
            uptr = &ref->path[ix];
2061 ca0defb9 Paolo Bonzini
        }
2062 ca0defb9 Paolo Bonzini
2063 ca0defb9 Paolo Bonzini
        /*
2064 ca0defb9 Paolo Bonzini
         * In base, count the number of '/' from the differing point
2065 ca0defb9 Paolo Bonzini
         */
2066 ca0defb9 Paolo Bonzini
        if (bptr[pos] != ref->path[pos]) {/* check for trivial URI == base */
2067 ca0defb9 Paolo Bonzini
            for (; bptr[ix] != 0; ix++) {
2068 ca0defb9 Paolo Bonzini
                if (bptr[ix] == '/')
2069 ca0defb9 Paolo Bonzini
                    nbslash++;
2070 ca0defb9 Paolo Bonzini
            }
2071 ca0defb9 Paolo Bonzini
        }
2072 ca0defb9 Paolo Bonzini
        len = strlen (uptr) + 1;
2073 ca0defb9 Paolo Bonzini
    }
2074 ca0defb9 Paolo Bonzini
2075 ca0defb9 Paolo Bonzini
    if (nbslash == 0) {
2076 ca0defb9 Paolo Bonzini
        if (uptr != NULL)
2077 ca0defb9 Paolo Bonzini
            /* exception characters from uri_to_string */
2078 ca0defb9 Paolo Bonzini
            val = uri_string_escape(uptr, "/;&=+$,");
2079 ca0defb9 Paolo Bonzini
        goto done;
2080 ca0defb9 Paolo Bonzini
    }
2081 ca0defb9 Paolo Bonzini
2082 ca0defb9 Paolo Bonzini
    /*
2083 ca0defb9 Paolo Bonzini
     * Allocate just enough space for the returned string -
2084 ca0defb9 Paolo Bonzini
     * length of the remainder of the URI, plus enough space
2085 ca0defb9 Paolo Bonzini
     * for the "../" groups, plus one for the terminator
2086 ca0defb9 Paolo Bonzini
     */
2087 ca0defb9 Paolo Bonzini
    val = g_malloc (len + 3 * nbslash);
2088 ca0defb9 Paolo Bonzini
    vptr = val;
2089 ca0defb9 Paolo Bonzini
    /*
2090 ca0defb9 Paolo Bonzini
     * Put in as many "../" as needed
2091 ca0defb9 Paolo Bonzini
     */
2092 ca0defb9 Paolo Bonzini
    for (; nbslash>0; nbslash--) {
2093 ca0defb9 Paolo Bonzini
        *vptr++ = '.';
2094 ca0defb9 Paolo Bonzini
        *vptr++ = '.';
2095 ca0defb9 Paolo Bonzini
        *vptr++ = '/';
2096 ca0defb9 Paolo Bonzini
    }
2097 ca0defb9 Paolo Bonzini
    /*
2098 ca0defb9 Paolo Bonzini
     * Finish up with the end of the URI
2099 ca0defb9 Paolo Bonzini
     */
2100 ca0defb9 Paolo Bonzini
    if (uptr != NULL) {
2101 ca0defb9 Paolo Bonzini
        if ((vptr > val) && (len > 0) &&
2102 ca0defb9 Paolo Bonzini
            (uptr[0] == '/') && (vptr[-1] == '/')) {
2103 ca0defb9 Paolo Bonzini
            memcpy (vptr, uptr + 1, len - 1);
2104 ca0defb9 Paolo Bonzini
            vptr[len - 2] = 0;
2105 ca0defb9 Paolo Bonzini
        } else {
2106 ca0defb9 Paolo Bonzini
            memcpy (vptr, uptr, len);
2107 ca0defb9 Paolo Bonzini
            vptr[len - 1] = 0;
2108 ca0defb9 Paolo Bonzini
        }
2109 ca0defb9 Paolo Bonzini
    } else {
2110 ca0defb9 Paolo Bonzini
        vptr[len - 1] = 0;
2111 ca0defb9 Paolo Bonzini
    }
2112 ca0defb9 Paolo Bonzini
2113 ca0defb9 Paolo Bonzini
    /* escape the freshly-built path */
2114 ca0defb9 Paolo Bonzini
    vptr = val;
2115 ca0defb9 Paolo Bonzini
        /* exception characters from uri_to_string */
2116 ca0defb9 Paolo Bonzini
    val = uri_string_escape(vptr, "/;&=+$,");
2117 ca0defb9 Paolo Bonzini
    g_free(vptr);
2118 ca0defb9 Paolo Bonzini
2119 ca0defb9 Paolo Bonzini
done:
2120 ca0defb9 Paolo Bonzini
    /*
2121 ca0defb9 Paolo Bonzini
     * Free the working variables
2122 ca0defb9 Paolo Bonzini
     */
2123 ca0defb9 Paolo Bonzini
    if (remove_path != 0)
2124 ca0defb9 Paolo Bonzini
        ref->path = NULL;
2125 ca0defb9 Paolo Bonzini
    if (ref != NULL)
2126 ca0defb9 Paolo Bonzini
        uri_free (ref);
2127 ca0defb9 Paolo Bonzini
    if (bas != NULL)
2128 ca0defb9 Paolo Bonzini
        uri_free (bas);
2129 ca0defb9 Paolo Bonzini
2130 ca0defb9 Paolo Bonzini
    return val;
2131 ca0defb9 Paolo Bonzini
}
2132 ca0defb9 Paolo Bonzini
2133 ca0defb9 Paolo Bonzini
/*
2134 ca0defb9 Paolo Bonzini
 * Utility functions to help parse and assemble query strings.
2135 ca0defb9 Paolo Bonzini
 */
2136 ca0defb9 Paolo Bonzini
2137 ca0defb9 Paolo Bonzini
struct QueryParams *
2138 ca0defb9 Paolo Bonzini
query_params_new (int init_alloc)
2139 ca0defb9 Paolo Bonzini
{
2140 ca0defb9 Paolo Bonzini
    struct QueryParams *ps;
2141 ca0defb9 Paolo Bonzini
2142 ca0defb9 Paolo Bonzini
    if (init_alloc <= 0) init_alloc = 1;
2143 ca0defb9 Paolo Bonzini
2144 ca0defb9 Paolo Bonzini
    ps = g_new(QueryParams, 1);
2145 ca0defb9 Paolo Bonzini
    ps->n = 0;
2146 ca0defb9 Paolo Bonzini
    ps->alloc = init_alloc;
2147 ca0defb9 Paolo Bonzini
    ps->p = g_new(QueryParam, ps->alloc);
2148 ca0defb9 Paolo Bonzini
2149 ca0defb9 Paolo Bonzini
    return ps;
2150 ca0defb9 Paolo Bonzini
}
2151 ca0defb9 Paolo Bonzini
2152 ca0defb9 Paolo Bonzini
/* Ensure there is space to store at least one more parameter
2153 ca0defb9 Paolo Bonzini
 * at the end of the set.
2154 ca0defb9 Paolo Bonzini
 */
2155 ca0defb9 Paolo Bonzini
static int
2156 ca0defb9 Paolo Bonzini
query_params_append (struct QueryParams *ps,
2157 ca0defb9 Paolo Bonzini
               const char *name, const char *value)
2158 ca0defb9 Paolo Bonzini
{
2159 ca0defb9 Paolo Bonzini
    if (ps->n >= ps->alloc) {
2160 ca0defb9 Paolo Bonzini
        ps->p = g_renew(QueryParam, ps->p, ps->alloc * 2);
2161 ca0defb9 Paolo Bonzini
        ps->alloc *= 2;
2162 ca0defb9 Paolo Bonzini
    }
2163 ca0defb9 Paolo Bonzini
2164 ca0defb9 Paolo Bonzini
    ps->p[ps->n].name = g_strdup(name);
2165 7f303adc Dong Xu Wang
    ps->p[ps->n].value = g_strdup(value);
2166 ca0defb9 Paolo Bonzini
    ps->p[ps->n].ignore = 0;
2167 ca0defb9 Paolo Bonzini
    ps->n++;
2168 ca0defb9 Paolo Bonzini
2169 ca0defb9 Paolo Bonzini
    return 0;
2170 ca0defb9 Paolo Bonzini
}
2171 ca0defb9 Paolo Bonzini
2172 ca0defb9 Paolo Bonzini
void
2173 ca0defb9 Paolo Bonzini
query_params_free (struct QueryParams *ps)
2174 ca0defb9 Paolo Bonzini
{
2175 ca0defb9 Paolo Bonzini
    int i;
2176 ca0defb9 Paolo Bonzini
2177 ca0defb9 Paolo Bonzini
    for (i = 0; i < ps->n; ++i) {
2178 ca0defb9 Paolo Bonzini
        g_free (ps->p[i].name);
2179 ca0defb9 Paolo Bonzini
        g_free (ps->p[i].value);
2180 ca0defb9 Paolo Bonzini
    }
2181 ca0defb9 Paolo Bonzini
    g_free (ps->p);
2182 ca0defb9 Paolo Bonzini
    g_free (ps);
2183 ca0defb9 Paolo Bonzini
}
2184 ca0defb9 Paolo Bonzini
2185 ca0defb9 Paolo Bonzini
struct QueryParams *
2186 ca0defb9 Paolo Bonzini
query_params_parse (const char *query)
2187 ca0defb9 Paolo Bonzini
{
2188 ca0defb9 Paolo Bonzini
    struct QueryParams *ps;
2189 ca0defb9 Paolo Bonzini
    const char *end, *eq;
2190 ca0defb9 Paolo Bonzini
2191 ca0defb9 Paolo Bonzini
    ps = query_params_new (0);
2192 ca0defb9 Paolo Bonzini
    if (!query || query[0] == '\0') return ps;
2193 ca0defb9 Paolo Bonzini
2194 ca0defb9 Paolo Bonzini
    while (*query) {
2195 ca0defb9 Paolo Bonzini
        char *name = NULL, *value = NULL;
2196 ca0defb9 Paolo Bonzini
2197 ca0defb9 Paolo Bonzini
        /* Find the next separator, or end of the string. */
2198 ca0defb9 Paolo Bonzini
        end = strchr (query, '&');
2199 ca0defb9 Paolo Bonzini
        if (!end)
2200 ca0defb9 Paolo Bonzini
            end = strchr (query, ';');
2201 ca0defb9 Paolo Bonzini
        if (!end)
2202 ca0defb9 Paolo Bonzini
            end = query + strlen (query);
2203 ca0defb9 Paolo Bonzini
2204 ca0defb9 Paolo Bonzini
        /* Find the first '=' character between here and end. */
2205 ca0defb9 Paolo Bonzini
        eq = strchr (query, '=');
2206 ca0defb9 Paolo Bonzini
        if (eq && eq >= end) eq = NULL;
2207 ca0defb9 Paolo Bonzini
2208 ca0defb9 Paolo Bonzini
        /* Empty section (eg. "&&"). */
2209 ca0defb9 Paolo Bonzini
        if (end == query)
2210 ca0defb9 Paolo Bonzini
            goto next;
2211 ca0defb9 Paolo Bonzini
2212 ca0defb9 Paolo Bonzini
        /* If there is no '=' character, then we have just "name"
2213 ca0defb9 Paolo Bonzini
         * and consistent with CGI.pm we assume value is "".
2214 ca0defb9 Paolo Bonzini
         */
2215 ca0defb9 Paolo Bonzini
        else if (!eq) {
2216 ca0defb9 Paolo Bonzini
            name = uri_string_unescape (query, end - query, NULL);
2217 ca0defb9 Paolo Bonzini
            value = NULL;
2218 ca0defb9 Paolo Bonzini
        }
2219 ca0defb9 Paolo Bonzini
        /* Or if we have "name=" here (works around annoying
2220 ca0defb9 Paolo Bonzini
         * problem when calling uri_string_unescape with len = 0).
2221 ca0defb9 Paolo Bonzini
         */
2222 ca0defb9 Paolo Bonzini
        else if (eq+1 == end) {
2223 ca0defb9 Paolo Bonzini
            name = uri_string_unescape (query, eq - query, NULL);
2224 ca0defb9 Paolo Bonzini
            value = g_new0(char, 1);
2225 ca0defb9 Paolo Bonzini
        }
2226 ca0defb9 Paolo Bonzini
        /* If the '=' character is at the beginning then we have
2227 ca0defb9 Paolo Bonzini
         * "=value" and consistent with CGI.pm we _ignore_ this.
2228 ca0defb9 Paolo Bonzini
         */
2229 ca0defb9 Paolo Bonzini
        else if (query == eq)
2230 ca0defb9 Paolo Bonzini
            goto next;
2231 ca0defb9 Paolo Bonzini
2232 ca0defb9 Paolo Bonzini
        /* Otherwise it's "name=value". */
2233 ca0defb9 Paolo Bonzini
        else {
2234 ca0defb9 Paolo Bonzini
            name = uri_string_unescape (query, eq - query, NULL);
2235 ca0defb9 Paolo Bonzini
            value = uri_string_unescape (eq+1, end - (eq+1), NULL);
2236 ca0defb9 Paolo Bonzini
        }
2237 ca0defb9 Paolo Bonzini
2238 ca0defb9 Paolo Bonzini
        /* Append to the parameter set. */
2239 ca0defb9 Paolo Bonzini
        query_params_append (ps, name, value);
2240 ca0defb9 Paolo Bonzini
        g_free(name);
2241 ca0defb9 Paolo Bonzini
        g_free(value);
2242 ca0defb9 Paolo Bonzini
2243 ca0defb9 Paolo Bonzini
    next:
2244 ca0defb9 Paolo Bonzini
        query = end;
2245 ca0defb9 Paolo Bonzini
        if (*query) query ++; /* skip '&' separator */
2246 ca0defb9 Paolo Bonzini
    }
2247 ca0defb9 Paolo Bonzini
2248 ca0defb9 Paolo Bonzini
    return ps;
2249 ca0defb9 Paolo Bonzini
}