• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/uhttpd/client.c

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

This page was automatically generated by LXR 0.3.1.  •  OpenWrt