--- /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)