updated on Thu Jan 26 16:09:46 UTC 2012
[aur-mirror.git] / libevent-hphp / libevent-1.4.14.fb-changes.diff
blobb8a782071dcb42657b65e1b7ff3496dcdebcc34b
1 diff -rp -U 5 libevent-1.4.14-stable/event.c libevent-1.4.14-stable-fb/event.c
2 --- libevent-1.4.14-stable/event.c 2010-06-07 14:40:35.000000000 -0700
3 +++ libevent-1.4.14-stable-fb/event.c 2010-06-18 16:30:57.000000000 -0700
4 @@ -136,14 +136,16 @@ detect_monotonic(void)
7 static int
8 gettime(struct event_base *base, struct timeval *tp)
10 +/*
11 if (base->tv_cache.tv_sec) {
12 *tp = base->tv_cache;
13 return (0);
15 +*/
17 #if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
18 if (use_monotonic) {
19 struct timespec ts;
21 @@ -479,11 +481,11 @@ event_base_loop(struct event_base *base,
22 struct timeval tv;
23 struct timeval *tv_p;
24 int res, done;
26 /* clear time cache */
27 - base->tv_cache.tv_sec = 0;
28 + /* base->tv_cache.tv_sec = 0; */
30 if (base->sig.ev_signal_added)
31 evsignal_base = base;
32 done = 0;
33 while (!done) {
34 @@ -531,17 +533,17 @@ event_base_loop(struct event_base *base,
36 /* update last old time */
37 gettime(base, &base->event_tv);
39 /* clear time cache */
40 - base->tv_cache.tv_sec = 0;
41 + /* base->tv_cache.tv_sec = 0; */
43 res = evsel->dispatch(base, evbase, tv_p);
45 if (res == -1)
46 return (-1);
47 - gettime(base, &base->tv_cache);
48 + /* gettime(base, &base->tv_cache); */
50 timeout_process(base);
52 if (base->event_count_active) {
53 event_process_active(base);
54 @@ -550,11 +552,11 @@ event_base_loop(struct event_base *base,
55 } else if (flags & EVLOOP_NONBLOCK)
56 done = 1;
59 /* clear time cache */
60 - base->tv_cache.tv_sec = 0;
61 + /* base->tv_cache.tv_sec = 0; */
63 event_debug(("%s: asked to terminate loop.", __func__));
64 return (0);
67 Only in libevent-1.4.14-stable-fb: event.c.orig
68 diff -rp -U 5 libevent-1.4.14-stable/evhttp.h libevent-1.4.14-stable-fb/evhttp.h
69 --- libevent-1.4.14-stable/evhttp.h 2010-06-07 14:40:35.000000000 -0700
70 +++ libevent-1.4.14-stable-fb/evhttp.h 2010-06-18 16:36:24.000000000 -0700
71 @@ -79,16 +79,54 @@ struct evhttp *evhttp_new(struct event_b
72 * to multiple different ports.
74 * @param http a pointer to an evhttp object
75 * @param address a string containing the IP address to listen(2) on
76 * @param port the port number to listen on
77 - * @return a newly allocated evhttp struct
78 + * @return 0 on success, -1 on error
79 * @see evhttp_free()
81 int evhttp_bind_socket(struct evhttp *http, const char *address, u_short port);
83 /**
84 + * Binds an HTTP server on the specified address and port, using backlog.
85 + *
86 + * Can be called multiple times to bind the same http server
87 + * to multiple different ports.
88 + *
89 + * @param http a pointer to an evhttp object
90 + * @param address a string containing the IP address to listen(2) on
91 + * @param port the port number to listen on
92 + * @param backlog the backlog value for listen(2)
93 + * @return 0 on success, -1 on error
94 + * @see evhttp_free()
95 + */
96 +int evhttp_bind_socket_backlog(struct evhttp *http, const char *address, u_short port, int backlog);
98 +/**
99 + * Like evhttp_bind_socket(), but returns the socket file descriptor.
101 + * @param http a pointer to an evhttp object
102 + * @param address a string containing the IP address to listen(2) on
103 + * @param port the port number to listen on
104 + * @return Socket file descriptor on success, -1 on failure
105 + * @see evhttp_bind_socket()
106 + */
107 +int evhttp_bind_socket_with_fd(struct evhttp *http, const char *address, u_short port);
109 +/**
110 + * Like evhttp_bind_socket(), but returns the socket file descriptor.
112 + * @param http a pointer to an evhttp object
113 + * @param address a string containing the IP address to listen(2) on
114 + * @param port the port number to listen on
115 + * @param backlog the backlog value for listen(2)
116 + * @return Socket file descriptor on success, -1 on failure
117 + * @see evhttp_bind_socket()
118 + */
119 +int evhttp_bind_socket_backlog_fd(struct evhttp *http, const char *address, u_short port, int backlog);
121 +/**
122 * Makes an HTTP server accept connections on the specified socket
124 * This may be useful to create a socket and then fork multiple instances
125 * of an http server, or when a socket has been communicated via file
126 * descriptor passing in situations where an http servers does not have
127 @@ -103,10 +141,25 @@ int evhttp_bind_socket(struct evhttp *ht
128 * @see evhttp_free(), evhttp_bind_socket()
130 int evhttp_accept_socket(struct evhttp *http, int fd);
133 + * Makes an HTTP server stop accepting connections on the specified socket
135 + * This may be useful when a socket has been sent via file descriptor passing
136 + * and is no longer needed by the current process.
138 + * This function does not close the socket.
140 + * @param http a pointer to an evhttp object
141 + * @param fd a socket fd that is currently accepting connections
142 + * @return 0 on success, -1 on failure.
143 + * @see evhttp_accept_socket()
144 + */
145 +int evhttp_del_accept_socket(struct evhttp *http, int fd);
147 +/**
148 * Free the previously created HTTP server.
150 * Works only if no requests are currently being served.
152 * @param http the evhttp server object to be freed
153 @@ -132,10 +185,25 @@ void evhttp_set_gencb(struct evhttp *,
154 * @param http an evhttp object
155 * @param timeout_in_secs the timeout, in seconds
157 void evhttp_set_timeout(struct evhttp *, int timeout_in_secs);
159 +/**
160 + * Limit the number of simultaneous connections via this http instance.
162 + * @param http an evhttp object
163 + * @param nlimit the maximum number of connections, zero is unlimited
164 + */
165 +int evhttp_set_connection_limit(struct evhttp *http, int nlimit);
167 +/**
168 + * Return the maximum number of connections allowed for this instance.
170 + * @param http an evhttp object
171 + */
172 +int evhttp_get_connection_limit(struct evhttp *http);
174 /* Request/Response functionality */
177 * Send an HTML error message to the client.
179 @@ -155,10 +223,23 @@ void evhttp_send_error(struct evhttp_req
180 * @param databuf the body of the response
182 void evhttp_send_reply(struct evhttp_request *req, int code,
183 const char *reason, struct evbuffer *databuf);
185 +/**
186 + * Send an HTML reply synchronously as much as possible by calling _begin().
187 + * Great for a worker thread to send the reply immediately without queuing up
188 + * events back to the loop. Call _end() to send the rest of the packet from
189 + * event loop.
191 + * When _begin() returns needs to be fed into _end() as the 1st parameter
192 + * "nwritten".
193 + */
194 +int evhttp_send_reply_sync_begin(struct evhttp_request *req, int code,
195 + const char *reason, struct evbuffer *databuf);
196 +void evhttp_send_reply_sync_end(int nwritten, struct evhttp_request *req);
198 /* Low-level response interface, for streaming/chunked replies */
199 void evhttp_send_reply_start(struct evhttp_request *, int, const char *);
200 void evhttp_send_reply_chunk(struct evhttp_request *, struct evbuffer *);
201 void evhttp_send_reply_end(struct evhttp_request *);
203 @@ -208,10 +289,11 @@ struct {
204 char *remote_host;
205 u_short remote_port;
207 enum evhttp_request_kind kind;
208 enum evhttp_cmd_type type;
209 + char *ext_method; /* webdav methods, for example */
211 char *uri; /* uri after HTTP request was parsed */
213 char major; /* HTTP Major number */
214 char minor; /* HTTP Minor number */
215 @@ -222,10 +304,12 @@ struct {
216 struct evbuffer *input_buffer; /* read data */
217 ev_int64_t ntoread;
218 int chunked:1, /* a chunked request */
219 userdone:1; /* the user has sent all data */
221 + int referenced;
223 struct evbuffer *output_buffer; /* outgoing post or data */
225 /* Callback */
226 void (*cb)(struct evhttp_request *, void *);
227 void *cb_arg;
228 diff -rp -U 5 libevent-1.4.14-stable/http-internal.h libevent-1.4.14-stable-fb/http-internal.h
229 --- libevent-1.4.14-stable/http-internal.h 2010-06-07 14:40:35.000000000 -0700
230 +++ libevent-1.4.14-stable-fb/http-internal.h 2010-06-18 16:30:57.000000000 -0700
231 @@ -114,10 +114,13 @@ struct evhttp {
232 TAILQ_HEAD(boundq, evhttp_bound_socket) sockets;
234 TAILQ_HEAD(httpcbq, evhttp_cb) callbacks;
235 struct evconq connections;
237 + int connection_count;
238 + int connection_limit;
240 int timeout;
242 void (*gencb)(struct evhttp_request *req, void *);
243 void *gencbarg;
245 diff -rp -U 5 libevent-1.4.14-stable/http.c libevent-1.4.14-stable-fb/http.c
246 --- libevent-1.4.14-stable/http.c 2010-06-07 14:40:35.000000000 -0700
247 +++ libevent-1.4.14-stable-fb/http.c 2010-06-18 16:35:23.000000000 -0700
248 @@ -217,10 +217,17 @@ static int evhttp_decode_uri_internal(co
249 char *ret, int always_decode_plus);
251 void evhttp_read(int, short, void *);
252 void evhttp_write(int, short, void *);
255 +void evhttp_server_drop_connection(struct evhttp_connection *evcon);
256 +void evhttp_server_add_connection(struct evhttp *http,
257 + struct evhttp_connection *evcon);
258 +void evhttp_pause(struct evhttp *http);
259 +void evhttp_resume(struct evhttp *http);
261 #ifndef HAVE_STRSEP
262 /* strsep replacement for platforms that lack it. Only works if
263 * del is one character long. */
264 static char *
265 strsep(char **s, const char *del)
266 @@ -476,21 +483,19 @@ evhttp_make_header_response(struct evhtt
268 if (req->minor == 0 && is_keepalive)
269 evhttp_add_header(req->output_headers,
270 "Connection", "keep-alive");
272 - if (req->minor == 1 || is_keepalive) {
274 * we need to add the content length if the
275 * user did not give it, this is required for
276 * persistent connections to work.
278 evhttp_maybe_add_content_length_header(
279 req->output_headers,
280 (long)EVBUFFER_LENGTH(req->output_buffer));
284 /* Potentially add headers for unidentified content. */
285 if (EVBUFFER_LENGTH(req->output_buffer)) {
286 if (evhttp_find_header(req->output_headers,
287 "Content-Type") == NULL) {
288 @@ -685,18 +690,18 @@ evhttp_connection_fail(struct evhttp_con
290 void
291 evhttp_write(int fd, short what, void *arg)
293 struct evhttp_connection *evcon = arg;
294 - int n;
296 if (what == EV_TIMEOUT) {
297 evhttp_connection_fail(evcon, EVCON_HTTP_TIMEOUT);
298 return;
301 - n = evbuffer_write(evcon->output_buffer, fd);
302 + if (EVBUFFER_LENGTH(evcon->output_buffer) != 0) {
303 + int n = evbuffer_write(evcon->output_buffer, fd);
304 if (n == -1) {
305 event_debug(("%s: evbuffer_write", __func__));
306 evhttp_connection_fail(evcon, EVCON_HTTP_EOF);
307 return;
309 @@ -704,10 +709,11 @@ evhttp_write(int fd, short what, void *a
310 if (n == 0) {
311 event_debug(("%s: write nothing", __func__));
312 evhttp_connection_fail(evcon, EVCON_HTTP_EOF);
313 return;
317 if (EVBUFFER_LENGTH(evcon->output_buffer) != 0) {
318 evhttp_add_event(&evcon->ev,
319 evcon->timeout, HTTP_WRITE_TIMEOUT);
320 return;
321 @@ -1010,15 +1016,13 @@ evhttp_connection_free(struct evhttp_con
323 while ((req = TAILQ_FIRST(&evcon->requests)) != NULL) {
324 TAILQ_REMOVE(&evcon->requests, req, next);
325 evhttp_request_free(req);
328 - if (evcon->http_server != NULL) {
329 - struct evhttp *http = evcon->http_server;
330 - TAILQ_REMOVE(&http->connections, evcon, next);
333 + if (evcon->http_server != NULL)
334 + evhttp_server_drop_connection(evcon);
336 if (event_initialized(&evcon->close_ev))
337 event_del(&evcon->close_ev);
339 if (event_initialized(&evcon->ev))
340 @@ -1099,14 +1103,20 @@ evhttp_connection_reset(struct evhttp_co
341 EVUTIL_CLOSESOCKET(evcon->fd);
342 evcon->fd = -1;
344 evcon->state = EVCON_DISCONNECTED;
346 - evbuffer_drain(evcon->input_buffer,
347 - EVBUFFER_LENGTH(evcon->input_buffer));
348 - evbuffer_drain(evcon->output_buffer,
349 - EVBUFFER_LENGTH(evcon->output_buffer));
350 + /*
351 + * These can grow quite large if processing a large photo or video
352 + * upload/download. Instead of keeping the buffers around, just
353 + * free and allocate new.
354 + */
355 + evbuffer_free(evcon->input_buffer);
356 + evcon->input_buffer = evbuffer_new();
358 + evbuffer_free(evcon->output_buffer);
359 + evcon->output_buffer = evbuffer_new();
362 static void
363 evhttp_detect_close_cb(int fd, short what, void *arg)
365 @@ -1276,23 +1286,56 @@ evhttp_parse_request_line(struct evhttp_
366 /* Parse the request line */
367 method = strsep(&line, " ");
368 if (line == NULL)
369 return (-1);
370 uri = strsep(&line, " ");
371 - if (line == NULL)
372 - return (-1);
373 + if (line == NULL) {
374 + version = "HTTP/1.0";
375 + } else {
376 version = strsep(&line, " ");
377 if (line != NULL)
378 return (-1);
381 /* First line */
382 + req->ext_method = NULL;
383 if (strcmp(method, "GET") == 0) {
384 req->type = EVHTTP_REQ_GET;
385 } else if (strcmp(method, "POST") == 0) {
386 req->type = EVHTTP_REQ_POST;
387 } else if (strcmp(method, "HEAD") == 0) {
388 req->type = EVHTTP_REQ_HEAD;
389 + } else if (strcmp(method, "OPTIONS") == 0) {
390 + req->type = EVHTTP_REQ_POST;
391 + req->ext_method = "OPTIONS";
392 + } else if (strcmp(method, "REPORT") == 0) {
393 + req->type = EVHTTP_REQ_POST;
394 + req->ext_method = "REPORT";
395 + } else if (strcmp(method, "PROPFIND") == 0) {
396 + req->type = EVHTTP_REQ_POST;
397 + req->ext_method = "PROPFIND";
398 + } else if (strcmp(method, "PROPPATH") == 0) {
399 + req->type = EVHTTP_REQ_POST;
400 + req->ext_method = "PROPPATH";
401 + } else if (strcmp(method, "MKCOL") == 0) {
402 + req->type = EVHTTP_REQ_POST;
403 + req->ext_method = "MKCOL";
404 + } else if (strcmp(method, "MKCALENDAR") == 0) {
405 + req->type = EVHTTP_REQ_POST;
406 + req->ext_method = "MKCALENDAR";
407 + } else if (strcmp(method, "PUT") == 0) {
408 + req->type = EVHTTP_REQ_POST;
409 + req->ext_method = "PUT";
410 + } else if (strcmp(method, "DELETE") == 0) {
411 + req->type = EVHTTP_REQ_POST;
412 + req->ext_method = "DELETE";
413 + } else if (strcmp(method, "LOCK") == 0) {
414 + req->type = EVHTTP_REQ_POST;
415 + req->ext_method = "LOCK";
416 + } else if (strcmp(method, "UNLOCK") == 0) {
417 + req->type = EVHTTP_REQ_POST;
418 + req->ext_method = "UNLOCK";
419 } else {
420 event_debug(("%s: bad method %s on request %p from %s",
421 __func__, method, req, req->remote_host));
422 return (-1);
424 @@ -1961,14 +2004,48 @@ evhttp_send_reply(struct evhttp_request
425 evhttp_response_code(req, code, reason);
427 evhttp_send(req, databuf);
430 +int
431 +evhttp_send_reply_sync_begin(struct evhttp_request *req, int code,
432 + const char *reason, struct evbuffer *databuf) {
433 + evhttp_response_code(req, code, reason);
434 + struct evhttp_connection *evcon = req->evcon;
436 + assert(TAILQ_FIRST(&evcon->requests) == req);
438 + /* xxx: not sure if we really should expose the data buffer this way */
439 + if (databuf != NULL)
440 + evbuffer_add_buffer(req->output_buffer, databuf);
442 + /* Adds headers to the response */
443 + evhttp_make_header(evcon, req);
445 + return evbuffer_write(evcon->output_buffer, evcon->fd);
448 +void
449 +evhttp_send_reply_sync_end(int nwritten, struct evhttp_request *req) {
450 + struct evhttp_connection *evcon = req->evcon;
452 + if (nwritten <= 0) {
453 + evhttp_connection_fail(evcon, EVCON_HTTP_EOF);
454 + } else if (EVBUFFER_LENGTH(evcon->output_buffer) == 0) {
455 + evhttp_send_done(evcon, NULL);
456 + } else {
457 + evhttp_write_buffer(evcon, evhttp_send_done, NULL);
462 void
463 evhttp_send_reply_start(struct evhttp_request *req, int code,
464 const char *reason)
466 + req->referenced = 1;
468 evhttp_response_code(req, code, reason);
469 if (req->major == 1 && req->minor == 1) {
470 /* use chunked encoding for HTTP/1.1 */
471 evhttp_add_header(req->output_headers, "Transfer-Encoding",
472 "chunked");
473 @@ -1984,10 +2061,12 @@ evhttp_send_reply_chunk(struct evhttp_re
474 struct evhttp_connection *evcon = req->evcon;
476 if (evcon == NULL)
477 return;
479 + if (req->referenced < 0) return;
481 if (req->chunked) {
482 evbuffer_add_printf(evcon->output_buffer, "%x\r\n",
483 (unsigned)EVBUFFER_LENGTH(databuf));
485 evbuffer_add_buffer(evcon->output_buffer, databuf);
486 @@ -2005,11 +2084,18 @@ evhttp_send_reply_end(struct evhttp_requ
487 if (evcon == NULL) {
488 evhttp_request_free(req);
489 return;
492 - /* we expect no more calls form the user on this request */
493 + if (req->referenced < 0) {
494 + req->referenced = 0;
495 + evhttp_request_free(req);
496 + return;
498 + req->referenced = 0;
500 + /* we expect no more calls form the user on this request */
501 req->userdone = 1;
503 if (req->chunked) {
504 evbuffer_add(req->evcon->output_buffer, "0\r\n\r\n", 5);
505 evhttp_write_buffer(req->evcon, evhttp_send_done, NULL);
506 @@ -2291,33 +2377,63 @@ accept_socket(int fd, short what, void *
508 evhttp_get_request(http, nfd, (struct sockaddr *)&ss, addrlen);
512 -evhttp_bind_socket(struct evhttp *http, const char *address, u_short port)
513 +evhttp_bind_socket_backlog_fd(struct evhttp *http, const char *address,
514 + u_short port, int backlog)
516 int fd;
517 int res;
519 if ((fd = bind_socket(address, port, 1 /*reuse*/)) == -1)
520 return (-1);
522 - if (listen(fd, 128) == -1) {
523 + if (listen(fd, backlog) == -1) {
524 event_warn("%s: listen", __func__);
525 EVUTIL_CLOSESOCKET(fd);
526 return (-1);
529 res = evhttp_accept_socket(http, fd);
531 - if (res != -1)
532 + if (res != -1) {
533 event_debug(("Bound to port %d - Awaiting connections ... ",
534 port));
535 + return (fd);
538 return (res);
541 +static int
542 +mask_fd(int fd)
544 + return fd > 0 ? 0 : fd;
547 +int
548 +evhttp_bind_socket(struct evhttp *http, const char *address, u_short port)
550 + return mask_fd(evhttp_bind_socket_backlog_fd(http, address, port, 128));
553 +int
554 +evhttp_bind_socket_with_fd(struct evhttp *http, const char *address,
555 + u_short port)
557 + return evhttp_bind_socket_backlog_fd(http, address, port, 128);
560 +int
561 +evhttp_bind_socket_backlog(struct evhttp *http, const char *address,
562 + u_short port, int backlog)
564 + return mask_fd(
565 + evhttp_bind_socket_backlog_fd(http, address, port, backlog));
569 evhttp_accept_socket(struct evhttp *http, int fd)
571 struct evhttp_bound_socket *bound;
572 struct event *ev;
573 @@ -2343,10 +2459,29 @@ evhttp_accept_socket(struct evhttp *http
574 TAILQ_INSERT_TAIL(&http->sockets, bound, next);
576 return (0);
579 +int
580 +evhttp_del_accept_socket(struct evhttp *http, int fd)
582 + struct evhttp_bound_socket *bound;
583 + TAILQ_FOREACH(bound, &http->sockets, next) {
584 + if (bound->bind_ev.ev_fd == fd)
585 + break;
588 + if (bound == NULL)
589 + return (-1);
591 + TAILQ_REMOVE(&http->sockets, bound, next);
592 + event_del(&bound->bind_ev);
593 + free(bound);
595 + return (0);
598 static struct evhttp*
599 evhttp_new_object(void)
601 struct evhttp *http = NULL;
603 @@ -2525,10 +2660,15 @@ evhttp_request_new(void (*cb)(struct evh
606 void
607 evhttp_request_free(struct evhttp_request *req)
609 + if (req->referenced) {
610 + req->referenced = -1;
611 + return;
614 if (req->remote_host != NULL)
615 free(req->remote_host);
616 if (req->uri != NULL)
617 free(req->uri);
618 if (req->response_code_line != NULL)
619 @@ -2655,17 +2795,76 @@ evhttp_get_request(struct evhttp *http,
622 * if we want to accept more than one request on a connection,
623 * we need to know which http server it belongs to.
625 - evcon->http_server = http;
626 - TAILQ_INSERT_TAIL(&http->connections, evcon, next);
628 + evhttp_server_add_connection(http, evcon);
630 if (evhttp_associate_new_request_with_connection(evcon) == -1)
631 evhttp_connection_free(evcon);
634 +void
635 +evhttp_pause(struct evhttp *http)
637 + struct evhttp_bound_socket *bound;
638 + TAILQ_FOREACH(bound, &http->sockets, next) {
639 + event_del(&bound->bind_ev);
643 +void
644 +evhttp_resume(struct evhttp *http)
646 + struct evhttp_bound_socket *bound;
647 + TAILQ_FOREACH(bound, &http->sockets, next) {
648 + event_add(&bound->bind_ev, 0);
652 +int
653 +evhttp_get_connection_limit(struct evhttp *http)
655 + return http->connection_limit;
658 +int
659 +evhttp_set_connection_limit(struct evhttp *http, int nlimit)
661 + int olimit = http->connection_limit;
662 + http->connection_limit = nlimit;
663 + return olimit;
666 +void
667 +evhttp_server_add_connection(struct evhttp *http,
668 + struct evhttp_connection *evcon)
670 + evcon->http_server = http;
671 + TAILQ_INSERT_TAIL(&http->connections, evcon, next);
673 + http->connection_count++;
674 + if (http->connection_limit > 0
675 + && http->connection_count >= http->connection_limit)
677 + evhttp_pause(http);
681 +void
682 +evhttp_server_drop_connection(struct evhttp_connection *evcon)
684 + struct evhttp *http = evcon->http_server;
685 + TAILQ_REMOVE(&http->connections, evcon, next);
686 + http->connection_count--;
687 + if (http->connection_limit > 0
688 + && http->connection_count < http->connection_limit)
690 + evhttp_resume(http);
695 * Network helper functions that we do not want to export to the rest of
696 * the world.