1*2264Sjacobs /* 2*2264Sjacobs * CDDL HEADER START 3*2264Sjacobs * 4*2264Sjacobs * The contents of this file are subject to the terms of the 5*2264Sjacobs * Common Development and Distribution License (the "License"). 6*2264Sjacobs * You may not use this file except in compliance with the License. 7*2264Sjacobs * 8*2264Sjacobs * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*2264Sjacobs * or http://www.opensolaris.org/os/licensing. 10*2264Sjacobs * See the License for the specific language governing permissions 11*2264Sjacobs * and limitations under the License. 12*2264Sjacobs * 13*2264Sjacobs * When distributing Covered Code, include this CDDL HEADER in each 14*2264Sjacobs * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*2264Sjacobs * If applicable, add the following below this CDDL HEADER, with the 16*2264Sjacobs * fields enclosed by brackets "[]" replaced with your own identifying 17*2264Sjacobs * information: Portions Copyright [yyyy] [name of copyright owner] 18*2264Sjacobs * 19*2264Sjacobs * CDDL HEADER END 20*2264Sjacobs */ 21*2264Sjacobs 22*2264Sjacobs /* 23*2264Sjacobs * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24*2264Sjacobs * Use is subject to license terms. 25*2264Sjacobs * 26*2264Sjacobs */ 27*2264Sjacobs 28*2264Sjacobs /* $Id: uri.c 146 2006-03-24 00:26:54Z njacobs $ */ 29*2264Sjacobs 30*2264Sjacobs #pragma ident "%Z%%M% %I% %E% SMI" 31*2264Sjacobs 32*2264Sjacobs /*LINTLIBRARY*/ 33*2264Sjacobs 34*2264Sjacobs #include <stdio.h> 35*2264Sjacobs #include <stdlib.h> 36*2264Sjacobs #include <unistd.h> 37*2264Sjacobs #include <string.h> 38*2264Sjacobs #include <sys/types.h> 39*2264Sjacobs #include <errno.h> 40*2264Sjacobs #include "uri.h" 41*2264Sjacobs 42*2264Sjacobs static char * 43*2264Sjacobs strndup(char *string, size_t length) 44*2264Sjacobs { 45*2264Sjacobs char *result = NULL; 46*2264Sjacobs 47*2264Sjacobs if (length > 0) { 48*2264Sjacobs length++; 49*2264Sjacobs 50*2264Sjacobs 51*2264Sjacobs if ((result = calloc(1, length)) != NULL) 52*2264Sjacobs (void) strlcat(result, string, length); 53*2264Sjacobs } 54*2264Sjacobs 55*2264Sjacobs return (result); 56*2264Sjacobs } 57*2264Sjacobs 58*2264Sjacobs 59*2264Sjacobs /* 60*2264Sjacobs * This will handle the following forms: 61*2264Sjacobs * scheme:scheme_data 62*2264Sjacobs * scheme://[[user[:password]@]host[:port]]/path[[#fragment]|[?query]] 63*2264Sjacobs */ 64*2264Sjacobs int 65*2264Sjacobs uri_from_string(char *string, uri_t **uri) 66*2264Sjacobs { 67*2264Sjacobs char *ptr; 68*2264Sjacobs uri_t *u; 69*2264Sjacobs 70*2264Sjacobs if ((string == NULL) || (uri == NULL)) { 71*2264Sjacobs errno = EINVAL; 72*2264Sjacobs return (-1); 73*2264Sjacobs } 74*2264Sjacobs 75*2264Sjacobs /* find the scheme:scheme_part split */ 76*2264Sjacobs if ((ptr = strchr(string, ':')) == NULL) { 77*2264Sjacobs errno = EINVAL; 78*2264Sjacobs return (-1); 79*2264Sjacobs } 80*2264Sjacobs 81*2264Sjacobs if ((*uri = u = calloc(1, sizeof (*u))) == NULL) 82*2264Sjacobs return (-1); 83*2264Sjacobs 84*2264Sjacobs u->scheme = strndup(string, ptr - string); 85*2264Sjacobs 86*2264Sjacobs if ((ptr[1] == '/') && (ptr[2] == '/')) { 87*2264Sjacobs /* 88*2264Sjacobs * CSTYLED 89*2264Sjacobs * scheme://[host_part]/[path_part] 90*2264Sjacobs */ 91*2264Sjacobs char *end = NULL, *user = NULL, *host = NULL, *path = NULL; 92*2264Sjacobs 93*2264Sjacobs string = ptr + 3; /* skip the :// */ 94*2264Sjacobs 95*2264Sjacobs if ((path = end = strchr(string, '/')) == NULL) 96*2264Sjacobs for (end = string; *end != '\0'; end++); 97*2264Sjacobs 98*2264Sjacobs u->host_part = strndup(string, end - string); 99*2264Sjacobs 100*2264Sjacobs for (host = string; host < end; host ++) 101*2264Sjacobs if (*host == '@') { 102*2264Sjacobs /* string to host is the user part */ 103*2264Sjacobs u->user_part = strndup(string, host-string); 104*2264Sjacobs /* host+1 to end is the host part */ 105*2264Sjacobs u->host_part = strndup(host + 1, 106*2264Sjacobs end - (host+1)); 107*2264Sjacobs user = string; 108*2264Sjacobs host++; 109*2264Sjacobs break; 110*2264Sjacobs } 111*2264Sjacobs 112*2264Sjacobs if (user != NULL) { 113*2264Sjacobs char *password = NULL; 114*2264Sjacobs 115*2264Sjacobs for (password = user; (password < host - 1); password++) 116*2264Sjacobs if (*password == ':') { 117*2264Sjacobs u->password = strndup(password + 1, 118*2264Sjacobs host - password - 2); 119*2264Sjacobs break; 120*2264Sjacobs } 121*2264Sjacobs u->user = strndup(user, password - user); 122*2264Sjacobs } else 123*2264Sjacobs host = string; 124*2264Sjacobs 125*2264Sjacobs if (host != NULL) { 126*2264Sjacobs char *port = NULL; 127*2264Sjacobs 128*2264Sjacobs for (port = host; (port < path); port++) 129*2264Sjacobs if ((*port == ':') || (*port == '/')) 130*2264Sjacobs break; 131*2264Sjacobs 132*2264Sjacobs if (port < path) { 133*2264Sjacobs u->port = strndup(port + 1, path - port - 1); 134*2264Sjacobs } 135*2264Sjacobs 136*2264Sjacobs u->host = strndup(host, port - host); 137*2264Sjacobs } 138*2264Sjacobs 139*2264Sjacobs if (path != NULL) { 140*2264Sjacobs char *name = strrchr(path, '/'); 141*2264Sjacobs 142*2264Sjacobs u->path_part = strdup(path); 143*2264Sjacobs 144*2264Sjacobs if (name != NULL) { 145*2264Sjacobs char *query, *fragment; 146*2264Sjacobs 147*2264Sjacobs query = strrchr(name, '?'); 148*2264Sjacobs if ((query != NULL) && (*query != '\0')) { 149*2264Sjacobs u->query = strdup(query + 1); 150*2264Sjacobs end = query; 151*2264Sjacobs } else 152*2264Sjacobs for (end = path; *end != '\0'; end++); 153*2264Sjacobs 154*2264Sjacobs fragment = strrchr(name, '#'); 155*2264Sjacobs if ((fragment != NULL) && (*fragment != '\0')) { 156*2264Sjacobs u->fragment = strndup(fragment + 1, 157*2264Sjacobs end - fragment - 1); 158*2264Sjacobs end = fragment; 159*2264Sjacobs } 160*2264Sjacobs 161*2264Sjacobs u->path = strndup(path, end - path); 162*2264Sjacobs } 163*2264Sjacobs } 164*2264Sjacobs } else { /* scheme:scheme_part */ 165*2264Sjacobs u->scheme_part = strdup(&ptr[1]); 166*2264Sjacobs } 167*2264Sjacobs 168*2264Sjacobs return (0); 169*2264Sjacobs } 170*2264Sjacobs 171*2264Sjacobs int 172*2264Sjacobs uri_to_string(uri_t *uri, char *buffer, size_t buflen) 173*2264Sjacobs { 174*2264Sjacobs if ((uri == NULL) || (buffer == NULL) || (buflen == 0) || 175*2264Sjacobs (uri->scheme == NULL) || 176*2264Sjacobs ((uri->password != NULL) && (uri->user == NULL)) || 177*2264Sjacobs ((uri->user != NULL) && (uri->host == NULL)) || 178*2264Sjacobs ((uri->port != NULL) && (uri->host == NULL)) || 179*2264Sjacobs ((uri->fragment != NULL) && (uri->path == NULL)) || 180*2264Sjacobs ((uri->query != NULL) && (uri->path == NULL))) { 181*2264Sjacobs errno = EINVAL; 182*2264Sjacobs return (-1); 183*2264Sjacobs } 184*2264Sjacobs 185*2264Sjacobs (void) memset(buffer, 0, buflen); 186*2264Sjacobs 187*2264Sjacobs if (uri->scheme_part == NULL) { 188*2264Sjacobs (void) snprintf(buffer, buflen, 189*2264Sjacobs "%s://%s%s%s%s%s%s%s%s%s%s%s%s%s", 190*2264Sjacobs uri->scheme, 191*2264Sjacobs (uri->user ? uri->user : ""), 192*2264Sjacobs (uri->password ? ":" : ""), 193*2264Sjacobs (uri->password ? uri->password : ""), 194*2264Sjacobs (uri->user ? "@": ""), 195*2264Sjacobs (uri->host ? uri->host : ""), 196*2264Sjacobs (uri->port ? ":" : ""), 197*2264Sjacobs (uri->port ? uri->port : ""), 198*2264Sjacobs (uri->path[0] != '/' ? "/" : ""), uri->path, 199*2264Sjacobs (uri->fragment ? "#" : ""), 200*2264Sjacobs (uri->fragment ? uri->fragment : ""), 201*2264Sjacobs (uri->query ? "?" : ""), 202*2264Sjacobs (uri->query ? uri->query : "")); 203*2264Sjacobs } else { 204*2264Sjacobs (void) snprintf(buffer, buflen, "%s:%s", uri->scheme, 205*2264Sjacobs uri->scheme_part); 206*2264Sjacobs } 207*2264Sjacobs 208*2264Sjacobs return (0); 209*2264Sjacobs } 210*2264Sjacobs 211*2264Sjacobs void 212*2264Sjacobs uri_free(uri_t *uri) 213*2264Sjacobs { 214*2264Sjacobs if (uri != NULL) { 215*2264Sjacobs if (uri->scheme != NULL) 216*2264Sjacobs free(uri->scheme); 217*2264Sjacobs if (uri->scheme_part != NULL) 218*2264Sjacobs free(uri->scheme_part); 219*2264Sjacobs if (uri->user != NULL) 220*2264Sjacobs free(uri->user); 221*2264Sjacobs if (uri->password != NULL) 222*2264Sjacobs free(uri->password); 223*2264Sjacobs if (uri->host != NULL) 224*2264Sjacobs free(uri->host); 225*2264Sjacobs if (uri->port != NULL) 226*2264Sjacobs free(uri->port); 227*2264Sjacobs if (uri->path != NULL) 228*2264Sjacobs free(uri->path); 229*2264Sjacobs if (uri->fragment != NULL) 230*2264Sjacobs free(uri->fragment); 231*2264Sjacobs if (uri->query != NULL) 232*2264Sjacobs free(uri->query); 233*2264Sjacobs /* help me debug */ 234*2264Sjacobs if (uri->user_part != NULL) 235*2264Sjacobs free(uri->user_part); 236*2264Sjacobs if (uri->host_part != NULL) 237*2264Sjacobs free(uri->host_part); 238*2264Sjacobs if (uri->path_part != NULL) 239*2264Sjacobs free(uri->path_part); 240*2264Sjacobs free(uri); 241*2264Sjacobs } 242*2264Sjacobs } 243*2264Sjacobs 244*2264Sjacobs #ifdef DEADBEEF 245*2264Sjacobs static void 246*2264Sjacobs uri_dump(FILE *fp, uri_t *uri) 247*2264Sjacobs { 248*2264Sjacobs if (uri != NULL) { 249*2264Sjacobs fprintf(fp, "URI:\n"); 250*2264Sjacobs if (uri->scheme != NULL) 251*2264Sjacobs fprintf(fp, "scheme: %s\n", uri->scheme); 252*2264Sjacobs if (uri->scheme_part != NULL) 253*2264Sjacobs fprintf(fp, "scheme_part: %s\n", uri->scheme_part); 254*2264Sjacobs if (uri->user != NULL) 255*2264Sjacobs fprintf(fp, "user: %s\n", uri->user); 256*2264Sjacobs if (uri->password != NULL) 257*2264Sjacobs fprintf(fp, "password: %s\n", uri->password); 258*2264Sjacobs if (uri->host != NULL) 259*2264Sjacobs fprintf(fp, "host: %s\n", uri->host); 260*2264Sjacobs if (uri->port != NULL) 261*2264Sjacobs fprintf(fp, "port: %s\n", uri->port); 262*2264Sjacobs if (uri->path != NULL) 263*2264Sjacobs fprintf(fp, "path: %s\n", uri->path); 264*2264Sjacobs if (uri->fragment != NULL) 265*2264Sjacobs fprintf(fp, "fragment: %s\n", uri->fragment); 266*2264Sjacobs if (uri->query != NULL) 267*2264Sjacobs fprintf(fp, "query: %s\n", uri->query); 268*2264Sjacobs /* help me debug */ 269*2264Sjacobs if (uri->user_part != NULL) 270*2264Sjacobs fprintf(fp, "user_part: %s\n", uri->user_part); 271*2264Sjacobs if (uri->host_part != NULL) 272*2264Sjacobs fprintf(fp, "host_part: %s\n", uri->host_part); 273*2264Sjacobs if (uri->path_part != NULL) 274*2264Sjacobs fprintf(fp, "path_part: %s\n", uri->path_part); 275*2264Sjacobs fflush(fp); 276*2264Sjacobs } 277*2264Sjacobs } 278*2264Sjacobs 279*2264Sjacobs int 280*2264Sjacobs main(int argc, char *argv[]) 281*2264Sjacobs { 282*2264Sjacobs uri_t *u = NULL; 283*2264Sjacobs 284*2264Sjacobs if (argc != 2) { 285*2264Sjacobs fprintf(stderr, "Usage: %s uri\n", argv[0]); 286*2264Sjacobs exit(1); 287*2264Sjacobs } 288*2264Sjacobs 289*2264Sjacobs if (uri_from_string(argv[1], &u) == 0) { 290*2264Sjacobs char buf[BUFSIZ]; 291*2264Sjacobs 292*2264Sjacobs uri_dump(stdout, u); 293*2264Sjacobs uri_to_string(u, buf, sizeof (buf)); 294*2264Sjacobs fprintf(stdout, "reconstituted: %s\n", buf); 295*2264Sjacobs 296*2264Sjacobs uri_to_string(u, buf, 12); 297*2264Sjacobs fprintf(stdout, "reconstituted(12): %s\n", buf); 298*2264Sjacobs } else 299*2264Sjacobs printf(" failed for %s (%s)\n", argv[1], strerror(errno)); 300*2264Sjacobs 301*2264Sjacobs exit(0); 302*2264Sjacobs } 303*2264Sjacobs #endif /* DEADBEEF */ 304