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