diff --git a/include/proto/dumpstats.h b/include/proto/dumpstats.h index 79ae40476..700fc95f8 100644 --- a/include/proto/dumpstats.h +++ b/include/proto/dumpstats.h @@ -59,6 +59,7 @@ int stats_dump_http(struct session *s, struct buffer *rep, struct uri_auth *uri) int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri); int stats_dump_sess_to_buffer(struct session *s, struct buffer *rep); int stats_dump_errors_to_buffer(struct session *s, struct buffer *rep); +void http_stats_io_handler(struct stream_interface *si); #endif /* _PROTO_DUMPSTATS_H */ diff --git a/include/proto/proto_http.h b/include/proto/proto_http.h index 35a216c10..5a129986e 100644 --- a/include/proto/proto_http.h +++ b/include/proto/proto_http.h @@ -1,23 +1,23 @@ /* - include/proto/proto_http.h - This file contains HTTP protocol definitions. - - Copyright (C) 2000-2008 Willy Tarreau - w@1wt.eu - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation, version 2.1 - exclusively. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ + * include/proto/proto_http.h + * This file contains HTTP protocol definitions. + * + * Copyright (C) 2000-2009 Willy Tarreau - w@1wt.eu + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation, version 2.1 + * exclusively. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ #ifndef _PROTO_PROTO_HTTP_H #define _PROTO_PROTO_HTTP_H @@ -68,9 +68,6 @@ int http_process_tarpit(struct session *s, struct buffer *req, int an_bit); int http_process_request_body(struct session *s, struct buffer *req, int an_bit); int process_response(struct session *t); -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); void get_srv_from_appsession(struct session *t, const char *begin, int len); int apply_filter_to_req_headers(struct session *t, struct buffer *req, struct hdr_exp *exp); diff --git a/include/types/session.h b/include/types/session.h index 226e00c98..d3dbe67b9 100644 --- a/include/types/session.h +++ b/include/types/session.h @@ -211,7 +211,7 @@ struct session { int ptr; /* <0: headers, >=0 : text pointer to restart from */ int bol; /* pointer to beginning of current line */ } errors; - } data_ctx; /* used by produce_content to dump the stats right now */ + } data_ctx; /* used by stats I/O handlers to dump the stats */ unsigned int uniq_id; /* unique ID used for the traces */ }; diff --git a/src/dumpstats.c b/src/dumpstats.c index 14cc51906..e8eef21f6 100644 --- a/src/dumpstats.c +++ b/src/dumpstats.c @@ -587,7 +587,6 @@ int stats_dump_raw_to_buffer(struct session *s, struct buffer *rep) /* skip the disabled proxies and non-networked ones */ if (px->state != PR_STSTOPPED && (px->cap & (PR_CAP_FE | PR_CAP_BE))) { - rep->flags |= BF_READ_PARTIAL; /* remove this once stats_dump_proxy uses buffer_feed */ if (stats_dump_proxy(s, px, NULL) == 0) return 0; } @@ -616,6 +615,57 @@ int stats_dump_raw_to_buffer(struct session *s, struct buffer *rep) } +/* This I/O handler runs as an applet embedded in a stream interface. It is + * used to send HTTP stats over a TCP socket. The mechanism is very simple. + * si->st0 becomes non-zero once the transfer is finished. The handler + * automatically unregisters itself once transfer is complete. + */ +void http_stats_io_handler(struct stream_interface *si) +{ + struct session *s = si->private; + struct buffer *req = si->ob; + struct buffer *res = si->ib; + + if (unlikely(si->state == SI_ST_DIS || si->state == SI_ST_CLO)) + goto out; + + /* check that the output is not closed */ + if (res->flags & (BF_SHUTW|BF_SHUTW_NOW)) + si->st0 = 1; + + if (!si->st0) { + if (stats_dump_http(s, res, s->be->uri_auth)) { + si->st0 = 1; + si->shutw(si); + } else { + /* buffer full */ + si->flags |= SI_FL_WAIT_ROOM; + } + } + + if ((res->flags & BF_SHUTR) && (si->state == SI_ST_EST)) + si->shutw(si); + + if ((req->flags & BF_SHUTW) && (si->state == SI_ST_EST) && si->st0) { + si->shutr(si); + res->flags |= BF_READ_NULL; + } + + /* update all other flags and resync with the other side */ + si->update(si); + + /* we don't want to expire timeouts while we're processing requests */ + si->ib->rex = TICK_ETERNITY; + si->ob->wex = TICK_ETERNITY; + + out: + if (unlikely(si->state == SI_ST_DIS || si->state == SI_ST_CLO)) { + /* check that we have released everything then unregister */ + stream_int_unregister_handler(si); + } +} + + /* * Produces statistics data for the session . Expects to be called with * client socket shut down on input. It stops by itself by unsetting the @@ -650,11 +700,9 @@ int stats_dump_http(struct session *s, struct buffer *rep, struct uri_auth *uri) chunk_printf(&msg, "\r\n"); s->txn.status = 200; - if (buffer_write_chunk(rep, &msg) >= 0) + if (buffer_feed_chunk(rep, &msg) >= 0) return 0; - msg.len = 0; - if (!(s->flags & SN_ERR_MASK)) // this is not really an error but it is s->flags |= SN_ERR_PRXCOND; // to mark that it comes from the proxy if (!(s->flags & SN_FINST_MASK)) @@ -663,7 +711,6 @@ int stats_dump_http(struct session *s, struct buffer *rep, 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; - buffer_stop_hijack(rep); return 1; } @@ -754,7 +801,7 @@ int stats_dump_http(struct session *s, struct buffer *rep, struct uri_auth *uri) } else { print_csv_header(&msg); } - if (buffer_write_chunk(rep, &msg) >= 0) + if (buffer_feed_chunk(rep, &msg) >= 0) return 0; s->data_state = DATA_ST_INFO; @@ -866,7 +913,7 @@ int stats_dump_http(struct session *s, struct buffer *rep, struct uri_auth *uri) "" ); - if (buffer_write_chunk(rep, &msg) >= 0) + if (buffer_feed_chunk(rep, &msg) >= 0) return 0; } @@ -895,7 +942,7 @@ int stats_dump_http(struct session *s, struct buffer *rep, struct uri_auth *uri) case DATA_ST_END: if (!(s->data_ctx.stats.flags & STAT_FMT_CSV)) { chunk_printf(&msg, "\n"); - if (buffer_write_chunk(rep, &msg) >= 0) + if (buffer_feed_chunk(rep, &msg) >= 0) return 0; } @@ -903,12 +950,11 @@ int stats_dump_http(struct session *s, struct buffer *rep, struct uri_auth *uri) /* fall through */ case DATA_ST_FIN: - buffer_stop_hijack(rep); return 1; default: /* unknown state ! */ - buffer_stop_hijack(rep); + s->data_state = DATA_ST_FIN; return -1; } } @@ -994,7 +1040,7 @@ int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri) px->id, px->desc ? "desc" : "empty", px->desc ? px->desc : ""); - if (buffer_write_chunk(rep, &msg) >= 0) + if (buffer_feed_chunk(rep, &msg) >= 0) return 0; } @@ -1075,7 +1121,7 @@ int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri) px->fe_sps_lim, px->fe_sps_max); } - if (buffer_write_chunk(rep, &msg) >= 0) + if (buffer_feed_chunk(rep, &msg) >= 0) return 0; } @@ -1339,7 +1385,7 @@ int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri) /* finish with EOL */ chunk_printf(&msg, "\n"); } - if (buffer_write_chunk(rep, &msg) >= 0) + if (buffer_feed_chunk(rep, &msg) >= 0) return 0; } /* for sv */ @@ -1452,7 +1498,7 @@ int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri) read_freq_ctr(&px->be_sess_per_sec), px->be_sps_max); } - if (buffer_write_chunk(rep, &msg) >= 0) + if (buffer_feed_chunk(rep, &msg) >= 0) return 0; } @@ -1463,7 +1509,7 @@ int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri) if (!(s->data_ctx.stats.flags & STAT_FMT_CSV)) { chunk_printf(&msg, "

