]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: filters: Replace filter_http_headers callback by an analyzer
authorChristopher Faulet <cfaulet@qualys.com>
Wed, 2 Dec 2015 08:57:32 +0000 (09:57 +0100)
committerWilly Tarreau <w@1wt.eu>
Tue, 9 Feb 2016 13:53:15 +0000 (14:53 +0100)
This new analyzer will be called for each HTTP request/response, before the
parsing of the body. It is identified by AN_FLT_HTTP_HDRS.

Special care was taken about the following condition :

  * the frontend is a TCP proxy
  * filters are defined in the frontend section
  * the selected backend is a HTTP proxy

So, this patch explicitly add AN_FLT_HTTP_HDRS analyzer on the request and the
response channels when the backend is a HTTP proxy and when there are filters
attatched on the stream.
This patch simplifies http_request_forward_body and http_response_forward_body
functions.

include/proto/filters.h
include/types/channel.h
include/types/filters.h
src/cfgparse.c
src/filters.c
src/flt_http_comp.c
src/proto_http.c
src/proxy.c
src/stream.c

index 0eb69a2cd0a87864be867c95984bba5f761a87ef..8eaaf3ad80627146d64a5523eb4b92612b55ab46 100644 (file)
@@ -91,17 +91,17 @@ int  flt_set_stream_backend(struct stream *s, struct proxy *be);
 int  flt_stream_init(struct stream *s);
 void flt_stream_release(struct stream *s, int only_backend);
 
-int  flt_http_headers(struct stream *s, struct http_msg *msg);
 int  flt_http_data(struct stream *s, struct http_msg *msg);
 int  flt_http_chunk_trailers(struct stream *s, struct http_msg *msg);
 int  flt_http_end(struct stream *s, struct http_msg *msg);
-void flt_http_reset(struct stream *s, struct http_msg *msg);
+int  flt_http_forward_data(struct stream *s, struct http_msg *msg, unsigned int len);
 
+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_http_forward_data(struct stream *s, struct http_msg *msg, unsigned int len);
 
 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_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);
 
 int  flt_xfer_data(struct stream *s, struct channel *chn, unsigned int an_bit);
index e43e8ebff8cb97c383d5a095d6bf19b6228c2df4..b31f493a01dfe6f60aa22ff7223c51bdbfb008fe 100644 (file)
 #define AN_FLT_START_BE         0x02000000
 #define AN_FLT_END              0x04000000
 #define AN_FLT_XFER_DATA        0x08000000
+#define AN_FLT_HTTP_HDRS        0x10000000
 
 #define AN_FLT_ALL_FE           0x0d000000
 #define AN_FLT_ALL_BE           0x0e000000
