/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
*/
/* $Id: uri.c 146 2006-03-24 00:26:54Z njacobs $ */
/*LINTLIBRARY*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <errno.h>
#include "uri.h"
/*
* This will handle the following forms:
* scheme:scheme_data
* scheme://[[user[:password]@]host[:port]]/path[[#fragment]|[?query]]
*/
int
uri_from_string(char *string, uri_t **uri)
{
char *ptr;
uri_t *u;
if ((string == NULL) || (uri == NULL)) {
errno = EINVAL;
return (-1);
}
/* find the scheme:scheme_part split */
if ((ptr = strchr(string, ':')) == NULL) {
errno = EINVAL;
return (-1);
}
if ((*uri = u = calloc(1, sizeof (*u))) == NULL)
return (-1);
u->scheme = strndup(string, ptr - string);
if ((ptr[1] == '/') && (ptr[2] == '/')) {
/*
* CSTYLED
* scheme://[host_part]/[path_part]
*/
char *end = NULL, *user = NULL, *host = NULL, *path = NULL;
string = ptr + 3; /* skip the :// */
if ((path = end = strchr(string, '/')) == NULL)
for (end = string; *end != '\0'; end++)
continue;
u->host_part = strndup(string, end - string);
for (host = string; host < end; host ++)
if (*host == '@') {
/* string to host is the user part */
u->user_part = strndup(string, host-string);
/* host+1 to end is the host part */
u->host_part = strndup(host + 1,
end - (host+1));
user = string;
host++;
break;
}
if (user != NULL) {
char *password = NULL;
for (password = user; (password < host - 1); password++)
if (*password == ':') {
u->password = strndup(password + 1,
host - password - 2);
break;
}
u->user = strndup(user, password - user);
} else
host = string;
if (host != NULL) {
char *port = NULL;
for (port = host; (port < path); port++)
if ((*port == ':') || (*port == '/'))
break;
if (port < path) {
u->port = strndup(port + 1, path - port - 1);
}
u->host = strndup(host, port - host);
}
if (path != NULL) {
char *name = strrchr(path, '/');
u->path_part = strdup(path);
if (name != NULL) {
char *query, *fragment;
query = strrchr(name, '?');
if ((query != NULL) && (*query != '\0')) {
u->query = strdup(query + 1);
end = query;
} else {
for (end = path; *end != '\0'; end++)
continue;
}
fragment = strrchr(name, '#');
if ((fragment != NULL) && (*fragment != '\0')) {
u->fragment = strndup(fragment + 1,
end - fragment - 1);
end = fragment;
}
u->path = strndup(path, end - path);
}
}
} else { /* scheme:scheme_part */
u->scheme_part = strdup(&ptr[1]);
}
if ((u->host_part == NULL) && (u->path_part == NULL) &&
(u->scheme_part == NULL)) {
errno = EINVAL;
uri_free(u);
*uri = NULL;
return (-1);
}
return (0);
}
int
uri_to_string(uri_t *uri, char *buffer, size_t buflen)
{
char *uri_ppfix;
if ((uri == NULL) || (buffer == NULL) || (buflen == 0) ||
(uri->scheme == NULL) ||
((uri->password != NULL) && (uri->user == NULL)) ||
((uri->user != NULL) && (uri->host == NULL)) ||
((uri->port != NULL) && (uri->host == NULL)) ||
((uri->fragment != NULL) && (uri->path == NULL)) ||
((uri->query != NULL) && (uri->path == NULL))) {
errno = EINVAL;
return (-1);
}
if (uri->path == NULL || uri->path[0] == '/')
uri_ppfix = "";
else
uri_ppfix = "/";
(void) memset(buffer, 0, buflen);
if (uri->scheme_part == NULL) {
(void) snprintf(buffer, buflen,
"%s://%s%s%s%s%s%s%s%s%s%s%s%s%s",
uri->scheme,
(uri->user ? uri->user : ""),
(uri->password ? ":" : ""),
(uri->password ? uri->password : ""),
(uri->user ? "@": ""),
(uri->host ? uri->host : ""),
(uri->port ? ":" : ""),
(uri->port ? uri->port : ""),
uri_ppfix,
(uri->path ? uri->path : ""),
(uri->fragment ? "#" : ""),
(uri->fragment ? uri->fragment : ""),
(uri->query ? "?" : ""),
(uri->query ? uri->query : ""));
} else {
(void) snprintf(buffer, buflen, "%s:%s", uri->scheme,
uri->scheme_part);
}
return (0);
}
void
uri_free(uri_t *uri)
{
if (uri != NULL) {
if (uri->scheme != NULL)
free(uri->scheme);
if (uri->scheme_part != NULL)
free(uri->scheme_part);
if (uri->user != NULL)
free(uri->user);
if (uri->password != NULL)
free(uri->password);
if (uri->host != NULL)
free(uri->host);
if (uri->port != NULL)
free(uri->port);
if (uri->path != NULL)
free(uri->path);
if (uri->fragment != NULL)
free(uri->fragment);
if (uri->query != NULL)
free(uri->query);
/* help me debug */
if (uri->user_part != NULL)
free(uri->user_part);
if (uri->host_part != NULL)
free(uri->host_part);
if (uri->path_part != NULL)
free(uri->path_part);
free(uri);
}
}
#ifdef DEADBEEF
static void
uri_dump(FILE *fp, uri_t *uri)
{
if (uri != NULL) {
fprintf(fp, "URI:\n");
if (uri->scheme != NULL)
fprintf(fp, "scheme: %s\n", uri->scheme);
if (uri->scheme_part != NULL)
fprintf(fp, "scheme_part: %s\n", uri->scheme_part);
if (uri->user != NULL)
fprintf(fp, "user: %s\n", uri->user);
if (uri->password != NULL)
fprintf(fp, "password: %s\n", uri->password);
if (uri->host != NULL)
fprintf(fp, "host: %s\n", uri->host);
if (uri->port != NULL)
fprintf(fp, "port: %s\n", uri->port);
if (uri->path != NULL)
fprintf(fp, "path: %s\n", uri->path);
if (uri->fragment != NULL)
fprintf(fp, "fragment: %s\n", uri->fragment);
if (uri->query != NULL)
fprintf(fp, "query: %s\n", uri->query);
/* help me debug */
if (uri->user_part != NULL)
fprintf(fp, "user_part: %s\n", uri->user_part);
if (uri->host_part != NULL)
fprintf(fp, "host_part: %s\n", uri->host_part);
if (uri->path_part != NULL)
fprintf(fp, "path_part: %s\n", uri->path_part);
fflush(fp);
}
}
int
main(int argc, char *argv[])
{
uri_t *u = NULL;
if (argc != 2) {
fprintf(stderr, "Usage: %s uri\n", argv[0]);
exit(1);
}
if (uri_from_string(argv[1], &u) == 0) {
char buf[BUFSIZ];
uri_dump(stdout, u);
uri_to_string(u, buf, sizeof (buf));
fprintf(stdout, "reconstituted: %s\n", buf);
uri_to_string(u, buf, 12);
fprintf(stdout, "reconstituted(12): %s\n", buf);
} else
printf(" failed for %s (%s)\n", argv[1], strerror(errno));
exit(0);
}
#endif /* DEADBEEF */