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