Filters are designed to be chained. It is possible to declare several filters in
the same proxy section. The evaluation order is the declaration order in legacy
mode, and the class order - possibly refined with "filter-sequence" - in the
-new mode. Frontend and backend filters are also chained, frontend ones called
-first. Even if the filters processing is serialized, each filter will behave
-as it was alone (unless it was developed to be aware of other filters). For
-all that, some constraints are imposed to filters, especially when data
-exchanged between the client and the server are processed. We will discuss
-again these constraints when we will tackle the subject of writing a filter.
+new mode. Frontend and backend filters are also chained: on the request
+path the frontend ones are called first, and on the response path the
+backend ones are called first. Even if the filters processing is
+serialized, each filter will behave as it was alone (unless it was
+developed to be aware of other filters). For all that, some constraints
+are imposed to filters, especially when data exchanged between the
+client and the server are processed. We will discuss again these
+constraints when we will tackle the subject of writing a filter.
+
chunked ""
rxresp
expect resp.status == 200
- expect resp.http.x-probe-order == "F.a;F.b;B.a;B.b;"
+ expect resp.http.x-probe-order == "B.a;B.b;F.a;F.b;"
expect resp.http.x-probe-errors == <undef>
expect resp.body == "complete response"
} -run
chunked ""
rxresp
expect resp.status == 200
- expect resp.http.x-probe-order == "F.a;F.b;B.a;B.b;"
+ expect resp.http.x-probe-order == "B.a;B.b;F.a;F.b;"
expect resp.http.x-probe-errors == <undef>
expect resp.body == "complete response"
} -run
txreq -req POST -url /legacy -body "second"
rxresp
expect resp.status == 200
- expect resp.http.x-probe-order == "F.b;F.a;L.a;L.c;"
- expect resp.http.x-probe-instances == "F.b:3;F.a:4;L.a:1;L.c:2;"
- expect resp.http.x-probe-request-bytes == "F.a:6;L.a:6;"
+ expect resp.http.x-probe-order == "L.a;L.c;F.b;F.a;"
+ expect resp.http.x-probe-instances == "L.a:1;L.c:2;F.b:3;F.a:4;"
+ expect resp.http.x-probe-request-bytes == "L.a:6;F.a:6;"
expect resp.http.x-probe-errors == <undef>
expect resp.body == "legacy response"
txreq
rxresp
expect resp.status == 200
- expect resp.http.x-filter-order == "Fa:2;Fb:1;Ba:1;Bb:2;"
+ expect resp.http.x-filter-order == "Ba:1;Bb:2;Fa:2;Fb:1;"
expect resp.http.x-filter-start == <undef>
} -run
if (flt_use_legacy_filter(px)) {
/* The attach callbacks are called in the global order, then
* the stream's request and response filter lists are filled
- * with the proxy's request and response orders.
+ * with the proxy's request and response orders. The backend
+ * filters are prepended to the response list, so they are
+ * evaluated before the frontend filters: a response reaches
+ * the backend filters first.
*/
list_for_each_entry(fconf, &px->filter_configs, list) {
if (flt_stream_add_filter(s, fconf, flags) < 0)
}
}
}
- list_for_each_entry(fconf, &px->filters_res_configs, by_res) {
- list_for_each_entry(filter, &strm_flt(s)->filters, list) {
- if (filter->config == fconf) {
- LIST_APPEND(&s->res.flt.filters, &filter->res_list);
- break;
+ if (flags & FLT_FL_IS_BACKEND_FILTER) {
+ list_for_each_entry_rev(fconf, &px->filters_res_configs, by_res) {
+ list_for_each_entry(filter, &strm_flt(s)->filters, list) {
+ if (filter->config == fconf) {
+ LIST_INSERT(&s->res.flt.filters, &filter->res_list);
+ break;
+ }
+ }
+ }
+ }
+ else {
+ list_for_each_entry(fconf, &px->filters_res_configs, by_res) {
+ list_for_each_entry(filter, &strm_flt(s)->filters, list) {
+ if (filter->config == fconf) {
+ LIST_APPEND(&s->res.flt.filters, &filter->res_list);
+ break;
+ }
}
}
}