diff --git a/include/proto/buffers.h b/include/proto/buffers.h index 536f5a11b..bc472a069 100644 --- a/include/proto/buffers.h +++ b/include/proto/buffers.h @@ -126,13 +126,21 @@ 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) +/* Installs as a hijacker on the buffer for session . The hijack + * flag is set, and the function called once. The function is responsible for + * clearing the hijack bit. It is possible that the function clears the flag + * during this first call. + */ +static inline void buffer_install_hijacker(struct session *s, + struct buffer *b, + void (*func)(struct session *, struct buffer *)) { - buf->flags |= BF_HIJACK; + b->hijacker = func; + b->flags |= BF_HIJACK; + func(s, b); } -/* releases the buffer from hijacking mode */ +/* Releases the buffer from hijacking mode. Often used by the hijack function */ static inline void buffer_stop_hijack(struct buffer *buf) { buf->flags &= ~BF_HIJACK; diff --git a/include/proto/dumpstats.h b/include/proto/dumpstats.h index a7c5ab499..bc6bdad37 100644 --- a/include/proto/dumpstats.h +++ b/include/proto/dumpstats.h @@ -45,7 +45,7 @@ #define STATS_ST_CLOSE 3 int stats_dump_raw(struct session *s, struct uri_auth *uri); -int stats_dump_raw_to_buffer(struct session *s, struct buffer *req); +void stats_dump_raw_to_buffer(struct session *s, struct buffer *req); int stats_dump_http(struct session *s, struct uri_auth *uri); int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri); diff --git a/include/proto/proto_http.h b/include/proto/proto_http.h index c72365187..41f1922a9 100644 --- a/include/proto/proto_http.h +++ b/include/proto/proto_http.h @@ -66,7 +66,7 @@ int http_process_tarpit(struct session *s, struct buffer *req); int http_process_request_body(struct session *s, struct buffer *req); int process_response(struct session *t); -int produce_content(struct session *s); +void produce_content(struct session *s, struct buffer *rep); int produce_content_stats(struct session *s); int produce_content_stats_proxy(struct session *s, struct proxy *px); void debug_hdr(const char *dir, struct session *t, const char *start, const char *end); diff --git a/include/types/buffers.h b/include/types/buffers.h index 665c75d79..3c79a4edd 100644 --- a/include/types/buffers.h +++ b/include/types/buffers.h @@ -80,7 +80,7 @@ * it is strictly forbidden for the stream interface to send anything from the * buffer. */ -#define BF_HIJACK 0x040000 /* the producer is temporarily replaced */ +#define BF_HIJACK 0x040000 /* the producer is temporarily replaced by ->hijacker */ #define BF_ANA_TIMEOUT 0x080000 /* the analyser timeout has expired */ #define BF_READ_ATTACHED 0x100000 /* the read side is attached for the first time */ @@ -116,6 +116,9 @@ struct chunk { int len; /* size of the string from first to last char. <0 = uninit. */ }; +/* needed for a declaration below */ +struct session; + struct buffer { unsigned int flags; /* BF_* */ int rex; /* expiration date for a read, in ticks */ @@ -128,6 +131,7 @@ struct buffer { char *rlim; /* read limit, used for header rewriting */ unsigned int analysers; /* bit field indicating what to do on the buffer */ int analyse_exp; /* expiration date for current analysers (if set) */ + void (*hijacker)(struct session *, struct buffer *); /* alternative content producer */ unsigned char xfer_large; /* number of consecutive large xfers */ unsigned char xfer_small; /* number of consecutive small xfers */ unsigned long long total; /* total data read */ diff --git a/src/dumpstats.c b/src/dumpstats.c index 215e14902..590edbe7e 100644 --- a/src/dumpstats.c +++ b/src/dumpstats.c @@ -290,18 +290,18 @@ int stats_dump_raw(struct session *s, struct uri_auth *uri) /* This function is called to send output to the response buffer. It simply * calls stats_dump_raw(), and releases the buffer's hijack bit when the dump - * is finished. It always returns 0. + * is finished. */ -int stats_dump_raw_to_buffer(struct session *s, struct buffer *req) +void stats_dump_raw_to_buffer(struct session *s, struct buffer *req) { if (s->ana_state != STATS_ST_REP) - return 0; + return; if (stats_dump_raw(s, NULL) != 0) { buffer_stop_hijack(s->rep); s->ana_state = STATS_ST_CLOSE; } - return 0; + return; } @@ -327,9 +327,6 @@ 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 */ - buffer_start_hijack(rep); - chunk_printf(&msg, sizeof(trash), "HTTP/1.0 200 OK\r\n" "Cache-Control: no-cache\r\n" diff --git a/src/proto_http.c b/src/proto_http.c index e24b01baa..092c730ab 100644 --- a/src/proto_http.c +++ b/src/proto_http.c @@ -2989,33 +2989,32 @@ int process_response(struct session *t) * called with client socket shut down on input. Right now, only statistics can * 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. + * the buffer, or simply by letting an empty buffer upon return. */ -int produce_content(struct session *s) +void produce_content(struct session *s, struct buffer *rep) { if (s->data_source == DATA_SRC_NONE) { - buffer_stop_hijack(s->rep); - return 1; + buffer_stop_hijack(rep); + return; } else if (s->data_source == DATA_SRC_STATS) { /* dump server statistics */ int ret = stats_dump_http(s, s->be->uri_auth); if (ret >= 0) - return ret; + return; /* -1 indicates an error */ } /* unknown data source or internal error */ s->txn.status = 500; - stream_int_retnclose(s->rep->cons, error_message(s, HTTP_ERR_500)); + stream_int_retnclose(rep->cons, error_message(s, HTTP_ERR_500)); trace_term(s, TT_HTTP_CNT_1); if (!(s->flags & SN_ERR_MASK)) s->flags |= SN_ERR_PRXCOND; if (!(s->flags & SN_FINST_MASK)) s->flags |= SN_FINST_R; - buffer_stop_hijack(s->rep); - return 1; + buffer_stop_hijack(rep); + return; } @@ -4392,12 +4391,11 @@ int stats_check_uri_auth(struct session *t, struct proxy *backend) buffer_write_dis(t->req); 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; t->task->nice = -32; /* small boost for HTTP statistics */ - produce_content(t); + buffer_install_hijacker(t, t->rep, produce_content); return 1; } diff --git a/src/proto_uxst.c b/src/proto_uxst.c index d7567509e..06ec18570 100644 --- a/src/proto_uxst.c +++ b/src/proto_uxst.c @@ -596,15 +596,13 @@ int unix_sock_parse_request(struct session *s, char *line) s->data_ctx.stats.flags |= STAT_SHOW_STAT; s->data_ctx.stats.flags |= STAT_FMT_CSV; s->ana_state = STATS_ST_REP; - buffer_start_hijack(s->rep); - stats_dump_raw_to_buffer(s, s->rep); + buffer_install_hijacker(s, s->rep, stats_dump_raw_to_buffer); } else if (strcmp(args[1], "info") == 0) { s->data_ctx.stats.flags |= STAT_SHOW_INFO; s->data_ctx.stats.flags |= STAT_FMT_CSV; s->ana_state = STATS_ST_REP; - buffer_start_hijack(s->rep); - stats_dump_raw_to_buffer(s, s->rep); + buffer_install_hijacker(s, s->rep, stats_dump_raw_to_buffer); } else { /* neither "stat" nor "info" */ return 0; @@ -837,8 +835,7 @@ void uxst_process_session(struct task *t, int *next) if ((s->rep->flags & (BF_WRITE_PARTIAL|BF_WRITE_ERROR|BF_SHUTW)) && !(s->rep->flags & BF_FULL)) { - /* it is the only hijacker right now */ - stats_dump_raw_to_buffer(s, s->rep); + s->rep->hijacker(s, s->rep); } s->rep->flags &= BF_CLEAR_READ & BF_CLEAR_WRITE & BF_CLEAR_TIMEOUT; flags &= BF_CLEAR_READ & BF_CLEAR_WRITE & BF_CLEAR_TIMEOUT; diff --git a/src/session.c b/src/session.c index e19bb5630..a6190730d 100644 --- a/src/session.c +++ b/src/session.c @@ -805,7 +805,7 @@ resync_stream_interface: if ((s->rep->flags & (BF_WRITE_PARTIAL|BF_WRITE_ERROR|BF_SHUTW)) && !(s->rep->flags & BF_FULL)) { - produce_content(s); + s->rep->hijacker(s, s->rep); } s->rep->flags &= BF_CLEAR_READ & BF_CLEAR_WRITE & BF_CLEAR_TIMEOUT; flags &= BF_CLEAR_READ & BF_CLEAR_WRITE & BF_CLEAR_TIMEOUT;