X-Git-Url: http://git.archive.openwrt.org/?a=blobdiff_plain;f=client.c;h=e2772dd45f490d5002ae83a543b065692b7e9558;hb=ce8b226cbdf4b1fbf10571ced052172fa3e2e04d;hp=28c8f760be9a14a0d9ee5572796a32b769f8862d;hpb=92f4e1306dd060106a3f5c5f61303d9613f93888;p=project%2Fuhttpd.git diff --git a/client.c b/client.c index 28c8f76..e2772dd 100644 --- a/client.c +++ b/client.c @@ -21,6 +21,7 @@ #include #include "uhttpd.h" +#include "tls.h" static LIST_HEAD(clients); @@ -142,9 +143,9 @@ static int client_parse_request(struct client *cl, char *data) if (!type || !path || !version) return CLIENT_STATE_DONE; - memset(&cl->request, 0, sizeof(cl->request)); - req->url = path; + blobmsg_add_string(&cl->hdr, "URL", path); + memset(&cl->request, 0, sizeof(cl->request)); h_method = find_idx(http_methods, ARRAY_SIZE(http_methods), type); h_version = find_idx(http_versions, ARRAY_SIZE(http_versions), version); if (h_method < 0 || h_version < 0) { @@ -168,9 +169,8 @@ static bool client_init_cb(struct client *cl, char *buf, int len) *newline = 0; blob_buf_init(&cl->hdr, 0); - blobmsg_add_string(&cl->hdr, "REQUEST", buf); + cl->state = client_parse_request(cl, buf); ustream_consume(cl->us, newline + 2 - buf); - cl->state = client_parse_request(cl, (char *) blobmsg_data(blob_data(cl->hdr.head))); if (cl->state == CLIENT_STATE_DONE) uh_header_error(cl, 400, "Bad Request"); @@ -250,29 +250,38 @@ static void client_parse_header(struct client *cl, char *data) cl->state = CLIENT_STATE_HEADER; } -static bool client_data_cb(struct client *cl, char *buf, int len) +void client_poll_post_data(struct client *cl) { struct dispatch *d = &cl->dispatch; struct http_request *r = &cl->request; - int consumed = 0; - int cur_len = 0; + char *buf; + int len; - if (!d->data_send) - return false; + if (cl->state == CLIENT_STATE_DONE) + return; - while (len) { - int offset = 0; + while (1) { char *sep; + int offset = 0; + int cur_len; - consumed += cur_len; - buf += cur_len; - len -= cur_len; - cur_len = min(r->content_length, len); + buf = ustream_get_read_buf(cl->us, &len); + if (!buf || !len) + break; + if (!d->data_send) + return; + + cur_len = min(r->content_length, len); if (cur_len) { - r->content_length -= cur_len; + if (d->data_blocked) + break; + if (d->data_send) - d->data_send(cl, buf, cur_len); + cur_len = d->data_send(cl, buf, cur_len); + + r->content_length -= cur_len; + ustream_consume(cl->us, cur_len); continue; } @@ -287,35 +296,38 @@ static bool client_data_cb(struct client *cl, char *buf, int len) break; *sep = 0; - cur_len = sep + 2 - buf; r->content_length = strtoul(buf + offset, &sep, 16); r->transfer_chunked++; + ustream_consume(cl->us, sep + 2 - buf); /* invalid chunk length */ - if (sep && *sep) - goto abort; + if (sep && *sep) { + r->content_length = 0; + r->transfer_chunked = 0; + break; + } /* empty chunk == eof */ - if (!r->content_length) + if (!r->content_length) { r->transfer_chunked = false; - - continue; - -abort: - consumed = len; - r->content_length = 0; - r->transfer_chunked = 0; - break; + break; + } } - ustream_consume(cl->us, consumed); - if (!r->content_length && !r->transfer_chunked) { + buf = ustream_get_read_buf(cl->us, &len); + if (!r->content_length && !r->transfer_chunked && + cl->state != CLIENT_STATE_DONE) { if (cl->dispatch.data_done) cl->dispatch.data_done(cl); cl->state = CLIENT_STATE_DONE; } +} + +static bool client_data_cb(struct client *cl, char *buf, int len) +{ + client_poll_post_data(cl); return false; } @@ -345,7 +357,7 @@ static read_cb_t read_cbs[] = { [CLIENT_STATE_DATA] = client_data_cb, }; -static void client_read_cb(struct client *cl) +void uh_client_read_cb(struct client *cl) { struct ustream *us = cl->us; char *str; @@ -373,6 +385,8 @@ static void client_close(struct client *cl) n_clients--; uh_dispatch_done(cl); uloop_timeout_cancel(&cl->timeout); + if (cl->tls) + uh_tls_client_detach(cl); ustream_free(&cl->sfd.stream); close(cl->sfd.fd.fd); list_del(&cl->list); @@ -382,11 +396,26 @@ static void client_close(struct client *cl) uh_unblock_listeners(); } +void uh_client_notify_state(struct client *cl) +{ + struct ustream *s = cl->us; + + if (!s->write_error) { + if (cl->state == CLIENT_STATE_DATA) + return; + + if (!s->eof || s->w.data_bytes) + return; + } + + return client_close(cl); +} + static void client_ustream_read_cb(struct ustream *s, int bytes) { struct client *cl = container_of(s, struct client, sfd); - client_read_cb(cl); + uh_client_read_cb(cl); } static void client_ustream_write_cb(struct ustream *s, int bytes) @@ -401,15 +430,7 @@ static void client_notify_state(struct ustream *s) { struct client *cl = container_of(s, struct client, sfd); - if (!s->write_error) { - if (cl->state == CLIENT_STATE_DATA) - return; - - if (!s->eof || s->w.data_bytes) - return; - } - - return client_close(cl); + uh_client_notify_state(cl); } static void set_addr(struct uh_addr *addr, void *src) @@ -427,7 +448,7 @@ static void set_addr(struct uh_addr *addr, void *src) } } -void uh_accept_client(int fd) +bool uh_accept_client(int fd, bool tls) { static struct client *next_client; struct client *cl; @@ -444,17 +465,23 @@ void uh_accept_client(int fd) sl = sizeof(addr); sfd = accept(fd, (struct sockaddr *) &addr, &sl); if (sfd < 0) - return; + return false; set_addr(&cl->peer_addr, &addr); sl = sizeof(addr); getsockname(fd, (struct sockaddr *) &addr, &sl); set_addr(&cl->srv_addr, &addr); + cl->us = &cl->sfd.stream; + if (tls) { + uh_tls_client_attach(cl); + } else { + cl->us->notify_read = client_ustream_read_cb; + cl->us->notify_write = client_ustream_write_cb; + cl->us->notify_state = client_notify_state; + } + cl->us->string_data = true; - cl->us->notify_read = client_ustream_read_cb; - cl->us->notify_write = client_ustream_write_cb; - cl->us->notify_state = client_notify_state; ustream_fd_init(&cl->sfd, sfd); cl->timeout.cb = client_timeout; @@ -465,6 +492,8 @@ void uh_accept_client(int fd) next_client = NULL; n_clients++; cl->id = client_id++; + + return true; } void uh_close_fds(void)