/* This file is part of Pies
Copyright (C) 2009 Sergey Poznyakoff
Pies 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, or (at your option)
any later version.
Pies 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 Pies. If not, see . */
#ifdef HAVE_CONFIG_H
# include
#endif
#include "pies.h"
#include
#include
#include
/* proto://[user[:password]@][host[:port]/]path[;arg=str[;arg=str...]
*/
static int
alloc_string_len (char **sptr, const char *start, size_t len)
{
*sptr = malloc (len + 1);
if (!*sptr)
return 1;
memcpy (*sptr, start, len);
(*sptr)[len] = 0;
return 0;
}
static int
alloc_string (char **sptr, const char *start, const char *end)
{
size_t len = end ? end - start : strlen (start);
return alloc_string_len (sptr, start, len);
}
static int
url_parse_args (struct pies_url *url, char **str)
{
struct wordsplit ws;
ws.ws_delim = ";";
if (wordsplit (*str, &ws, WRDSF_NOVAR | WRDSF_NOCMD | WRDSF_DELIM))
return 1;
url->argc = ws.ws_wordc;
url->argv = ws.ws_wordv;
return 0;
}
static int
url_parse_path (struct pies_url *url, char **str)
{
char *p;
p = strchr (*str, ';');
if (!p)
p = *str + strlen (*str);
if (alloc_string(&url->path, *str, p))
return 1;
*str = p;
if (*p)
++ * str;
return url_parse_args (url, str);
}
/* On input str points at the beginning of host part */
static int
url_parse_host (struct pies_url *url, char **str)
{
char *s = *str;
size_t len = strcspn (s, "/:");
if (s[len] == ':')
{
char *q;
unsigned long n = strtoul (s + len + 1, &q, 10);
if ((*q && !strchr("/;:", *q)) || n > USHRT_MAX)
return 1;
url->port = n;
*str = q + strcspn(q, "/");
}
else
*str = s + len;
if (alloc_string_len (&url->host, s, len))
return 1;
if (**str)
{
++*str;
return url_parse_path (url, str);
}
return 0;
}
/* On input str points past the mech:// part */
static int
url_parse_user (struct pies_url *url, char **str)
{
size_t len = strcspn (*str, ":;@/");
char *p = *str + len;
switch (*p)
{
case ';':
case ':':
len = strcspn (p + 1, "@/:");
if (p[len+1] == '@')
{
if (alloc_string_len(&url->passwd, p + 1, len))
return 1;
if (alloc_string (&url->user, *str, p))
return 1;
*str = p + len + 2;
}
break;
case '@':
if (alloc_string (&url->user, *str, p))
return 1;
url->passwd = NULL;
*str = p + 1;
}
return url_parse_host (url, str);
}
static int
url_parse_proto (struct pies_url *url, const char *str)
{
char *p;
if (!str)
{
errno = EINVAL;
return 1;
}
p = strchr (str, ':');
if (!p)
{
errno = EINVAL;
return 1;
}
alloc_string (&url->proto, str, p);
/* Skip slashes */
for (p++; *p == '/'; p++)
;
return url_parse_user (url, &p);
}
void
pies_url_destroy (struct pies_url **purl)
{
int i;
struct pies_url *url = *purl;
free (url->string);
free (url->proto);
free (url->host);
free (url->path);
free (url->user);
free (url->passwd);
for (i = 0; i < url->argc; i++)
free (url->argv[i]);
free (url->argv);
free(url);
*purl = NULL;
}
int
pies_url_create (struct pies_url **purl, const char *str)
{
int rc;
struct pies_url *url;
url = malloc (sizeof (*url));
if (!url)
return 1;
memset (url, 0, sizeof(*url));
rc = url_parse_proto (url, str);
if (rc)
pies_url_destroy (&url);
else
{
url->string = strdup (str);
*purl = url;
}
return rc;
}
const char *
pies_url_get_arg (struct pies_url *url, const char *argname)
{
int i;
size_t arglen = strlen (argname);
for (i = 0; i < url->argc; i++)
{
size_t len = strcspn (url->argv[i], "=");
if (len == arglen && memcmp (url->argv[i], argname, arglen) == 0)
return url->argv[i] + len + 1;
}
return NULL;
}