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

Last change on this file was 3bacee1, checked in by Jiri Svoboda <jiri@…>, 7 years ago

Make ccheck-fix again and commit more good files.

  • Property mode set to 100644
File size: 6.2 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 <stddef.h>
39#include <str.h>
40#include <ctype.h>
41#include <errno.h>
42
43#include "uri.h"
44#include "internal/ctype.h"
45
46static char *cut_str(const char *start, const char *end)
47{
48 size_t size = end - start;
49 return str_ndup(start, size);
50}
51
52uri_t *uri_parse(const char *str)
53{
54 uri_t *uri = malloc(sizeof(uri_t));
55 if (uri == NULL)
56 return NULL;
57 memset(uri, 0, sizeof(uri_t));
58
59 /* scheme ":" */
60 const char *scheme = str;
61 while (*str != 0 && *str != ':')
62 str++;
63 if (*str == 0) {
64 uri_destroy(uri);
65 return NULL;
66 }
67 uri->scheme = cut_str(scheme, str);
68
69 /* skip the colon */
70 str++;
71
72 if (*str == '/' && str[1] == '/') {
73 /* "//" [user-info [":" user-credential] "@"] host [":" port] */
74 str++;
75 str++;
76 const char *authority_start = str;
77
78 char *host_or_user_info = NULL;
79 char *port_or_user_credential = NULL;
80
81 while (*str != 0 && *str != '?' && *str != '#' && *str != '@' &&
82 *str != ':' && *str != '/')
83 str++;
84
85 host_or_user_info = cut_str(authority_start, str);
86 if (*str == ':') {
87 str++;
88 const char *second_part = str;
89 while (*str != 0 && *str != '?' && *str != '#' &&
90 *str != '@' && *str != '/')
91 str++;
92 port_or_user_credential = cut_str(second_part, str);
93 }
94
95 if (*str == '@') {
96 uri->user_info = host_or_user_info;
97 uri->user_credential = port_or_user_credential;
98
99 str++;
100 const char *host_start = str;
101 while (*str != 0 && *str != '?' && *str != '#' &&
102 *str != ':' && *str != '/')
103 str++;
104 uri->host = cut_str(host_start, str);
105
106 if (*str == ':') {
107 str++;
108 const char *port_start = str;
109 while (*str != 0 && *str != '?' && *str != '#' && *str != '/')
110 str++;
111 uri->port = cut_str(port_start, str);
112 }
113 } else {
114 uri->host = host_or_user_info;
115 uri->port = port_or_user_credential;
116 }
117 }
118
119 const char *path_start = str;
120 while (*str != 0 && *str != '?' && *str != '#')
121 str++;
122 uri->path = cut_str(path_start, str);
123
124 if (*str == '?') {
125 str++;
126 const char *query_start = str;
127 while (*str != 0 && *str != '#')
128 str++;
129 uri->query = cut_str(query_start, str);
130 }
131
132 if (*str == '#') {
133 str++;
134 const char *fragment_start = str;
135 while (*str != 0)
136 str++;
137 uri->fragment = cut_str(fragment_start, str);
138 }
139
140 assert(*str == 0);
141 return uri;
142}
143
144/** Parse the URI scheme
145 *
146 * @param endptr The position of the first character after the scheme
147 * is stored there.
148 * @return EOK on success
149 */
150errno_t uri_scheme_parse(const char *str, const char **endptr)
151{
152 if (*str == 0) {
153 *endptr = str;
154 return ELIMIT;
155 }
156
157 if (!isalpha(*str)) {
158 *endptr = str;
159 return EINVAL;
160 }
161
162 while (isalpha(*str) || isdigit(*str) ||
163 *str == '+' || *str == '-' || *str == '.') {
164 str++;
165 }
166
167 *endptr = str;
168 return EOK;
169}
170
171/** Determine if the URI scheme is valid
172 *
173 */
174bool uri_scheme_validate(const char *str)
175{
176 const char *endptr = NULL;
177 if (uri_scheme_parse(str, &endptr) != EOK)
178 return false;
179 return *endptr == 0;
180}
181
182errno_t uri_percent_parse(const char *str, const char **endptr,
183 uint8_t *decoded)
184{
185 *endptr = str;
186 if (str[0] == 0 || str[1] == 0 || str[2] == 0)
187 return ELIMIT;
188
189 if (str[0] != '%' || !is_hexdig(str[1]) || !is_hexdig(str[2]))
190 return EINVAL;
191
192 if (decoded != NULL) {
193 errno_t rc = str_uint8_t(str + 1, NULL, 16, true, decoded);
194 if (rc != EOK)
195 return rc;
196 }
197
198 *endptr = str + 3;
199 return EOK;
200}
201
202errno_t uri_user_info_parse(const char *str, const char **endptr)
203{
204 while (*str != 0) {
205 while (is_unreserved(*str) || is_subdelim(*str) || *str == ':')
206 str++;
207 if (*str == 0)
208 break;
209 errno_t rc = uri_percent_parse(str, &str, NULL);
210 if (rc != EOK) {
211 *endptr = str;
212 return rc;
213 }
214 }
215
216 *endptr = str;
217 return EOK;
218}
219
220bool uri_user_info_validate(const char *str)
221{
222 const char *endptr = NULL;
223 if (uri_user_info_parse(str, &endptr) != EOK)
224 return false;
225 return *endptr == 0;
226}
227
228errno_t uri_port_parse(const char *str, const char **endptr)
229{
230 if (*str == 0)
231 return ELIMIT;
232 if (!isdigit(*str))
233 return EINVAL;
234 while (isdigit(*str))
235 str++;
236 *endptr = str;
237 return EOK;
238}
239
240bool uri_port_validate(const char *str)
241{
242 const char *endptr = NULL;
243 if (uri_port_parse(str, &endptr) != EOK)
244 return false;
245 return *endptr == 0;
246}
247
248bool uri_validate(uri_t *uri)
249{
250 if (uri->scheme && !uri_scheme_validate(uri->scheme))
251 return false;
252
253 if (uri->user_info && !uri_user_info_validate(uri->user_info))
254 return false;
255
256 if (uri->user_credential && !uri_user_info_validate(uri->user_credential))
257 return false;
258
259 if (uri->port && !uri_port_validate(uri->port))
260 return false;
261
262 return true;
263}
264
265void uri_destroy(uri_t *uri)
266{
267 free(uri->scheme);
268 free(uri->user_info);
269 free(uri->user_credential);
270 free(uri->host);
271 free(uri->port);
272 free(uri->path);
273 free(uri->query);
274 free(uri->fragment);
275 free(uri);
276}
277
278/** @}
279 */
Note: See TracBrowser for help on using the repository browser.