summary refs log blame commit diff stats
path: root/encode.c
blob: 480613632cd3ff5179a84e8cc0df8a028ae09d5f (plain) (tree)
1
2
3
4
5
6





                   
































































































































































































































































































































                                                                                 









                                                                       



                                 


                                                         


                                        
                                    


                                             














                                                         




                                                                                             





                                                
                                               

                 
                                                                                     


                                    


















                                                                                    
                                                          







                                                        




                                                                                          
                         
                                                                               


                                            



                       
                              






                                        



                                                                   


                          
                              






                                        



                                                                         



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