#include #include #include #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; }