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);
#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
* 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.
/*
* 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
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;
+ }
}
}
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;
+ }
}
}
}
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
} 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);
}
/*
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;
}
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)
{
.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
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;
* 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.
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.
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 */
}
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;
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;
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;