diff --git a/http.c b/http.c index fd7ce3cb..a2d9f878 100644 --- a/http.c +++ b/http.c @@ -1372,6 +1372,28 @@ evhttp_connection_cb_cleanup(struct evhttp_connection *evcon) } } +static void +evhttp_connection_read_on_write_error(struct evhttp_connection *evcon, + struct evhttp_request *req) +{ + struct evbuffer *buf; + + evcon->state = EVCON_READING_FIRSTLINE; + req->kind = EVHTTP_RESPONSE; + + buf = bufferevent_get_output(evcon->bufev); + evbuffer_unfreeze(buf, 1); + evbuffer_drain(buf, evbuffer_get_length(buf)); + evbuffer_freeze(buf, 1); + + bufferevent_setcb(evcon->bufev, + evhttp_read_cb, + NULL, /* evhttp_write_cb */ + evhttp_error_cb, + evcon); + evhttp_connection_start_detectclose(evcon); +} + static void evhttp_error_cb(struct bufferevent *bufev, short what, void *arg) { @@ -1441,6 +1463,12 @@ evhttp_error_cb(struct bufferevent *bufev, short what, void *arg) if (what & BEV_EVENT_TIMEOUT) { evhttp_connection_fail_(evcon, EVREQ_HTTP_TIMEOUT); } else if (what & (BEV_EVENT_EOF|BEV_EVENT_ERROR)) { + if (what & BEV_EVENT_WRITING && + evcon->flags & EVHTTP_CON_READ_ON_WRITE_ERROR) { + evhttp_connection_read_on_write_error(evcon, req); + return; + } + evhttp_connection_fail_(evcon, EVREQ_HTTP_EOF); } else if (what == BEV_EVENT_CONNECTED) { } else { @@ -2344,6 +2372,7 @@ int evhttp_connection_set_flags(struct evhttp_connection *evcon, { int avail_flags = 0; avail_flags |= EVHTTP_CON_REUSE_CONNECTED_ADDR; + avail_flags |= EVHTTP_CON_READ_ON_WRITE_ERROR; if (flags & ~avail_flags || flags > EVHTTP_CON_PUBLIC_FLAGS_END) return 1; diff --git a/include/event2/http.h b/include/event2/http.h index e9978207..c7ed4ccf 100644 --- a/include/event2/http.h +++ b/include/event2/http.h @@ -639,6 +639,10 @@ void evhttp_connection_set_family(struct evhttp_connection *evcon, /* reuse connection address on retry */ #define EVHTTP_CON_REUSE_CONNECTED_ADDR 0x0008 +/* Try to read error, since server may already send and close + * 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 /* Padding for public flags, @see EVHTTP_CON_* in http-internal.h */ #define EVHTTP_CON_PUBLIC_FLAGS_END 0x100000 /**