blob: 75c640ce7e1466aa210c47ad35f40222cfb2cfd2 [file] [log] [blame]
Christopher Fauletc3fe5332016-04-07 15:30:10 +02001 -----------------------------------------
Willy Tarreau7b677262017-04-03 09:27:49 +02002 Filters Guide - version 1.8
Christopher Faulet71a6a8e2017-07-27 16:33:28 +02003 ( Last update: 2017-07-27 )
Christopher Fauletc3fe5332016-04-07 15:30:10 +02004 ------------------------------------------
5 Author : Christopher Faulet
6 Contact : christopher dot faulet at capflam dot org
7
8
9ABSTRACT
10--------
11
12The filters support is a new feature of HAProxy 1.7. It is a way to extend
13HAProxy without touching its core code and, in certain extent, without knowing
14its internals. This feature will ease contributions, reducing impact of
15changes. Another advantage will be to simplify HAProxy by replacing some parts
16by filters. As we will see, and as an example, the HTTP compression is the first
17feature moved in a filter.
18
19This document describes how to write a filter and what you have to keep in mind
20to do so. It also talks about the known limits and the pitfalls to avoid.
21
22As said, filters are quite new for now. The API is not freezed and will be
23updated/modified/improved/extended as needed.
24
25
26
27SUMMARY
28-------
29
30 1. Filters introduction
31 2. How to use filters
32 3. How to write a new filter
33 3.1. API Overview
34 3.2. Defining the filter name and its configuration
35 3.3. Managing the filter lifecycle
Christopher Faulet71a6a8e2017-07-27 16:33:28 +020036 3.3.1. Dealing with threads
Christopher Faulet9adb0a52016-06-21 11:50:49 +020037 3.4. Handling the streams activity
Christopher Fauletc3fe5332016-04-07 15:30:10 +020038 3.5. Analyzing the channels activity
39 3.6. Filtering the data exchanged
40 4. FAQ
41
42
43
441. FILTERS INTRODUCTION
45-----------------------
46
47First of all, to fully understand how filters work and how to create one, it is
48best to know, at least from a distance, what is a proxy (frontend/backend), a
49stream and a channel in HAProxy and how these entities are linked to each other.
50doc/internals/entities.pdf is a good overview.
51
52Then, to support filters, many callbacks has been added to HAProxy at different
53places, mainly around channel analyzers. Their purpose is to allow filters to
54be involved in the data processing, from the stream creation/destruction to
55the data forwarding. Depending of what it should do, a filter can implement all
56or part of these callbacks. For now, existing callbacks are focused on
57streams. But futur improvements could enlarge filters scope. For example, it
58could be useful to handle events at the connection level.
59
60In HAProxy configuration file, a filter is declared in a proxy section, except
61default. So the configuration corresponding to a filter declaration is attached
62to a specific proxy, and will be shared by all its instances. it is opaque from
63the HAProxy point of view, this is the filter responsibility to manage it. For
64each filter declaration matches a uniq configuration. Several declarations of
65the same filter in the same proxy will be handle as different filters by
66HAProxy.
67
68A filter instance is represented by a partially opaque context (or a state)
69attached to a stream and passed as arguments to callbacks. Through this context,
70filter instances are stateful. Depending the filter is declared in a frontend or
71a backend section, its instances will be created, respectively, when a stream is
72created or when a backend is selected. Their behaviors will also be
73different. Only instances of filters declared in a frontend section will be
74aware of the creation and the destruction of the stream, and will take part in
75the channels analyzing before the backend is defined.
76
77It is important to remember the configuration of a filter is shared by all its
78instances, while the context of an instance is owned by a uniq stream.
79
80Filters are designed to be chained. It is possible to declare several filters in
81the same proxy section. The declaration order is important because filters will
82be called one after the other respecting this order. Frontend and backend
83filters are also chained, frontend ones called first. Even if the filters
84processing is serialized, each filter will bahave as it was alone (unless it was
85developed to be aware of other filters). For all that, some constraints are
86imposed to filters, especially when data exchanged between the client and the
87server are processed. We will dicuss again these contraints when we will tackle
88the subject of writing a filter.
89
90
91
922. HOW TO USE FILTERS
93---------------------
94
95To use a filter, you must use the parameter 'filter' followed by the filter name
96and, optionnaly, its configuration in the desired listen, frontend or backend
97section. For example:
98
99 listen test
100 ...
101 filter trace name TST
102 ...
103
104
105See doc/configuration.txt for a formal definition of the parameter 'filter'.
106Note that additional parameters on the filter line must be parsed by the filter
107itself.
108
109The list of available filters is reported by 'haproxy -vv':
110
111 $> haproxy -vv
112 HA-Proxy version 1.7-dev2-3a1d4a-33 2016/03/21
113 Copyright 2000-2016 Willy Tarreau <willy@haproxy.org>
114
115 [...]
116
117 Available filters :
118 [COMP] compression
119 [TRACE] trace
120
121
122Multiple filter lines can be used in a proxy section to chain filters. Filters
123will be called in the declaration order.
124
125Some filters can support implicit declarartions in certain circumstances
126(without the filter line). This is not recommanded for new features but are
127useful for existing ones moved in a filter, for backward compatibility
128reasons. Implicit declarartions are supported when there is only one filter used
129on a proxy. When several filters are used, explicit declarartions are mandatory.
130The HTTP compression filter is one of these filters. Alone, using 'compression'
131keywords is enough to use it. But when at least a second filter is used, a
132filter line must be added.
133
134 # filter line is optionnal
135 listen t1
136 bind *:80
137 compression algo gzip
138 compression offload
139 server srv x.x.x.x:80
140
141 # filter line is mandatory for the compression filter
142 listen t2
143 bind *:81
144 filter trace name T2
145 filter compression
146 compression algo gzip
147 compression offload
148 server srv x.x.x.x:80
149
150
151
152
1533. HOW TO WRITE A NEW FILTER
154----------------------------
155
156If you want to write a filter, there are 2 header files that you must know:
157
158 * include/types/filters.h: This is the main header file, containing all
159 important structures you will use. It represents
160 the filter API.
161 * include/proto/filters.h: This header file contains helper functions that
162 you may need to use. It also contains the internal
163 API used by HAProxy to handle filters.
164
165To ease the filters integration, it is better to follow some conventions:
166
167 * Use 'flt_' prefix to name your filter (e.g: flt_http_comp or flt_trace).
168 * Keep everything related to your filter in a same file.
169
170The filter 'trace' can be used as a template to write your own filter. It is a
171good start to see how filters really work.
172
1733.1 API OVERVIEW
174----------------
175
176Writing a filter can be summarized to write functions and attach them to the
177existing callbacks. Available callbacks are listed in the following structure:
178
179 struct flt_ops {
180 /*
181 * Callbacks to manage the filter lifecycle
182 */
Christopher Faulet71a6a8e2017-07-27 16:33:28 +0200183 int (*init) (struct proxy *p, struct flt_conf *fconf);
184 void (*deinit) (struct proxy *p, struct flt_conf *fconf);
185 int (*check) (struct proxy *p, struct flt_conf *fconf);
186 int (*init_per_thread) (struct proxy *p, struct flt_conf *fconf);
187 void (*deinit_per_thread)(struct proxy *p, struct flt_conf *fconf);
Christopher Fauletc3fe5332016-04-07 15:30:10 +0200188
189 /*
190 * Stream callbacks
191 */
Christopher Faulet9adb0a52016-06-21 11:50:49 +0200192 int (*attach) (struct stream *s, struct filter *f);
193 int (*stream_start) (struct stream *s, struct filter *f);
194 int (*stream_set_backend)(struct stream *s, struct filter *f, struct proxy *be);
195 void (*stream_stop) (struct stream *s, struct filter *f);
196 void (*detach) (struct stream *s, struct filter *f);
Christopher Fauleta00d8172016-11-10 14:58:05 +0100197 void (*check_timeouts) (struct stream *s, struct filter *f);
Christopher Fauletc3fe5332016-04-07 15:30:10 +0200198
199 /*
200 * Channel callbacks
201 */
202 int (*channel_start_analyze)(struct stream *s, struct filter *f,
Christopher Fauletf34b28a2016-05-11 17:29:14 +0200203 struct channel *chn);
204 int (*channel_pre_analyze) (struct stream *s, struct filter *f,
205 struct channel *chn,
206 unsigned int an_bit);
207 int (*channel_post_analyze) (struct stream *s, struct filter *f,
Christopher Fauletc3fe5332016-04-07 15:30:10 +0200208 struct channel *chn,
209 unsigned int an_bit);
210 int (*channel_end_analyze) (struct stream *s, struct filter *f,
211 struct channel *chn);
212
213 /*
214 * HTTP callbacks
215 */
Christopher Fauletf34b28a2016-05-11 17:29:14 +0200216 int (*http_headers) (struct stream *s, struct filter *f,
217 struct http_msg *msg);
Christopher Fauletc3fe5332016-04-07 15:30:10 +0200218 int (*http_data) (struct stream *s, struct filter *f,
219 struct http_msg *msg);
220 int (*http_chunk_trailers)(struct stream *s, struct filter *f,
221 struct http_msg *msg);
222 int (*http_end) (struct stream *s, struct filter *f,
223 struct http_msg *msg);
224 int (*http_forward_data) (struct stream *s, struct filter *f,
225 struct http_msg *msg,
226 unsigned int len);
227
228 void (*http_reset) (struct stream *s, struct filter *f,
229 struct http_msg *msg);
230 void (*http_reply) (struct stream *s, struct filter *f,
231 short status,
232 const struct chunk *msg);
233
234 /*
235 * TCP callbacks
236 */
237 int (*tcp_data) (struct stream *s, struct filter *f,
238 struct channel *chn);
239 int (*tcp_forward_data)(struct stream *s, struct filter *f,
240 struct channel *chn,
241 unsigned int len);
242 };
243
244
245We will explain in following parts when these callbacks are called and what they
246should do.
247
248Filters are declared in proxy sections. So each proxy have an ordered list of
249filters, possibly empty if no filter is used. When the configuration of a proxy
250is parsed, each filter line represents an entry in this list. In the structure
251'proxy', the filters configurations are stored in the field 'filter_configs',
252each one of type 'struct flt_conf *':
253
254 /*
255 * Structure representing the filter configuration, attached to a proxy and
256 * accessible from a filter when instantiated in a stream
257 */
258 struct flt_conf {
259 const char *id; /* The filter id */
260 struct flt_ops *ops; /* The filter callbacks */
261 void *conf; /* The filter configuration */
262 struct list list; /* Next filter for the same proxy */
263 };
264
265 * 'flt_conf.id' is an identifier, defined by the filter. It can be
266 NULL. HAProxy does not use this field. Filters can use it in log messages or
267 as a uniq identifier to check multiple declarations. It is the filter
268 responsibility to free it, if necessary.
269
270 * 'flt_conf.conf' is opaque. It is the internal configuration of a filter,
271 generally allocated and filled by its parsing function (See § 3.2). It is
272 the filter responsibility to free it.
273
274 * 'flt_conf.ops' references the callbacks implemented by the filter. This
275 field must be set during the parsing phase (See § 3.2) and can be refine
276 during the initialization phase (See § 3.3). If it is dynamically allocated,
277 it is the filter responsibility to free it.
278
279
280The filter configuration is global and shared by all its instances. A filter
281instance is created in the context of a stream and attached to this stream. in
282the structure 'stream', the field 'strm_flt' is the state of all filter
283instances attached to a stream:
284
285 /*
286 * Structure reprensenting the "global" state of filters attached to a
287 * stream.
288 */
289 struct strm_flt {
290 struct list filters; /* List of filters attached to a stream */
291 struct filter *current[2]; /* From which filter resume processing, for a specific channel.
292 * This is used for resumable callbacks only,
293 * If NULL, we start from the first filter.
294 * 0: request channel, 1: response channel */
295 unsigned short flags; /* STRM_FL_* */
296 unsigned char nb_req_data_filters; /* Number of data filters registerd on the request channel */
297 unsigned char nb_rsp_data_filters; /* Number of data filters registerd on the response channel */
298 };
299
300
301Filter instances attached to a stream are stored in the field
302'strm_flt.filters', each instance is of type 'struct filter *':
303
304 /*
305 * Structure reprensenting a filter instance attached to a stream
306 *
307 * 2D-Array fields are used to store info per channel. The first index
308 * stands for the request channel, and the second one for the response
309 * channel. Especially, <next> and <fwd> are offets representing amount of
310 * data that the filter are, respectively, parsed and forwarded on a
311 * channel. Filters can access these values using FLT_NXT and FLT_FWD
312 * macros.
313 */
314 struct filter {
315 struct flt_conf *config; /* the filter's configuration */
316 void *ctx; /* The filter context (opaque) */
317 unsigned short flags; /* FLT_FL_* */
318 unsigned int next[2]; /* Offset, relative to buf->p, to the next
319 * byte to parse for a specific channel
320 * 0: request channel, 1: response channel */
321 unsigned int fwd[2]; /* Offset, relative to buf->p, to the next
322 * byte to forward for a specific channel
323 * 0: request channel, 1: response channel */
Christopher Fauletf34b28a2016-05-11 17:29:14 +0200324 unsigned int pre_analyzers; /* bit field indicating analyzers to
325 * pre-process */
326 unsigned int post_analyzers; /* bit field indicating analyzers to
327 * post-process */
Christopher Fauletc3fe5332016-04-07 15:30:10 +0200328 struct list list; /* Next filter for the same proxy/stream */
329 };
330
331 * 'filter.config' is the filter configuration previously described. All
332 instances of a filter share it.
333
334 * 'filter.ctx' is an opaque context. It is managed by the filter, so it is its
335 responsibility to free it.
336
Christopher Fauletf34b28a2016-05-11 17:29:14 +0200337 * 'filter.pre_analyzers and 'filter.post_analyzers will be described later
338 (See § 3.5).
339
Christopher Fauletc3fe5332016-04-07 15:30:10 +0200340 * 'filter.next' and 'filter.fwd' will be described later (See § 3.6).
341
342
3433.2. DEFINING THE FILTER NAME AND ITS CONFIGURATION
344---------------------------------------------------
345
346When you write a filter, the first thing to do is to add it in the supported
347filters. To do so, you must register its name as a valid keyword on the filter
348line:
349
350 /* Declare the filter parser for "my_filter" keyword */
351 static struct flt_kw_list flt_kws = { "MY_FILTER_SCOPE", { }, {
Christopher Fauletf34b28a2016-05-11 17:29:14 +0200352 { "my_filter", parse_my_filter_cfg, NULL /* private data */ },
353 { NULL, NULL, NULL },
Christopher Fauletc3fe5332016-04-07 15:30:10 +0200354 }
355 };
356
357 __attribute__((constructor))
358 static void
359 __my_filter_init(void)
360 {
361 flt_register_keywords(&flt_kws);
362 }
363
364
365Then you must define the internal configuration your filter will use. For
366example:
367
368 struct my_filter_config {
369 struct proxy *proxy;
370 char *name;
371 /* ... */
372 };
373
374
375You also must list all callbacks implemented by your filter. Here, we use a
376global variable:
377
378 struct flt_ops my_filter_ops {
379 .init = my_filter_init,
380 .deinit = my_filter_deinit,
381 .check = my_filter_config_check,
382
383 /* ... */
384 };
385
386
387Finally, you must define the function to parse your filter configuration, here
388'parse_my_filter_cfg'. This function must parse all remaining keywords on the
389filter line:
390
391 /* Return -1 on error, else 0 */
392 static int
393 parse_my_filter_cfg(char **args, int *cur_arg, struct proxy *px,
Christopher Fauletf34b28a2016-05-11 17:29:14 +0200394 struct flt_conf *flt_conf, char **err, void *private)
Christopher Fauletc3fe5332016-04-07 15:30:10 +0200395 {
396 struct my_filter_config *my_conf;
397 int pos = *cur_arg;
398
399 /* Allocate the internal configuration used by the filter */
400 my_conf = calloc(1, sizeof(*my_conf));
401 if (!my_conf) {
402 memprintf(err, "%s: out of memory", args[*cur_arg]);
403 return -1;
404 }
405 my_conf->proxy = px;
406
407 /* ... */
408
409 /* Parse all keywords supported by the filter and fill the internal
410 * configuration */
411 pos++; /* Skip the filter name */
412 while (*args[pos]) {
413 if (!strcmp(args[pos], "name")) {
414 if (!*args[pos + 1]) {
415 memprintf(err, "'%s' : '%s' option without value",
416 args[*cur_arg], args[pos]);
417 goto error;
418 }
419 my_conf->name = strdup(args[pos + 1]);
420 if (!my_conf->name) {
421 memprintf(err, "%s: out of memory", args[*cur_arg]);
422 goto error;
423 }
424 pos += 2;
425 }
426
427 /* ... parse other keywords ... */
428 }
429 *cur_arg = pos;
430
431 /* Set callbacks supported by the filter */
432 flt_conf->ops = &my_filter_ops;
433
434 /* Last, save the internal configuration */
435 flt_conf->conf = my_conf;
436 return 0;
437
438 error:
439 if (my_conf->name)
440 free(my_conf->name);
441 free(my_conf);
442 return -1;
443 }
444
445
446WARNING: In your parsing function, you must define 'flt_conf->ops'. You must
447 also parse all arguments on the filter line. This is mandatory.
448
449In the previous example, we expect to read a filter line as follows:
450
451 filter my_filter name MY_NAME ...
452
453
454Optionnaly, by implementing the 'flt_ops.check' callback, you add a step to
455check the internal configuration of your filter after the parsing phase, when
456the HAProxy configuration is fully defined. For example:
457
458 /* Check configuration of a trace filter for a specified proxy.
459 * Return 1 on error, else 0. */
460 static int
461 my_filter_config_check(struct proxy *px, struct flt_conf *my_conf)
462 {
463 if (px->mode != PR_MODE_HTTP) {
464 Alert("The filter 'my_filter' cannot be used in non-HTTP mode.\n");
465 return 1;
466 }
467
468 /* ... */
469
470 return 0;
471 }
472
473
474
4753.3. MANAGING THE FILTER LIFECYCLE
476----------------------------------
477
478Once the configuration parsed and checked, filters are ready to by used. There
Christopher Faulet71a6a8e2017-07-27 16:33:28 +0200479are two main callbacks to manage the filter lifecycle:
Christopher Fauletc3fe5332016-04-07 15:30:10 +0200480
481 * 'flt_ops.init': It initializes the filter for a proxy. You may define this
482 callback if you need to complete your filter configuration.
483
484 * 'flt_ops.deinit': It cleans up what the parsing function and the init
485 callback have done. This callback is useful to release
486 memory allocated for the filter configuration.
487
488Here is an example:
489
490 /* Initialize the filter. Returns -1 on error, else 0. */
491 static int
492 my_filter_init(struct proxy *px, struct flt_conf *fconf)
493 {
494 struct my_filter_config *my_conf = fconf->conf;
495
496 /* ... */
497
498 return 0;
499 }
500
501 /* Free ressources allocated by the trace filter. */
502 static void
503 my_filter_deinit(struct proxy *px, struct flt_conf *fconf)
504 {
505 struct my_filter_config *my_conf = fconf->conf;
506
507 if (my_conf) {
508 free(my_conf->name);
509 /* ... */
510 free(my_conf);
511 }
512 fconf->conf = NULL;
513 }
514
515
516TODO: Add callbacks to handle creation/destruction of filter instances. And
517 document it.
518
519
Christopher Faulet71a6a8e2017-07-27 16:33:28 +02005203.3.1 DEALING WITH THREADS
521--------------------------
522
523When HAProxy is compiled with the threads support and started with more that one
524thread (global.nbthread > 1), then it is possible to manage the filter per
525thread with following callbacks:
526
527 * 'flt_ops.init_per_thread': It initializes the filter for each thread. It
528 works the same way than 'flt_ops.init' but in the
529 context of a thread. This callback is called
530 after the thread creation.
531
532 * 'flt_ops.deinit_per_thread': It cleans up what the init_per_thread callback
533 have done. It is called in the context of a
534 thread, before exiting it.
535
536This is the filter's responsibility to deal with concurrency. check, init and
537deinit callbacks are called on the main thread. All others are called on a
538"worker" thread (not always the same). This is also the filter's responsibility
539to know if HAProxy is started with more than one thread. If it is started with
540one thread (or compiled without the threads support), these callbacks will be
541silently ignored (in this case, global.nbthread will be always equal to one).
542
543
Christopher Faulet9adb0a52016-06-21 11:50:49 +02005443.4. HANDLING THE STREAMS ACTIVITY
545-----------------------------------
Christopher Fauletc3fe5332016-04-07 15:30:10 +0200546
Christopher Faulet9adb0a52016-06-21 11:50:49 +0200547You may be interessted to handle streams activity. For now, there is three
548callbacks that you should define to do so:
Christopher Fauletc3fe5332016-04-07 15:30:10 +0200549
550 * 'flt_ops.stream_start': It is called when a stream is started. This callback
551 can fail by returning a negative value. It will be
552 considered as a critical error by HAProxy which
553 disabled the listener for a short time.
554
Christopher Faulet9adb0a52016-06-21 11:50:49 +0200555 * 'flt_ops.stream_set_backend': It is called when a backend is set for a
556 stream. This callbacks will be called for all
557 filters attached to a stream (frontend and
558 backend). Note this callback is not called if
559 the frontend and the backend are the same.
560
Christopher Fauletc3fe5332016-04-07 15:30:10 +0200561 * 'flt_ops.stream_stop': It is called when a stream is stopped. This callback
562 always succeed. Anyway, it is too late to return an
563 error.
564
565For example:
566
567 /* Called when a stream is created. Returns -1 on error, else 0. */
568 static int
569 my_filter_stream_start(struct stream *s, struct filter *filter)
570 {
571 struct my_filter_config *my_conf = FLT_CONF(filter);
572
573 /* ... */
574
575 return 0;
576 }
577
Christopher Faulet9adb0a52016-06-21 11:50:49 +0200578 /* Called when a backend is set for a stream */
579 static int
580 my_filter_stream_set_backend(struct stream *s, struct filter *filter,
581 struct proxy *be)
582 {
583 struct my_filter_config *my_conf = FLT_CONF(filter);
584
585 /* ... */
586
587 return 0;
588 }
589
Christopher Fauletc3fe5332016-04-07 15:30:10 +0200590 /* Called when a stream is destroyed */
591 static void
592 my_filter_stream_stop(struct stream *s, struct filter *filter)
593 {
594 struct my_filter_config *my_conf = FLT_CONF(filter);
595
596 /* ... */
597 }
598
599
600WARNING: Handling the streams creation and destuction is only possible for
601 filters defined on proxies with the frontend capability.
602
Christopher Faulet9adb0a52016-06-21 11:50:49 +0200603In addition, it is possible to handle creation and destruction of filter
604instances using following callbacks:
605
606 * 'flt_ops.attach': It is called after a filter instance creation, when it is
607 attached to a stream. This happens when the stream is
608 started for filters defined on the stream's frontend and
609 when the backend is set for filters declared on the
610 stream's backend. It is possible to ignore the filter, if
611 needed, by returning 0. This could be useful to have
612 conditional filtering.
613
614 * 'flt_ops.detach': It is called when a filter instance is detached from a
615 stream, before its destruction. This happens when the
616 stream is stopped for filters defined on the stream's
617 frontend and when the analyze ends for filters defined on
618 the stream's backend.
619
620For example:
621
622 /* Called when a filter instance is created and attach to a stream */
623 static int
624 my_filter_attach(struct stream *s, struct filter *filter)
625 {
626 struct my_filter_config *my_conf = FLT_CONF(filter);
627
628 if (/* ... */)
629 return 0; /* Ignore the filter here */
630 return 1;
631 }
632
633 /* Called when a filter instance is detach from a stream, just before its
634 * destruction */
635 static void
636 my_filter_detach(struct stream *s, struct filter *filter)
637 {
638 struct my_filter_config *my_conf = FLT_CONF(filter);
639
640 /* ... */
641 }
Christopher Fauletc3fe5332016-04-07 15:30:10 +0200642
Christopher Fauleta00d8172016-11-10 14:58:05 +0100643Finally, you may be interested to be notified when the stream is woken up
644because of an expired timer. This could let you a chance to check your own
645timeouts, if any. To do so you can use the following callback:
646
647 * 'flt_opt.check_timeouts': It is called when a stream is woken up because
648 of an expired timer.
649
650For example:
651
652 /* Called when a stream is woken up because of an expired timer */
653 static void
654 my_filter_check_timeouts(struct stream *s, struct filter *filter)
655 {
656 struct my_filter_config *my_conf = FLT_CONF(filter);
657
658 /* ... */
659 }
660
661
Christopher Fauletc3fe5332016-04-07 15:30:10 +02006623.5. ANALYZING THE CHANNELS ACTIVITY
663------------------------------------
664
665The main purpose of filters is to take part in the channels analyzing. To do so,
Christopher Fauletf34b28a2016-05-11 17:29:14 +0200666there is 2 callbacks, 'flt_ops.channel_pre_analyze' and
667'flt_ops.channel_post_analyze', called respectively before and after each
668analyzer attached to a channel, execpt analyzers responsible for the data
669parsing/forwarding (TCP or HTTP data). Concretely, on the request channel, these
670callbacks could be called before following analyzers:
Christopher Fauletc3fe5332016-04-07 15:30:10 +0200671
672 * tcp_inspect_request (AN_REQ_INSPECT_FE and AN_REQ_INSPECT_BE)
673 * http_wait_for_request (AN_REQ_WAIT_HTTP)
674 * http_wait_for_request_body (AN_REQ_HTTP_BODY)
675 * http_process_req_common (AN_REQ_HTTP_PROCESS_FE)
676 * process_switching_rules (AN_REQ_SWITCHING_RULES)
677 * http_process_req_ common (AN_REQ_HTTP_PROCESS_BE)
678 * http_process_tarpit (AN_REQ_HTTP_TARPIT)
679 * process_server_rules (AN_REQ_SRV_RULES)
680 * http_process_request (AN_REQ_HTTP_INNER)
681 * tcp_persist_rdp_cookie (AN_REQ_PRST_RDP_COOKIE)
682 * process_sticking_rules (AN_REQ_STICKING_RULES)
Christopher Fauletc3fe5332016-04-07 15:30:10 +0200683
684And on the response channel:
685
686 * tcp_inspect_response (AN_RES_INSPECT)
687 * http_wait_for_response (AN_RES_WAIT_HTTP)
688 * process_store_rules (AN_RES_STORE_RULES)
689 * http_process_res_common (AN_RES_HTTP_PROCESS_BE)
Christopher Fauletc3fe5332016-04-07 15:30:10 +0200690
Christopher Fauletf34b28a2016-05-11 17:29:14 +0200691Unlike the other callbacks previously seen before, 'flt_ops.channel_pre_analyze'
692can interrupt the stream processing. So a filter can decide to not execute the
Christopher Fauletc3fe5332016-04-07 15:30:10 +0200693analyzer that follows and wait the next iteration. If there are more than one
694filter, following ones are skipped. On the next iteration, the filtering resumes
695where it was stopped, i.e. on the filter that has previously stopped the
Christopher Fauletf34b28a2016-05-11 17:29:14 +0200696processing. So it is possible for a filter to stop the stream processing on a
697specific analyzer for a while before continuing. Moreover, this callback can be
698called many times for the same analyzer, until it finishes its processing. For
699example:
Christopher Fauletc3fe5332016-04-07 15:30:10 +0200700
701 /* Called before a processing happens on a given channel.
702 * Returns a negative value if an error occurs, 0 if it needs to wait,
703 * any other value otherwise. */
704 static int
Christopher Fauletf34b28a2016-05-11 17:29:14 +0200705 my_filter_chn_pre_analyze(struct stream *s, struct filter *filter,
706 struct channel *chn, unsigned an_bit)
Christopher Fauletc3fe5332016-04-07 15:30:10 +0200707 {
708 struct my_filter_config *my_conf = FLT_CONF(filter);
709
710 switch (an_bit) {
711 case AN_REQ_WAIT_HTTP:
712 if (/* wait that a condition is verified before continuing */)
713 return 0;
714 break;
715 /* ... * /
716 }
717 return 1;
718 }
719
720 * 'an_bit' is the analyzer id. All analyzers are listed in
721 'include/types/channels.h'.
722
723 * 'chn' is the channel on which the analyzing is done. You can know if it is
724 the request or the response channel by testing if CF_ISRESP flag is set:
725
726 │ ((chn->flags & CF_ISRESP) == CF_ISRESP)
727
728
729In previous example, the stream processing is blocked before receipt of the HTTP
730request until a condition is verified.
731
Christopher Fauletf34b28a2016-05-11 17:29:14 +0200732'flt_ops.channel_post_analyze', for its part, is not resumable. It returns a
733negative value if an error occurs, any other value otherwise. It is called when
734a filterable analyzer finishes its processing. So it called once for the same
735analyzer. For example:
736
737 /* Called after a processing happens on a given channel.
738 * Returns a negative value if an error occurs, any other
739 * value otherwise. */
740 static int
741 my_filter_chn_post_analyze(struct stream *s, struct filter *filter,
742 struct channel *chn, unsigned an_bit)
743 {
744 struct my_filter_config *my_conf = FLT_CONF(filter);
745 struct http_msg *msg;
746
747 switch (an_bit) {
748 case AN_REQ_WAIT_HTTP:
749 if (/* A test on received headers before any other treatment */) {
750 msg = ((chn->flags & CF_ISRESP) ? &s->txn->rsp : &s->txn->req);
751 txn->status = 400;
752 msg->msg_state = HTTP_MSG_ERROR;
753 http_reply_and_close(s, s->txn->status,
754 http_error_message(s, HTTP_ERR_400));
755 return -1; /* This is an error ! */
756 }
757 break;
758 /* ... * /
759 }
760 return 1;
761 }
762
763
764Pre and post analyzer callbacks of a filter are not automatically called. You
765must register it explicitly on analyzers, updating the value of
766'filter.pre_analyzers' and 'filter.post_analyzers' bit fields. All analyzer bits
767are listed in 'include/types/channels.h'. Here is an example:
768
769 static int
770 my_filter_stream_start(struct stream *s, struct filter *filter)
771 {
772 /* ... * /
773
774 /* Register the pre analyzer callback on all request and response
775 * analyzers */
776 filter->pre_analyzers |= (AN_REQ_ALL | AN_RES_ALL)
777
778 /* Register the post analyzer callback of only on AN_REQ_WAIT_HTTP and
779 * AN_RES_WAIT_HTTP analyzers */
780 filter->post_analyzers |= (AN_REQ_WAIT_HTTP | AN_RES_WAIT_HTTP)
781
782 /* ... * /
783 return 0;
784 }
785
786
Christopher Fauletc3fe5332016-04-07 15:30:10 +0200787To surround activity of a filter during the channel analyzing, two new analyzers
788has been added:
789
Christopher Faulet0184ea72017-01-05 14:06:34 +0100790 * 'flt_start_analyze' (AN_REQ/RES_FLT_START_FE/AN_REQ_RES_FLT_START_BE): For
791 a specific filter, this analyzer is called before any call to the
792 'channel_analyze' callback. From the filter point of view, it calls the
Christopher Fauletc3fe5332016-04-07 15:30:10 +0200793 'flt_ops.channel_start_analyze' callback.
794
Christopher Faulet0184ea72017-01-05 14:06:34 +0100795 * 'flt_end_analyze' (AN_REQ/RES_FLT_END): For a specific filter, this analyzer
796 is called when all other analyzers have finished their processing. From the
Christopher Fauletc3fe5332016-04-07 15:30:10 +0200797 filter point of view, it calls the 'flt_ops.channel_end_analyze' callback.
798
799For TCP streams, these analyzers are called only once. For HTTP streams, if the
800client connection is kept alive, this happens at each request/response roundtip.
801
802'flt_ops.channel_start_analyze' and 'flt_ops.channel_end_analyze' callbacks can
803interrupt the stream processing, as 'flt_ops.channel_analyze'. Here is an
804example:
805
806 /* Called when analyze starts for a given channel
807 * Returns a negative value if an error occurs, 0 if it needs to wait,
808 * any other value otherwise. */
809 static int
810 my_filter_chn_start_analyze(struct stream *s, struct filter *filter,
811 struct channel *chn)
812 {
813 struct my_filter_config *my_conf = FLT_CONF(filter);
814
815 /* ... TODO ... */
816
817 return 1;
818 }
819
820 /* Called when analyze ends for a given channel
821 * Returns a negative value if an error occurs, 0 if it needs to wait,
822 * any other value otherwise. */
823 static int
824 my_filter_chn_end_analyze(struct stream *s, struct filter *filter,
825 struct channel *chn)
826 {
827 struct my_filter_config *my_conf = FLT_CONF(filter);
828
829 /* ... TODO ... */
830
831 return 1;
832 }
833
834
835Workflow on channels can be summarized as following:
836
Christopher Faulet9adb0a52016-06-21 11:50:49 +0200837 FE: Called for filters defined on the stream's frontend
838 BE: Called for filters defined on the stream's backend
839
840 +------->---------+
841 | | |
842 +----------------------+ | +----------------------+
843 | flt_ops.attach (FE) | | | flt_ops.attach (BE) |
844 +----------------------+ | +----------------------+
845 | | |
846 V | V
847 +--------------------------+ | +------------------------------------+
848 | flt_ops.stream_start (FE)| | | flt_ops.stream_set_backend (FE+BE) |
849 +--------------------------+ | +------------------------------------+
850 | | |
851 ... | ...
852 | | |
853 +-<-- [1] ^ |
854 | --+ | | --+
855 +------<----------+ | | +--------<--------+ |
856 | | | | | | |
857 V | | | V | |
858+-------------------------------+ | | | +-------------------------------+ | |
859| flt_start_analyze (FE) +-+ | | | flt_start_analyze (BE) +-+ |
860|(flt_ops.channel_start_analyze)| | F | |(flt_ops.channel_start_analyze)| |
861+---------------+---------------+ | R | +-------------------------------+ |
862 | | O | | |
863 +------<---------+ | N ^ +--------<-------+ | B
864 | | | T | | | | A
865+---------------|------------+ | | E | +---------------|------------+ | | C
866|+--------------V-------------+ | | N | |+--------------V-------------+ | | K
867||+----------------------------+ | | D | ||+----------------------------+ | | E
868|||flt_ops.channel_pre_analyze | | | | |||flt_ops.channel_pre_analyze | | | N
869||| V | | | | ||| V | | | D
870||| analyzer (FE) +-+ | | ||| analyzer (FE+BE) +-+ |
871+|| V | | | +|| V | |
872 +|flt_ops.channel_post_analyze| | | +|flt_ops.channel_post_analyze| |
873 +----------------------------+ | | +----------------------------+ |
874 | --+ | | |
875 +------------>------------+ ... |
876 | |
877 [ data filtering (see below) ] |
878 | |
879 ... |
880 | |
881 +--------<--------+ |
882 | | |
883 V | |
884 +-------------------------------+ | |
885 | flt_end_analyze (FE+BE) +-+ |
886 | (flt_ops.channel_end_analyze) | |
887 +---------------+---------------+ |
888 | --+
889 V
890 +----------------------+
891 | flt_ops.detach (BE) |
892 +----------------------+
893 |
894 If HTTP stream, go back to [1] --<--+
895 |
896 ...
897 |
898 V
899 +--------------------------+
900 | flt_ops.stream_stop (FE) |
901 +--------------------------+
902 |
903 V
904 +----------------------+
905 | flt_ops.detach (FE) |
906 +----------------------+
907 |
908 V
Christopher Fauletc3fe5332016-04-07 15:30:10 +0200909
Christopher Fauletf34b28a2016-05-11 17:29:14 +0200910By zooming on an analyzer box we have:
Christopher Fauletc3fe5332016-04-07 15:30:10 +0200911
Christopher Fauletf34b28a2016-05-11 17:29:14 +0200912 ...
913 |
914 V
915 |
916 +-----------<-----------+
917 | |
918 +-----------------+--------------------+ |
919 | | | |
920 | +--------<---------+ | |
921 | | | | |
922 | V | | |
923 | flt_ops.channel_pre_analyze ->-+ | ^
924 | | | |
925 | | | |
926 | V | |
927 | analyzer --------->-----+--+
928 | | |
929 | | |
930 | V |
931 | flt_ops.channel_post_analyze |
932 | | |
933 | | |
934 +-----------------+--------------------+
935 |
936 V
937 ...
Christopher Fauletc3fe5332016-04-07 15:30:10 +0200938
939
940 3.6. FILTERING THE DATA EXCHANGED
941-----------------------------------
942
943WARNING: To fully understand this part, you must be aware on how the buffers
944 work in HAProxy. In particular, you must be comfortable with the idea
945 of circular buffers. See doc/internals/buffer-operations.txt and
946 doc/internals/buffer-ops.fig for details.
947 doc/internals/body-parsing.txt could also be useful.
948
949An extended feature of the filters is the data filtering. By default a filter
950does not look into data exchanged between the client and the server because it
951is expensive. Indeed, instead of forwarding data without any processing, each
952byte need to be buffered.
953
954So, to enable the data filtering on a channel, at any time, in one of previous
955callbacks, you should call 'register_data_filter' function. And conversely, to
956disable it, you should call 'unregister_data_filter' function. For example:
957
Christopher Fauletf34b28a2016-05-11 17:29:14 +0200958 my_filter_http_headers(struct stream *s, struct filter *filter,
959 struct http_msg *msg)
Christopher Fauletc3fe5332016-04-07 15:30:10 +0200960 {
961 struct my_filter_config *my_conf = FLT_CONF(filter);
962
963 /* 'chn' must be the request channel */
Christopher Fauletf34b28a2016-05-11 17:29:14 +0200964 if (!(msg->chn->flags & CF_ISRESP)) {
Christopher Fauletc3fe5332016-04-07 15:30:10 +0200965 struct http_txn *txn = s->txn;
Christopher Fauletc3fe5332016-04-07 15:30:10 +0200966 struct buffer *req = msg->chn->buf;
967 struct hdr_ctx ctx;
968
969 /* Enable the data filtering for the request if 'X-Filter' header
970 * is set to 'true'. */
971 if (http_find_header2("X-Filter", 8, req->p, &txn->hdr_idx, &ctx) &&
972 ctx.vlen >= 3 && memcmp(ctx.line + ctx.val, "true", 4) == 0)
Christopher Fauletf34b28a2016-05-11 17:29:14 +0200973 register_data_filter(s, chn, filter);
Christopher Fauletc3fe5332016-04-07 15:30:10 +0200974 }
975
976 return 1;
977 }
978
979Here, the data filtering is enabled if the HTTP header 'X-Filter' is found and
980set to 'true'.
981
982If several filters are declared, the evaluation order remains the same,
983regardless the order of the registrations to the data filtering.
984
985Depending on the stream type, TCP or HTTP, the way to handle data filtering will
986be slightly different. Among other things, for HTTP streams, there are more
987callbacks to help you to fully handle all steps of an HTTP transaction. But the
988basis is the same. The data filtering is done in 2 stages:
989
990 * The data parsing: At this stage, filters will analyze input data on a
991 channel. Once a filter has parsed some data, it cannot parse it again. At
992 any time, a filter can choose to not parse all available data. So, it is
993 possible for a filter to retain data for a while. Because filters are
994 chained, a filter cannot parse more data than its predecessors. Thus only
995 data considered as parsed by the last filter will be available to the next
996 stage, the data forwarding.
997
998 * The data forwarding: At this stage, filters will decide how much data
999 HAProxy can forward among those considered as parsed at the previous
1000 stage. Once a filter has marked data as forwardable, it cannot analyze it
1001 anymore. At any time, a filter can choose to not forward all parsed
1002 data. So, it is possible for a filter to retain data for a while. Because
1003 filters are chained, a filter cannot forward more data than its
1004 predecessors. Thus only data marked as forwardable by the last filter will
1005 be actually forwarded by HAProxy.
1006
1007Internally, filters own 2 offsets, relatively to 'buf->p', representing the
1008number of bytes already parsed in the available input data and the number of
1009bytes considered as forwarded. We will call these offsets, respectively, 'nxt'
1010and 'fwd'. Following macros reference these offsets:
1011
1012 * FLT_NXT(flt, chn), flt_req_nxt(flt) and flt_rsp_nxt(flt)
1013
1014 * FLT_FWD(flt, chn), flt_req_fwd(flt) and flt_rsp_fwd(flt)
1015
1016where 'flt' is the 'struct filter' passed as argument in all callbacks and 'chn'
1017is the considered channel.
1018
1019Using these offsets, following operations on buffers are possible:
1020
1021 chn->buf->p + FLT_NXT(flt, chn) // the pointer on parsable data for
1022 // the filter 'flt' on the channel 'chn'.
1023 // Everything between chn->buf->p and 'nxt' offset was already parsed
1024 // by the filter.
1025
1026 chn->buf->i - FLT_NXT(flt, chn) // the number of bytes of parsable data for
1027 // the filter 'flt' on the channel 'chn'.
1028
1029 chn->buf->p + FLT_FWD(flt, chn) // the pointer on forwardable data for
1030 // the filter 'flt' on the channel 'chn'.
1031 // Everything between chn->buf->p and 'fwd' offset was already forwarded
1032 // by the filter.
1033
1034
1035Note that at any time, for a filter, 'nxt' offset is always greater or equal to
1036'fwd' offset.
1037
1038TODO: Add schema with buffer states when there is 2 filters that analyze data.
1039
1040
10413.6.1 FILTERING DATA ON TCP STREAMS
1042-----------------------------------
1043
1044The TCP data filtering is the easy case, because HAProxy do not parse these
1045data. So you have only two callbacks that you need to consider:
1046
1047 * 'flt_ops.tcp_data': This callback is called when unparsed data are
1048 available. If not defined, all available data will be considered as parsed
1049 for the filter.
1050
1051 * 'flt_ops.tcp_forward_data': This callback is called when parsed data are
1052 available. If not defined, all parsed data will be considered as forwarded
1053 for the filter.
1054
1055Here is an example:
1056
1057 /* Returns a negative value if an error occurs, else the number of
1058 * consumed bytes. */
1059 static int
1060 my_filter_tcp_data(struct stream *s, struct filter *filter,
1061 struct channel *chn)
1062 {
1063 struct my_filter_config *my_conf = FLT_CONF(filter);
1064 int avail = chn->buf->i - FLT_NXT(filter, chn);
1065 int ret = avail;
1066
1067 /* Do not parse more than 'my_conf->max_parse' bytes at a time */
1068 if (my_conf->max_parse != 0 && ret > my_conf->max_parse)
1069 ret = my_conf->max_parse;
1070
1071 /* if available data are not completely parsed, wake up the stream to
1072 * be sure to not freeze it. */
1073 if (ret != avail)
1074 task_wakeup(s->task, TASK_WOKEN_MSG);
1075 return ret;
1076 }
1077
1078
1079 /* Returns a negative value if an error occurs, else * or the number of
1080 * forwarded bytes. */
1081 static int
1082 my_filter_tcp_forward_data(struct stream *s, struct filter *filter,
1083 struct channel *chn, unsigned int len)
1084 {
1085 struct my_filter_config *my_conf = FLT_CONF(filter);
1086 int ret = len;
1087
1088 /* Do not forward more than 'my_conf->max_forward' bytes at a time */
1089 if (my_conf->max_forward != 0 && ret > my_conf->max_forward)
1090 ret = my_conf->max_forward;
1091
1092 /* if parsed data are not completely forwarded, wake up the stream to
1093 * be sure to not freeze it. */
1094 if (ret != len)
1095 task_wakeup(s->task, TASK_WOKEN_MSG);
1096 return ret;
1097 }
1098
1099
1100
11013.6.2 FILTERING DATA ON HTTP STREAMS
1102------------------------------------
1103
1104The HTTP data filtering is a bit tricky because HAProxy will parse the body
1105structure, especially chunked body. So basically there is the HTTP counterpart
1106to the previous callbacks:
1107
1108 * 'flt_ops.http_data': This callback is called when unparsed data are
1109 available. If not defined, all available data will be considered as parsed
1110 for the filter.
1111
1112 * 'flt_ops.http_forward_data': This callback is called when parsed data are
1113 available. If not defined, all parsed data will be considered as forwarded
1114 for the filter.
1115
1116But the prototype for these callbacks is slightly different. Instead of having
1117the channel as parameter, we have the HTTP message (struct http_msg). You need
1118to be careful when you use 'http_msg.chunk_len' size. This value is the number
1119of bytes remaining to parse in the HTTP body (or the chunk for chunked
1120messages). The HTTP parser of HAProxy uses it to have the number of bytes that
1121it could consume:
1122
1123 /* Available input data in the current chunk from the HAProxy point of view.
1124 * msg->next bytes were already parsed. Without data filtering, HAProxy
1125 * will consume all of it. */
1126 Bytes = MIN(msg->chunk_len, chn->buf->i - msg->next);
1127
1128
1129But in your filter, you need to recompute it:
1130
1131 /* Available input data in the current chunk from the filter point of view.
1132 * 'nxt' bytes were already parsed. */
1133 Bytes = MIN(msg->chunk_len + msg->next, chn->buf->i) - FLT_NXT(flt, chn);
1134
1135
Christopher Fauletf34b28a2016-05-11 17:29:14 +02001136In addition to these callbacks, there are three others:
1137
1138 * 'flt_ops.http_headers': This callback is called just before the HTTP body
1139 parsing and after any processing on the request/response HTTP headers. When
1140 defined, this callback is always called for HTTP streams (i.e. without needs
1141 of a registration on data filtering).
Christopher Fauletc3fe5332016-04-07 15:30:10 +02001142
1143 * 'flt_ops.http_end': This callback is called when the whole HTTP
1144 request/response is processed. It can interrupt the stream processing. So,
1145 it could be used to synchronize the HTTP request with the HTTP response, for
1146 example:
1147
1148 /* Returns a negative value if an error occurs, 0 if it needs to wait,
1149 * any other value otherwise. */
1150 static int
1151 my_filter_http_end(struct stream *s, struct filter *filter,
1152 struct http_msg *msg)
1153 {
1154 struct my_filter_ctx *my_ctx = filter->ctx;
1155
1156
1157 if (!(msg->chn->flags & CF_ISRESP)) /* The request */
1158 my_ctx->end_of_req = 1;
1159 else /* The response */
1160 my_ctx->end_of_rsp = 1;
1161
1162 /* Both the request and the response are finished */
1163 if (my_ctx->end_of_req == 1 && my_ctx->end_of_rsp == 1)
1164 return 1;
1165
1166 /* Wait */
1167 return 0;
1168 }
1169
1170
1171 * 'flt_ops.http_chunk_trailers': This callback is called for chunked HTTP
1172 messages only when all chunks were parsed. HTTP trailers can be parsed into
1173 several passes. This callback will be called each time. The number of bytes
1174 parsed by HAProxy at each iteration is stored in 'msg->sol'.
1175
1176Then, to finish, there are 2 informational callbacks:
1177
1178 * 'flt_ops.http_reset': This callback is called when a HTTP message is
1179 reset. This only happens when a '100-continue' response is received. It
1180 could be useful to reset the filter context before receiving the true
1181 response.
1182
1183 * 'flt_ops.http_reply': This callback is called when, at any time, HAProxy
1184 decides to stop the processing on a HTTP message and to send an internal
1185 response to the client. This mainly happens when an error or a redirect
1186 occurs.
1187
1188
11893.6.3 REWRITING DATA
1190--------------------
1191
1192The last part, and the trickiest one about the data filtering, is about the data
1193rewriting. For now, the filter API does not offer a lot of functions to handle
1194it. There are only functions to notify HAProxy that the data size has changed to
1195let it update internal state of filters. This is your responsibility to update
1196data itself, i.e. the buffer offsets. For a HTTP message, you also must update
1197'msg->next' and 'msg->chunk_len' values accordingly:
1198
1199 * 'flt_change_next_size': This function must be called when a filter alter
1200 incoming data. It updates 'nxt' offset value of all its predecessors. Do not
1201 call this function when a filter change the size of incoming data leads to
1202 an undefined behavior.
1203
1204 unsigned int avail = MIN(msg->chunk_len + msg->next, chn->buf->i) -
1205 flt_rsp_next(filter);
1206
1207 if (avail > 10 and /* ...Some condition... */) {
1208 /* Move the buffer forward to have buf->p pointing on unparsed
1209 * data */
Willy Tarreaubcbd3932018-06-06 07:13:22 +02001210 c_adv(msg->chn, flt_rsp_nxt(filter));
Christopher Fauletc3fe5332016-04-07 15:30:10 +02001211
1212 /* Skip first 10 bytes. To simplify this example, we consider a
1213 * non-wrapping buffer */
1214 memmove(buf->p + 10, buf->p, avail - 10);
1215
1216 /* Restore buf->p value */
Willy Tarreaubcbd3932018-06-06 07:13:22 +02001217 c_rew(msg->chn, flt_rsp_nxt(filter));
Christopher Fauletc3fe5332016-04-07 15:30:10 +02001218
1219 /* Now update other filters */
1220 flt_change_next_size(filter, msg->chn, -10);
1221
1222 /* Update the buffer state */
1223 buf->i -= 10;
1224
1225 /* And update the HTTP message state */
1226 msg->chunk_len -= 10;
1227
1228 return (avail - 10);
1229 }
1230 else
1231 return 0; /* Wait for more data */
1232
1233
1234 * 'flt_change_forward_size': This function must be called when a filter alter
1235 parsed data. It updates offset values ('nxt' and 'fwd') of all filters. Do
1236 not call this function when a filter change the size of parsed data leads to
1237 an undefined behavior.
1238
1239 /* len is the number of bytes of forwardable data */
1240 if (len > 10 and /* ...Some condition... */) {
1241 /* Move the buffer forward to have buf->p pointing on non-forwarded
1242 * data */
Willy Tarreaubcbd3932018-06-06 07:13:22 +02001243 c_adv(msg->chn, flt_rsp_fwd(filter));
Christopher Fauletc3fe5332016-04-07 15:30:10 +02001244
1245 /* Skip first 10 bytes. To simplify this example, we consider a
1246 * non-wrapping buffer */
1247 memmove(buf->p + 10, buf->p, len - 10);
1248
1249 /* Restore buf->p value */
Willy Tarreaubcbd3932018-06-06 07:13:22 +02001250 c_rew(msg->chn, flt_rsp_fwd(filter));
Christopher Fauletc3fe5332016-04-07 15:30:10 +02001251
1252 /* Now update other filters */
1253 flt_change_forward_size(filter, msg->chn, -10);
1254
1255 /* Update the buffer state */
1256 buf->i -= 10;
1257
1258 /* And update the HTTP message state */
1259 msg->next -= 10;
1260
1261 return (len - 10);
1262 }
1263 else
1264 return 0; /* Wait for more data */
1265
1266
1267TODO: implement all the stuff to easily rewrite data. For HTTP messages, this
1268 requires to have a chunked message. Else the size of data cannot be
1269 changed.
1270
1271
1272
1273
12744. FAQ
1275------
1276
12774.1. Detect multiple declarations of the same filter
1278----------------------------------------------------
1279
1280TODO