]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: filters: Add pre and post analyzer callbacks
authorChristopher Faulet <cfaulet@qualys.com>
Wed, 11 May 2016 15:13:39 +0000 (17:13 +0200)
committerWilly Tarreau <w@1wt.eu>
Wed, 18 May 2016 13:11:54 +0000 (15:11 +0200)
'channel_analyze' callback has been removed. Now, there are 2 callbacks to
surround calls to analyzers:

  * channel_pre_analyze: Called BEFORE all filterable analyzers. it can be
    called many times for the same analyzer, once at each loop until the
    analyzer finishes its processing. This callback is resumable, it returns a
    negative value if an error occurs, 0 if it needs to wait, any other value
    otherwise.

  * channel_post_analyze: Called AFTER all filterable analyzers. Here, AFTER
    means when an analyzer finishes its processing. This callback is NOT
    resumable, it returns a negative value if an error occurs, any other value
    otherwise.

Pre and post analyzer callbacks are not automatically called. 'pre_analyzers'
and 'post_analyzers' bit fields in the filter structure must be set to the right
value using AN_* flags (see include/types/channel.h).

The flag AN_RES_ALL has been added (AN_REQ_ALL already exists) to ease the life
of filter developers. AN_REQ_ALL and AN_RES_ALL include all filterable
analyzers.

include/proto/filters.h
include/types/channel.h
include/types/filters.h
src/filters.c
src/flt_trace.c
src/stream.c

index 7020285621eb5f920d50b9d359b2d353a76c3431..c351f6e20fe2fa23838fe9ed8eea49cc89a6b67f 100644 (file)
@@ -114,7 +114,8 @@ void flt_http_reset(struct stream *s, struct http_msg *msg);
 void flt_http_reply(struct stream *s, short status, const struct chunk *msg);
 
 int  flt_start_analyze(struct stream *s, struct channel *chn, unsigned int an_bit);
-int  flt_analyze(struct stream *s, struct channel *chn, unsigned int an_bit);
+int  flt_pre_analyze(struct stream *s, struct channel *chn, unsigned int an_bit);
+int  flt_post_analyze(struct stream *s, struct channel *chn, unsigned int an_bit);
 int  flt_analyze_http_headers(struct stream *s, struct channel *chn, unsigned int an_bit);
 int  flt_end_analyze(struct stream *s, struct channel *chn, unsigned int an_bit);
 
index b31f493a01dfe6f60aa22ff7223c51bdbfb008fe..dd50993110e9d943e7064eed08d2d1fc3b785279 100644 (file)
 #define AN_RES_HTTP_PROCESS_FE  0x00040000  /* process frontend's HTTP part (same for now) */
 #define AN_RES_STORE_RULES      0x00080000  /* table persistence matching */
 #define AN_RES_HTTP_XFER_BODY   0x00100000  /* forward response body */
+#define AN_RES_ALL              0x001f0000  /* all of the response analysers */
 
 #define AN_FLT_START_FE         0x01000000
 #define AN_FLT_START_BE         0x02000000
