source: mainline/uspace/lib/uri/uri.c@ da4e695

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since da4e695 was d7b7f5e, checked in by Martin Sucha <sucha14@…>, 12 years ago

Add a basic HTTP download tool

  • Property mode set to 100644
File size: 6.1 KB
Line 
1/*
2 * Copyright (c) 2013 Martin Sucha
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup uri
30 * @{
31 */
32/**
33 * @file
34 */
35
36#include <assert.h>
37#include <stdlib.h>
38#include <str.h>
39#include <ctype.h>
40#include <errno.h>
41
42#include "uri.h"
43#include "ctype.h"
44
45static char *cut_str(const char *start, const char *end)
46{
47 size_t size = end - start;
48 return str_ndup(start, size);
49}
50
51uri_t *uri_parse(const char *str)
52{
53 uri_t *uri = malloc(sizeof(uri_t));
54 if (uri == NULL)
55 return NULL;
56 memset(uri, 0, sizeof(uri_t));
57
58 /* scheme ":" */
59 const char *scheme = str;
60 while (*str != 0 && *str != ':') str++;
61 if (*str == 0) {
62 uri_destroy(uri);
63 return NULL;
64 }
65 uri->scheme = cut_str(scheme, str);
66
67 /* skip the colon */
68 str++;
69
70 if (*str == '/' && str[1] == '/') {
71 /* "//" [user-info [":" user-credential] "@"] host [":" port] */
72 str++;
73 str++;
74 const char *authority_start = str;
75
76 char *host_or_user_info = NULL;
77 char *port_or_user_credential = NULL;
78
79 while (*str != 0 && *str != '?' && *str != '#' && *str != '@'
80 && *str != ':' && *str != '/')
81 str++;
82
83 host_or_user_info = cut_str(authority_start, str);
84 if (*str == ':') {
85 str++;
86 const char *second_part = str;
87 while (*str != 0 && *str != '?' && *str != '#' &&
88 *str != '@' && *str != '/') str++;
89 port_or_user_credential = cut_str(second_part, str);
90 }
91
92 if (*str == '@') {
93 uri->user_info = host_or_user_info;
94 uri->user_credential = port_or_user_credential;
95
96 str++;
97 const char *host_start = str;
98 while (*str != 0 && *str != '?' && *str != '#'
99 && *str != ':' && *str != '/') str++;
100 uri->host = cut_str(host_start, str);
101
102 if (*str == ':') {
103 str++;
104 const char *port_start = str;
105 while (*str != 0 && *str != '?' && *str != '#' && *str != '/')
106 str++;
107 uri->port = cut_str(port_start, str);
108 }
109 }
110 else {
111 uri->host = host_or_user_info;
112 uri->port = port_or_user_credential;
113 }
114 }
115
116 const char *path_start = str;
117 while (*str != 0 && *str != '?' && *str != '#') str++;
118 uri->path = cut_str(path_start, str);
119
120 if (*str == '?') {
121 str++;
122 const char *query_start = str;
123 while (*str != 0 && *str != '#') str++;
124 uri->query = cut_str(query_start, str);
125 }
126
127 if (*str == '#') {
128 str++;
129 const char *fragment_start = str;
130 while (*str != 0) str++;
131 uri->fragment = cut_str(fragment_start, str);
132 }
133
134 assert(*str == 0);
135 return uri;
136}
137
138/** Parse the URI scheme
139 *
140 * @param endptr The position of the first character after the scheme
141 * is stored there.
142 * @return EOK on success
143 */
144int uri_scheme_parse(const char *str, const char **endptr)
145{
146 if (*str == 0) {
147 *endptr = str;
148 return ELIMIT;
149 }
150
151 if (!isalpha(*str)) {
152 *endptr = str;
153 return EINVAL;
154 }
155
156 while (isalpha(*str) || isdigit(*str) ||
157 *str == '+' || *str == '-' || *str == '.') {
158 str++;
159 }
160
161 *endptr = str;
162 return EOK;
163}
164
165/** Determine if the URI scheme is valid
166 *
167 */
168bool uri_scheme_validate(const char *str)
169{
170 const char *endptr = NULL;
171 if (uri_scheme_parse(str, &endptr) != EOK)
172 return false;
173 return *endptr == 0;
174}
175
176int uri_percent_parse(const char *str, const char **endptr,
177 uint8_t *decoded)
178{
179 *endptr = str;
180 if (str[0] == 0 || str[1] == 0 || str[2] == 0)
181 return ELIMIT;
182
183 if (str[0] != '%' || !is_hexdig(str[1]) || !is_hexdig(str[2]))
184 return EINVAL;
185
186 if (decoded != NULL) {
187 int rc = str_uint8_t(str + 1, NULL, 16, true, decoded);
188 if (rc != EOK)
189 return rc;
190 }
191
192 *endptr = str + 3;
193 return EOK;
194}
195
196int uri_user_info_parse(const char *str, const char **endptr)
197{
198 while (*str != 0) {
199 while (is_unreserved(*str) || is_subdelim(*str) || *str == ':') str++;
200 if (*str == 0)
201 break;
202 int rc = uri_percent_parse(str, &str, NULL);
203 if (rc != EOK) {
204 *endptr = str;
205 return rc;
206 }
207 }
208
209 *endptr = str;
210 return EOK;
211}
212
213bool uri_user_info_validate(const char *str)
214{
215 const char *endptr = NULL;
216 if (uri_user_info_parse(str, &endptr) != EOK)
217 return false;
218 return *endptr == 0;
219}
220
221int uri_port_parse(const char *str, const char **endptr)
222{
223 if (*str == 0)
224 return ELIMIT;
225 if (!isdigit(*str))
226 return EINVAL;
227 while (isdigit(*str)) str++;
228 *endptr = str;
229 return EOK;
230}
231
232bool uri_port_validate(const char *str)
233{
234 const char *endptr = NULL;
235 if (uri_port_parse(str, &endptr) != EOK)
236 return false;
237 return *endptr == 0;
238}
239
240bool uri_validate(uri_t *uri)
241{
242 if (uri->scheme && !uri_scheme_validate(uri->scheme))
243 return false;
244
245 if (uri->user_info && !uri_user_info_validate(uri->user_info))
246 return false;
247
248 if (uri->user_credential && !uri_user_info_validate(uri->user_credential))
249 return false;
250
251 if (uri->port && !uri_port_validate(uri->port))
252 return false;
253
254 return true;
255}
256
257void uri_destroy(uri_t *uri)
258{
259 free(uri->scheme);
260 free(uri->user_info);
261 free(uri->user_credential);
262 free(uri->host);
263 free(uri->port);
264 free(uri->path);
265 free(uri->query);
266 free(uri->fragment);
267 free(uri);
268}
269
270/** @}
271 */
Note: See TracBrowser for help on using the repository browser.