blob: 40381ccbc1e8c5048c03abbdbc6bdb246c1beaad [file] [log] [blame]
Willy Tarreau79e57332018-10-02 16:01:16 +02001/*
2 * HTTP samples fetching
3 *
4 * Copyright 2000-2018 Willy Tarreau <w@1wt.eu>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 *
11 */
12
13#include <sys/types.h>
14
15#include <ctype.h>
16#include <string.h>
17#include <time.h>
18
19#include <common/base64.h>
20#include <common/chunk.h>
21#include <common/compat.h>
22#include <common/config.h>
23#include <common/debug.h>
24#include <common/http.h>
25#include <common/memory.h>
26#include <common/standard.h>
27#include <common/version.h>
28
29#include <types/global.h>
30
31#include <proto/arg.h>
32#include <proto/auth.h>
33#include <proto/http_fetch.h>
34#include <proto/log.h>
35#include <proto/obj_type.h>
36#include <proto/proto_http.h>
37#include <proto/sample.h>
38#include <proto/stream.h>
39
40
41/* this struct is used between calls to smp_fetch_hdr() or smp_fetch_cookie() */
42static THREAD_LOCAL struct hdr_ctx static_hdr_ctx;
43
44/*
45 * Returns the data from Authorization header. Function may be called more
46 * than once so data is stored in txn->auth_data. When no header is found
47 * or auth method is unknown auth_method is set to HTTP_AUTH_WRONG to avoid
48 * searching again for something we are unable to find anyway. However, if
49 * the result if valid, the cache is not reused because we would risk to
50 * have the credentials overwritten by another stream in parallel.
51 */
52
53static int get_http_auth(struct stream *s)
54{
55
56 struct http_txn *txn = s->txn;
57 struct buffer auth_method;
58 struct hdr_ctx ctx;
59 char *h, *p;
60 int len;
61
62#ifdef DEBUG_AUTH
63 printf("Auth for stream %p: %d\n", s, txn->auth.method);
64#endif
65
66 if (txn->auth.method == HTTP_AUTH_WRONG)
67 return 0;
68
69 txn->auth.method = HTTP_AUTH_WRONG;
70
71 ctx.idx = 0;
72
73 if (txn->flags & TX_USE_PX_CONN) {
74 h = "Proxy-Authorization";
75 len = strlen(h);
76 } else {
77 h = "Authorization";
78 len = strlen(h);
79 }
80
81 if (!http_find_header2(h, len, ci_head(&s->req), &txn->hdr_idx, &ctx))
82 return 0;
83
84 h = ctx.line + ctx.val;
85
86 p = memchr(h, ' ', ctx.vlen);
87 len = p - h;
88 if (!p || len <= 0)
89 return 0;
90
91 if (chunk_initlen(&auth_method, h, 0, len) != 1)
92 return 0;
93
94 chunk_initlen(&txn->auth.method_data, p + 1, 0, ctx.vlen - len - 1);
95
96 if (!strncasecmp("Basic", auth_method.area, auth_method.data)) {
97 struct buffer *http_auth = get_trash_chunk();
98
99 len = base64dec(txn->auth.method_data.area,
100 txn->auth.method_data.data,
101 http_auth->area, global.tune.bufsize - 1);
102
103 if (len < 0)
104 return 0;
105
106
107 http_auth->area[len] = '\0';
108
109 p = strchr(http_auth->area, ':');
110
111 if (!p)
112 return 0;
113
114 txn->auth.user = http_auth->area;
115 *p = '\0';
116 txn->auth.pass = p+1;
117
118 txn->auth.method = HTTP_AUTH_BASIC;
119 return 1;
120 }
121
122 return 0;
123}
124
125/* This function ensures that the prerequisites for an L7 fetch are ready,
126 * which means that a request or response is ready. If some data is missing,
127 * a parsing attempt is made. This is useful in TCP-based ACLs which are able
128 * to extract data from L7. If <req_vol> is non-null during a request prefetch,
129 * another test is made to ensure the required information is not gone.
130 *
131 * The function returns :
132 * 0 with SMP_F_MAY_CHANGE in the sample flags if some data is missing to
133 * decide whether or not an HTTP message is present ;
134 * 0 if the requested data cannot be fetched or if it is certain that
135 * we'll never have any HTTP message there ;
136 * 1 if an HTTP message is ready
137 */
138int smp_prefetch_http(struct proxy *px, struct stream *s, unsigned int opt,
139 const struct arg *args, struct sample *smp, int req_vol)
140{
141 struct http_txn *txn;
142 struct http_msg *msg;
143
144 /* Note: it is possible that <s> is NULL when called before stream
145 * initialization (eg: tcp-request connection), so this function is the
146 * one responsible for guarding against this case for all HTTP users.
147 */
148 if (!s)
149 return 0;
150
151 if (!s->txn) {
152 if (unlikely(!http_alloc_txn(s)))
153 return 0; /* not enough memory */
154 http_init_txn(s);
155 }
156 txn = s->txn;
157 msg = &txn->req;
158
159 /* Check for a dependency on a request */
160 smp->data.type = SMP_T_BOOL;
161
162 if ((opt & SMP_OPT_DIR) == SMP_OPT_DIR_REQ) {
163 /* If the buffer does not leave enough free space at the end,
164 * we must first realign it.
165 */
166 if (ci_head(&s->req) > b_orig(&s->req.buf) &&
167 ci_head(&s->req) + ci_data(&s->req) > b_wrap(&s->req.buf) - global.tune.maxrewrite)
168 channel_slow_realign(&s->req, trash.area);
169
170 if (unlikely(txn->req.msg_state < HTTP_MSG_BODY)) {
171 if (msg->msg_state == HTTP_MSG_ERROR)
172 return 0;
173
174 /* Try to decode HTTP request */
175 if (likely(msg->next < ci_data(&s->req)))
176 http_msg_analyzer(msg, &txn->hdr_idx);
177
178 /* Still no valid request ? */
179 if (unlikely(msg->msg_state < HTTP_MSG_BODY)) {
180 if ((msg->msg_state == HTTP_MSG_ERROR) ||
181 channel_full(&s->req, global.tune.maxrewrite)) {
182 return 0;
183 }
184 /* wait for final state */
185 smp->flags |= SMP_F_MAY_CHANGE;
186 return 0;
187 }
188
189 /* OK we just got a valid HTTP request. We have some minor
190 * preparation to perform so that further checks can rely
191 * on HTTP tests.
192 */
193
194 /* If the request was parsed but was too large, we must absolutely
195 * return an error so that it is not processed. At the moment this
196 * cannot happen, but if the parsers are to change in the future,
197 * we want this check to be maintained.
198 */
199 if (unlikely(ci_head(&s->req) + ci_data(&s->req) >
200 b_wrap(&s->req.buf) - global.tune.maxrewrite)) {
201 msg->err_state = msg->msg_state;
202 msg->msg_state = HTTP_MSG_ERROR;
203 smp->data.u.sint = 1;
204 return 1;
205 }
206
207 txn->meth = find_http_meth(ci_head(msg->chn), msg->sl.rq.m_l);
208 if (txn->meth == HTTP_METH_GET || txn->meth == HTTP_METH_HEAD)
209 s->flags |= SF_REDIRECTABLE;
210
211 if (unlikely(msg->sl.rq.v_l == 0) && !http_upgrade_v09_to_v10(txn))
212 return 0;
213 }
214
215 if (req_vol && txn->rsp.msg_state != HTTP_MSG_RPBEFORE) {
216 return 0; /* data might have moved and indexes changed */
217 }
218
219 /* otherwise everything's ready for the request */
220 }
221 else {
222 /* Check for a dependency on a response */
223 if (txn->rsp.msg_state < HTTP_MSG_BODY) {
224 smp->flags |= SMP_F_MAY_CHANGE;
225 return 0;
226 }
227 }
228
229 /* everything's OK */
230 smp->data.u.sint = 1;
231 return 1;
232}
233
234/* This function fetches the method of current HTTP request and stores
235 * it in the global pattern struct as a chunk. There are two possibilities :
236 * - if the method is known (not HTTP_METH_OTHER), its identifier is stored
237 * in <len> and <ptr> is NULL ;
238 * - if the method is unknown (HTTP_METH_OTHER), <ptr> points to the text and
239 * <len> to its length.
240 * This is intended to be used with pat_match_meth() only.
241 */
242static int smp_fetch_meth(const struct arg *args, struct sample *smp, const char *kw, void *private)
243{
244 int meth;
245 struct http_txn *txn;
246
247 CHECK_HTTP_MESSAGE_FIRST_PERM();
248
249 txn = smp->strm->txn;
250 meth = txn->meth;
251 smp->data.type = SMP_T_METH;
252 smp->data.u.meth.meth = meth;
253 if (meth == HTTP_METH_OTHER) {
254 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
255 /* ensure the indexes are not affected */
256 return 0;
257 smp->flags |= SMP_F_CONST;
258 smp->data.u.meth.str.data = txn->req.sl.rq.m_l;
259 smp->data.u.meth.str.area = ci_head(txn->req.chn);
260 }
261 smp->flags |= SMP_F_VOL_1ST;
262 return 1;
263}
264
265static int smp_fetch_rqver(const struct arg *args, struct sample *smp, const char *kw, void *private)
266{
267 struct http_txn *txn;
268 char *ptr;
269 int len;
270
271 CHECK_HTTP_MESSAGE_FIRST();
272
273 txn = smp->strm->txn;
274 len = txn->req.sl.rq.v_l;
275 ptr = ci_head(txn->req.chn) + txn->req.sl.rq.v;
276
277 while ((len-- > 0) && (*ptr++ != '/'));
278 if (len <= 0)
279 return 0;
280
281 smp->data.type = SMP_T_STR;
282 smp->data.u.str.area = ptr;
283 smp->data.u.str.data = len;
284
285 smp->flags = SMP_F_VOL_1ST | SMP_F_CONST;
286 return 1;
287}
288
289static int smp_fetch_stver(const struct arg *args, struct sample *smp, const char *kw, void *private)
290{
291 struct http_txn *txn;
292 char *ptr;
293 int len;
294
295 CHECK_HTTP_MESSAGE_FIRST();
296
297 txn = smp->strm->txn;
298 if (txn->rsp.msg_state < HTTP_MSG_BODY)
299 return 0;
300
301 len = txn->rsp.sl.st.v_l;
302 ptr = ci_head(txn->rsp.chn);
303
304 while ((len-- > 0) && (*ptr++ != '/'));
305 if (len <= 0)
306 return 0;
307
308 smp->data.type = SMP_T_STR;
309 smp->data.u.str.area = ptr;
310 smp->data.u.str.data = len;
311
312 smp->flags = SMP_F_VOL_1ST | SMP_F_CONST;
313 return 1;
314}
315
316/* 3. Check on Status Code. We manipulate integers here. */
317static int smp_fetch_stcode(const struct arg *args, struct sample *smp, const char *kw, void *private)
318{
319 struct http_txn *txn;
320 char *ptr;
321 int len;
322
323 CHECK_HTTP_MESSAGE_FIRST();
324
325 txn = smp->strm->txn;
326 if (txn->rsp.msg_state < HTTP_MSG_BODY)
327 return 0;
328
329 len = txn->rsp.sl.st.c_l;
330 ptr = ci_head(txn->rsp.chn) + txn->rsp.sl.st.c;
331
332 smp->data.type = SMP_T_SINT;
333 smp->data.u.sint = __strl2ui(ptr, len);
334 smp->flags = SMP_F_VOL_1ST;
335 return 1;
336}
337
338static int smp_fetch_uniqueid(const struct arg *args, struct sample *smp, const char *kw, void *private)
339{
340 if (LIST_ISEMPTY(&smp->sess->fe->format_unique_id))
341 return 0;
342
343 if (!smp->strm->unique_id) {
344 if ((smp->strm->unique_id = pool_alloc(pool_head_uniqueid)) == NULL)
345 return 0;
346 smp->strm->unique_id[0] = '\0';
347 }
348 smp->data.u.str.data = build_logline(smp->strm, smp->strm->unique_id,
349 UNIQUEID_LEN, &smp->sess->fe->format_unique_id);
350
351 smp->data.type = SMP_T_STR;
352 smp->data.u.str.area = smp->strm->unique_id;
353 smp->flags = SMP_F_CONST;
354 return 1;
355}
356
357/* Returns a string block containing all headers including the
358 * empty line wich separes headers from the body. This is useful
359 * form some headers analysis.
360 */
361static int smp_fetch_hdrs(const struct arg *args, struct sample *smp, const char *kw, void *private)
362{
363 struct http_msg *msg;
364 struct hdr_idx *idx;
365 struct http_txn *txn;
366
367 CHECK_HTTP_MESSAGE_FIRST();
368
369 txn = smp->strm->txn;
370 idx = &txn->hdr_idx;
371 msg = &txn->req;
372
373 smp->data.type = SMP_T_STR;
374 smp->data.u.str.area = ci_head(msg->chn) + hdr_idx_first_pos(idx);
375 smp->data.u.str.data = msg->eoh - hdr_idx_first_pos(idx) + 1 +
376 (ci_head(msg->chn)[msg->eoh] == '\r');
377
378 return 1;
379}
380
381/* Returns the header request in a length/value encoded format.
382 * This is useful for exchanges with the SPOE.
383 *
384 * A "length value" is a multibyte code encoding numbers. It uses the
385 * SPOE format. The encoding is the following:
386 *
387 * Each couple "header name" / "header value" is composed
388 * like this:
389 * "length value" "header name bytes"
390 * "length value" "header value bytes"
391 * When the last header is reached, the header name and the header
392 * value are empty. Their length are 0
393 */
394static int smp_fetch_hdrs_bin(const struct arg *args, struct sample *smp, const char *kw, void *private)
395{
396 struct http_msg *msg;
397 struct buffer *temp;
398 struct hdr_idx *idx;
399 const char *cur_ptr, *cur_next, *p;
400 int old_idx, cur_idx;
401 struct hdr_idx_elem *cur_hdr;
402 const char *hn, *hv;
403 int hnl, hvl;
404 int ret;
405 struct http_txn *txn;
406 char *buf;
407 char *end;
408
409 CHECK_HTTP_MESSAGE_FIRST();
410
411 temp = get_trash_chunk();
412 buf = temp->area;
413 end = temp->area + temp->size;
414
415 txn = smp->strm->txn;
416 idx = &txn->hdr_idx;
417 msg = &txn->req;
418
419 /* Build array of headers. */
420 old_idx = 0;
421 cur_next = ci_head(msg->chn) + hdr_idx_first_pos(idx);
422 while (1) {
423 cur_idx = idx->v[old_idx].next;
424 if (!cur_idx)
425 break;
426 old_idx = cur_idx;
427
428 cur_hdr = &idx->v[cur_idx];
429 cur_ptr = cur_next;
430 cur_next = cur_ptr + cur_hdr->len + cur_hdr->cr + 1;
431
432 /* Now we have one full header at cur_ptr of len cur_hdr->len,
433 * and the next header starts at cur_next. We'll check
434 * this header in the list as well as against the default
435 * rule.
436 */
437
438 /* look for ': *'. */
439 hn = cur_ptr;
440 for (p = cur_ptr; p < cur_ptr + cur_hdr->len && *p != ':'; p++);
441 if (p >= cur_ptr+cur_hdr->len)
442 continue;
443 hnl = p - hn;
444 p++;
445 while (p < cur_ptr + cur_hdr->len && (*p == ' ' || *p == '\t'))
446 p++;
447 if (p >= cur_ptr + cur_hdr->len)
448 continue;
449 hv = p;
450 hvl = cur_ptr + cur_hdr->len-p;
451
452 /* encode the header name. */
453 ret = encode_varint(hnl, &buf, end);
454 if (ret == -1)
455 return 0;
456 if (buf + hnl > end)
457 return 0;
458 memcpy(buf, hn, hnl);
459 buf += hnl;
460
461 /* encode and copy the value. */
462 ret = encode_varint(hvl, &buf, end);
463 if (ret == -1)
464 return 0;
465 if (buf + hvl > end)
466 return 0;
467 memcpy(buf, hv, hvl);
468 buf += hvl;
469 }
470
471 /* encode the end of the header list with empty
472 * header name and header value.
473 */
474 ret = encode_varint(0, &buf, end);
475 if (ret == -1)
476 return 0;
477 ret = encode_varint(0, &buf, end);
478 if (ret == -1)
479 return 0;
480
481 /* Initialise sample data which will be filled. */
482 smp->data.type = SMP_T_BIN;
483 smp->data.u.str.area = temp->area;
484 smp->data.u.str.data = buf - temp->area;
485 smp->data.u.str.size = temp->size;
486
487 return 1;
488}
489
490/* returns the longest available part of the body. This requires that the body
491 * has been waited for using http-buffer-request.
492 */
493static int smp_fetch_body(const struct arg *args, struct sample *smp, const char *kw, void *private)
494{
495 struct http_msg *msg;
496 unsigned long len;
497 unsigned long block1;
498 char *body;
499 struct buffer *temp;
500
501 CHECK_HTTP_MESSAGE_FIRST();
502
503 if ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_REQ)
504 msg = &smp->strm->txn->req;
505 else
506 msg = &smp->strm->txn->rsp;
507
508 len = http_body_bytes(msg);
509 body = c_ptr(msg->chn, -http_data_rewind(msg));
510
511 block1 = len;
512 if (block1 > b_wrap(&msg->chn->buf) - body)
513 block1 = b_wrap(&msg->chn->buf) - body;
514
515 if (block1 == len) {
516 /* buffer is not wrapped (or empty) */
517 smp->data.type = SMP_T_BIN;
518 smp->data.u.str.area = body;
519 smp->data.u.str.data = len;
520 smp->flags = SMP_F_VOL_TEST | SMP_F_CONST;
521 }
522 else {
523 /* buffer is wrapped, we need to defragment it */
524 temp = get_trash_chunk();
525 memcpy(temp->area, body, block1);
526 memcpy(temp->area + block1, b_orig(&msg->chn->buf),
527 len - block1);
528 smp->data.type = SMP_T_BIN;
529 smp->data.u.str.area = temp->area;
530 smp->data.u.str.data = len;
531 smp->flags = SMP_F_VOL_TEST;
532 }
533 return 1;
534}
535
536
537/* returns the available length of the body. This requires that the body
538 * has been waited for using http-buffer-request.
539 */
540static int smp_fetch_body_len(const struct arg *args, struct sample *smp, const char *kw, void *private)
541{
542 struct http_msg *msg;
543
544 CHECK_HTTP_MESSAGE_FIRST();
545
546 if ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_REQ)
547 msg = &smp->strm->txn->req;
548 else
549 msg = &smp->strm->txn->rsp;
550
551 smp->data.type = SMP_T_SINT;
552 smp->data.u.sint = http_body_bytes(msg);
553
554 smp->flags = SMP_F_VOL_TEST;
555 return 1;
556}
557
558
559/* returns the advertised length of the body, or the advertised size of the
560 * chunks available in the buffer. This requires that the body has been waited
561 * for using http-buffer-request.
562 */
563static int smp_fetch_body_size(const struct arg *args, struct sample *smp, const char *kw, void *private)
564{
565 struct http_msg *msg;
566
567 CHECK_HTTP_MESSAGE_FIRST();
568
569 if ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_REQ)
570 msg = &smp->strm->txn->req;
571 else
572 msg = &smp->strm->txn->rsp;
573
574 smp->data.type = SMP_T_SINT;
575 smp->data.u.sint = msg->body_len;
576
577 smp->flags = SMP_F_VOL_TEST;
578 return 1;
579}
580
581
582/* 4. Check on URL/URI. A pointer to the URI is stored. */
583static int smp_fetch_url(const struct arg *args, struct sample *smp, const char *kw, void *private)
584{
585 struct http_txn *txn;
586
587 CHECK_HTTP_MESSAGE_FIRST();
588
589 txn = smp->strm->txn;
590 smp->data.type = SMP_T_STR;
591 smp->data.u.str.data = txn->req.sl.rq.u_l;
592 smp->data.u.str.area = ci_head(txn->req.chn) + txn->req.sl.rq.u;
593 smp->flags = SMP_F_VOL_1ST | SMP_F_CONST;
594 return 1;
595}
596
597static int smp_fetch_url_ip(const struct arg *args, struct sample *smp, const char *kw, void *private)
598{
599 struct http_txn *txn;
600 struct sockaddr_storage addr;
601
602 CHECK_HTTP_MESSAGE_FIRST();
603
604 txn = smp->strm->txn;
605 url2sa(ci_head(txn->req.chn) + txn->req.sl.rq.u, txn->req.sl.rq.u_l, &addr, NULL);
606 if (((struct sockaddr_in *)&addr)->sin_family != AF_INET)
607 return 0;
608
609 smp->data.type = SMP_T_IPV4;
610 smp->data.u.ipv4 = ((struct sockaddr_in *)&addr)->sin_addr;
611 smp->flags = 0;
612 return 1;
613}
614
615static int smp_fetch_url_port(const struct arg *args, struct sample *smp, const char *kw, void *private)
616{
617 struct http_txn *txn;
618 struct sockaddr_storage addr;
619
620 CHECK_HTTP_MESSAGE_FIRST();
621
622 txn = smp->strm->txn;
623 url2sa(ci_head(txn->req.chn) + txn->req.sl.rq.u, txn->req.sl.rq.u_l, &addr, NULL);
624 if (((struct sockaddr_in *)&addr)->sin_family != AF_INET)
625 return 0;
626
627 smp->data.type = SMP_T_SINT;
628 smp->data.u.sint = ntohs(((struct sockaddr_in *)&addr)->sin_port);
629 smp->flags = 0;
630 return 1;
631}
632
633/* Fetch an HTTP header. A pointer to the beginning of the value is returned.
634 * Accepts an optional argument of type string containing the header field name,
635 * and an optional argument of type signed or unsigned integer to request an
636 * explicit occurrence of the header. Note that in the event of a missing name,
637 * headers are considered from the first one. It does not stop on commas and
638 * returns full lines instead (useful for User-Agent or Date for example).
639 */
640static int smp_fetch_fhdr(const struct arg *args, struct sample *smp, const char *kw, void *private)
641{
642 struct hdr_idx *idx;
643 struct hdr_ctx *ctx = smp->ctx.a[0];
644 const struct http_msg *msg;
645 int occ = 0;
646 const char *name_str = NULL;
647 int name_len = 0;
648
649 if (!ctx) {
650 /* first call */
651 ctx = &static_hdr_ctx;
652 ctx->idx = 0;
653 smp->ctx.a[0] = ctx;
654 }
655
656 if (args) {
657 if (args[0].type != ARGT_STR)
658 return 0;
659 name_str = args[0].data.str.area;
660 name_len = args[0].data.str.data;
661
662 if (args[1].type == ARGT_SINT)
663 occ = args[1].data.sint;
664 }
665
666 CHECK_HTTP_MESSAGE_FIRST();
667
668 idx = &smp->strm->txn->hdr_idx;
669 msg = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_REQ) ? &smp->strm->txn->req : &smp->strm->txn->rsp;
670
671 if (ctx && !(smp->flags & SMP_F_NOT_LAST))
672 /* search for header from the beginning */
673 ctx->idx = 0;
674
675 if (!occ && !(smp->opt & SMP_OPT_ITERATE))
676 /* no explicit occurrence and single fetch => last header by default */
677 occ = -1;
678
679 if (!occ)
680 /* prepare to report multiple occurrences for ACL fetches */
681 smp->flags |= SMP_F_NOT_LAST;
682
683 smp->data.type = SMP_T_STR;
684 smp->flags |= SMP_F_VOL_HDR | SMP_F_CONST;
685 if (http_get_fhdr(msg, name_str, name_len, idx, occ, ctx, &smp->data.u.str.area, &smp->data.u.str.data))
686 return 1;
687
688 smp->flags &= ~SMP_F_NOT_LAST;
689 return 0;
690}
691
692/* 6. Check on HTTP header count. The number of occurrences is returned.
693 * Accepts exactly 1 argument of type string. It does not stop on commas and
694 * returns full lines instead (useful for User-Agent or Date for example).
695 */
696static int smp_fetch_fhdr_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
697{
698 struct hdr_idx *idx;
699 struct hdr_ctx ctx;
700 const struct http_msg *msg;
701 int cnt;
702 const char *name = NULL;
703 int len = 0;
704
705 if (args && args->type == ARGT_STR) {
706 name = args->data.str.area;
707 len = args->data.str.data;
708 }
709
710 CHECK_HTTP_MESSAGE_FIRST();
711
712 idx = &smp->strm->txn->hdr_idx;
713 msg = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_REQ) ? &smp->strm->txn->req : &smp->strm->txn->rsp;
714
715 ctx.idx = 0;
716 cnt = 0;
717 while (http_find_full_header2(name, len, ci_head(msg->chn), idx, &ctx))
718 cnt++;
719
720 smp->data.type = SMP_T_SINT;
721 smp->data.u.sint = cnt;
722 smp->flags = SMP_F_VOL_HDR;
723 return 1;
724}
725
726static int smp_fetch_hdr_names(const struct arg *args, struct sample *smp, const char *kw, void *private)
727{
728 struct hdr_idx *idx;
729 struct hdr_ctx ctx;
730 const struct http_msg *msg;
731 struct buffer *temp;
732 char del = ',';
733
734 if (args && args->type == ARGT_STR)
735 del = *args[0].data.str.area;
736
737 CHECK_HTTP_MESSAGE_FIRST();
738
739 idx = &smp->strm->txn->hdr_idx;
740 msg = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_REQ) ? &smp->strm->txn->req : &smp->strm->txn->rsp;
741
742 temp = get_trash_chunk();
743
744 ctx.idx = 0;
745 while (http_find_next_header(ci_head(msg->chn), idx, &ctx)) {
746 if (temp->data)
747 temp->area[temp->data++] = del;
748 memcpy(temp->area + temp->data, ctx.line, ctx.del);
749 temp->data += ctx.del;
750 }
751
752 smp->data.type = SMP_T_STR;
753 smp->data.u.str.area = temp->area;
754 smp->data.u.str.data = temp->data;
755 smp->flags = SMP_F_VOL_HDR;
756 return 1;
757}
758
759/* Fetch an HTTP header. A pointer to the beginning of the value is returned.
760 * Accepts an optional argument of type string containing the header field name,
761 * and an optional argument of type signed or unsigned integer to request an
762 * explicit occurrence of the header. Note that in the event of a missing name,
763 * headers are considered from the first one.
764 */
765static int smp_fetch_hdr(const struct arg *args, struct sample *smp, const char *kw, void *private)
766{
767 struct hdr_idx *idx;
768 struct hdr_ctx *ctx = smp->ctx.a[0];
769 const struct http_msg *msg;
770 int occ = 0;
771 const char *name_str = NULL;
772 int name_len = 0;
773
774 if (!ctx) {
775 /* first call */
776 ctx = &static_hdr_ctx;
777 ctx->idx = 0;
778 smp->ctx.a[0] = ctx;
779 }
780
781 if (args) {
782 if (args[0].type != ARGT_STR)
783 return 0;
784 name_str = args[0].data.str.area;
785 name_len = args[0].data.str.data;
786
787 if (args[1].type == ARGT_SINT)
788 occ = args[1].data.sint;
789 }
790
791 CHECK_HTTP_MESSAGE_FIRST();
792
793 idx = &smp->strm->txn->hdr_idx;
794 msg = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_REQ) ? &smp->strm->txn->req : &smp->strm->txn->rsp;
795
796 if (ctx && !(smp->flags & SMP_F_NOT_LAST))
797 /* search for header from the beginning */
798 ctx->idx = 0;
799
800 if (!occ && !(smp->opt & SMP_OPT_ITERATE))
801 /* no explicit occurrence and single fetch => last header by default */
802 occ = -1;
803
804 if (!occ)
805 /* prepare to report multiple occurrences for ACL fetches */
806 smp->flags |= SMP_F_NOT_LAST;
807
808 smp->data.type = SMP_T_STR;
809 smp->flags |= SMP_F_VOL_HDR | SMP_F_CONST;
810 if (http_get_hdr(msg, name_str, name_len, idx, occ, ctx, &smp->data.u.str.area, &smp->data.u.str.data))
811 return 1;
812
813 smp->flags &= ~SMP_F_NOT_LAST;
814 return 0;
815}
816
817/* 6. Check on HTTP header count. The number of occurrences is returned.
818 * Accepts exactly 1 argument of type string.
819 */
820static int smp_fetch_hdr_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
821{
822 struct hdr_idx *idx;
823 struct hdr_ctx ctx;
824 const struct http_msg *msg;
825 int cnt;
826 const char *name = NULL;
827 int len = 0;
828
829 if (args && args->type == ARGT_STR) {
830 name = args->data.str.area;
831 len = args->data.str.data;
832 }
833
834 CHECK_HTTP_MESSAGE_FIRST();
835
836 idx = &smp->strm->txn->hdr_idx;
837 msg = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_REQ) ? &smp->strm->txn->req : &smp->strm->txn->rsp;
838
839 ctx.idx = 0;
840 cnt = 0;
841 while (http_find_header2(name, len, ci_head(msg->chn), idx, &ctx))
842 cnt++;
843
844 smp->data.type = SMP_T_SINT;
845 smp->data.u.sint = cnt;
846 smp->flags = SMP_F_VOL_HDR;
847 return 1;
848}
849
850/* Fetch an HTTP header's integer value. The integer value is returned. It
851 * takes a mandatory argument of type string and an optional one of type int
852 * to designate a specific occurrence. It returns an unsigned integer, which
853 * may or may not be appropriate for everything.
854 */
855static int smp_fetch_hdr_val(const struct arg *args, struct sample *smp, const char *kw, void *private)
856{
857 int ret = smp_fetch_hdr(args, smp, kw, private);
858
859 if (ret > 0) {
860 smp->data.type = SMP_T_SINT;
861 smp->data.u.sint = strl2ic(smp->data.u.str.area,
862 smp->data.u.str.data);
863 }
864
865 return ret;
866}
867
868/* Fetch an HTTP header's IP value. takes a mandatory argument of type string
869 * and an optional one of type int to designate a specific occurrence.
870 * It returns an IPv4 or IPv6 address.
871 */
872static int smp_fetch_hdr_ip(const struct arg *args, struct sample *smp, const char *kw, void *private)
873{
874 int ret;
875
876 while ((ret = smp_fetch_hdr(args, smp, kw, private)) > 0) {
877 if (url2ipv4((char *) smp->data.u.str.area, &smp->data.u.ipv4)) {
878 smp->data.type = SMP_T_IPV4;
879 break;
880 } else {
881 struct buffer *temp = get_trash_chunk();
882 if (smp->data.u.str.data < temp->size - 1) {
883 memcpy(temp->area, smp->data.u.str.area,
884 smp->data.u.str.data);
885 temp->area[smp->data.u.str.data] = '\0';
886 if (inet_pton(AF_INET6, temp->area, &smp->data.u.ipv6)) {
887 smp->data.type = SMP_T_IPV6;
888 break;
889 }
890 }
891 }
892
893 /* if the header doesn't match an IP address, fetch next one */
894 if (!(smp->flags & SMP_F_NOT_LAST))
895 return 0;
896 }
897 return ret;
898}
899
900/* 8. Check on URI PATH. A pointer to the PATH is stored. The path starts at
901 * the first '/' after the possible hostname, and ends before the possible '?'.
902 */
903static int smp_fetch_path(const struct arg *args, struct sample *smp, const char *kw, void *private)
904{
905 struct http_txn *txn;
906 char *ptr, *end;
907
908 CHECK_HTTP_MESSAGE_FIRST();
909
910 txn = smp->strm->txn;
911 end = ci_head(txn->req.chn) + txn->req.sl.rq.u + txn->req.sl.rq.u_l;
912 ptr = http_txn_get_path(txn);
913 if (!ptr)
914 return 0;
915
916 /* OK, we got the '/' ! */
917 smp->data.type = SMP_T_STR;
918 smp->data.u.str.area = ptr;
919
920 while (ptr < end && *ptr != '?')
921 ptr++;
922
923 smp->data.u.str.data = ptr - smp->data.u.str.area;
924 smp->flags = SMP_F_VOL_1ST | SMP_F_CONST;
925 return 1;
926}
927
928/* This produces a concatenation of the first occurrence of the Host header
929 * followed by the path component if it begins with a slash ('/'). This means
930 * that '*' will not be added, resulting in exactly the first Host entry.
931 * If no Host header is found, then the path is returned as-is. The returned
932 * value is stored in the trash so it does not need to be marked constant.
933 * The returned sample is of type string.
934 */
935static int smp_fetch_base(const struct arg *args, struct sample *smp, const char *kw, void *private)
936{
937 struct http_txn *txn;
938 char *ptr, *end, *beg;
939 struct hdr_ctx ctx;
940 struct buffer *temp;
941
942 CHECK_HTTP_MESSAGE_FIRST();
943
944 txn = smp->strm->txn;
945 ctx.idx = 0;
946 if (!http_find_header2("Host", 4, ci_head(txn->req.chn), &txn->hdr_idx, &ctx) || !ctx.vlen)
947 return smp_fetch_path(args, smp, kw, private);
948
949 /* OK we have the header value in ctx.line+ctx.val for ctx.vlen bytes */
950 temp = get_trash_chunk();
951 memcpy(temp->area, ctx.line + ctx.val, ctx.vlen);
952 smp->data.type = SMP_T_STR;
953 smp->data.u.str.area = temp->area;
954 smp->data.u.str.data = ctx.vlen;
955
956 /* now retrieve the path */
957 end = ci_head(txn->req.chn) + txn->req.sl.rq.u + txn->req.sl.rq.u_l;
958 beg = http_txn_get_path(txn);
959 if (!beg)
960 beg = end;
961
962 for (ptr = beg; ptr < end && *ptr != '?'; ptr++);
963
964 if (beg < ptr && *beg == '/') {
965 memcpy(smp->data.u.str.area + smp->data.u.str.data, beg,
966 ptr - beg);
967 smp->data.u.str.data += ptr - beg;
968 }
969
970 smp->flags = SMP_F_VOL_1ST;
971 return 1;
972}
973
974/* This produces a 32-bit hash of the concatenation of the first occurrence of
975 * the Host header followed by the path component if it begins with a slash ('/').
976 * This means that '*' will not be added, resulting in exactly the first Host
977 * entry. If no Host header is found, then the path is used. The resulting value
978 * is hashed using the path hash followed by a full avalanche hash and provides a
979 * 32-bit integer value. This fetch is useful for tracking per-path activity on
980 * high-traffic sites without having to store whole paths.
981 */
982static int smp_fetch_base32(const struct arg *args, struct sample *smp, const char *kw, void *private)
983{
984 struct http_txn *txn;
985 struct hdr_ctx ctx;
986 unsigned int hash = 0;
987 char *ptr, *beg, *end;
988 int len;
989
990 CHECK_HTTP_MESSAGE_FIRST();
991
992 txn = smp->strm->txn;
993 ctx.idx = 0;
994 if (http_find_header2("Host", 4, ci_head(txn->req.chn), &txn->hdr_idx, &ctx)) {
995 /* OK we have the header value in ctx.line+ctx.val for ctx.vlen bytes */
996 ptr = ctx.line + ctx.val;
997 len = ctx.vlen;
998 while (len--)
999 hash = *(ptr++) + (hash << 6) + (hash << 16) - hash;
1000 }
1001
1002 /* now retrieve the path */
1003 end = ci_head(txn->req.chn) + txn->req.sl.rq.u + txn->req.sl.rq.u_l;
1004 beg = http_txn_get_path(txn);
1005 if (!beg)
1006 beg = end;
1007
1008 for (ptr = beg; ptr < end && *ptr != '?'; ptr++);
1009
1010 if (beg < ptr && *beg == '/') {
1011 while (beg < ptr)
1012 hash = *(beg++) + (hash << 6) + (hash << 16) - hash;
1013 }
1014 hash = full_hash(hash);
1015
1016 smp->data.type = SMP_T_SINT;
1017 smp->data.u.sint = hash;
1018 smp->flags = SMP_F_VOL_1ST;
1019 return 1;
1020}
1021
1022/* This concatenates the source address with the 32-bit hash of the Host and
1023 * path as returned by smp_fetch_base32(). The idea is to have per-source and
1024 * per-path counters. The result is a binary block from 8 to 20 bytes depending
1025 * on the source address length. The path hash is stored before the address so
1026 * that in environments where IPv6 is insignificant, truncating the output to
1027 * 8 bytes would still work.
1028 */
1029static int smp_fetch_base32_src(const struct arg *args, struct sample *smp, const char *kw, void *private)
1030{
1031 struct buffer *temp;
1032 struct connection *cli_conn = objt_conn(smp->sess->origin);
1033
1034 if (!cli_conn)
1035 return 0;
1036
1037 if (!smp_fetch_base32(args, smp, kw, private))
1038 return 0;
1039
1040 temp = get_trash_chunk();
1041 *(unsigned int *) temp->area = htonl(smp->data.u.sint);
1042 temp->data += sizeof(unsigned int);
1043
1044 switch (cli_conn->addr.from.ss_family) {
1045 case AF_INET:
1046 memcpy(temp->area + temp->data,
1047 &((struct sockaddr_in *)&cli_conn->addr.from)->sin_addr,
1048 4);
1049 temp->data += 4;
1050 break;
1051 case AF_INET6:
1052 memcpy(temp->area + temp->data,
1053 &((struct sockaddr_in6 *)&cli_conn->addr.from)->sin6_addr,
1054 16);
1055 temp->data += 16;
1056 break;
1057 default:
1058 return 0;
1059 }
1060
1061 smp->data.u.str = *temp;
1062 smp->data.type = SMP_T_BIN;
1063 return 1;
1064}
1065
1066/* Extracts the query string, which comes after the question mark '?'. If no
1067 * question mark is found, nothing is returned. Otherwise it returns a sample
1068 * of type string carrying the whole query string.
1069 */
1070static int smp_fetch_query(const struct arg *args, struct sample *smp, const char *kw, void *private)
1071{
1072 struct http_txn *txn;
1073 char *ptr, *end;
1074
1075 CHECK_HTTP_MESSAGE_FIRST();
1076
1077 txn = smp->strm->txn;
1078 ptr = ci_head(txn->req.chn) + txn->req.sl.rq.u;
1079 end = ptr + txn->req.sl.rq.u_l;
1080
1081 /* look up the '?' */
1082 do {
1083 if (ptr == end)
1084 return 0;
1085 } while (*ptr++ != '?');
1086
1087 smp->data.type = SMP_T_STR;
1088 smp->data.u.str.area = ptr;
1089 smp->data.u.str.data = end - ptr;
1090 smp->flags = SMP_F_VOL_1ST | SMP_F_CONST;
1091 return 1;
1092}
1093
1094static int smp_fetch_proto_http(const struct arg *args, struct sample *smp, const char *kw, void *private)
1095{
1096 /* Note: hdr_idx.v cannot be NULL in this ACL because the ACL is tagged
1097 * as a layer7 ACL, which involves automatic allocation of hdr_idx.
1098 */
1099
1100 CHECK_HTTP_MESSAGE_FIRST_PERM();
1101
1102 smp->data.type = SMP_T_BOOL;
1103 smp->data.u.sint = 1;
1104 return 1;
1105}
1106
1107/* return a valid test if the current request is the first one on the connection */
1108static int smp_fetch_http_first_req(const struct arg *args, struct sample *smp, const char *kw, void *private)
1109{
1110 smp->data.type = SMP_T_BOOL;
1111 smp->data.u.sint = !(smp->strm->txn->flags & TX_NOT_FIRST);
1112 return 1;
1113}
1114
1115/* Accepts exactly 1 argument of type userlist */
1116static int smp_fetch_http_auth(const struct arg *args, struct sample *smp, const char *kw, void *private)
1117{
1118
1119 if (!args || args->type != ARGT_USR)
1120 return 0;
1121
1122 CHECK_HTTP_MESSAGE_FIRST();
1123
1124 if (!get_http_auth(smp->strm))
1125 return 0;
1126
1127 smp->data.type = SMP_T_BOOL;
1128 smp->data.u.sint = check_user(args->data.usr, smp->strm->txn->auth.user,
1129 smp->strm->txn->auth.pass);
1130 return 1;
1131}
1132
1133/* Accepts exactly 1 argument of type userlist */
1134static int smp_fetch_http_auth_grp(const struct arg *args, struct sample *smp, const char *kw, void *private)
1135{
1136 if (!args || args->type != ARGT_USR)
1137 return 0;
1138
1139 CHECK_HTTP_MESSAGE_FIRST();
1140
1141 if (!get_http_auth(smp->strm))
1142 return 0;
1143
1144 /* if the user does not belong to the userlist or has a wrong password,
1145 * report that it unconditionally does not match. Otherwise we return
1146 * a string containing the username.
1147 */
1148 if (!check_user(args->data.usr, smp->strm->txn->auth.user,
1149 smp->strm->txn->auth.pass))
1150 return 0;
1151
1152 /* pat_match_auth() will need the user list */
1153 smp->ctx.a[0] = args->data.usr;
1154
1155 smp->data.type = SMP_T_STR;
1156 smp->flags = SMP_F_CONST;
1157 smp->data.u.str.area = smp->strm->txn->auth.user;
1158 smp->data.u.str.data = strlen(smp->strm->txn->auth.user);
1159
1160 return 1;
1161}
1162
1163/* Fetch a captured HTTP request header. The index is the position of
1164 * the "capture" option in the configuration file
1165 */
1166static int smp_fetch_capture_req_hdr(const struct arg *args, struct sample *smp, const char *kw, void *private)
1167{
1168 struct proxy *fe = strm_fe(smp->strm);
1169 int idx;
1170
1171 if (!args || args->type != ARGT_SINT)
1172 return 0;
1173
1174 idx = args->data.sint;
1175
1176 if (idx > (fe->nb_req_cap - 1) || smp->strm->req_cap == NULL || smp->strm->req_cap[idx] == NULL)
1177 return 0;
1178
1179 smp->data.type = SMP_T_STR;
1180 smp->flags |= SMP_F_CONST;
1181 smp->data.u.str.area = smp->strm->req_cap[idx];
1182 smp->data.u.str.data = strlen(smp->strm->req_cap[idx]);
1183
1184 return 1;
1185}
1186
1187/* Fetch a captured HTTP response header. The index is the position of
1188 * the "capture" option in the configuration file
1189 */
1190static int smp_fetch_capture_res_hdr(const struct arg *args, struct sample *smp, const char *kw, void *private)
1191{
1192 struct proxy *fe = strm_fe(smp->strm);
1193 int idx;
1194
1195 if (!args || args->type != ARGT_SINT)
1196 return 0;
1197
1198 idx = args->data.sint;
1199
1200 if (idx > (fe->nb_rsp_cap - 1) || smp->strm->res_cap == NULL || smp->strm->res_cap[idx] == NULL)
1201 return 0;
1202
1203 smp->data.type = SMP_T_STR;
1204 smp->flags |= SMP_F_CONST;
1205 smp->data.u.str.area = smp->strm->res_cap[idx];
1206 smp->data.u.str.data = strlen(smp->strm->res_cap[idx]);
1207
1208 return 1;
1209}
1210
1211/* Extracts the METHOD in the HTTP request, the txn->uri should be filled before the call */
1212static int smp_fetch_capture_req_method(const struct arg *args, struct sample *smp, const char *kw, void *private)
1213{
1214 struct buffer *temp;
1215 struct http_txn *txn = smp->strm->txn;
1216 char *ptr;
1217
1218 if (!txn || !txn->uri)
1219 return 0;
1220
1221 ptr = txn->uri;
1222
1223 while (*ptr != ' ' && *ptr != '\0') /* find first space */
1224 ptr++;
1225
1226 temp = get_trash_chunk();
1227 temp->area = txn->uri;
1228 temp->data = ptr - txn->uri;
1229 smp->data.u.str = *temp;
1230 smp->data.type = SMP_T_STR;
1231 smp->flags = SMP_F_CONST;
1232
1233 return 1;
1234
1235}
1236
1237/* Extracts the path in the HTTP request, the txn->uri should be filled before the call */
1238static int smp_fetch_capture_req_uri(const struct arg *args, struct sample *smp, const char *kw, void *private)
1239{
1240 struct http_txn *txn = smp->strm->txn;
1241 struct ist path;
1242 const char *ptr;
1243
1244 if (!txn || !txn->uri)
1245 return 0;
1246
1247 ptr = txn->uri;
1248
1249 while (*ptr != ' ' && *ptr != '\0') /* find first space */
1250 ptr++;
1251
1252 if (!*ptr)
1253 return 0;
1254
1255 ptr++; /* skip the space */
1256
1257 path = http_get_path(ist(ptr));
1258 if (!path.ptr)
1259 return 0;
1260
1261 smp->data.u.str.area = path.ptr;
1262 smp->data.u.str.data = path.len;
1263 smp->data.type = SMP_T_STR;
1264 smp->flags = SMP_F_CONST;
1265
1266 return 1;
1267}
1268
1269/* Retrieves the HTTP version from the request (either 1.0 or 1.1) and emits it
1270 * as a string (either "HTTP/1.0" or "HTTP/1.1").
1271 */
1272static int smp_fetch_capture_req_ver(const struct arg *args, struct sample *smp, const char *kw, void *private)
1273{
1274 struct http_txn *txn = smp->strm->txn;
1275
1276 if (!txn || txn->req.msg_state < HTTP_MSG_HDR_FIRST)
1277 return 0;
1278
1279 if (txn->req.flags & HTTP_MSGF_VER_11)
1280 smp->data.u.str.area = "HTTP/1.1";
1281 else
1282 smp->data.u.str.area = "HTTP/1.0";
1283
1284 smp->data.u.str.data = 8;
1285 smp->data.type = SMP_T_STR;
1286 smp->flags = SMP_F_CONST;
1287 return 1;
1288
1289}
1290
1291/* Retrieves the HTTP version from the response (either 1.0 or 1.1) and emits it
1292 * as a string (either "HTTP/1.0" or "HTTP/1.1").
1293 */
1294static int smp_fetch_capture_res_ver(const struct arg *args, struct sample *smp, const char *kw, void *private)
1295{
1296 struct http_txn *txn = smp->strm->txn;
1297
1298 if (!txn || txn->rsp.msg_state < HTTP_MSG_HDR_FIRST)
1299 return 0;
1300
1301 if (txn->rsp.flags & HTTP_MSGF_VER_11)
1302 smp->data.u.str.area = "HTTP/1.1";
1303 else
1304 smp->data.u.str.area = "HTTP/1.0";
1305
1306 smp->data.u.str.data = 8;
1307 smp->data.type = SMP_T_STR;
1308 smp->flags = SMP_F_CONST;
1309 return 1;
1310
1311}
1312
1313/* Iterate over all cookies present in a message. The context is stored in
1314 * smp->ctx.a[0] for the in-header position, smp->ctx.a[1] for the
1315 * end-of-header-value, and smp->ctx.a[2] for the hdr_ctx. Depending on
1316 * the direction, multiple cookies may be parsed on the same line or not.
1317 * The cookie name is in args and the name length in args->data.str.len.
1318 * Accepts exactly 1 argument of type string. If the input options indicate
1319 * that no iterating is desired, then only last value is fetched if any.
1320 * The returned sample is of type CSTR. Can be used to parse cookies in other
1321 * files.
1322 */
1323static int smp_fetch_cookie(const struct arg *args, struct sample *smp, const char *kw, void *private)
1324{
1325 struct http_txn *txn;
1326 struct hdr_idx *idx;
1327 struct hdr_ctx *ctx = smp->ctx.a[2];
1328 const struct http_msg *msg;
1329 const char *hdr_name;
1330 int hdr_name_len;
1331 char *sol;
1332 int occ = 0;
1333 int found = 0;
1334
1335 if (!args || args->type != ARGT_STR)
1336 return 0;
1337
1338 if (!ctx) {
1339 /* first call */
1340 ctx = &static_hdr_ctx;
1341 ctx->idx = 0;
1342 smp->ctx.a[2] = ctx;
1343 }
1344
1345 CHECK_HTTP_MESSAGE_FIRST();
1346
1347 txn = smp->strm->txn;
1348 idx = &smp->strm->txn->hdr_idx;
1349
1350 if ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_REQ) {
1351 msg = &txn->req;
1352 hdr_name = "Cookie";
1353 hdr_name_len = 6;
1354 } else {
1355 msg = &txn->rsp;
1356 hdr_name = "Set-Cookie";
1357 hdr_name_len = 10;
1358 }
1359
1360 if (!occ && !(smp->opt & SMP_OPT_ITERATE))
1361 /* no explicit occurrence and single fetch => last cookie by default */
1362 occ = -1;
1363
1364 /* OK so basically here, either we want only one value and it's the
1365 * last one, or we want to iterate over all of them and we fetch the
1366 * next one.
1367 */
1368
1369 sol = ci_head(msg->chn);
1370 if (!(smp->flags & SMP_F_NOT_LAST)) {
1371 /* search for the header from the beginning, we must first initialize
1372 * the search parameters.
1373 */
1374 smp->ctx.a[0] = NULL;
1375 ctx->idx = 0;
1376 }
1377
1378 smp->flags |= SMP_F_VOL_HDR;
1379
1380 while (1) {
1381 /* Note: smp->ctx.a[0] == NULL every time we need to fetch a new header */
1382 if (!smp->ctx.a[0]) {
1383 if (!http_find_header2(hdr_name, hdr_name_len, sol, idx, ctx))
1384 goto out;
1385
1386 if (ctx->vlen < args->data.str.data + 1)
1387 continue;
1388
1389 smp->ctx.a[0] = ctx->line + ctx->val;
1390 smp->ctx.a[1] = smp->ctx.a[0] + ctx->vlen;
1391 }
1392
1393 smp->data.type = SMP_T_STR;
1394 smp->flags |= SMP_F_CONST;
1395 smp->ctx.a[0] = http_extract_cookie_value(smp->ctx.a[0], smp->ctx.a[1],
1396 args->data.str.area, args->data.str.data,
1397 (smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_REQ,
1398 &smp->data.u.str.area, &smp->data.u.str.data);
1399 if (smp->ctx.a[0]) {
1400 found = 1;
1401 if (occ >= 0) {
1402 /* one value was returned into smp->data.u.str.{str,len} */
1403 smp->flags |= SMP_F_NOT_LAST;
1404 return 1;
1405 }
1406 }
1407 /* if we're looking for last occurrence, let's loop */
1408 }
1409 /* all cookie headers and values were scanned. If we're looking for the
1410 * last occurrence, we may return it now.
1411 */
1412 out:
1413 smp->flags &= ~SMP_F_NOT_LAST;
1414 return found;
1415}
1416
1417/* Iterate over all cookies present in a request to count how many occurrences
1418 * match the name in args and args->data.str.len. If <multi> is non-null, then
1419 * multiple cookies may be parsed on the same line. The returned sample is of
1420 * type UINT. Accepts exactly 1 argument of type string.
1421 */
1422static int smp_fetch_cookie_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
1423{
1424 struct http_txn *txn;
1425 struct hdr_idx *idx;
1426 struct hdr_ctx ctx;
1427 const struct http_msg *msg;
1428 const char *hdr_name;
1429 int hdr_name_len;
1430 int cnt;
1431 char *val_beg, *val_end;
1432 char *sol;
1433
1434 if (!args || args->type != ARGT_STR)
1435 return 0;
1436
1437 CHECK_HTTP_MESSAGE_FIRST();
1438
1439 txn = smp->strm->txn;
1440 idx = &smp->strm->txn->hdr_idx;
1441
1442 if ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_REQ) {
1443 msg = &txn->req;
1444 hdr_name = "Cookie";
1445 hdr_name_len = 6;
1446 } else {
1447 msg = &txn->rsp;
1448 hdr_name = "Set-Cookie";
1449 hdr_name_len = 10;
1450 }
1451
1452 sol = ci_head(msg->chn);
1453 val_end = val_beg = NULL;
1454 ctx.idx = 0;
1455 cnt = 0;
1456
1457 while (1) {
1458 /* Note: val_beg == NULL every time we need to fetch a new header */
1459 if (!val_beg) {
1460 if (!http_find_header2(hdr_name, hdr_name_len, sol, idx, &ctx))
1461 break;
1462
1463 if (ctx.vlen < args->data.str.data + 1)
1464 continue;
1465
1466 val_beg = ctx.line + ctx.val;
1467 val_end = val_beg + ctx.vlen;
1468 }
1469
1470 smp->data.type = SMP_T_STR;
1471 smp->flags |= SMP_F_CONST;
1472 while ((val_beg = http_extract_cookie_value(val_beg, val_end,
1473 args->data.str.area, args->data.str.data,
1474 (smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_REQ,
1475 &smp->data.u.str.area, &smp->data.u.str.data))) {
1476 cnt++;
1477 }
1478 }
1479
1480 smp->data.type = SMP_T_SINT;
1481 smp->data.u.sint = cnt;
1482 smp->flags |= SMP_F_VOL_HDR;
1483 return 1;
1484}
1485
1486/* Fetch an cookie's integer value. The integer value is returned. It
1487 * takes a mandatory argument of type string. It relies on smp_fetch_cookie().
1488 */
1489static int smp_fetch_cookie_val(const struct arg *args, struct sample *smp, const char *kw, void *private)
1490{
1491 int ret = smp_fetch_cookie(args, smp, kw, private);
1492
1493 if (ret > 0) {
1494 smp->data.type = SMP_T_SINT;
1495 smp->data.u.sint = strl2ic(smp->data.u.str.area,
1496 smp->data.u.str.data);
1497 }
1498
1499 return ret;
1500}
1501
1502/************************************************************************/
1503/* The code below is dedicated to sample fetches */
1504/************************************************************************/
1505
1506/* This scans a URL-encoded query string. It takes an optionally wrapping
1507 * string whose first contigous chunk has its beginning in ctx->a[0] and end
1508 * in ctx->a[1], and the optional second part in (ctx->a[2]..ctx->a[3]). The
1509 * pointers are updated for next iteration before leaving.
1510 */
1511static int smp_fetch_param(char delim, const char *name, int name_len, const struct arg *args, struct sample *smp, const char *kw, void *private)
1512{
1513 const char *vstart, *vend;
1514 struct buffer *temp;
1515 const char **chunks = (const char **)smp->ctx.a;
1516
1517 if (!http_find_next_url_param(chunks, name, name_len,
1518 &vstart, &vend, delim))
1519 return 0;
1520
1521 /* Create sample. If the value is contiguous, return the pointer as CONST,
1522 * if the value is wrapped, copy-it in a buffer.
1523 */
1524 smp->data.type = SMP_T_STR;
1525 if (chunks[2] &&
1526 vstart >= chunks[0] && vstart <= chunks[1] &&
1527 vend >= chunks[2] && vend <= chunks[3]) {
1528 /* Wrapped case. */
1529 temp = get_trash_chunk();
1530 memcpy(temp->area, vstart, chunks[1] - vstart);
1531 memcpy(temp->area + ( chunks[1] - vstart ), chunks[2],
1532 vend - chunks[2]);
1533 smp->data.u.str.area = temp->area;
1534 smp->data.u.str.data = ( chunks[1] - vstart ) + ( vend - chunks[2] );
1535 } else {
1536 /* Contiguous case. */
1537 smp->data.u.str.area = (char *)vstart;
1538 smp->data.u.str.data = vend - vstart;
1539 smp->flags = SMP_F_VOL_1ST | SMP_F_CONST;
1540 }
1541
1542 /* Update context, check wrapping. */
1543 chunks[0] = vend;
1544 if (chunks[2] && vend >= chunks[2] && vend <= chunks[3]) {
1545 chunks[1] = chunks[3];
1546 chunks[2] = NULL;
1547 }
1548
1549 if (chunks[0] < chunks[1])
1550 smp->flags |= SMP_F_NOT_LAST;
1551
1552 return 1;
1553}
1554
1555/* This function iterates over each parameter of the query string. It uses
1556 * ctx->a[0] and ctx->a[1] to store the beginning and end of the current
1557 * parameter. Since it uses smp_fetch_param(), ctx->a[2..3] are both NULL.
1558 * An optional parameter name is passed in args[0], otherwise any parameter is
1559 * considered. It supports an optional delimiter argument for the beginning of
1560 * the string in args[1], which defaults to "?".
1561 */
1562static int smp_fetch_url_param(const struct arg *args, struct sample *smp, const char *kw, void *private)
1563{
1564 struct http_msg *msg;
1565 char delim = '?';
1566 const char *name;
1567 int name_len;
1568
1569 if (!args ||
1570 (args[0].type && args[0].type != ARGT_STR) ||
1571 (args[1].type && args[1].type != ARGT_STR))
1572 return 0;
1573
1574 name = "";
1575 name_len = 0;
1576 if (args->type == ARGT_STR) {
1577 name = args->data.str.area;
1578 name_len = args->data.str.data;
1579 }
1580
1581 if (args[1].type)
1582 delim = *args[1].data.str.area;
1583
1584 if (!smp->ctx.a[0]) { // first call, find the query string
1585 CHECK_HTTP_MESSAGE_FIRST();
1586
1587 msg = &smp->strm->txn->req;
1588
1589 smp->ctx.a[0] = http_find_param_list(ci_head(msg->chn) + msg->sl.rq.u,
1590 msg->sl.rq.u_l, delim);
1591 if (!smp->ctx.a[0])
1592 return 0;
1593
1594 smp->ctx.a[1] = ci_head(msg->chn) + msg->sl.rq.u + msg->sl.rq.u_l;
1595
1596 /* Assume that the context is filled with NULL pointer
1597 * before the first call.
1598 * smp->ctx.a[2] = NULL;
1599 * smp->ctx.a[3] = NULL;
1600 */
1601 }
1602
1603 return smp_fetch_param(delim, name, name_len, args, smp, kw, private);
1604}
1605
1606/* This function iterates over each parameter of the body. This requires
1607 * that the body has been waited for using http-buffer-request. It uses
1608 * ctx->a[0] and ctx->a[1] to store the beginning and end of the first
1609 * contigous part of the body, and optionally ctx->a[2..3] to reference the
1610 * optional second part if the body wraps at the end of the buffer. An optional
1611 * parameter name is passed in args[0], otherwise any parameter is considered.
1612 */
1613static int smp_fetch_body_param(const struct arg *args, struct sample *smp, const char *kw, void *private)
1614{
1615 struct http_msg *msg;
1616 unsigned long len;
1617 unsigned long block1;
1618 char *body;
1619 const char *name;
1620 int name_len;
1621
1622 if (!args || (args[0].type && args[0].type != ARGT_STR))
1623 return 0;
1624
1625 name = "";
1626 name_len = 0;
1627 if (args[0].type == ARGT_STR) {
1628 name = args[0].data.str.area;
1629 name_len = args[0].data.str.data;
1630 }
1631
1632 if (!smp->ctx.a[0]) { // first call, find the query string
1633 CHECK_HTTP_MESSAGE_FIRST();
1634
1635 if ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_REQ)
1636 msg = &smp->strm->txn->req;
1637 else
1638 msg = &smp->strm->txn->rsp;
1639
1640 len = http_body_bytes(msg);
1641 body = c_ptr(msg->chn, -http_data_rewind(msg));
1642
1643 block1 = len;
1644 if (block1 > b_wrap(&msg->chn->buf) - body)
1645 block1 = b_wrap(&msg->chn->buf) - body;
1646
1647 if (block1 == len) {
1648 /* buffer is not wrapped (or empty) */
1649 smp->ctx.a[0] = body;
1650 smp->ctx.a[1] = body + len;
1651
1652 /* Assume that the context is filled with NULL pointer
1653 * before the first call.
1654 * smp->ctx.a[2] = NULL;
1655 * smp->ctx.a[3] = NULL;
1656 */
1657 }
1658 else {
1659 /* buffer is wrapped, we need to defragment it */
1660 smp->ctx.a[0] = body;
1661 smp->ctx.a[1] = body + block1;
1662 smp->ctx.a[2] = b_orig(&msg->chn->buf);
1663 smp->ctx.a[3] = b_orig(&msg->chn->buf) + ( len - block1 );
1664 }
1665 }
1666 return smp_fetch_param('&', name, name_len, args, smp, kw, private);
1667}
1668
1669/* Return the signed integer value for the specified url parameter (see url_param
1670 * above).
1671 */
1672static int smp_fetch_url_param_val(const struct arg *args, struct sample *smp, const char *kw, void *private)
1673{
1674 int ret = smp_fetch_url_param(args, smp, kw, private);
1675
1676 if (ret > 0) {
1677 smp->data.type = SMP_T_SINT;
1678 smp->data.u.sint = strl2ic(smp->data.u.str.area,
1679 smp->data.u.str.data);
1680 }
1681
1682 return ret;
1683}
1684
1685/* This produces a 32-bit hash of the concatenation of the first occurrence of
1686 * the Host header followed by the path component if it begins with a slash ('/').
1687 * This means that '*' will not be added, resulting in exactly the first Host
1688 * entry. If no Host header is found, then the path is used. The resulting value
1689 * is hashed using the url hash followed by a full avalanche hash and provides a
1690 * 32-bit integer value. This fetch is useful for tracking per-URL activity on
1691 * high-traffic sites without having to store whole paths.
1692 * this differs from the base32 functions in that it includes the url parameters
1693 * as well as the path
1694 */
1695static int smp_fetch_url32(const struct arg *args, struct sample *smp, const char *kw, void *private)
1696{
1697 struct http_txn *txn;
1698 struct hdr_ctx ctx;
1699 unsigned int hash = 0;
1700 char *ptr, *beg, *end;
1701 int len;
1702
1703 CHECK_HTTP_MESSAGE_FIRST();
1704
1705 txn = smp->strm->txn;
1706 ctx.idx = 0;
1707 if (http_find_header2("Host", 4, ci_head(txn->req.chn), &txn->hdr_idx, &ctx)) {
1708 /* OK we have the header value in ctx.line+ctx.val for ctx.vlen bytes */
1709 ptr = ctx.line + ctx.val;
1710 len = ctx.vlen;
1711 while (len--)
1712 hash = *(ptr++) + (hash << 6) + (hash << 16) - hash;
1713 }
1714
1715 /* now retrieve the path */
1716 end = ci_head(txn->req.chn) + txn->req.sl.rq.u + txn->req.sl.rq.u_l;
1717 beg = http_txn_get_path(txn);
1718 if (!beg)
1719 beg = end;
1720
1721 for (ptr = beg; ptr < end ; ptr++);
1722
1723 if (beg < ptr && *beg == '/') {
1724 while (beg < ptr)
1725 hash = *(beg++) + (hash << 6) + (hash << 16) - hash;
1726 }
1727 hash = full_hash(hash);
1728
1729 smp->data.type = SMP_T_SINT;
1730 smp->data.u.sint = hash;
1731 smp->flags = SMP_F_VOL_1ST;
1732 return 1;
1733}
1734
1735/* This concatenates the source address with the 32-bit hash of the Host and
1736 * URL as returned by smp_fetch_base32(). The idea is to have per-source and
1737 * per-url counters. The result is a binary block from 8 to 20 bytes depending
1738 * on the source address length. The URL hash is stored before the address so
1739 * that in environments where IPv6 is insignificant, truncating the output to
1740 * 8 bytes would still work.
1741 */
1742static int smp_fetch_url32_src(const struct arg *args, struct sample *smp, const char *kw, void *private)
1743{
1744 struct buffer *temp;
1745 struct connection *cli_conn = objt_conn(smp->sess->origin);
1746
1747 if (!cli_conn)
1748 return 0;
1749
1750 if (!smp_fetch_url32(args, smp, kw, private))
1751 return 0;
1752
1753 temp = get_trash_chunk();
1754 *(unsigned int *) temp->area = htonl(smp->data.u.sint);
1755 temp->data += sizeof(unsigned int);
1756
1757 switch (cli_conn->addr.from.ss_family) {
1758 case AF_INET:
1759 memcpy(temp->area + temp->data,
1760 &((struct sockaddr_in *)&cli_conn->addr.from)->sin_addr,
1761 4);
1762 temp->data += 4;
1763 break;
1764 case AF_INET6:
1765 memcpy(temp->area + temp->data,
1766 &((struct sockaddr_in6 *)&cli_conn->addr.from)->sin6_addr,
1767 16);
1768 temp->data += 16;
1769 break;
1770 default:
1771 return 0;
1772 }
1773
1774 smp->data.u.str = *temp;
1775 smp->data.type = SMP_T_BIN;
1776 return 1;
1777}
1778
1779/************************************************************************/
1780/* Other utility functions */
1781/************************************************************************/
1782
1783/* This function is used to validate the arguments passed to any "hdr" fetch
1784 * keyword. These keywords support an optional positive or negative occurrence
1785 * number. We must ensure that the number is greater than -MAX_HDR_HISTORY. It
1786 * is assumed that the types are already the correct ones. Returns 0 on error,
1787 * non-zero if OK. If <err> is not NULL, it will be filled with a pointer to an
1788 * error message in case of error, that the caller is responsible for freeing.
1789 * The initial location must either be freeable or NULL.
1790 * Note: this function's pointer is checked from Lua.
1791 */
1792int val_hdr(struct arg *arg, char **err_msg)
1793{
1794 if (arg && arg[1].type == ARGT_SINT && arg[1].data.sint < -MAX_HDR_HISTORY) {
1795 memprintf(err_msg, "header occurrence must be >= %d", -MAX_HDR_HISTORY);
1796 return 0;
1797 }
1798 return 1;
1799}
1800
1801/************************************************************************/
1802/* All supported sample fetch keywords must be declared here. */
1803/************************************************************************/
1804
1805/* Note: must not be declared <const> as its list will be overwritten */
1806static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, {
1807 { "base", smp_fetch_base, 0, NULL, SMP_T_STR, SMP_USE_HRQHV },
1808 { "base32", smp_fetch_base32, 0, NULL, SMP_T_SINT, SMP_USE_HRQHV },
1809 { "base32+src", smp_fetch_base32_src, 0, NULL, SMP_T_BIN, SMP_USE_HRQHV },
1810
1811 /* capture are allocated and are permanent in the stream */
1812 { "capture.req.hdr", smp_fetch_capture_req_hdr, ARG1(1,SINT), NULL, SMP_T_STR, SMP_USE_HRQHP },
1813
1814 /* retrieve these captures from the HTTP logs */
1815 { "capture.req.method", smp_fetch_capture_req_method, 0, NULL, SMP_T_STR, SMP_USE_HRQHP },
1816 { "capture.req.uri", smp_fetch_capture_req_uri, 0, NULL, SMP_T_STR, SMP_USE_HRQHP },
1817 { "capture.req.ver", smp_fetch_capture_req_ver, 0, NULL, SMP_T_STR, SMP_USE_HRQHP },
1818
1819 { "capture.res.hdr", smp_fetch_capture_res_hdr, ARG1(1,SINT), NULL, SMP_T_STR, SMP_USE_HRSHP },
1820 { "capture.res.ver", smp_fetch_capture_res_ver, 0, NULL, SMP_T_STR, SMP_USE_HRQHP },
1821
1822 /* cookie is valid in both directions (eg: for "stick ...") but cook*
1823 * are only here to match the ACL's name, are request-only and are used
1824 * for ACL compatibility only.
1825 */
1826 { "cook", smp_fetch_cookie, ARG1(0,STR), NULL, SMP_T_STR, SMP_USE_HRQHV },
1827 { "cookie", smp_fetch_cookie, ARG1(0,STR), NULL, SMP_T_STR, SMP_USE_HRQHV|SMP_USE_HRSHV },
1828 { "cook_cnt", smp_fetch_cookie_cnt, ARG1(0,STR), NULL, SMP_T_SINT, SMP_USE_HRQHV },
1829 { "cook_val", smp_fetch_cookie_val, ARG1(0,STR), NULL, SMP_T_SINT, SMP_USE_HRQHV },
1830
1831 /* hdr is valid in both directions (eg: for "stick ...") but hdr_* are
1832 * only here to match the ACL's name, are request-only and are used for
1833 * ACL compatibility only.
1834 */
1835 { "hdr", smp_fetch_hdr, ARG2(0,STR,SINT), val_hdr, SMP_T_STR, SMP_USE_HRQHV|SMP_USE_HRSHV },
1836 { "hdr_cnt", smp_fetch_hdr_cnt, ARG1(0,STR), NULL, SMP_T_SINT, SMP_USE_HRQHV },
1837 { "hdr_ip", smp_fetch_hdr_ip, ARG2(0,STR,SINT), val_hdr, SMP_T_IPV4, SMP_USE_HRQHV },
1838 { "hdr_val", smp_fetch_hdr_val, ARG2(0,STR,SINT), val_hdr, SMP_T_SINT, SMP_USE_HRQHV },
1839
1840 { "http_auth", smp_fetch_http_auth, ARG1(1,USR), NULL, SMP_T_BOOL, SMP_USE_HRQHV },
1841 { "http_auth_group", smp_fetch_http_auth_grp, ARG1(1,USR), NULL, SMP_T_STR, SMP_USE_HRQHV },
1842 { "http_first_req", smp_fetch_http_first_req, 0, NULL, SMP_T_BOOL, SMP_USE_HRQHP },
1843 { "method", smp_fetch_meth, 0, NULL, SMP_T_METH, SMP_USE_HRQHP },
1844 { "path", smp_fetch_path, 0, NULL, SMP_T_STR, SMP_USE_HRQHV },
1845 { "query", smp_fetch_query, 0, NULL, SMP_T_STR, SMP_USE_HRQHV },
1846
1847 /* HTTP protocol on the request path */
1848 { "req.proto_http", smp_fetch_proto_http, 0, NULL, SMP_T_BOOL, SMP_USE_HRQHP },
1849 { "req_proto_http", smp_fetch_proto_http, 0, NULL, SMP_T_BOOL, SMP_USE_HRQHP },
1850
1851 /* HTTP version on the request path */
1852 { "req.ver", smp_fetch_rqver, 0, NULL, SMP_T_STR, SMP_USE_HRQHV },
1853 { "req_ver", smp_fetch_rqver, 0, NULL, SMP_T_STR, SMP_USE_HRQHV },
1854
1855 { "req.body", smp_fetch_body, 0, NULL, SMP_T_BIN, SMP_USE_HRQHV },
1856 { "req.body_len", smp_fetch_body_len, 0, NULL, SMP_T_SINT, SMP_USE_HRQHV },
1857 { "req.body_size", smp_fetch_body_size, 0, NULL, SMP_T_SINT, SMP_USE_HRQHV },
1858 { "req.body_param", smp_fetch_body_param, ARG1(0,STR), NULL, SMP_T_BIN, SMP_USE_HRQHV },
1859
1860 { "req.hdrs", smp_fetch_hdrs, 0, NULL, SMP_T_BIN, SMP_USE_HRQHV },
1861 { "req.hdrs_bin", smp_fetch_hdrs_bin, 0, NULL, SMP_T_BIN, SMP_USE_HRQHV },
1862
1863 /* HTTP version on the response path */
1864 { "res.ver", smp_fetch_stver, 0, NULL, SMP_T_STR, SMP_USE_HRSHV },
1865 { "resp_ver", smp_fetch_stver, 0, NULL, SMP_T_STR, SMP_USE_HRSHV },
1866
1867 /* explicit req.{cook,hdr} are used to force the fetch direction to be request-only */
1868 { "req.cook", smp_fetch_cookie, ARG1(0,STR), NULL, SMP_T_STR, SMP_USE_HRQHV },
1869 { "req.cook_cnt", smp_fetch_cookie_cnt, ARG1(0,STR), NULL, SMP_T_SINT, SMP_USE_HRQHV },
1870 { "req.cook_val", smp_fetch_cookie_val, ARG1(0,STR), NULL, SMP_T_SINT, SMP_USE_HRQHV },
1871
1872 { "req.fhdr", smp_fetch_fhdr, ARG2(0,STR,SINT), val_hdr, SMP_T_STR, SMP_USE_HRQHV },
1873 { "req.fhdr_cnt", smp_fetch_fhdr_cnt, ARG1(0,STR), NULL, SMP_T_SINT, SMP_USE_HRQHV },
1874 { "req.hdr", smp_fetch_hdr, ARG2(0,STR,SINT), val_hdr, SMP_T_STR, SMP_USE_HRQHV },
1875 { "req.hdr_cnt", smp_fetch_hdr_cnt, ARG1(0,STR), NULL, SMP_T_SINT, SMP_USE_HRQHV },
1876 { "req.hdr_ip", smp_fetch_hdr_ip, ARG2(0,STR,SINT), val_hdr, SMP_T_IPV4, SMP_USE_HRQHV },
1877 { "req.hdr_names", smp_fetch_hdr_names, ARG1(0,STR), NULL, SMP_T_STR, SMP_USE_HRQHV },
1878 { "req.hdr_val", smp_fetch_hdr_val, ARG2(0,STR,SINT), val_hdr, SMP_T_SINT, SMP_USE_HRQHV },
1879
1880 /* explicit req.{cook,hdr} are used to force the fetch direction to be response-only */
1881 { "res.cook", smp_fetch_cookie, ARG1(0,STR), NULL, SMP_T_STR, SMP_USE_HRSHV },
1882 { "res.cook_cnt", smp_fetch_cookie_cnt, ARG1(0,STR), NULL, SMP_T_SINT, SMP_USE_HRSHV },
1883 { "res.cook_val", smp_fetch_cookie_val, ARG1(0,STR), NULL, SMP_T_SINT, SMP_USE_HRSHV },
1884
1885 { "res.fhdr", smp_fetch_fhdr, ARG2(0,STR,SINT), val_hdr, SMP_T_STR, SMP_USE_HRSHV },
1886 { "res.fhdr_cnt", smp_fetch_fhdr_cnt, ARG1(0,STR), NULL, SMP_T_SINT, SMP_USE_HRSHV },
1887 { "res.hdr", smp_fetch_hdr, ARG2(0,STR,SINT), val_hdr, SMP_T_STR, SMP_USE_HRSHV },
1888 { "res.hdr_cnt", smp_fetch_hdr_cnt, ARG1(0,STR), NULL, SMP_T_SINT, SMP_USE_HRSHV },
1889 { "res.hdr_ip", smp_fetch_hdr_ip, ARG2(0,STR,SINT), val_hdr, SMP_T_IPV4, SMP_USE_HRSHV },
1890 { "res.hdr_names", smp_fetch_hdr_names, ARG1(0,STR), NULL, SMP_T_STR, SMP_USE_HRSHV },
1891 { "res.hdr_val", smp_fetch_hdr_val, ARG2(0,STR,SINT), val_hdr, SMP_T_SINT, SMP_USE_HRSHV },
1892
1893 /* scook is valid only on the response and is used for ACL compatibility */
1894 { "scook", smp_fetch_cookie, ARG1(0,STR), NULL, SMP_T_STR, SMP_USE_HRSHV },
1895 { "scook_cnt", smp_fetch_cookie_cnt, ARG1(0,STR), NULL, SMP_T_SINT, SMP_USE_HRSHV },
1896 { "scook_val", smp_fetch_cookie_val, ARG1(0,STR), NULL, SMP_T_SINT, SMP_USE_HRSHV },
1897 { "set-cookie", smp_fetch_cookie, ARG1(0,STR), NULL, SMP_T_STR, SMP_USE_HRSHV }, /* deprecated */
1898
1899 /* shdr is valid only on the response and is used for ACL compatibility */
1900 { "shdr", smp_fetch_hdr, ARG2(0,STR,SINT), val_hdr, SMP_T_STR, SMP_USE_HRSHV },
1901 { "shdr_cnt", smp_fetch_hdr_cnt, ARG1(0,STR), NULL, SMP_T_SINT, SMP_USE_HRSHV },
1902 { "shdr_ip", smp_fetch_hdr_ip, ARG2(0,STR,SINT), val_hdr, SMP_T_IPV4, SMP_USE_HRSHV },
1903 { "shdr_val", smp_fetch_hdr_val, ARG2(0,STR,SINT), val_hdr, SMP_T_SINT, SMP_USE_HRSHV },
1904
1905 { "status", smp_fetch_stcode, 0, NULL, SMP_T_SINT, SMP_USE_HRSHP },
1906 { "unique-id", smp_fetch_uniqueid, 0, NULL, SMP_T_STR, SMP_SRC_L4SRV },
1907 { "url", smp_fetch_url, 0, NULL, SMP_T_STR, SMP_USE_HRQHV },
1908 { "url32", smp_fetch_url32, 0, NULL, SMP_T_SINT, SMP_USE_HRQHV },
1909 { "url32+src", smp_fetch_url32_src, 0, NULL, SMP_T_BIN, SMP_USE_HRQHV },
1910 { "url_ip", smp_fetch_url_ip, 0, NULL, SMP_T_IPV4, SMP_USE_HRQHV },
1911 { "url_port", smp_fetch_url_port, 0, NULL, SMP_T_SINT, SMP_USE_HRQHV },
1912 { "url_param", smp_fetch_url_param, ARG2(0,STR,STR), NULL, SMP_T_STR, SMP_USE_HRQHV },
1913 { "urlp" , smp_fetch_url_param, ARG2(0,STR,STR), NULL, SMP_T_STR, SMP_USE_HRQHV },
1914 { "urlp_val", smp_fetch_url_param_val, ARG2(0,STR,STR), NULL, SMP_T_SINT, SMP_USE_HRQHV },
1915 { /* END */ },
1916}};
1917
1918
1919__attribute__((constructor))
1920static void __http_fetch_init(void)
1921{
1922 sample_register_fetches(&sample_fetch_keywords);
1923}
1924
1925/*
1926 * Local variables:
1927 * c-indent-level: 8
1928 * c-basic-offset: 8
1929 * End:
1930 */