/* 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])
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);
}
}
+/* 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 */
* 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
* 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.
* 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);
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 */
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_* */
};
/*
* 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 */
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 */
#include <proto/compression.h>
#include <proto/filters.h>
#include <proto/flt_http_comp.h>
+#include <proto/http_htx.h>
+#include <proto/htx.h>
#include <proto/proto_http.h>
#include <proto/stream.h>
#include <proto/stream_interface.h>
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;
}
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));
* 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)
* 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)
* 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)
/*
* 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)
/*
* 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)
}
/*
- * 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)
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
* 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)
}
} 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: