mirror of
https://github.com/haproxy/haproxy.git
synced 2026-02-03 20:39:41 -05:00
This patch adds the support of filters in HAProxy. The main idea is to have a
way to "easely" extend HAProxy by adding some "modules", called filters, that
will be able to change HAProxy behavior in a programmatic way.
To do so, many entry points has been added in code to let filters to hook up to
different steps of the processing. A filter must define a flt_ops sutrctures
(see include/types/filters.h for details). This structure contains all available
callbacks that a filter can define:
struct flt_ops {
/*
* Callbacks to manage the filter lifecycle
*/
int (*init) (struct proxy *p);
void (*deinit)(struct proxy *p);
int (*check) (struct proxy *p);
/*
* Stream callbacks
*/
void (*stream_start) (struct stream *s);
void (*stream_accept) (struct stream *s);
void (*session_establish)(struct stream *s);
void (*stream_stop) (struct stream *s);
/*
* HTTP callbacks
*/
int (*http_start) (struct stream *s, struct http_msg *msg);
int (*http_start_body) (struct stream *s, struct http_msg *msg);
int (*http_start_chunk) (struct stream *s, struct http_msg *msg);
int (*http_data) (struct stream *s, struct http_msg *msg);
int (*http_last_chunk) (struct stream *s, struct http_msg *msg);
int (*http_end_chunk) (struct stream *s, struct http_msg *msg);
int (*http_chunk_trailers)(struct stream *s, struct http_msg *msg);
int (*http_end_body) (struct stream *s, struct http_msg *msg);
void (*http_end) (struct stream *s, struct http_msg *msg);
void (*http_reset) (struct stream *s, struct http_msg *msg);
int (*http_pre_process) (struct stream *s, struct http_msg *msg);
int (*http_post_process) (struct stream *s, struct http_msg *msg);
void (*http_reply) (struct stream *s, short status,
const struct chunk *msg);
};
To declare and use a filter, in the configuration, the "filter" keyword must be
used in a listener/frontend section:
frontend test
...
filter <FILTER-NAME> [OPTIONS...]
The filter referenced by the <FILTER-NAME> must declare a configuration parser
on its own name to fill flt_ops and filter_conf field in the proxy's
structure. An exemple will be provided later to make it perfectly clear.
For now, filters cannot be used in backend section. But this is only a matter of
time. Documentation will also be added later. This is the first commit of a long
list about filters.
It is possible to have several filters on the same listener/frontend. These
filters are stored in an array of at most MAX_FILTERS elements (define in
include/types/filters.h). Again, this will be replaced later by a list of
filters.
The filter API has been highly refactored. Main changes are:
* Now, HA supports an infinite number of filters per proxy. To do so, filters
are stored in list.
* Because filters are stored in list, filters state has been moved from the
channel structure to the filter structure. This is cleaner because there is no
more info about filters in channel structure.
* It is possible to defined filters on backends only. For such filters,
stream_start/stream_stop callbacks are not called. Of course, it is possible
to mix frontend and backend filters.
* Now, TCP streams are also filtered. All callbacks without the 'http_' prefix
are called for all kind of streams. In addition, 2 new callbacks were added to
filter data exchanged through a TCP stream:
- tcp_data: it is called when new data are available or when old unprocessed
data are still waiting.
- tcp_forward_data: it is called when some data can be consumed.
* New callbacks attached to channel were added:
- channel_start_analyze: it is called when a filter is ready to process data
exchanged through a channel. 2 new analyzers (a frontend and a backend)
are attached to channels to call this callback. For a frontend filter, it
is called before any other analyzer. For a backend filter, it is called
when a backend is attached to a stream. So some processing cannot be
filtered in that case.
- channel_analyze: it is called before each analyzer attached to a channel,
expects analyzers responsible for data sending.
- channel_end_analyze: it is called when all other analyzers have finished
their processing. A new analyzers is attached to channels to call this
callback. For a TCP stream, this is always the last one called. For a HTTP
one, the callback is called when a request/response ends, so it is called
one time for each request/response.
* 'session_established' callback has been removed. Everything that is done in
this callback can be handled by 'channel_start_analyze' on the response
channel.
* 'http_pre_process' and 'http_post_process' callbacks have been replaced by
'channel_analyze'.
* 'http_start' callback has been replaced by 'http_headers'. This new one is
called just before headers sending and parsing of the body.
* 'http_end' callback has been replaced by 'channel_end_analyze'.
* It is possible to set a forwarder for TCP channels. It was already possible to
do it for HTTP ones.
* Forwarders can partially consumed forwardable data. For this reason a new
HTTP message state was added before HTTP_MSG_DONE : HTTP_MSG_ENDING.
Now all filters can define corresponding callbacks (http_forward_data
and tcp_forward_data). Each filter owns 2 offsets relative to buf->p, next and
forward, to track, respectively, input data already parsed but not forwarded yet
by the filter and parsed data considered as forwarded by the filter. A any time,
we have the warranty that a filter cannot parse or forward more input than
previous ones. And, of course, it cannot forward more input than it has
parsed. 2 macros has been added to retrieve these offets: FLT_NXT and FLT_FWD.
In addition, 2 functions has been added to change the 'next size' and the
'forward size' of a filter. When a filter parses input data, it can alter these
data, so the size of these data can vary. This action has an effet on all
previous filters that must be handled. To do so, the function
'filter_change_next_size' must be called, passing the size variation. In the
same spirit, if a filter alter forwarded data, it must call the function
'filter_change_forward_size'. 'filter_change_next_size' can be called in
'http_data' and 'tcp_data' callbacks and only these ones. And
'filter_change_forward_size' can be called in 'http_forward_data' and
'tcp_forward_data' callbacks and only these ones. The data changes are the
filter responsability, but with some limitation. It must not change already
parsed/forwarded data or data that previous filters have not parsed/forwarded
yet.
Because filters can be used on backends, when we the backend is set for a
stream, we add filters defined for this backend in the filter list of the
stream. But we must only do that when the backend and the frontend of the stream
are not the same. Else same filters are added a second time leading to undefined
behavior.
The HTTP compression code had to be moved.
So it simplifies http_response_forward_body function. To do so, the way the data
are forwarded has changed. Now, a filter (and only one) can forward data. In a
commit to come, this limitation will be removed to let all filters take part to
data forwarding. There are 2 new functions that filters should use to deal with
this feature:
* flt_set_http_data_forwarder: This function sets the filter (using its id)
that will forward data for the specified HTTP message. It is possible if it
was not already set by another filter _AND_ if no data was yet forwarded
(msg->msg_state <= HTTP_MSG_BODY). It returns -1 if an error occurs.
* flt_http_data_forwarder: This function returns the filter id that will
forward data for the specified HTTP message. If there is no forwarder set, it
returns -1.
When an HTTP data forwarder is set for the response, the HTTP compression is
disabled. Of course, this is not definitive.
178 lines
8.8 KiB
C
178 lines
8.8 KiB
C
/*
|
|
* include/types/stream.h
|
|
* This file defines everything related to streams.
|
|
*
|
|
* Copyright (C) 2000-2015 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
|
|
* License as published by the Free Software Foundation, version 2.1
|
|
* exclusively.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
#ifndef _TYPES_STREAM_H
|
|
#define _TYPES_STREAM_H
|
|
|
|
|
|
#include <sys/time.h>
|
|
#include <unistd.h>
|
|
#include <netinet/in.h>
|
|
#include <arpa/inet.h>
|
|
|
|
#include <common/config.h>
|
|
#include <common/mini-clist.h>
|
|
|
|
#include <types/channel.h>
|
|
#include <types/compression.h>
|
|
#include <types/filters.h>
|
|
#include <types/hlua.h>
|
|
#include <types/obj_type.h>
|
|
#include <types/proto_http.h>
|
|
#include <types/proxy.h>
|
|
#include <types/queue.h>
|
|
#include <types/server.h>
|
|
#include <types/session.h>
|
|
#include <types/stream_interface.h>
|
|
#include <types/task.h>
|
|
#include <types/stick_table.h>
|
|
#include <types/vars.h>
|
|
|
|
/* Various Stream Flags, bits values 0x01 to 0x100 (shift 0) */
|
|
#define SF_DIRECT 0x00000001 /* connection made on the server matching the client cookie */
|
|
#define SF_ASSIGNED 0x00000002 /* no need to assign a server to this stream */
|
|
#define SF_ADDR_SET 0x00000004 /* this stream's server address has been set */
|
|
#define SF_BE_ASSIGNED 0x00000008 /* a backend was assigned. Conns are accounted. */
|
|
|
|
#define SF_FORCE_PRST 0x00000010 /* force persistence here, even if server is down */
|
|
#define SF_MONITOR 0x00000020 /* this stream comes from a monitoring system */
|
|
#define SF_CURR_SESS 0x00000040 /* a connection is currently being counted on the server */
|
|
#define SF_INITIALIZED 0x00000080 /* the stream was fully initialized */
|
|
#define SF_REDISP 0x00000100 /* set if this stream was redispatched from one server to another */
|
|
#define SF_CONN_TAR 0x00000200 /* set if this stream is turning around before reconnecting */
|
|
#define SF_REDIRECTABLE 0x00000400 /* set if this stream is redirectable (GET or HEAD) */
|
|
#define SF_TUNNEL 0x00000800 /* tunnel-mode stream, nothing to catch after data */
|
|
|
|
/* stream termination conditions, bits values 0x1000 to 0x7000 (0-9 shift 12) */
|
|
#define SF_ERR_NONE 0x00000000 /* normal end of request */
|
|
#define SF_ERR_LOCAL 0x00001000 /* the proxy locally processed this request => not an error */
|
|
#define SF_ERR_CLITO 0x00002000 /* client time-out */
|
|
#define SF_ERR_CLICL 0x00003000 /* client closed (read/write error) */
|
|
#define SF_ERR_SRVTO 0x00004000 /* server time-out, connect time-out */
|
|
#define SF_ERR_SRVCL 0x00005000 /* server closed (connect/read/write error) */
|
|
#define SF_ERR_PRXCOND 0x00006000 /* the proxy decided to close (deny...) */
|
|
#define SF_ERR_RESOURCE 0x00007000 /* the proxy encountered a lack of a local resources (fd, mem, ...) */
|
|
#define SF_ERR_INTERNAL 0x00008000 /* the proxy encountered an internal error */
|
|
#define SF_ERR_DOWN 0x00009000 /* the proxy killed a stream because the backend became unavailable */
|
|
#define SF_ERR_KILLED 0x0000a000 /* the proxy killed a stream because it was asked to do so */
|
|
#define SF_ERR_UP 0x0000b000 /* the proxy killed a stream because a preferred backend became available */
|
|
#define SF_ERR_MASK 0x0000f000 /* mask to get only stream error flags */
|
|
#define SF_ERR_SHIFT 12 /* bit shift */
|
|
|
|
/* stream state at termination, bits values 0x10000 to 0x70000 (0-7 shift 16) */
|
|
#define SF_FINST_R 0x00010000 /* stream ended during client request */
|
|
#define SF_FINST_C 0x00020000 /* stream ended during server connect */
|
|
#define SF_FINST_H 0x00030000 /* stream ended during server headers */
|
|
#define SF_FINST_D 0x00040000 /* stream ended during data phase */
|
|
#define SF_FINST_L 0x00050000 /* stream ended while pushing last data to client */
|
|
#define SF_FINST_Q 0x00060000 /* stream ended while waiting in queue for a server slot */
|
|
#define SF_FINST_T 0x00070000 /* stream ended tarpitted */
|
|
#define SF_FINST_MASK 0x00070000 /* mask to get only final stream state flags */
|
|
#define SF_FINST_SHIFT 16 /* bit shift */
|
|
|
|
#define SF_IGNORE_PRST 0x00080000 /* ignore persistence */
|
|
|
|
#define SF_COMP_READY 0x00100000 /* the compression is initialized */
|
|
#define SF_SRV_REUSED 0x00200000 /* the server-side connection was reused */
|
|
|
|
/* some external definitions */
|
|
struct strm_logs {
|
|
int logwait; /* log fields waiting to be collected : LW_* */
|
|
int level; /* log level to force + 1 if > 0, -1 = no log */
|
|
struct timeval accept_date; /* date of the stream's accept() in user date */
|
|
struct timeval tv_accept; /* date of the stream's accept() in internal date (monotonic) */
|
|
struct timeval tv_request; /* date the request arrives, {0,0} if never occurs */
|
|
long t_queue; /* delay before the stream gets out of the connect queue, -1 if never occurs */
|
|
long t_connect; /* delay before the connect() to the server succeeds, -1 if never occurs */
|
|
long t_data; /* delay before the first data byte from the server ... */
|
|
unsigned long t_close; /* total stream duration */
|
|
unsigned long srv_queue_size; /* number of streams waiting for a connect slot on this server at accept() time (in direct assignment) */
|
|
unsigned long prx_queue_size; /* overall number of streams waiting for a connect slot on this instance at accept() time */
|
|
long long bytes_in; /* number of bytes transferred from the client to the server */
|
|
long long bytes_out; /* number of bytes transferred from the server to the client */
|
|
};
|
|
|
|
struct stream {
|
|
int flags; /* some flags describing the stream */
|
|
unsigned int uniq_id; /* unique ID used for the traces */
|
|
enum obj_type *target; /* target to use for this stream */
|
|
|
|
struct channel req; /* request channel */
|
|
struct channel res; /* response channel */
|
|
|
|
struct proxy *be; /* the proxy this stream depends on for the server side */
|
|
|
|
struct session *sess; /* the session this stream is attached to */
|
|
|
|
struct server *srv_conn; /* stream already has a slot on a server and is not in queue */
|
|
struct pendconn *pend_pos; /* if not NULL, points to the position in the pending queue */
|
|
|
|
struct http_txn *txn; /* current HTTP transaction being processed. Should become a list. */
|
|
|
|
struct {
|
|
struct list filters;
|
|
struct filter *current[2]; /* 0: request, 1: response */
|
|
} strm_flt;
|
|
|
|
struct task *task; /* the task associated with this stream */
|
|
struct list list; /* position in global streams list */
|
|
struct list by_srv; /* position in server stream list */
|
|
struct list back_refs; /* list of users tracking this stream */
|
|
struct list buffer_wait; /* position in the list of streams waiting for a buffer */
|
|
|
|
struct {
|
|
struct stksess *ts;
|
|
struct stktable *table;
|
|
} store[8]; /* tracked stickiness values to store */
|
|
int store_count;
|
|
/* 4 unused bytes here */
|
|
|
|
struct stkctr stkctr[MAX_SESS_STKCTR]; /* content-aware stick counters */
|
|
|
|
char **req_cap; /* array of captures from the request (may be NULL) */
|
|
char **res_cap; /* array of captures from the response (may be NULL) */
|
|
struct vars vars_txn; /* list of variables for the txn scope. */
|
|
struct vars vars_reqres; /* list of variables for the request and resp scope. */
|
|
|
|
struct stream_interface si[2]; /* client and server stream interfaces */
|
|
struct strm_logs logs; /* logs for this stream */
|
|
|
|
void (*do_log)(struct stream *s); /* the function to call in order to log (or NULL) */
|
|
void (*srv_error)(struct stream *s, /* the function to call upon unrecoverable server errors (or NULL) */
|
|
struct stream_interface *si);
|
|
struct comp_ctx *comp_ctx; /* HTTP compression context */
|
|
struct comp_algo *comp_algo; /* HTTP compression algorithm if not NULL */
|
|
char *unique_id; /* custom unique ID */
|
|
|
|
/* These two pointers are used to resume the execution of the rule lists. */
|
|
struct list *current_rule_list; /* this is used to store the current executed rule list. */
|
|
void *current_rule; /* this is used to store the current rule to be resumed. */
|
|
struct hlua hlua; /* lua runtime context */
|
|
};
|
|
|
|
#endif /* _TYPES_STREAM_H */
|
|
|
|
/*
|
|
* Local variables:
|
|
* c-indent-level: 8
|
|
* c-basic-offset: 8
|
|
* End:
|
|
*/
|