1355b4669Sjacobs /*
2355b4669Sjacobs  * CDDL HEADER START
3355b4669Sjacobs  *
4355b4669Sjacobs  * The contents of this file are subject to the terms of the
5355b4669Sjacobs  * Common Development and Distribution License (the "License").
6355b4669Sjacobs  * You may not use this file except in compliance with the License.
7355b4669Sjacobs  *
8355b4669Sjacobs  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9355b4669Sjacobs  * or http://www.opensolaris.org/os/licensing.
10355b4669Sjacobs  * See the License for the specific language governing permissions
11355b4669Sjacobs  * and limitations under the License.
12355b4669Sjacobs  *
13355b4669Sjacobs  * When distributing Covered Code, include this CDDL HEADER in each
14355b4669Sjacobs  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15355b4669Sjacobs  * If applicable, add the following below this CDDL HEADER, with the
16355b4669Sjacobs  * fields enclosed by brackets "[]" replaced with your own identifying
17355b4669Sjacobs  * information: Portions Copyright [yyyy] [name of copyright owner]
18355b4669Sjacobs  *
19355b4669Sjacobs  * CDDL HEADER END
20355b4669Sjacobs  */
21355b4669Sjacobs 
22355b4669Sjacobs /*
23*23a1cceaSRoger A. Faulkner  * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
24355b4669Sjacobs  */
25355b4669Sjacobs 
26355b4669Sjacobs /* $Id: uri.c 146 2006-03-24 00:26:54Z njacobs $ */
27355b4669Sjacobs 
28355b4669Sjacobs /*LINTLIBRARY*/
29355b4669Sjacobs 
30355b4669Sjacobs #include <stdio.h>
31355b4669Sjacobs #include <stdlib.h>
32355b4669Sjacobs #include <unistd.h>
33355b4669Sjacobs #include <string.h>
34355b4669Sjacobs #include <sys/types.h>
35355b4669Sjacobs #include <errno.h>
36355b4669Sjacobs #include "uri.h"
37355b4669Sjacobs 
38355b4669Sjacobs /*
39355b4669Sjacobs  * This will handle the following forms:
40355b4669Sjacobs  *	scheme:scheme_data
41355b4669Sjacobs  *	scheme://[[user[:password]@]host[:port]]/path[[#fragment]|[?query]]
42355b4669Sjacobs  */
43355b4669Sjacobs int
uri_from_string(char * string,uri_t ** uri)44355b4669Sjacobs uri_from_string(char *string, uri_t **uri)
45355b4669Sjacobs {
46355b4669Sjacobs 	char *ptr;
47355b4669Sjacobs 	uri_t *u;
48355b4669Sjacobs 
49355b4669Sjacobs 	if ((string == NULL) || (uri == NULL)) {
50355b4669Sjacobs 		errno = EINVAL;
51355b4669Sjacobs 		return (-1);
52355b4669Sjacobs 	}
53355b4669Sjacobs 
54355b4669Sjacobs 	/* find the scheme:scheme_part split */
55355b4669Sjacobs 	if ((ptr = strchr(string, ':')) == NULL) {
56355b4669Sjacobs 		errno = EINVAL;
57355b4669Sjacobs 		return (-1);
58355b4669Sjacobs 	}
59355b4669Sjacobs 
60355b4669Sjacobs 	if ((*uri = u = calloc(1, sizeof (*u))) == NULL)
61355b4669Sjacobs 		return (-1);
62355b4669Sjacobs 
63355b4669Sjacobs 	u->scheme = strndup(string, ptr - string);
64355b4669Sjacobs 
65355b4669Sjacobs 	if ((ptr[1] == '/') && (ptr[2] == '/')) {
66355b4669Sjacobs 		/*
67355b4669Sjacobs 		 * CSTYLED
68355b4669Sjacobs 		 * scheme://[host_part]/[path_part]
69355b4669Sjacobs 		 */
70355b4669Sjacobs 		char *end = NULL, *user = NULL, *host = NULL, *path = NULL;
71355b4669Sjacobs 
72355b4669Sjacobs 		string = ptr + 3; /* skip the :// */
73355b4669Sjacobs 
74355b4669Sjacobs 		if ((path = end = strchr(string, '/')) == NULL)
75*23a1cceaSRoger A. Faulkner 			for (end = string; *end != '\0'; end++)
76*23a1cceaSRoger A. Faulkner 				continue;
77355b4669Sjacobs 
78355b4669Sjacobs 		u->host_part = strndup(string, end - string);
79355b4669Sjacobs 
80355b4669Sjacobs 		for (host = string; host < end; host ++)
81355b4669Sjacobs 			if (*host == '@') {
82355b4669Sjacobs 				/* string to host is the user part */
83355b4669Sjacobs 				u->user_part = strndup(string, host-string);
84355b4669Sjacobs 				/* host+1 to end is the host part */
85355b4669Sjacobs 				u->host_part = strndup(host + 1,
86*23a1cceaSRoger A. Faulkner 				    end - (host+1));
87355b4669Sjacobs 				user = string;
88355b4669Sjacobs 				host++;
89355b4669Sjacobs 				break;
90355b4669Sjacobs 			}
91355b4669Sjacobs 
92355b4669Sjacobs 		if (user != NULL) {
93355b4669Sjacobs 			char *password  = NULL;
94355b4669Sjacobs 
95355b4669Sjacobs 			for (password = user; (password < host - 1); password++)
96355b4669Sjacobs 				if (*password == ':') {
97355b4669Sjacobs 					u->password = strndup(password + 1,
98*23a1cceaSRoger A. Faulkner 					    host - password - 2);
99355b4669Sjacobs 					break;
100355b4669Sjacobs 				}
101355b4669Sjacobs 			u->user = strndup(user, password - user);
102355b4669Sjacobs 		} else
103355b4669Sjacobs 			host = string;
104355b4669Sjacobs 
105355b4669Sjacobs 		if (host != NULL) {
106355b4669Sjacobs 			char *port  = NULL;
107355b4669Sjacobs 
108355b4669Sjacobs 			for (port = host; (port < path); port++)
109355b4669Sjacobs 				if ((*port == ':') || (*port == '/'))
110355b4669Sjacobs 					break;
111355b4669Sjacobs 
112355b4669Sjacobs 			if (port < path) {
113355b4669Sjacobs 				u->port = strndup(port + 1, path - port - 1);
114355b4669Sjacobs 			}
115355b4669Sjacobs 
116355b4669Sjacobs 			u->host = strndup(host, port - host);
117355b4669Sjacobs 		}
118355b4669Sjacobs 
119355b4669Sjacobs 		if (path != NULL) {
120355b4669Sjacobs 			char *name = strrchr(path, '/');
121355b4669Sjacobs 
122355b4669Sjacobs 			u->path_part = strdup(path);
123355b4669Sjacobs 
124355b4669Sjacobs 			if (name != NULL) {
125355b4669Sjacobs 				char *query, *fragment;
126355b4669Sjacobs 
127355b4669Sjacobs 				query = strrchr(name, '?');
128355b4669Sjacobs 				if ((query != NULL) && (*query != '\0')) {
129355b4669Sjacobs 					u->query = strdup(query + 1);
130355b4669Sjacobs 					end = query;
131*23a1cceaSRoger A. Faulkner 				} else {
132*23a1cceaSRoger A. Faulkner 					for (end = path; *end != '\0'; end++)
133*23a1cceaSRoger A. Faulkner 						continue;
134*23a1cceaSRoger A. Faulkner 				}
135355b4669Sjacobs 
136355b4669Sjacobs 				fragment = strrchr(name, '#');
137355b4669Sjacobs 				if ((fragment != NULL) && (*fragment != '\0')) {
138355b4669Sjacobs 					u->fragment = strndup(fragment + 1,
139*23a1cceaSRoger A. Faulkner 					    end - fragment - 1);
140355b4669Sjacobs 					end = fragment;
141355b4669Sjacobs 				}
142355b4669Sjacobs 
143355b4669Sjacobs 				u->path = strndup(path, end - path);
144355b4669Sjacobs 			}
145355b4669Sjacobs 		}
146355b4669Sjacobs 	} else {	/* scheme:scheme_part */
147355b4669Sjacobs 		u->scheme_part = strdup(&ptr[1]);
148355b4669Sjacobs 	}
149355b4669Sjacobs 
150c1ecd8b9Sjacobs 	if ((u->host_part == NULL) && (u->path_part == NULL) &&
151c1ecd8b9Sjacobs 	    (u->scheme_part == NULL)) {
152c1ecd8b9Sjacobs 		errno = EINVAL;
153c1ecd8b9Sjacobs 		uri_free(u);
154c1ecd8b9Sjacobs 		*uri = NULL;
155c1ecd8b9Sjacobs 		return (-1);
156c1ecd8b9Sjacobs 	}
157c1ecd8b9Sjacobs 
158355b4669Sjacobs 	return (0);
159355b4669Sjacobs }
160355b4669Sjacobs 
161355b4669Sjacobs int
uri_to_string(uri_t * uri,char * buffer,size_t buflen)162355b4669Sjacobs uri_to_string(uri_t *uri, char *buffer, size_t buflen)
163355b4669Sjacobs {
164e059026eSKeerthi Kondaka 	char *uri_ppfix;
165e059026eSKeerthi Kondaka 
166355b4669Sjacobs 	if ((uri == NULL) || (buffer == NULL) || (buflen == 0) ||
167355b4669Sjacobs 	    (uri->scheme == NULL) ||
168355b4669Sjacobs 	    ((uri->password != NULL) && (uri->user == NULL)) ||
169355b4669Sjacobs 	    ((uri->user != NULL) && (uri->host == NULL)) ||
170355b4669Sjacobs 	    ((uri->port != NULL) && (uri->host == NULL)) ||
171355b4669Sjacobs 	    ((uri->fragment != NULL) && (uri->path == NULL)) ||
172355b4669Sjacobs 	    ((uri->query != NULL) && (uri->path == NULL))) {
173355b4669Sjacobs 		errno = EINVAL;
174355b4669Sjacobs 		return (-1);
175355b4669Sjacobs 	}
176e059026eSKeerthi Kondaka 	if (uri->path == NULL || uri->path[0] == '/')
177e059026eSKeerthi Kondaka 		uri_ppfix = "";
178e059026eSKeerthi Kondaka 	else
179e059026eSKeerthi Kondaka 		uri_ppfix = "/";
180355b4669Sjacobs 
181355b4669Sjacobs 	(void) memset(buffer, 0, buflen);
182355b4669Sjacobs 
183355b4669Sjacobs 	if (uri->scheme_part == NULL) {
184355b4669Sjacobs 		(void) snprintf(buffer, buflen,
185e059026eSKeerthi Kondaka 		    "%s://%s%s%s%s%s%s%s%s%s%s%s%s%s",
186e059026eSKeerthi Kondaka 		    uri->scheme,
187e059026eSKeerthi Kondaka 		    (uri->user ? uri->user : ""),
188e059026eSKeerthi Kondaka 		    (uri->password ? ":" : ""),
189e059026eSKeerthi Kondaka 		    (uri->password ? uri->password : ""),
190e059026eSKeerthi Kondaka 		    (uri->user ? "@": ""),
191e059026eSKeerthi Kondaka 		    (uri->host ? uri->host : ""),
192e059026eSKeerthi Kondaka 		    (uri->port ? ":" : ""),
193e059026eSKeerthi Kondaka 		    (uri->port ? uri->port : ""),
194e059026eSKeerthi Kondaka 		    uri_ppfix,
195e059026eSKeerthi Kondaka 		    (uri->path ? uri->path : ""),
196e059026eSKeerthi Kondaka 		    (uri->fragment ? "#" : ""),
197e059026eSKeerthi Kondaka 		    (uri->fragment ? uri->fragment : ""),
198e059026eSKeerthi Kondaka 		    (uri->query ? "?" : ""),
199e059026eSKeerthi Kondaka 		    (uri->query ? uri->query : ""));
200355b4669Sjacobs 	} else {
201355b4669Sjacobs 		(void) snprintf(buffer, buflen, "%s:%s", uri->scheme,
202*23a1cceaSRoger A. Faulkner 		    uri->scheme_part);
203355b4669Sjacobs 	}
204355b4669Sjacobs 
205355b4669Sjacobs 	return (0);
206355b4669Sjacobs }
207355b4669Sjacobs 
208355b4669Sjacobs void
uri_free(uri_t * uri)209355b4669Sjacobs uri_free(uri_t *uri)
210355b4669Sjacobs {
211355b4669Sjacobs 	if (uri != NULL) {
212355b4669Sjacobs 		if (uri->scheme != NULL)
213355b4669Sjacobs 			free(uri->scheme);
214355b4669Sjacobs 		if (uri->scheme_part != NULL)
215355b4669Sjacobs 			free(uri->scheme_part);
216355b4669Sjacobs 		if (uri->user != NULL)
217355b4669Sjacobs 			free(uri->user);
218355b4669Sjacobs 		if (uri->password != NULL)
219355b4669Sjacobs 			free(uri->password);
220355b4669Sjacobs 		if (uri->host != NULL)
221355b4669Sjacobs 			free(uri->host);
222355b4669Sjacobs 		if (uri->port != NULL)
223355b4669Sjacobs 			free(uri->port);
224355b4669Sjacobs 		if (uri->path != NULL)
225355b4669Sjacobs 			free(uri->path);
226355b4669Sjacobs 		if (uri->fragment != NULL)
227355b4669Sjacobs 			free(uri->fragment);
228355b4669Sjacobs 		if (uri->query != NULL)
229355b4669Sjacobs 			free(uri->query);
230355b4669Sjacobs 		/* help me debug */
231355b4669Sjacobs 		if (uri->user_part != NULL)
232355b4669Sjacobs 			free(uri->user_part);
233355b4669Sjacobs 		if (uri->host_part != NULL)
234355b4669Sjacobs 			free(uri->host_part);
235355b4669Sjacobs 		if (uri->path_part != NULL)
236355b4669Sjacobs 			free(uri->path_part);
237355b4669Sjacobs 		free(uri);
238355b4669Sjacobs 	}
239355b4669Sjacobs }
240355b4669Sjacobs 
241355b4669Sjacobs #ifdef DEADBEEF
242355b4669Sjacobs static void
uri_dump(FILE * fp,uri_t * uri)243355b4669Sjacobs uri_dump(FILE *fp, uri_t *uri)
244355b4669Sjacobs {
245355b4669Sjacobs 	if (uri != NULL) {
246355b4669Sjacobs 		fprintf(fp, "URI:\n");
247355b4669Sjacobs 		if (uri->scheme != NULL)
248355b4669Sjacobs 			fprintf(fp, "scheme: %s\n", uri->scheme);
249355b4669Sjacobs 		if (uri->scheme_part != NULL)
250355b4669Sjacobs 			fprintf(fp, "scheme_part: %s\n", uri->scheme_part);
251355b4669Sjacobs 		if (uri->user != NULL)
252355b4669Sjacobs 			fprintf(fp, "user: %s\n", uri->user);
253355b4669Sjacobs 		if (uri->password != NULL)
254355b4669Sjacobs 			fprintf(fp, "password: %s\n", uri->password);
255355b4669Sjacobs 		if (uri->host != NULL)
256355b4669Sjacobs 			fprintf(fp, "host: %s\n", uri->host);
257355b4669Sjacobs 		if (uri->port != NULL)
258355b4669Sjacobs 			fprintf(fp, "port: %s\n", uri->port);
259355b4669Sjacobs 		if (uri->path != NULL)
260355b4669Sjacobs 			fprintf(fp, "path: %s\n", uri->path);
261355b4669Sjacobs 		if (uri->fragment != NULL)
262355b4669Sjacobs 			fprintf(fp, "fragment: %s\n", uri->fragment);
263355b4669Sjacobs 		if (uri->query != NULL)
264355b4669Sjacobs 			fprintf(fp, "query: %s\n", uri->query);
265355b4669Sjacobs 		/* help me debug */
266355b4669Sjacobs 		if (uri->user_part != NULL)
267355b4669Sjacobs 			fprintf(fp, "user_part: %s\n", uri->user_part);
268355b4669Sjacobs 		if (uri->host_part != NULL)
269355b4669Sjacobs 			fprintf(fp, "host_part: %s\n", uri->host_part);
270355b4669Sjacobs 		if (uri->path_part != NULL)
271355b4669Sjacobs 			fprintf(fp, "path_part: %s\n", uri->path_part);
272355b4669Sjacobs 		fflush(fp);
273355b4669Sjacobs 	}
274355b4669Sjacobs }
275355b4669Sjacobs 
276355b4669Sjacobs int
main(int argc,char * argv[])277355b4669Sjacobs main(int argc, char *argv[])
278355b4669Sjacobs {
279355b4669Sjacobs 	uri_t *u = NULL;
280355b4669Sjacobs 
281355b4669Sjacobs 	if (argc != 2) {
282355b4669Sjacobs 		fprintf(stderr, "Usage: %s uri\n", argv[0]);
283355b4669Sjacobs 		exit(1);
284355b4669Sjacobs 	}
285355b4669Sjacobs 
286355b4669Sjacobs 	if (uri_from_string(argv[1], &u) == 0) {
287355b4669Sjacobs 		char buf[BUFSIZ];
288355b4669Sjacobs 
289355b4669Sjacobs 		uri_dump(stdout, u);
290355b4669Sjacobs 		uri_to_string(u, buf, sizeof (buf));
291355b4669Sjacobs 		fprintf(stdout, "reconstituted: %s\n", buf);
292355b4669Sjacobs 
293355b4669Sjacobs 		uri_to_string(u, buf, 12);
294355b4669Sjacobs 		fprintf(stdout, "reconstituted(12): %s\n", buf);
295355b4669Sjacobs 	} else
296355b4669Sjacobs 		printf(" failed for %s  (%s)\n", argv[1], strerror(errno));
297355b4669Sjacobs 
298355b4669Sjacobs 	exit(0);
299355b4669Sjacobs }
300355b4669Sjacobs #endif /* DEADBEEF */
301