summary refs log tree commit diff stats
path: root/encode.c
diff options
context:
space:
mode:
Diffstat (limited to 'encode.c')
-rw-r--r--encode.c362
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;