\n"); - if (buffer_write_chunk(rep, &msg) >= 0) + if (buffer_feed_chunk(rep, &msg) >= 0) return 0; } diff --git a/src/proto_http.c b/src/proto_http.c index 33f01311b..025cd6446 100644 --- a/src/proto_http.c +++ b/src/proto_http.c @@ -3238,40 +3238,6 @@ int process_response(struct session *t) return 0; } -/* - * 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 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. - */ -void produce_content(struct session *s, struct buffer *rep) -{ - if (s->data_source == DATA_SRC_NONE) { - buffer_stop_hijack(rep); - return; - } - else if (s->data_source == DATA_SRC_STATS) { - /* dump server statistics */ - int ret; - ret = stats_dump_http(s, rep, s->be->uri_auth); - if (ret >= 0) - return; - /* -1 indicates an error */ - } - - /* unknown data source or internal error */ - s->txn.status = 500; - stream_int_retnclose(rep->cons, error_message(s, HTTP_ERR_500)); - 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(rep); - return; -} - - /* Iterate the same filter through all request headers. * Returns 1 if this filter can be stopped upon return, otherwise 0. * Since it can manage the switch to another backend, it updates the per-proxy @@ -4508,7 +4474,7 @@ void get_srv_from_appsession(struct session *t, const char *begin, int len) * * It is assumed that the request is either a HEAD or GET and that the * t->be->uri_auth field is valid. An HTTP/401 response may be sent, or - * produce_content() can be called to start sending data. + * the stats I/O handler will be registered to start sending data. * * Returns 1 if the session's state changes, otherwise 0. */ @@ -4625,15 +4591,13 @@ int stats_check_uri_auth(struct session *t, struct proxy *backend) /* The request is valid, the user is authenticated. Let's start sending * data. */ - buffer_dont_connect(t->req); - buffer_shutw_now(t->req); - buffer_shutr_now(t->rep); - stream_int_retnclose(t->rep->cons, NULL); 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 */ - buffer_install_hijacker(t, t->rep, produce_content); + stream_int_register_handler(t->rep->prod, http_stats_io_handler); + t->rep->prod->private = t; + t->rep->prod->st0 = t->rep->prod->st1 = 0; return 1; }