mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2025-04-07 01:31:35 +00:00
[MEDIUM] add support for infinite forwarding
In TCP, we don't want to forward chunks of data, we want to forward indefinitely. This patch introduces a special value for the amount of data to be forwarded. When buffer_forward() is called with BUF_INFINITE_FORWARD, it configures the buffer to never stop forwarding until the end.
This commit is contained in:
parent
59454bfaa4
commit
31971e536a
@ -2,7 +2,7 @@
|
||||
include/common/defaults.h
|
||||
Miscellaneous default values.
|
||||
|
||||
Copyright (C) 2000-2008 Willy Tarreau - w@1wt.eu
|
||||
Copyright (C) 2000-2009 Willy Tarreau - w@1wt.eu
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
@ -40,16 +40,6 @@
|
||||
#define MAXREWRITE (BUFSIZE / 2)
|
||||
#endif
|
||||
|
||||
/* FORWARD_DEFAULT_SIZE
|
||||
* Indicates how many bytes may be forwarded at once in low-level stream-socks
|
||||
* without waking the owner task up. This should be much larger than the buffer
|
||||
* size. A few megabytes seem appropriate.
|
||||
*/
|
||||
#ifndef FORWARD_DEFAULT_SIZE
|
||||
#define FORWARD_DEFAULT_SIZE (16*1024*1024)
|
||||
#endif
|
||||
|
||||
|
||||
#define REQURI_LEN 1024
|
||||
#define CAPTURE_LEN 64
|
||||
|
||||
|
@ -85,9 +85,9 @@ static inline void buffer_check_timeouts(struct buffer *b)
|
||||
* cause lockups when send_max goes down to zero if nobody is ready to push the
|
||||
* remaining data.
|
||||
*/
|
||||
static inline void buffer_forward(struct buffer *buf, unsigned int bytes)
|
||||
static inline void buffer_forward(struct buffer *buf, unsigned long bytes)
|
||||
{
|
||||
unsigned int data_left;
|
||||
unsigned long data_left;
|
||||
|
||||
if (!bytes)
|
||||
return;
|
||||
@ -98,8 +98,13 @@ static inline void buffer_forward(struct buffer *buf, unsigned int bytes)
|
||||
return;
|
||||
}
|
||||
|
||||
buf->to_forward += bytes - data_left;
|
||||
buf->send_max += data_left;
|
||||
if (buf->to_forward == BUF_INFINITE_FORWARD)
|
||||
return;
|
||||
|
||||
buf->to_forward += bytes - data_left;
|
||||
if (bytes == BUF_INFINITE_FORWARD)
|
||||
buf->to_forward = bytes;
|
||||
}
|
||||
|
||||
/* Schedule all remaining buffer data to be sent. send_max is not touched if it
|
||||
@ -380,8 +385,9 @@ static inline int buffer_si_putchar(struct buffer *buf, char c)
|
||||
if (buf->r - buf->data == buf->size)
|
||||
buf->r -= buf->size;
|
||||
|
||||
if ((signed)(buf->to_forward - 1) >= 0) {
|
||||
buf->to_forward--;
|
||||
if (buf->to_forward >= 1) {
|
||||
if (buf->to_forward != BUF_INFINITE_FORWARD)
|
||||
buf->to_forward--;
|
||||
buf->send_max++;
|
||||
buf->flags &= ~BF_OUT_EMPTY;
|
||||
}
|
||||
|
@ -143,6 +143,9 @@
|
||||
#define AN_RTR_HTTP_HDR 0x00000200 /* inspect HTTP response headers */
|
||||
#define AN_REQ_PRST_RDP_COOKIE 0x00000400 /* persistence on rdp cookie */
|
||||
|
||||
/* Magic value to forward infinite size (TCP, ...), used with ->to_forward */
|
||||
#define BUF_INFINITE_FORWARD (~0UL)
|
||||
|
||||
/* describes a chunk of string */
|
||||
struct chunk {
|
||||
char *str; /* beginning of the string itself. Might not be 0-terminated */
|
||||
@ -164,7 +167,7 @@ struct buffer {
|
||||
unsigned int size; /* buffer size in bytes */
|
||||
unsigned int max_len; /* read limit, used to keep room for header rewriting */
|
||||
unsigned int send_max; /* number of bytes the sender can consume om this buffer, <= l */
|
||||
unsigned int to_forward; /* number of bytes to forward after send_max without a wake-up */
|
||||
unsigned long to_forward; /* number of bytes to forward after send_max without a wake-up */
|
||||
unsigned int analysers; /* bit field indicating what to do on the buffer */
|
||||
int analyse_exp; /* expiration date for current analysers (if set) */
|
||||
void (*hijacker)(struct session *, struct buffer *); /* alternative content producer */
|
||||
@ -205,7 +208,8 @@ struct buffer {
|
||||
|
||||
The producer is responsible for decreasing ->to_forward and increasing
|
||||
->send_max. The ->to_forward parameter indicates how many bytes may be fed
|
||||
into either data buffer without waking the parent up. The ->send_max
|
||||
into either data buffer without waking the parent up. The special value
|
||||
BUF_INFINITE_FORWARD is never decreased nor increased. The ->send_max
|
||||
parameter says how many bytes may be read from the visible buffer. Thus it
|
||||
may never exceed ->l. This parameter is updated by any buffer_write() as
|
||||
well as any data forwarded through the visible buffer.
|
||||
|
@ -101,10 +101,14 @@ int buffer_feed(struct buffer *buf, const char *str, int len)
|
||||
buf->l += len;
|
||||
buf->r += len;
|
||||
buf->total += len;
|
||||
if (buf->to_forward > 0) {
|
||||
int fwd = MIN(buf->to_forward, len);
|
||||
buf->send_max += fwd;
|
||||
buf->to_forward -= fwd;
|
||||
if (buf->to_forward) {
|
||||
unsigned long fwd = len;
|
||||
if (buf->to_forward != BUF_INFINITE_FORWARD) {
|
||||
if (fwd > buf->to_forward)
|
||||
fwd = buf->to_forward;
|
||||
buf->to_forward -= fwd;
|
||||
}
|
||||
buf->send_max += fwd;
|
||||
buf->flags &= ~BF_OUT_EMPTY;
|
||||
}
|
||||
|
||||
|
@ -941,12 +941,12 @@ resync_stream_interface:
|
||||
|
||||
|
||||
/* If noone is interested in analysing data, it's time to forward
|
||||
* everything. We will wake up from time to time when either send_max
|
||||
* or to_forward are reached.
|
||||
* everything. We configure the buffer to forward indefinitely.
|
||||
*/
|
||||
if (!s->req->analysers &&
|
||||
!(s->req->flags & (BF_HIJACK|BF_SHUTW)) &&
|
||||
(s->req->prod->state >= SI_ST_EST)) {
|
||||
(s->req->prod->state >= SI_ST_EST) &&
|
||||
(s->req->to_forward != BUF_INFINITE_FORWARD)) {
|
||||
/* This buffer is freewheeling, there's no analyser nor hijacker
|
||||
* attached to it. If any data are left in, we'll permit them to
|
||||
* move.
|
||||
@ -955,13 +955,12 @@ resync_stream_interface:
|
||||
buffer_auto_close(s->req);
|
||||
buffer_flush(s->req);
|
||||
|
||||
/* If the producer is still connected, we'll schedule large blocks
|
||||
* of data to be forwarded from the producer to the consumer (which
|
||||
* might possibly not be connected yet).
|
||||
/* If the producer is still connected, we'll enable data to flow
|
||||
* from the producer to the consumer (which might possibly not be
|
||||
* connected yet).
|
||||
*/
|
||||
if (!(s->req->flags & (BF_SHUTR|BF_SHUTW|BF_SHUTW_NOW)) &&
|
||||
s->req->to_forward < FORWARD_DEFAULT_SIZE)
|
||||
buffer_forward(s->req, FORWARD_DEFAULT_SIZE);
|
||||
if (!(s->req->flags & (BF_SHUTR|BF_SHUTW|BF_SHUTW_NOW)))
|
||||
buffer_forward(s->req, BUF_INFINITE_FORWARD);
|
||||
}
|
||||
|
||||
/* check if it is wise to enable kernel splicing to forward request data */
|
||||
@ -1063,26 +1062,20 @@ resync_stream_interface:
|
||||
/* perform output updates to the response buffer */
|
||||
|
||||
/* If noone is interested in analysing data, it's time to forward
|
||||
* everything. We will wake up from time to time when either send_max
|
||||
* or to_forward are reached.
|
||||
* everything. We configure the buffer to forward indefinitely.
|
||||
*/
|
||||
if (!s->rep->analysers &&
|
||||
!(s->rep->flags & (BF_HIJACK|BF_SHUTW)) &&
|
||||
(s->rep->prod->state >= SI_ST_EST)) {
|
||||
(s->rep->prod->state >= SI_ST_EST) &&
|
||||
(s->rep->to_forward != BUF_INFINITE_FORWARD)) {
|
||||
/* This buffer is freewheeling, there's no analyser nor hijacker
|
||||
* attached to it. If any data are left in, we'll permit them to
|
||||
* move.
|
||||
*/
|
||||
buffer_auto_close(s->rep);
|
||||
buffer_flush(s->rep);
|
||||
|
||||
/* If the producer is still connected, we'll schedule large blocks
|
||||
* of data to be forwarded from the producer to the consumer (which
|
||||
* might possibly not be connected yet).
|
||||
*/
|
||||
if (!(s->rep->flags & (BF_SHUTR|BF_SHUTW|BF_SHUTW_NOW)) &&
|
||||
s->rep->to_forward < FORWARD_DEFAULT_SIZE)
|
||||
buffer_forward(s->rep, FORWARD_DEFAULT_SIZE);
|
||||
if (!(s->rep->flags & (BF_SHUTR|BF_SHUTW|BF_SHUTW_NOW)))
|
||||
buffer_forward(s->rep, BUF_INFINITE_FORWARD);
|
||||
}
|
||||
|
||||
/* check if it is wise to enable kernel splicing to forward response data */
|
||||
|
@ -105,7 +105,8 @@ _syscall6(int, splice, int, fdin, loff_t *, off_in, int, fdout, loff_t *, off_ou
|
||||
static int stream_sock_splice_in(struct buffer *b, struct stream_interface *si)
|
||||
{
|
||||
int fd = si->fd;
|
||||
int ret, max, total = 0;
|
||||
int ret;
|
||||
unsigned long max;
|
||||
int retval = 1;
|
||||
|
||||
if (!b->to_forward)
|
||||
@ -138,7 +139,7 @@ static int stream_sock_splice_in(struct buffer *b, struct stream_interface *si)
|
||||
|
||||
while (1) {
|
||||
max = b->to_forward;
|
||||
if (max <= 0) {
|
||||
if (!max) {
|
||||
/* It looks like the buffer + the pipe already contain
|
||||
* the maximum amount of data to be transferred. Try to
|
||||
* send those data immediately on the other side if it
|
||||
@ -202,8 +203,8 @@ static int stream_sock_splice_in(struct buffer *b, struct stream_interface *si)
|
||||
break;
|
||||
} /* ret <= 0 */
|
||||
|
||||
b->to_forward -= ret;
|
||||
total += ret;
|
||||
if (b->to_forward != BUF_INFINITE_FORWARD)
|
||||
b->to_forward -= ret;
|
||||
b->total += ret;
|
||||
b->pipe->data += ret;
|
||||
b->flags |= BF_READ_PARTIAL;
|
||||
@ -332,10 +333,14 @@ int stream_sock_read(int fd) {
|
||||
cur_read += ret;
|
||||
|
||||
/* if we're allowed to directly forward data, we must update send_max */
|
||||
if (b->to_forward > 0 && !(b->flags & (BF_SHUTW|BF_SHUTW_NOW))) {
|
||||
int fwd = MIN(b->to_forward, ret);
|
||||
b->send_max += fwd;
|
||||
b->to_forward -= fwd;
|
||||
if (b->to_forward && !(b->flags & (BF_SHUTW|BF_SHUTW_NOW))) {
|
||||
unsigned long fwd = ret;
|
||||
if (b->to_forward != BUF_INFINITE_FORWARD) {
|
||||
if (fwd > b->to_forward)
|
||||
fwd = b->to_forward;
|
||||
b->to_forward -= fwd;
|
||||
}
|
||||
b->send_max += fwd;
|
||||
b->flags &= ~BF_OUT_EMPTY;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user