]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
[MEDIUM] stats: make HTTP stats use an I/O handler
authorWilly Tarreau <w@1wt.eu>
Sun, 4 Oct 2009 13:56:38 +0000 (15:56 +0200)
committerWilly Tarreau <w@1wt.eu>
Sun, 4 Oct 2009 13:56:38 +0000 (15:56 +0200)
Doing this, we can remove the last BF_HIJACK user and remove
produce_content(). s->data_source could also be removed but
it is currently used to detect if the stats or a server was
used.

include/proto/dumpstats.h
include/proto/proto_http.h
include/types/session.h
src/dumpstats.c
src/proto_http.c

index 79ae40476244906203bd226a1aaaae914cf934b9..700fc95f8387c78ae6ae95f265b49a041c93d3cc 100644 (file)
@@ -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 */
index 35a216c10018c1e7295f63948a30d167306b3acb..5a129986eee18a9d26c781184387e12a918fbfde 100644 (file)
@@ -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);
index 226e00c985779c0c06853d4d7db39a5aa5c577b2..d3dbe67b915674460e4f4179c0972b6630bfe5e8 100644 (file)
@@ -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 */
 };
 
index 14cc519063143ab6ff5e282183a18c089818556a..e8eef21f61f23e3eac3d54bf747d11df45e26c48 100644 (file)
@@ -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 <s>. 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, "</body></html>\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, "</table><p>\n");
 
-                       if (buffer_write_chunk(rep, &msg) >= 0)
+                       if (buffer_feed_chunk(rep, &msg) >= 0)
                                return 0;
                }
 
index 33f01311b395c3cf1f790eb8e3d837c556a214c7..025cd64467bec709537c1157c8185cca4c0acd1f 100644 (file)
@@ -3238,40 +3238,6 @@ int process_response(struct session *t)
        return 0;
 }
 
-/*
- * Produces data for the session <s> 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;
 }