1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26 /* $Id: uri.c 146 2006-03-24 00:26:54Z njacobs $ */
27
28 /*LINTLIBRARY*/
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <unistd.h>
33 #include <string.h>
34 #include <sys/types.h>
35 #include <errno.h>
36 #include "uri.h"
37
38 /*
39 * This will handle the following forms:
40 * scheme:scheme_data
41 * scheme://[[user[:password]@]host[:port]]/path[[#fragment]|[?query]]
42 */
43 int
uri_from_string(char * string,uri_t ** uri)44 uri_from_string(char *string, uri_t **uri)
45 {
46 char *ptr;
47 uri_t *u;
48
49 if ((string == NULL) || (uri == NULL)) {
50 errno = EINVAL;
51 return (-1);
52 }
53
54 /* find the scheme:scheme_part split */
55 if ((ptr = strchr(string, ':')) == NULL) {
56 errno = EINVAL;
57 return (-1);
58 }
59
60 if ((*uri = u = calloc(1, sizeof (*u))) == NULL)
61 return (-1);
62
63 u->scheme = strndup(string, ptr - string);
64
65 if ((ptr[1] == '/') && (ptr[2] == '/')) {
66 /*
67 * CSTYLED
68 * scheme://[host_part]/[path_part]
69 */
70 char *end = NULL, *user = NULL, *host = NULL, *path = NULL;
71
72 string = ptr + 3; /* skip the :// */
73
74 if ((path = end = strchr(string, '/')) == NULL)
75 for (end = string; *end != '\0'; end++)
76 continue;
77
78 u->host_part = strndup(string, end - string);
79
80 for (host = string; host < end; host ++)
81 if (*host == '@') {
82 /* string to host is the user part */
83 u->user_part = strndup(string, host-string);
84 /* host+1 to end is the host part */
85 u->host_part = strndup(host + 1,
86 end - (host+1));
87 user = string;
88 host++;
89 break;
90 }
91
92 if (user != NULL) {
93 char *password = NULL;
94
95 for (password = user; (password < host - 1); password++)
96 if (*password == ':') {
97 u->password = strndup(password + 1,
98 host - password - 2);
99 break;
100 }
101 u->user = strndup(user, password - user);
102 } else
103 host = string;
104
105 if (host != NULL) {
106 char *port = NULL;
107
108 for (port = host; (port < path); port++)
109 if ((*port == ':') || (*port == '/'))
110 break;
111
112 if (port < path) {
113 u->port = strndup(port + 1, path - port - 1);
114 }
115
116 u->host = strndup(host, port - host);
117 }
118
119 if (path != NULL) {
120 char *name = strrchr(path, '/');
121
122 u->path_part = strdup(path);
123
124 if (name != NULL) {
125 char *query, *fragment;
126
127 query = strrchr(name, '?');
128 if ((query != NULL) && (*query != '\0')) {
129 u->query = strdup(query + 1);
130 end = query;
131 } else {
132 for (end = path; *end != '\0'; end++)
133 continue;
134 }
135
136 fragment = strrchr(name, '#');
137 if ((fragment != NULL) && (*fragment != '\0')) {
138 u->fragment = strndup(fragment + 1,
139 end - fragment - 1);
140 end = fragment;
141 }
142
143 u->path = strndup(path, end - path);
144 }
145 }
146 } else { /* scheme:scheme_part */
147 u->scheme_part = strdup(&ptr[1]);
148 }
149
150 if ((u->host_part == NULL) && (u->path_part == NULL) &&
151 (u->scheme_part == NULL)) {
152 errno = EINVAL;
153 uri_free(u);
154 *uri = NULL;
155 return (-1);
156 }
157
158 return (0);
159 }
160
161 int
uri_to_string(uri_t * uri,char * buffer,size_t buflen)162 uri_to_string(uri_t *uri, char *buffer, size_t buflen)
163 {
164 char *uri_ppfix;
165
166 if ((uri == NULL) || (buffer == NULL) || (buflen == 0) ||
167 (uri->scheme == NULL) ||
168 ((uri->password != NULL) && (uri->user == NULL)) ||
169 ((uri->user != NULL) && (uri->host == NULL)) ||
170 ((uri->port != NULL) && (uri->host == NULL)) ||
171 ((uri->fragment != NULL) && (uri->path == NULL)) ||
172 ((uri->query != NULL) && (uri->path == NULL))) {
173 errno = EINVAL;
174 return (-1);
175 }
176 if (uri->path == NULL || uri->path[0] == '/')
177 uri_ppfix = "";
178 else
179 uri_ppfix = "/";
180
181 (void) memset(buffer, 0, buflen);
182
183 if (uri->scheme_part == NULL) {
184 (void) snprintf(buffer, buflen,
185 "%s://%s%s%s%s%s%s%s%s%s%s%s%s%s",
186 uri->scheme,
187 (uri->user ? uri->user : ""),
188 (uri->password ? ":" : ""),
189 (uri->password ? uri->password : ""),
190 (uri->user ? "@": ""),
191 (uri->host ? uri->host : ""),
192 (uri->port ? ":" : ""),
193 (uri->port ? uri->port : ""),
194 uri_ppfix,
195 (uri->path ? uri->path : ""),
196 (uri->fragment ? "#" : ""),
197 (uri->fragment ? uri->fragment : ""),
198 (uri->query ? "?" : ""),
199 (uri->query ? uri->query : ""));
200 } else {
201 (void) snprintf(buffer, buflen, "%s:%s", uri->scheme,
202 uri->scheme_part);
203 }
204
205 return (0);
206 }
207
208 void
uri_free(uri_t * uri)209 uri_free(uri_t *uri)
210 {
211 if (uri != NULL) {
212 if (uri->scheme != NULL)
213 free(uri->scheme);
214 if (uri->scheme_part != NULL)
215 free(uri->scheme_part);
216 if (uri->user != NULL)
217 free(uri->user);
218 if (uri->password != NULL)
219 free(uri->password);
220 if (uri->host != NULL)
221 free(uri->host);
222 if (uri->port != NULL)
223 free(uri->port);
224 if (uri->path != NULL)
225 free(uri->path);
226 if (uri->fragment != NULL)
227 free(uri->fragment);
228 if (uri->query != NULL)
229 free(uri->query);
230 /* help me debug */
231 if (uri->user_part != NULL)
232 free(uri->user_part);
233 if (uri->host_part != NULL)
234 free(uri->host_part);
235 if (uri->path_part != NULL)
236 free(uri->path_part);
237 free(uri);
238 }
239 }
240
241 #ifdef DEADBEEF
242 static void
uri_dump(FILE * fp,uri_t * uri)243 uri_dump(FILE *fp, uri_t *uri)
244 {
245 if (uri != NULL) {
246 fprintf(fp, "URI:\n");
247 if (uri->scheme != NULL)
248 fprintf(fp, "scheme: %s\n", uri->scheme);
249 if (uri->scheme_part != NULL)
250 fprintf(fp, "scheme_part: %s\n", uri->scheme_part);
251 if (uri->user != NULL)
252 fprintf(fp, "user: %s\n", uri->user);
253 if (uri->password != NULL)
254 fprintf(fp, "password: %s\n", uri->password);
255 if (uri->host != NULL)
256 fprintf(fp, "host: %s\n", uri->host);
257 if (uri->port != NULL)
258 fprintf(fp, "port: %s\n", uri->port);
259 if (uri->path != NULL)
260 fprintf(fp, "path: %s\n", uri->path);
261 if (uri->fragment != NULL)
262 fprintf(fp, "fragment: %s\n", uri->fragment);
263 if (uri->query != NULL)
264 fprintf(fp, "query: %s\n", uri->query);
265 /* help me debug */
266 if (uri->user_part != NULL)
267 fprintf(fp, "user_part: %s\n", uri->user_part);
268 if (uri->host_part != NULL)
269 fprintf(fp, "host_part: %s\n", uri->host_part);
270 if (uri->path_part != NULL)
271 fprintf(fp, "path_part: %s\n", uri->path_part);
272 fflush(fp);
273 }
274 }
275
276 int
main(int argc,char * argv[])277 main(int argc, char *argv[])
278 {
279 uri_t *u = NULL;
280
281 if (argc != 2) {
282 fprintf(stderr, "Usage: %s uri\n", argv[0]);
283 exit(1);
284 }
285
286 if (uri_from_string(argv[1], &u) == 0) {
287 char buf[BUFSIZ];
288
289 uri_dump(stdout, u);
290 uri_to_string(u, buf, sizeof (buf));
291 fprintf(stdout, "reconstituted: %s\n", buf);
292
293 uri_to_string(u, buf, 12);
294 fprintf(stdout, "reconstituted(12): %s\n", buf);
295 } else
296 printf(" failed for %s (%s)\n", argv[1], strerror(errno));
297
298 exit(0);
299 }
300 #endif /* DEADBEEF */
301