tvheadend/src/url.c
2014-06-01 20:58:23 +02:00

213 lines
4.5 KiB
C

/*
* Tvheadend - URL Processing
*
* Copyright (C) 2013 Adam Sutton
*
* 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 "tvheadend.h"
#include "url.h"
#include <stdlib.h>
#include <unistd.h>
#include <regex.h>
#include <string.h>
void
urlreset ( url_t *url )
{
free(url->scheme);
free(url->user);
free(url->pass);
free(url->host);
free(url->path);
free(url->query);
free(url->frag);
free(url->raw);
memset(url, 0, sizeof(*url));
}
void
urlcopy ( url_t *dst, const url_t *src )
{
dst->scheme = strdup(src->scheme);
dst->user = strdup(src->user);
dst->pass = strdup(src->pass);
dst->host = strdup(src->host);
dst->port = src->port;
dst->path = strdup(src->path);
dst->query = strdup(src->query);
dst->frag = strdup(src->frag);
dst->raw = strdup(src->raw);
}
/* Use liburiparser if available */
#if ENABLE_URIPARSER
#include <uriparser/Uri.h>
int
urlparse ( const char *str, url_t *url )
{
UriParserStateA state;
UriPathSegmentA *path;
UriUriA uri;
char *s, buf[256];
if (str == NULL || url == NULL)
return -1;
urlreset(url);
/* Parse */
state.uri = &uri;
if (uriParseUriA(&state, str) != URI_SUCCESS) {
uriFreeUriMembersA(&uri);
return -1;
}
/* Store raw */
url->raw = strdup(str);
/* Copy */
#define uri_copy(y, x)\
if (x.first) {\
size_t len = x.afterLast - x.first;\
y = strndup(x.first, len);\
}
#define uri_copy_static(y, x)\
if (x.first) {\
size_t len = x.afterLast - x.first;\
strncpy(y, x.first, len);\
y[len] = '\0';\
} else {\
y[0] = '\0';\
}
uri_copy(url->scheme, uri.scheme);
uri_copy(url->host, uri.hostText);
uri_copy(url->user, uri.userInfo);
uri_copy(url->query, uri.query);
uri_copy(url->frag, uri.fragment);
uri_copy_static(buf, uri.portText);
if (*buf)
url->port = atoi(buf);
else
url->port = 0;
path = uri.pathHead;
while (path) {
uri_copy_static(buf, path->text);
if (url->path)
url->path = realloc(url->path, strlen(url->path) + strlen(buf) + 2);
else
url->path = calloc(1, strlen(buf) + 2);
strcat(url->path, "/");
strcat(url->path, buf);
path = path->next;
}
// TODO: query/fragment
/* Split user/pass */
if (url->user) {
s = strstr(url->user, ":");
if (s) {
url->pass = strdup(s + 1);
*s = 0;
}
}
/* Cleanup */
uriFreeUriMembersA(&uri);
return 0;
}
void
urlparse_done( void )
{
}
/* Fallback to limited support */
#else /* ENABLE_URIPARSER */
/* URL regexp - I probably found this online */
// TODO: does not support ipv6
#define UC "[a-z0-9_\\-\\.!£$%^&]"
#define PC UC
#define HC "[a-z0-9\\-\\.]"
#define URL_RE "^([A-Za-z]+)://(("UC"+)(:("PC"+))?@)?("HC"+)(:([0-9]+))?(/[^\\?]*)?(.([^#]*))?(#(.*))?"
static regex_t *urlparse_exp = NULL;
int
urlparse ( const char *str, url_t *url )
{
regmatch_t m[16];
char buf[16];
if (str == NULL || url == NULL)
return -1;
urlreset(url);
/* Create regexp */
if (!urlparse_exp) {
urlparse_exp = calloc(1, sizeof(regex_t));
if (regcomp(urlparse_exp, URL_RE, REG_ICASE | REG_EXTENDED)) {
tvherror("url", "failed to compile regexp");
exit(1);
}
}
/* Execute */
if (regexec(urlparse_exp, str, ARRAY_SIZE(m), m, 0))
return -1;
/* Extract data */
#define copy(x, i)\
{\
x = strndup(str+m[i].rm_so, m[i].rm_eo - m[i].rm_so);\
}(void)0
#define copy_static(x, i)\
{\
int len = m[i].rm_eo - m[i].rm_so;\
if (len >= sizeof(x) - 1)\
len = sizeof(x) - 1;\
memcpy(x, str+m[i].rm_so, len);\
x[len] = 0;\
}(void)0
copy(url->scheme, 1);
copy(url->user, 3);
copy(url->pass, 5);
copy(url->host, 6);
copy(url->path, 9);
copy_static(buf, 8);
url->port = atoi(buf);
copy(url->query, 11);
copy(url->frag, 13);
url->raw = strdup(str);
return 0;
}
void
urlparse_done( void )
{
if (urlparse_exp) {
regfree(urlparse_exp);
free(urlparse_exp);
}
}
#endif /* ENABLE_URIPARSER */