xref: /illumos-gate/usr/src/lib/print/libpapi-common/common/uri.c (revision 4eaa471005973e11a6110b69fe990530b3b95a38)
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 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  *
26  */
27 
28 /* $Id: uri.c 146 2006-03-24 00:26:54Z njacobs $ */
29 
30 /*LINTLIBRARY*/
31 
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <unistd.h>
35 #include <string.h>
36 #include <sys/types.h>
37 #include <errno.h>
38 #include "uri.h"
39 
40 static char *
41 strndup(char *string, size_t length)
42 {
43 	char *result = NULL;
44 
45 	if (length > 0) {
46 		length++;
47 
48 
49 		if ((result = calloc(1, length)) != NULL)
50 			(void) strlcat(result, string, length);
51 	}
52 
53 	return (result);
54 }
55 
56 
57 /*
58  * This will handle the following forms:
59  *	scheme:scheme_data
60  *	scheme://[[user[:password]@]host[:port]]/path[[#fragment]|[?query]]
61  */
62 int
63 uri_from_string(char *string, uri_t **uri)
64 {
65 	char *ptr;
66 	uri_t *u;
67 
68 	if ((string == NULL) || (uri == NULL)) {
69 		errno = EINVAL;
70 		return (-1);
71 	}
72 
73 	/* find the scheme:scheme_part split */
74 	if ((ptr = strchr(string, ':')) == NULL) {
75 		errno = EINVAL;
76 		return (-1);
77 	}
78 
79 	if ((*uri = u = calloc(1, sizeof (*u))) == NULL)
80 		return (-1);
81 
82 	u->scheme = strndup(string, ptr - string);
83 
84 	if ((ptr[1] == '/') && (ptr[2] == '/')) {
85 		/*
86 		 * CSTYLED
87 		 * scheme://[host_part]/[path_part]
88 		 */
89 		char *end = NULL, *user = NULL, *host = NULL, *path = NULL;
90 
91 		string = ptr + 3; /* skip the :// */
92 
93 		if ((path = end = strchr(string, '/')) == NULL)
94 			for (end = string; *end != '\0'; end++);
95 
96 		u->host_part = strndup(string, end - string);
97 
98 		for (host = string; host < end; host ++)
99 			if (*host == '@') {
100 				/* string to host is the user part */
101 				u->user_part = strndup(string, host-string);
102 				/* host+1 to end is the host part */
103 				u->host_part = strndup(host + 1,
104 							end - (host+1));
105 				user = string;
106 				host++;
107 				break;
108 			}
109 
110 		if (user != NULL) {
111 			char *password  = NULL;
112 
113 			for (password = user; (password < host - 1); password++)
114 				if (*password == ':') {
115 					u->password = strndup(password + 1,
116 							host - password - 2);
117 					break;
118 				}
119 			u->user = strndup(user, password - user);
120 		} else
121 			host = string;
122 
123 		if (host != NULL) {
124 			char *port  = NULL;
125 
126 			for (port = host; (port < path); port++)
127 				if ((*port == ':') || (*port == '/'))
128 					break;
129 
130 			if (port < path) {
131 				u->port = strndup(port + 1, path - port - 1);
132 			}
133 
134 			u->host = strndup(host, port - host);
135 		}
136 
137 		if (path != NULL) {
138 			char *name = strrchr(path, '/');
139 
140 			u->path_part = strdup(path);
141 
142 			if (name != NULL) {
143 				char *query, *fragment;
144 
145 				query = strrchr(name, '?');
146 				if ((query != NULL) && (*query != '\0')) {
147 					u->query = strdup(query + 1);
148 					end = query;
149 				} else
150 					for (end = path; *end != '\0'; end++);
151 
152 				fragment = strrchr(name, '#');
153 				if ((fragment != NULL) && (*fragment != '\0')) {
154 					u->fragment = strndup(fragment + 1,
155 							end - fragment - 1);
156 					end = fragment;
157 				}
158 
159 				u->path = strndup(path, end - path);
160 			}
161 		}
162 	} else {	/* scheme:scheme_part */
163 		u->scheme_part = strdup(&ptr[1]);
164 	}
165 
166 	if ((u->host_part == NULL) && (u->path_part == NULL) &&
167 	    (u->scheme_part == NULL)) {
168 		errno = EINVAL;
169 		uri_free(u);
170 		*uri = NULL;
171 		return (-1);
172 	}
173 
174 	return (0);
175 }
176 
177 int
178 uri_to_string(uri_t *uri, char *buffer, size_t buflen)
179 {
180 	char *uri_ppfix;
181 
182 	if ((uri == NULL) || (buffer == NULL) || (buflen == 0) ||
183 	    (uri->scheme == NULL) ||
184 	    ((uri->password != NULL) && (uri->user == NULL)) ||
185 	    ((uri->user != NULL) && (uri->host == NULL)) ||
186 	    ((uri->port != NULL) && (uri->host == NULL)) ||
187 	    ((uri->fragment != NULL) && (uri->path == NULL)) ||
188 	    ((uri->query != NULL) && (uri->path == NULL))) {
189 		errno = EINVAL;
190 		return (-1);
191 	}
192 	if (uri->path == NULL || uri->path[0] == '/')
193 		uri_ppfix = "";
194 	else
195 		uri_ppfix = "/";
196 
197 	(void) memset(buffer, 0, buflen);
198 
199 	if (uri->scheme_part == NULL) {
200 		(void) snprintf(buffer, buflen,
201 		    "%s://%s%s%s%s%s%s%s%s%s%s%s%s%s",
202 		    uri->scheme,
203 		    (uri->user ? uri->user : ""),
204 		    (uri->password ? ":" : ""),
205 		    (uri->password ? uri->password : ""),
206 		    (uri->user ? "@": ""),
207 		    (uri->host ? uri->host : ""),
208 		    (uri->port ? ":" : ""),
209 		    (uri->port ? uri->port : ""),
210 		    uri_ppfix,
211 		    (uri->path ? uri->path : ""),
212 		    (uri->fragment ? "#" : ""),
213 		    (uri->fragment ? uri->fragment : ""),
214 		    (uri->query ? "?" : ""),
215 		    (uri->query ? uri->query : ""));
216 	} else {
217 		(void) snprintf(buffer, buflen, "%s:%s", uri->scheme,
218 				uri->scheme_part);
219 	}
220 
221 	return (0);
222 }
223 
224 void
225 uri_free(uri_t *uri)
226 {
227 	if (uri != NULL) {
228 		if (uri->scheme != NULL)
229 			free(uri->scheme);
230 		if (uri->scheme_part != NULL)
231 			free(uri->scheme_part);
232 		if (uri->user != NULL)
233 			free(uri->user);
234 		if (uri->password != NULL)
235 			free(uri->password);
236 		if (uri->host != NULL)
237 			free(uri->host);
238 		if (uri->port != NULL)
239 			free(uri->port);
240 		if (uri->path != NULL)
241 			free(uri->path);
242 		if (uri->fragment != NULL)
243 			free(uri->fragment);
244 		if (uri->query != NULL)
245 			free(uri->query);
246 		/* help me debug */
247 		if (uri->user_part != NULL)
248 			free(uri->user_part);
249 		if (uri->host_part != NULL)
250 			free(uri->host_part);
251 		if (uri->path_part != NULL)
252 			free(uri->path_part);
253 		free(uri);
254 	}
255 }
256 
257 #ifdef DEADBEEF
258 static void
259 uri_dump(FILE *fp, uri_t *uri)
260 {
261 	if (uri != NULL) {
262 		fprintf(fp, "URI:\n");
263 		if (uri->scheme != NULL)
264 			fprintf(fp, "scheme: %s\n", uri->scheme);
265 		if (uri->scheme_part != NULL)
266 			fprintf(fp, "scheme_part: %s\n", uri->scheme_part);
267 		if (uri->user != NULL)
268 			fprintf(fp, "user: %s\n", uri->user);
269 		if (uri->password != NULL)
270 			fprintf(fp, "password: %s\n", uri->password);
271 		if (uri->host != NULL)
272 			fprintf(fp, "host: %s\n", uri->host);
273 		if (uri->port != NULL)
274 			fprintf(fp, "port: %s\n", uri->port);
275 		if (uri->path != NULL)
276 			fprintf(fp, "path: %s\n", uri->path);
277 		if (uri->fragment != NULL)
278 			fprintf(fp, "fragment: %s\n", uri->fragment);
279 		if (uri->query != NULL)
280 			fprintf(fp, "query: %s\n", uri->query);
281 		/* help me debug */
282 		if (uri->user_part != NULL)
283 			fprintf(fp, "user_part: %s\n", uri->user_part);
284 		if (uri->host_part != NULL)
285 			fprintf(fp, "host_part: %s\n", uri->host_part);
286 		if (uri->path_part != NULL)
287 			fprintf(fp, "path_part: %s\n", uri->path_part);
288 		fflush(fp);
289 	}
290 }
291 
292 int
293 main(int argc, char *argv[])
294 {
295 	uri_t *u = NULL;
296 
297 	if (argc != 2) {
298 		fprintf(stderr, "Usage: %s uri\n", argv[0]);
299 		exit(1);
300 	}
301 
302 	if (uri_from_string(argv[1], &u) == 0) {
303 		char buf[BUFSIZ];
304 
305 		uri_dump(stdout, u);
306 		uri_to_string(u, buf, sizeof (buf));
307 		fprintf(stdout, "reconstituted: %s\n", buf);
308 
309 		uri_to_string(u, buf, 12);
310 		fprintf(stdout, "reconstituted(12): %s\n", buf);
311 	} else
312 		printf(" failed for %s  (%s)\n", argv[1], strerror(errno));
313 
314 	exit(0);
315 }
316 #endif /* DEADBEEF */
317