[MEDIUM] reference the current hijack function in the buffer itself

Instead of calling a hard-coded function to produce data, let's
reference this function into the buffer and call it from there
when BF_HIJACK is set. This goes in the direction of more generic
session management code.
This commit is contained in:
Willy Tarreau 2008-12-07 18:03:29 +01:00
parent b5654f6ff4
commit 01bf8675ed
8 changed files with 36 additions and 32 deletions

View File

@ -126,13 +126,21 @@ static inline void buffer_abort(struct buffer *buf)
buf->flags |= BF_SHUTR_NOW | BF_SHUTW_NOW; buf->flags |= BF_SHUTR_NOW | BF_SHUTW_NOW;
} }
/* set the buffer to hijacking mode */ /* Installs <func> as a hijacker on the buffer <b> for session <s>. The hijack
static inline void buffer_start_hijack(struct buffer *buf) * 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) static inline void buffer_stop_hijack(struct buffer *buf)
{ {
buf->flags &= ~BF_HIJACK; buf->flags &= ~BF_HIJACK;

View File

@ -45,7 +45,7 @@
#define STATS_ST_CLOSE 3 #define STATS_ST_CLOSE 3
int stats_dump_raw(struct session *s, struct uri_auth *uri); 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_http(struct session *s, struct uri_auth *uri);
int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri); int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri);

View File

@ -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 http_process_request_body(struct session *s, struct buffer *req);
int process_response(struct session *t); 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(struct session *s);
int produce_content_stats_proxy(struct session *s, struct proxy *px); 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); void debug_hdr(const char *dir, struct session *t, const char *start, const char *end);

View File

@ -80,7 +80,7 @@
* it is strictly forbidden for the stream interface to send anything from the * it is strictly forbidden for the stream interface to send anything from the
* buffer. * 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_ANA_TIMEOUT 0x080000 /* the analyser timeout has expired */
#define BF_READ_ATTACHED 0x100000 /* the read side is attached for the first time */ #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. */ int len; /* size of the string from first to last char. <0 = uninit. */
}; };
/* needed for a declaration below */
struct session;
struct buffer { struct buffer {
unsigned int flags; /* BF_* */ unsigned int flags; /* BF_* */
int rex; /* expiration date for a read, in ticks */ int rex; /* expiration date for a read, in ticks */
@ -128,6 +131,7 @@ struct buffer {
char *rlim; /* read limit, used for header rewriting */ char *rlim; /* read limit, used for header rewriting */
unsigned int analysers; /* bit field indicating what to do on the buffer */ unsigned int analysers; /* bit field indicating what to do on the buffer */
int analyse_exp; /* expiration date for current analysers (if set) */ 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_large; /* number of consecutive large xfers */
unsigned char xfer_small; /* number of consecutive small xfers */ unsigned char xfer_small; /* number of consecutive small xfers */
unsigned long long total; /* total data read */ unsigned long long total; /* total data read */

View File

@ -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 /* 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 * 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) if (s->ana_state != STATS_ST_REP)
return 0; return;
if (stats_dump_raw(s, NULL) != 0) { if (stats_dump_raw(s, NULL) != 0) {
buffer_stop_hijack(s->rep); buffer_stop_hijack(s->rep);
s->ana_state = STATS_ST_CLOSE; 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) { switch (s->data_state) {
case DATA_ST_INIT: case DATA_ST_INIT:
/* the function had not been called yet */
buffer_start_hijack(rep);
chunk_printf(&msg, sizeof(trash), chunk_printf(&msg, sizeof(trash),
"HTTP/1.0 200 OK\r\n" "HTTP/1.0 200 OK\r\n"
"Cache-Control: no-cache\r\n" "Cache-Control: no-cache\r\n"

View File

@ -2989,33 +2989,32 @@ int process_response(struct session *t)
* called with client socket shut down on input. Right now, only statistics can * 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 * 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 * 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 * the buffer, or simply by letting an empty buffer upon return.
* when it wants to stop sending data, otherwise 0.
*/ */
int produce_content(struct session *s) void produce_content(struct session *s, struct buffer *rep)
{ {
if (s->data_source == DATA_SRC_NONE) { if (s->data_source == DATA_SRC_NONE) {
buffer_stop_hijack(s->rep); buffer_stop_hijack(rep);
return 1; return;
} }
else if (s->data_source == DATA_SRC_STATS) { else if (s->data_source == DATA_SRC_STATS) {
/* dump server statistics */ /* dump server statistics */
int ret = stats_dump_http(s, s->be->uri_auth); int ret = stats_dump_http(s, s->be->uri_auth);
if (ret >= 0) if (ret >= 0)
return ret; return;
/* -1 indicates an error */ /* -1 indicates an error */
} }
/* unknown data source or internal error */ /* unknown data source or internal error */
s->txn.status = 500; 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); trace_term(s, TT_HTTP_CNT_1);
if (!(s->flags & SN_ERR_MASK)) if (!(s->flags & SN_ERR_MASK))
s->flags |= SN_ERR_PRXCOND; s->flags |= SN_ERR_PRXCOND;
if (!(s->flags & SN_FINST_MASK)) if (!(s->flags & SN_FINST_MASK))
s->flags |= SN_FINST_R; s->flags |= SN_FINST_R;
buffer_stop_hijack(s->rep); buffer_stop_hijack(rep);
return 1; return;
} }
@ -4392,12 +4391,11 @@ int stats_check_uri_auth(struct session *t, struct proxy *backend)
buffer_write_dis(t->req); buffer_write_dis(t->req);
buffer_shutw_now(t->req); buffer_shutw_now(t->req);
buffer_shutr_now(t->rep); buffer_shutr_now(t->rep);
buffer_start_hijack(t->rep);
t->logs.tv_request = now; t->logs.tv_request = now;
t->data_source = DATA_SRC_STATS; t->data_source = DATA_SRC_STATS;
t->data_state = DATA_ST_INIT; t->data_state = DATA_ST_INIT;
t->task->nice = -32; /* small boost for HTTP statistics */ t->task->nice = -32; /* small boost for HTTP statistics */
produce_content(t); buffer_install_hijacker(t, t->rep, produce_content);
return 1; return 1;
} }

View File

@ -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_SHOW_STAT;
s->data_ctx.stats.flags |= STAT_FMT_CSV; s->data_ctx.stats.flags |= STAT_FMT_CSV;
s->ana_state = STATS_ST_REP; s->ana_state = STATS_ST_REP;
buffer_start_hijack(s->rep); buffer_install_hijacker(s, s->rep, stats_dump_raw_to_buffer);
stats_dump_raw_to_buffer(s, s->rep);
} }
else if (strcmp(args[1], "info") == 0) { else if (strcmp(args[1], "info") == 0) {
s->data_ctx.stats.flags |= STAT_SHOW_INFO; s->data_ctx.stats.flags |= STAT_SHOW_INFO;
s->data_ctx.stats.flags |= STAT_FMT_CSV; s->data_ctx.stats.flags |= STAT_FMT_CSV;
s->ana_state = STATS_ST_REP; s->ana_state = STATS_ST_REP;
buffer_start_hijack(s->rep); buffer_install_hijacker(s, s->rep, stats_dump_raw_to_buffer);
stats_dump_raw_to_buffer(s, s->rep);
} }
else { /* neither "stat" nor "info" */ else { /* neither "stat" nor "info" */
return 0; 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)) && if ((s->rep->flags & (BF_WRITE_PARTIAL|BF_WRITE_ERROR|BF_SHUTW)) &&
!(s->rep->flags & BF_FULL)) { !(s->rep->flags & BF_FULL)) {
/* it is the only hijacker right now */ s->rep->hijacker(s, s->rep);
stats_dump_raw_to_buffer(s, s->rep);
} }
s->rep->flags &= BF_CLEAR_READ & BF_CLEAR_WRITE & BF_CLEAR_TIMEOUT; s->rep->flags &= BF_CLEAR_READ & BF_CLEAR_WRITE & BF_CLEAR_TIMEOUT;
flags &= BF_CLEAR_READ & BF_CLEAR_WRITE & BF_CLEAR_TIMEOUT; flags &= BF_CLEAR_READ & BF_CLEAR_WRITE & BF_CLEAR_TIMEOUT;

View File

@ -805,7 +805,7 @@ resync_stream_interface:
if ((s->rep->flags & (BF_WRITE_PARTIAL|BF_WRITE_ERROR|BF_SHUTW)) && if ((s->rep->flags & (BF_WRITE_PARTIAL|BF_WRITE_ERROR|BF_SHUTW)) &&
!(s->rep->flags & BF_FULL)) { !(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; s->rep->flags &= BF_CLEAR_READ & BF_CLEAR_WRITE & BF_CLEAR_TIMEOUT;
flags &= BF_CLEAR_READ & BF_CLEAR_WRITE & BF_CLEAR_TIMEOUT; flags &= BF_CLEAR_READ & BF_CLEAR_WRITE & BF_CLEAR_TIMEOUT;