diff --git a/include/common/buf.h b/include/common/buf.h index d9de0734f..02a66b366 100644 --- a/include/common/buf.h +++ b/include/common/buf.h @@ -32,10 +32,10 @@ /* Structure defining a buffer's head */ struct buffer { - char *p; /* buffer's start pointer, separates in and out data */ + size_t head; /* start offset of remaining data relative to data */ + size_t len; /* length of data after head */ size_t size; /* buffer size in bytes */ - size_t i; /* number of input bytes pending for analysis in the buffer */ - size_t o; /* number of out bytes the sender can consume from this buffer */ + size_t output; /* TEMPORARY: part of which is to be forwarded */ char data[0]; /* bytes of stored data */ }; @@ -73,7 +73,7 @@ static inline char *b_wrap(const struct buffer *b) /* b_data() : returns the number of bytes present in the buffer. */ static inline size_t b_data(const struct buffer *b) { - return b->i + b->o; + return b->len; } /* b_room() : returns the amount of room left in the buffer */ @@ -95,12 +95,12 @@ static inline size_t b_full(const struct buffer *b) */ static inline size_t __b_stop_ofs(const struct buffer *b) { - return b->p - b->data + b->i; + return b->head + b->len; } static inline const char *__b_stop(const struct buffer *b) { - return b->p + b->i; + return b_orig(b) + __b_stop_ofs(b); } static inline size_t b_stop_ofs(const struct buffer *b) @@ -114,7 +114,7 @@ static inline size_t b_stop_ofs(const struct buffer *b) static inline const char *b_stop(const struct buffer *b) { - return b->data + b_stop_ofs(b); + return b_orig(b) + b_stop_ofs(b); } @@ -125,32 +125,27 @@ static inline const char *b_stop(const struct buffer *b) */ static inline size_t __b_peek_ofs(const struct buffer *b, size_t ofs) { - return b->p - b->data + ofs - b->o; + return b->head + ofs; } static inline char *__b_peek(const struct buffer *b, size_t ofs) { - return b->p - b->o + ofs; + return b_orig(b) + __b_peek_ofs(b, ofs); } static inline size_t b_peek_ofs(const struct buffer *b, size_t ofs) { size_t ret = __b_peek_ofs(b, ofs); - if (ret >= b->size) { - /* wraps either up or down */ - if ((ssize_t)ret < 0) - ret += b->size; - else - ret -= b->size; - } + if (ret >= b->size) + ret -= b->size; return ret; } static inline char *b_peek(const struct buffer *b, size_t ofs) { - return (char *)b->data + b_peek_ofs(b, ofs); + return b_orig(b) + b_peek_ofs(b, ofs); } @@ -160,22 +155,22 @@ static inline char *b_peek(const struct buffer *b, size_t ofs) */ static inline size_t __b_head_ofs(const struct buffer *b) { - return __b_peek_ofs(b, 0); + return b->head; } static inline char *__b_head(const struct buffer *b) { - return __b_peek(b, 0); + return b_orig(b) + __b_head_ofs(b); } static inline size_t b_head_ofs(const struct buffer *b) { - return b_peek_ofs(b, 0); + return __b_head_ofs(b); } static inline char *b_head(const struct buffer *b) { - return b_peek(b, 0); + return __b_head(b); } @@ -248,20 +243,11 @@ static inline int b_almost_full(const struct buffer *b) } /* b_space_wraps() : returns non-zero only if the buffer's free space wraps : - * [ |oooo| ] => yes - * [ |iiii| ] => yes - * [ |oooo|iiii| ] => yes - * [oooo| ] => no - * [ |oooo] => no - * [iiii| ] => no - * [ |iiii] => no - * [oooo|iiii| ] => no - * [ |oooo|iiii] => no - * [iiii| |oooo] => no - * [oo|iiii| |oo] => no - * [iiii| |oo|ii] => no - * [oooooooooo|iiiiiiiiiii] => no - * [iiiiiiiiiiiii|oooooooo] => no + * [ |xxxx| ] => yes + * [xxxx| ] => no + * [ |xxxx] => no + * [xxxx| |xxxx] => no + * [xxxxxxxxxx|xxxxxxxxxxx] => no * * So the only case where the buffer does not wrap is when there's data either * at the beginning or at the end of the buffer. Thus we have this : @@ -379,32 +365,29 @@ static inline size_t b_getblk_nc(const struct buffer *buf, const char **blk1, si /* b_reset() : resets a buffer. The size is not touched. */ static inline void b_reset(struct buffer *b) { - b->o = 0; - b->i = 0; - b->p = b_orig(b); + b->head = 0; + b->len = 0; + b->output = 0; } /* b_sub() : decreases the buffer length by */ static inline void b_sub(struct buffer *b, size_t count) { - b->i -= count; + b->len -= count; } /* b_add() : increase the buffer length by */ static inline void b_add(struct buffer *b, size_t count) { - b->i += count; + b->len += count; } /* b_set_data() : sets the buffer's length */ static inline void b_set_data(struct buffer *b, size_t len) { - if (len >= b->o) - b->i = len - b->o; - else { - b->o = len; - b->i = 0; - } + if (len < b->output) + b->output = len; + b->len = len; } /* b_del() : skips bytes in a buffer . Covers both the output and the @@ -413,22 +396,21 @@ static inline void b_set_data(struct buffer *b, size_t len) */ static inline void b_del(struct buffer *b, size_t del) { - if (del <= b->o) { - b->o -= del; - del = 0; - } - if (del) { - b->p = b_peek(b, del); - b->i -= del; - del = 0; - } + if (del >= b->output) + b->output = 0; + else + b->output -= del; + b->len -= del; + b->head += del; + if (b->head >= b->size) + b->head -= b->size; } /* b_realign_if_empty() : realigns a buffer if it's empty */ static inline void b_realign_if_empty(struct buffer *b) { if (!b_data(b)) - b->p = b->data; + b->head = 0; } /* b_slow_realign() : this function realigns a possibly wrapping buffer so that @@ -470,7 +452,7 @@ static inline void b_slow_realign(struct buffer *b, char *swap, size_t output) memcpy(b_orig(b), swap, b_data(b) - output); memcpy(b_wrap(b) - output, swap + b_size(b) - output, output); - b->p = b->data; + b->head = b_size(b) - output; } #endif /* _COMMON_BUF_H */ diff --git a/include/common/buffer.h b/include/common/buffer.h index 86eec168b..fde7b03f2 100644 --- a/include/common/buffer.h +++ b/include/common/buffer.h @@ -104,16 +104,14 @@ static inline int buffer_almost_full(const struct buffer *buf) return b_almost_full(buf); } -/* Cut the first pending bytes in a contiguous buffer. It is illegal to - * call this function with remaining data waiting to be sent (o > 0). The - * caller must ensure that is smaller than the actual buffer's length. - * This is mainly used to remove empty lines at the beginning of a request - * or a response. +/* Cut the first pending bytes in a contiguous buffer. The caller must + * ensure that is smaller than the actual buffer's length. This is mainly + * used to remove empty lines at the beginning of a request or a response. */ static inline void bi_fast_delete(struct buffer *buf, int n) { - buf->i -= n; - buf->p += n; + buf->len -= n; + buf->head += n; } /* This function writes the string at position which must be in @@ -128,16 +126,16 @@ static inline int buffer_replace(struct buffer *b, char *pos, char *end, const c return buffer_replace2(b, pos, end, str, strlen(str)); } -/* Tries to write char into output data at buffer . Supports wrapping. - * Data are truncated if buffer is full. +/* Tries to append char at the end of buffer . Supports wrapping. Data + * are truncated if buffer is full. */ static inline void bo_putchr(struct buffer *b, char c) { if (b_data(b) == b->size) return; *b_tail(b) = c; - b->p = b_peek(b, b->o + 1); - b->o++; + b->len++; + b->output++; } /* Tries to append block at the end of buffer . Supports wrapping. @@ -158,13 +156,12 @@ static inline unsigned int bo_putblk(struct buffer *b, const char *blk, unsigned half = len; memcpy(b_tail(b), blk, half); - b->p = b_peek(b, b->o + half); - b->o += half; + b->len += half; if (len > half) { memcpy(b_tail(b), blk + half, len - half); - b->p = b_peek(b, b->o + len - half); - b->o += len - half; + b->len += len - half; } + b->output += len; return len; } @@ -194,7 +191,7 @@ static inline void bi_putchr(struct buffer *b, char c) if (b_data(b) == b->size) return; *b_tail(b) = c; - b->i++; + b->len++; } /* Tries to append block at the end of buffer . Supports wrapping. @@ -215,10 +212,10 @@ static inline unsigned int bi_putblk(struct buffer *b, const char *blk, unsigned half = len; memcpy(b_tail(b), blk, half); - b->i += half; + b->len += half; if (len > half) { memcpy(b_tail(b), blk + half, len - half); - b->i += len - half; + b->len += len - half; } return len; } @@ -443,7 +440,7 @@ static inline int bi_istput(struct buffer *b, const struct ist ist) return r.len < b->size ? 0 : -1; p = b_tail(b); - b->i += r.len; + b->len += r.len; while (r.len--) { *p++ = *r.ptr++; if (unlikely(p == end)) @@ -472,8 +469,8 @@ static inline int bo_istput(struct buffer *b, const struct ist ist) return r.len < b->size ? 0 : -1; p = b_tail(b); - b->p = b_peek(b, b->o + r.len); - b->o += r.len; + b->len += r.len; + b->output += r.len; while (r.len--) { *p++ = *r.ptr++; if (unlikely(p == end)) diff --git a/include/proto/channel.h b/include/proto/channel.h index 8ca669578..291bb08f8 100644 --- a/include/proto/channel.h +++ b/include/proto/channel.h @@ -128,7 +128,7 @@ static inline size_t c_full(const struct channel *c) /* co_data() : returns the amount of output data in the channel's buffer */ static inline size_t co_data(const struct channel *c) { - return c->buf->o; + return c->buf->output; } /* ci_data() : returns the amount of input data in the channel's buffer */ @@ -170,11 +170,7 @@ static inline char *c_ptr(const struct channel *c, ssize_t ofs) */ static inline void c_adv(struct channel *c, size_t adv) { - struct buffer *b = c->buf; - - b->p = c_ptr(c, adv); - b->i -= adv; - b->o += adv; + c->buf->output += adv; } /* c_rew() : rewinds the channel's buffer by bytes, which means that the @@ -184,11 +180,7 @@ static inline void c_adv(struct channel *c, size_t adv) */ static inline void c_rew(struct channel *c, size_t adv) { - struct buffer *b = c->buf; - - b->p = c_ptr(c, (int)-adv); - b->i += adv; - b->o -= adv; + c->buf->output -= adv; } /* c_realign_if_empty() : realign the channel's buffer if it's empty */ @@ -200,7 +192,8 @@ static inline void c_realign_if_empty(struct channel *chn) /* Sets the amount of output for the channel */ static inline void co_set_data(struct channel *c, size_t output) { - c->buf->o = output; + c->buf->len += output - c->buf->output; + c->buf->output = output; } @@ -750,7 +743,7 @@ static inline void channel_truncate(struct channel *chn) if (!ci_data(chn)) return; - chn->buf->i = 0; + chn->buf->len = co_data(chn); } /* This function realigns a possibly wrapping channel buffer so that the input diff --git a/src/buffer.c b/src/buffer.c index a1ffec7a5..306f011d1 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -28,8 +28,8 @@ struct pool_head *pool_head_buffer; * what channel wants a buffer. They can reliably be exchanged, the split * between the two is only an optimization. */ -struct buffer buf_empty = { .p = buf_empty.data }; -struct buffer buf_wanted = { .p = buf_wanted.data }; +struct buffer buf_empty = { }; +struct buffer buf_wanted = { }; /* list of objects waiting for at least one buffer */ struct list buffer_wq = LIST_HEAD_INIT(buffer_wq); diff --git a/src/flt_http_comp.c b/src/flt_http_comp.c index 4972088c0..f8c82c4b7 100644 --- a/src/flt_http_comp.c +++ b/src/flt_http_comp.c @@ -38,6 +38,7 @@ static struct pool_head *pool_head_comp_state = NULL; static THREAD_LOCAL struct buffer *tmpbuf = &buf_empty; static THREAD_LOCAL struct buffer *zbuf = &buf_empty; +static THREAD_LOCAL unsigned int buf_output; struct comp_state { struct comp_ctx *comp_ctx; /* compression context */ @@ -56,13 +57,14 @@ static int select_compression_response_header(struct comp_state *st, struct stream *s, struct http_msg *msg); -static int http_compression_buffer_init(struct channel *inc, struct buffer *out); +static int http_compression_buffer_init(struct channel *inc, struct buffer *out, unsigned int *out_len); static int http_compression_buffer_add_data(struct comp_state *st, struct buffer *in, + int in_out, struct buffer *out, int sz); static int http_compression_buffer_end(struct comp_state *st, struct stream *s, struct channel *chn, struct buffer **out, - int end); + unsigned int *out_len, int end); /***********************************************************************/ static int @@ -191,7 +193,7 @@ comp_http_data(struct stream *s, struct filter *filter, struct http_msg *msg) b_reset(tmpbuf); c_adv(chn, fwd); - ret = http_compression_buffer_init(chn, zbuf); + ret = http_compression_buffer_init(chn, zbuf, &buf_output); c_rew(chn, fwd); if (ret < 0) { msg->chn->flags |= CF_WAKE_WRITE; @@ -216,7 +218,7 @@ comp_http_data(struct stream *s, struct filter *filter, struct http_msg *msg) } else { c_adv(chn, *nxt); - ret = http_compression_buffer_add_data(st, chn->buf, zbuf, len); + ret = http_compression_buffer_add_data(st, chn->buf, co_data(chn), zbuf, len); c_rew(chn, *nxt); if (ret < 0) return ret; @@ -242,7 +244,7 @@ comp_http_chunk_trailers(struct stream *s, struct filter *filter, b_reset(tmpbuf); c_adv(chn, fwd); - http_compression_buffer_init(chn, zbuf); + http_compression_buffer_init(chn, zbuf, &buf_output); c_rew(chn, fwd); st->initialized = 1; } @@ -296,17 +298,18 @@ comp_http_forward_data(struct stream *s, struct filter *filter, } if (msg->flags & HTTP_MSGF_TE_CHNK) { - ret = http_compression_buffer_add_data(st, tmpbuf, zbuf, tmpbuf->i); - if (ret != tmpbuf->i) { + ret = http_compression_buffer_add_data(st, tmpbuf, 0, + zbuf, b_data(tmpbuf)); + if (ret != b_data(tmpbuf)) { ha_warning("HTTP compression failed: Must consume %u bytes but only %d bytes consumed\n", - (unsigned int)tmpbuf->i, ret); + (unsigned int)b_data(tmpbuf), ret); return -1; } } st->consumed = len - st->hdrs_len - st->tlrs_len; c_adv(msg->chn, flt_rsp_fwd(filter) + st->hdrs_len); - ret = http_compression_buffer_end(st, s, msg->chn, &zbuf, msg->msg_state >= HTTP_MSG_TRAILERS); + ret = http_compression_buffer_end(st, s, msg->chn, &zbuf, &buf_output, msg->msg_state >= HTTP_MSG_TRAILERS); c_rew(msg->chn, flt_rsp_fwd(filter) + st->hdrs_len); if (ret < 0) return ret; @@ -601,7 +604,7 @@ http_emit_chunk_size(char *end, unsigned int chksz) * Init HTTP compression */ static int -http_compression_buffer_init(struct channel *inc, struct buffer *out) +http_compression_buffer_init(struct channel *inc, struct buffer *out, unsigned int *out_len) { /* output stream requires at least 10 bytes for the gzip header, plus * at least 8 bytes for the gzip trailer (crc+len), plus a possible @@ -616,9 +619,8 @@ http_compression_buffer_init(struct channel *inc, struct buffer *out) * cancel the operation later, it's cheap. */ b_reset(out); - out->o = co_data(inc); - out->p += out->o; - out->i = 10; + *out_len = co_data(inc); + out->head += *out_len + 10; return 0; } @@ -627,7 +629,7 @@ http_compression_buffer_init(struct channel *inc, struct buffer *out) */ static int http_compression_buffer_add_data(struct comp_state *st, struct buffer *in, - struct buffer *out, int sz) + int in_out, struct buffer *out, int sz) { int consumed_data = 0; int data_process_len; @@ -643,15 +645,15 @@ http_compression_buffer_add_data(struct comp_state *st, struct buffer *in, data_process_len = MIN(b_room(out), sz); block1 = data_process_len; - if (block1 > b_contig_data(in, in->o)) - block1 = b_contig_data(in, in->o); + if (block1 > b_contig_data(in, in_out)) + block1 = b_contig_data(in, in_out); block2 = data_process_len - block1; /* compressors return < 0 upon error or the amount of bytes read */ - consumed_data = st->comp_algo->add_data(st->comp_ctx, b_peek(in, in->o), block1, out); + consumed_data = st->comp_algo->add_data(st->comp_ctx, b_head(in) + in_out, block1, out); if (consumed_data != block1 || !block2) goto end; - consumed_data = st->comp_algo->add_data(st->comp_ctx, in->data, block2, out); + consumed_data = st->comp_algo->add_data(st->comp_ctx, b_peek(in, 0), block2, out); if (consumed_data < 0) goto end; consumed_data += block1; @@ -667,11 +669,12 @@ http_compression_buffer_add_data(struct comp_state *st, struct buffer *in, static int http_compression_buffer_end(struct comp_state *st, struct stream *s, struct channel *chn, struct buffer **out, - int end) + unsigned int *buf_out, int end) { - struct buffer *ib = chn->buf, *ob = *out; + struct buffer *ob = *out; char *tail; int to_forward, left; + unsigned int tmp_out; #if defined(USE_SLZ) || defined(USE_ZLIB) int ret; @@ -701,35 +704,38 @@ http_compression_buffer_end(struct comp_state *st, struct stream *s, * +---------+---+------------+-----------+ * data p size * - * is the room reserved to copy ib->o. It starts at ob->data and - * has not yet been filled. is the room reserved to write the chunk - * size (10 bytes). is the compressed equivalent of the data - * part of ib->i. is the amount of empty bytes at the end of - * the buffer, into which we may have to copy the remaining bytes from - * ib->i after the data (chunk size, trailers, ...). + * is the room reserved to copy the channel output. It starts at + * ob->data and has not yet been filled. is the room reserved to + * write the chunk size (10 bytes). is the compressed + * equivalent of the data part of ib->len. is the amount of + * empty bytes at the end of the buffer, into which we may have to + * copy the remaining bytes from ib->len after the data + * (chunk size, trailers, ...). */ /* Write real size at the begining of the chunk, no need of wrapping. * We write the chunk using a dynamic length and adjust ob->p and ob->i * accordingly afterwards. That will move away from . */ - left = 10 - http_emit_chunk_size(ob->p + 10, ob->i - 10); - ob->p += left; - ob->i -= left; + left = http_emit_chunk_size(b_head(ob), b_data(ob)); + b_add(ob, left); + ob->head -= *buf_out + (left); + /* Copy previous data from chn into ob */ + if (co_data(chn) > 0) { + left = b_contig_data(chn->buf, 0); + if (left > *buf_out) + left = *buf_out; - /* Copy previous data from ib->o into ob->o */ - if (ib->o > 0) { - left = b_contig_data(ib, 0); - if (left > ib->o) - left = ib->o; - - memcpy(ob->p - ob->o, b_head(ib), left); - if (ib->o - left) /* second part of the buffer */ - memcpy(ob->p - ob->o + left, ib->data, ib->o - left); + memcpy(b_head(ob), co_head(chn), left); + b_add(ob, left); + if (co_data(chn) - left) {/* second part of the buffer */ + memcpy(b_head(ob) + left, b_orig(chn->buf), co_data(chn) - left); + b_add(ob, co_data(chn) - left); + } } /* chunked encoding requires CRLF after data */ - tail = ob->p + ob->i; + tail = b_tail(ob); *tail++ = '\r'; *tail++ = '\n'; @@ -751,8 +757,8 @@ http_compression_buffer_end(struct comp_state *st, struct stream *s, } } - ob->i = tail - ob->p; - to_forward = ob->i; + b_add(ob, tail - b_tail(ob)); + to_forward = b_data(ob) - *buf_out; /* update input rate */ if (st->comp_ctx && st->comp_ctx->cur_lvl > 0) { @@ -766,19 +772,22 @@ http_compression_buffer_end(struct comp_state *st, struct stream *s, /* copy the remaining data in the tmp buffer. */ c_adv(chn, st->consumed); - if (ib->i > 0) { + if (b_data(chn->buf) - co_data(chn) > 0) { left = ci_contig_data(chn); - memcpy(ob->p + ob->i, ci_head(chn), left); + memcpy(b_tail(ob), ci_head(chn), left); b_add(ob, left); - if (ib->i - left) { - memcpy(ob->p + ob->i, ib->data, ib->i - left); - b_add(ob, ib->i - left); + if (b_data(chn->buf) - (co_data(chn) + left)) { + memcpy(b_tail(ob), b_orig(chn->buf), b_data(chn->buf) - left); + b_add(ob, b_data(chn->buf) - left); } } - /* swap the buffers */ + *out = chn->buf; chn->buf = ob; - *out = ib; + tmp_out = chn->buf->output; + chn->buf->output = *buf_out; + *buf_out = tmp_out; + if (st->comp_ctx && st->comp_ctx->cur_lvl > 0) {