Hi, the following diff adds support for HTTP pipelining.
With pipelining, the client sends multiple requests before receiving the responses in the same order. It was long dead and disabled in most browsers before Apple decided to turn it on in iOS Safari. btw. There is no need to enable EV_READ in server_write() - and it can cause a problem with pipelining - so I removed this line below. OK? Testers? Reyk Index: usr.sbin/httpd/httpd.h =================================================================== RCS file: /cvs/src/usr.sbin/httpd/httpd.h,v retrieving revision 1.127 diff -u -p -u -p -r1.127 httpd.h --- usr.sbin/httpd/httpd.h 31 Jan 2017 14:39:47 -0000 1.127 +++ usr.sbin/httpd/httpd.h 31 Jan 2017 19:59:11 -0000 @@ -342,6 +342,7 @@ struct client { size_t clt_headerlen; int clt_headersdone; unsigned int clt_persist; + unsigned int clt_pipelining; int clt_line; int clt_done; int clt_chunk; Index: usr.sbin/httpd/server.c =================================================================== RCS file: /cvs/src/usr.sbin/httpd/server.c,v retrieving revision 1.104 diff -u -p -u -p -r1.104 server.c --- usr.sbin/httpd/server.c 31 Jan 2017 17:25:05 -0000 1.104 +++ usr.sbin/httpd/server.c 31 Jan 2017 19:59:11 -0000 @@ -846,8 +846,6 @@ server_write(struct bufferevent *bev, vo if (clt->clt_done) goto done; - bufferevent_enable(bev, EV_READ); - if (clt->clt_srvbev && clt->clt_srvbev_throttled) { bufferevent_enable(clt->clt_srvbev, EV_READ); clt->clt_srvbev_throttled = 0; Index: usr.sbin/httpd/server_file.c =================================================================== RCS file: /cvs/src/usr.sbin/httpd/server_file.c,v retrieving revision 1.64 diff -u -p -u -p -r1.64 server_file.c --- usr.sbin/httpd/server_file.c 31 Jan 2017 14:39:47 -0000 1.64 +++ usr.sbin/httpd/server_file.c 31 Jan 2017 19:59:11 -0000 @@ -589,7 +589,7 @@ void server_file_error(struct bufferevent *bev, short error, void *arg) { struct client *clt = arg; - struct evbuffer *dst; + struct evbuffer *src, *dst; if (error & EVBUFFER_TIMEOUT) { server_close(clt, "buffer event timeout"); @@ -608,6 +608,12 @@ server_file_error(struct bufferevent *be clt->clt_done = 1; + src = EVBUFFER_INPUT(clt->clt_bev); + + /* Close the connection if a previous pipeline is empty */ + if (clt->clt_pipelining && EVBUFFER_LENGTH(src) == 0) + clt->clt_persist = 0; + if (clt->clt_persist) { /* Close input file and wait for next HTTP request */ if (clt->clt_fd != -1) @@ -616,6 +622,12 @@ server_file_error(struct bufferevent *be clt->clt_toread = TOREAD_HTTP_HEADER; server_reset_http(clt); bufferevent_enable(clt->clt_bev, EV_READ|EV_WRITE); + + /* Start pipelining if the buffer is not empty */ + if (EVBUFFER_LENGTH(src)) { + clt->clt_pipelining++; + server_read_http(clt->clt_bev, arg); + } return; } Index: usr.sbin/httpd/server_http.c =================================================================== RCS file: /cvs/src/usr.sbin/httpd/server_http.c,v retrieving revision 1.112 diff -u -p -u -p -r1.112 server_http.c --- usr.sbin/httpd/server_http.c 31 Jan 2017 14:39:47 -0000 1.112 +++ usr.sbin/httpd/server_http.c 31 Jan 2017 19:59:11 -0000 @@ -1186,6 +1186,10 @@ server_response(struct httpd *httpd, str if (clt->clt_persist >= srv_conf->maxrequests) clt->clt_persist = 0; + /* pipelining should end after the first "idempotent" method */ + if (clt->clt_pipelining && clt->clt_toread > 0) + clt->clt_persist = 0; + /* * Do we have a Host header and matching configuration? * XXX the Host can also appear in the URL path.