mirror of
https://github.com/cuberite/libevent.git
synced 2025-09-09 12:28:19 -04:00
Add new error_cb for actual reporting of HTTP request errors.
It is useful to know why you callback called with NULL (i.e. it failed), for example if you set max_body with evhttp_connection_set_max_body_size() you must know that it failed because of body was longer than this size. (Commit message tweaked by Nick)
This commit is contained in:
parent
f935e2159a
commit
7b077194cc
2
evrpc.c
2
evrpc.c
@ -977,7 +977,7 @@ evrpc_request_timeout(evutil_socket_t fd, short what, void *arg)
|
|||||||
struct evhttp_connection *evcon = ctx->evcon;
|
struct evhttp_connection *evcon = ctx->evcon;
|
||||||
EVUTIL_ASSERT(evcon != NULL);
|
EVUTIL_ASSERT(evcon != NULL);
|
||||||
|
|
||||||
evhttp_connection_fail_(evcon, EVCON_HTTP_TIMEOUT);
|
evhttp_connection_fail_(evcon, EVREQ_HTTP_TIMEOUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -29,14 +29,6 @@ enum message_read_status {
|
|||||||
DATA_TOO_LONG = -3
|
DATA_TOO_LONG = -3
|
||||||
};
|
};
|
||||||
|
|
||||||
enum evhttp_connection_error {
|
|
||||||
EVCON_HTTP_TIMEOUT,
|
|
||||||
EVCON_HTTP_EOF,
|
|
||||||
EVCON_HTTP_INVALID_HEADER,
|
|
||||||
EVCON_HTTP_BUFFER_ERROR,
|
|
||||||
EVCON_HTTP_REQUEST_CANCEL
|
|
||||||
};
|
|
||||||
|
|
||||||
struct evbuffer;
|
struct evbuffer;
|
||||||
struct addrinfo;
|
struct addrinfo;
|
||||||
struct evhttp_request;
|
struct evhttp_request;
|
||||||
@ -182,9 +174,10 @@ void evhttp_connection_reset_(struct evhttp_connection *);
|
|||||||
/* connects if necessary */
|
/* connects if necessary */
|
||||||
int evhttp_connection_connect_(struct evhttp_connection *);
|
int evhttp_connection_connect_(struct evhttp_connection *);
|
||||||
|
|
||||||
|
enum evhttp_request_error;
|
||||||
/* notifies the current request that it failed; resets connection */
|
/* notifies the current request that it failed; resets connection */
|
||||||
void evhttp_connection_fail_(struct evhttp_connection *,
|
void evhttp_connection_fail_(struct evhttp_connection *,
|
||||||
enum evhttp_connection_error error);
|
enum evhttp_request_error error);
|
||||||
|
|
||||||
enum message_read_status;
|
enum message_read_status;
|
||||||
|
|
||||||
|
56
http.c
56
http.c
@ -625,11 +625,11 @@ evhttp_connection_set_max_body_size(struct evhttp_connection* evcon,
|
|||||||
|
|
||||||
static int
|
static int
|
||||||
evhttp_connection_incoming_fail(struct evhttp_request *req,
|
evhttp_connection_incoming_fail(struct evhttp_request *req,
|
||||||
enum evhttp_connection_error error)
|
enum evhttp_request_error error)
|
||||||
{
|
{
|
||||||
switch (error) {
|
switch (error) {
|
||||||
case EVCON_HTTP_TIMEOUT:
|
case EVREQ_HTTP_TIMEOUT:
|
||||||
case EVCON_HTTP_EOF:
|
case EVREQ_HTTP_EOF:
|
||||||
/*
|
/*
|
||||||
* these are cases in which we probably should just
|
* these are cases in which we probably should just
|
||||||
* close the connection and not send a reply. this
|
* close the connection and not send a reply. this
|
||||||
@ -647,9 +647,10 @@ evhttp_connection_incoming_fail(struct evhttp_request *req,
|
|||||||
req->evcon = NULL;
|
req->evcon = NULL;
|
||||||
}
|
}
|
||||||
return (-1);
|
return (-1);
|
||||||
case EVCON_HTTP_INVALID_HEADER:
|
case EVREQ_HTTP_INVALID_HEADER:
|
||||||
case EVCON_HTTP_BUFFER_ERROR:
|
case EVREQ_HTTP_BUFFER_ERROR:
|
||||||
case EVCON_HTTP_REQUEST_CANCEL:
|
case EVREQ_HTTP_REQUEST_CANCEL:
|
||||||
|
case EVREQ_HTTP_DATA_TOO_LONG:
|
||||||
default: /* xxx: probably should just error on default */
|
default: /* xxx: probably should just error on default */
|
||||||
/* the callback looks at the uri to determine errors */
|
/* the callback looks at the uri to determine errors */
|
||||||
if (req->uri) {
|
if (req->uri) {
|
||||||
@ -677,12 +678,14 @@ evhttp_connection_incoming_fail(struct evhttp_request *req,
|
|||||||
* delegates to evhttp_connection_incoming_fail(). */
|
* delegates to evhttp_connection_incoming_fail(). */
|
||||||
void
|
void
|
||||||
evhttp_connection_fail_(struct evhttp_connection *evcon,
|
evhttp_connection_fail_(struct evhttp_connection *evcon,
|
||||||
enum evhttp_connection_error error)
|
enum evhttp_request_error error)
|
||||||
{
|
{
|
||||||
const int errsave = EVUTIL_SOCKET_ERROR();
|
const int errsave = EVUTIL_SOCKET_ERROR();
|
||||||
struct evhttp_request* req = TAILQ_FIRST(&evcon->requests);
|
struct evhttp_request* req = TAILQ_FIRST(&evcon->requests);
|
||||||
void (*cb)(struct evhttp_request *, void *);
|
void (*cb)(struct evhttp_request *, void *);
|
||||||
void *cb_arg;
|
void *cb_arg;
|
||||||
|
void (*error_cb)(enum evhttp_request_error, void *);
|
||||||
|
void *error_cb_arg;
|
||||||
EVUTIL_ASSERT(req != NULL);
|
EVUTIL_ASSERT(req != NULL);
|
||||||
|
|
||||||
bufferevent_disable(evcon->bufev, EV_READ|EV_WRITE);
|
bufferevent_disable(evcon->bufev, EV_READ|EV_WRITE);
|
||||||
@ -701,8 +704,10 @@ evhttp_connection_fail_(struct evhttp_connection *evcon,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
error_cb = req->error_cb;
|
||||||
|
error_cb_arg = req->cb_arg;
|
||||||
/* when the request was canceled, the callback is not executed */
|
/* when the request was canceled, the callback is not executed */
|
||||||
if (error != EVCON_HTTP_REQUEST_CANCEL) {
|
if (error != EVREQ_HTTP_REQUEST_CANCEL) {
|
||||||
/* save the callback for later; the cb might free our object */
|
/* save the callback for later; the cb might free our object */
|
||||||
cb = req->cb;
|
cb = req->cb;
|
||||||
cb_arg = req->cb_arg;
|
cb_arg = req->cb_arg;
|
||||||
@ -732,6 +737,8 @@ evhttp_connection_fail_(struct evhttp_connection *evcon,
|
|||||||
EVUTIL_SET_SOCKET_ERROR(errsave);
|
EVUTIL_SET_SOCKET_ERROR(errsave);
|
||||||
|
|
||||||
/* inform the user */
|
/* inform the user */
|
||||||
|
if (error_cb != NULL)
|
||||||
|
error_cb(error, error_cb_arg);
|
||||||
if (cb != NULL)
|
if (cb != NULL)
|
||||||
(*cb)(NULL, cb_arg);
|
(*cb)(NULL, cb_arg);
|
||||||
}
|
}
|
||||||
@ -925,7 +932,7 @@ evhttp_read_trailer(struct evhttp_connection *evcon, struct evhttp_request *req)
|
|||||||
switch (evhttp_parse_headers_(req, buf)) {
|
switch (evhttp_parse_headers_(req, buf)) {
|
||||||
case DATA_CORRUPTED:
|
case DATA_CORRUPTED:
|
||||||
case DATA_TOO_LONG:
|
case DATA_TOO_LONG:
|
||||||
evhttp_connection_fail_(evcon, EVCON_HTTP_INVALID_HEADER);
|
evhttp_connection_fail_(evcon, EVREQ_HTTP_DATA_TOO_LONG);
|
||||||
break;
|
break;
|
||||||
case ALL_DATA_READ:
|
case ALL_DATA_READ:
|
||||||
bufferevent_disable(evcon->bufev, EV_READ);
|
bufferevent_disable(evcon->bufev, EV_READ);
|
||||||
@ -952,10 +959,10 @@ evhttp_read_body(struct evhttp_connection *evcon, struct evhttp_request *req)
|
|||||||
evhttp_read_trailer(evcon, req);
|
evhttp_read_trailer(evcon, req);
|
||||||
return;
|
return;
|
||||||
case DATA_CORRUPTED:
|
case DATA_CORRUPTED:
|
||||||
case DATA_TOO_LONG:/*separate error for this? XXX */
|
case DATA_TOO_LONG:
|
||||||
/* corrupted data */
|
/* corrupted data */
|
||||||
evhttp_connection_fail_(evcon,
|
evhttp_connection_fail_(evcon,
|
||||||
EVCON_HTTP_INVALID_HEADER);
|
EVREQ_HTTP_DATA_TOO_LONG);
|
||||||
return;
|
return;
|
||||||
case REQUEST_CANCELED:
|
case REQUEST_CANCELED:
|
||||||
/* request canceled */
|
/* request canceled */
|
||||||
@ -968,7 +975,7 @@ evhttp_read_body(struct evhttp_connection *evcon, struct evhttp_request *req)
|
|||||||
} else if (req->ntoread < 0) {
|
} else if (req->ntoread < 0) {
|
||||||
/* Read until connection close. */
|
/* Read until connection close. */
|
||||||
if ((size_t)(req->body_size + evbuffer_get_length(buf)) < req->body_size) {
|
if ((size_t)(req->body_size + evbuffer_get_length(buf)) < req->body_size) {
|
||||||
evhttp_connection_fail_(evcon, EVCON_HTTP_INVALID_HEADER);
|
evhttp_connection_fail_(evcon, EVREQ_HTTP_INVALID_HEADER);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -994,7 +1001,7 @@ evhttp_read_body(struct evhttp_connection *evcon, struct evhttp_request *req)
|
|||||||
/* failed body length test */
|
/* failed body length test */
|
||||||
event_debug(("Request body is too long"));
|
event_debug(("Request body is too long"));
|
||||||
evhttp_connection_fail_(evcon,
|
evhttp_connection_fail_(evcon,
|
||||||
EVCON_HTTP_INVALID_HEADER);
|
EVREQ_HTTP_DATA_TOO_LONG);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1375,12 +1382,12 @@ evhttp_error_cb(struct bufferevent *bufev, short what, void *arg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (what & BEV_EVENT_TIMEOUT) {
|
if (what & BEV_EVENT_TIMEOUT) {
|
||||||
evhttp_connection_fail_(evcon, EVCON_HTTP_TIMEOUT);
|
evhttp_connection_fail_(evcon, EVREQ_HTTP_TIMEOUT);
|
||||||
} else if (what & (BEV_EVENT_EOF|BEV_EVENT_ERROR)) {
|
} else if (what & (BEV_EVENT_EOF|BEV_EVENT_ERROR)) {
|
||||||
evhttp_connection_fail_(evcon, EVCON_HTTP_EOF);
|
evhttp_connection_fail_(evcon, EVREQ_HTTP_EOF);
|
||||||
} else if (what == BEV_EVENT_CONNECTED) {
|
} else if (what == BEV_EVENT_CONNECTED) {
|
||||||
} else {
|
} else {
|
||||||
evhttp_connection_fail_(evcon, EVCON_HTTP_BUFFER_ERROR);
|
evhttp_connection_fail_(evcon, EVREQ_HTTP_BUFFER_ERROR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2032,7 +2039,7 @@ evhttp_get_body(struct evhttp_connection *evcon, struct evhttp_request *req)
|
|||||||
} else {
|
} else {
|
||||||
if (evhttp_get_body_length(req) == -1) {
|
if (evhttp_get_body_length(req) == -1) {
|
||||||
evhttp_connection_fail_(evcon,
|
evhttp_connection_fail_(evcon,
|
||||||
EVCON_HTTP_INVALID_HEADER);
|
EVREQ_HTTP_INVALID_HEADER);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (req->kind == EVHTTP_REQUEST && req->ntoread < 1) {
|
if (req->kind == EVHTTP_REQUEST && req->ntoread < 1) {
|
||||||
@ -2088,7 +2095,7 @@ evhttp_read_firstline(struct evhttp_connection *evcon,
|
|||||||
/* Error while reading, terminate */
|
/* Error while reading, terminate */
|
||||||
event_debug(("%s: bad header lines on "EV_SOCK_FMT"\n",
|
event_debug(("%s: bad header lines on "EV_SOCK_FMT"\n",
|
||||||
__func__, EV_SOCK_ARG(evcon->fd)));
|
__func__, EV_SOCK_ARG(evcon->fd)));
|
||||||
evhttp_connection_fail_(evcon, EVCON_HTTP_INVALID_HEADER);
|
evhttp_connection_fail_(evcon, EVREQ_HTTP_INVALID_HEADER);
|
||||||
return;
|
return;
|
||||||
} else if (res == MORE_DATA_EXPECTED) {
|
} else if (res == MORE_DATA_EXPECTED) {
|
||||||
/* Need more header lines */
|
/* Need more header lines */
|
||||||
@ -2111,7 +2118,7 @@ evhttp_read_header(struct evhttp_connection *evcon,
|
|||||||
/* Error while reading, terminate */
|
/* Error while reading, terminate */
|
||||||
event_debug(("%s: bad header lines on "EV_SOCK_FMT"\n",
|
event_debug(("%s: bad header lines on "EV_SOCK_FMT"\n",
|
||||||
__func__, EV_SOCK_ARG(fd)));
|
__func__, EV_SOCK_ARG(fd)));
|
||||||
evhttp_connection_fail_(evcon, EVCON_HTTP_INVALID_HEADER);
|
evhttp_connection_fail_(evcon, EVREQ_HTTP_INVALID_HEADER);
|
||||||
return;
|
return;
|
||||||
} else if (res == MORE_DATA_EXPECTED) {
|
} else if (res == MORE_DATA_EXPECTED) {
|
||||||
/* Need more header lines */
|
/* Need more header lines */
|
||||||
@ -2153,7 +2160,7 @@ evhttp_read_header(struct evhttp_connection *evcon,
|
|||||||
default:
|
default:
|
||||||
event_warnx("%s: bad header on "EV_SOCK_FMT, __func__,
|
event_warnx("%s: bad header on "EV_SOCK_FMT, __func__,
|
||||||
EV_SOCK_ARG(fd));
|
EV_SOCK_ARG(fd));
|
||||||
evhttp_connection_fail_(evcon, EVCON_HTTP_INVALID_HEADER);
|
evhttp_connection_fail_(evcon, EVREQ_HTTP_INVALID_HEADER);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* request may have been freed above */
|
/* request may have been freed above */
|
||||||
@ -2454,7 +2461,7 @@ evhttp_cancel_request(struct evhttp_request *req)
|
|||||||
* the connection.
|
* the connection.
|
||||||
*/
|
*/
|
||||||
evhttp_connection_fail_(evcon,
|
evhttp_connection_fail_(evcon,
|
||||||
EVCON_HTTP_REQUEST_CANCEL);
|
EVREQ_HTTP_REQUEST_CANCEL);
|
||||||
|
|
||||||
/* connection fail freed the request */
|
/* connection fail freed the request */
|
||||||
return;
|
return;
|
||||||
@ -3764,6 +3771,13 @@ evhttp_request_set_chunked_cb(struct evhttp_request *req,
|
|||||||
req->chunk_cb = cb;
|
req->chunk_cb = cb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
evhttp_request_set_error_cb(struct evhttp_request *req,
|
||||||
|
void (*cb)(enum evhttp_request_error, void *))
|
||||||
|
{
|
||||||
|
req->error_cb = cb;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Allows for inspection of the request URI
|
* Allows for inspection of the request URI
|
||||||
*/
|
*/
|
||||||
|
@ -470,6 +470,47 @@ struct evhttp_request *evhttp_request_new(
|
|||||||
void evhttp_request_set_chunked_cb(struct evhttp_request *,
|
void evhttp_request_set_chunked_cb(struct evhttp_request *,
|
||||||
void (*cb)(struct evhttp_request *, void *));
|
void (*cb)(struct evhttp_request *, void *));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The different error types supported by evhttp
|
||||||
|
*
|
||||||
|
* @see evhttp_request_set_error_cb()
|
||||||
|
*/
|
||||||
|
enum evhttp_request_error {
|
||||||
|
/**
|
||||||
|
* Timeout reached, also @see evhttp_connection_set_timeout()
|
||||||
|
*/
|
||||||
|
EVREQ_HTTP_TIMEOUT,
|
||||||
|
/**
|
||||||
|
* EOF reached
|
||||||
|
*/
|
||||||
|
EVREQ_HTTP_EOF,
|
||||||
|
/**
|
||||||
|
* Error while reading header, or invalid header
|
||||||
|
*/
|
||||||
|
EVREQ_HTTP_INVALID_HEADER,
|
||||||
|
/**
|
||||||
|
* Error encountered while reading or writing
|
||||||
|
*/
|
||||||
|
EVREQ_HTTP_BUFFER_ERROR,
|
||||||
|
/**
|
||||||
|
* The evhttp_cancel_request() called on this request.
|
||||||
|
*/
|
||||||
|
EVREQ_HTTP_REQUEST_CANCEL,
|
||||||
|
/**
|
||||||
|
* Body is greater then evhttp_connection_set_max_body_size()
|
||||||
|
*/
|
||||||
|
EVREQ_HTTP_DATA_TOO_LONG
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Set a callback for errors
|
||||||
|
* @see evhttp_request_error for error types.
|
||||||
|
*
|
||||||
|
* On error, both the error callback and the regular callback will be called,
|
||||||
|
* error callback is called before the regular callback.
|
||||||
|
**/
|
||||||
|
void evhttp_request_set_error_cb(struct evhttp_request *,
|
||||||
|
void (*)(enum evhttp_request_error, void *));
|
||||||
|
|
||||||
/** Frees the request object and removes associated events. */
|
/** Frees the request object and removes associated events. */
|
||||||
void evhttp_request_free(struct evhttp_request *req);
|
void evhttp_request_free(struct evhttp_request *req);
|
||||||
|
|
||||||
|
@ -120,6 +120,13 @@ struct {
|
|||||||
* the regular callback.
|
* the regular callback.
|
||||||
*/
|
*/
|
||||||
void (*chunk_cb)(struct evhttp_request *, void *);
|
void (*chunk_cb)(struct evhttp_request *, void *);
|
||||||
|
/*
|
||||||
|
* Error callback - called when error is occured.
|
||||||
|
* @see evhttp_request_error for error types.
|
||||||
|
*
|
||||||
|
* @see evhttp_request_set_error_cb()
|
||||||
|
*/
|
||||||
|
void (*error_cb)(enum evhttp_request_error, void *);
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
@ -56,6 +56,7 @@
|
|||||||
|
|
||||||
#include "event2/event.h"
|
#include "event2/event.h"
|
||||||
#include "event2/http.h"
|
#include "event2/http.h"
|
||||||
|
#include "event2/http_struct.h"
|
||||||
#include "event2/buffer.h"
|
#include "event2/buffer.h"
|
||||||
#include "event2/bufferevent.h"
|
#include "event2/bufferevent.h"
|
||||||
#include "event2/util.h"
|
#include "event2/util.h"
|
||||||
@ -647,7 +648,7 @@ http_large_delay_cb(struct evhttp_request *req, void *arg)
|
|||||||
tv.tv_usec = 500000;
|
tv.tv_usec = 500000;
|
||||||
|
|
||||||
event_base_once(arg, -1, EV_TIMEOUT, http_delay_reply, req, &tv);
|
event_base_once(arg, -1, EV_TIMEOUT, http_delay_reply, req, &tv);
|
||||||
evhttp_connection_fail_(delayed_client, EVCON_HTTP_EOF);
|
evhttp_connection_fail_(delayed_client, EVREQ_HTTP_EOF);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Loading…
x
Reference in New Issue
Block a user