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 }