index e01e22599f93cd0f8ddfe9778217d447a7a3b1de..62fcfb1291e73552e969c52b90039164c57b19ca 100644 (file)
@@ -77,10 +77,14 @@ struct flt_kw_list {
  *  - channel_start_analyze: Called when a filter starts to analyze a channel.
  *                          Returns a negative value if an error occurs, 0 if
  *                          it needs to wait, any other value otherwise.
- *  - channel_analyze     : Called before each analyzer attached to a channel,
+ *  - channel_pre_analyze : Called before each analyzer attached to a channel,
  *                          expects analyzers responsible for data sending.
  *                          Returns a negative value if an error occurs, 0 if
  *                          it needs to wait, any other value otherwise.
+ *  - channel_post_analyze: Called after each analyzer attached to a channel,
+ *                          expects analyzers responsible for data sending.
+ *                          Returns a negative value if an error occurs,
+ *                          any other value otherwise.
  *  - channel_end_analyze : Called when all other analyzers have finished their
  *                          processing.
  *                          Returns a negative value if an error occurs, 0 if
@@ -140,7 +144,8 @@ struct flt_ops {
         * Channel callbacks
         */
        int  (*channel_start_analyze)(struct stream *s, struct filter *f, struct channel *chn);
-       int  (*channel_analyze)      (struct stream *s, struct filter *f, struct channel *chn, unsigned int an_bit);
+       int  (*channel_pre_analyze)  (struct stream *s, struct filter *f, struct channel *chn, unsigned int an_bit);
+       int  (*channel_post_analyze) (struct stream *s, struct filter *f, struct channel *chn, unsigned int an_bit);
        int  (*channel_end_analyze)  (struct stream *s, struct filter *f, struct channel *chn);
 
        /*
@@ -202,6 +207,8 @@ struct filter {
                                            * 0: request channel, 1: response channel */
        unsigned int    fwd[2];            /* Offset, relative to buf->p, to the next byte to forward for a specific channel
                                            * 0: request channel, 1: response channel */
+       unsigned int    pre_analyzers;     /* bit field indicating analyzers to pre-process */
+       unsigned int    post_analyzers;    /* bit field indicating analyzers to post-process */
        struct list     list;              /* Next filter for the same proxy/stream */
 };
 
index 051aa4873c19aeb7bf73896f4d6016f2bd20ec3b..139440d15c23a327e981dcce6bc356af72d888d8 100644 (file)
@@ -656,20 +656,23 @@ flt_start_analyze(struct stream *s, struct channel *chn, unsigned int an_bit)
 }
 
 /*
- * Calls 'channel_analyze' callback for all filters attached to a stream. This
- * function is called before each analyzer attached to a channel, expects
- * analyzers responsible for data sending. 'channel_analyze' callback is
- * resumable, so this function returns 0 if an error occurs or if it needs to
- * wait, any other value otherwise.
+ * Calls 'channel_pre_analyze' callback for all filters attached to a
+ * stream. This function is called BEFORE each analyzer attached to a channel,
+ * expects analyzers responsible for data sending. 'channel_pre_analyze'
+ * callback is resumable, so this function returns 0 if an error occurs or if it
+ * needs to wait, any other value otherwise.
+ *
+ * Note this function can be called many times for the same analyzer. In fact,
+ * it is called until the analyzer finishes its processing.
  */
 int
