mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-09-23 14:51:27 +02:00
BUG/MEDIUM: filters: Fix data filtering when data are modified
Filters can alter data during the parsing, i.e when http_data or tcp_data callbacks are called. For now, the update must be done by hand. So we must handle changes in the channel buffers, especially on the number of input bytes pending (buf->i). In addition, a filter can choose to switch channel buffers to do its updates. So, during data filtering, we must always use the right buffer and not use variable to reference them. Without this patch, filters cannot safely alter data during the data parsing.
This commit is contained in:
parent
78f8dcb7f0
commit
55048a498a
@ -418,12 +418,11 @@ int
|
|||||||
flt_http_data(struct stream *s, struct http_msg *msg)
|
flt_http_data(struct stream *s, struct http_msg *msg)
|
||||||
{
|
{
|
||||||
struct filter *filter;
|
struct filter *filter;
|
||||||
struct buffer *buf = msg->chn->buf;
|
|
||||||
unsigned int buf_i;
|
unsigned int buf_i;
|
||||||
int ret = 0;
|
int delta = 0, ret = 0;
|
||||||
|
|
||||||
/* Save buffer state */
|
/* Save buffer state */
|
||||||
buf_i = buf->i;
|
buf_i = msg->chn->buf->i;
|
||||||
|
|
||||||
list_for_each_entry(filter, &strm_flt(s)->filters, list) {
|
list_for_each_entry(filter, &strm_flt(s)->filters, list) {
|
||||||
unsigned int *nxt;
|
unsigned int *nxt;
|
||||||
@ -440,9 +439,12 @@ flt_http_data(struct stream *s, struct http_msg *msg)
|
|||||||
*nxt = msg->next;
|
*nxt = msg->next;
|
||||||
|
|
||||||
if (FLT_OPS(filter)->http_data) {
|
if (FLT_OPS(filter)->http_data) {
|
||||||
|
unsigned int i = msg->chn->buf->i;
|
||||||
|
|
||||||
ret = FLT_OPS(filter)->http_data(s, filter, msg);
|
ret = FLT_OPS(filter)->http_data(s, filter, msg);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
break;
|
break;
|
||||||
|
delta += (int)(msg->chn->buf->i - i);
|
||||||
|
|
||||||
/* Update the next offset of the current filter */
|
/* Update the next offset of the current filter */
|
||||||
*nxt += ret;
|
*nxt += ret;
|
||||||
@ -450,18 +452,18 @@ flt_http_data(struct stream *s, struct http_msg *msg)
|
|||||||
/* And set this value as the bound for the next
|
/* And set this value as the bound for the next
|
||||||
* filter. It will not able to parse more data than this
|
* filter. It will not able to parse more data than this
|
||||||
* one. */
|
* one. */
|
||||||
buf->i = *nxt;
|
msg->chn->buf->i = *nxt;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* Consume all available data and update the next offset
|
/* Consume all available data and update the next offset
|
||||||
* of the current filter. buf->i is untouched here. */
|
* of the current filter. buf->i is untouched here. */
|
||||||
ret = MIN(msg->chunk_len + msg->next, buf->i) - *nxt;
|
ret = MIN(msg->chunk_len + msg->next, msg->chn->buf->i) - *nxt;
|
||||||
*nxt += ret;
|
*nxt += ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Restore the original buffer state */
|
/* Restore the original buffer state */
|
||||||
buf->i = buf_i;
|
msg->chn->buf->i = buf_i + delta;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -806,12 +808,11 @@ static int
|
|||||||
flt_data(struct stream *s, struct channel *chn)
|
flt_data(struct stream *s, struct channel *chn)
|
||||||
{
|
{
|
||||||
struct filter *filter;
|
struct filter *filter;
|
||||||
struct buffer *buf = chn->buf;
|
|
||||||
unsigned int buf_i;
|
unsigned int buf_i;
|
||||||
int ret = 0;
|
int delta = 0, ret = 0;
|
||||||
|
|
||||||
/* Save buffer state */
|
/* Save buffer state */
|
||||||
buf_i = buf->i;
|
buf_i = chn->buf->i;
|
||||||
|
|
||||||
list_for_each_entry(filter, &strm_flt(s)->filters, list) {
|
list_for_each_entry(filter, &strm_flt(s)->filters, list) {
|
||||||
unsigned int *nxt;
|
unsigned int *nxt;
|
||||||
@ -822,9 +823,12 @@ flt_data(struct stream *s, struct channel *chn)
|
|||||||
|
|
||||||
nxt = &FLT_NXT(filter, chn);
|
nxt = &FLT_NXT(filter, chn);
|
||||||
if (FLT_OPS(filter)->tcp_data) {
|
if (FLT_OPS(filter)->tcp_data) {
|
||||||
|
unsigned int i = chn->buf->i;
|
||||||
|
|
||||||
ret = FLT_OPS(filter)->tcp_data(s, filter, chn);
|
ret = FLT_OPS(filter)->tcp_data(s, filter, chn);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
break;
|
break;
|
||||||
|
delta += (int)(chn->buf->i - i);
|
||||||
|
|
||||||
/* Increase next offset of the current filter */
|
/* Increase next offset of the current filter */
|
||||||
*nxt += ret;
|
*nxt += ret;
|
||||||
@ -832,11 +836,11 @@ flt_data(struct stream *s, struct channel *chn)
|
|||||||
/* And set this value as the bound for the next
|
/* And set this value as the bound for the next
|
||||||
* filter. It will not able to parse more data than the
|
* filter. It will not able to parse more data than the
|
||||||
* current one. */
|
* current one. */
|
||||||
buf->i = *nxt;
|
chn->buf->i = *nxt;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* Consume all available data */
|
/* Consume all available data */
|
||||||
*nxt = buf->i;
|
*nxt = chn->buf->i;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Update <ret> value to be sure to have the last one when we
|
/* Update <ret> value to be sure to have the last one when we
|
||||||
@ -846,7 +850,7 @@ flt_data(struct stream *s, struct channel *chn)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Restore the original buffer state */
|
/* Restore the original buffer state */
|
||||||
chn->buf->i = buf_i;
|
chn->buf->i = buf_i + delta;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user