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*7253Sjacobs * Copyright 2008 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 #pragma ident "%Z%%M% %I% %E% SMI" 312264Sjacobs 322264Sjacobs /*LINTLIBRARY*/ 332264Sjacobs 342264Sjacobs #include <stdio.h> 352264Sjacobs #include <stdlib.h> 362264Sjacobs #include <unistd.h> 372264Sjacobs #include <string.h> 382264Sjacobs #include <sys/types.h> 392264Sjacobs #include <errno.h> 402264Sjacobs #include "uri.h" 412264Sjacobs 422264Sjacobs static char * 432264Sjacobs strndup(char *string, size_t length) 442264Sjacobs { 452264Sjacobs char *result = NULL; 462264Sjacobs 472264Sjacobs if (length > 0) { 482264Sjacobs length++; 492264Sjacobs 502264Sjacobs 512264Sjacobs if ((result = calloc(1, length)) != NULL) 522264Sjacobs (void) strlcat(result, string, length); 532264Sjacobs } 542264Sjacobs 552264Sjacobs return (result); 562264Sjacobs } 572264Sjacobs 582264Sjacobs 592264Sjacobs /* 602264Sjacobs * This will handle the following forms: 612264Sjacobs * scheme:scheme_data 622264Sjacobs * scheme://[[user[:password]@]host[:port]]/path[[#fragment]|[?query]] 632264Sjacobs */ 642264Sjacobs int 652264Sjacobs uri_from_string(char *string, uri_t **uri) 662264Sjacobs { 672264Sjacobs char *ptr; 682264Sjacobs uri_t *u; 692264Sjacobs 702264Sjacobs if ((string == NULL) || (uri == NULL)) { 712264Sjacobs errno = EINVAL; 722264Sjacobs return (-1); 732264Sjacobs } 742264Sjacobs 752264Sjacobs /* find the scheme:scheme_part split */ 762264Sjacobs if ((ptr = strchr(string, ':')) == NULL) { 772264Sjacobs errno = EINVAL; 782264Sjacobs return (-1); 792264Sjacobs } 802264Sjacobs 812264Sjacobs if ((*uri = u = calloc(1, sizeof (*u))) == NULL) 822264Sjacobs return (-1); 832264Sjacobs 842264Sjacobs u->scheme = strndup(string, ptr - string); 852264Sjacobs 862264Sjacobs if ((ptr[1] == '/') && (ptr[2] == '/')) { 872264Sjacobs /* 882264Sjacobs * CSTYLED 892264Sjacobs * scheme://[host_part]/[path_part] 902264Sjacobs */ 912264Sjacobs char *end = NULL, *user = NULL, *host = NULL, *path = NULL; 922264Sjacobs 932264Sjacobs string = ptr + 3; /* skip the :// */ 942264Sjacobs 952264Sjacobs if ((path = end = strchr(string, '/')) == NULL) 962264Sjacobs for (end = string; *end != '\0'; end++); 972264Sjacobs 982264Sjacobs u->host_part = strndup(string, end - string); 992264Sjacobs 1002264Sjacobs for (host = string; host < end; host ++) 1012264Sjacobs if (*host == '@') { 1022264Sjacobs /* string to host is the user part */ 1032264Sjacobs u->user_part = strndup(string, host-string); 1042264Sjacobs /* host+1 to end is the host part */ 1052264Sjacobs u->host_part = strndup(host + 1, 1062264Sjacobs end - (host+1)); 1072264Sjacobs user = string; 1082264Sjacobs host++; 1092264Sjacobs break; 1102264Sjacobs } 1112264Sjacobs 1122264Sjacobs if (user != NULL) { 1132264Sjacobs char *password = NULL; 1142264Sjacobs 1152264Sjacobs for (password = user; (password < host - 1); password++) 1162264Sjacobs if (*password == ':') { 1172264Sjacobs u->password = strndup(password + 1, 1182264Sjacobs host - password - 2); 1192264Sjacobs break; 1202264Sjacobs } 1212264Sjacobs u->user = strndup(user, password - user); 1222264Sjacobs } else 1232264Sjacobs host = string; 1242264Sjacobs 1252264Sjacobs if (host != NULL) { 1262264Sjacobs char *port = NULL; 1272264Sjacobs 1282264Sjacobs for (port = host; (port < path); port++) 1292264Sjacobs if ((*port == ':') || (*port == '/')) 1302264Sjacobs break; 1312264Sjacobs 1322264Sjacobs if (port < path) { 1332264Sjacobs u->port = strndup(port + 1, path - port - 1); 1342264Sjacobs } 1352264Sjacobs 1362264Sjacobs u->host = strndup(host, port - host); 1372264Sjacobs } 1382264Sjacobs 1392264Sjacobs if (path != NULL) { 1402264Sjacobs char *name = strrchr(path, '/'); 1412264Sjacobs 1422264Sjacobs u->path_part = strdup(path); 1432264Sjacobs 1442264Sjacobs if (name != NULL) { 1452264Sjacobs char *query, *fragment; 1462264Sjacobs 1472264Sjacobs query = strrchr(name, '?'); 1482264Sjacobs if ((query != NULL) && (*query != '\0')) { 1492264Sjacobs u->query = strdup(query + 1); 1502264Sjacobs end = query; 1512264Sjacobs } else 1522264Sjacobs for (end = path; *end != '\0'; end++); 1532264Sjacobs 1542264Sjacobs fragment = strrchr(name, '#'); 1552264Sjacobs if ((fragment != NULL) && (*fragment != '\0')) { 1562264Sjacobs u->fragment = strndup(fragment + 1, 1572264Sjacobs end - fragment - 1); 1582264Sjacobs end = fragment; 1592264Sjacobs } 1602264Sjacobs 1612264Sjacobs u->path = strndup(path, end - path); 1622264Sjacobs } 1632264Sjacobs } 1642264Sjacobs } else { /* scheme:scheme_part */ 1652264Sjacobs u->scheme_part = strdup(&ptr[1]); 1662264Sjacobs } 1672264Sjacobs 168*7253Sjacobs if ((u->host_part == NULL) && (u->path_part == NULL) && 169*7253Sjacobs (u->scheme_part == NULL)) { 170*7253Sjacobs errno = EINVAL; 171*7253Sjacobs uri_free(u); 172*7253Sjacobs *uri = NULL; 173*7253Sjacobs return (-1); 174*7253Sjacobs } 175*7253Sjacobs 1762264Sjacobs return (0); 1772264Sjacobs } 1782264Sjacobs 1792264Sjacobs int 1802264Sjacobs uri_to_string(uri_t *uri, char *buffer, size_t buflen) 1812264Sjacobs { 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 } 1922264Sjacobs 1932264Sjacobs (void) memset(buffer, 0, buflen); 1942264Sjacobs 1952264Sjacobs if (uri->scheme_part == NULL) { 1962264Sjacobs (void) snprintf(buffer, buflen, 1972264Sjacobs "%s://%s%s%s%s%s%s%s%s%s%s%s%s%s", 1982264Sjacobs uri->scheme, 1992264Sjacobs (uri->user ? uri->user : ""), 2002264Sjacobs (uri->password ? ":" : ""), 2012264Sjacobs (uri->password ? uri->password : ""), 2022264Sjacobs (uri->user ? "@": ""), 2032264Sjacobs (uri->host ? uri->host : ""), 2042264Sjacobs (uri->port ? ":" : ""), 2052264Sjacobs (uri->port ? uri->port : ""), 2062264Sjacobs (uri->path[0] != '/' ? "/" : ""), uri->path, 2072264Sjacobs (uri->fragment ? "#" : ""), 2082264Sjacobs (uri->fragment ? uri->fragment : ""), 2092264Sjacobs (uri->query ? "?" : ""), 2102264Sjacobs (uri->query ? uri->query : "")); 2112264Sjacobs } else { 2122264Sjacobs (void) snprintf(buffer, buflen, "%s:%s", uri->scheme, 2132264Sjacobs uri->scheme_part); 2142264Sjacobs } 2152264Sjacobs 2162264Sjacobs return (0); 2172264Sjacobs } 2182264Sjacobs 2192264Sjacobs void 2202264Sjacobs uri_free(uri_t *uri) 2212264Sjacobs { 2222264Sjacobs if (uri != NULL) { 2232264Sjacobs if (uri->scheme != NULL) 2242264Sjacobs free(uri->scheme); 2252264Sjacobs if (uri->scheme_part != NULL) 2262264Sjacobs free(uri->scheme_part); 2272264Sjacobs if (uri->user != NULL) 2282264Sjacobs free(uri->user); 2292264Sjacobs if (uri->password != NULL) 2302264Sjacobs free(uri->password); 2312264Sjacobs if (uri->host != NULL) 2322264Sjacobs free(uri->host); 2332264Sjacobs if (uri->port != NULL) 2342264Sjacobs free(uri->port); 2352264Sjacobs if (uri->path != NULL) 2362264Sjacobs free(uri->path); 2372264Sjacobs if (uri->fragment != NULL) 2382264Sjacobs free(uri->fragment); 2392264Sjacobs if (uri->query != NULL) 2402264Sjacobs free(uri->query); 2412264Sjacobs /* help me debug */ 2422264Sjacobs if (uri->user_part != NULL) 2432264Sjacobs free(uri->user_part); 2442264Sjacobs if (uri->host_part != NULL) 2452264Sjacobs free(uri->host_part); 2462264Sjacobs if (uri->path_part != NULL) 2472264Sjacobs free(uri->path_part); 2482264Sjacobs free(uri); 2492264Sjacobs } 2502264Sjacobs } 2512264Sjacobs 2522264Sjacobs #ifdef DEADBEEF 2532264Sjacobs static void 2542264Sjacobs uri_dump(FILE *fp, uri_t *uri) 2552264Sjacobs { 2562264Sjacobs if (uri != NULL) { 2572264Sjacobs fprintf(fp, "URI:\n"); 2582264Sjacobs if (uri->scheme != NULL) 2592264Sjacobs fprintf(fp, "scheme: %s\n", uri->scheme); 2602264Sjacobs if (uri->scheme_part != NULL) 2612264Sjacobs fprintf(fp, "scheme_part: %s\n", uri->scheme_part); 2622264Sjacobs if (uri->user != NULL) 2632264Sjacobs fprintf(fp, "user: %s\n", uri->user); 2642264Sjacobs if (uri->password != NULL) 2652264Sjacobs fprintf(fp, "password: %s\n", uri->password); 2662264Sjacobs if (uri->host != NULL) 2672264Sjacobs fprintf(fp, "host: %s\n", uri->host); 2682264Sjacobs if (uri->port != NULL) 2692264Sjacobs fprintf(fp, "port: %s\n", uri->port); 2702264Sjacobs if (uri->path != NULL) 2712264Sjacobs fprintf(fp, "path: %s\n", uri->path); 2722264Sjacobs if (uri->fragment != NULL) 2732264Sjacobs fprintf(fp, "fragment: %s\n", uri->fragment); 2742264Sjacobs if (uri->query != NULL) 2752264Sjacobs fprintf(fp, "query: %s\n", uri->query); 2762264Sjacobs /* help me debug */ 2772264Sjacobs if (uri->user_part != NULL) 2782264Sjacobs fprintf(fp, "user_part: %s\n", uri->user_part); 2792264Sjacobs if (uri->host_part != NULL) 2802264Sjacobs fprintf(fp, "host_part: %s\n", uri->host_part); 2812264Sjacobs if (uri->path_part != NULL) 2822264Sjacobs fprintf(fp, "path_part: %s\n", uri->path_part); 2832264Sjacobs fflush(fp); 2842264Sjacobs } 2852264Sjacobs } 2862264Sjacobs 2872264Sjacobs int 2882264Sjacobs main(int argc, char *argv[]) 2892264Sjacobs { 2902264Sjacobs uri_t *u = NULL; 2912264Sjacobs 2922264Sjacobs if (argc != 2) { 2932264Sjacobs fprintf(stderr, "Usage: %s uri\n", argv[0]); 2942264Sjacobs exit(1); 2952264Sjacobs } 2962264Sjacobs 2972264Sjacobs if (uri_from_string(argv[1], &u) == 0) { 2982264Sjacobs char buf[BUFSIZ]; 2992264Sjacobs 3002264Sjacobs uri_dump(stdout, u); 3012264Sjacobs uri_to_string(u, buf, sizeof (buf)); 3022264Sjacobs fprintf(stdout, "reconstituted: %s\n", buf); 3032264Sjacobs 3042264Sjacobs uri_to_string(u, buf, 12); 3052264Sjacobs fprintf(stdout, "reconstituted(12): %s\n", buf); 3062264Sjacobs } else 3072264Sjacobs printf(" failed for %s (%s)\n", argv[1], strerror(errno)); 3082264Sjacobs 3092264Sjacobs exit(0); 3102264Sjacobs } 3112264Sjacobs #endif /* DEADBEEF */ 312