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