From 1e20eca97df4f46ab4fe8f9c7c1d8ac8f384a03d Mon Sep 17 00:00:00 2001 From: Jianhui Zhao Date: Fri, 1 Jan 2021 00:14:31 +0800 Subject: [PATCH] Fix bug: handle fail when multi requests sent at a time Signed-off-by: Jianhui Zhao --- src/connection.c | 93 +++++++++++++++++++++++++++++++++--------------- src/connection.h | 2 ++ 2 files changed, 67 insertions(+), 28 deletions(-) diff --git a/src/connection.c b/src/connection.c index 4d2e054..3e8449f 100644 --- a/src/connection.c +++ b/src/connection.c @@ -40,8 +40,6 @@ static void conn_done(struct uh_connection *conn) { struct ev_loop *loop = conn->srv->loop; - buffer_pull(&conn->rb, NULL, buffer_length(&conn->rb)); - if (!http_should_keep_alive(&conn->parser)) conn->flags |= CONN_F_SEND_AND_CLOSE; @@ -273,15 +271,9 @@ static struct uh_str conn_get_body(struct uh_connection *conn) static struct uh_str conn_extract_body(struct uh_connection *conn) { - struct uh_request *req = &conn->req; - struct uh_str body; + struct uh_str body = conn_get_body(conn); - body.p = O2D(conn, req->body.offset); - body.len = req->body.length; - - req->body.length = 0; - - buffer_discard(&conn->rb, body.len); + conn->req.body.consumed = true; return body; } @@ -411,6 +403,13 @@ static int on_body_cb(struct http_parser *parser, const char *at, size_t length) if (conn->flags & CONN_F_SEND_AND_CLOSE) return -1; + if (req->body.consumed) { + req->body.consumed = false; + buffer_discard(&conn->rb, req->body.length); + req->length -= req->body.length; + req->body.length = 0; + } + return 0; } @@ -423,6 +422,8 @@ static int on_message_complete_cb(struct http_parser *parser) conn->handler(conn, UH_EV_COMPLETE); + http_parser_pause(parser, true); + return 0; } @@ -475,6 +476,43 @@ void conn_free(struct uh_connection *conn) free(conn); } +static void conn_http_parse(struct uh_connection *conn) +{ + struct http_parser *parser = &conn->parser; + struct uh_request *req = &conn->req; + struct buffer *rb = &conn->rb; + uint8_t *data = buffer_data(rb) + req->length; + size_t length = buffer_length(rb) - req->length; + size_t nparsed; + + if (parser->http_errno == HPE_PAUSED) + return; + + nparsed = http_parser_execute(parser, &settings, (const char *)data, length); + + switch (parser->http_errno) { + case HPE_PAUSED: + case HPE_OK: + if (parser->upgrade) { + conn_error(conn, HTTP_STATUS_NOT_IMPLEMENTED, NULL); + return; + } + + req->length += nparsed; + + /* paused in on_message_complete */ + if (parser->http_errno == HPE_PAUSED) { + buffer_pull(rb, NULL, req->length); + req->length = 0; + } + return; + + default: + conn_error(conn, HTTP_STATUS_BAD_REQUEST, http_errno_description(parser->http_errno)); + return; + } +} + #if UHTTPD_SSL_SUPPORT static int conn_ssl_write(int fd, void *buf, size_t count, void *ssl) { @@ -527,10 +565,16 @@ static void conn_write_cb(struct ev_loop *loop, struct ev_io *w, int revents) conn->file.fd = -1; } - if (conn->flags & CONN_F_SEND_AND_CLOSE) + if (conn->flags & CONN_F_SEND_AND_CLOSE) { conn_free(conn); - else + } else { ev_io_stop(loop, w); + + http_parser_pause(&conn->parser, false); + + if (buffer_length(&conn->rb) > 0) + conn_http_parse(conn); + } } } @@ -550,10 +594,9 @@ static int conn_ssl_read(int fd, void *buf, size_t count, void *ssl) static void conn_read_cb(struct ev_loop *loop, struct ev_io *w, int revents) { struct uh_connection *conn = container_of(w, struct uh_connection, ior); - struct http_parser *parser = &conn->parser; struct buffer *rb = &conn->rb; - int ret, nread, length, nparsed; bool eof; + int ret; if (conn->flags & CONN_F_SEND_AND_CLOSE) { ev_io_stop(loop, w); @@ -575,8 +618,6 @@ static void conn_read_cb(struct ev_loop *loop, struct ev_io *w, int revents) conn->activity = ev_now(loop); - length = buffer_length(rb); - #if UHTTPD_SSL_SUPPORT if (conn->ssl) ret = buffer_put_fd_ex(rb, w->fd, -1, &eof, conn_ssl_read, conn->ssl); @@ -585,23 +626,19 @@ static void conn_read_cb(struct ev_loop *loop, struct ev_io *w, int revents) ret = buffer_put_fd(rb, w->fd, -1, &eof); if (ret < 0) { - conn_error(conn, HTTP_STATUS_INTERNAL_SERVER_ERROR, NULL); uh_log_err("read error: %s\n", strerror(errno)); - return; + goto done; } - if (eof) { - conn_free(conn); - return; - } + if (eof) + goto done; - nread = buffer_length(rb) - length; + conn_http_parse(conn); - nparsed = http_parser_execute(parser, &settings, (const char *)rb->data + length, nread); - if (parser->upgrade) - conn_error(conn, HTTP_STATUS_NOT_IMPLEMENTED, NULL); - else if (nparsed != nread) - conn_error(conn, HTTP_STATUS_BAD_REQUEST, http_errno_description(parser->http_errno)); + return; + +done: + conn_free(conn); } static void keepalive_cb(struct ev_loop *loop, struct ev_timer *w, int revents) diff --git a/src/connection.h b/src/connection.h index 9ec6bb9..3326430 100644 --- a/src/connection.h +++ b/src/connection.h @@ -47,6 +47,7 @@ struct uh_str { }; struct uh_request { + size_t length; /* The total length of the request which still remain in buffer */ struct { ssize_t offset; size_t length; @@ -66,6 +67,7 @@ struct uh_request { } headers[UHTTPD_MAX_HEADER_NUM]; struct { + bool consumed; /* Indicates whether the extract_body is called */ ssize_t offset; size_t length; } body;