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 2006 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 return (0); 169 } 170 171 int 172 uri_to_string(uri_t *uri, char *buffer, size_t buflen) 173 { 174 if ((uri == NULL) || (buffer == NULL) || (buflen == 0) || 175 (uri->scheme == NULL) || 176 ((uri->password != NULL) && (uri->user == NULL)) || 177 ((uri->user != NULL) && (uri->host == NULL)) || 178 ((uri->port != NULL) && (uri->host == NULL)) || 179 ((uri->fragment != NULL) && (uri->path == NULL)) || 180 ((uri->query != NULL) && (uri->path == NULL))) { 181 errno = EINVAL; 182 return (-1); 183 } 184 185 (void) memset(buffer, 0, buflen); 186 187 if (uri->scheme_part == NULL) { 188 (void) snprintf(buffer, buflen, 189 "%s://%s%s%s%s%s%s%s%s%s%s%s%s%s", 190 uri->scheme, 191 (uri->user ? uri->user : ""), 192 (uri->password ? ":" : ""), 193 (uri->password ? uri->password : ""), 194 (uri->user ? "@": ""), 195 (uri->host ? uri->host : ""), 196 (uri->port ? ":" : ""), 197 (uri->port ? uri->port : ""), 198 (uri->path[0] != '/' ? "/" : ""), uri->path, 199 (uri->fragment ? "#" : ""), 200 (uri->fragment ? uri->fragment : ""), 201 (uri->query ? "?" : ""), 202 (uri->query ? uri->query : "")); 203 } else { 204 (void) snprintf(buffer, buflen, "%s:%s", uri->scheme, 205 uri->scheme_part); 206 } 207 208 return (0); 209 } 210 211 void 212 uri_free(uri_t *uri) 213 { 214 if (uri != NULL) { 215 if (uri->scheme != NULL) 216 free(uri->scheme); 217 if (uri->scheme_part != NULL) 218 free(uri->scheme_part); 219 if (uri->user != NULL) 220 free(uri->user); 221 if (uri->password != NULL) 222 free(uri->password); 223 if (uri->host != NULL) 224 free(uri->host); 225 if (uri->port != NULL) 226 free(uri->port); 227 if (uri->path != NULL) 228 free(uri->path); 229 if (uri->fragment != NULL) 230 free(uri->fragment); 231 if (uri->query != NULL) 232 free(uri->query); 233 /* help me debug */ 234 if (uri->user_part != NULL) 235 free(uri->user_part); 236 if (uri->host_part != NULL) 237 free(uri->host_part); 238 if (uri->path_part != NULL) 239 free(uri->path_part); 240 free(uri); 241 } 242 } 243 244 #ifdef DEADBEEF 245 static void 246 uri_dump(FILE *fp, uri_t *uri) 247 { 248 if (uri != NULL) { 249 fprintf(fp, "URI:\n"); 250 if (uri->scheme != NULL) 251 fprintf(fp, "scheme: %s\n", uri->scheme); 252 if (uri->scheme_part != NULL) 253 fprintf(fp, "scheme_part: %s\n", uri->scheme_part); 254 if (uri->user != NULL) 255 fprintf(fp, "user: %s\n", uri->user); 256 if (uri->password != NULL) 257 fprintf(fp, "password: %s\n", uri->password); 258 if (uri->host != NULL) 259 fprintf(fp, "host: %s\n", uri->host); 260 if (uri->port != NULL) 261 fprintf(fp, "port: %s\n", uri->port); 262 if (uri->path != NULL) 263 fprintf(fp, "path: %s\n", uri->path); 264 if (uri->fragment != NULL) 265 fprintf(fp, "fragment: %s\n", uri->fragment); 266 if (uri->query != NULL) 267 fprintf(fp, "query: %s\n", uri->query); 268 /* help me debug */ 269 if (uri->user_part != NULL) 270 fprintf(fp, "user_part: %s\n", uri->user_part); 271 if (uri->host_part != NULL) 272 fprintf(fp, "host_part: %s\n", uri->host_part); 273 if (uri->path_part != NULL) 274 fprintf(fp, "path_part: %s\n", uri->path_part); 275 fflush(fp); 276 } 277 } 278 279 int 280 main(int argc, char *argv[]) 281 { 282 uri_t *u = NULL; 283 284 if (argc != 2) { 285 fprintf(stderr, "Usage: %s uri\n", argv[0]); 286 exit(1); 287 } 288 289 if (uri_from_string(argv[1], &u) == 0) { 290 char buf[BUFSIZ]; 291 292 uri_dump(stdout, u); 293 uri_to_string(u, buf, sizeof (buf)); 294 fprintf(stdout, "reconstituted: %s\n", buf); 295 296 uri_to_string(u, buf, 12); 297 fprintf(stdout, "reconstituted(12): %s\n", buf); 298 } else 299 printf(" failed for %s (%s)\n", argv[1], strerror(errno)); 300 301 exit(0); 302 } 303 #endif /* DEADBEEF */ 304