added lib/libevent-terom-r848.diff
authorTero Marttila <terom@fixme.fi>
Sat, 07 Jun 2008 05:18:06 +0300
changeset 14 5a2246f5be78
parent 13 ee426f453cf5
child 15 e7f0697814dc
added lib/libevent-terom-r848.diff

committer: Tero Marttila <terom@fixme.fi>
.gitignore
lib/libevent-terom-r848.diff
--- a/.gitignore	Sat Jun 07 05:05:18 2008 +0300
+++ b/.gitignore	Sat Jun 07 05:18:06 2008 +0300
@@ -1,6 +1,4 @@
 .*.swp
 *.o
-render_file
-render_node
-web_main
 *.png
+*_main
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/libevent-terom-r848.diff	Sat Jun 07 05:18:06 2008 +0300
@@ -0,0 +1,325 @@
+Index: http.c
+===================================================================
+--- http.c	(revision 848)
++++ http.c	(working copy)
+@@ -167,8 +167,10 @@
+ static void evhttp_read_header_cb(struct bufferevent *bufev, void *arg);
+ static void evhttp_write_cb(struct bufferevent *, void *);
+ static void evhttp_error_cb(struct bufferevent *bufev, short what, void *arg);
++
+ static int evhttp_decode_uri_internal(const char *uri, size_t length,
+     char *ret);
++static void _evhttp_reply_notify (struct evhttp_connection *evcon, void *arg);
+ 
+ #ifndef HAVE_STRSEP
+ /* strsep replacement for platforms that lack it.  Only works if
+@@ -293,13 +295,20 @@
+ 
+ void
+ evhttp_write_buffer(struct evhttp_connection *evcon,
+-    void (*cb)(struct evhttp_connection *, void *), void *arg)
++    void (*cb)(struct evhttp_connection *, void *), void *arg,
++    size_t threshold)
+ {
+ 	event_debug(("%s: preparing to write buffer\n", __func__));
+ 
+ 	/* Set call back */
+ 	evcon->cb = cb;
+ 	evcon->cb_arg = arg;
++    
++    if (threshold > 0) {
++        bufferevent_setwatermark(evcon->bufev, EV_WRITE, threshold, 0);
++    } else {
++        bufferevent_setwatermark(evcon->bufev, EV_WRITE, 0, 0);
++    }
+ 
+ 	bufferevent_disable(evcon->bufev, EV_READ);
+ 	bufferevent_enable(evcon->bufev, EV_WRITE);
+@@ -483,6 +492,17 @@
+ 	switch (error) {
+ 	case EVCON_HTTP_TIMEOUT:
+ 	case EVCON_HTTP_EOF:
++        /*
++         * Fix a bug that caused a nasty infinite-malloc()-and-write() loop.
++         * A write buffer error (e.g. EPIPE) means that we can't write to that 
++         * socket anymore, and evhttp_connection_fail does disable
++         * EV_WRITE|EV_READ for that buffer. However, if we call req->cb, then
++         * that adds a "400 Bad Request" to the buffer, and enables it for
++         * EV_WRITE... which causes evhttp_connection_incoming_fail to be
++         * called again with EVCON_HTTP_BUFFER_ERROR... ended up having to
++         * hard-reset my machine.
++         */
++	case EVCON_HTTP_BUFFER_ERROR:
+ 		/* 
+ 		 * these are cases in which we probably should just
+ 		 * close the connection and not send a reply.  this
+@@ -491,7 +511,6 @@
+ 		 */
+ 		return (-1);
+ 	case EVCON_HTTP_INVALID_HEADER:
+-	case EVCON_HTTP_BUFFER_ERROR:
+ 	case EVCON_HTTP_REQUEST_CANCEL:
+ 	default:	/* xxx: probably should just error on default */
+ 		/* the callback looks at the uri to determine errors */
+@@ -869,7 +888,7 @@
+ 	/* Create the header from the store arguments */
+ 	evhttp_make_header(evcon, req);
+ 
+-	evhttp_write_buffer(evcon, evhttp_write_connectioncb, NULL);
++	evhttp_write_buffer(evcon, evhttp_write_connectioncb, NULL, 0);
+ }
+ 
+ /* Reset our connection state */
+@@ -1353,9 +1372,9 @@
+ 		}
+ 	}
+ 		
+-	event_debug(("%s: bytes to read: %d (in buffer %ld)\n",
++	event_debug(("%s: bytes to read: %ld (in buffer %ld)\n",
+ 		__func__, req->ntoread,
+-		EVBUFFER_LENGTH(req->evcon->input_buffer)));
++		EVBUFFER_LENGTH(EVBUFFER_INPUT(req->evcon->bufev))));
+ 
+ 	return (0);
+ }
+@@ -1688,6 +1707,10 @@
+ 
+ 	/* delete possible close detection events */
+ 	evhttp_connection_stop_detectclose(evcon);
++
++    /* now that the reply was sent, we don't need to abort on connection lost */
++    if (req->abort_cb)
++        evhttp_connection_set_closecb(evcon, NULL, NULL);
+ 	
+ 	need_close =
+ 	    (req->minor == 0 &&
+@@ -1753,7 +1776,7 @@
+ 	/* Adds headers to the response */
+ 	evhttp_make_header(evcon, req);
+ 
+-	evhttp_write_buffer(evcon, evhttp_send_done, NULL);
++	evhttp_write_buffer(evcon, evhttp_send_done, NULL, 0);
+ }
+ 
+ void
+@@ -1781,7 +1804,7 @@
+ 		req->chunked = 1;
+ 	}
+ 	evhttp_make_header(req->evcon, req);
+-	evhttp_write_buffer(req->evcon, NULL, NULL);
++	evhttp_write_buffer(req->evcon, NULL, NULL, 0);
+ }
+ 
+ void
+@@ -1796,9 +1819,32 @@
+ 	if (req->chunked) {
+ 		evbuffer_add(output, "\r\n", 2);
+ 	}
+-	evhttp_write_buffer(req->evcon, NULL, NULL);
++
++	evhttp_write_buffer(req->evcon, &_evhttp_reply_notify, req, req->write_threshold);
+ }
+ 
++static void
++_evhttp_reply_notify (struct evhttp_connection *evcon, void *arg)
++{
++    struct evhttp_request *req = arg;
++
++    if (req->write_cb)
++        req->write_cb(req, req->write_cb_arg);
++}
++
++int
++evhttp_set_reply_notify(struct evhttp_request *req, size_t threshold,
++    void (*write_cb)(struct evhttp_request *, void *), void *cb_arg)
++{
++    req->write_threshold = threshold;
++    req->write_cb = write_cb;
++    req->write_cb_arg = cb_arg;
++
++	evhttp_write_buffer(req->evcon, &_evhttp_reply_notify, req, threshold);
++
++    return 0;
++}
++
+ void
+ evhttp_send_reply_end(struct evhttp_request *req)
+ {
+@@ -1807,7 +1853,7 @@
+ 
+ 	if (req->chunked) {
+ 		evbuffer_add(output, "0\r\n\r\n", 5);
+-		evhttp_write_buffer(req->evcon, evhttp_send_done, NULL);
++		evhttp_write_buffer(req->evcon, evhttp_send_done, NULL, 0);
+ 		req->chunked = 0;
+ 	} else if (EVBUFFER_LENGTH(output) == 0) {
+ 		/* let the connection know that we are done with the request */
+@@ -1819,6 +1865,28 @@
+ 	}
+ }
+ 
++void _evhttp_reply_aborted(struct evhttp_connection *evcon, void *arg)
++{
++    struct evhttp_request *req = arg;
++    
++    /* call the callback */
++    req->abort_cb(req, req->abort_cb_arg);
++    
++    /* the request is now aborted, we don't want this called twice */
++    evhttp_connection_set_closecb(evcon, NULL, NULL);
++}
++
++void evhttp_set_reply_abortcb(struct evhttp_request *req,
++    void (*cb)(struct evhttp_request *, void *), void *cb_arg)
++{
++    /* store the cb/arg in req */
++    req->abort_cb = cb;
++    req->abort_cb_arg = cb_arg;
++    
++    /* add a closecb to the connection */
++    evhttp_connection_set_closecb(req->evcon, &_evhttp_reply_aborted, req);
++}
++
+ void
+ evhttp_response_code(struct evhttp_request *req, int code, const char *reason)
+ {
+@@ -2448,6 +2516,19 @@
+  * Allows for inspection of the request URI
+  */
+ 
++enum evhttp_cmd_type
++evhttp_request_get_type(struct evhttp_request *req)
++{
++    return req->type;
++}
++
++void
++evhttp_request_get_peer(struct evhttp_request *req,
++    char **address, ev_uint16_t *port)
++{
++    return evhttp_connection_get_peer(req->evcon, address, port);
++}
++
+ const char *
+ evhttp_request_get_uri(struct evhttp_request *req) {
+ 	if (req->uri == NULL)
+Index: http-internal.h
+===================================================================
+--- http-internal.h	(revision 848)
++++ http-internal.h	(working copy)
+@@ -141,7 +141,8 @@
+ void evhttp_make_header(struct evhttp_connection *, struct evhttp_request *);
+ 
+ void evhttp_write_buffer(struct evhttp_connection *,
+-    void (*)(struct evhttp_connection *, void *), void *);
++    void (*)(struct evhttp_connection *, void *), void *,
++    size_t);
+ 
+ /* response sending HTML the data in the buffer */
+ void evhttp_response_code(struct evhttp_request *, int, const char *);
+Index: include/event2/http.h
+===================================================================
+--- include/event2/http.h	(revision 848)
++++ include/event2/http.h	(working copy)
+@@ -243,6 +243,7 @@
+ */
+ void evhttp_send_reply_chunk(struct evhttp_request *req,
+     struct evbuffer *databuf);
++
+ /**
+    Complete a chunked reply.
+ 
+@@ -250,6 +251,43 @@
+ */
+ void evhttp_send_reply_end(struct evhttp_request *req);
+ 
++/**
++   Used to implement flow control for sending HTTP replies.
++
++   After calling evhttp_send_reply_start, and before calling
++   evhttp_send_reply_end, you may call this function to register a callback
++   that will be fired when the level of the HTTP connection's output buffer is
++   below the given threshold (if the output buffer is empty when this function
++   is called, this will happen on the next event-loop iteration).
++
++   This callback behaves in an edge-triggered way, such that it will only fire
++   once if the otuput buffer's level is below the threshold. It may be called
++   again after the next evhttp_send_reply_chunk call.
++
++   Once evhttp_send_reply_end is called (or an error occurs), the callback is
++   invalidated and not used anymore.
++
++   @param req a request object
++   @param threshold the buffer level to watch for
++   @param write_cb the callback to use
++   @param cb_arg the callback argument
++ 
++*/
++int evhttp_set_reply_notify(struct evhttp_request *req, size_t threshold,
++    void (*write_cb)(struct evhttp_request *, void *), void *cb_arg);
++
++/**
++   Register a callback to get called if the request is aborted due to some
++   reason other than evhttp_send_{reply,error,reply_end}, e.g. the HTTP
++   connection was lost.
++
++   @param req a request object
++   @param cb the callback to use
++   @param cb_arg the callback argument
++*/
++void evhttp_set_reply_abortcb(struct evhttp_request *,
++    void (*)(struct evhttp_request *, void *), void *);
++
+ /*
+  * Interfaces for making requests
+  */
+@@ -360,6 +398,11 @@
+ void evhttp_cancel_request(struct evhttp_request *req);
+ 
+ 
++/** Get the request type for this request */
++enum evhttp_cmd_type evhttp_request_get_type(struct evhttp_request *req);
++/** Get the remote address and port this request came from. */
++void evhttp_request_get_peer(struct evhttp_request *req,
++    char **address, ev_uint16_t *port);
+ /** Returns the request URI */
+ const char *evhttp_request_get_uri(struct evhttp_request *req);
+ /** Returns the input headers */
+Index: include/event2/http_struct.h
+===================================================================
+--- include/event2/http_struct.h	(revision 848)
++++ include/event2/http_struct.h	(working copy)
+@@ -113,6 +113,19 @@
+ 	 * the regular callback.
+ 	 */
+ 	void (*chunk_cb)(struct evhttp_request *, void *);
++
++    /*
++     * Request reply flow control callback
++     */
++    size_t write_threshold;
++    void (*write_cb)(struct evhttp_request *, void *);
++    void *write_cb_arg;
++
++    /*
++     * Request abort callback
++     */
++    void (*abort_cb)(struct evhttp_request *, void *);
++    void *abort_cb_arg;
+ };
+ 
+ #ifdef __cplusplus
+Index: buffer.c
+===================================================================
+--- buffer.c	(revision 848)
++++ buffer.c	(working copy)
+@@ -412,6 +412,9 @@
+ 	if (size == 0 || size > buf->total_len)
+ 		return (NULL);
+ 
++// XXX: the following will segfault if buf->total_len == 0 && size < -1
++// XXX: the following will return a buffer of arbitrary length if size < -1
++
+ 	/* No need to pull up anything; the first size bytes are
+ 	 * already here. */
+ 	if (chain->off >= size)