simplefiles

A lightweight C CGI web application for managing files.
git clone https://scm.kuandu.systems/git-raw/simplefiles.git
Log | Files | Refs | README | LICENSE

url.c (3171B)


      1 #include <ctype.h>
      2 #include <string.h>
      3 #include <stdlib.h>
      4 
      5 #include "url.h"
      6 #include "common.h"
      7 #include "http.h"
      8 
      9 static int hex_value(unsigned char c);
     10 
     11 char *
     12 url_encode(const char *s)
     13 {
     14 	const unsigned char *p;
     15 	char *out;
     16 	char *q;
     17 	size_t len = 0;
     18 
     19 	if (s == NULL)
     20 		return NULL;
     21 
     22 	for (p = (const unsigned char *) s; *p != '\0'; p++) {
     23 		if (isalnum(*p) ||
     24 		    *p == '-' ||
     25 		    *p == '_' ||
     26 		    *p == '.' ||
     27 		    *p == '~') {
     28 			len++;
     29 		} else {
     30 			len += 3;
     31 		}
     32 	}
     33 
     34 	out = malloc(len + 1);
     35 	if (out == NULL)
     36 		return NULL;
     37 
     38 	q = out;
     39 
     40 	for (p = (const unsigned char *) s; *p != '\0'; p++) {
     41 		if (isalnum(*p) ||
     42 		    *p == '-' ||
     43 		    *p == '_' ||
     44 		    *p == '.' ||
     45 		    *p == '~') {
     46 			*q++ = (char) *p;
     47 		} else {
     48 			static const char hex[] = "0123456789ABCDEF";
     49 
     50 			*q++ = '%';
     51 			*q++ = hex[*p >> 4];
     52 			*q++ = hex[*p & 0x0f];
     53 		}
     54 	}
     55 
     56 	*q = '\0';
     57 
     58 	return out;
     59 }
     60 
     61 int
     62 url_decode(char *s)
     63 {
     64 	char *src;
     65 	char *dst;
     66 
     67 	src = s;
     68 	dst = s;
     69 
     70 	while (*src != '\0') {
     71 		unsigned char c;
     72 
     73 		if (*src == '%') {
     74 			int hi;
     75 			int lo;
     76 
     77 			if (src[1] == '\0' || src[2] == '\0')
     78 				return -1;
     79 
     80 			hi = hex_value((unsigned char) src[1]);
     81 			lo = hex_value((unsigned char) src[2]);
     82 
     83 			if (hi == -1 || lo == -1)
     84 				return -1;
     85 
     86 			c = (unsigned char) ((hi << 4) | lo);
     87 			src += 3;
     88 		} else if (*src == '+') {
     89 			c = ' ';
     90 			src++;
     91 		} else {
     92 			c = (unsigned char) *src++;
     93 		}
     94 
     95 		if (c == '\0')
     96 			return -1;
     97 
     98 		*dst++ = (char) c;
     99 	}
    100 
    101 	*dst = '\0';
    102 
    103 	return 0;
    104 }
    105 
    106 static int
    107 hex_value(unsigned char c)
    108 {
    109 	if (c >= '0' && c <= '9')
    110 		return c - '0';
    111 
    112 	if (c >= 'a' && c <= 'f')
    113 		return c - 'a' + 10;
    114 
    115 	if (c >= 'A' && c <= 'F')
    116 		return c - 'A' + 10;
    117 
    118 	return -1;
    119 }
    120 
    121 int
    122 query_param(const char *query,
    123     const char *name,
    124     char *value,
    125     size_t value_len)
    126 {
    127 	const char *p;
    128 	const char *eq;
    129 	const char *field_end;
    130 	size_t name_len;
    131 	size_t encoded_len;
    132 	char *encoded;
    133 	int found = 0;
    134 
    135 	if (query == NULL || name == NULL ||
    136 	    value == NULL || value_len == 0)
    137 		return -1;
    138 
    139 	name_len = strlen(name);
    140 
    141 	p = query;
    142 
    143 	while (*p != '\0') {
    144 		const char *field_start = p;
    145 		size_t field_len;
    146 		size_t key_len;
    147 
    148 		field_end = strchr(p, '&');
    149 		if (field_end == NULL)
    150 			field_end = p + strlen(p);
    151 
    152 		field_len = (size_t)(field_end - field_start);
    153 
    154 		eq = memchr(field_start, '=', field_len);
    155 
    156 		if (eq != NULL) {
    157 			key_len = (size_t)(eq - field_start);
    158 
    159 			if (key_len == name_len &&
    160 			    memcmp(field_start, name, name_len) == 0) {
    161 
    162 				/* Reject duplicate parameters. */
    163 				if (found)
    164 					return -1;
    165 
    166 				encoded_len = field_len - key_len - 1;
    167 
    168 				/*
    169 				 * Need a writable, NUL-terminated copy because
    170 				 * url_decode() works in-place.
    171 				 */
    172 				encoded = malloc(encoded_len + 1);
    173 				if (encoded == NULL)
    174 					return -1;
    175 
    176 				memcpy(encoded, eq + 1, encoded_len);
    177 				encoded[encoded_len] = '\0';
    178 
    179 				if (url_decode(encoded) == -1) {
    180 					free(encoded);
    181 					return -1;
    182 				}
    183 
    184 				if (strlen(encoded) >= value_len) {
    185 					free(encoded);
    186 					return -1;
    187 				}
    188 
    189 				memcpy(value, encoded, strlen(encoded) + 1);
    190 				free(encoded);
    191 
    192 				found = 1;
    193 			}
    194 		}
    195 
    196 		if (*field_end == '\0')
    197 			break;
    198 
    199 		p = field_end + 1;
    200 	}
    201 
    202 	return found ? 0 : 1;
    203 }