-flt_analyze(struct stream *s, struct channel *chn, unsigned int an_bit)
+flt_pre_analyze(struct stream *s, struct channel *chn, unsigned int an_bit)
 {
        int ret = 1;
 
        RESUME_FILTER_LOOP(s, chn) {
-               if (FLT_OPS(filter)->channel_analyze) {
-                       ret = FLT_OPS(filter)->channel_analyze(s, filter, chn, an_bit);
+               if (FLT_OPS(filter)->channel_pre_analyze && (filter->pre_analyzers & an_bit)) {
+                       ret = FLT_OPS(filter)->channel_pre_analyze(s, filter, chn, an_bit);
                        if (ret <= 0)
                                BREAK_EXECUTION(s, chn, check_result);
                }
@@ -679,6 +682,31 @@ flt_analyze(struct stream *s, struct channel *chn, unsigned int an_bit)
        return handle_analyzer_result(s, chn, 0, ret);
 }
 
+/*
+ * Calls 'channel_post_analyze' callback for all filters attached to a
+ * stream. This function is called AFTER each analyzer attached to a channel,
+ * expects analyzers responsible for data sending. 'channel_post_analyze'
+ * callback is NOT resumable, so this function returns a 0 if an error occurs,
+ * any other value otherwise.
+ *
+ * Here, AFTER means when the analyzer finishes its processing.
+ */
+int
+flt_post_analyze(struct stream *s, struct channel *chn, unsigned int an_bit)
+{
+       struct filter *filter;
+       int            ret = 1;
+
+       list_for_each_entry(filter, &strm_flt(s)->filters, list) {
+               if (FLT_OPS(filter)->channel_post_analyze &&  (filter->post_analyzers & an_bit)) {
+                       ret = FLT_OPS(filter)->channel_post_analyze(s, filter, chn, an_bit);
+                       if (ret < 0)
+                               break;
+               }
+       }
+       return handle_analyzer_result(s, chn, 0, ret);
+}
+
 /*
  * This function is the AN_FLT_HTTP_HDRS analyzer, used to filter HTTP headers
  * or a request or a response. Returns 0 if an error occurs or if it needs to
index 8a9d14dfaa7a9d24861cd6c394de7093e0934e61..a052ab59bad98d55bd1715a67f47ebff5ebe9506 100644 (file)
@@ -145,7 +145,8 @@ trace_chn_start_analyze(struct stream *s, struct filter *filter,
        STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s)",
                   __FUNCTION__,
                   channel_label(chn), proxy_mode(s), stream_pos(s));
-       register_data_filter(s, chn, filter);
+       filter->pre_analyzers  |= (AN_REQ_ALL | AN_RES_ALL);
+       filter->post_analyzers |= (AN_REQ_ALL | AN_RES_ALL);
        return 1;
 }
 
@@ -216,10 +217,11 @@ trace_chn_analyze(struct stream *s, struct filter *filter,
                        ana = "unknown";
        }
 
-       STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - analyzer=%s",
+       STRM_TRACE(conf, s, "%-25s: channel=%-10s - mode=%-5s (%s) - "
+                  "analyzer=%s - step=%s",
                   __FUNCTION__,
                   channel_label(chn), proxy_mode(s), stream_pos(s),
-                  ana);
+                  ana, ((chn->analysers & an_bit) ? "PRE" : "POST"));
        return 1;
 }
 
@@ -413,7 +415,8 @@ struct flt_ops trace_ops = {
 
        /* Handle channels activity */
        .channel_start_analyze = trace_chn_start_analyze,
-       .channel_analyze       = trace_chn_analyze,
+       .channel_pre_analyze   = trace_chn_analyze,
+       .channel_post_analyze  = trace_chn_analyze,
        .channel_end_analyze   = trace_chn_end_analyze,
 
        /* Filter HTTP requests and responses */
index 24eba1b71e1d06b77e6a47c4e1a4bd781c89b18f..2ca3b360069909d8259f2c672776ca7231595acc 100644 (file)
@@ -1498,17 +1498,19 @@ static int process_store_rules(struct stream *s, struct channel *rep, int an_bit
 
 /* These 2 following macros call an analayzer for the specified channel if the
  * right flag is set. The first one is used for "filterable" analyzers. If a
- * stream has some registered filters, 'channel_analyaze' callback is called.
- * The second are used for other analyzers (AN_FLT_* and
+ * stream has some registered filters, pre and post analyaze callbacks are
+ * called. The second are used for other analyzers (AN_FLT_* and
  * AN_REQ/RES_HTTP_XFER_BODY) */
 #define FLT_ANALYZE(strm, chn, fun, list, back, flag, ...)                     \
        {                                                                       \
                if ((list) & (flag)) {                                          \
                        if (HAS_FILTERS(strm)) {                                \
-                               if (!flt_analyze((strm), (chn), (flag)))        \
+                               if (!flt_pre_analyze((strm), (chn), (flag)))    \
                                        break;                                  \
                                if (!fun((strm), (chn), (flag), ##__VA_ARGS__)) \
                                        break;                                  \
+                               if (!flt_post_analyze((strm), (chn), (flag)))   \
+                                       break;                                  \
                        }                                                       \
                        else {                                                  \
                                if (!fun((strm), (chn), (flag), ##__VA_ARGS__)) \