[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[Libevent-users] [patch] Add callback for handling incoming connection errors



Hi,

Currently, there is no way to inform user about some type of http connection errors(like network timeout). The gencb will be still called if invalid http request was encountered, but the error kind is not exposed. Is some situatons, we need all this info(like for logging purposes). So, here's the patch which adds the possibility to set the connection failure callback for the evhttp instance. It adds new function - evhttp_set_errorcb() to set the callback. Also, it makes the contents of evhttp_connection_error enum public
diff --git a/http-internal.h b/http-internal.h
index 49ee9bc..86a0ee2 100644
--- a/http-internal.h
+++ b/http-internal.h
@@ -28,13 +28,7 @@ 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
-};
+enum evhttp_connection_error;
 
 struct evbuffer;
 struct addrinfo;
@@ -139,6 +133,9 @@ struct evhttp {
 	void (*gencb)(struct evhttp_request *req, void *);
 	void *gencbarg;
 
+	void (*errorcb)(enum evhttp_connection_error, struct evhttp_connection *evcon, void *);
+	void *errorcbarg;
+
 	struct event_base *base;
 };
 
diff --git a/http.c b/http.c
index 26e81ca..ea821a5 100644
--- a/http.c
+++ b/http.c
@@ -544,6 +544,13 @@ static int
 evhttp_connection_incoming_fail(struct evhttp_request *req,
     enum evhttp_connection_error error)
 {
+	EVUTIL_ASSERT(req->evcon != NULL);
+
+	if (req->evcon->http_server != NULL && req->evcon->http_server->errorcb != NULL) {
+		(*req->evcon->http_server->errorcb)(error, req->evcon,
+						    req->evcon->http_server->errorcbarg);
+	}
+		
 	switch (error) {
 	case EVCON_HTTP_TIMEOUT:
 	case EVCON_HTTP_EOF:
@@ -2742,6 +2749,15 @@ evhttp_set_gencb(struct evhttp *http,
 	http->gencbarg = cbarg;
 }
 
+void
+evhttp_set_errorcb(struct evhttp *http,
+    void (*cb)(enum evhttp_connection_error, struct evhttp_connection *, void *),
+    void (*cbarg))
+{
+	http->errorcb = cb;
+	http->errorcbarg = cbarg;
+}
+
 /*
  * Request related functions
  */
diff --git a/include/event2/http.h b/include/event2/http.h
index 328eefa..3731137 100644
--- a/include/event2/http.h
+++ b/include/event2/http.h
@@ -66,7 +66,17 @@ struct event_base;
 #define HTTP_NOTFOUND		404	/**< could not find content for uri */
 #define HTTP_SERVUNAVAIL	503	/**< the server is not available */
 
+
+enum evhttp_connection_error {
+	EVCON_HTTP_TIMEOUT,
+	EVCON_HTTP_EOF,
+	EVCON_HTTP_INVALID_HEADER,
+	EVCON_HTTP_BUFFER_ERROR,
+	EVCON_HTTP_REQUEST_CANCEL
+};
+
 struct evhttp;
+struct evhttp_connection;
 struct evhttp_request;
 struct evkeyvalq;
 struct evhttp_bound_socket;
@@ -206,6 +216,10 @@ int evhttp_del_cb(struct evhttp *, const char *);
 void evhttp_set_gencb(struct evhttp *http,
     void (*cb)(struct evhttp_request *, void *), void *arg);
 
+void evhttp_set_errorcb(struct evhttp *http,
+    void (*cb)(enum evhttp_connection_error, struct evhttp_connection *, void *),
+    void (*arg));
+	
 /**
    Adds a virtual host to the http server.
 
diff --git a/test/regress_http.c b/test/regress_http.c
index c91fbb4..b303fe8 100644
--- a/test/regress_http.c
+++ b/test/regress_http.c
@@ -1171,12 +1171,18 @@ http_failure_readcb(struct bufferevent *bev, void *arg)
 	const char *what = "400 Bad Request";
 	if (evbuffer_find(bufferevent_get_input(bev),
 		(const unsigned char*) what, strlen(what)) != NULL) {
-		test_ok = 2;
+		test_ok += 1;
 		bufferevent_disable(bev, EV_READ);
 		event_loopexit(NULL);
 	}
 }
 
+
+static void http_failure_errorcb(enum evhttp_connection_error err,
+                                 struct evhttp_connection* conn, void *arg)
+{
+	test_ok += 1;
+}
 /*
  * Testing that the HTTP server can deal with a malformed request.
  */
@@ -1194,6 +1200,7 @@ http_failure_test(void)
 
 	fd = http_connect("127.0.0.1", port);
 
+        evhttp_set_errorcb(http, http_failure_errorcb, NULL);
 	/* Stupid thing to send a request */
 	bev = bufferevent_new(fd, http_failure_readcb, http_writecb,
 	    http_errorcb, NULL);
@@ -1209,7 +1216,7 @@ http_failure_test(void)
 
 	evhttp_free(http);
 
-	tt_int_op(test_ok, ==, 2);
+	tt_int_op(test_ok, ==, 3);
  end:
 	;
 }
@@ -2198,6 +2205,16 @@ end:
 }
 
 static void
+http_data_length_constraints_errorcb(enum evhttp_connection_error err,
+				     struct evhttp_connection* conn,
+				     void* arg)
+{
+	if (err == EVCON_HTTP_INVALID_HEADER) {
+		test_ok++;
+	}
+}
+
+static void
 http_data_length_constraints_test(void)
 {
 	short port = -1;
@@ -2220,6 +2237,7 @@ http_data_length_constraints_test(void)
 	 * server using our make request method.
 	 */
 
+	evhttp_set_errorcb(http, http_data_length_constraints_errorcb, NULL);
 	req = evhttp_request_new(http_data_length_constraints_test_done, NULL);
 	tt_assert(req);
 
@@ -2234,6 +2252,7 @@ http_data_length_constraints_test(void)
 		tt_abort_msg("Couldn't make request");
 	}
 	event_dispatch();
+	tt_int_op(test_ok, ==, 1);
 
 	req = evhttp_request_new(http_data_length_constraints_test_done, NULL);
 	tt_assert(req);
@@ -2244,6 +2263,7 @@ http_data_length_constraints_test(void)
 		tt_abort_msg("Couldn't make request");
 	}
 	event_dispatch();
+	tt_int_op(test_ok, ==, 2);
 
 	evhttp_set_max_body_size(http, 8190);
 	req = evhttp_request_new(http_data_length_constraints_test_done, NULL);
@@ -2254,7 +2274,8 @@ http_data_length_constraints_test(void)
 	}
 	event_dispatch();
 
-        test_ok = 1;
+	tt_int_op(test_ok, ==, 3);
+
  end:
 	if (evcon)
 		evhttp_connection_free(evcon);