return !(c->buf->o | (long)c->pipe);
}
-/* Returns non-zero if the buffer input is considered full. The reserved space
- * is taken into account if ->to_forward indicates that an end of transfer is
- * close to happen. The test is optimized to avoid as many operations as
- * possible for the fast case and to be used as an "if" condition.
+/* Returns non-zero if the buffer input has all of its reserve available. This
+ * is used to decide when a request or response may be parsed when some data
+ * from a previous exchange might still be present.
+ */
+static inline int channel_reserved(const struct channel *chn)
+{
+ int rem = chn->buf->size;
+
+ rem -= chn->buf->o;
+ rem -= chn->buf->i;
+ rem -= global.tune.maxrewrite;
+ return rem >= 0;
+}
+
+/* Returns non-zero if the buffer input is considered full. This is used to
+ * decide when to stop reading into a buffer when we want to ensure that we
+ * leave the reserve untouched after all pending outgoing data are forwarded.
+ * The reserved space is taken into account if ->to_forward indicates that an
+ * end of transfer is close to happen. Note that both ->buf->o and ->to_forward
+ * are considered as available since they're supposed to leave the buffer. The
+ * test is optimized to avoid as many operations as possible for the fast case
+ * and to be used as an "if" condition.
*/
static inline int channel_full(const struct channel *chn)
{
* data later, which is much more complicated.
*/
if (buffer_not_empty(req->buf) && msg->msg_state < HTTP_MSG_ERROR) {
- if ((txn->flags & TX_NOT_FIRST) &&
- unlikely(channel_full(req) ||
- bi_end(req->buf) < b_ptr(req->buf, msg->next) ||
- bi_end(req->buf) > req->buf->data + req->buf->size - global.tune.maxrewrite)) {
- if (req->buf->o) {
+ if (txn->flags & TX_NOT_FIRST) {
+ if (unlikely(!channel_reserved(req))) {
if (req->flags & (CF_SHUTW|CF_SHUTW_NOW|CF_WRITE_ERROR|CF_WRITE_TIMEOUT))
goto failed_keep_alive;
/* some data has still not left the buffer, wake us once that's done */
req->flags |= CF_READ_DONTWAIT; /* try to get back here ASAP */
return 0;
}
- if (bi_end(req->buf) < b_ptr(req->buf, msg->next) ||
- bi_end(req->buf) > req->buf->data + req->buf->size - global.tune.maxrewrite)
- buffer_slow_realign(msg->chn->buf);
+ if (unlikely(bi_end(req->buf) < b_ptr(req->buf, msg->next) ||
+ bi_end(req->buf) > req->buf->data + req->buf->size - global.tune.maxrewrite))
+ buffer_slow_realign(req->buf);
}
/* Note that we have the same problem with the response ; we
* keep-alive requests.
*/
if ((txn->flags & TX_NOT_FIRST) &&
- unlikely(channel_full(s->rep) ||
+ unlikely(!channel_reserved(s->rep) ||
bi_end(s->rep->buf) < b_ptr(s->rep->buf, txn->rsp.next) ||
bi_end(s->rep->buf) > s->rep->buf->data + s->rep->buf->size - global.tune.maxrewrite)) {
if (s->rep->buf->o) {
* data later, which is much more complicated.
*/
if (buffer_not_empty(rep->buf) && msg->msg_state < HTTP_MSG_ERROR) {
- if (unlikely(channel_full(rep) ||
- bi_end(rep->buf) < b_ptr(rep->buf, msg->next) ||
- bi_end(rep->buf) > rep->buf->data + rep->buf->size - global.tune.maxrewrite)) {
- if (rep->buf->o) {
- /* some data has still not left the buffer, wake us once that's done */
- if (rep->flags & (CF_SHUTW|CF_SHUTW_NOW|CF_WRITE_ERROR|CF_WRITE_TIMEOUT))
- goto abort_response;
- channel_dont_close(rep);
- rep->flags |= CF_READ_DONTWAIT; /* try to get back here ASAP */
- return 0;
- }
- if (rep->buf->i <= rep->buf->size - global.tune.maxrewrite)
- buffer_slow_realign(msg->chn->buf);
+ if (unlikely(!channel_reserved(rep))) {
+ /* some data has still not left the buffer, wake us once that's done */
+ if (rep->flags & (CF_SHUTW|CF_SHUTW_NOW|CF_WRITE_ERROR|CF_WRITE_TIMEOUT))
+ goto abort_response;
+ channel_dont_close(rep);
+ rep->flags |= CF_READ_DONTWAIT; /* try to get back here ASAP */
+ return 0;
}
+ if (unlikely(bi_end(rep->buf) < b_ptr(rep->buf, msg->next) ||
+ bi_end(rep->buf) > rep->buf->data + rep->buf->size - global.tune.maxrewrite))
+ buffer_slow_realign(rep->buf);
+
if (likely(msg->next < rep->buf->i))
http_msg_analyzer(msg, &txn->hdr_idx);
}