diff --git a/include/types/buffers.h b/include/types/buffers.h index fc070bda1..8c8ee9b7e 100644 --- a/include/types/buffers.h +++ b/include/types/buffers.h @@ -111,6 +111,8 @@ #define BF_READ_DONTWAIT 0x400000 /* wake the task up after every read (eg: HTTP request) */ #define BF_AUTO_CONNECT 0x800000 /* consumer may attempt to establish a new connection */ +#define BF_DONT_READ 0x1000000 /* disable reading for now */ + /* Use these masks to clear the flags before going back to lower layers */ #define BF_CLEAR_READ (~(BF_READ_NULL|BF_READ_PARTIAL|BF_READ_ERROR|BF_READ_ATTACHED)) #define BF_CLEAR_WRITE (~(BF_WRITE_NULL|BF_WRITE_PARTIAL|BF_WRITE_ERROR)) diff --git a/src/proto_http.c b/src/proto_http.c index a68335ca0..6aade9fb4 100644 --- a/src/proto_http.c +++ b/src/proto_http.c @@ -2297,6 +2297,18 @@ int http_process_req_common(struct session *s, struct buffer *req, int an_bit, s } } + /* We can shut read side if "connection: close" && !abort_on_close && !content-length */ + if ((txn->meth == HTTP_METH_GET || txn->meth == HTTP_METH_HEAD) && + (s->flags & SN_CONN_CLOSED) && !(s->be->options & PR_O_ABRT_CLOSE)) { + struct hdr_ctx ctx; + ctx.idx = 0; + if (!http_find_header2("Transfer-Encoding", 17, msg->sol, &txn->hdr_idx, &ctx)) { + ctx.idx = 0; + if (!http_find_header2("Content-length", 14, msg->sol, &txn->hdr_idx, &ctx)) + req->flags |= BF_DONT_READ; + } + } + /* that's OK for us now, let's move on to next analysers */ return 1; diff --git a/src/stream_interface.c b/src/stream_interface.c index 96b26def5..f4b723b6d 100644 --- a/src/stream_interface.c +++ b/src/stream_interface.c @@ -123,7 +123,7 @@ void stream_int_update_embedded(struct stream_interface *si) /* we're almost sure that we need some space if the buffer is not * empty, even if it's not full, because the applets can't fill it. */ - if ((si->ib->flags & (BF_SHUTR|BF_OUT_EMPTY)) == 0) + if ((si->ib->flags & (BF_SHUTR|BF_OUT_EMPTY|BF_DONT_READ)) == 0) si->flags |= SI_FL_WAIT_ROOM; if (si->ob->flags & BF_WRITE_ACTIVITY) { @@ -137,7 +137,7 @@ void stream_int_update_embedded(struct stream_interface *si) si->ib->rex = tick_add_ifset(now_ms, si->ib->rto); } - if (likely((si->ob->flags & (BF_SHUTW|BF_WRITE_PARTIAL|BF_FULL)) == BF_WRITE_PARTIAL && + if (likely((si->ob->flags & (BF_SHUTW|BF_WRITE_PARTIAL|BF_FULL|BF_DONT_READ)) == BF_WRITE_PARTIAL && (si->ob->prod->flags & SI_FL_WAIT_ROOM))) si->ob->prod->chk_rcv(si->ob->prod); @@ -210,7 +210,7 @@ void stream_int_shutw(struct stream_interface *si) switch (si->state) { case SI_ST_EST: - if (!(si->ib->flags & BF_SHUTR)) + if (!(si->ib->flags & (BF_SHUTR|BF_DONT_READ))) break; /* fall through */ @@ -242,9 +242,9 @@ void stream_int_chk_rcv(struct stream_interface *si) if (unlikely(si->state != SI_ST_EST || (ib->flags & BF_SHUTR))) return; - if (ib->flags & (BF_FULL|BF_HIJACK)) { + if (ib->flags & (BF_FULL|BF_HIJACK|BF_DONT_READ)) { /* stop reading */ - if ((ib->flags & (BF_FULL|BF_HIJACK)) == BF_FULL) + if ((ib->flags & (BF_FULL|BF_HIJACK|BF_DONT_READ)) == BF_FULL) si->flags |= SI_FL_WAIT_ROOM; } else { diff --git a/src/stream_sock.c b/src/stream_sock.c index 65b790a0b..479222aee 100644 --- a/src/stream_sock.c +++ b/src/stream_sock.c @@ -486,7 +486,7 @@ int stream_sock_read(int fd) { EV_FD_CLR(fd, DIR_RD); b->rex = TICK_ETERNITY; } - else if ((b->flags & (BF_SHUTR|BF_READ_PARTIAL|BF_FULL|BF_READ_NOEXP)) == BF_READ_PARTIAL) + else if ((b->flags & (BF_SHUTR|BF_READ_PARTIAL|BF_FULL|BF_DONT_READ|BF_READ_NOEXP)) == BF_READ_PARTIAL) b->rex = tick_add_ifset(now_ms, b->rto); /* we have to wake up if there is a special event or if we don't have @@ -777,7 +777,7 @@ int stream_sock_write(int fd) } /* the producer might be waiting for more room to store data */ - if (likely((b->flags & (BF_SHUTW|BF_WRITE_PARTIAL|BF_FULL)) == BF_WRITE_PARTIAL && + if (likely((b->flags & (BF_SHUTW|BF_WRITE_PARTIAL|BF_FULL|BF_DONT_READ)) == BF_WRITE_PARTIAL && (b->prod->flags & SI_FL_WAIT_ROOM))) b->prod->chk_rcv(b->prod); @@ -834,7 +834,7 @@ void stream_sock_shutw(struct stream_interface *si) EV_FD_CLR(si->fd, DIR_WR); shutdown(si->fd, SHUT_WR); - if (!(si->ib->flags & BF_SHUTR)) + if (!(si->ib->flags & (BF_SHUTR|BF_DONT_READ))) return; /* fall through */ @@ -906,9 +906,9 @@ void stream_sock_data_finish(struct stream_interface *si) /* Check if we need to close the read side */ if (!(ib->flags & BF_SHUTR)) { /* Read not closed, update FD status and timeout for reads */ - if (ib->flags & (BF_FULL|BF_HIJACK)) { + if (ib->flags & (BF_FULL|BF_HIJACK|BF_DONT_READ)) { /* stop reading */ - if ((ib->flags & (BF_FULL|BF_HIJACK)) == BF_FULL) + if ((ib->flags & (BF_FULL|BF_HIJACK|BF_DONT_READ)) == BF_FULL) si->flags |= SI_FL_WAIT_ROOM; EV_FD_COND_C(fd, DIR_RD); ib->rex = TICK_ETERNITY; @@ -921,7 +921,7 @@ void stream_sock_data_finish(struct stream_interface *si) */ si->flags &= ~SI_FL_WAIT_ROOM; EV_FD_COND_S(fd, DIR_RD); - if (!(ib->flags & BF_READ_NOEXP) && !tick_isset(ib->rex)) + if (!(ib->flags & (BF_READ_NOEXP|BF_DONT_READ)) && !tick_isset(ib->rex)) ib->rex = tick_add_ifset(now_ms, ib->rto); } } @@ -980,9 +980,9 @@ void stream_sock_chk_rcv(struct stream_interface *si) if (unlikely(si->state != SI_ST_EST || (ib->flags & BF_SHUTR))) return; - if (ib->flags & (BF_FULL|BF_HIJACK)) { + if (ib->flags & (BF_FULL|BF_HIJACK|BF_DONT_READ)) { /* stop reading */ - if ((ib->flags & (BF_FULL|BF_HIJACK)) == BF_FULL) + if ((ib->flags & (BF_FULL|BF_HIJACK|BF_DONT_READ)) == BF_FULL) si->flags |= SI_FL_WAIT_ROOM; EV_FD_COND_C(si->fd, DIR_RD); }