06336eb39046a18da75981a46e248793ed22d3a9
2 * uhttpd - Tiny single-threaded httpd
4 * Copyright (C) 2010-2013 Jo-Philipp Wich <xm@subsignal.org>
5 * Copyright (C) 2013 Felix Fietkau <nbd@openwrt.org>
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.
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.
20 #include <libubox/blobmsg.h>
26 static LIST_HEAD(clients
);
27 static bool client_done
= false;
30 struct config conf
= {};
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",
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",
48 void uh_http_header(struct client
*cl
, int code
, const char *summary
)
50 struct http_request
*r
= &cl
->request
;
51 struct blob_attr
*cur
;
52 const char *enc
= "Transfer-Encoding: chunked\r\n";
58 if (!uh_use_chunked(cl
))
61 if (r
->connection_close
)
62 conn
= "Connection: close";
64 conn
= "Connection: Keep-Alive";
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
);
70 if (!r
->connection_close
)
71 ustream_printf(cl
->us
, "Keep-Alive: timeout=%d\r\n", conf
.http_keepalive
);
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
));
78 static void uh_connection_close(struct client
*cl
)
80 cl
->state
= CLIENT_STATE_CLOSE
;
82 ustream_state_change(cl
->us
);
85 static void uh_dispatch_done(struct client
*cl
)
87 if (cl
->dispatch
.free
)
88 cl
->dispatch
.free(cl
);
89 if (cl
->dispatch
.req_free
)
90 cl
->dispatch
.req_free(cl
);
93 static void client_timeout(struct uloop_timeout
*timeout
)
95 struct client
*cl
= container_of(timeout
, struct client
, timeout
);
97 cl
->state
= CLIENT_STATE_CLOSE
;
98 cl
->request
.connection_close
= true;
102 static void uh_set_client_timeout(struct client
*cl
, int timeout
)
104 cl
->timeout
.cb
= client_timeout
;
105 uloop_timeout_set(&cl
->timeout
, timeout
* 1000);
108 static void uh_keepalive_poll_cb(struct uloop_timeout
*timeout
)
110 struct client
*cl
= container_of(timeout
, struct client
, timeout
);
111 int sec
= cl
->requests
> 0 ? conf
.http_keepalive
: conf
.network_timeout
;
113 uh_set_client_timeout(cl
, sec
);
114 cl
->us
->notify_read(cl
->us
, 0);
117 static void uh_poll_connection(struct client
*cl
)
119 cl
->timeout
.cb
= uh_keepalive_poll_cb
;
120 uloop_timeout_set(&cl
->timeout
, 1);
123 void uh_request_done(struct client
*cl
)
126 uh_dispatch_done(cl
);
127 blob_buf_init(&cl
->hdr_response
, 0);
128 memset(&cl
->dispatch
, 0, sizeof(cl
->dispatch
));
130 if (!conf
.http_keepalive
|| cl
->request
.connection_close
)
131 return uh_connection_close(cl
);
133 cl
->state
= CLIENT_STATE_INIT
;
135 uh_poll_connection(cl
);
139 uh_client_error(struct client
*cl
, int code
, const char *summary
, const char *fmt
, ...)
141 struct http_request
*r
= &cl
->request
;
144 uh_http_header(cl
, code
, summary
);
145 ustream_printf(cl
->us
, "Content-Type: text/html\r\n\r\n");
147 uh_chunk_printf(cl
, "<h1>%s</h1>", summary
);
151 uh_chunk_vprintf(cl
, fmt
, arg
);
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.
161 if (r
->transfer_chunked
|| r
->content_length
> 0) {
162 cl
->state
= CLIENT_STATE_CLOSE
;
163 cl
->request
.connection_close
= true;
169 static void uh_header_error(struct client
*cl
, int code
, const char *summary
)
171 uh_client_error(cl
, code
, summary
, NULL
);
172 uh_connection_close(cl
);
175 static int find_idx(const char * const *list
, int max
, const char *str
)
179 for (i
= 0; i
< max
; i
++)
180 if (!strcmp(list
[i
], str
))
186 static int client_parse_request(struct client
*cl
, char *data
)
188 struct http_request
*req
= &cl
->request
;
189 char *type
, *path
, *version
;
190 int h_method
, h_version
;
192 type
= strtok(data
, " ");
193 path
= strtok(NULL
, " ");
194 version
= strtok(NULL
, " ");
195 if (!type
|| !path
|| !version
)
196 return CLIENT_STATE_DONE
;
198 blobmsg_add_string(&cl
->hdr
, "URL", path
);
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
;
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;
213 return CLIENT_STATE_HEADER
;
216 static bool client_init_cb(struct client
*cl
, char *buf
, int len
)
220 newline
= strstr(buf
, "\r\n");
224 if (newline
== buf
) {
225 ustream_consume(cl
->us
, 2);
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");
239 static bool rfc1918_filter_check(struct client
*cl
)
241 if (!conf
.rfc1918_filter
)
244 if (!uh_addr_rfc1918(&cl
->peer_addr
) || uh_addr_rfc1918(&cl
->srv_addr
))
247 uh_client_error(cl
, 403, "Forbidden",
248 "Rejected request from RFC1918 IP "
249 "to public server address");
253 static bool tls_redirect_check(struct client
*cl
)
256 struct blob_attr
*cur
;
257 char *ptr
, *url
= NULL
, *host
= NULL
;
259 if (cl
->tls
|| !conf
.tls_redirect
)
262 if ((port
= uh_first_tls_port(cl
->srv_addr
.family
)) == -1)
265 blob_for_each_attr(cur
, cl
->hdr
.head
, rem
) {
266 if (!strncmp(blobmsg_name(cur
), "host", 4))
267 host
= blobmsg_get_string(cur
);
269 if (!strncmp(blobmsg_name(cur
), "URL", 3))
270 url
= blobmsg_get_string(cur
);
279 if ((ptr
= strchr(host
, ']')) != NULL
)
281 else if ((ptr
= strchr(host
, ':')) != NULL
)
284 cl
->request
.disable_chunked
= true;
285 cl
->request
.connection_close
= true;
287 uh_http_header(cl
, 307, "Temporary Redirect");
290 ustream_printf(cl
->us
, "Location: https://%s:%d%s\r\n\r\n", host
, port
, url
);
292 ustream_printf(cl
->us
, "Location: https://%s%s\r\n\r\n", host
, url
);
299 static void client_header_complete(struct client
*cl
)
301 struct http_request
*r
= &cl
->request
;
303 if (!rfc1918_filter_check(cl
))
306 if (!tls_redirect_check(cl
))
310 ustream_printf(cl
->us
, "HTTP/1.1 100 Continue\r\n\r\n");
314 if (r
->method
!= UH_HTTP_MSG_POST
)
319 r
->connection_close
= true;
325 uh_handle_request(cl
);
328 static void client_parse_header(struct client
*cl
, char *data
)
330 struct http_request
*r
= &cl
->request
;
336 uloop_timeout_cancel(&cl
->timeout
);
337 cl
->state
= CLIENT_STATE_DATA
;
338 client_header_complete(cl
);
342 val
= uh_split_header(data
);
344 cl
->state
= CLIENT_STATE_DONE
;
348 for (name
= data
; *name
; name
++)
350 *name
= tolower(*name
);
352 if (!strcmp(data
, "expect")) {
353 if (!strcasecmp(val
, "100-continue"))
354 r
->expect_cont
= true;
356 uh_header_error(cl
, 412, "Precondition Failed");
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");
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")) {
374 if (strstr(val
, "Opera"))
376 else if ((str
= strstr(val
, "MSIE ")) != NULL
) {
377 r
->ua
= UH_UA_MSIE_NEW
;
378 if (str
[5] && str
[6] == '.') {
381 if (strstr(str
, "SV1"))
386 r
->ua
= UH_UA_MSIE_OLD
;
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/"))
397 else if (strstr(val
, "Konqueror"))
398 r
->ua
= UH_UA_KONQUEROR
;
402 blobmsg_add_string(&cl
->hdr
, data
, val
);
404 cl
->state
= CLIENT_STATE_HEADER
;
407 void client_poll_post_data(struct client
*cl
)
409 struct dispatch
*d
= &cl
->dispatch
;
410 struct http_request
*r
= &cl
->request
;
411 enum client_state st
;
415 if (cl
->state
== CLIENT_STATE_DONE
)
423 buf
= ustream_get_read_buf(cl
->us
, &len
);
430 cur_len
= min(r
->content_length
, len
);
436 cur_len
= d
->data_send(cl
, buf
, cur_len
);
438 r
->content_length
-= cur_len
;
439 ustream_consume(cl
->us
, cur_len
);
443 if (!r
->transfer_chunked
)
446 if (r
->transfer_chunked
> 1)
449 sep
= strstr(buf
+ offset
, "\r\n");
455 r
->content_length
= strtoul(buf
+ offset
, &sep
, 16);
456 r
->transfer_chunked
++;
457 ustream_consume(cl
->us
, sep
+ 2 - buf
);
459 /* invalid chunk length */
460 if ((sep
&& *sep
) || r
->content_length
< 0) {
461 r
->content_length
= 0;
462 r
->transfer_chunked
= 0;
466 /* empty chunk == eof */
467 if (!r
->content_length
) {
468 r
->transfer_chunked
= false;
473 buf
= ustream_get_read_buf(cl
->us
, &len
);
474 if (!r
->content_length
&& !r
->transfer_chunked
&&
475 cl
->state
!= CLIENT_STATE_DONE
) {
478 if (cl
->dispatch
.data_done
)
479 cl
->dispatch
.data_done(cl
);
482 cl
->state
= CLIENT_STATE_DONE
;
486 static bool client_data_cb(struct client
*cl
, char *buf
, int len
)
488 client_poll_post_data(cl
);
492 static bool client_header_cb(struct client
*cl
, char *buf
, int len
)
497 newline
= strstr(buf
, "\r\n");
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
);
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
,
518 void uh_client_read_cb(struct client
*cl
)
520 struct ustream
*us
= cl
->us
;
526 str
= ustream_get_read_buf(us
, &len
);
530 if (cl
->state
>= array_size(read_cbs
) || !read_cbs
[cl
->state
])
533 if (!read_cbs
[cl
->state
](cl
, str
, len
)) {
534 if (len
== us
->r
.buffer_len
&&
535 cl
->state
!= CLIENT_STATE_DATA
)
536 uh_header_error(cl
, 413, "Request Entity Too Large");
539 } while (!client_done
);
542 static void client_close(struct client
*cl
)
545 cl
->state
= CLIENT_STATE_CLEANUP
;
551 uh_dispatch_done(cl
);
552 uloop_timeout_cancel(&cl
->timeout
);
554 uh_tls_client_detach(cl
);
555 ustream_free(&cl
->sfd
.stream
);
556 close(cl
->sfd
.fd
.fd
);
558 blob_buf_free(&cl
->hdr
);
559 blob_buf_free(&cl
->hdr_response
);
562 uh_unblock_listeners();
565 void uh_client_notify_state(struct client
*cl
)
567 struct ustream
*s
= cl
->us
;
569 if (!s
->write_error
&& cl
->state
!= CLIENT_STATE_CLEANUP
) {
570 if (cl
->state
== CLIENT_STATE_DATA
)
573 if (!s
->eof
|| s
->w
.data_bytes
)
577 if (cl
->tls
&& cl
->ssl
.conn
&& cl
->ssl
.conn
->w
.data_bytes
) {
578 cl
->ssl
.conn
->eof
= s
->eof
;
579 if (!ustream_write_pending(cl
->ssl
.conn
))
585 return client_close(cl
);
588 static void client_ustream_read_cb(struct ustream
*s
, int bytes
)
590 struct client
*cl
= container_of(s
, struct client
, sfd
.stream
);
592 uh_client_read_cb(cl
);
595 static void client_ustream_write_cb(struct ustream
*s
, int bytes
)
597 struct client
*cl
= container_of(s
, struct client
, sfd
.stream
);
599 if (cl
->dispatch
.write_cb
)
600 cl
->dispatch
.write_cb(cl
);
603 static void client_notify_state(struct ustream
*s
)
605 struct client
*cl
= container_of(s
, struct client
, sfd
.stream
);
607 uh_client_notify_state(cl
);
610 static void set_addr(struct uh_addr
*addr
, void *src
)
612 struct sockaddr_in
*sin
= src
;
613 struct sockaddr_in6
*sin6
= src
;
615 addr
->family
= sin
->sin_family
;
616 if (addr
->family
== AF_INET
) {
617 addr
->port
= ntohs(sin
->sin_port
);
618 memcpy(&addr
->in
, &sin
->sin_addr
, sizeof(addr
->in
));
620 addr
->port
= ntohs(sin6
->sin6_port
);
621 memcpy(&addr
->in6
, &sin6
->sin6_addr
, sizeof(addr
->in6
));
625 bool uh_accept_client(int fd
, bool tls
)
627 static struct client
*next_client
;
631 static int client_id
= 0;
632 struct sockaddr_in6 addr
;
635 next_client
= calloc(1, sizeof(*next_client
));
640 sfd
= accept(fd
, (struct sockaddr
*) &addr
, &sl
);
644 set_addr(&cl
->peer_addr
, &addr
);
646 getsockname(sfd
, (struct sockaddr
*) &addr
, &sl
);
647 set_addr(&cl
->srv_addr
, &addr
);
649 cl
->us
= &cl
->sfd
.stream
;
651 uh_tls_client_attach(cl
);
653 cl
->us
->notify_read
= client_ustream_read_cb
;
654 cl
->us
->notify_write
= client_ustream_write_cb
;
655 cl
->us
->notify_state
= client_notify_state
;
658 cl
->us
->string_data
= true;
659 ustream_fd_init(&cl
->sfd
, sfd
);
661 uh_poll_connection(cl
);
662 list_add_tail(&cl
->list
, &clients
);
666 cl
->id
= client_id
++;
672 void uh_close_fds(void)
677 uh_close_listen_fds();
678 list_for_each_entry(cl
, &clients
, list
) {
679 close(cl
->sfd
.fd
.fd
);
680 if (cl
->dispatch
.close_fds
)
681 cl
->dispatch
.close_fds(cl
);