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 <ctype.h> 21 #include "uhttpd.h" 22 23 bool uh_use_chunked(struct client *cl) 24 { 25 if (cl->request.version != UH_HTTP_VER_1_1) 26 return false; 27 28 if (cl->request.method == UH_HTTP_MSG_HEAD || cl->request.method == UH_HTTP_MSG_OPTIONS) 29 return false; 30 31 /* RFC2616 10.2.5, 10.3.5 */ 32 if (cl->http_code == 204 || cl->http_code == 304) 33 return false; 34 35 return !cl->request.disable_chunked; 36 } 37 38 void uh_chunk_write(struct client *cl, const void *data, int len) 39 { 40 bool chunked = uh_use_chunked(cl); 41 42 if (cl->state == CLIENT_STATE_CLEANUP) 43 return; 44 45 uloop_timeout_set(&cl->timeout, conf.network_timeout * 1000); 46 if (chunked) 47 ustream_printf(cl->us, "%X\r\n", len); 48 ustream_write(cl->us, data, len, true); 49 if (chunked) 50 ustream_printf(cl->us, "\r\n"); 51 } 52 53 void uh_chunk_vprintf(struct client *cl, const char *format, va_list arg) 54 { 55 char buf[256]; 56 va_list arg2; 57 int len; 58 59 if (cl->state != CLIENT_STATE_DATA && 60 cl->state != CLIENT_STATE_DONE) 61 return; 62 63 uloop_timeout_set(&cl->timeout, conf.network_timeout * 1000); 64 if (!uh_use_chunked(cl)) { 65 ustream_vprintf(cl->us, format, arg); 66 return; 67 } 68 69 va_copy(arg2, arg); 70 len = vsnprintf(buf, sizeof(buf), format, arg2); 71 va_end(arg2); 72 73 ustream_printf(cl->us, "%X\r\n", len); 74 if (len < sizeof(buf)) 75 ustream_write(cl->us, buf, len, true); 76 else 77 ustream_vprintf(cl->us, format, arg); 78 ustream_printf(cl->us, "\r\n"); 79 } 80 81 void uh_chunk_printf(struct client *cl, const char *format, ...) 82 { 83 va_list arg; 84 85 va_start(arg, format); 86 uh_chunk_vprintf(cl, format, arg); 87 va_end(arg); 88 } 89 90 void uh_chunk_eof(struct client *cl) 91 { 92 if (!uh_use_chunked(cl)) 93 return; 94 95 if (cl->state != CLIENT_STATE_DATA && 96 cl->state != CLIENT_STATE_DONE) 97 return; 98 99 ustream_printf(cl->us, "\r\n\r\n"); 100 } 101 102 /* blen is the size of buf; slen is the length of src. The input-string need 103 ** not be, and the output string will not be, null-terminated. Returns the 104 ** length of the decoded string, -1 on buffer overflow, -2 on malformed string. */ 105 int uh_urldecode(char *buf, int blen, const char *src, int slen) 106 { 107 int i; 108 int len = 0; 109 110 #define hex(x) \ 111 (((x) <= '9') ? ((x) - '') : \ 112 (((x) <= 'F') ? ((x) - 'A' + 10) : \ 113 ((x) - 'a' + 10))) 114 115 for (i = 0; (i < slen) && (len < blen); i++) 116 { 117 if (src[i] != '%') { 118 buf[len++] = src[i]; 119 continue; 120 } 121 122 if (i + 2 >= slen || !isxdigit(src[i + 1]) || !isxdigit(src[i + 2])) 123 return -2; 124 125 buf[len++] = (char)(16 * hex(src[i+1]) + hex(src[i+2])); 126 i += 2; 127 } 128 buf[len] = 0; 129 130 return (i == slen) ? len : -1; 131 } 132 133 /* blen is the size of buf; slen is the length of src. The input-string need 134 ** not be, and the output string will not be, null-terminated. Returns the 135 ** length of the encoded string, or -1 on error (buffer overflow) */ 136 int uh_urlencode(char *buf, int blen, const char *src, int slen) 137 { 138 int i; 139 int len = 0; 140 static const char hex[] = "0123456789abcdef"; 141 142 for (i = 0; (i < slen) && (len < blen); i++) 143 { 144 if( isalnum(src[i]) || (src[i] == '-') || (src[i] == '_') || 145 (src[i] == '.') || (src[i] == '~') ) 146 { 147 buf[len++] = src[i]; 148 } 149 else if ((len+3) <= blen) 150 { 151 buf[len++] = '%'; 152 buf[len++] = hex[(src[i] >> 4) & 15]; 153 buf[len++] = hex[ src[i] & 15]; 154 } 155 else 156 { 157 len = -1; 158 break; 159 } 160 } 161 162 return (i == slen) ? len : -1; 163 } 164 165 int uh_b64decode(char *buf, int blen, const void *src, int slen) 166 { 167 const unsigned char *str = src; 168 unsigned int cout = 0; 169 unsigned int cin = 0; 170 int len = 0; 171 int i = 0; 172 173 for (i = 0; (i <= slen) && (str[i] != 0); i++) 174 { 175 cin = str[i]; 176 177 if ((cin >= '') && (cin <= '9')) 178 cin = cin - '' + 52; 179 else if ((cin >= 'A') && (cin <= 'Z')) 180 cin = cin - 'A'; 181 else if ((cin >= 'a') && (cin <= 'z')) 182 cin = cin - 'a' + 26; 183 else if (cin == '+') 184 cin = 62; 185 else if (cin == '/') 186 cin = 63; 187 else if (cin == '=') 188 cin = 0; 189 else 190 continue; 191 192 cout = (cout << 6) | cin; 193 194 if ((i % 4) != 3) 195 continue; 196 197 if ((len + 3) >= blen) 198 break; 199 200 buf[len++] = (char)(cout >> 16); 201 buf[len++] = (char)(cout >> 8); 202 buf[len++] = (char)(cout); 203 } 204 205 buf[len++] = 0; 206 return len; 207 } 208 209 bool uh_path_match(const char *prefix, const char *url) 210 { 211 int len = strlen(prefix); 212 213 /* A prefix of "/" will - by definition - match any url */ 214 if (prefix[0] == '/' && len == 1) 215 return true; 216 217 if (strncmp(url, prefix, len) != 0) 218 return false; 219 220 return url[len] == '/' || url[len] == '?' || url[len] == 0; 221 } 222 223 char *uh_split_header(char *str) 224 { 225 char *val; 226 227 val = strchr(str, ':'); 228 if (!val) 229 return NULL; 230 231 *val = 0; 232 val++; 233 234 while (isspace(*val)) 235 val++; 236 237 return val; 238 } 239 240 bool uh_addr_rfc1918(struct uh_addr *addr) 241 { 242 uint32_t a; 243 244 if (addr->family != AF_INET) 245 return false; 246 247 a = htonl(addr->in.s_addr); 248 return ((a >= 0x0A000000) && (a <= 0x0AFFFFFF)) || 249 ((a >= 0xAC100000) && (a <= 0xAC1FFFFF)) || 250 ((a >= 0xC0A80000) && (a <= 0xC0A8FFFF)); 251 252 return 0; 253 } 254 255 256 static bool is_html_special_char(char c) 257 { 258 switch (c) 259 { 260 case 0x22: 261 case 0x26: 262 case 0x27: 263 case 0x3C: 264 case 0x3E: 265 return true; 266 267 default: 268 return false; 269 } 270 } 271 272 char *uh_htmlescape(const char *str) 273 { 274 size_t i, len; 275 char *p, *copy; 276 277 for (i = 0, len = 1; str[i]; i++) 278 if (is_html_special_char(str[i])) 279 len += 6; /* &#x??; */ 280 else 281 len++; 282 283 copy = calloc(1, len); 284 285 if (!copy) 286 return NULL; 287 288 for (i = 0, p = copy; str[i]; i++) 289 if (is_html_special_char(str[i])) 290 p += sprintf(p, "&#x%02x;", (unsigned int)str[i]); 291 else 292 *p++ = str[i]; 293 294 return copy; 295 } 296
This page was automatically generated by LXR 0.3.1. • OpenWrt