diff --git a/include/proto/buffers.h b/include/proto/buffers.h index 3b5e2bdc7..194f4ee12 100644 --- a/include/proto/buffers.h +++ b/include/proto/buffers.h @@ -108,6 +108,18 @@ static inline void buffer_abort(struct buffer *buf) buf->flags |= BF_SHUTR_NOW | BF_SHUTW_NOW; } +/* set the buffer to hijacking mode */ +static inline void buffer_start_hijack(struct buffer *buf) +{ + buf->flags |= BF_HIJACK; +} + +/* releases the buffer from hijacking mode */ +static inline void buffer_stop_hijack(struct buffer *buf) +{ + buf->flags &= ~BF_HIJACK; +} + /* returns the maximum number of bytes writable at once in this buffer */ static inline int buffer_max(const struct buffer *buf) { diff --git a/include/types/buffers.h b/include/types/buffers.h index bc8a18490..d67c93241 100644 --- a/include/types/buffers.h +++ b/include/types/buffers.h @@ -72,6 +72,7 @@ #define BF_MASK_INTERFACE (BF_MASK_INTF_I | BF_MASK_INTF_O) #define BF_MASK_ANALYSER (BF_FULL|BF_READ_NULL|BF_READ_ERROR|BF_READ_TIMEOUT|BF_SHUTR|BF_WRITE_ERROR) +#define BF_MASK_INJECTER (BF_FULL|BF_WRITE_STATUS|BF_WRITE_TIMEOUT|BF_SHUTW) /* Analysers (buffer->analysers). * Those bits indicate that there are some processing to do on the buffer diff --git a/include/types/session.h b/include/types/session.h index 2d0439b7d..8b87be21a 100644 --- a/include/types/session.h +++ b/include/types/session.h @@ -47,7 +47,7 @@ #define SN_BE_ASSIGNED 0x00000008 /* a backend was assigned. Conns are accounted. */ #define SN_CONN_CLOSED 0x00000010 /* "Connection: close" was present or added */ #define SN_MONITOR 0x00000020 /* this session comes from a monitoring system */ -#define SN_SELF_GEN 0x00000040 /* the proxy generates data for the client (eg: stats) */ +/* unused: 0x00000040 */ #define SN_FRT_ADDR_SET 0x00000080 /* set if the frontend address has been filled */ #define SN_REDISP 0x00000100 /* set if this session was redispatched from one server to another */ #define SN_CONN_TAR 0x00000200 /* set if this session is turning around before reconnecting */ diff --git a/src/dumpstats.c b/src/dumpstats.c index 1b7e1924c..e4ef0b655 100644 --- a/src/dumpstats.c +++ b/src/dumpstats.c @@ -290,7 +290,7 @@ int stats_dump_raw(struct session *s, struct uri_auth *uri) /* * Produces statistics data for the session . Expects to be called with * client socket shut down on input. It stops by itself by unsetting the - * SN_SELF_GEN flag from the session, which it uses to keep on being called + * BF_HIJACK flag from the buffer, which it uses to keep on being called * when there is free space in the buffer, of simply by letting an empty buffer * upon return.s->data_ctx must have been zeroed before the first call, and the * flags set. It returns 0 if it had to stop writing data and an I/O is needed, @@ -310,7 +310,7 @@ int stats_dump_http(struct session *s, struct uri_auth *uri) switch (s->data_state) { case DATA_ST_INIT: /* the function had not been called yet */ - s->flags |= SN_SELF_GEN; // more data will follow + buffer_start_hijack(rep); chunk_printf(&msg, sizeof(trash), "HTTP/1.0 200 OK\r\n" @@ -337,7 +337,7 @@ int stats_dump_http(struct session *s, struct uri_auth *uri) if (s->txn.meth == HTTP_METH_HEAD) { /* that's all we return in case of HEAD request */ s->data_state = DATA_ST_FIN; - s->flags &= ~SN_SELF_GEN; + buffer_stop_hijack(rep); return 1; } @@ -570,12 +570,12 @@ int stats_dump_http(struct session *s, struct uri_auth *uri) /* fall through */ case DATA_ST_FIN: - s->flags &= ~SN_SELF_GEN; + buffer_stop_hijack(rep); return 1; default: /* unknown state ! */ - s->flags &= ~SN_SELF_GEN; + buffer_stop_hijack(rep); return -1; } } diff --git a/src/proto_http.c b/src/proto_http.c index e8bd63142..66f8e169b 100644 --- a/src/proto_http.c +++ b/src/proto_http.c @@ -772,15 +772,25 @@ void process_session(struct task *t, int *next) rqf_req = s->req->flags; } - if ((rpf_rep ^ s->rep->flags) & BF_MASK_ANALYSER) { - /* the analysers must block it themselves */ - if (s->rep->prod->state >= SI_ST_EST) { + if (unlikely(s->rep->flags & BF_HIJACK)) { + /* In inject mode, we wake up everytime something has + * happened on the write side of the buffer. + */ + if ((s->rep->flags & (BF_PARTIAL_WRITE|BF_WRITE_ERROR|BF_SHUTW)) && + !(s->rep->flags & BF_FULL)) { + if (produce_content(s) != 0) + resync = 1; /* completed, better re-check flags */ + } + } + else if (s->rep->prod->state >= SI_ST_EST) { + if ((rpf_rep ^ s->rep->flags) & BF_MASK_ANALYSER) { + /* the analysers must block it themselves */ resync = 1; s->rep->flags |= BF_MAY_FORWARD; if (s->rep->analysers) process_response(s); + rpf_rep = s->rep->flags; } - rpf_rep = s->rep->flags; } } while (resync); @@ -3895,15 +3905,15 @@ int process_srv_conn(struct session *t) /* * Produces data for the session depending on its source. Expects to be * called with client socket shut down on input. Right now, only statistics can - * be produced. It stops by itself by unsetting the SN_SELF_GEN flag from the - * session, which it uses to keep on being called when there is free space in + * be produced. It stops by itself by unsetting the BF_HIJACK flag from the + * buffer, which it uses to keep on being called when there is free space in * the buffer, or simply by letting an empty buffer upon return. It returns 1 * when it wants to stop sending data, otherwise 0. */ int produce_content(struct session *s) { if (s->data_source == DATA_SRC_NONE) { - s->flags &= ~SN_SELF_GEN; + buffer_stop_hijack(s->rep); return 1; } else if (s->data_source == DATA_SRC_STATS) { @@ -3922,7 +3932,7 @@ int produce_content(struct session *s) s->flags |= SN_ERR_PRXCOND; if (!(s->flags & SN_FINST_MASK)) s->flags |= SN_FINST_R; - s->flags &= ~SN_SELF_GEN; + buffer_stop_hijack(s->rep); return 1; } @@ -5297,10 +5307,9 @@ int stats_check_uri_auth(struct session *t, struct proxy *backend) /* The request is valid, the user is authenticated. Let's start sending * data. */ - EV_FD_CLR(t->req->prod->fd, DIR_RD); - buffer_shutr(t->req); - buffer_shutr(t->rep); - buffer_set_rlim(t->req, BUFSIZE); /* no more rewrite needed */ + buffer_shutw_now(t->req); + buffer_shutr_now(t->rep); + buffer_start_hijack(t->rep); t->logs.tv_request = now; t->data_source = DATA_SRC_STATS; t->data_state = DATA_ST_INIT;