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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since db51a6a6 was 582a0b8, checked in by Jakub Jermar <jakub@…>, 8 years ago

Remove unistd.h

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