1 /* 2 * uhttpd - Tiny single-threaded httpd 3 * 4 * Copyright (C) 2010-2013 Jo-Philipp Wich <xm@subsignal.org> 5 * Copyright (C) 2013 Felix Fietkau <nbd@openwrt.org> 6 * 7 * Permission to use, copy, modify, and/or distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 #include "uhttpd.h" 21 22 uint8_t chartypes[256] = { 23 /* 00..07 */ CT_CTL, CT_CTL, CT_CTL, CT_CTL, CT_CTL, CT_CTL, CT_CTL, CT_CTL, 24 /* 08..0f */ CT_CTL, CT_WSP, CT_CTL, CT_CTL, CT_CTL, CT_CTL, CT_CTL, CT_CTL, 25 /* 10..17 */ CT_CTL, CT_CTL, CT_CTL, CT_CTL, CT_CTL, CT_CTL, CT_CTL, CT_CTL, 26 /* 18..1f */ CT_CTL, CT_CTL, CT_CTL, CT_CTL, CT_CTL, CT_CTL, CT_CTL, CT_CTL, 27 /* 20..27 */ CT_WSP, CT_VCHAR, CT_VDELIM, CT_VCHAR, CT_VCHAR, CT_VCHAR, CT_VCHAR, CT_VCHAR, 28 /* 28..2f */ CT_VDELIM, CT_VDELIM, CT_VCHAR, CT_VCHAR, CT_VDELIM, CT_VCHAR, CT_VCHAR, CT_VDELIM, 29 /* 30..37 */ CT_XDIGIT, CT_XDIGIT, CT_XDIGIT, CT_XDIGIT, CT_XDIGIT, CT_XDIGIT, CT_XDIGIT, CT_XDIGIT, 30 /* 38..3f */ CT_XDIGIT, CT_XDIGIT, CT_VDELIM, CT_VDELIM, CT_VDELIM, CT_VDELIM, CT_VDELIM, CT_VDELIM, 31 /* 40..47 */ CT_VDELIM, CT_XALPHA, CT_XALPHA, CT_XALPHA, CT_XALPHA, CT_XALPHA, CT_XALPHA, CT_VALPHA, 32 /* 48..4f */ CT_VALPHA, CT_VALPHA, CT_VALPHA, CT_VALPHA, CT_VALPHA, CT_VALPHA, CT_VALPHA, CT_VALPHA, 33 /* 50..57 */ CT_VALPHA, CT_VALPHA, CT_VALPHA, CT_VALPHA, CT_VALPHA, CT_VALPHA, CT_VALPHA, CT_VALPHA, 34 /* 58..5f */ CT_VALPHA, CT_VALPHA, CT_VALPHA, CT_VDELIM, CT_VDELIM, CT_VDELIM, CT_VCHAR, CT_VCHAR, 35 /* 60..67 */ CT_VCHAR, CT_XALPHA, CT_XALPHA, CT_XALPHA, CT_XALPHA, CT_XALPHA, CT_XALPHA, CT_VALPHA, 36 /* 68..6f */ CT_VALPHA, CT_VALPHA, CT_VALPHA, CT_VALPHA, CT_VALPHA, CT_VALPHA, CT_VALPHA, CT_VALPHA, 37 /* 70..77 */ CT_VALPHA, CT_VALPHA, CT_VALPHA, CT_VALPHA, CT_VALPHA, CT_VALPHA, CT_VALPHA, CT_VALPHA, 38 /* 78..7f */ CT_VALPHA, CT_VALPHA, CT_VALPHA, CT_VDELIM, CT_VCHAR, CT_VDELIM, CT_VCHAR, CT_CTL, 39 /* 80..ff: no flags */ 40 }; 41 42 bool uh_use_chunked(struct client *cl) 43 { 44 if (cl->request.version != UH_HTTP_VER_1_1) 45 return false; 46 47 if (cl->request.method == UH_HTTP_MSG_HEAD || cl->request.method == UH_HTTP_MSG_OPTIONS) 48 return false; 49 50 /* RFC2616 10.2.5, 10.3.5 */ 51 if (cl->http_code == 204 || cl->http_code == 304) 52 return false; 53 54 return !cl->request.disable_chunked; 55 } 56 57 void uh_chunk_write(struct client *cl, const void *data, int len) 58 { 59 bool chunked = uh_use_chunked(cl); 60 61 if (cl->state == CLIENT_STATE_CLEANUP) 62 return; 63 64 uloop_timeout_set(&cl->timeout, conf.network_timeout * 1000); 65 if (chunked) 66 ustream_printf(cl->us, "%X\r\n", len); 67 ustream_write(cl->us, data, len, true); 68 if (chunked) 69 ustream_printf(cl->us, "\r\n"); 70 } 71 72 void uh_chunk_vprintf(struct client *cl, const char *format, va_list arg) 73 { 74 char buf[256]; 75 va_list arg2; 76 int len; 77 78 if (cl->state != CLIENT_STATE_DATA && 79 cl->state != CLIENT_STATE_DONE) 80 return; 81 82 uloop_timeout_set(&cl->timeout, conf.network_timeout * 1000); 83 if (!uh_use_chunked(cl)) { 84 ustream_vprintf(cl->us, format, arg); 85 return; 86 } 87 88 va_copy(arg2, arg); 89 len = vsnprintf(buf, sizeof(buf), format, arg2); 90 va_end(arg2); 91 92 ustream_printf(cl->us, "%X\r\n", len); 93 if (len < sizeof(buf)) 94 ustream_write(cl->us, buf, len, true); 95 else 96 ustream_vprintf(cl->us, format, arg); 97 ustream_printf(cl->us, "\r\n"); 98 } 99 100 void uh_chunk_printf(struct client *cl, const char *format, ...) 101 { 102 va_list arg; 103 104 va_start(arg, format); 105 uh_chunk_vprintf(cl, format, arg); 106 va_end(arg); 107 } 108 109 void uh_chunk_eof(struct client *cl) 110 { 111 if (!uh_use_chunked(cl)) 112 return; 113 114 if (cl->state != CLIENT_STATE_DATA && 115 cl->state != CLIENT_STATE_DONE) 116 return; 117 118 ustream_printf(cl->us, "\r\n\r\n"); 119 } 120 121 /* blen is the size of buf; slen is the length of src. The input-string need 122 ** not be null-terminated. The output string is always null-terminated when 123 ** blen > 0. Returns the length of the decoded string (excluding the trailing 124 ** NUL), -1 on buffer overflow, -2 on malformed string. */ 125 int uh_urldecode(char *buf, int blen, const char *src, int slen) 126 { 127 int i; 128 int len = 0; 129 130 #define hex(x) \ 131 (((x) <= '9') ? ((x) - '') : \ 132 (((x) <= 'F') ? ((x) - 'A' + 10) : \ 133 ((x) - 'a' + 10))) 134 135 if (blen <= 0) 136 return -1; 137 138 for (i = 0; (i < slen) && (len < blen - 1); i++) 139 { 140 if (src[i] != '%') { 141 buf[len++] = src[i]; 142 continue; 143 } 144 145 if (i + 2 >= slen || 146 !(chartypes[(uint8_t)src[i + 1]] & CT_HEXDIG) || 147 !(chartypes[(uint8_t)src[i + 2]] & CT_HEXDIG)) 148 return -2; 149 150 buf[len++] = (char)(16 * hex(src[i+1]) + hex(src[i+2])); 151 i += 2; 152 } 153 buf[len] = 0; 154 155 return (i == slen) ? len : -1; 156 } 157 158 /* blen is the size of buf; slen is the length of src. The input-string need 159 ** not be, and the output string will not be, null-terminated. Returns the 160 ** length of the encoded string, or -1 on error (buffer overflow) */ 161 int uh_urlencode(char *buf, int blen, const char *src, int slen) 162 { 163 int i; 164 int len = 0; 165 static const char hex[] = "0123456789abcdef"; 166 167 for (i = 0; (i < slen) && (len < blen); i++) 168 { 169 if( (chartypes[(uint8_t)src[i]] & (CT_ALPHA | CT_DIGIT)) || (src[i] == '-') || (src[i] == '_') || 170 (src[i] == '.') || (src[i] == '~') ) 171 { 172 buf[len++] = src[i]; 173 } 174 else if ((len+3) <= blen) 175 { 176 buf[len++] = '%'; 177 buf[len++] = hex[(src[i] >> 4) & 15]; 178 buf[len++] = hex[ src[i] & 15]; 179 } 180 else 181 { 182 len = -1; 183 break; 184 } 185 } 186 187 return (i == slen) ? len : -1; 188 } 189 190 int uh_b64decode(char *buf, int blen, const void *src, int slen) 191 { 192 const unsigned char *str = src; 193 unsigned int cout = 0; 194 unsigned int cin = 0; 195 int len = 0; 196 int i = 0; 197 198 for (i = 0; (i < slen) && (str[i] != 0); i++) 199 { 200 cin = str[i]; 201 202 if ((cin >= '') && (cin <= '9')) 203 cin = cin - '' + 52; 204 else if ((cin >= 'A') && (cin <= 'Z')) 205 cin = cin - 'A'; 206 else if ((cin >= 'a') && (cin <= 'z')) 207 cin = cin - 'a' + 26; 208 else if (cin == '+') 209 cin = 62; 210 else if (cin == '/') 211 cin = 63; 212 else if (cin == '=') 213 cin = 0; 214 else 215 continue; 216 217 cout = (cout << 6) | cin; 218 219 if ((i % 4) != 3) 220 continue; 221 222 if ((len + 3) >= blen) 223 break; 224 225 buf[len++] = (char)(cout >> 16); 226 buf[len++] = (char)(cout >> 8); 227 buf[len++] = (char)(cout); 228 } 229 230 buf[len++] = 0; 231 return len; 232 } 233 234 bool uh_path_match(const char *prefix, const char *url) 235 { 236 int len = strlen(prefix); 237 238 /* A prefix of "/" will - by definition - match any url */ 239 if (prefix[0] == '/' && len == 1) 240 return true; 241 242 if (strncmp(url, prefix, len) != 0) 243 return false; 244 245 return url[len] == '/' || url[len] == '?' || url[len] == 0; 246 } 247 248 char *uh_split_header(char *str, size_t len) 249 { 250 char *val, *end; 251 252 val = memchr(str, ':', len); 253 254 if (!val) 255 return NULL; 256 257 *val++ = 0; 258 259 while (chartypes[(uint8_t)*val] & CT_WSP) 260 val++; 261 262 for (end = str + len - 1; end > val && (chartypes[(uint8_t)*end] & CT_WSP); end--) 263 ; 264 265 *(end + 1) = 0; 266 267 return val; 268 } 269 270 bool uh_addr_rfc1918(struct uh_addr *addr) 271 { 272 uint32_t a; 273 274 if (addr->family != AF_INET) 275 return false; 276 277 a = htonl(addr->in.s_addr); 278 return ((a >= 0x0A000000) && (a <= 0x0AFFFFFF)) || 279 ((a >= 0xAC100000) && (a <= 0xAC1FFFFF)) || 280 ((a >= 0xC0A80000) && (a <= 0xC0A8FFFF)); 281 } 282 283 284 static bool is_html_special_char(char c) 285 { 286 switch (c) 287 { 288 case 0x22: 289 case 0x26: 290 case 0x27: 291 case 0x3C: 292 case 0x3E: 293 return true; 294 295 default: 296 return false; 297 } 298 } 299 300 char *uh_htmlescape(const char *str) 301 { 302 size_t i, len; 303 char *p, *copy; 304 305 for (i = 0, len = 1; str[i]; i++) 306 if (is_html_special_char(str[i])) 307 len += 6; /* &#x??; */ 308 else 309 len++; 310 311 copy = calloc(1, len); 312 313 if (!copy) 314 return NULL; 315 316 for (i = 0, p = copy; str[i]; i++) 317 if (is_html_special_char(str[i])) 318 p += sprintf(p, "&#x%02x;", (unsigned int)str[i]); 319 else 320 *p++ = str[i]; 321 322 return copy; 323 } 324
This page was automatically generated by LXR 0.3.1. • OpenWrt