12264Sjacobs /*
22264Sjacobs  * CDDL HEADER START
32264Sjacobs  *
42264Sjacobs  * The contents of this file are subject to the terms of the
52264Sjacobs  * Common Development and Distribution License (the "License").
62264Sjacobs  * You may not use this file except in compliance with the License.
72264Sjacobs  *
82264Sjacobs  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
92264Sjacobs  * or http://www.opensolaris.org/os/licensing.
102264Sjacobs  * See the License for the specific language governing permissions
112264Sjacobs  * and limitations under the License.
122264Sjacobs  *
132264Sjacobs  * When distributing Covered Code, include this CDDL HEADER in each
142264Sjacobs  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
152264Sjacobs  * If applicable, add the following below this CDDL HEADER, with the
162264Sjacobs  * fields enclosed by brackets "[]" replaced with your own identifying
172264Sjacobs  * information: Portions Copyright [yyyy] [name of copyright owner]
182264Sjacobs  *
192264Sjacobs  * CDDL HEADER END
202264Sjacobs  */
212264Sjacobs 
222264Sjacobs /*
23*9411SKeerthi.Kondaka@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
242264Sjacobs  * Use is subject to license terms.
252264Sjacobs  *
262264Sjacobs  */
272264Sjacobs 
282264Sjacobs /* $Id: uri.c 146 2006-03-24 00:26:54Z njacobs $ */
292264Sjacobs 
302264Sjacobs /*LINTLIBRARY*/
312264Sjacobs 
322264Sjacobs #include <stdio.h>
332264Sjacobs #include <stdlib.h>
342264Sjacobs #include <unistd.h>
352264Sjacobs #include <string.h>
362264Sjacobs #include <sys/types.h>
372264Sjacobs #include <errno.h>
382264Sjacobs #include "uri.h"
392264Sjacobs 
402264Sjacobs static char *
412264Sjacobs strndup(char *string, size_t length)
422264Sjacobs {
432264Sjacobs 	char *result = NULL;
442264Sjacobs 
452264Sjacobs 	if (length > 0) {
462264Sjacobs 		length++;
472264Sjacobs 
482264Sjacobs 
492264Sjacobs 		if ((result = calloc(1, length)) != NULL)
502264Sjacobs 			(void) strlcat(result, string, length);
512264Sjacobs 	}
522264Sjacobs 
532264Sjacobs 	return (result);
542264Sjacobs }
552264Sjacobs 
562264Sjacobs 
572264Sjacobs /*
582264Sjacobs  * This will handle the following forms:
592264Sjacobs  *	scheme:scheme_data
602264Sjacobs  *	scheme://[[user[:password]@]host[:port]]/path[[#fragment]|[?query]]
612264Sjacobs  */
622264Sjacobs int
632264Sjacobs uri_from_string(char *string, uri_t **uri)
642264Sjacobs {
652264Sjacobs 	char *ptr;
662264Sjacobs 	uri_t *u;
672264Sjacobs 
682264Sjacobs 	if ((string == NULL) || (uri == NULL)) {
692264Sjacobs 		errno = EINVAL;
702264Sjacobs 		return (-1);
712264Sjacobs 	}
722264Sjacobs 
732264Sjacobs 	/* find the scheme:scheme_part split */
742264Sjacobs 	if ((ptr = strchr(string, ':')) == NULL) {
752264Sjacobs 		errno = EINVAL;
762264Sjacobs 		return (-1);
772264Sjacobs 	}
782264Sjacobs 
792264Sjacobs 	if ((*uri = u = calloc(1, sizeof (*u))) == NULL)
802264Sjacobs 		return (-1);
812264Sjacobs 
822264Sjacobs 	u->scheme = strndup(string, ptr - string);
832264Sjacobs 
842264Sjacobs 	if ((ptr[1] == '/') && (ptr[2] == '/')) {
852264Sjacobs 		/*
862264Sjacobs 		 * CSTYLED
872264Sjacobs 		 * scheme://[host_part]/[path_part]
882264Sjacobs 		 */
892264Sjacobs 		char *end = NULL, *user = NULL, *host = NULL, *path = NULL;
902264Sjacobs 
912264Sjacobs 		string = ptr + 3; /* skip the :// */
922264Sjacobs 
932264Sjacobs 		if ((path = end = strchr(string, '/')) == NULL)
942264Sjacobs 			for (end = string; *end != '\0'; end++);
952264Sjacobs 
962264Sjacobs 		u->host_part = strndup(string, end - string);
972264Sjacobs 
982264Sjacobs 		for (host = string; host < end; host ++)
992264Sjacobs 			if (*host == '@') {
1002264Sjacobs 				/* string to host is the user part */
1012264Sjacobs 				u->user_part = strndup(string, host-string);
1022264Sjacobs 				/* host+1 to end is the host part */
1032264Sjacobs 				u->host_part = strndup(host + 1,
1042264Sjacobs 							end - (host+1));
1052264Sjacobs 				user = string;
1062264Sjacobs 				host++;
1072264Sjacobs 				break;
1082264Sjacobs 			}
1092264Sjacobs 
1102264Sjacobs 		if (user != NULL) {
1112264Sjacobs 			char *password  = NULL;
1122264Sjacobs 
1132264Sjacobs 			for (password = user; (password < host - 1); password++)
1142264Sjacobs 				if (*password == ':') {
1152264Sjacobs 					u->password = strndup(password + 1,
1162264Sjacobs 							host - password - 2);
1172264Sjacobs 					break;
1182264Sjacobs 				}
1192264Sjacobs 			u->user = strndup(user, password - user);
1202264Sjacobs 		} else
1212264Sjacobs 			host = string;
1222264Sjacobs 
1232264Sjacobs 		if (host != NULL) {
1242264Sjacobs 			char *port  = NULL;
1252264Sjacobs 
1262264Sjacobs 			for (port = host; (port < path); port++)
1272264Sjacobs 				if ((*port == ':') || (*port == '/'))
1282264Sjacobs 					break;
1292264Sjacobs 
1302264Sjacobs 			if (port < path) {
1312264Sjacobs 				u->port = strndup(port + 1, path - port - 1);
1322264Sjacobs 			}
1332264Sjacobs 
1342264Sjacobs 			u->host = strndup(host, port - host);
1352264Sjacobs 		}
1362264Sjacobs 
1372264Sjacobs 		if (path != NULL) {
1382264Sjacobs 			char *name = strrchr(path, '/');
1392264Sjacobs 
1402264Sjacobs 			u->path_part = strdup(path);
1412264Sjacobs 
1422264Sjacobs 			if (name != NULL) {
1432264Sjacobs 				char *query, *fragment;
1442264Sjacobs 
1452264Sjacobs 				query = strrchr(name, '?');
1462264Sjacobs 				if ((query != NULL) && (*query != '\0')) {
1472264Sjacobs 					u->query = strdup(query + 1);
1482264Sjacobs 					end = query;
1492264Sjacobs 				} else
1502264Sjacobs 					for (end = path; *end != '\0'; end++);
1512264Sjacobs 
1522264Sjacobs 				fragment = strrchr(name, '#');
1532264Sjacobs 				if ((fragment != NULL) && (*fragment != '\0')) {
1542264Sjacobs 					u->fragment = strndup(fragment + 1,
1552264Sjacobs 							end - fragment - 1);
1562264Sjacobs 					end = fragment;
1572264Sjacobs 				}
1582264Sjacobs 
1592264Sjacobs 				u->path = strndup(path, end - path);
1602264Sjacobs 			}
1612264Sjacobs 		}
1622264Sjacobs 	} else {	/* scheme:scheme_part */
1632264Sjacobs 		u->scheme_part = strdup(&ptr[1]);
1642264Sjacobs 	}
1652264Sjacobs 
1667253Sjacobs 	if ((u->host_part == NULL) && (u->path_part == NULL) &&
1677253Sjacobs 	    (u->scheme_part == NULL)) {
1687253Sjacobs 		errno = EINVAL;
1697253Sjacobs 		uri_free(u);
1707253Sjacobs 		*uri = NULL;
1717253Sjacobs 		return (-1);
1727253Sjacobs 	}
1737253Sjacobs 
1742264Sjacobs 	return (0);
1752264Sjacobs }
1762264Sjacobs 
1772264Sjacobs int
1782264Sjacobs uri_to_string(uri_t *uri, char *buffer, size_t buflen)
1792264Sjacobs {
180*9411SKeerthi.Kondaka@Sun.COM 	char *uri_ppfix;
181*9411SKeerthi.Kondaka@Sun.COM 
1822264Sjacobs 	if ((uri == NULL) || (buffer == NULL) || (buflen == 0) ||
1832264Sjacobs 	    (uri->scheme == NULL) ||
1842264Sjacobs 	    ((uri->password != NULL) && (uri->user == NULL)) ||
1852264Sjacobs 	    ((uri->user != NULL) && (uri->host == NULL)) ||
1862264Sjacobs 	    ((uri->port != NULL) && (uri->host == NULL)) ||
1872264Sjacobs 	    ((uri->fragment != NULL) && (uri->path == NULL)) ||
1882264Sjacobs 	    ((uri->query != NULL) && (uri->path == NULL))) {
1892264Sjacobs 		errno = EINVAL;
1902264Sjacobs 		return (-1);
1912264Sjacobs 	}
192*9411SKeerthi.Kondaka@Sun.COM 	if (uri->path == NULL || uri->path[0] == '/')
193*9411SKeerthi.Kondaka@Sun.COM 		uri_ppfix = "";
194*9411SKeerthi.Kondaka@Sun.COM 	else
195*9411SKeerthi.Kondaka@Sun.COM 		uri_ppfix = "/";
1962264Sjacobs 
1972264Sjacobs 	(void) memset(buffer, 0, buflen);
1982264Sjacobs 
1992264Sjacobs 	if (uri->scheme_part == NULL) {
2002264Sjacobs 		(void) snprintf(buffer, buflen,
201*9411SKeerthi.Kondaka@Sun.COM 		    "%s://%s%s%s%s%s%s%s%s%s%s%s%s%s",
202*9411SKeerthi.Kondaka@Sun.COM 		    uri->scheme,
203*9411SKeerthi.Kondaka@Sun.COM 		    (uri->user ? uri->user : ""),
204*9411SKeerthi.Kondaka@Sun.COM 		    (uri->password ? ":" : ""),
205*9411SKeerthi.Kondaka@Sun.COM 		    (uri->password ? uri->password : ""),
206*9411SKeerthi.Kondaka@Sun.COM 		    (uri->user ? "@": ""),
207*9411SKeerthi.Kondaka@Sun.COM 		    (uri->host ? uri->host : ""),
208*9411SKeerthi.Kondaka@Sun.COM 		    (uri->port ? ":" : ""),
209*9411SKeerthi.Kondaka@Sun.COM 		    (uri->port ? uri->port : ""),
210*9411SKeerthi.Kondaka@Sun.COM 		    uri_ppfix,
211*9411SKeerthi.Kondaka@Sun.COM 		    (uri->path ? uri->path : ""),
212*9411SKeerthi.Kondaka@Sun.COM 		    (uri->fragment ? "#" : ""),
213*9411SKeerthi.Kondaka@Sun.COM 		    (uri->fragment ? uri->fragment : ""),
214*9411SKeerthi.Kondaka@Sun.COM 		    (uri->query ? "?" : ""),
215*9411SKeerthi.Kondaka@Sun.COM 		    (uri->query ? uri->query : ""));
2162264Sjacobs 	} else {
2172264Sjacobs 		(void) snprintf(buffer, buflen, "%s:%s", uri->scheme,
2182264Sjacobs 				uri->scheme_part);
2192264Sjacobs 	}
2202264Sjacobs 
2212264Sjacobs 	return (0);
2222264Sjacobs }
2232264Sjacobs 
2242264Sjacobs void
2252264Sjacobs uri_free(uri_t *uri)
2262264Sjacobs {
2272264Sjacobs 	if (uri != NULL) {
2282264Sjacobs 		if (uri->scheme != NULL)
2292264Sjacobs 			free(uri->scheme);
2302264Sjacobs 		if (uri->scheme_part != NULL)
2312264Sjacobs 			free(uri->scheme_part);
2322264Sjacobs 		if (uri->user != NULL)
2332264Sjacobs 			free(uri->user);
2342264Sjacobs 		if (uri->password != NULL)
2352264Sjacobs 			free(uri->password);
2362264Sjacobs 		if (uri->host != NULL)
2372264Sjacobs 			free(uri->host);
2382264Sjacobs 		if (uri->port != NULL)
2392264Sjacobs 			free(uri->port);
2402264Sjacobs 		if (uri->path != NULL)
2412264Sjacobs 			free(uri->path);
2422264Sjacobs 		if (uri->fragment != NULL)
2432264Sjacobs 			free(uri->fragment);
2442264Sjacobs 		if (uri->query != NULL)
2452264Sjacobs 			free(uri->query);
2462264Sjacobs 		/* help me debug */
2472264Sjacobs 		if (uri->user_part != NULL)
2482264Sjacobs 			free(uri->user_part);
2492264Sjacobs 		if (uri->host_part != NULL)
2502264Sjacobs 			free(uri->host_part);
2512264Sjacobs 		if (uri->path_part != NULL)
2522264Sjacobs 			free(uri->path_part);
2532264Sjacobs 		free(uri);
2542264Sjacobs 	}
2552264Sjacobs }
2562264Sjacobs 
2572264Sjacobs #ifdef DEADBEEF
2582264Sjacobs static void
2592264Sjacobs uri_dump(FILE *fp, uri_t *uri)
2602264Sjacobs {
2612264Sjacobs 	if (uri != NULL) {
2622264Sjacobs 		fprintf(fp, "URI:\n");
2632264Sjacobs 		if (uri->scheme != NULL)
2642264Sjacobs 			fprintf(fp, "scheme: %s\n", uri->scheme);
2652264Sjacobs 		if (uri->scheme_part != NULL)
2662264Sjacobs 			fprintf(fp, "scheme_part: %s\n", uri->scheme_part);
2672264Sjacobs 		if (uri->user != NULL)
2682264Sjacobs 			fprintf(fp, "user: %s\n", uri->user);
2692264Sjacobs 		if (uri->password != NULL)
2702264Sjacobs 			fprintf(fp, "password: %s\n", uri->password);
2712264Sjacobs 		if (uri->host != NULL)
2722264Sjacobs 			fprintf(fp, "host: %s\n", uri->host);
2732264Sjacobs 		if (uri->port != NULL)
2742264Sjacobs 			fprintf(fp, "port: %s\n", uri->port);
2752264Sjacobs 		if (uri->path != NULL)
2762264Sjacobs 			fprintf(fp, "path: %s\n", uri->path);
2772264Sjacobs 		if (uri->fragment != NULL)
2782264Sjacobs 			fprintf(fp, "fragment: %s\n", uri->fragment);
2792264Sjacobs 		if (uri->query != NULL)
2802264Sjacobs 			fprintf(fp, "query: %s\n", uri->query);
2812264Sjacobs 		/* help me debug */
2822264Sjacobs 		if (uri->user_part != NULL)
2832264Sjacobs 			fprintf(fp, "user_part: %s\n", uri->user_part);
2842264Sjacobs 		if (uri->host_part != NULL)
2852264Sjacobs 			fprintf(fp, "host_part: %s\n", uri->host_part);
2862264Sjacobs 		if (uri->path_part != NULL)
2872264Sjacobs 			fprintf(fp, "path_part: %s\n", uri->path_part);
2882264Sjacobs 		fflush(fp);
2892264Sjacobs 	}
2902264Sjacobs }
2912264Sjacobs 
2922264Sjacobs int
2932264Sjacobs main(int argc, char *argv[])
2942264Sjacobs {
2952264Sjacobs 	uri_t *u = NULL;
2962264Sjacobs 
2972264Sjacobs 	if (argc != 2) {
2982264Sjacobs 		fprintf(stderr, "Usage: %s uri\n", argv[0]);
2992264Sjacobs 		exit(1);
3002264Sjacobs 	}
3012264Sjacobs 
3022264Sjacobs 	if (uri_from_string(argv[1], &u) == 0) {
3032264Sjacobs 		char buf[BUFSIZ];
3042264Sjacobs 
3052264Sjacobs 		uri_dump(stdout, u);
3062264Sjacobs 		uri_to_string(u, buf, sizeof (buf));
3072264Sjacobs 		fprintf(stdout, "reconstituted: %s\n", buf);
3082264Sjacobs 
3092264Sjacobs 		uri_to_string(u, buf, 12);
3102264Sjacobs 		fprintf(stdout, "reconstituted(12): %s\n", buf);
3112264Sjacobs 	} else
3122264Sjacobs 		printf(" failed for %s  (%s)\n", argv[1], strerror(errno));
3132264Sjacobs 
3142264Sjacobs 	exit(0);
3152264Sjacobs }
3162264Sjacobs #endif /* DEADBEEF */
317