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