mirror of
git://git.psyc.eu/libpsyc
synced 2024-08-15 03:19:02 +00:00
200 lines
5.2 KiB
C
200 lines
5.2 KiB
C
/*
|
|
This file is part of libpsyc.
|
|
Copyright (C) 2011,2012 Carlo v. Loesch, Gabor X Toth, Mathias L. Baumann,
|
|
and other contributing authors.
|
|
|
|
libpsyc is free software: you can redistribute it and/or modify it under the
|
|
terms of the GNU Affero General Public License as published by the Free
|
|
Software Foundation, either version 3 of the License, or (at your option) any
|
|
later version. As a special exception, libpsyc is distributed with additional
|
|
permissions to link libpsyc libraries with non-AGPL works.
|
|
|
|
libpsyc 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 Affero General Public License for more
|
|
details.
|
|
|
|
You should have received a copy of the GNU Affero General Public License and
|
|
the linking exception along with libpsyc in a COPYING file.
|
|
*/
|
|
|
|
#include <ctype.h>
|
|
#include "lib.h"
|
|
#include "psyc/uniform.h"
|
|
#include "psyc/parse.h"
|
|
|
|
/**
|
|
* Parse uniform.
|
|
*
|
|
* @return PsycScheme on success, PsycParseUniformRC on error.
|
|
*/
|
|
int
|
|
psyc_uniform_parse (PsycUniform *uni, const char *buffer, size_t length)
|
|
{
|
|
char c;
|
|
PsycString *p;
|
|
char *data = (char*)buffer;
|
|
size_t pos = 0, part = PSYC_UNIFORM_SCHEME;
|
|
|
|
uni->valid = 0;
|
|
uni->full = PSYC_STRING(data, length);
|
|
|
|
while (pos < length) {
|
|
c = data[pos];
|
|
if (c == ':') {
|
|
uni->scheme = PSYC_STRING(data, pos++);
|
|
break;
|
|
} else if (!psyc_is_host_char(c))
|
|
return PSYC_PARSE_UNIFORM_INVALID_SCHEME;
|
|
pos++;
|
|
}
|
|
|
|
p = &uni->scheme;
|
|
if (p->length == 4 && (tolower(p->data[0]) == 'p' &&
|
|
tolower(p->data[1]) == 's' &&
|
|
tolower(p->data[2]) == 'y' &&
|
|
tolower(p->data[3]) == 'c')) {
|
|
uni->type = PSYC_SCHEME_PSYC;
|
|
part = PSYC_UNIFORM_SLASHES;
|
|
uni->slashes = PSYC_STRING(data + pos, 0);
|
|
|
|
while (pos < length) {
|
|
c = data[pos];
|
|
switch (part) {
|
|
case PSYC_UNIFORM_SLASHES:
|
|
if (c == '/')
|
|
uni->slashes.length++;
|
|
else
|
|
return PSYC_PARSE_UNIFORM_INVALID_SLASHES;
|
|
|
|
if (uni->slashes.length == 2) {
|
|
part = PSYC_UNIFORM_HOST;
|
|
uni->host = PSYC_STRING(data + pos + 1, 0);
|
|
}
|
|
break;
|
|
|
|
case PSYC_UNIFORM_HOST:
|
|
if (psyc_is_host_char(c)) {
|
|
uni->host.length++;
|
|
break;
|
|
}
|
|
|
|
if (uni->host.length == 0)
|
|
return PSYC_PARSE_UNIFORM_INVALID_HOST;
|
|
|
|
if (c == ':') {
|
|
part = PSYC_UNIFORM_PORT;
|
|
p = &uni->port;
|
|
} else if (c == '/') {
|
|
uni->slash = PSYC_STRING(data + pos, 1);
|
|
|
|
part = PSYC_UNIFORM_RESOURCE;
|
|
p = &uni->resource;
|
|
} else
|
|
return PSYC_PARSE_UNIFORM_INVALID_HOST;
|
|
|
|
*p = PSYC_STRING(data + pos + 1, 0);
|
|
break;
|
|
|
|
case PSYC_UNIFORM_PORT:
|
|
if (psyc_is_numeric(c) || (uni->port.length == 0 && c == '-')) {
|
|
uni->port.length++;
|
|
break;
|
|
}
|
|
|
|
if (uni->port.length == 0 && c != PSYC_TRANSPORT_GNUNET)
|
|
return PSYC_PARSE_UNIFORM_INVALID_PORT;
|
|
|
|
if (c == '/') {
|
|
uni->slash = PSYC_STRING(data + pos, 1);
|
|
|
|
part = PSYC_UNIFORM_RESOURCE;
|
|
uni->resource = PSYC_STRING(data + pos + 1, 0);
|
|
break;
|
|
} else {
|
|
part = PSYC_UNIFORM_TRANSPORT;
|
|
uni->transport = PSYC_STRING(data + pos, 0);
|
|
}
|
|
// fall thru
|
|
|
|
case PSYC_UNIFORM_TRANSPORT:
|
|
switch (c) {
|
|
case PSYC_TRANSPORT_GNUNET:
|
|
if (uni->port.length > 0)
|
|
return PSYC_PARSE_UNIFORM_INVALID_TRANSPORT;
|
|
case PSYC_TRANSPORT_TCP:
|
|
case PSYC_TRANSPORT_UDP:
|
|
case PSYC_TRANSPORT_TLS:
|
|
if (uni->transport.length > 0)
|
|
return PSYC_PARSE_UNIFORM_INVALID_TRANSPORT;
|
|
uni->transport.length++;
|
|
break;
|
|
case '/':
|
|
uni->slash = PSYC_STRING(data + pos, 1);
|
|
|
|
part = PSYC_UNIFORM_RESOURCE;
|
|
uni->resource = PSYC_STRING(data + pos + 1, 0);
|
|
break;
|
|
default:
|
|
return PSYC_PARSE_UNIFORM_INVALID_TRANSPORT;
|
|
}
|
|
break;
|
|
|
|
case PSYC_UNIFORM_RESOURCE:
|
|
if (psyc_is_name_char(c)) {
|
|
uni->resource.length++;
|
|
break;
|
|
} else if (c == '#') {
|
|
part = PSYC_UNIFORM_CHANNEL;
|
|
uni->channel = PSYC_STRING(data + pos + 1, 0);
|
|
break;
|
|
} else
|
|
return PSYC_PARSE_UNIFORM_INVALID_RESOURCE;
|
|
|
|
case PSYC_UNIFORM_CHANNEL:
|
|
if (psyc_is_name_char(c)) {
|
|
uni->channel.length++;
|
|
break;
|
|
} else
|
|
return PSYC_PARSE_UNIFORM_INVALID_CHANNEL;
|
|
}
|
|
pos++;
|
|
}
|
|
|
|
if (uni->host.length == 0)
|
|
return PSYC_PARSE_UNIFORM_INVALID_HOST;
|
|
|
|
uni->host_port = PSYC_STRING(uni->host.data, uni->host.length
|
|
+ uni->port.length + uni->transport.length);
|
|
if (uni->port.length > 0 || uni->transport.length > 0)
|
|
uni->host_port.length++;
|
|
|
|
uni->root = PSYC_STRING(data, uni->scheme.length + 1
|
|
+ uni->slashes.length + uni->host_port.length);
|
|
|
|
uni->entity = PSYC_STRING(data, uni->root.length + uni->slash.length
|
|
+ uni->resource.length);
|
|
|
|
uni->body = PSYC_STRING(uni->host.data,
|
|
length - uni->scheme.length - 1 - uni->slashes.length);
|
|
|
|
if (uni->slash.length) {
|
|
uni->path.data = uni->slash.data;
|
|
uni->path.length = length - uni->root.length;
|
|
}
|
|
|
|
if (uni->resource.length)
|
|
uni->nick = PSYC_STRING(uni->resource.data + 1, uni->resource.length - 1);
|
|
|
|
} else
|
|
return PSYC_PARSE_UNIFORM_INVALID_SCHEME;
|
|
|
|
if (uni->host.length == 0)
|
|
return PSYC_PARSE_UNIFORM_INVALID_HOST;
|
|
|
|
uni->valid = 1;
|
|
return uni->type;
|
|
}
|
|
|
|
extern inline int
|
|
psyc_entity_type (char entity);
|