ZeroTierOne/attic/historic/anode/libanode/uri.c
2017-05-04 10:42:22 -07:00

186 lines
5.4 KiB
C

/* libanode: the Anode C reference implementation
* Copyright (C) 2009-2010 Adam Ierymenko <adam.ierymenko@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include <stdio.h>
#include <stdlib.h>
#include "impl/misc.h"
#include "anode.h"
int AnodeURI_parse(AnodeURI *parsed_uri,const char *uri_string)
{
char buf[sizeof(AnodeURI)];
unsigned long ptr = 0;
char c;
char *p1,*p2;
Anode_zero((void *)parsed_uri,sizeof(AnodeURI));
/* Get the scheme */
for(;;) {
c = *(uri_string++);
if (!c) {
parsed_uri->scheme[ptr] = (char)0;
return ANODE_ERR_INVALID_URI;
} else if (c == ':') {
parsed_uri->scheme[ptr] = (char)0;
break;
} else {
parsed_uri->scheme[ptr++] = c;
if (ptr == sizeof(parsed_uri->scheme))
return ANODE_ERR_BUFFER_TOO_SMALL;
}
}
if (*uri_string == '/') {
/* If it starts with /, it's a URL */
/* Skip double slash */
if (!(*(++uri_string)))
return 0; /* Scheme with no path */
if (*uri_string == '/') {
if (!(*(++uri_string)))
return 0; /* Scheme with no path */
}
/* Get the host section and put it in buf[] */
ptr = 0;
while ((*uri_string)&&(*uri_string != '/')) {
buf[ptr++] = *(uri_string++);
if (ptr == sizeof(buf))
return ANODE_ERR_BUFFER_TOO_SMALL;
}
buf[ptr] = (char)0;
/* Parse host section for host, username, password, and port */
if (buf[0]) {
p1 = (char *)Anode_strchr(buf,'@');
if (p1) {
*(p1++) = (char)0;
if (*p1) {
p2 = (char *)Anode_strchr(buf,':');
if (p2) {
*(p2++) = (char)0;
Anode_str_copy(parsed_uri->password,p2,sizeof(parsed_uri->password));
}
Anode_str_copy(parsed_uri->username,buf,sizeof(parsed_uri->username));
} else return ANODE_ERR_INVALID_URI;
} else p1 = buf;
p2 = (char *)Anode_strchr(p1,':');
if (p2) {
*(p2++) = (char)0;
if (*p2)
parsed_uri->port = (int)strtoul(p2,(char **)0,10);
}
Anode_str_copy(parsed_uri->host,p1,sizeof(parsed_uri->host));
}
/* Get the path, query, and fragment section and put it in buf[] */
ptr = 0;
while ((buf[ptr++] = *(uri_string++))) {
if (ptr == sizeof(buf))
return ANODE_ERR_BUFFER_TOO_SMALL;
}
/* Parse path section for path, query, and fragment */
if (buf[0]) {
p1 = (char *)Anode_strchr(buf,'?');
if (p1) {
*(p1++) = (char)0;
p2 = (char *)Anode_strchr(p1,'#');
if (p2) {
*(p2++) = (char)0;
Anode_str_copy(parsed_uri->fragment,p2,sizeof(parsed_uri->fragment));
}
Anode_str_copy(parsed_uri->query,p1,sizeof(parsed_uri->query));
} else {
p2 = (char *)Anode_strchr(buf,'#');
if (p2) {
*(p2++) = (char)0;
Anode_str_copy(parsed_uri->fragment,p2,sizeof(parsed_uri->fragment));
}
}
Anode_str_copy(parsed_uri->path,buf,sizeof(parsed_uri->path));
}
} else {
/* Otherwise, it's a URN and what remains is all path */
ptr = 0;
while ((parsed_uri->path[ptr++] = *(uri_string++))) {
if (ptr == sizeof(parsed_uri->path))
return ANODE_ERR_BUFFER_TOO_SMALL;
}
}
return 0;
}
char *AnodeURI_to_string(const AnodeURI *uri,char *buf,int len)
{
int i = 0;
char portbuf[16];
const char *p;
p = uri->scheme;
while (*p) { buf[i++] = *(p++); if (i >= len) return (char *)0; }
buf[i++] = ':'; if (i >= len) return (char *)0;
if (uri->host[0]) {
buf[i++] = '/'; if (i >= len) return (char *)0;
buf[i++] = '/'; if (i >= len) return (char *)0;
if (uri->username[0]) {
p = uri->username;
while (*p) { buf[i++] = *(p++); if (i >= len) return (char *)0; }
if (uri->password[0]) {
buf[i++] = ':'; if (i >= len) return (char *)0;
p = uri->password;
while (*p) { buf[i++] = *(p++); if (i >= len) return (char *)0; }
}
buf[i++] = '@'; if (i >= len) return (char *)0;
}
p = uri->host;
while (*p) { buf[i++] = *(p++); if (i >= len) return (char *)0; }
if ((uri->port > 0)&&(uri->port <= 0xffff)) {
buf[i++] = ':'; if (i >= len) return (char *)0;
snprintf(portbuf,sizeof(portbuf),"%d",uri->port);
p = portbuf;
while (*p) { buf[i++] = *(p++); if (i >= len) return (char *)0; }
}
}
p = uri->path;
while (*p) { buf[i++] = *(p++); if (i >= len) return (char *)0; }
if (uri->query[0]) {
buf[i++] = '?'; if (i >= len) return (char *)0;
p = uri->query;
while (*p) { buf[i++] = *(p++); if (i >= len) return (char *)0; }
}
if (uri->fragment[0]) {
buf[i++] = '#'; if (i >= len) return (char *)0;
p = uri->fragment;
while (*p) { buf[i++] = *(p++); if (i >= len) return (char *)0; }
}
buf[i] = (char)0;
return buf;
}