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 <libubox/blobmsg.h> 21 #include <ctype.h> 22 23 #include "uhttpd.h" 24 #include "tls.h" 25 26 static LIST_HEAD(clients); 27 static bool client_done = false; 28 29 int n_clients = 0; 30 struct config conf = {}; 31 32 const char * const http_versions[] = { 33 [UH_HTTP_VER_0_9] = "HTTP/0.9", 34 [UH_HTTP_VER_1_0] = "HTTP/1.0", 35 [UH_HTTP_VER_1_1] = "HTTP/1.1", 36 }; 37 38 const char * const http_methods[] = { 39 [UH_HTTP_MSG_GET] = "GET", 40 [UH_HTTP_MSG_POST] = "POST", 41 [UH_HTTP_MSG_HEAD] = "HEAD", 42 [UH_HTTP_MSG_OPTIONS] = "OPTIONS", 43 [UH_HTTP_MSG_PUT] = "PUT", 44 [UH_HTTP_MSG_PATCH] = "PATCH", 45 [UH_HTTP_MSG_DELETE] = "DELETE", 46 }; 47 48 void uh_http_header(struct client *cl, int code, const char *summary) 49 { 50 struct http_request *r = &cl->request; 51 struct blob_attr *cur; 52 const char *enc = "Transfer-Encoding: chunked\r\n"; 53 const char *conn; 54 int rem; 55 56 cl->http_code = code; 57 58 if (!uh_use_chunked(cl)) 59 enc = ""; 60 61 if (r->connection_close) 62 conn = "Connection: close"; 63 else 64 conn = "Connection: Keep-Alive"; 65 66 ustream_printf(cl->us, "%s %03i %s\r\n%s\r\n%s", 67 http_versions[cl->request.version], 68 code, summary, conn, enc); 69 70 if (!r->connection_close) 71 ustream_printf(cl->us, "Keep-Alive: timeout=%d\r\n", conf.http_keepalive); 72 73 blobmsg_for_each_attr(cur, cl->hdr_response.head, rem) 74 ustream_printf(cl->us, "%s: %s\r\n", blobmsg_name(cur), 75 blobmsg_get_string(cur)); 76 } 77 78 static void uh_connection_close(struct client *cl) 79 { 80 cl->state = CLIENT_STATE_CLOSE; 81 cl->us->eof = true; 82 ustream_state_change(cl->us); 83 } 84 85 static void uh_dispatch_done(struct client *cl) 86 { 87 if (cl->dispatch.free) 88 cl->dispatch.free(cl); 89 if (cl->dispatch.req_free) 90 cl->dispatch.req_free(cl); 91 } 92 93 static void client_timeout(struct uloop_timeout *timeout) 94 { 95 struct client *cl = container_of(timeout, struct client, timeout); 96 97 cl->state = CLIENT_STATE_CLOSE; 98 cl->request.connection_close = true; 99 uh_request_done(cl); 100 } 101 102 static void uh_set_client_timeout(struct client *cl, int timeout) 103 { 104 cl->timeout.cb = client_timeout; 105 uloop_timeout_set(&cl->timeout, timeout * 1000); 106 } 107 108 static void uh_keepalive_poll_cb(struct uloop_timeout *timeout) 109 { 110 struct client *cl = container_of(timeout, struct client, timeout); 111 int sec = cl->requests > 0 ? conf.http_keepalive : conf.network_timeout; 112 113 uh_set_client_timeout(cl, sec); 114 cl->us->notify_read(cl->us, 0); 115 } 116 117 static void uh_poll_connection(struct client *cl) 118 { 119 cl->timeout.cb = uh_keepalive_poll_cb; 120 uloop_timeout_set(&cl->timeout, 1); 121 } 122 123 void uh_request_done(struct client *cl) 124 { 125 uh_chunk_eof(cl); 126 uh_dispatch_done(cl); 127 blob_buf_init(&cl->hdr_response, 0); 128 memset(&cl->dispatch, 0, sizeof(cl->dispatch)); 129 130 if (!conf.http_keepalive || cl->request.connection_close) 131 return uh_connection_close(cl); 132 133 cl->state = CLIENT_STATE_INIT; 134 cl->requests++; 135 uh_poll_connection(cl); 136 } 137 138 void __printf(4, 5) 139 uh_client_error(struct client *cl, int code, const char *summary, const char *fmt, ...) 140 { 141 struct http_request *r = &cl->request; 142 va_list arg; 143 144 uh_http_header(cl, code, summary); 145 ustream_printf(cl->us, "Content-Type: text/html\r\n\r\n"); 146 147 uh_chunk_printf(cl, "<h1>%s</h1>", summary); 148 149 if (fmt) { 150 va_start(arg, fmt); 151 uh_chunk_vprintf(cl, fmt, arg); 152 va_end(arg); 153 } 154 155 /* Close the connection even when keep alive is set, when it 156 * contains a request body, as it was not read and we are 157 * currently out of sync. Without handling this the body will be 158 * interpreted as part of the next request. The alternative 159 * would be to read and discard the request body here. 160 */ 161 if (r->transfer_chunked || r->content_length > 0) { 162 cl->state = CLIENT_STATE_CLOSE; 163 cl->request.connection_close = true; 164 } 165 166 uh_request_done(cl); 167 } 168 169 static void uh_header_error(struct client *cl, int code, const char *summary) 170 { 171 uh_client_error(cl, code, summary, NULL); 172 uh_connection_close(cl); 173 } 174 175 static int find_idx(const char * const *list, int max, const char *str) 176 { 177 int i; 178 179 for (i = 0; i < max; i++) 180 if (!strcmp(list[i], str)) 181 return i; 182 183 return -1; 184 } 185 186 static int client_parse_request(struct client *cl, char *data) 187 { 188 struct http_request *req = &cl->request; 189 char *type, *path, *version; 190 int h_method, h_version; 191 192 type = strtok(data, " "); 193 path = strtok(NULL, " "); 194 version = strtok(NULL, " "); 195 if (!type || !path || !version) 196 return CLIENT_STATE_DONE; 197 198 blobmsg_add_string(&cl->hdr, "URL", path); 199 200 memset(&cl->request, 0, sizeof(cl->request)); 201 h_method = find_idx(http_methods, ARRAY_SIZE(http_methods), type); 202 h_version = find_idx(http_versions, ARRAY_SIZE(http_versions), version); 203 if (h_method < 0 || h_version < 0) { 204 req->version = UH_HTTP_VER_1_0; 205 return CLIENT_STATE_DONE; 206 } 207 208 req->method = h_method; 209 req->version = h_version; 210 if (req->version < UH_HTTP_VER_1_1 || !conf.http_keepalive) 211 req->connection_close = true; 212 213 return CLIENT_STATE_HEADER; 214 } 215 216 static bool client_init_cb(struct client *cl, char *buf, int len) 217 { 218 char *newline; 219 220 newline = strstr(buf, "\r\n"); 221 if (!newline) 222 return false; 223 224 if (newline == buf) { 225 ustream_consume(cl->us, 2); 226 return true; 227 } 228 229 *newline = 0; 230 blob_buf_init(&cl->hdr, 0); 231 cl->state = client_parse_request(cl, buf); 232 ustream_consume(cl->us, newline + 2 - buf); 233 if (cl->state == CLIENT_STATE_DONE) 234 uh_header_error(cl, 400, "Bad Request"); 235 236 return true; 237 } 238 239 static bool rfc1918_filter_check(struct client *cl) 240 { 241 if (!conf.rfc1918_filter) 242 return true; 243 244 if (!uh_addr_rfc1918(&cl->peer_addr) || uh_addr_rfc1918(&cl->srv_addr)) 245 return true; 246 247 uh_client_error(cl, 403, "Forbidden", 248 "Rejected request from RFC1918 IP " 249 "to public server address"); 250 return false; 251 } 252 253 static bool tls_redirect_check(struct client *cl) 254 { 255 int rem, port; 256 struct blob_attr *cur; 257 char *ptr, *url = NULL, *host = NULL; 258 259 if (cl->tls || !conf.tls_redirect) 260 return true; 261 262 if ((port = uh_first_tls_port(cl->srv_addr.family)) == -1) 263 return true; 264 265 blob_for_each_attr(cur, cl->hdr.head, rem) { 266 if (!strncmp(blobmsg_name(cur), "host", 4)) 267 host = blobmsg_get_string(cur); 268 269 if (!strncmp(blobmsg_name(cur), "URL", 3)) 270 url = blobmsg_get_string(cur); 271 272 if (url && host) 273 break; 274 } 275 276 if (!url || !host) 277 return true; 278 279 if ((ptr = strchr(host, ']')) != NULL) 280 *(ptr+1) = 0; 281 else if ((ptr = strchr(host, ':')) != NULL) 282 *ptr = 0; 283 284 cl->request.disable_chunked = true; 285 cl->request.connection_close = true; 286 287 uh_http_header(cl, 307, "Temporary Redirect"); 288 289 if (port != 443) 290 ustream_printf(cl->us, "Location: https://%s:%d%s\r\n\r\n", host, port, url); 291 else 292 ustream_printf(cl->us, "Location: https://%s%s\r\n\r\n", host, url); 293 294 uh_request_done(cl); 295 296 return false; 297 } 298 299 static void client_header_complete(struct client *cl) 300 { 301 struct http_request *r = &cl->request; 302 303 if (!rfc1918_filter_check(cl)) 304 return; 305 306 if (!tls_redirect_check(cl)) 307 return; 308 309 if (r->expect_cont) 310 ustream_printf(cl->us, "HTTP/1.1 100 Continue\r\n\r\n"); 311 312 switch(r->ua) { 313 case UH_UA_MSIE_OLD: 314 if (r->method != UH_HTTP_MSG_POST) 315 break; 316 317 /* fall through */ 318 case UH_UA_SAFARI: 319 r->connection_close = true; 320 break; 321 default: 322 break; 323 } 324 325 uh_handle_request(cl); 326 } 327 328 static void client_parse_header(struct client *cl, char *data) 329 { 330 struct http_request *r = &cl->request; 331 char *err; 332 char *name; 333 char *val; 334 335 if (!*data) { 336 uloop_timeout_cancel(&cl->timeout); 337 cl->state = CLIENT_STATE_DATA; 338 client_header_complete(cl); 339 return; 340 } 341 342 val = uh_split_header(data); 343 if (!val) { 344 cl->state = CLIENT_STATE_DONE; 345 return; 346 } 347 348 for (name = data; *name; name++) 349 if (isupper(*name)) 350 *name = tolower(*name); 351 352 if (!strcmp(data, "expect")) { 353 if (!strcasecmp(val, "100-continue")) 354 r->expect_cont = true; 355 else { 356 uh_header_error(cl, 412, "Precondition Failed"); 357 return; 358 } 359 } else if (!strcmp(data, "content-length")) { 360 r->content_length = strtoul(val, &err, 0); 361 if ((err && *err) || r->content_length < 0) { 362 uh_header_error(cl, 400, "Bad Request"); 363 return; 364 } 365 } else if (!strcmp(data, "transfer-encoding")) { 366 if (!strcmp(val, "chunked")) 367 r->transfer_chunked = true; 368 } else if (!strcmp(data, "connection")) { 369 if (!strcasecmp(val, "close")) 370 r->connection_close = true; 371 } else if (!strcmp(data, "user-agent")) { 372 char *str; 373 374 if (strstr(val, "Opera")) 375 r->ua = UH_UA_OPERA; 376 else if ((str = strstr(val, "MSIE ")) != NULL) { 377 r->ua = UH_UA_MSIE_NEW; 378 if (str[5] && str[6] == '.') { 379 switch (str[5]) { 380 case '6': 381 if (strstr(str, "SV1")) 382 break; 383 /* fall through */ 384 case '5': 385 case '4': 386 r->ua = UH_UA_MSIE_OLD; 387 break; 388 } 389 } 390 } 391 else if (strstr(val, "Chrome/")) 392 r->ua = UH_UA_CHROME; 393 else if (strstr(val, "Safari/") && strstr(val, "Mac OS X")) 394 r->ua = UH_UA_SAFARI; 395 else if (strstr(val, "Gecko/")) 396 r->ua = UH_UA_GECKO; 397 else if (strstr(val, "Konqueror")) 398 r->ua = UH_UA_KONQUEROR; 399 } 400 401 402 blobmsg_add_string(&cl->hdr, data, val); 403 404 cl->state = CLIENT_STATE_HEADER; 405 } 406 407 void client_poll_post_data(struct client *cl) 408 { 409 struct dispatch *d = &cl->dispatch; 410 struct http_request *r = &cl->request; 411 enum client_state st; 412 char *buf; 413 int len; 414 415 if (cl->state == CLIENT_STATE_DONE) 416 return; 417 418 while (1) { 419 char *sep; 420 int offset = 0; 421 int cur_len; 422 423 buf = ustream_get_read_buf(cl->us, &len); 424 if (!buf || !len) 425 break; 426 427 if (!d->data_send) 428 return; 429 430 cur_len = min(r->content_length, len); 431 if (cur_len) { 432 if (d->data_blocked) 433 break; 434 435 if (d->data_send) 436 cur_len = d->data_send(cl, buf, cur_len); 437 438 r->content_length -= cur_len; 439 ustream_consume(cl->us, cur_len); 440 continue; 441 } 442 443 if (!r->transfer_chunked) 444 break; 445 446 if (r->transfer_chunked > 1) 447 offset = 2; 448 449 sep = strstr(buf + offset, "\r\n"); 450 if (!sep) 451 break; 452 453 *sep = 0; 454 455 r->content_length = strtoul(buf + offset, &sep, 16); 456 r->transfer_chunked++; 457 ustream_consume(cl->us, sep + 2 - buf); 458 459 /* invalid chunk length */ 460 if ((sep && *sep) || r->content_length < 0) { 461 r->content_length = 0; 462 r->transfer_chunked = 0; 463 break; 464 } 465 466 /* empty chunk == eof */ 467 if (!r->content_length) { 468 r->transfer_chunked = false; 469 break; 470 } 471 } 472 473 buf = ustream_get_read_buf(cl->us, &len); 474 if (!r->content_length && !r->transfer_chunked && 475 cl->state != CLIENT_STATE_DONE) { 476 st = cl->state; 477 478 if (cl->dispatch.data_done) 479 cl->dispatch.data_done(cl); 480 481 if (cl->state == st) 482 cl->state = CLIENT_STATE_DONE; 483 } 484 } 485 486 static bool client_data_cb(struct client *cl, char *buf, int len) 487 { 488 client_poll_post_data(cl); 489 return false; 490 } 491 492 static bool client_header_cb(struct client *cl, char *buf, int len) 493 { 494 char *newline; 495 int line_len; 496 497 newline = strstr(buf, "\r\n"); 498 if (!newline) 499 return false; 500 501 *newline = 0; 502 client_parse_header(cl, buf); 503 line_len = newline + 2 - buf; 504 ustream_consume(cl->us, line_len); 505 if (cl->state == CLIENT_STATE_DATA) 506 return client_data_cb(cl, newline + 2, len - line_len); 507 508 return true; 509 } 510 511 typedef bool (*read_cb_t)(struct client *cl, char *buf, int len); 512 static read_cb_t read_cbs[] = { 513 [CLIENT_STATE_INIT] = client_init_cb, 514 [CLIENT_STATE_HEADER] = client_header_cb, 515 [CLIENT_STATE_DATA] = client_data_cb, 516 }; 517 518 void uh_client_read_cb(struct client *cl) 519 { 520 struct ustream *us = cl->us; 521 char *str; 522 int len; 523 524 client_done = false; 525 do { 526 str = ustream_get_read_buf(us, &len); 527 if (!str || !len) 528 break; 529 530 if (cl->state >= array_size(read_cbs) || !read_cbs[cl->state]) 531 break; 532 533 if (!read_cbs[cl->state](cl, str, len)) { 534 if (len == us->r.buffer_len && 535 cl->state != CLIENT_STATE_DATA && 536 cl->state != CLIENT_STATE_DONE) 537 uh_header_error(cl, 413, "Request Entity Too Large"); 538 break; 539 } 540 } while (!client_done); 541 } 542 543 static void client_close(struct client *cl) 544 { 545 if (cl->refcount) { 546 cl->state = CLIENT_STATE_CLEANUP; 547 return; 548 } 549 550 client_done = true; 551 n_clients--; 552 uh_dispatch_done(cl); 553 uloop_timeout_cancel(&cl->timeout); 554 if (cl->tls) 555 uh_tls_client_detach(cl); 556 ustream_free(&cl->sfd.stream); 557 close(cl->sfd.fd.fd); 558 list_del(&cl->list); 559 blob_buf_free(&cl->hdr); 560 blob_buf_free(&cl->hdr_response); 561 free(cl); 562 563 uh_unblock_listeners(); 564 } 565 566 void uh_client_notify_state(struct client *cl) 567 { 568 struct ustream *s = cl->us; 569 570 if (!s->write_error && cl->state != CLIENT_STATE_CLEANUP) { 571 if (cl->state == CLIENT_STATE_DATA) 572 return; 573 574 if (!s->eof || s->w.data_bytes) 575 return; 576 577 #ifdef HAVE_TLS 578 if (cl->tls && cl->ssl.conn && cl->ssl.conn->w.data_bytes) { 579 cl->ssl.conn->eof = s->eof; 580 if (!ustream_write_pending(cl->ssl.conn)) 581 return; 582 } 583 #endif 584 } 585 586 return client_close(cl); 587 } 588 589 static void client_ustream_read_cb(struct ustream *s, int bytes) 590 { 591 struct client *cl = container_of(s, struct client, sfd.stream); 592 593 uh_client_read_cb(cl); 594 } 595 596 static void client_ustream_write_cb(struct ustream *s, int bytes) 597 { 598 struct client *cl = container_of(s, struct client, sfd.stream); 599 600 if (cl->dispatch.write_cb) 601 cl->dispatch.write_cb(cl); 602 } 603 604 static void client_notify_state(struct ustream *s) 605 { 606 struct client *cl = container_of(s, struct client, sfd.stream); 607 608 uh_client_notify_state(cl); 609 } 610 611 static void set_addr(struct uh_addr *addr, void *src) 612 { 613 struct sockaddr_in *sin = src; 614 struct sockaddr_in6 *sin6 = src; 615 616 addr->family = sin->sin_family; 617 if (addr->family == AF_INET) { 618 addr->port = ntohs(sin->sin_port); 619 memcpy(&addr->in, &sin->sin_addr, sizeof(addr->in)); 620 } else { 621 addr->port = ntohs(sin6->sin6_port); 622 memcpy(&addr->in6, &sin6->sin6_addr, sizeof(addr->in6)); 623 } 624 } 625 626 bool uh_accept_client(int fd, bool tls) 627 { 628 static struct client *next_client; 629 struct client *cl; 630 unsigned int sl; 631 int sfd; 632 static int client_id = 0; 633 struct sockaddr_in6 addr; 634 635 if (!next_client) 636 next_client = calloc(1, sizeof(*next_client)); 637 638 cl = next_client; 639 640 sl = sizeof(addr); 641 sfd = accept(fd, (struct sockaddr *) &addr, &sl); 642 if (sfd < 0) 643 return false; 644 645 set_addr(&cl->peer_addr, &addr); 646 sl = sizeof(addr); 647 getsockname(sfd, (struct sockaddr *) &addr, &sl); 648 set_addr(&cl->srv_addr, &addr); 649 650 cl->us = &cl->sfd.stream; 651 if (tls) { 652 uh_tls_client_attach(cl); 653 } else { 654 cl->us->notify_read = client_ustream_read_cb; 655 cl->us->notify_write = client_ustream_write_cb; 656 cl->us->notify_state = client_notify_state; 657 } 658 659 cl->us->string_data = true; 660 ustream_fd_init(&cl->sfd, sfd); 661 662 uh_poll_connection(cl); 663 list_add_tail(&cl->list, &clients); 664 665 next_client = NULL; 666 n_clients++; 667 cl->id = client_id++; 668 cl->tls = tls; 669 670 return true; 671 } 672 673 void uh_close_fds(void) 674 { 675 struct client *cl; 676 677 uloop_done(); 678 uh_close_listen_fds(); 679 list_for_each_entry(cl, &clients, list) { 680 close(cl->sfd.fd.fd); 681 if (cl->dispatch.close_fds) 682 cl->dispatch.close_fds(cl); 683 } 684 } 685
This page was automatically generated by LXR 0.3.1. • OpenWrt