diff options
Diffstat (limited to 'encode.c')
-rw-r--r-- | encode.c | 362 |
1 files changed, 344 insertions, 18 deletions
diff --git a/encode.c b/encode.c index 75b7f90..4806136 100644 --- a/encode.c +++ b/encode.c @@ -4,9 +4,327 @@ #include "yuri.h" -/* - * TODO: percent encode appropriate characters - */ +#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) { @@ -46,23 +364,24 @@ uri_encode(struct uri *u) 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, u->authority.user, len); + strlcat(ret, "@", len); } - len += strlen(u->authority.host); - dup = realloc(ret, len); - if (dup == NULL) { + if (pct_encode_authority_host(&ret, &len, u->authority.host) == -1) { free(ret); return NULL; } - ret = dup; - strlcat(ret, u->authority.host, len); if (u->authority.port) { memset(portbuf, 0, sizeof(portbuf)); @@ -91,20 +410,21 @@ uri_encode(struct uri *u) } ret = dup; strlcat(ret, "/", len); + if (pct_encode_segment_nc(&ret, &len, u->path[i]) == -1) { + free(ret); + return NULL; + } + continue; } - len += strlen(u->path[i]); - dup = realloc(ret, len); - if (dup == NULL) { + if (pct_encode_segment(&ret, &len, u->path[i]) == -1) { free(ret); return NULL; } - ret = dup; - strlcat(ret, u->path[i], len); } } if (u->query) { - len += strlen(u->query)+1; /* ?query */ + len++; /* ? */ dup = realloc(ret, len); if (dup == NULL) { free(ret); @@ -112,11 +432,14 @@ uri_encode(struct uri *u) } ret = dup; strlcat(ret, "?", len); - strlcat(ret, u->query, len); + if (pct_encode_query(&ret, &len, u->query) == -1) { + free(ret); + return NULL; + } } if (u->fragment) { - len += strlen(u->fragment)+1; /* #fragment */ + len++; /* # */ dup = realloc(ret, len); if (dup == NULL) { free(ret); @@ -124,7 +447,10 @@ uri_encode(struct uri *u) } ret = dup; strlcat(ret, "#", len); - strlcat(ret, u->fragment, len); + if (pct_encode_fragment(&ret, &len, u->fragment) == -1) { + free(ret); + return NULL; + } } return ret; |