index e3a091dd164818e3fd6d2a26453588564088449f..4bfa1c22b9c970862deeac4ce3ea2fc8d1340168 100644 (file)
@@ -99,12 +99,6 @@ struct flt_kw_list {
  *                          it needs to wait, any other value otherwise.
  *
  *
- *  - http_headers        : Called just before headers sending and parsing of
- *                          the body. At this step, headers are fully parsed
- *                          and the processing on it is finished.
- *                          Returns a negative value if an error occurs, 0 if
- *                          it needs to read more data (or to wait for some
- *                          reason), any other value otherwise.
  *  - http_data           : Called when unparsed body data are available.
  *                          Returns a negative value if an error occurs, else
  *                          the number of consumed bytes.
@@ -160,16 +154,15 @@ struct flt_ops {
        /*
         * HTTP callbacks
         */
-       int  (*http_headers)       (struct stream *s, struct filter *f, struct http_msg *msg);
        int  (*http_data)          (struct stream *s, struct filter *f, struct http_msg *msg);
        int  (*http_chunk_trailers)(struct stream *s, struct filter *f, struct http_msg *msg);
        int  (*http_end)           (struct stream *s, struct filter *f, struct http_msg *msg);
-       void (*http_reset)         (struct stream *s, struct filter *f, struct http_msg *msg);
+       int  (*http_forward_data)  (struct stream *s, struct filter *f, struct http_msg *msg,
+                                   unsigned int len);
 
+       void (*http_reset)         (struct stream *s, struct filter *f, struct http_msg *msg);
        void (*http_reply)         (struct stream *s, struct filter *f, short status,
                                    const struct chunk *msg);
-       int  (*http_forward_data)  (struct stream *s, struct filter *f, struct http_msg *msg,
-                                   unsigned int len);
 
        /*
         * TCP callbacks
index d343f0515310b117201e5c490586a3937080c967..55622a4255402275e6fdec38e954eb0ab1b6f1b8 100644 (file)
@@ -8438,6 +8438,10 @@ out_uri_auth_compat:
                        if (!LIST_ISEMPTY(&curproxy->filters)) {
                                curproxy->fe_req_ana |= AN_FLT_ALL_FE;
                                curproxy->fe_rsp_ana |= AN_FLT_ALL_FE;
+                               if (curproxy->mode == PR_MODE_HTTP) {
+                                       curproxy->fe_req_ana |= AN_FLT_HTTP_HDRS;
+                                       curproxy->fe_rsp_ana |= AN_FLT_HTTP_HDRS;
+                               }
                        }
                }
 
@@ -8464,6 +8468,10 @@ out_uri_auth_compat:
                        if (!LIST_ISEMPTY(&curproxy->filters)) {
                                curproxy->be_req_ana |= AN_FLT_ALL_BE;
                                curproxy->be_rsp_ana |= AN_FLT_ALL_BE;
+                               if (curproxy->mode == PR_MODE_HTTP) {
+                                       curproxy->be_req_ana |= AN_FLT_HTTP_HDRS;
+                                       curproxy->be_rsp_ana |= AN_FLT_HTTP_HDRS;
+                               }
                        }
                }
        }
index 88c361246187991f5e2b2e676c81fd77eff4ae5d..b2ceefe2c496dce397f3a0fc772596fd0c80f098 100644 (file)
@@ -391,30 +391,6 @@ flt_set_stream_backend(struct stream *s, struct proxy *be)
        return 0;
 }
 
-int
-flt_http_headers(struct stream *s, struct http_msg *msg)
-{
-       struct filter *filter;
-       int            ret = 1;
-
-       RESUME_FILTER_LOOP(s, msg->chn) {
-               if (filter->ops  && filter->ops->http_headers) {
-                       ret = filter->ops->http_headers(s, filter, msg);
-                       if (ret <= 0)
-                               BREAK_EXECUTION(s, msg->chn, end);
-               }
-       } RESUME_FILTER_END;
-
-       /* We increase FLT_NXT offset after all processing on headers because
-        * any filter can alter them. So the definitive size of headers
-        * (msg->sov) is only known when all filters have been called. */
-       list_for_each_entry(filter, &s->strm_flt.filters, list) {
-               FLT_NXT(filter, msg->chn) = msg->sov;
-       }
- end:
-       return ret;
-}
-
 /*
  * Calls 'http_data' callback for all "data" filters attached to a stream. This
  * function is called when incoming data are available (excluding chunks
@@ -659,8 +635,41 @@ flt_analyze(struct stream *s, struct channel *chn, unsigned int an_bit)
        } RESUME_FILTER_END;
 
  check_result:
-       ret = handle_analyzer_result(s, chn, 0, ret);
-       return ret;
+       return handle_analyzer_result(s, chn, 0, ret);
+}
+
+/*
+ * This function do the same that the previsous one, but for the
+ * AN_FLT_HTTP_HDRS analyzer. The difference is what is done when all filters
+ * have been called. Returns 0 if an error occurs or if it needs to wait, any
+ * other value otherwise.
+ */
+int
+flt_analyze_http_headers(struct stream *s, struct channel *chn, unsigned int an_bit)
+{
+       struct filter   *filter;
+       struct http_msg *msg;
+       int              ret = 1;
+
+       RESUME_FILTER_LOOP(s, chn) {
+               if (filter->ops->channel_analyze) {
+                       ret = filter->ops->channel_analyze(s, filter, chn, an_bit);
+                       if (ret <= 0)
+                               BREAK_EXECUTION(s, chn, check_result);
+               }
+       } RESUME_FILTER_END;
+
+       /* We increase next offset of all "data" filters after all processing on
+        * headers because any filter can alter them. So the definitive size of
+        * headers (msg->sov) is only known when all filters have been
+        * called. */
+       msg = ((chn->flags & CF_ISRESP) ? &s->txn->rsp : &s->txn->req);
+       list_for_each_entry(filter, &s->strm_flt.filters, list) {
+               FLT_NXT(filter, msg->chn) = msg->sov;
+       }
+
+ check_result:
+       return handle_analyzer_result(s, chn, an_bit, ret);
 }
 
 /*
index 5dacc90d7debeb9109b91060c110b3567b2740df..b07065d7a0d73b0220f467df29826ad9d7142160 100644 (file)
@@ -108,13 +108,16 @@ comp_analyze(struct stream *s, struct filter *filter, struct channel *chn,
        if (!strm_fe(s)->comp && !s->be->comp)
                goto end;
 
-       switch (an_bit) {
-               case AN_RES_HTTP_PROCESS_BE:
+       if (an_bit == AN_FLT_HTTP_HDRS) {
+               if (!(chn->flags & CF_ISRESP))
+                       select_compression_request_header(st, s, &s->txn->req);
+               else {
                        select_compression_response_header(st, s, &s->txn->rsp);
                        if (st->comp_algo)
                                st->sov = s->txn->rsp.sov;
-                       break;
+               }
        }
+
   end:
        return 1;
 }
@@ -145,19 +148,6 @@ comp_end_analyze(struct stream *s, struct filter *filter, struct channel *chn)
        return 1;
 }
 
-static int
-comp_http_headers(struct stream *s, struct filter *filter,
-                 struct http_msg *msg)
-{
-       struct comp_state *st = filter->ctx;
-
-       if (strm_fe(s)->comp || s->be->comp) {
-               if (!(msg->chn->flags & CF_ISRESP))
-                       select_compression_request_header(st, s, msg);
-       }
-       return 1;
-}
-
 static int
 comp_http_data(struct stream *s, struct filter *filter, struct http_msg *msg)
 {
@@ -725,10 +715,9 @@ struct flt_ops comp_ops = {
        .channel_analyze       = comp_analyze,
        .channel_end_analyze   = comp_end_analyze,
 
-       .http_headers      = comp_http_headers,
-       .http_data         = comp_http_data,
-       .http_chunk_trailers = comp_http_chunk_trailers,
-       .http_forward_data = comp_http_forward_data,
+       .http_data             = comp_http_data,
+       .http_chunk_trailers   = comp_http_chunk_trailers,
+       .http_forward_data     = comp_http_forward_data,
 };
 
 static int
index ab608fedf90974a1145627913cc247d58e4179bd..fdb17b6cc3365f5c10786ad944da71c38ac432bf 100644 (file)
@@ -4191,7 +4191,7 @@ int http_process_req_common(struct stream *s, struct channel *req, int an_bit, s
                        s->flags |= SF_FINST_R;
 
                /* enable the minimally required analyzers to handle keep-alive and compression on the HTTP response */
-               req->analysers &= (AN_REQ_HTTP_BODY | AN_FLT_END);
+               req->analysers &= (AN_REQ_HTTP_BODY | AN_FLT_HTTP_HDRS | AN_FLT_END);
                req->analysers &= ~AN_FLT_XFER_DATA;
                req->analysers |= AN_REQ_HTTP_XFER_BODY;
                goto done;
@@ -5462,16 +5462,6 @@ int http_request_forward_body(struct stream *s, struct channel *req, int an_bit)
         * an "Expect: 100-continue" header.
         */
        if (msg->msg_state == HTTP_MSG_BODY) {
-               /* we have msg->sov which points to the first byte of message
-                * body, and req->buf.p still points to the beginning of the
-                * message. We forward the headers now, as we don't need them
-                * anymore, and we want to flush them.
-                */
-               FLT_STRM_CB(s, flt_http_headers(s, msg),
-                           /* default_ret */ 1,
-                           /* on_error    */ goto return_bad_req,
-                           /* on_wait     */ return 0);
-
                /* The previous analysers guarantee that the state is somewhere
                 * between MSG_BODY and the first MSG_DATA. So msg->sol and
                 * msg->next are always correct.
@@ -6774,16 +6764,6 @@ int http_response_forward_body(struct stream *s, struct channel *res, int an_bit
        channel_auto_close(res);
 
        if (msg->msg_state == HTTP_MSG_BODY) {
-               /* we have msg->sov which points to the first byte of message
-                * body, and res->buf.p still points to the beginning of the
-                * message. We forward the headers now, as we don't need them
-                * anymore, and we want to flush them.
-                */
-               FLT_STRM_CB(s, flt_http_headers(s, msg),
-                           /* default_ret */ 1,
-                           /* on_error    */ goto return_bad_res,
-                           /* on_wait     */ return 0);
-
                /* The previous analysers guarantee that the state is somewhere
                 * between MSG_BODY and the first MSG_DATA. So msg->sol and
                 * msg->next are always correct.
index f22c7462f10050e77d794d0bfbcfdfb38466e657..1c92e91f8d58c3297cff4dc0acd9bdeeefc0cc7b 100644 (file)
@@ -1164,6 +1164,11 @@ int stream_set_backend(struct stream *s, struct proxy *be)
                http_init_txn(s);
        }
 
+       /* Be sure to filter request headers if the backend is an HTTP proxy and
+        * if there are filters attached to the stream. */
+       if (s->be->mode == PR_MODE_HTTP && HAS_FILTERS(s))
+               s->req.analysers |= AN_FLT_HTTP_HDRS;
+
        if (s->txn) {
                if (be->options2 & PR_O2_RSPBUG_OK)
                        s->txn->rsp.err_pos = -1; /* let buggy responses pass */
index a274ea450d095ff431f0aa535fefc419fe85c264..7c10158a002d4465aff793e24a66315d691c4b8d 100644 (file)
@@ -755,6 +755,12 @@ static void sess_establish(struct stream *s)
        }
 
        rep->analysers |= strm_fe(s)->fe_rsp_ana | s->be->be_rsp_ana;
+
+       /* Be sure to filter response headers if the backend is an HTTP proxy
+        * and if there are filters attached to the stream. */
+       if (s->be->mode == PR_MODE_HTTP && HAS_FILTERS(s))
+               rep->analysers |= AN_FLT_HTTP_HDRS;
+
        rep->flags |= CF_READ_ATTACHED; /* producer is now attached */
        if (req->flags & CF_WAKE_CONNECT) {
                req->flags |= CF_WAKE_ONCE;
@@ -1854,6 +1860,12 @@ struct task *process_stream(struct task *t)
                                        UPDATE_ANALYSERS(req->analysers, ana_list, ana_back, AN_REQ_STICKING_RULES);
                                }
 
+                               if (ana_list & AN_FLT_HTTP_HDRS) {
+                                       if (!flt_analyze_http_headers(s, req, AN_FLT_HTTP_HDRS))
+                                               break;
+                                       UPDATE_ANALYSERS(req->analysers, ana_list, ana_back, AN_FLT_HTTP_HDRS);
+                               }
+
                                if (ana_list & AN_FLT_XFER_DATA) {
                                        if (!flt_xfer_data(s, req, AN_FLT_XFER_DATA))
                                                break;
@@ -1980,6 +1992,12 @@ struct task *process_stream(struct task *t)
                                        UPDATE_ANALYSERS(res->analysers, ana_list, ana_back, AN_RES_HTTP_PROCESS_BE);
                                }
 
+                               if (ana_list & AN_FLT_HTTP_HDRS) {
+                                       if (!flt_analyze_http_headers(s, res, AN_FLT_HTTP_HDRS))
+                                               break;
+                                       UPDATE_ANALYSERS(res->analysers, ana_list, ana_back, AN_FLT_HTTP_HDRS);
+                               }
+
                                if (ana_list & AN_FLT_XFER_DATA) {
                                        if (!flt_xfer_data(s, res, AN_FLT_XFER_DATA))
                                                break;