diff --git a/include/proto/filters.h b/include/proto/filters.h index 2ad0f4997..346d8a012 100644 --- a/include/proto/filters.h +++ b/include/proto/filters.h @@ -36,6 +36,9 @@ /* Useful macros to access per-channel values. It can be safely used inside * filters. */ #define CHN_IDX(chn) (((chn)->flags & CF_ISRESP) == CF_ISRESP) +#define FLT_STRM_OFF(s, chn) (strm_flt(s)->offset[CHN_IDX(chn)]) +#define FLT_OFF(flt, chn) ((flt)->offset[CHN_IDX(chn)]) + #define FLT_NXT(flt, chn) ((flt)->next[CHN_IDX(chn)]) #define FLT_FWD(flt, chn) ((flt)->fwd[CHN_IDX(chn)]) #define flt_req_nxt(flt) ((flt)->next[0]) @@ -103,9 +106,11 @@ int flt_stream_init(struct stream *s); void flt_stream_release(struct stream *s, int only_backend); void flt_stream_check_timeouts(struct stream *s); +int flt_http_payload(struct stream *s, struct http_msg *msg, unsigned int len); +int flt_http_end(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); 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); @@ -219,5 +224,26 @@ flt_change_forward_size(struct filter *filter, struct channel *chn, int len) } } +/* This function must be called when a filter alter payload data. It updates + * offsets of all previous filters and the offset of the stream. Do not call + * this function when a filter change the size of payload data leads to an + * undefined behavior. + * + * This is the filter's responsiblitiy to update data itself.. + */ +static inline void +flt_update_offsets(struct filter *filter, struct channel *chn, int len) +{ + struct stream *s = chn_strm(chn); + struct filter *f; + + list_for_each_entry(f, &strm_flt(s)->filters, list) { + if (f == filter) + break; + if (IS_DATA_FILTER(filter, chn)) + FLT_OFF(f, chn) += len; + } +} + #endif /* _PROTO_FILTERS_H */ diff --git a/include/types/filters.h b/include/types/filters.h index c460e7968..f52592d85 100644 --- a/include/types/filters.h +++ b/include/types/filters.h @@ -120,14 +120,17 @@ struct flt_kw_list { * headers was parsed and analyzed. * Returns a negative value if an error occurs, 0 if * it needs to wait, any other value otherwise. + * - http_payload : Called when some data can be consumed. + * Returns a negative value if an error occurs, else + * the number of forwarded bytes. * - http_data : Called when unparsed body data are available. * Returns a negative value if an error occurs, else - * the number of consumed bytes. + * the number of consumed bytes. [DEPRECATED] * - http_chunk_trailers : Called when part of trailer headers of a * chunk-encoded request/response are ready to be * processed. * Returns a negative value if an error occurs, any - * other value otherwise. + * other value otherwise. [DEPRECATED] * - http_end : Called when all the request/response has been * processed and all body data has been forwarded. * Returns a negative value if an error occurs, 0 if @@ -143,7 +146,7 @@ struct flt_kw_list { * Returns nothing. * - http_forward_data : Called when some data can be consumed. * Returns a negative value if an error occurs, else - * the number of forwarded bytes. + * the number of forwarded bytes. [DEPRECATED] * - tcp_data : Called when unparsed data are available. * Returns a negative value if an error occurs, else * the number of consumed bytes. @@ -181,10 +184,12 @@ 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_payload) (struct stream *s, struct filter *f, struct http_msg *msg, + unsigned int offset, unsigned int len); int (*http_end) (struct stream *s, struct filter *f, struct http_msg *msg); - int (*http_forward_data) (struct stream *s, struct filter *f, struct http_msg *msg, + int (*http_data) (struct stream *s, struct filter *f, struct http_msg *msg); // DEPRECATED + int (*http_chunk_trailers)(struct stream *s, struct filter *f, struct http_msg *msg); // DEPRECATED + int (*http_forward_data) (struct stream *s, struct filter *f, struct http_msg *msg, // DEPRECATED unsigned int len); void (*http_reset) (struct stream *s, struct filter *f, struct http_msg *msg); @@ -199,12 +204,14 @@ struct flt_ops { unsigned int len); }; +/* Flags set on a filter config */ +#define FLT_CFG_FL_HTX 0x00000001 /* The filter can filter HTX streams */ + /* Flags set on a filter instance */ #define FLT_FL_IS_BACKEND_FILTER 0x0001 /* The filter is a backend filter */ #define FLT_FL_IS_REQ_DATA_FILTER 0x0002 /* The filter will parse data on the request channel */ #define FLT_FL_IS_RSP_DATA_FILTER 0x0004 /* The filter will parse data on the response channel */ - /* Flags set on the stream, common to all filters attached to its stream */ #define STRM_FLT_FL_HAS_FILTERS 0x0001 /* The stream has at least one filter */ @@ -217,6 +224,7 @@ struct flt_conf { struct flt_ops *ops; /* The filter callbacks */ void *conf; /* The filter configuration */ struct list list; /* Next filter for the same proxy */ + unsigned int flags; /* FLT_CFG_FL_* */ }; /* @@ -236,6 +244,7 @@ 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 long long offset[2]; 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 */ @@ -253,6 +262,7 @@ struct strm_flt { unsigned short flags; /* STRM_FL_* */ unsigned char nb_req_data_filters; /* Number of data filters registered on the request channel */ unsigned char nb_rsp_data_filters; /* Number of data filters registered on the response channel */ + unsigned long long offset[2]; }; #endif /* _TYPES_FILTERS_H */ diff --git a/src/filters.c b/src/filters.c index d29a0c08e..2b8238957 100644 --- a/src/filters.c +++ b/src/filters.c @@ -27,6 +27,8 @@ #include #include #include +#include +#include #include #include #include @@ -335,15 +337,6 @@ flt_check(struct proxy *proxy) err += fconf->ops->check(proxy, fconf); } err += check_legacy_http_comp_flt(proxy); - - if (!LIST_ISEMPTY(&proxy->filter_configs) && - (proxy->options2 & PR_O2_USE_HTX)) { - ha_alert("config: %s '%s' : filters cannot be used when " - "the HTX internal representation is enabled.\n", - proxy_type_str(proxy), proxy->id); - err++; - } - return err; } @@ -394,8 +387,12 @@ flt_deinit_all_per_thread() static int flt_stream_add_filter(struct stream *s, struct flt_conf *fconf, unsigned int flags) { - struct filter *f = pool_alloc(pool_head_filter); + struct filter *f; + if ((strm_fe(s)->options2 & PR_O2_USE_HTX) && !(fconf->flags & FLT_CFG_FL_HTX)) + return 0; + + f = pool_alloc(pool_head_filter); if (!f) /* not enough memory */ return -1; memset(f, 0, sizeof(*f)); @@ -540,6 +537,8 @@ flt_set_stream_backend(struct stream *s, struct proxy *be) * filters and adjusts available data to be sure that a filter cannot parse more * data than its predecessors. A filter can choose to not consume all available * data. Returns -1 if an error occurs, the number of consumed bytes otherwise. + * + * DEPRECATED FUNCTION - CALLED FROM LEGACY HTTP ANALYZERS */ int flt_http_data(struct stream *s, struct http_msg *msg) @@ -602,6 +601,8 @@ flt_http_data(struct stream *s, struct http_msg *msg) * analyzers. Filters can know how much data were parsed by the HTTP parsing * until the last call with the msg->sol value. Returns a negative value if an * error occurs, any other value otherwise. + * + * DEPRECATED FUNCTION - CALLED FROM LEGACY HTTP ANALYZERS */ int flt_http_chunk_trailers(struct stream *s, struct http_msg *msg) @@ -640,6 +641,10 @@ flt_http_chunk_trailers(struct stream *s, struct http_msg *msg) * functions is called when all data were parsed and forwarded. 'http_end' * callback is resumable, so this function returns a negative value if an error * occurs, 0 if it needs to wait for some reason, any other value otherwise. + * + * Be carefull, this function can be called from the HTTP legacy analyzers or + * from HTX analyzers. If your filter is compatible with the two modes, use + * IS_HTX_STRM macro on the stream. */ int flt_http_end(struct stream *s, struct http_msg *msg) @@ -660,6 +665,10 @@ end: /* * Calls 'http_reset' callback for all filters attached to a stream. This * happens when a 100-continue response is received. + * + * Be carefull, this function can be called from the HTTP legacy analyzers or + * from HTX analyzers. If your filter is compatible with the two modes, use + * IS_HTX_STRM macro on the stream. */ void flt_http_reset(struct stream *s, struct http_msg *msg) @@ -675,6 +684,10 @@ flt_http_reset(struct stream *s, struct http_msg *msg) /* * Calls 'http_reply' callback for all filters attached to a stream when HA * decides to stop the HTTP message processing. + * + * Be carefull, this function can be called from the HTTP legacy analyzers or + * from HTX analyzers. If your filter is compatible with the two modes, use + * IS_HTX_STRM macro on the stream. */ void flt_http_reply(struct stream *s, short status, const struct buffer *msg) @@ -688,13 +701,15 @@ flt_http_reply(struct stream *s, short status, const struct buffer *msg) } /* - * Calls 'http_forward_data' callback for all "data" filters attached to a - * stream. This function is called when some data can be forwarded in the + * Calls 'http_forward_data' callback for all "data" filters attached to a HTTP + * legacy stream. This function is called when some data can be forwarded in the * AN_REQ_HTTP_XFER_BODY and AN_RES_HTTP_XFER_BODY analyzers. It takes care to * update the forward offset of filters and adjusts "forwardable" data to be * sure that a filter cannot forward more data than its predecessors. A filter * can choose to not forward all parsed data. Returns a negative value if an * error occurs, else the number of forwarded bytes. + * + * DEPRECATED FUNCTION - CALLED FROM LEGACY HTTP ANALYZERS */ int flt_http_forward_data(struct stream *s, struct http_msg *msg, unsigned int len) @@ -749,6 +764,48 @@ flt_http_forward_data(struct stream *s, struct http_msg *msg, unsigned int len) return ret; } +/* + * Calls 'http_payload' callback for all "data" filters attached to a + * stream. This function is called when some data can be forwarded in the + * AN_REQ_HTTP_XFER_BODY and AN_RES_HTTP_XFER_BODY analyzers. It takes care to + * update the filters and the stream offset to be sure that a filter cannot + * forward more data than its predecessors. A filter can choose to not forward + * all data. Returns a negative value if an error occurs, else the number of + * forwarded bytes. + * + * Be carefull, this callback is only called from HTX analyzers. So the + * channel's buffer must be considered as an HTX structured. Of course, your + * filter must support HTX streams. + */ +int +flt_http_payload(struct stream *s, struct http_msg *msg, unsigned int len) +{ + struct filter *filter; + unsigned long long *strm_off = &FLT_STRM_OFF(s, msg->chn); + unsigned int out = co_data(msg->chn); + int ret = len - out; + + list_for_each_entry(filter, &strm_flt(s)->filters, list) { + /* Call "data" filters only */ + if (!IS_DATA_FILTER(filter, msg->chn)) + continue; + if (FLT_OPS(filter)->http_payload) { + unsigned long long *flt_off = &FLT_OFF(filter, msg->chn); + unsigned int offset = *flt_off - *strm_off; + + ret = FLT_OPS(filter)->http_payload(s, filter, msg, out + offset, ret - offset); + if (ret < 0) + goto end; + *flt_off += ret; + ret += offset; + } + } + *strm_off += ret; + + end: + return ret; +} + /* * Calls 'channel_start_analyze' callback for all filters attached to a * stream. This function is called when we start to analyze a request or a @@ -851,6 +908,10 @@ flt_post_analyze(struct stream *s, struct channel *chn, unsigned int an_bit) * This function is the AN_REQ/RES_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 wait, any other value otherwise. + * + * Be carefull, this function can be called from the HTTP legacy analyzers or + * from HTX analyzers. If your filter is compatible with the two modes, use + * IS_HTX_STRM macro on the stream. */ int flt_analyze_http_headers(struct stream *s, struct channel *chn, unsigned int an_bit) @@ -868,15 +929,28 @@ flt_analyze_http_headers(struct stream *s, struct channel *chn, unsigned int an_ } } 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. */ - list_for_each_entry(filter, &strm_flt(s)->filters, list) { - /* Handle "data" filters only */ - if (!IS_DATA_FILTER(filter, chn)) - continue; - FLT_NXT(filter, chn) = msg->sov; + if (IS_HTX_STRM(s)) { + struct htx *htx = htx_from_buf(&chn->buf); + int32_t pos; + + for (pos = htx_get_head(htx); pos != -1; pos = htx_get_next(htx, pos)) { + struct htx_blk *blk = htx_get_blk(htx, pos); + c_adv(chn, htx_get_blksz(blk)); + if (htx_get_blk_type(blk) == HTX_BLK_EOH) + break; + } + } + else { + /* 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. */ + list_for_each_entry(filter, &strm_flt(s)->filters, list) { + /* Handle "data" filters only */ + if (!IS_DATA_FILTER(filter, chn)) + continue; + FLT_NXT(filter, chn) = msg->sov; + } } check_result: