#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "yuri.h"
#include "types.h"
static int
pct_encode_authority_user(char **str, size_t *plen, const char *raw)
{
int i;
char *ret;
char *buf;
char *ptr;
size_t len;
len = 0;
ptr = raw;
while (*ptr != '\0') {
if (_is_unreserved(*ptr) || _is_sub_delim(*ptr) || *ptr == ':')
len++;
else
len += 3;
ptr++;
}
if (len == 0)
return 0;
buf = malloc(len+1);
if (buf == NULL)
return -1;
i = 0;
ptr = raw;
while (*ptr != '\0') {
if (_is_unreserved(*ptr) || _is_sub_delim(*ptr) || *ptr == ':') {
buf[i] = *ptr;
i++;
} else {
buf[i] = '%';
sprintf(buf+i+1, "%X", (unsigned int)*ptr);
i += 3;
}
ptr++;
}
buf[i] = '\0';
ret = realloc(*str, (*plen)+len);
if (ret == NULL) {
free(buf);
return -1;
}
(*plen) += len;
*str = ret;
strlcat(*str, buf, *plen);
free(buf);
return 0;
}
static int
pct_encode_authority_host(char **str, size_t *plen, const char *raw)
{
int i;
char *ret;
char *buf;
char *ptr;
size_t len;
len = 0;
ptr = raw;
while (*ptr != '\0') {
if (_is_unreserved(*ptr) || _is_sub_delim(*ptr))
len++;
else
len += 3;
ptr++;
}
if (len == 0)
return 0;
buf = malloc(len+1);
if (buf == NULL)
return -1;
i = 0;
ptr = raw;
while (*ptr != '\0') {
if (_is_unreserved(*ptr) || _is_sub_delim(*ptr)) {
buf[i] = *ptr;
i++;
} else {
buf[i] = '%';
sprintf(buf+i+1, "%X", (unsigned int)*ptr);
i += 3;
}
ptr++;
}
buf[i] = '\0';
ret = realloc(*str, (*plen)+len);
if (ret == NULL) {
free(buf);
return -1;
}
(*plen) += len;
*str = ret;
strlcat(*str, buf, *plen);
free(buf);
return 0;
}
static int
pct_encode_segment(char **str, size_t *plen, char *raw)
{
int i;
char *ret;
char *buf;
char *ptr;
size_t len;
len = 0;
ptr = raw;
while (*ptr != '\0') {
if (_is_segment(*ptr))
len++;
else
len += 3;
ptr++;
}
if (len == 0)
return 0;
buf = malloc(len+1);
if (buf == NULL)
return -1;
i = 0;
ptr = raw;
while (*ptr != '\0') {
if (_is_segment(*ptr)) {
buf[i] = *ptr;
i++;
} else {
buf[i] = '%';
sprintf(buf+i+1, "%X", (unsigned int)*ptr);
i += 3;
}
ptr++;
}
buf[i] = '\0';
ret = realloc(*str, (*plen)+len);
if (ret == NULL) {
free(buf);
return -1;
}
(*plen) += len;
*str = ret;
strlcat(*str, buf, *plen);
free(buf);
return 0;
}
static int
pct_encode_segment_nc(char **str, size_t *plen, char *raw)
{
int i;
char *ret;
char *buf;
char *ptr;
size_t len;
len = 0;
ptr = raw;
while (*ptr != '\0') {
if (_is_segment_nc(*ptr))
len++;
else
len += 3;
ptr++;
}
if (len == 0)
return 0;
buf = malloc(len+1);
if (buf == NULL)
return -1;
i = 0;
ptr = raw;
while (*ptr != '\0') {
if (_is_segment_nc(*ptr)) {
buf[i] = *ptr;
i++;
} else {
buf[i] = '%';
sprintf(buf+i+1, "%X", (unsigned int)*ptr);
i += 3;
}
ptr++;
}
buf[i] = '\0';
ret = realloc(*str, (*plen)+len);
if (ret == NULL) {
free(buf);
return -1;
}
(*plen) += len;
*str = ret;
strlcat(*str, buf, *plen);
free(buf);
return 0;
}
static int
pct_encode_query(char **str, size_t *plen, char *raw)
{
int i;
char *ret;
char *buf;
char *ptr;
size_t len;
len = 0;
ptr = raw;
while (*ptr != '\0') {
if (_is_pchar(*ptr) || *ptr == '/' || *ptr == '?')
len++;
else
len += 3;
ptr++;
}
if (len == 0)
return 0;
buf = malloc(len+1);
if (buf == NULL)
return -1;
i = 0;
ptr = raw;
while (*ptr != '\0') {
if (_is_pchar(*ptr) || *ptr == '/' || *ptr == '?') {
buf[i] = *ptr;
i++;
} else {
buf[i] = '%';
sprintf(buf+i+1, "%X", (unsigned int)*ptr);
i += 3;
}
ptr++;
}
buf[i] = '\0';
ret = realloc(*str, (*plen)+len);
if (ret == NULL) {
free(buf);
return -1;
}
(*plen) += len;
*str = ret;
strlcat(*str, buf, *plen);
free(buf);
return 0;
}
static int
pct_encode_fragment(char **str, size_t *plen, char *raw)
{
int i;
char *ret;
char *buf;
char *ptr;
size_t len;
len = 0;
ptr = raw;
while (*ptr != '\0') {
if (_is_pchar(*ptr) || *ptr == '/' || *ptr == '?')
len++;
else
len += 3;
ptr++;
}
if (len == 0)
return 0;
buf = malloc(len+1);
if (buf == NULL)
return -1;
i = 0;
ptr = raw;
while (*ptr != '\0') {
if (_is_pchar(*ptr) || *ptr == '/' || *ptr == '?') {
buf[i] = *ptr;
i++;
} else {
buf[i] = '%';
sprintf(buf+i+1, "%X", (unsigned int)*ptr);
i += 3;
}
ptr++;
}
buf[i] = '\0';
ret = realloc(*str, (*plen)+len);
if (ret == NULL) {
free(buf);
return -1;
}
(*plen) += len;
*str = ret;
strlcat(*str, buf, *plen);
free(buf);
return 0;
}
char *
uri_encode(struct uri *u)
{
int i;
char *ret;
char *dup;
char portbuf[6]; /* highest port number is 5 digits minus \0 */
size_t len;
len = 1; /* \0 */
ret = realloc(NULL, len);
if (ret == NULL)
return NULL;
ret[0] = '\0';
if (u->scheme) {
len += strlen(u->scheme)+1; /* scheme: */
dup = realloc(ret, len);
if (ret == NULL) {
free(ret);
return NULL;
}
ret = dup;
strlcat(ret, u->scheme, len);
strlcat(ret, ":", len);
}
if (u->authority.host) {
len += 2; /* // */
dup = realloc(ret, len);
if (dup == NULL) {
free(ret);
return NULL;
}
ret = dup;
strlcat(ret, "//", len);
if (u->authority.user) {
len += strlen(u->authority.user);
if (pct_encode_authority_user(&ret, &len, u->authority.user) == -1) {
free(ret);
return NULL;
}
len++; /* @ */
dup = realloc(ret, len);
if (dup == NULL) {
free(ret);
return NULL;
}
ret = dup;
strlcat(ret, "@", len);
}
if (pct_encode_authority_host(&ret, &len, u->authority.host) == -1) {
free(ret);
return NULL;
}
if (u->authority.port) {
memset(portbuf, 0, sizeof(portbuf));
/* snprintf is to be replaced in the future */
snprintf(portbuf, sizeof(portbuf), "%d", u->authority.port);
len += strlen(portbuf)+1; /* :port */
dup = realloc(ret, len);
if (dup == NULL) {
free(ret);
return NULL;
}
ret = dup;
strlcat(ret, ":", len);
strlcat(ret, portbuf, len);
}
}
if (u->npath != 0) {
for (i = 0; i < u->npath; i++) {
if (i != 0 || u->authority.host) {
len += 1; /* / */
dup = realloc(ret, len);
if (dup == NULL) {
free(ret);
return NULL;
}
ret = dup;
strlcat(ret, "/", len);
if (pct_encode_segment_nc(&ret, &len, u->path[i]) == -1) {
free(ret);
return NULL;
}
continue;
}
if (pct_encode_segment(&ret, &len, u->path[i]) == -1) {
free(ret);
return NULL;
}
}
}
if (u->query) {
len++; /* ? */
dup = realloc(ret, len);
if (dup == NULL) {
free(ret);
return NULL;
}
ret = dup;
strlcat(ret, "?", len);
if (pct_encode_query(&ret, &len, u->query) == -1) {
free(ret);
return NULL;
}
}
if (u->fragment) {
len++; /* # */
dup = realloc(ret, len);
if (dup == NULL) {
free(ret);
return NULL;
}
ret = dup;
strlcat(ret, "#", len);
if (pct_encode_fragment(&ret, &len, u->fragment) == -1) {
free(ret);
return NULL;
}
}
return ret;
}