mirror of
https://github.com/libevent/libevent.git
synced 2025-01-31 09:12:55 +08: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;
|
||||
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
|
||||
};
|
||||
|
||||
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 addrinfo;
|
||||
struct evhttp_request;
|
||||
@ -182,9 +174,10 @@ void evhttp_connection_reset_(struct evhttp_connection *);
|
||||
/* connects if necessary */
|
||||
int evhttp_connection_connect_(struct evhttp_connection *);
|
||||
|
||||
enum evhttp_request_error;
|
||||
/* notifies the current request that it failed; resets connection */
|
||||
void evhttp_connection_fail_(struct evhttp_connection *,
|
||||
enum evhttp_connection_error error);
|
||||
enum evhttp_request_error error);
|
||||
|
||||
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
|
||||
evhttp_connection_incoming_fail(struct evhttp_request *req,
|
||||
enum evhttp_connection_error error)
|
||||
enum evhttp_request_error error)
|
||||
{
|
||||
switch (error) {
|
||||
case EVCON_HTTP_TIMEOUT:
|
||||
case EVCON_HTTP_EOF:
|
||||
case EVREQ_HTTP_TIMEOUT:
|
||||
case EVREQ_HTTP_EOF:
|
||||
/*
|
||||
* these are cases in which we probably should just
|
||||
* close the connection and not send a reply. this
|
||||
@ -647,9 +647,10 @@ evhttp_connection_incoming_fail(struct evhttp_request *req,
|
||||
req->evcon = NULL;
|
||||
}
|
||||
return (-1);
|
||||
case EVCON_HTTP_INVALID_HEADER:
|
||||
case EVCON_HTTP_BUFFER_ERROR:
|
||||
case EVCON_HTTP_REQUEST_CANCEL:
|
||||
case EVREQ_HTTP_INVALID_HEADER:
|
||||
case EVREQ_HTTP_BUFFER_ERROR:
|
||||
case EVREQ_HTTP_REQUEST_CANCEL:
|
||||
case EVREQ_HTTP_DATA_TOO_LONG:
|
||||
default: /* xxx: probably should just error on default */
|
||||
/* the callback looks at the uri to determine errors */
|
||||
if (req->uri) {
|
||||
@ -677,12 +678,14 @@ evhttp_connection_incoming_fail(struct evhttp_request *req,
|
||||
* delegates to evhttp_connection_incoming_fail(). */
|
||||
void
|
||||
evhttp_connection_fail_(struct evhttp_connection *evcon,
|
||||
enum evhttp_connection_error error)
|
||||
enum evhttp_request_error error)
|
||||
{
|
||||
const int errsave = EVUTIL_SOCKET_ERROR();
|
||||
struct evhttp_request* req = TAILQ_FIRST(&evcon->requests);
|
||||
void (*cb)(struct evhttp_request *, void *);
|
||||
void *cb_arg;
|
||||
void (*error_cb)(enum evhttp_request_error, void *);
|
||||
void *error_cb_arg;
|
||||
EVUTIL_ASSERT(req != NULL);
|
||||
|
||||
bufferevent_disable(evcon->bufev, EV_READ|EV_WRITE);
|
||||
@ -701,8 +704,10 @@ evhttp_connection_fail_(struct evhttp_connection *evcon,
|
||||
return;
|
||||
}
|
||||
|
||||
error_cb = req->error_cb;
|
||||
error_cb_arg = req->cb_arg;
|
||||
/* 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 */
|
||||
cb = req->cb;
|
||||
cb_arg = req->cb_arg;
|
||||
@ -732,6 +737,8 @@ evhttp_connection_fail_(struct evhttp_connection *evcon,
|
||||
EVUTIL_SET_SOCKET_ERROR(errsave);
|
||||
|
||||
/* inform the user */
|
||||
if (error_cb != NULL)
|
||||
error_cb(error, error_cb_arg);
|
||||
if (cb != NULL)
|
||||
(*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)) {
|
||||
case DATA_CORRUPTED:
|
||||
case DATA_TOO_LONG:
|
||||
evhttp_connection_fail_(evcon, EVCON_HTTP_INVALID_HEADER);
|
||||
evhttp_connection_fail_(evcon, EVREQ_HTTP_DATA_TOO_LONG);
|
||||
break;
|
||||
case ALL_DATA_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);
|
||||
return;
|
||||
case DATA_CORRUPTED:
|
||||
case DATA_TOO_LONG:/*separate error for this? XXX */
|
||||
case DATA_TOO_LONG:
|
||||
/* corrupted data */
|
||||
evhttp_connection_fail_(evcon,
|
||||
EVCON_HTTP_INVALID_HEADER);
|
||||
EVREQ_HTTP_DATA_TOO_LONG);
|
||||
return;
|
||||
case REQUEST_CANCELED:
|
||||
/* request canceled */
|
||||
@ -968,7 +975,7 @@ evhttp_read_body(struct evhttp_connection *evcon, struct evhttp_request *req)
|
||||
} else if (req->ntoread < 0) {
|
||||
/* Read until connection close. */
|
||||
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;
|
||||
}
|
||||
|
||||
@ -994,7 +1001,7 @@ evhttp_read_body(struct evhttp_connection *evcon, struct evhttp_request *req)
|
||||
/* failed body length test */
|
||||
event_debug(("Request body is too long"));
|
||||
evhttp_connection_fail_(evcon,
|
||||
EVCON_HTTP_INVALID_HEADER);
|
||||
EVREQ_HTTP_DATA_TOO_LONG);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1375,12 +1382,12 @@ evhttp_error_cb(struct bufferevent *bufev, short what, void *arg)
|
||||
}
|
||||
|
||||
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)) {
|
||||
evhttp_connection_fail_(evcon, EVCON_HTTP_EOF);
|
||||
evhttp_connection_fail_(evcon, EVREQ_HTTP_EOF);
|
||||
} else if (what == BEV_EVENT_CONNECTED) {
|
||||
} 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 {
|
||||
if (evhttp_get_body_length(req) == -1) {
|
||||
evhttp_connection_fail_(evcon,
|
||||
EVCON_HTTP_INVALID_HEADER);
|
||||
EVREQ_HTTP_INVALID_HEADER);
|
||||
return;
|
||||
}
|
||||
if (req->kind == EVHTTP_REQUEST && req->ntoread < 1) {
|
||||
@ -2088,7 +2095,7 @@ evhttp_read_firstline(struct evhttp_connection *evcon,
|
||||
/* Error while reading, terminate */
|
||||
event_debug(("%s: bad header lines on "EV_SOCK_FMT"\n",
|
||||
__func__, EV_SOCK_ARG(evcon->fd)));
|
||||
evhttp_connection_fail_(evcon, EVCON_HTTP_INVALID_HEADER);
|
||||
evhttp_connection_fail_(evcon, EVREQ_HTTP_INVALID_HEADER);
|
||||
return;
|
||||
} else if (res == MORE_DATA_EXPECTED) {
|
||||
/* Need more header lines */
|
||||
@ -2111,7 +2118,7 @@ evhttp_read_header(struct evhttp_connection *evcon,
|
||||
/* Error while reading, terminate */
|
||||
event_debug(("%s: bad header lines on "EV_SOCK_FMT"\n",
|
||||
__func__, EV_SOCK_ARG(fd)));
|
||||
evhttp_connection_fail_(evcon, EVCON_HTTP_INVALID_HEADER);
|
||||
evhttp_connection_fail_(evcon, EVREQ_HTTP_INVALID_HEADER);
|
||||
return;
|
||||
} else if (res == MORE_DATA_EXPECTED) {
|
||||
/* Need more header lines */
|
||||
@ -2153,7 +2160,7 @@ evhttp_read_header(struct evhttp_connection *evcon,
|
||||
default:
|
||||
event_warnx("%s: bad header on "EV_SOCK_FMT, __func__,
|
||||
EV_SOCK_ARG(fd));
|
||||
evhttp_connection_fail_(evcon, EVCON_HTTP_INVALID_HEADER);
|
||||
evhttp_connection_fail_(evcon, EVREQ_HTTP_INVALID_HEADER);
|
||||
break;
|
||||
}
|
||||
/* request may have been freed above */
|
||||
@ -2454,7 +2461,7 @@ evhttp_cancel_request(struct evhttp_request *req)
|
||||
* the connection.
|
||||
*/
|
||||
evhttp_connection_fail_(evcon,
|
||||
EVCON_HTTP_REQUEST_CANCEL);
|
||||
EVREQ_HTTP_REQUEST_CANCEL);
|
||||
|
||||
/* connection fail freed the request */
|
||||
return;
|
||||
@ -3764,6 +3771,13 @@ evhttp_request_set_chunked_cb(struct evhttp_request *req,
|
||||
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
|
||||
*/
|
||||
|
@ -470,6 +470,47 @@ struct evhttp_request *evhttp_request_new(
|
||||
void evhttp_request_set_chunked_cb(struct evhttp_request *,
|
||||
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. */
|
||||
void evhttp_request_free(struct evhttp_request *req);
|
||||
|
||||
|
@ -120,6 +120,13 @@ struct {
|
||||
* the regular callback.
|
||||
*/
|
||||
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
|
||||
|
@ -56,6 +56,7 @@
|
||||
|
||||
#include "event2/event.h"
|
||||
#include "event2/http.h"
|
||||
#include "event2/http_struct.h"
|
||||
#include "event2/buffer.h"
|
||||
#include "event2/bufferevent.h"
|
||||
#include "event2/util.h"
|
||||
@ -647,7 +648,7 @@ http_large_delay_cb(struct evhttp_request *req, void *arg)
|
||||
tv.tv_usec = 500000;
|
||||
|
||||
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