mirror of
https://github.com/cuberite/libevent.git
synced 2025-08-04 01:36:23 -04:00
http: lingering close (like nginx have) for entity-too-large
By lingering close I mean something what nginx have for this name, by this term I mean that we need to read all the body even if it's size greater then `max_body_size`, otherwise browsers on win32 (including chrome) failed read the http status - entity-too-large (while on linux chrome for instance are good), and also this includes badly written http clients. Refs: #321 v2: do this only under EVHTTP_SERVER_LINGERING_CLOSE
This commit is contained in:
parent
680742e166
commit
9fde5189df
@ -154,6 +154,7 @@ struct evhttp {
|
||||
|
||||
size_t default_max_headers_size;
|
||||
ev_uint64_t default_max_body_size;
|
||||
int flags;
|
||||
const char *default_content_type;
|
||||
|
||||
/* Bitmask of all HTTP methods that we accept and pass to user
|
||||
|
46
http.c
46
http.c
@ -984,6 +984,25 @@ evhttp_read_trailer(struct evhttp_connection *evcon, struct evhttp_request *req)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
evhttp_lingering_close(struct evhttp_connection *evcon, struct evhttp_request *req)
|
||||
{
|
||||
struct evbuffer *buf = bufferevent_get_input(evcon->bufev);
|
||||
|
||||
size_t n = evbuffer_get_length(buf);
|
||||
if (n > (size_t) req->ntoread)
|
||||
n = (size_t) req->ntoread;
|
||||
req->ntoread -= n;
|
||||
req->body_size += n;
|
||||
|
||||
event_debug(("Request body is too long, left " EV_SIZE_FMT,
|
||||
EV_SIZE_ARG(req->ntoread)));
|
||||
|
||||
evbuffer_drain(buf, n);
|
||||
if (!req->ntoread)
|
||||
evhttp_connection_fail_(evcon, EVREQ_HTTP_DATA_TOO_LONG);
|
||||
}
|
||||
|
||||
static void
|
||||
evhttp_read_body(struct evhttp_connection *evcon, struct evhttp_request *req)
|
||||
{
|
||||
@ -1037,9 +1056,12 @@ evhttp_read_body(struct evhttp_connection *evcon, struct evhttp_request *req)
|
||||
(size_t)req->ntoread > req->evcon->max_body_size)) {
|
||||
/* XXX: The above casted comparison must checked for overflow */
|
||||
/* failed body length test */
|
||||
event_debug(("Request body is too long"));
|
||||
evhttp_connection_fail_(evcon,
|
||||
EVREQ_HTTP_DATA_TOO_LONG);
|
||||
|
||||
if (evcon->flags & EVHTTP_CON_LINGERING_CLOSE)
|
||||
evhttp_lingering_close(evcon, req);
|
||||
else
|
||||
evhttp_connection_fail_(evcon, EVREQ_HTTP_DATA_TOO_LONG);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1055,7 +1077,7 @@ evhttp_read_body(struct evhttp_connection *evcon, struct evhttp_request *req)
|
||||
}
|
||||
}
|
||||
|
||||
if (req->ntoread == 0) {
|
||||
if (!req->ntoread) {
|
||||
bufferevent_disable(evcon->bufev, EV_READ);
|
||||
/* Completed content length */
|
||||
evhttp_connection_done(evcon);
|
||||
@ -3719,6 +3741,20 @@ evhttp_set_timeout_tv(struct evhttp* http, const struct timeval* tv)
|
||||
}
|
||||
}
|
||||
|
||||
int evhttp_set_flags(struct evhttp *http, int flags)
|
||||
{
|
||||
int avail_flags = 0;
|
||||
avail_flags |= EVHTTP_SERVER_LINGERING_CLOSE;
|
||||
|
||||
if (flags & ~avail_flags)
|
||||
return 1;
|
||||
http->flags &= ~avail_flags;
|
||||
|
||||
http->flags |= flags;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
evhttp_set_max_headers_size(struct evhttp* http, ev_ssize_t max_headers_size)
|
||||
{
|
||||
@ -4091,6 +4127,8 @@ evhttp_get_request_connection(
|
||||
|
||||
evcon->max_headers_size = http->default_max_headers_size;
|
||||
evcon->max_body_size = http->default_max_body_size;
|
||||
if (http->flags & EVHTTP_SERVER_LINGERING_CLOSE)
|
||||
evcon->flags |= EVHTTP_CON_LINGERING_CLOSE;
|
||||
|
||||
evcon->flags |= EVHTTP_CON_INCOMING;
|
||||
evcon->state = EVCON_READING_FIRSTLINE;
|
||||
|
@ -373,6 +373,19 @@ void evhttp_set_timeout(struct evhttp *http, int timeout_in_secs);
|
||||
EVENT2_EXPORT_SYMBOL
|
||||
void evhttp_set_timeout_tv(struct evhttp *http, const struct timeval* tv);
|
||||
|
||||
/* Read all the clients body, and only after this respond with an error if the
|
||||
* clients body exceed max_body_size */
|
||||
#define EVHTTP_SERVER_LINGERING_CLOSE 0x0001
|
||||
/**
|
||||
* Set connection flags for HTTP server.
|
||||
*
|
||||
* @see EVHTTP_SERVER_*
|
||||
* @return 0 on success, otherwise non zero (for example if flag doesn't
|
||||
* supported).
|
||||
*/
|
||||
EVENT2_EXPORT_SYMBOL
|
||||
int evhttp_set_flags(struct evhttp *http, int flags);
|
||||
|
||||
/* Request/Response functionality */
|
||||
|
||||
/**
|
||||
@ -643,6 +656,8 @@ void evhttp_connection_set_family(struct evhttp_connection *evcon,
|
||||
* connection, but if at that time we have some data to send then we
|
||||
* can send get EPIPE and fail, while we can read that HTTP error. */
|
||||
#define EVHTTP_CON_READ_ON_WRITE_ERROR 0x0010
|
||||
/* @see EVHTTP_SERVER_LINGERING_CLOSE */
|
||||
#define EVHTTP_CON_LINGERING_CLOSE 0x0020
|
||||
/* Padding for public flags, @see EVHTTP_CON_* in http-internal.h */
|
||||
#define EVHTTP_CON_PUBLIC_FLAGS_END 0x100000
|
||||
/**
|
||||
|
Loading…
x
Reference in New Issue
Block a user