HelenOS sources
This source file includes following definitions.
- cut_str
- uri_parse
- uri_scheme_parse
- uri_scheme_validate
- uri_percent_parse
- uri_user_info_parse
- uri_user_info_validate
- uri_port_parse
- uri_port_validate
- uri_validate
- uri_destroy
#include <assert.h>
#include <stdlib.h>
#include <stddef.h>
#include <str.h>
#include <ctype.h>
#include <errno.h>
#include "uri.h"
#include "internal/ctype.h"
static char *cut_str(const char *start, const char *end)
{
size_t size = end - start;
return str_ndup(start, size);
}
uri_t *uri_parse(const char *str)
{
uri_t *uri = malloc(sizeof(uri_t));
if (uri == NULL)
return NULL;
memset(uri, 0, sizeof(uri_t));
const char *scheme = str;
while (*str != 0 && *str != ':')
str++;
if (*str == 0) {
uri_destroy(uri);
return NULL;
}
uri->scheme = cut_str(scheme, str);
str++;
if (*str == '/' && str[1] == '/') {
str++;
str++;
const char *authority_start = str;
char *host_or_user_info = NULL;
char *port_or_user_credential = NULL;
while (*str != 0 && *str != '?' && *str != '#' && *str != '@' &&
*str != ':' && *str != '/')
str++;
host_or_user_info = cut_str(authority_start, str);
if (*str == ':') {
str++;
const char *second_part = str;
while (*str != 0 && *str != '?' && *str != '#' &&
*str != '@' && *str != '/')
str++;
port_or_user_credential = cut_str(second_part, str);
}
if (*str == '@') {
uri->user_info = host_or_user_info;
uri->user_credential = port_or_user_credential;
str++;
const char *host_start = str;
while (*str != 0 && *str != '?' && *str != '#' &&
*str != ':' && *str != '/')
str++;
uri->host = cut_str(host_start, str);
if (*str == ':') {
str++;
const char *port_start = str;
while (*str != 0 && *str != '?' && *str != '#' && *str != '/')
str++;
uri->port = cut_str(port_start, str);
}
} else {
uri->host = host_or_user_info;
uri->port = port_or_user_credential;
}
}
const char *path_start = str;
while (*str != 0 && *str != '?' && *str != '#')
str++;
uri->path = cut_str(path_start, str);
if (*str == '?') {
str++;
const char *query_start = str;
while (*str != 0 && *str != '#')
str++;
uri->query = cut_str(query_start, str);
}
if (*str == '#') {
str++;
const char *fragment_start = str;
while (*str != 0)
str++;
uri->fragment = cut_str(fragment_start, str);
}
assert(*str == 0);
return uri;
}
errno_t uri_scheme_parse(const char *str, const char **endptr)
{
if (*str == 0) {
*endptr = str;
return ELIMIT;
}
if (!isalpha(*str)) {
*endptr = str;
return EINVAL;
}
while (isalpha(*str) || isdigit(*str) ||
*str == '+' || *str == '-' || *str == '.') {
str++;
}
*endptr = str;
return EOK;
}
bool uri_scheme_validate(const char *str)
{
const char *endptr = NULL;
if (uri_scheme_parse(str, &endptr) != EOK)
return false;
return *endptr == 0;
}
errno_t uri_percent_parse(const char *str, const char **endptr,
uint8_t *decoded)
{
*endptr = str;
if (str[0] == 0 || str[1] == 0 || str[2] == 0)
return ELIMIT;
if (str[0] != '%' || !is_hexdig(str[1]) || !is_hexdig(str[2]))
return EINVAL;
if (decoded != NULL) {
errno_t rc = str_uint8_t(str + 1, NULL, 16, true, decoded);
if (rc != EOK)
return rc;
}
*endptr = str + 3;
return EOK;
}
errno_t uri_user_info_parse(const char *str, const char **endptr)
{
while (*str != 0) {
while (is_unreserved(*str) || is_subdelim(*str) || *str == ':')
str++;
if (*str == 0)
break;
errno_t rc = uri_percent_parse(str, &str, NULL);
if (rc != EOK) {
*endptr = str;
return rc;
}
}
*endptr = str;
return EOK;
}
bool uri_user_info_validate(const char *str)
{
const char *endptr = NULL;
if (uri_user_info_parse(str, &endptr) != EOK)
return false;
return *endptr == 0;
}
errno_t uri_port_parse(const char *str, const char **endptr)
{
if (*str == 0)
return ELIMIT;
if (!isdigit(*str))
return EINVAL;
while (isdigit(*str))
str++;
*endptr = str;
return EOK;
}
bool uri_port_validate(const char *str)
{
const char *endptr = NULL;
if (uri_port_parse(str, &endptr) != EOK)
return false;
return *endptr == 0;
}
bool uri_validate(uri_t *uri)
{
if (uri->scheme && !uri_scheme_validate(uri->scheme))
return false;
if (uri->user_info && !uri_user_info_validate(uri->user_info))
return false;
if (uri->user_credential && !uri_user_info_validate(uri->user_credential))
return false;
if (uri->port && !uri_port_validate(uri->port))
return false;
return true;
}
void uri_destroy(uri_t *uri)
{
free(uri->scheme);
free(uri->user_info);
free(uri->user_credential);
free(uri->host);
free(uri->port);
free(uri->path);
free(uri->query);
free(uri->fragment);
free(uri);
}
HelenOS homepage, sources at GitHub