Coverage Report

Created: 2026-08-13 07:18

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/haproxy/src/http_fetch.c
Line
Count
Source
1
/*
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 <haproxy/api.h>
20
#include <haproxy/arg.h>
21
#include <haproxy/auth.h>
22
#include <haproxy/base64.h>
23
#include <haproxy/channel.h>
24
#include <haproxy/chunk.h>
25
#include <haproxy/check.h>
26
#include <haproxy/connection.h>
27
#include <haproxy/global.h>
28
#include <haproxy/h1.h>
29
#include <haproxy/h1_htx.h>
30
#include <haproxy/http.h>
31
#include <haproxy/http_ana.h>
32
#include <haproxy/http_fetch.h>
33
#include <haproxy/http_htx.h>
34
#include <haproxy/htx.h>
35
#include <haproxy/obj_type.h>
36
#include <haproxy/pool.h>
37
#include <haproxy/sample.h>
38
#include <haproxy/sc_strm.h>
39
#include <haproxy/stream.h>
40
#include <haproxy/log.h>
41
#include <haproxy/tools.h>
42
#include <haproxy/version.h>
43
44
45
/* this struct is used between calls to smp_fetch_hdr() or smp_fetch_cookie() */
46
static THREAD_LOCAL struct http_hdr_ctx static_http_hdr_ctx;
47
/* this is used to convert raw connection buffers to htx */
48
/* NOTE: For now, raw buffers cannot exceeds the standard size */
49
static THREAD_LOCAL struct buffer static_raw_htx_chunk;
50
static THREAD_LOCAL char *static_raw_htx_buf;
51
52
0
#define SMP_REQ_CHN(smp) (smp->strm ? &smp->strm->req : NULL)
53
0
#define SMP_RES_CHN(smp) (smp->strm ? &smp->strm->res : NULL)
54
55
0
#define SMP_REQ_SC(smp) (smp->strm ? smp->strm->scf : NULL)
56
0
#define SMP_RES_SC(smp) (smp->strm ? smp->strm->scb : NULL)
57
58
/* This function returns the static htx chunk, where raw connections get
59
 * converted to HTX as needed for samplxsing.
60
 */
61
struct buffer *get_raw_htx_chunk(void)
62
0
{
63
0
  chunk_reset(&static_raw_htx_chunk);
64
0
  return &static_raw_htx_chunk;
65
0
}
66
67
static int alloc_raw_htx_chunk_per_thread()
68
0
{
69
0
  static_raw_htx_buf = malloc(global.tune.bufsize);
70
0
  if (!static_raw_htx_buf)
71
0
    return 0;
72
0
  chunk_init(&static_raw_htx_chunk, static_raw_htx_buf, global.tune.bufsize);
73
0
  return 1;
74
0
}
75
76
static void free_raw_htx_chunk_per_thread()
77
0
{
78
0
  ha_free(&static_raw_htx_buf);
79
0
}
80
81
REGISTER_PER_THREAD_ALLOC(alloc_raw_htx_chunk_per_thread);
82
REGISTER_PER_THREAD_FREE(free_raw_htx_chunk_per_thread);
83
84
/*
85
 * Returns the data from Authorization header. Function may be called more
86
 * than once so data is stored in txn->auth_data. When no header is found
87
 * or auth method is unknown auth_method is set to HTTP_AUTH_WRONG to avoid
88
 * searching again for something we are unable to find anyway. However, if
89
 * the result if valid, the cache is not reused because we would risk to
90
 * have the credentials overwritten by another stream in parallel.
91
 * The caller is responsible for passing a sample with a valid stream/txn,
92
 * and a valid htx.
93
 */
94
95
static int get_http_auth(struct sample *smp, struct htx *htx)
96
0
{
97
0
  struct stream *s = smp->strm;
98
0
  struct http_txn *txn = s->txn.http;
99
0
  struct http_hdr_ctx ctx = { .blk = NULL };
100
0
  struct ist hdr;
101
0
  struct buffer auth_method;
102
0
  char *p;
103
0
  int len;
104
105
#ifdef DEBUG_AUTH
106
  printf("Auth for stream %p: %d\n", s, txn->auth.method);
107
#endif
108
0
  if (txn->auth.method == HTTP_AUTH_WRONG)
109
0
    return 0;
110
111
0
  txn->auth.method = HTTP_AUTH_WRONG;
112
113
0
  if (txn->flags & TX_USE_PX_CONN)
114
0
    hdr = ist("Proxy-Authorization");
115
0
  else
116
0
    hdr = ist("Authorization");
117
118
0
  ctx.blk = NULL;
119
0
  if (!http_find_header(htx, hdr, &ctx, 0))
120
0
    return 0;
121
122
0
  p = memchr(ctx.value.ptr, ' ', ctx.value.len);
123
0
  if (!p || p == ctx.value.ptr) /* if no space was found or if the space is the first character */
124
0
    return 0;
125
0
  len = p - ctx.value.ptr;
126
127
0
  if (chunk_initlen(&auth_method, ctx.value.ptr, 0, len) != 1)
128
0
    return 0;
129
130
  /* According to RFC7235, there could be multiple spaces between the
131
   * scheme and its value, we must skip all of them.
132
   */
133
0
  while (p < istend(ctx.value) && *p == ' ')
134
0
    ++p;
135
136
0
  chunk_initlen(&txn->auth.method_data, p, 0, istend(ctx.value) - p);
137
138
0
  if (isteqi(ist2(auth_method.area, auth_method.data), ist("Basic"))) {
139
0
    struct buffer *http_auth = get_trash_chunk();
140
141
0
    len = base64dec(txn->auth.method_data.area,
142
0
        txn->auth.method_data.data,
143
0
        http_auth->area, http_auth->size -1);
144
145
0
    if (len < 0)
146
0
      return 0;
147
148
149
0
    http_auth->area[len] = '\0';
150
151
0
    p = strchr(http_auth->area, ':');
152
153
0
    if (!p)
154
0
      return 0;
155
156
0
    txn->auth.user = http_auth->area;
157
0
    *p = '\0';
158
0
    txn->auth.pass = p+1;
159
160
0
    txn->auth.method = HTTP_AUTH_BASIC;
161
0
    return 1;
162
0
  } else if (isteqi(ist2(auth_method.area, auth_method.data), ist("Bearer"))) {
163
0
    txn->auth.method = HTTP_AUTH_BEARER;
164
0
    return 1;
165
0
  }
166
167
0
  return 0;
168
0
}
169
170
/* This function ensures that the prerequisites for an L7 fetch are ready,
171
 * which means that a request or response is ready. If some data is missing,
172
 * a parsing attempt is made. This is useful in TCP-based ACLs which are able
173
 * to extract data from L7. If <vol> is non-null during a prefetch, another
174
 * test is made to ensure the required information is not gone.
175
 *
176
 * The function returns :
177
 *   NULL with SMP_F_MAY_CHANGE in the sample flags if some data is missing to
178
 *     decide whether or not an HTTP message is present ;
179
 *   NULL if the requested data cannot be fetched or if it is certain that
180
 *     we'll never have any HTTP message there; this includes null strm or chn.
181
 *   NULL if the sample's direction does not match the channel's (i.e. the
182
 *     function was asked to work on the wrong channel)
183
 *   The HTX message if ready
184
 */
185
struct htx *smp_prefetch_htx(struct sample *smp, struct channel *chn, struct check *check, int vol)
186
0
{
187
0
  struct stream *s = smp->strm;
188
0
  struct http_txn *txn = NULL;
189
0
  struct htx *htx = NULL;
190
0
  struct http_msg *msg;
191
0
  struct htx_sl *sl;
192
193
0
  if (chn &&
194
0
      (((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_REQ && (chn->flags & CF_ISRESP)) ||
195
0
       ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES && !(chn->flags & CF_ISRESP))))
196
0
    return 0;
197
198
  /* Note: it is possible that <s> is NULL when called before stream
199
   * initialization (eg: tcp-request connection), so this function is the
200
   * one responsible for guarding against this case for all HTTP users.
201
   *
202
   * In the health check context, the stream and the channel must be NULL
203
   * and <check> must be set. In this case, only the input buffer,
204
   * corresponding to the response, is considered. It is the caller
205
   * responsibility to provide <check>.
206
   */
207
0
  BUG_ON(check && (s || chn));
208
0
  if (!s || !chn) {
209
0
    if (check) {
210
      /* The check input buffer only contains an HTX message for
211
       * an HTTP check.
212
       */
213
0
      if (!IS_HTX_SC(check->sc))
214
0
        return NULL;
215
216
0
      htx = htxbuf(&check->bi);
217
218
      /* Analyse not yet started */
219
0
      if (htx_is_empty(htx) || htx->first == -1)
220
0
        return NULL;
221
222
0
      sl = http_get_stline(htx);
223
0
      if (vol && !sl) {
224
        /* The start-line was already forwarded, it is too late to fetch anything */
225
0
        return NULL;
226
0
      }
227
0
      goto end;
228
0
    }
229
230
0
    return NULL;
231
0
  }
232
233
0
  if (!s->txn.http && !http_create_txn(s))
234
0
    return NULL;
235
0
  txn = s->txn.http;
236
0
  msg = (!(chn->flags & CF_ISRESP) ? &txn->req : &txn->rsp);
237
238
0
  if (IS_HTX_STRM(s)) {
239
0
    htx = htxbuf(&chn->buf);
240
241
0
    if (htx->flags & HTX_FL_PARSING_ERROR)
242
0
      return NULL;
243
244
0
    if (msg->msg_state < HTTP_MSG_BODY) {
245
      /* Analyse not yet started */
246
0
      if (htx_is_empty(htx) || htx->first == -1) {
247
        /* Parsing is done by the mux, just wait */
248
0
        smp->flags |= SMP_F_MAY_CHANGE;
249
0
        return NULL;
250
0
      }
251
0
    }
252
0
    sl = http_get_stline(htx);
253
0
    if (vol && !sl) {
254
      /* The start-line was already forwarded, it is too late to fetch anything */
255
0
      return NULL;
256
0
    }
257
0
  }
258
0
  else { /* RAW mode */
259
0
    struct buffer *buf;
260
0
    struct h1m h1m;
261
0
    struct http_hdr hdrs[global.tune.max_http_hdr];
262
0
    union h1_sl h1sl;
263
0
    unsigned int flags = HTX_FL_NONE;
264
0
    int ret;
265
266
    /* no HTTP fetch on the response in TCP mode */
267
0
    if (chn->flags & CF_ISRESP)
268
0
      return NULL;
269
270
    /* Now we are working on the request only */
271
0
    buf = &chn->buf;
272
0
    if (b_head(buf) + b_data(buf) > b_wrap(buf))
273
0
      b_slow_realign(buf, trash.area, 0);
274
275
0
    h1m_init_req(&h1m);
276
0
    ret = h1_headers_to_hdr_list(b_head(buf), b_stop(buf),
277
0
               hdrs, sizeof(hdrs)/sizeof(hdrs[0]), &h1m, &h1sl);
278
0
    if (ret <= 0) {
279
      /* Invalid or too big*/
280
0
      if (ret < 0 || channel_full(&s->req, global.tune.maxrewrite))
281
0
        return NULL;
282
283
      /* wait for a full request */
284
0
      smp->flags |= SMP_F_MAY_CHANGE;
285
0
      return NULL;
286
0
    }
287
288
    /* OK we just got a valid HTTP message. We have to convert it
289
     * into an HTX message.
290
     */
291
0
    if (unlikely(h1sl.rq.v.len == 0)) {
292
      /* try to convert HTTP/0.9 requests to HTTP/1.0 */
293
0
      if (h1sl.rq.meth != HTTP_METH_GET || !h1sl.rq.u.len)
294
0
        return NULL;
295
0
      h1sl.rq.v = ist("HTTP/1.0");
296
0
    }
297
298
    /* Set HTX start-line flags */
299
0
    if (h1m.flags & H1_MF_VER_11)
300
0
      flags |= HTX_SL_F_VER_11;
301
0
    if (h1m.flags & H1_MF_XFER_ENC)
302
0
      flags |= HTX_SL_F_XFER_ENC;
303
0
    flags |= HTX_SL_F_XFER_LEN;
304
0
    if (h1m.flags & H1_MF_CHNK)
305
0
      flags |= HTX_SL_F_CHNK;
306
0
    else if (h1m.flags & H1_MF_CLEN)
307
0
      flags |= HTX_SL_F_CLEN;
308
309
0
    htx = htx_from_buf(get_raw_htx_chunk());
310
0
    sl = htx_add_stline(htx, HTX_BLK_REQ_SL, flags, h1sl.rq.m, h1sl.rq.u, h1sl.rq.v);
311
0
    if (!sl || !htx_add_all_headers(htx, hdrs))
312
0
      return NULL;
313
0
    sl->info.req.meth = h1sl.rq.meth;
314
0
  }
315
316
  /* OK we just got a valid HTTP message. If not already done by
317
   * HTTP analyzers, we have some minor preparation to perform so
318
   * that further checks can rely on HTTP tests.
319
   */
320
0
  if (sl && msg->msg_state < HTTP_MSG_BODY) {
321
0
    struct ist vsn;
322
323
0
    if (!(chn->flags & CF_ISRESP)) {
324
0
      vsn = htx_sl_req_vsn(sl);
325
0
      txn->meth = sl->info.req.meth;
326
0
      if (txn->meth == HTTP_METH_GET || txn->meth == HTTP_METH_HEAD)
327
0
        s->flags |= SF_REDIRECTABLE;
328
0
    }
329
0
    else {
330
0
      vsn = htx_sl_res_vsn(sl);
331
0
      if (txn->status == -1)
332
0
        txn->status = sl->info.res.status;
333
0
      if (txn->server_status == -1)
334
0
        txn->server_status = sl->info.res.status;
335
0
    }
336
337
0
    if ((sl->flags & HTX_SL_F_NOT_HTTP) || istlen(vsn) != 8) {
338
      /* Not an HTTP message */
339
0
      msg->vsn = 0;
340
0
    }
341
0
    else {
342
0
      char *ptr = istptr(vsn);
343
344
0
      msg->vsn = ((ptr[5] - '0') << 4) + (ptr[7] - '0');
345
0
      if (sl->flags & HTX_SL_F_VER_11)
346
0
        msg->flags |= HTTP_MSGF_VER_11;
347
0
    }
348
0
  }
349
350
  /* everything's OK */
351
0
  end:
352
0
  return htx;
353
0
}
354
355
/* Get the HTTP version from <msg> or <htx> and append it into the chunk <chk>
356
 * with the format "<major>.<minor>".
357
 * It returns 0 if <msg> and <htx> are both NULL or if the version
358
 * is not a valid HTTP version. Otherwise, it returns 1 (success).
359
 *
360
 * The version is retrieved from <msg>, if not NULL. Otherwise, it is retrieved
361
 * from <htx>.
362
 */
363
static int get_msg_version(const struct http_msg *msg, const struct htx *htx, struct buffer *chk)
364
0
{
365
0
  if (msg) {
366
0
    if (msg->vsn) {
367
0
      chunk_appendf(chk, "%d.%d", (msg->vsn & 0xf0) >> 4, msg->vsn & 0xf);
368
0
      return 1;
369
0
    }
370
0
  }
371
0
  else if (htx) {
372
0
    struct htx_sl *sl = http_get_stline(htx);
373
0
    struct ist vsn = htx_sl_vsn(sl);
374
375
0
    if (!(sl->flags & HTX_SL_F_NOT_HTTP) && istlen(vsn) == 8) {
376
0
      chunk_appendf(chk, "%d.%d", istptr(vsn)[5] - '0',  istptr(vsn)[7] - '0');
377
0
      return 1;
378
0
    }
379
0
  }
380
381
  /* <msg> and <htx> are both NULL or not a valid HTTP version */
382
0
  return 0;
383
0
}
384
385
386
/* This function fetches the method of current HTTP request and stores
387
 * it in the global pattern struct as a chunk. There are two possibilities :
388
 *   - if the method is known (not HTTP_METH_OTHER), its identifier is stored
389
 *     in <len> and <ptr> is NULL ;
390
 *   - if the method is unknown (HTTP_METH_OTHER), <ptr> points to the text and
391
 *     <len> to its length.
392
 * This is intended to be used with pat_match_meth() only.
393
 */
394
static int smp_fetch_meth(const struct arg *args, struct sample *smp, const char *kw, void *private)
395
0
{
396
0
  struct channel *chn = SMP_REQ_CHN(smp);
397
0
  struct http_txn *txn;
398
0
  struct htx *htx = NULL;
399
0
  int meth;
400
401
0
  txn = (smp->strm ? smp->strm->txn.http : NULL);
402
0
  if (!txn)
403
0
    return 0;
404
405
0
  meth = txn->meth;
406
0
  if (meth == HTTP_METH_OTHER) {
407
0
    htx = smp_prefetch_htx(smp, chn, NULL, 1);
408
0
    if (!htx)
409
0
      return 0;
410
0
    meth = txn->meth;
411
0
  }
412
413
0
  smp->data.type = SMP_T_METH;
414
0
  smp->data.u.meth.meth = meth;
415
0
  if (meth == HTTP_METH_OTHER) {
416
0
    struct htx_sl *sl;
417
418
0
    sl = http_get_stline(htx);
419
0
    smp->flags |= SMP_F_CONST;
420
0
    smp->data.u.meth.str.area = HTX_SL_REQ_MPTR(sl);
421
0
    smp->data.u.meth.str.data = HTX_SL_REQ_MLEN(sl);
422
0
  }
423
0
  smp->flags |= SMP_F_VOL_1ST;
424
0
  return 1;
425
0
}
426
427
static int smp_fetch_rqver(const struct arg *args, struct sample *smp, const char *kw, void *private)
428
0
{
429
0
  struct stream *s = smp->strm;
430
0
  struct channel *chn = SMP_REQ_CHN(smp);
431
0
  struct htx *htx = smp_prefetch_htx(smp, chn, NULL, 1);
432
0
  struct buffer *vsn = get_trash_chunk();
433
434
0
  if (!get_msg_version((s && s->txn.http) ? &s->txn.http->req : NULL, htx, vsn))
435
0
    return 0;
436
437
0
  smp->data.type = SMP_T_STR;
438
0
  smp->data.u.str = *vsn;
439
0
  return 1;
440
0
}
441
442
static int smp_fetch_stver(const struct arg *args, struct sample *smp, const char *kw, void *private)
443
0
{
444
0
  struct stream *s = smp->strm;
445
0
  struct channel *chn = SMP_RES_CHN(smp);
446
0
  struct check *check = objt_check(smp->sess->origin);
447
0
  struct htx *htx = smp_prefetch_htx(smp, chn, check, 1);
448
0
  struct buffer *vsn = get_trash_chunk();
449
450
0
  if (!get_msg_version((s && s->txn.http) ? &s->txn.http->rsp : NULL, htx, vsn))
451
0
    return 0;
452
453
0
  smp->data.type = SMP_T_STR;
454
0
  smp->data.u.str = *vsn;
455
0
  return 1;
456
0
}
457
458
/* 3. Check on Status Code. We manipulate integers here. */
459
static int smp_fetch_stcode(const struct arg *args, struct sample *smp, const char *kw, void *private)
460
0
{
461
0
  struct channel *chn = SMP_RES_CHN(smp);
462
0
  struct check *check = objt_check(smp->sess->origin);
463
0
  struct htx *htx = smp_prefetch_htx(smp, chn, check, 1);
464
0
  struct htx_sl *sl;
465
0
  char *ptr;
466
0
  int len;
467
468
0
  if (!htx)
469
0
    return 0;
470
471
0
  sl = http_get_stline(htx);
472
0
  len = HTX_SL_RES_CLEN(sl);
473
0
  ptr = HTX_SL_RES_CPTR(sl);
474
475
0
  smp->data.type = SMP_T_SINT;
476
0
  smp->data.u.sint = __strl2ui(ptr, len);
477
0
  smp->flags = SMP_F_VOL_1ST;
478
0
  return 1;
479
0
}
480
481
/* It returns the server or the txn status code, depending on the keyword */
482
static int smp_fetch_srv_status(const struct arg *args, struct sample *smp, const char *kw, void *private)
483
0
{
484
0
  struct http_txn *txn;
485
0
  short status;
486
487
0
  txn = (smp->strm ? smp->strm->txn.http : NULL);
488
0
  if (!txn)
489
0
    return 0;
490
491
0
  status = (kw[0] == 't' ? txn->status : txn->server_status);
492
0
  if (status == -1) {
493
0
    struct channel *chn = SMP_RES_CHN(smp);
494
0
    struct htx *htx = smp_prefetch_htx(smp, chn, NULL, 1);
495
496
0
    if (!htx)
497
0
      return 0;
498
499
0
    status = (kw[0] == 't' ? txn->status : txn->server_status);
500
0
  }
501
502
0
  if (kw[0] != 't')
503
0
    smp->flags = SMP_F_VOL_1ST;
504
0
  smp->data.type = SMP_T_SINT;
505
0
  smp->data.u.sint = status;
506
0
  return 1;
507
0
}
508
509
static int smp_fetch_uniqueid(const struct arg *args, struct sample *smp, const char *kw, void *private)
510
0
{
511
0
  struct ist unique_id;
512
0
  struct check *check;
513
514
0
  if (smp->strm) {
515
0
    if (lf_expr_isempty(&smp->sess->fe->format_unique_id))
516
0
      return 0;
517
518
0
    unique_id = stream_generate_unique_id(smp->strm, &smp->sess->fe->format_unique_id);
519
0
  } else if ((check = objt_check(smp->sess->origin)) != NULL) {
520
0
    if (lf_expr_isempty(&check->proxy->format_unique_id))
521
0
      return 0;
522
523
0
    unique_id = check_generate_unique_id(check, &check->proxy->format_unique_id);
524
0
  } else {
525
0
    return 0;
526
0
  }
527
528
0
  if (!isttest(unique_id))
529
0
    return 0;
530
531
0
  smp->data.u.str.area = istptr(unique_id);
532
0
  smp->data.u.str.data = istlen(unique_id);
533
0
  smp->data.type = SMP_T_STR;
534
0
  smp->flags = SMP_F_CONST;
535
0
  return 1;
536
0
}
537
538
/* Returns a string block containing all headers including the
539
 * empty line which separates headers from the body. This is useful
540
 * for some headers analysis.
541
 */
542
static int smp_fetch_hdrs(const struct arg *args, struct sample *smp, const char *kw, void *private)
543
0
{
544
  /* possible keywords: req.hdrs, res.hdrs */
545
0
  struct channel *chn = ((kw[2] == 'q') ? SMP_REQ_CHN(smp) : SMP_RES_CHN(smp));
546
0
  struct check *check = ((kw[2] == 's') ? objt_check(smp->sess->origin) : NULL);
547
0
  struct htx *htx = smp_prefetch_htx(smp, chn, check, 1);
548
0
  struct buffer *temp;
549
0
  int32_t pos;
550
551
0
  if (!htx)
552
0
    return 0;
553
0
  temp = get_trash_chunk();
554
0
  for (pos = htx_get_first(htx); pos != -1; pos = htx_get_next(htx, pos)) {
555
0
    struct htx_blk *blk = htx_get_blk(htx, pos);
556
0
    enum htx_blk_type type = htx_get_blk_type(blk);
557
558
0
    if (type == HTX_BLK_HDR) {
559
0
      struct ist n = htx_get_blk_name(htx, blk);
560
0
      struct ist v = htx_get_blk_value(htx, blk);
561
562
0
      if (!h1_format_htx_hdr(n, v, temp, NULL))
563
0
        return 0;
564
0
    }
565
0
    else if (type == HTX_BLK_EOH) {
566
0
      if (!chunk_memcat(temp, "\r\n", 2))
567
0
        return 0;
568
0
      break;
569
0
    }
570
0
  }
571
0
  smp->data.type = SMP_T_STR;
572
0
  smp->data.u.str = *temp;
573
0
  return 1;
574
0
}
575
576
/* Returns the header request in a length/value encoded format.
577
 * This is useful for exchanges with the SPOE.
578
 *
579
 * A "length value" is a multibyte code encoding numbers. It uses the
580
 * SPOE format. The encoding is the following:
581
 *
582
 * Each couple "header name" / "header value" is composed
583
 * like this:
584
 *    "length value" "header name bytes"
585
 *    "length value" "header value bytes"
586
 * When the last header is reached, the header name and the header
587
 * value are empty. Their length are 0
588
 */
589
static int smp_fetch_hdrs_bin(const struct arg *args, struct sample *smp, const char *kw, void *private)
590
0
{
591
  /* possible keywords: req.hdrs_bin, res.hdrs_bin */
592
0
  struct channel *chn = ((kw[2] == 'q') ? SMP_REQ_CHN(smp) : SMP_RES_CHN(smp));
593
0
  struct check *check = ((kw[2] == 's') ? objt_check(smp->sess->origin) : NULL);
594
0
  struct htx *htx = smp_prefetch_htx(smp, chn, check, 1);
595
0
  struct buffer *temp;
596
0
  char *p, *end;
597
0
  int32_t pos;
598
0
  int ret;
599
600
0
  if (!htx)
601
0
    return 0;
602
0
  temp = get_trash_chunk();
603
0
  p = temp->area;
604
0
  end = temp->area + temp->size;
605
0
  for (pos = htx_get_first(htx); pos != -1; pos = htx_get_next(htx, pos)) {
606
0
    struct htx_blk *blk = htx_get_blk(htx, pos);
607
0
    enum htx_blk_type type = htx_get_blk_type(blk);
608
0
    struct ist n, v;
609
610
0
    if (type == HTX_BLK_HDR) {
611
0
      n = htx_get_blk_name(htx,blk);
612
0
      v = htx_get_blk_value(htx, blk);
613
614
      /* encode the header name. */
615
0
      ret = encode_varint(n.len, &p, end);
616
0
      if (ret == -1)
617
0
        return 0;
618
0
      if (p + n.len > end)
619
0
        return 0;
620
0
      memcpy(p, n.ptr, n.len);
621
0
      p += n.len;
622
623
      /* encode the header value. */
624
0
      ret = encode_varint(v.len, &p, end);
625
0
      if (ret == -1)
626
0
        return 0;
627
0
      if (p + v.len > end)
628
0
        return 0;
629
0
      memcpy(p, v.ptr, v.len);
630
0
      p += v.len;
631
632
0
    }
633
0
    else if (type == HTX_BLK_EOH) {
634
      /* encode the end of the header list with empty
635
       * header name and header value.
636
       */
637
0
      ret = encode_varint(0, &p, end);
638
0
      if (ret == -1)
639
0
        return 0;
640
0
      ret = encode_varint(0, &p, end);
641
0
      if (ret == -1)
642
0
        return 0;
643
0
      break;
644
0
    }
645
0
  }
646
647
  /* Initialise sample data which will be filled. */
648
0
  smp->data.type = SMP_T_BIN;
649
0
  smp->data.u.str.area = temp->area;
650
0
  smp->data.u.str.data = p - temp->area;
651
0
  smp->data.u.str.size = temp->size;
652
0
  return 1;
653
0
}
654
655
/* returns the longest available part of the body. This requires that the body
656
 * has been waited for using http-buffer-request.
657
 */
658
static int smp_fetch_body(const struct arg *args, struct sample *smp, const char *kw, void *private)
659
0
{
660
  /* possible keywords: req.body, res.body */
661
0
  struct channel *chn = ((kw[2] == 'q') ? SMP_REQ_CHN(smp) : SMP_RES_CHN(smp));
662
0
  struct check *check = ((kw[2] == 's') ? objt_check(smp->sess->origin) : NULL);
663
0
  struct htx *htx = smp_prefetch_htx(smp, chn, check, 1);
664
0
  struct buffer *chk = NULL;
665
0
  struct ist body = IST_NULL;
666
0
  int32_t pos;
667
0
  int finished = 0;
668
669
0
  if (!htx)
670
0
    return 0;
671
672
0
  if ((htx->flags & (HTX_FL_FRAGMENTED|HTX_FL_UNORDERED)) || htx_space_wraps(htx))
673
0
    htx_defrag(htx, NULL, 0);
674
675
0
  for (pos = htx_get_first(htx); pos != -1; pos = htx_get_next(htx, pos)) {
676
0
    struct htx_blk *blk = htx_get_blk(htx, pos);
677
0
    enum htx_blk_type type = htx_get_blk_type(blk);
678
679
0
    if (type == HTX_BLK_TLR || type == HTX_BLK_EOT) {
680
0
      finished = 1;
681
0
      break;
682
0
    }
683
0
    if (type == HTX_BLK_DATA) {
684
0
      if (isttest(body)) {
685
        /* More than one DATA block we must use a trash */
686
0
        if (!chk) {
687
0
          smp->flags &= ~SMP_F_CONST;
688
          /* <chn> is NULL in the health-check context,
689
           * where the message comes from <check->bi>
690
           */
691
0
          chk = get_best_trash_chunk((chn ? &chn->buf : &check->bi), htx->data);
692
0
          if (!chk || !chunk_istcat(chk, body))
693
0
            return 0;
694
0
        }
695
0
        if (!chunk_istcat(chk, htx_get_blk_value(htx, blk)))
696
0
          return 0;
697
0
        body = ist2(b_orig(chk), b_data(chk));
698
0
      }
699
0
      else {
700
0
        body = htx_get_blk_value(htx, blk);
701
0
        smp->flags |= SMP_F_CONST;
702
0
      }
703
0
    }
704
0
  }
705
706
0
  smp->data.type = SMP_T_BIN;
707
0
  smp->data.u.str.area = istptr(body);
708
0
  smp->data.u.str.data = istlen(body);
709
0
  smp->flags |= SMP_F_VOL_TEST;
710
711
0
  if (!finished && (check || (chn && !channel_full(chn, global.tune.maxrewrite) &&
712
0
            !(chn_prod(chn)->flags & (SC_FL_EOI|SC_FL_EOS|SC_FL_ABRT_DONE)))))
713
0
    smp->flags |= SMP_F_MAY_CHANGE;
714
715
0
  return 1;
716
0
}
717
718
719
/* returns the available length of the body. This requires that the body
720
 * has been waited for using http-buffer-request.
721
 */
722
static int smp_fetch_body_len(const struct arg *args, struct sample *smp, const char *kw, void *private)
723
0
{
724
  /* possible keywords: req.body_len, res.body_len */
725
0
  struct channel *chn = ((kw[2] == 'q') ? SMP_REQ_CHN(smp) : SMP_RES_CHN(smp));
726
0
  struct check *check = ((kw[2] == 's') ? objt_check(smp->sess->origin) : NULL);
727
0
  struct htx *htx = smp_prefetch_htx(smp, chn, check, 1);
728
0
  int32_t pos;
729
0
  unsigned long long len = 0;
730
731
0
  if (!htx)
732
0
    return 0;
733
734
0
  for (pos = htx_get_first(htx); pos != -1; pos = htx_get_next(htx, pos)) {
735
0
    struct htx_blk *blk = htx_get_blk(htx, pos);
736
0
    enum htx_blk_type type = htx_get_blk_type(blk);
737
738
0
    if (type == HTX_BLK_TLR || type == HTX_BLK_EOT)
739
0
      break;
740
0
    if (type == HTX_BLK_DATA)
741
0
      len += htx_get_blksz(blk);
742
0
  }
743
744
0
  smp->data.type = SMP_T_SINT;
745
0
  smp->data.u.sint = len;
746
0
  smp->flags = SMP_F_VOL_TEST;
747
0
  return 1;
748
0
}
749
750
751
/* returns the advertised length of the body, or the advertised size of the
752
 * chunks available in the buffer. This requires that the body has been waited
753
 * for using http-buffer-request.
754
 */
755
static int smp_fetch_body_size(const struct arg *args, struct sample *smp, const char *kw, void *private)
756
0
{
757
  /* possible keywords: req.body_size, res.body_size */
758
0
  struct stconn *sc = ((kw[2] == 'q') ? SMP_REQ_SC(smp) : SMP_RES_SC(smp));
759
0
  struct check *check = ((kw[2] == 's') ? objt_check(smp->sess->origin) : NULL);
760
0
  struct htx *htx = smp_prefetch_htx(smp, (sc ? sc_ic(sc) : NULL), check, 1);
761
0
  unsigned long long len = 0;
762
763
0
  if (!htx)
764
0
    return 0;
765
0
  len = (sc ? sc->sedesc->kip : check->sc->sedesc->kip);
766
767
0
  smp->data.type = SMP_T_SINT;
768
0
  smp->data.u.sint = len;
769
0
  smp->flags = SMP_F_VOL_TEST;
770
0
  return 1;
771
0
}
772
773
774
/* 4. Check on URL/URI. A pointer to the URI is stored. */
775
static int smp_fetch_url(const struct arg *args, struct sample *smp, const char *kw, void *private)
776
0
{
777
0
  struct channel *chn = SMP_REQ_CHN(smp);
778
0
  struct htx *htx = smp_prefetch_htx(smp, chn, NULL, 1);
779
0
  struct htx_sl *sl;
780
781
0
  if (!htx)
782
0
    return 0;
783
0
  sl = http_get_stline(htx);
784
0
  smp->data.type = SMP_T_STR;
785
0
  smp->data.u.str.area = HTX_SL_REQ_UPTR(sl);
786
0
  smp->data.u.str.data = HTX_SL_REQ_ULEN(sl);
787
0
  smp->flags = SMP_F_VOL_1ST | SMP_F_CONST;
788
0
  return 1;
789
0
}
790
791
static int smp_fetch_url_ip(const struct arg *args, struct sample *smp, const char *kw, void *private)
792
0
{
793
0
  struct channel *chn = SMP_REQ_CHN(smp);
794
0
  struct htx *htx = smp_prefetch_htx(smp, chn, NULL, 1);
795
0
  struct htx_sl *sl;
796
0
  struct sockaddr_storage addr;
797
798
0
  memset(&addr, 0, sizeof(addr));
799
800
0
  if (!htx)
801
0
    return 0;
802
0
  sl = http_get_stline(htx);
803
0
  if (url2sa(HTX_SL_REQ_UPTR(sl), HTX_SL_REQ_ULEN(sl), &addr, NULL) < 0)
804
0
    return 0;
805
806
0
  if (addr.ss_family != AF_INET)
807
0
    return 0;
808
809
0
  smp->data.type = SMP_T_IPV4;
810
0
  smp->data.u.ipv4 = ((struct sockaddr_in *)&addr)->sin_addr;
811
0
  smp->flags = 0;
812
0
  return 1;
813
0
}
814
815
static int smp_fetch_url_port(const struct arg *args, struct sample *smp, const char *kw, void *private)
816
0
{
817
0
  struct channel *chn = SMP_REQ_CHN(smp);
818
0
  struct htx *htx = smp_prefetch_htx(smp, chn, NULL, 1);
819
0
  struct htx_sl *sl;
820
0
  struct sockaddr_storage addr;
821
822
0
  memset(&addr, 0, sizeof(addr));
823
824
0
  if (!htx)
825
0
    return 0;
826
0
  sl = http_get_stline(htx);
827
0
  if (url2sa(HTX_SL_REQ_UPTR(sl), HTX_SL_REQ_ULEN(sl), &addr, NULL) < 0)
828
0
    return 0;
829
830
0
  if (addr.ss_family != AF_INET)
831
0
    return 0;
832
833
0
  smp->data.type = SMP_T_SINT;
834
0
  smp->data.u.sint = get_host_port(&addr);
835
0
  smp->flags = 0;
836
0
  return 1;
837
0
}
838
839
/* Fetch an HTTP header. A pointer to the beginning of the value is returned.
840
 * Accepts an optional argument of type string containing the header field name,
841
 * and an optional argument of type signed or unsigned integer to request an
842
 * explicit occurrence of the header. Note that in the event of a missing name,
843
 * headers are considered from the first one. It does not stop on commas and
844
 * returns full lines instead (useful for User-Agent or Date for example).
845
 */
846
static int smp_fetch_fhdr(const struct arg *args, struct sample *smp, const char *kw, void *private)
847
0
{
848
  /* possible keywords: req.fhdr, res.fhdr */
849
0
  struct channel *chn = ((kw[2] == 'q') ? SMP_REQ_CHN(smp) : SMP_RES_CHN(smp));
850
0
  struct check *check = ((kw[2] == 's') ? objt_check(smp->sess->origin) : NULL);
851
0
  struct htx *htx = smp_prefetch_htx(smp, chn, check, 1);
852
0
  struct http_hdr_ctx *ctx = smp->ctx.a[0];
853
0
  struct ist name;
854
0
  int occ = 0;
855
856
0
  if (!ctx) {
857
    /* first call */
858
0
    ctx = &static_http_hdr_ctx;
859
0
    ctx->blk = NULL;
860
0
    smp->ctx.a[0] = ctx;
861
0
  }
862
863
0
  if (args[0].type != ARGT_STR)
864
0
    return 0;
865
0
  name = ist2(args[0].data.str.area, args[0].data.str.data);
866
867
0
  if (args[1].type == ARGT_SINT)
868
0
    occ = args[1].data.sint;
869
870
0
  if (!htx)
871
0
    return 0;
872
873
0
  if (ctx && !(smp->flags & SMP_F_NOT_LAST))
874
    /* search for header from the beginning */
875
0
    ctx->blk = NULL;
876
877
0
  if (!occ && !(smp->opt & SMP_OPT_ITERATE))
878
    /* no explicit occurrence and single fetch => last header by default */
879
0
    occ = -1;
880
881
0
  if (!occ)
882
    /* prepare to report multiple occurrences for ACL fetches */
883
0
    smp->flags |= SMP_F_NOT_LAST;
884
885
0
  smp->data.type = SMP_T_STR;
886
0
  smp->flags |= SMP_F_VOL_HDR | SMP_F_CONST;
887
0
  if (http_get_htx_fhdr(htx, name, occ, ctx, &smp->data.u.str.area, &smp->data.u.str.data))
888
0
    return 1;
889
0
  smp->flags &= ~SMP_F_NOT_LAST;
890
0
  return 0;
891
0
}
892
893
/* 6. Check on HTTP header count. The number of occurrences is returned.
894
 * Accepts exactly 1 argument of type string. It does not stop on commas and
895
 * returns full lines instead (useful for User-Agent or Date for example).
896
 */
897
static int smp_fetch_fhdr_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
898
0
{
899
  /* possible keywords: req.fhdr_cnt, res.fhdr_cnt */
900
0
  struct channel *chn = ((kw[2] == 'q') ? SMP_REQ_CHN(smp) : SMP_RES_CHN(smp));
901
0
  struct check *check = ((kw[2] == 's') ? objt_check(smp->sess->origin) : NULL);
902
0
  struct htx *htx = smp_prefetch_htx(smp, chn, check, 1);
903
0
  struct http_hdr_ctx ctx;
904
0
  struct ist name;
905
0
  int cnt;
906
907
0
  if (!htx)
908
0
    return 0;
909
910
0
  if (args->type == ARGT_STR) {
911
0
    name = ist2(args->data.str.area, args->data.str.data);
912
0
  } else {
913
0
    name = IST_NULL;
914
0
  }
915
916
0
  ctx.blk = NULL;
917
0
  cnt = 0;
918
0
  while (http_find_header(htx, name, &ctx, 1))
919
0
    cnt++;
920
0
  smp->data.type = SMP_T_SINT;
921
0
  smp->data.u.sint = cnt;
922
0
  smp->flags = SMP_F_VOL_HDR;
923
0
  return 1;
924
0
}
925
926
static int smp_fetch_hdr_names(const struct arg *args, struct sample *smp, const char *kw, void *private)
927
0
{
928
  /* possible keywords: req.hdr_names, res.hdr_names */
929
0
  struct channel *chn = ((kw[2] == 'q') ? SMP_REQ_CHN(smp) : SMP_RES_CHN(smp));
930
0
  struct check *check = ((kw[2] == 's') ? objt_check(smp->sess->origin) : NULL);
931
0
  struct htx *htx = smp_prefetch_htx(smp, chn, check, 1);
932
0
  struct buffer *temp;
933
0
  char del = ',';
934
935
0
  int32_t pos;
936
937
0
  if (!htx)
938
0
    return 0;
939
940
0
  if (args->type == ARGT_STR)
941
0
    del = *args[0].data.str.area;
942
943
0
  temp = get_trash_chunk();
944
0
  for (pos = htx_get_first(htx); pos != -1; pos = htx_get_next(htx, pos)) {
945
0
    struct htx_blk *blk = htx_get_blk(htx, pos);
946
0
    enum htx_blk_type type = htx_get_blk_type(blk);
947
0
    struct ist n;
948
949
0
    if (type == HTX_BLK_EOH)
950
0
      break;
951
0
    if (type != HTX_BLK_HDR)
952
0
      continue;
953
0
    n = htx_get_blk_name(htx, blk);
954
955
0
    if (temp->data) {
956
0
      if (!chunk_memcat(temp, &del, 1))
957
0
        return 0;
958
0
    }
959
0
    if (!chunk_istcat(temp, n))
960
0
      return 0;
961
0
  }
962
963
0
  smp->data.type = SMP_T_STR;
964
0
  smp->data.u.str = *temp;
965
0
  smp->flags = SMP_F_VOL_HDR;
966
0
  return 1;
967
0
}
968
969
/* Fetch an HTTP header. A pointer to the beginning of the value is returned.
970
 * Accepts an optional argument of type string containing the header field name,
971
 * and an optional argument of type signed or unsigned integer to request an
972
 * explicit occurrence of the header. Note that in the event of a missing name,
973
 * headers are considered from the first one.
974
 */
975
static int smp_fetch_hdr(const struct arg *args, struct sample *smp, const char *kw, void *private)
976
0
{
977
  /* possible keywords: req.hdr / hdr, res.hdr / shdr */
978
0
  struct channel *chn = ((kw[0] == 'h' || kw[2] == 'q') ? SMP_REQ_CHN(smp) : SMP_RES_CHN(smp));
979
0
  struct check *check = ((kw[0] == 's' || kw[2] == 's') ? objt_check(smp->sess->origin) : NULL);
980
0
  struct htx *htx = smp_prefetch_htx(smp, chn, check, 1);
981
0
  struct http_hdr_ctx *ctx = smp->ctx.a[0];
982
0
  struct ist name;
983
0
  int occ = 0;
984
985
0
  if (!ctx) {
986
    /* first call */
987
0
    ctx = &static_http_hdr_ctx;
988
0
    ctx->blk = NULL;
989
0
    smp->ctx.a[0] = ctx;
990
0
  }
991
992
0
  if (args[0].type != ARGT_STR)
993
0
    return 0;
994
0
  name = ist2(args[0].data.str.area, args[0].data.str.data);
995
996
0
  if (args[1].type == ARGT_SINT)
997
0
    occ = args[1].data.sint;
998
999
0
  if (!htx)
1000
0
    return 0;
1001
1002
0
  if (ctx && !(smp->flags & SMP_F_NOT_LAST))
1003
    /* search for header from the beginning */
1004
0
    ctx->blk = NULL;
1005
1006
0
  if (!occ && !(smp->opt & SMP_OPT_ITERATE))
1007
    /* no explicit occurrence and single fetch => last header by default */
1008
0
    occ = -1;
1009
1010
0
  if (!occ)
1011
    /* prepare to report multiple occurrences for ACL fetches */
1012
0
    smp->flags |= SMP_F_NOT_LAST;
1013
1014
0
  smp->data.type = SMP_T_STR;
1015
0
  smp->flags |= SMP_F_VOL_HDR | SMP_F_CONST;
1016
0
  if (http_get_htx_hdr(htx, name, occ, ctx, &smp->data.u.str.area, &smp->data.u.str.data))
1017
0
    return 1;
1018
1019
0
  smp->flags &= ~SMP_F_NOT_LAST;
1020
0
  return 0;
1021
0
}
1022
1023
/* Same than smp_fetch_hdr() but only relies on the sample direction to choose
1024
 * the right channel. So instead of duplicating the code, we just change the
1025
 * keyword and then fallback on smp_fetch_hdr().
1026
 */
1027
static int smp_fetch_chn_hdr(const struct arg *args, struct sample *smp, const char *kw, void *private)
1028
0
{
1029
0
  kw = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_REQ ? "req.hdr" : "res.hdr");
1030
0
  return smp_fetch_hdr(args, smp, kw, private);
1031
0
}
1032
1033
/* 6. Check on HTTP header count. The number of occurrences is returned.
1034
 * Accepts exactly 1 argument of type string.
1035
 */
1036
static int smp_fetch_hdr_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
1037
0
{
1038
  /* possible keywords: req.hdr_cnt / hdr_cnt, res.hdr_cnt / shdr_cnt */
1039
0
  struct channel *chn = ((kw[0] == 'h' || kw[2] == 'q') ? SMP_REQ_CHN(smp) : SMP_RES_CHN(smp));
1040
0
  struct check *check = ((kw[0] == 's' || kw[2] == 's') ? objt_check(smp->sess->origin) : NULL);
1041
0
  struct htx *htx = smp_prefetch_htx(smp, chn, check, 1);
1042
0
  struct http_hdr_ctx ctx;
1043
0
  struct ist name;
1044
0
  int cnt;
1045
1046
0
  if (!htx)
1047
0
    return 0;
1048
1049
0
  if (args->type == ARGT_STR) {
1050
0
    name = ist2(args->data.str.area, args->data.str.data);
1051
0
  } else {
1052
0
    name = IST_NULL;
1053
0
  }
1054
1055
0
  ctx.blk = NULL;
1056
0
  cnt = 0;
1057
0
  while (http_find_header(htx, name, &ctx, 0))
1058
0
    cnt++;
1059
1060
0
  smp->data.type = SMP_T_SINT;
1061
0
  smp->data.u.sint = cnt;
1062
0
  smp->flags = SMP_F_VOL_HDR;
1063
0
  return 1;
1064
0
}
1065
1066
/* Fetch an HTTP header's integer value. The integer value is returned. It
1067
 * takes a mandatory argument of type string and an optional one of type int
1068
 * to designate a specific occurrence. It returns an unsigned integer, which
1069
 * may or may not be appropriate for everything.
1070
 */
1071
static int smp_fetch_hdr_val(const struct arg *args, struct sample *smp, const char *kw, void *private)
1072
0
{
1073
0
  int ret = smp_fetch_hdr(args, smp, kw, private);
1074
1075
0
  if (ret > 0) {
1076
0
    smp->data.type = SMP_T_SINT;
1077
0
    smp->data.u.sint = strl2ic(smp->data.u.str.area,
1078
0
             smp->data.u.str.data);
1079
0
  }
1080
1081
0
  return ret;
1082
0
}
1083
1084
/* Fetch an HTTP header's IP value. takes a mandatory argument of type string
1085
 * and an optional one of type int to designate a specific occurrence.
1086
 * It returns an IPv4 or IPv6 address. Addresses surrounded by invalid chars
1087
 * are rejected. However IPv4 addresses may be followed with a colon and a
1088
 * valid port number.
1089
 */
1090
static int smp_fetch_hdr_ip(const struct arg *args, struct sample *smp, const char *kw, void *private)
1091
0
{
1092
0
  struct buffer *temp = get_trash_chunk();
1093
0
  int ret, len;
1094
0
  int port;
1095
1096
0
  while ((ret = smp_fetch_hdr(args, smp, kw, private)) > 0) {
1097
0
    if (smp->data.u.str.data < temp->size - 1) {
1098
0
      memcpy(temp->area, smp->data.u.str.area,
1099
0
             smp->data.u.str.data);
1100
0
      temp->area[smp->data.u.str.data] = '\0';
1101
0
      len = url2ipv4((char *) temp->area, &smp->data.u.ipv4);
1102
0
      if (len > 0 && len == smp->data.u.str.data) {
1103
        /* plain IPv4 address */
1104
0
        smp->data.type = SMP_T_IPV4;
1105
0
        break;
1106
0
      } else if (len > 0 && temp->area[len] == ':' &&
1107
0
           strl2irc(temp->area + len + 1, smp->data.u.str.data - len - 1, &port) == 0 &&
1108
0
           port >= 0 && port <= 65535) {
1109
        /* IPv4 address suffixed with ':' followed by a valid port number */
1110
0
        smp->data.type = SMP_T_IPV4;
1111
0
        break;
1112
0
      } else if (smp->data.u.str.data >= 2 && temp->area[0] == '[' && temp->area[smp->data.u.str.data-1] == ']') {
1113
        /* IPv6 address enclosed in square brackets */
1114
0
        temp->area[smp->data.u.str.data-1] = '\0';
1115
0
        if (inet_pton(AF_INET6, temp->area+1, &smp->data.u.ipv6)) {
1116
0
          smp->data.type = SMP_T_IPV6;
1117
0
          break;
1118
0
        }
1119
0
      } else if (inet_pton(AF_INET6, temp->area, &smp->data.u.ipv6)) {
1120
        /* plain IPv6 address */
1121
0
        smp->data.type = SMP_T_IPV6;
1122
0
        break;
1123
0
      }
1124
0
    }
1125
1126
    /* if the header doesn't match an IP address, fetch next one */
1127
0
    if (!(smp->flags & SMP_F_NOT_LAST))
1128
0
      return 0;
1129
0
  }
1130
0
  return ret;
1131
0
}
1132
1133
/* 8. Check on URI PATH. A pointer to the PATH is stored. The path starts at the
1134
 * first '/' after the possible hostname. It ends before the possible '?' except
1135
 * for 'pathq' keyword.
1136
 */
1137
static int smp_fetch_path(const struct arg *args, struct sample *smp, const char *kw, void *private)
1138
0
{
1139
0
  struct channel *chn = SMP_REQ_CHN(smp);
1140
0
  struct htx *htx = smp_prefetch_htx(smp, chn, NULL, 1);
1141
0
  struct htx_sl *sl;
1142
0
  struct ist path;
1143
0
  struct http_uri_parser parser;
1144
1145
0
  if (!htx)
1146
0
    return 0;
1147
1148
0
  sl = http_get_stline(htx);
1149
0
  parser = http_uri_parser_init(htx_sl_req_uri(sl));
1150
1151
0
  if (kw[4] == 'q' && (kw[0] == 'p' || kw[0] == 'b')) // pathq or baseq
1152
0
    path = http_parse_path(&parser);
1153
0
  else
1154
0
    path = iststop(http_parse_path(&parser), '?');
1155
1156
0
  if (!isttest(path))
1157
0
    return 0;
1158
1159
  /* OK, we got the '/' ! */
1160
0
  smp->data.type = SMP_T_STR;
1161
0
  smp->data.u.str.area = path.ptr;
1162
0
  smp->data.u.str.data = path.len;
1163
0
  smp->flags = SMP_F_VOL_1ST | SMP_F_CONST;
1164
0
  return 1;
1165
0
}
1166
1167
/* This produces a concatenation of the first occurrence of the Host header
1168
 * followed by the path component if it begins with a slash ('/'). This means
1169
 * that '*' will not be added, resulting in exactly the first Host entry.
1170
 * If no Host header is found, then the path is returned as-is. The returned
1171
 * value is stored in the trash so it does not need to be marked constant.
1172
 * The returned sample is of type string.
1173
 */
1174
static int smp_fetch_base(const struct arg *args, struct sample *smp, const char *kw, void *private)
1175
0
{
1176
0
  struct channel *chn = SMP_REQ_CHN(smp);
1177
0
  struct htx *htx = smp_prefetch_htx(smp, chn, NULL, 1);
1178
0
  struct htx_sl *sl;
1179
0
  struct buffer *temp;
1180
0
  struct http_hdr_ctx ctx;
1181
0
  struct ist path;
1182
0
  struct http_uri_parser parser;
1183
1184
0
  if (!htx)
1185
0
    return 0;
1186
1187
0
  ctx.blk = NULL;
1188
0
  if (!http_find_header(htx, ist("Host"), &ctx, 0) || !ctx.value.len)
1189
0
    return smp_fetch_path(args, smp, kw, private);
1190
1191
  /* OK we have the header value in ctx.value */
1192
0
  temp = get_trash_chunk();
1193
0
  if (!chunk_istcat(temp, ctx.value))
1194
0
    return 0;
1195
1196
  /* now retrieve the path */
1197
0
  sl = http_get_stline(htx);
1198
0
  parser = http_uri_parser_init(htx_sl_req_uri(sl));
1199
0
  path = http_parse_path(&parser);
1200
0
  if (isttest(path)) {
1201
0
    size_t len;
1202
1203
0
    if (kw[4] == 'q' && kw[0] == 'b') { // baseq
1204
0
      len = path.len;
1205
0
    } else {
1206
0
      for (len = 0; len < path.len && *(path.ptr + len) != '?'; len++)
1207
0
        ;
1208
0
    }
1209
1210
0
    if (len && *(path.ptr) == '/') {
1211
0
      if (!chunk_memcat(temp, path.ptr, len))
1212
0
        return 0;
1213
0
    }
1214
0
  }
1215
1216
0
  smp->data.type = SMP_T_STR;
1217
0
  smp->data.u.str = *temp;
1218
0
  smp->flags = SMP_F_VOL_1ST;
1219
0
  return 1;
1220
0
}
1221
1222
/* This produces a 32-bit hash of the concatenation of the first occurrence of
1223
 * the Host header followed by the path component if it begins with a slash ('/').
1224
 * This means that '*' will not be added, resulting in exactly the first Host
1225
 * entry. If no Host header is found, then the path is used. The resulting value
1226
 * is hashed using the path hash followed by a full avalanche hash and provides a
1227
 * 32-bit integer value. This fetch is useful for tracking per-path activity on
1228
 * high-traffic sites without having to store whole paths.
1229
 */
1230
static int smp_fetch_base32(const struct arg *args, struct sample *smp, const char *kw, void *private)
1231
0
{
1232
0
  struct channel *chn = SMP_REQ_CHN(smp);
1233
0
  struct htx *htx = smp_prefetch_htx(smp, chn, NULL, 1);
1234
0
  struct htx_sl *sl;
1235
0
  struct http_hdr_ctx ctx;
1236
0
  struct ist path;
1237
0
  unsigned int hash = 0;
1238
0
  struct http_uri_parser parser;
1239
1240
0
  if (!htx)
1241
0
    return 0;
1242
1243
0
  ctx.blk = NULL;
1244
0
  if (http_find_header(htx, ist("Host"), &ctx, 0)) {
1245
    /* OK we have the header value in ctx.value */
1246
0
    while (ctx.value.len--)
1247
0
      hash = *(ctx.value.ptr++) + (hash << 6) + (hash << 16) - hash;
1248
0
  }
1249
1250
  /* now retrieve the path */
1251
0
  sl = http_get_stline(htx);
1252
0
  parser = http_uri_parser_init(htx_sl_req_uri(sl));
1253
0
  path = http_parse_path(&parser);
1254
0
  if (isttest(path)) {
1255
0
    size_t len;
1256
1257
0
    for (len = 0; len < path.len && *(path.ptr + len) != '?'; len++)
1258
0
      ;
1259
1260
0
    if (len && *(path.ptr) == '/') {
1261
0
      while (len--)
1262
0
        hash = *(path.ptr++) + (hash << 6) + (hash << 16) - hash;
1263
0
    }
1264
0
  }
1265
1266
0
  hash = full_hash(hash);
1267
1268
0
  smp->data.type = SMP_T_SINT;
1269
0
  smp->data.u.sint = hash;
1270
0
  smp->flags = SMP_F_VOL_1ST;
1271
0
  return 1;
1272
0
}
1273
1274
/* This concatenates the source address with the 32-bit hash of the Host and
1275
 * path as returned by smp_fetch_base32(). The idea is to have per-source and
1276
 * per-path counters. The result is a binary block from 8 to 20 bytes depending
1277
 * on the source address length. The path hash is stored before the address so
1278
 * that in environments where IPv6 is insignificant, truncating the output to
1279
 * 8 bytes would still work.
1280
 */
1281
static int smp_fetch_base32_src(const struct arg *args, struct sample *smp, const char *kw, void *private)
1282
0
{
1283
0
  const struct sockaddr_storage *src = (smp->strm ? sc_src(smp->strm->scf) : NULL);
1284
0
  struct buffer *temp;
1285
1286
0
  if (!src)
1287
0
    return 0;
1288
1289
0
  if (!smp_fetch_base32(args, smp, kw, private))
1290
0
    return 0;
1291
1292
0
  temp = get_trash_chunk();
1293
0
  *(unsigned int *) temp->area = htonl(smp->data.u.sint);
1294
0
  temp->data += sizeof(unsigned int);
1295
1296
0
  switch (src->ss_family) {
1297
0
  case AF_INET:
1298
0
    memcpy(temp->area + temp->data,
1299
0
           &((struct sockaddr_in *)src)->sin_addr,
1300
0
           4);
1301
0
    temp->data += 4;
1302
0
    break;
1303
0
  case AF_INET6:
1304
0
    memcpy(temp->area + temp->data,
1305
0
           &((struct sockaddr_in6 *)src)->sin6_addr,
1306
0
           16);
1307
0
    temp->data += 16;
1308
0
    break;
1309
0
  default:
1310
0
    return 0;
1311
0
  }
1312
1313
0
  smp->data.u.str = *temp;
1314
0
  smp->data.type = SMP_T_BIN;
1315
0
  return 1;
1316
0
}
1317
1318
/* Extracts the query string, which comes after the question mark '?'. If no
1319
 * question mark is found, nothing is returned. Otherwise it returns a sample
1320
 * of type string carrying the whole query string.
1321
 */
1322
static int smp_fetch_query(const struct arg *args, struct sample *smp, const char *kw, void *private)
1323
0
{
1324
0
  struct channel *chn = SMP_REQ_CHN(smp);
1325
0
  struct htx *htx = smp_prefetch_htx(smp, chn, NULL, 1);
1326
0
  struct htx_sl *sl;
1327
0
  char *ptr, *end;
1328
1329
0
  if (!htx)
1330
0
    return 0;
1331
1332
0
  sl = http_get_stline(htx);
1333
0
  ptr = HTX_SL_REQ_UPTR(sl);
1334
0
  end = HTX_SL_REQ_UPTR(sl) + HTX_SL_REQ_ULEN(sl);
1335
1336
  /* look up the '?' */
1337
0
  do {
1338
0
    if (ptr == end)
1339
0
      return 0;
1340
0
  } while (*ptr++ != '?');
1341
1342
0
  if (ptr != end && args[0].type == ARGT_SINT && args[0].data.sint == 1)
1343
0
    ptr--;
1344
1345
0
  smp->data.type = SMP_T_STR;
1346
0
  smp->data.u.str.area = ptr;
1347
0
  smp->data.u.str.data = end - ptr;
1348
0
  smp->flags = SMP_F_VOL_1ST | SMP_F_CONST;
1349
0
  return 1;
1350
0
}
1351
1352
static int smp_fetch_proto_http(const struct arg *args, struct sample *smp, const char *kw, void *private)
1353
0
{
1354
0
  struct channel *chn = SMP_REQ_CHN(smp);
1355
0
  struct htx *htx = smp_prefetch_htx(smp, chn, NULL, 0);
1356
1357
0
  if (!htx)
1358
0
    return 0;
1359
0
  smp->data.type = SMP_T_BOOL;
1360
0
  smp->data.u.sint = 1;
1361
0
  return 1;
1362
0
}
1363
1364
/* return a valid test if the current request is the first one on the connection */
1365
static int smp_fetch_http_first_req(const struct arg *args, struct sample *smp, const char *kw, void *private)
1366
0
{
1367
0
  if (!smp->strm || !smp->strm->txn.http)
1368
0
    return 0;
1369
1370
0
  smp->data.type = SMP_T_BOOL;
1371
0
  smp->data.u.sint = !(smp->strm->txn.http->flags & TX_NOT_FIRST);
1372
0
  return 1;
1373
0
}
1374
1375
/* Fetch the authentication method if there is an Authorization header. It
1376
 * relies on get_http_auth()
1377
 */
1378
static int smp_fetch_http_auth_type(const struct arg *args, struct sample *smp, const char *kw, void *private)
1379
0
{
1380
0
  struct channel *chn = SMP_REQ_CHN(smp);
1381
0
  struct htx *htx = smp_prefetch_htx(smp, chn, NULL, 1);
1382
0
  struct http_txn *txn;
1383
1384
0
  if (!htx)
1385
0
    return 0;
1386
1387
0
  txn = smp->strm->txn.http;
1388
0
  if (!get_http_auth(smp, htx))
1389
0
    return 0;
1390
1391
0
  switch (txn->auth.method) {
1392
0
    case HTTP_AUTH_BASIC:
1393
0
      smp->data.u.str.area = "Basic";
1394
0
      smp->data.u.str.data = 5;
1395
0
      break;
1396
0
    case HTTP_AUTH_DIGEST:
1397
      /* Unexpected because not supported */
1398
0
      smp->data.u.str.area = "Digest";
1399
0
      smp->data.u.str.data = 6;
1400
0
      break;
1401
0
    case HTTP_AUTH_BEARER:
1402
0
      smp->data.u.str.area = "Bearer";
1403
0
      smp->data.u.str.data = 6;
1404
0
      break;
1405
0
    default:
1406
0
      return 0;
1407
0
  }
1408
1409
0
  smp->data.type = SMP_T_STR;
1410
0
  smp->flags = SMP_F_CONST;
1411
0
  return 1;
1412
0
}
1413
1414
/* Fetch the user supplied if there is an Authorization header. It relies on
1415
 * get_http_auth()
1416
 */
1417
static int smp_fetch_http_auth_user(const struct arg *args, struct sample *smp, const char *kw, void *private)
1418
0
{
1419
0
  struct channel *chn = SMP_REQ_CHN(smp);
1420
0
  struct htx *htx = smp_prefetch_htx(smp, chn, NULL, 1);
1421
0
  struct http_txn *txn;
1422
1423
0
  if (!htx)
1424
0
    return 0;
1425
1426
0
  txn = smp->strm->txn.http;
1427
0
  if (!get_http_auth(smp, htx) || txn->auth.method != HTTP_AUTH_BASIC)
1428
0
    return 0;
1429
1430
0
  smp->data.type = SMP_T_STR;
1431
0
  smp->data.u.str.area = txn->auth.user;
1432
0
  smp->data.u.str.data = strlen(txn->auth.user);
1433
0
  smp->flags = SMP_F_CONST;
1434
0
  return 1;
1435
0
}
1436
1437
/* Fetch the password supplied if there is an Authorization header. It relies on
1438
 * get_http_auth()
1439
 */
1440
static int smp_fetch_http_auth_pass(const struct arg *args, struct sample *smp, const char *kw, void *private)
1441
0
{
1442
0
  struct channel *chn = SMP_REQ_CHN(smp);
1443
0
  struct htx *htx = smp_prefetch_htx(smp, chn, NULL, 1);
1444
0
  struct http_txn *txn;
1445
1446
0
  if (!htx)
1447
0
    return 0;
1448
1449
0
  txn = smp->strm->txn.http;
1450
0
  if (!get_http_auth(smp, htx) || txn->auth.method != HTTP_AUTH_BASIC)
1451
0
    return 0;
1452
1453
0
  smp->data.type = SMP_T_STR;
1454
0
  smp->data.u.str.area = txn->auth.pass;
1455
0
  smp->data.u.str.data = strlen(txn->auth.pass);
1456
0
  smp->flags = SMP_F_CONST;
1457
0
  return 1;
1458
0
}
1459
1460
static int smp_fetch_http_auth_bearer(const struct arg *args, struct sample *smp, const char *kw, void *private)
1461
0
{
1462
0
  struct channel *chn = SMP_REQ_CHN(smp);
1463
0
  struct htx *htx = smp_prefetch_htx(smp, chn, NULL, 1);
1464
0
  struct http_txn *txn;
1465
0
  struct buffer bearer_val = {};
1466
1467
0
  if (!htx)
1468
0
    return 0;
1469
1470
0
  if (args->type == ARGT_STR) {
1471
0
    struct http_hdr_ctx ctx;
1472
0
    struct ist hdr_name = ist2(args->data.str.area, args->data.str.data);
1473
1474
0
    ctx.blk = NULL;
1475
0
    if (http_find_header(htx, hdr_name, &ctx, 0)) {
1476
0
      struct ist type = istsplit(&ctx.value, ' ');
1477
1478
      /* no space was found or the space is the first character or no "Bearer" method */
1479
0
      if (!istlen(type) || istlen(type) == istlen(ctx.value) || !isteqi(type, ist("Bearer")))
1480
0
        return 0;
1481
1482
      /* There must be "at least" one space character between
1483
       * the scheme and the following value so ctx.value might
1484
       * still have leading spaces here (see RFC7235).
1485
       */
1486
0
      ctx.value = istskip(ctx.value, ' ');
1487
0
      chunk_initlen(&bearer_val, istptr(ctx.value), 0, istlen(ctx.value));
1488
0
    }
1489
0
  }
1490
0
  else {
1491
0
    txn = smp->strm->txn.http;
1492
0
    if (!get_http_auth(smp, htx) || txn->auth.method != HTTP_AUTH_BEARER)
1493
0
      return 0;
1494
1495
0
    bearer_val = txn->auth.method_data;
1496
0
  }
1497
1498
0
  smp->data.type = SMP_T_STR;
1499
0
  smp->data.u.str = bearer_val;
1500
0
  smp->flags = SMP_F_CONST;
1501
0
  return 1;
1502
0
}
1503
1504
/* Accepts exactly 1 argument of type userlist */
1505
static int smp_fetch_http_auth(const struct arg *args, struct sample *smp, const char *kw, void *private)
1506
0
{
1507
0
  struct channel *chn = SMP_REQ_CHN(smp);
1508
0
  struct htx *htx = smp_prefetch_htx(smp, chn, NULL, 1);
1509
1510
0
  if (args->type != ARGT_USR)
1511
0
    return 0;
1512
1513
0
  if (!htx)
1514
0
    return 0;
1515
0
  if (!get_http_auth(smp, htx) || smp->strm->txn.http->auth.method != HTTP_AUTH_BASIC)
1516
0
    return 0;
1517
1518
0
  smp->data.type = SMP_T_BOOL;
1519
0
  smp->data.u.sint = check_user(args->data.usr, smp->strm->txn.http->auth.user,
1520
0
              smp->strm->txn.http->auth.pass);
1521
0
  return 1;
1522
0
}
1523
1524
/* Accepts exactly 1 argument of type userlist */
1525
static int smp_fetch_http_auth_grp(const struct arg *args, struct sample *smp, const char *kw, void *private)
1526
0
{
1527
0
  struct channel *chn = SMP_REQ_CHN(smp);
1528
0
  struct htx *htx = smp_prefetch_htx(smp, chn, NULL, 1);
1529
1530
0
  if (args->type != ARGT_USR)
1531
0
    return 0;
1532
1533
0
  if (!htx)
1534
0
    return 0;
1535
0
  if (!get_http_auth(smp, htx) || smp->strm->txn.http->auth.method != HTTP_AUTH_BASIC)
1536
0
    return 0;
1537
1538
  /* if the user does not belong to the userlist or has a wrong password,
1539
   * report that it unconditionally does not match. Otherwise we return
1540
   * a string containing the username.
1541
   */
1542
0
  if (!check_user(args->data.usr, smp->strm->txn.http->auth.user,
1543
0
                  smp->strm->txn.http->auth.pass))
1544
0
    return 0;
1545
1546
  /* pat_match_auth() will need the user list */
1547
0
  smp->ctx.a[0] = args->data.usr;
1548
1549
0
  smp->data.type = SMP_T_STR;
1550
0
  smp->flags = SMP_F_CONST;
1551
0
  smp->data.u.str.area = smp->strm->txn.http->auth.user;
1552
0
  smp->data.u.str.data = strlen(smp->strm->txn.http->auth.user);
1553
1554
0
  return 1;
1555
0
}
1556
1557
/* Fetch a captured HTTP request header. The index is the position of
1558
 * the "capture" option in the configuration file
1559
 */
1560
static int smp_fetch_capture_req_hdr(const struct arg *args, struct sample *smp, const char *kw, void *private)
1561
0
{
1562
0
  struct proxy *fe;
1563
0
  int idx;
1564
1565
0
  if (args->type != ARGT_SINT)
1566
0
    return 0;
1567
1568
0
  if (!smp->strm)
1569
0
    return 0;
1570
1571
0
  fe = strm_fe(smp->strm);
1572
0
  idx = args->data.sint;
1573
1574
0
  if (idx > (fe->nb_req_cap - 1) || smp->strm->req_cap == NULL || smp->strm->req_cap[idx] == NULL)
1575
0
    return 0;
1576
1577
0
  smp->data.type = SMP_T_STR;
1578
0
  smp->flags |= SMP_F_CONST;
1579
0
  smp->data.u.str.area = smp->strm->req_cap[idx];
1580
0
  smp->data.u.str.data = strlen(smp->strm->req_cap[idx]);
1581
1582
0
  return 1;
1583
0
}
1584
1585
/* Fetch a captured HTTP response header. The index is the position of
1586
 * the "capture" option in the configuration file
1587
 */
1588
static int smp_fetch_capture_res_hdr(const struct arg *args, struct sample *smp, const char *kw, void *private)
1589
0
{
1590
0
  struct proxy *fe;
1591
0
  int idx;
1592
1593
0
  if (args->type != ARGT_SINT)
1594
0
    return 0;
1595
1596
0
  if (!smp->strm)
1597
0
    return 0;
1598
1599
0
  fe = strm_fe(smp->strm);
1600
0
  idx = args->data.sint;
1601
1602
0
  if (idx > (fe->nb_rsp_cap - 1) || smp->strm->res_cap == NULL || smp->strm->res_cap[idx] == NULL)
1603
0
    return 0;
1604
1605
0
  smp->data.type = SMP_T_STR;
1606
0
  smp->flags |= SMP_F_CONST;
1607
0
  smp->data.u.str.area = smp->strm->res_cap[idx];
1608
0
  smp->data.u.str.data = strlen(smp->strm->res_cap[idx]);
1609
1610
0
  return 1;
1611
0
}
1612
1613
/* Extracts the METHOD in the HTTP request, the txn->uri should be filled before the call */
1614
static int smp_fetch_capture_req_method(const struct arg *args, struct sample *smp, const char *kw, void *private)
1615
0
{
1616
0
  struct buffer *temp;
1617
0
  struct http_txn *txn;
1618
0
  char *ptr;
1619
1620
0
  if (!smp->strm)
1621
0
    return 0;
1622
1623
0
  txn = smp->strm->txn.http;
1624
0
  if (!txn || !txn->uri)
1625
0
    return 0;
1626
1627
0
  ptr = txn->uri;
1628
1629
0
  while (*ptr != ' ' && *ptr != '\0')  /* find first space */
1630
0
    ptr++;
1631
1632
0
  temp = get_trash_chunk();
1633
0
  temp->area = txn->uri;
1634
0
  temp->data = ptr - txn->uri;
1635
0
  smp->data.u.str = *temp;
1636
0
  smp->data.type = SMP_T_STR;
1637
0
  smp->flags = SMP_F_CONST;
1638
1639
0
  return 1;
1640
1641
0
}
1642
1643
/* Extracts the path in the HTTP request, the txn->uri should be filled before the call  */
1644
static int smp_fetch_capture_req_uri(const struct arg *args, struct sample *smp, const char *kw, void *private)
1645
0
{
1646
0
  struct http_txn *txn;
1647
0
  struct ist path;
1648
0
  const char *ptr;
1649
0
  struct http_uri_parser parser;
1650
1651
0
  if (!smp->strm)
1652
0
    return 0;
1653
1654
0
  txn = smp->strm->txn.http;
1655
0
  if (!txn || !txn->uri)
1656
0
    return 0;
1657
1658
0
  ptr = txn->uri;
1659
1660
0
  while (*ptr != ' ' && *ptr != '\0')  /* find first space */
1661
0
    ptr++;
1662
1663
0
  if (!*ptr)
1664
0
    return 0;
1665
1666
  /* skip the first space and find space after URI */
1667
0
  path = ist2(++ptr, 0);
1668
0
  while (*ptr != ' ' && *ptr != '\0')
1669
0
    ptr++;
1670
0
  path.len = ptr - path.ptr;
1671
1672
0
  parser = http_uri_parser_init(path);
1673
0
  path = http_parse_path(&parser);
1674
0
  if (!isttest(path))
1675
0
    return 0;
1676
1677
0
  smp->data.u.str.area = path.ptr;
1678
0
  smp->data.u.str.data = path.len;
1679
0
  smp->data.type = SMP_T_STR;
1680
0
  smp->flags = SMP_F_CONST;
1681
1682
0
  return 1;
1683
0
}
1684
1685
/* Retrieves the HTTP version from the request (either 1.0 or 1.1) and emits it
1686
 * as a string (either "HTTP/1.0" or "HTTP/1.1").
1687
 */
1688
static int smp_fetch_capture_req_ver(const struct arg *args, struct sample *smp, const char *kw, void *private)
1689
0
{
1690
0
  struct stream *s = smp->strm;
1691
0
  struct buffer *vsn;
1692
1693
0
  vsn = get_trash_chunk();
1694
0
  chunk_memcat(vsn, "HTTP/", 5);
1695
0
  if (!get_msg_version((s && s->txn.http) ? &s->txn.http->req : NULL, NULL, vsn))
1696
0
    return 0;
1697
1698
0
  smp->data.type = SMP_T_STR;
1699
0
  smp->data.u.str = *vsn;
1700
0
  return 1;
1701
0
}
1702
1703
/* Retrieves the HTTP version from the response (either 1.0 or 1.1) and emits it
1704
 * as a string (either "HTTP/1.0" or "HTTP/1.1").
1705
 */
1706
static int smp_fetch_capture_res_ver(const struct arg *args, struct sample *smp, const char *kw, void *private)
1707
0
{
1708
0
  struct stream *s = smp->strm;
1709
0
  struct buffer *vsn;
1710
1711
0
  vsn = get_trash_chunk();
1712
0
  chunk_memcat(vsn, "HTTP/", 5);
1713
0
  if (!get_msg_version((s && s->txn.http) ? &s->txn.http->rsp : NULL, NULL, vsn))
1714
0
    return 0;
1715
1716
0
  smp->data.type = SMP_T_STR;
1717
0
  smp->data.u.str = *vsn;
1718
0
  return 1;
1719
1720
0
}
1721
1722
/* Iterate over all cookies present in a message. The context is stored in
1723
 * smp->ctx.a[0] for the in-header position, smp->ctx.a[1] for the
1724
 * end-of-header-value, and smp->ctx.a[2] for the hdr_ctx. Depending on
1725
 * the direction, multiple cookies may be parsed on the same line or not.
1726
 * If provided, the searched cookie name is in args, in args->data.str. If
1727
 * the input options indicate that no iterating is desired, then only last
1728
 * value is fetched if any. If no cookie name is provided, the first cookie
1729
 * value found is fetched. The returned sample is of type CSTR.  Can be used
1730
 * to parse cookies in other files.
1731
 */
1732
static int smp_fetch_cookie(const struct arg *args, struct sample *smp, const char *kw, void *private)
1733
0
{
1734
  /* possible keywords: req.cookie / cookie / cook, res.cookie / scook / set-cookie */
1735
0
  struct channel *chn = ((kw[0] == 'c' || kw[2] == 'q') ? SMP_REQ_CHN(smp) : SMP_RES_CHN(smp));
1736
0
  struct check *check = ((kw[0] == 's' || kw[2] == 's') ? objt_check(smp->sess->origin) : NULL);
1737
0
  struct htx *htx = smp_prefetch_htx(smp, chn, check, 1);
1738
0
  struct http_hdr_ctx *ctx = smp->ctx.a[2];
1739
0
  struct ist hdr;
1740
0
  char *cook = NULL;
1741
0
  size_t cook_l = 0;
1742
0
  int found = 0;
1743
1744
0
  if (args->type == ARGT_STR) {
1745
0
    cook = args->data.str.area;
1746
0
    cook_l = args->data.str.data;
1747
0
  }
1748
1749
0
  if (!ctx) {
1750
    /* first call */
1751
0
    ctx = &static_http_hdr_ctx;
1752
0
    ctx->blk = NULL;
1753
0
    smp->ctx.a[2] = ctx;
1754
0
  }
1755
1756
0
  if (!htx)
1757
0
    return 0;
1758
1759
0
  hdr = (!(check || (chn && chn->flags & CF_ISRESP)) ? ist("Cookie") : ist("Set-Cookie"));
1760
1761
  /* OK so basically here, either we want only one value or we want to
1762
   * iterate over all of them and we fetch the next one. In this last case
1763
   * SMP_OPT_ITERATE option is set.
1764
   */
1765
1766
0
  if (!(smp->flags & SMP_F_NOT_LAST)) {
1767
    /* search for the header from the beginning, we must first initialize
1768
     * the search parameters.
1769
     */
1770
0
    smp->ctx.a[0] = NULL;
1771
0
    ctx->blk = NULL;
1772
0
  }
1773
1774
0
  smp->flags |= SMP_F_VOL_HDR;
1775
0
  while (1) {
1776
    /* Note: smp->ctx.a[0] == NULL every time we need to fetch a new header */
1777
0
    if (!smp->ctx.a[0]) {
1778
0
      if (!http_find_header(htx, hdr, ctx, 0))
1779
0
        goto out;
1780
1781
0
      if (ctx->value.len < cook_l + 1)
1782
0
        continue;
1783
1784
0
      smp->ctx.a[0] = ctx->value.ptr;
1785
0
      smp->ctx.a[1] = smp->ctx.a[0] + ctx->value.len;
1786
0
    }
1787
1788
0
    smp->data.type = SMP_T_STR;
1789
0
    smp->flags |= SMP_F_CONST;
1790
0
    smp->ctx.a[0] = http_extract_cookie_value(smp->ctx.a[0], smp->ctx.a[1],
1791
0
                cook, cook_l,
1792
0
                (smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_REQ,
1793
0
                &smp->data.u.str.area,
1794
0
                &smp->data.u.str.data);
1795
0
    if (smp->ctx.a[0]) {
1796
0
      found = 1;
1797
0
      if (smp->opt & SMP_OPT_ITERATE) {
1798
        /* iterate on cookie value */
1799
0
        smp->flags |= SMP_F_NOT_LAST;
1800
0
        return 1;
1801
0
      }
1802
0
      if (args->data.str.data == 0) {
1803
        /* No cookie name, first occurrence returned */
1804
0
        break;
1805
0
      }
1806
0
    }
1807
    /* if we're looking for last occurrence, let's loop */
1808
0
  }
1809
1810
  /* all cookie headers and values were scanned. If we're looking for the
1811
   * last occurrence, we may return it now.
1812
   */
1813
0
  out:
1814
0
  smp->flags &= ~SMP_F_NOT_LAST;
1815
0
  return found;
1816
0
}
1817
1818
/* Same than smp_fetch_cookie() but only relies on the sample direction to
1819
 * choose the right channel. So instead of duplicating the code, we just change
1820
 * the keyword and then fallback on smp_fetch_cookie().
1821
 */
1822
static int smp_fetch_chn_cookie(const struct arg *args, struct sample *smp, const char *kw, void *private)
1823
0
{
1824
0
  kw = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_REQ ? "req.cook" : "res.cook");
1825
0
  return smp_fetch_cookie(args, smp, kw, private);
1826
0
}
1827
1828
/* Iterate over all cookies present in a request to count how many occurrences
1829
 * match the name in args and args->data.str.len. If <multi> is non-null, then
1830
 * multiple cookies may be parsed on the same line. The returned sample is of
1831
 * type UINT. Accepts exactly 1 argument of type string.
1832
 */
1833
static int smp_fetch_cookie_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
1834
0
{
1835
  /* possible keywords: req.cook_cnt / cook_cnt, res.cook_cnt / scook_cnt */
1836
0
  struct channel *chn = ((kw[0] == 'c' || kw[2] == 'q') ? SMP_REQ_CHN(smp) : SMP_RES_CHN(smp));
1837
0
  struct check *check = ((kw[0] == 's' || kw[2] == 's') ? objt_check(smp->sess->origin) : NULL);
1838
0
  struct htx *htx = smp_prefetch_htx(smp, chn, check, 1);
1839
0
  struct http_hdr_ctx ctx;
1840
0
  struct ist hdr;
1841
0
  char *val_beg, *val_end;
1842
0
  char *cook = NULL;
1843
0
  size_t cook_l = 0;
1844
0
  int cnt;
1845
1846
0
  if (args->type == ARGT_STR){
1847
0
    cook = args->data.str.area;
1848
0
    cook_l = args->data.str.data;
1849
0
  }
1850
1851
0
  if (!htx)
1852
0
    return 0;
1853
1854
0
  hdr = (!(check || (chn && chn->flags & CF_ISRESP)) ? ist("Cookie") : ist("Set-Cookie"));
1855
1856
0
  val_end = val_beg = NULL;
1857
0
  ctx.blk = NULL;
1858
0
  cnt = 0;
1859
0
  while (1) {
1860
    /* Note: val_beg == NULL every time we need to fetch a new header */
1861
0
    if (!val_beg) {
1862
0
      if (!http_find_header(htx, hdr, &ctx, 0))
1863
0
        break;
1864
1865
0
      if (ctx.value.len < cook_l + 1)
1866
0
        continue;
1867
1868
0
      val_beg = ctx.value.ptr;
1869
0
      val_end = val_beg + ctx.value.len;
1870
0
    }
1871
1872
0
    smp->data.type = SMP_T_STR;
1873
0
    smp->flags |= SMP_F_CONST;
1874
0
    while ((val_beg = http_extract_cookie_value(val_beg, val_end,
1875
0
                  cook, cook_l,
1876
0
                  (smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_REQ,
1877
0
                  &smp->data.u.str.area,
1878
0
                  &smp->data.u.str.data))) {
1879
0
      cnt++;
1880
0
    }
1881
0
  }
1882
1883
0
  smp->data.type = SMP_T_SINT;
1884
0
  smp->data.u.sint = cnt;
1885
0
  smp->flags |= SMP_F_VOL_HDR;
1886
0
  return 1;
1887
0
}
1888
1889
/* Fetch an cookie's integer value. The integer value is returned. It
1890
 * takes a mandatory argument of type string. It relies on smp_fetch_cookie().
1891
 */
1892
static int smp_fetch_cookie_val(const struct arg *args, struct sample *smp, const char *kw, void *private)
1893
0
{
1894
0
  int ret = smp_fetch_cookie(args, smp, kw, private);
1895
1896
0
  if (ret > 0) {
1897
0
    smp->data.type = SMP_T_SINT;
1898
0
    smp->data.u.sint = strl2ic(smp->data.u.str.area,
1899
0
             smp->data.u.str.data);
1900
0
  }
1901
1902
0
  return ret;
1903
0
}
1904
1905
/* Iterate over all cookies present in a message,
1906
 * and return the list of cookie names separated by
1907
 * the input argument character.
1908
 * If no input argument is provided,
1909
 * the default delimiter is ','.
1910
 * The returned sample is of type CSTR.
1911
 */
1912
static int smp_fetch_cookie_names(const struct arg *args, struct sample *smp, const char *kw, void *private)
1913
0
{
1914
  /* possible keywords: req.cook_names, res.cook_names */
1915
0
  struct channel *chn = ((kw[2] == 'q') ? SMP_REQ_CHN(smp) : SMP_RES_CHN(smp));
1916
0
  struct check *check = ((kw[2] == 's') ? objt_check(smp->sess->origin) : NULL);
1917
0
  struct htx *htx = smp_prefetch_htx(smp, chn, check, 1);
1918
0
  struct http_hdr_ctx ctx;
1919
0
  struct ist hdr;
1920
0
  struct buffer *temp;
1921
0
  char del = ',';
1922
0
  char *ptr, *attr_beg, *attr_end;
1923
0
  size_t len = 0;
1924
0
  int is_req = !(check || (chn && chn->flags & CF_ISRESP));
1925
1926
0
  if (!htx)
1927
0
    return 0;
1928
1929
0
  if (args->type == ARGT_STR)
1930
0
    del = *args[0].data.str.area;
1931
1932
0
  hdr = (is_req ? ist("Cookie") : ist("Set-Cookie"));
1933
0
  temp = get_trash_chunk();
1934
1935
0
  smp->flags |= SMP_F_VOL_HDR;
1936
0
  attr_end = attr_beg = NULL;
1937
0
  ctx.blk = NULL;
1938
  /* Scan through all headers and extract all cookie names from
1939
   * 1. Cookie header(s) for request channel OR
1940
   * 2. Set-Cookie header(s) for response channel
1941
   */
1942
0
  while (1) {
1943
    /* Note: attr_beg == NULL every time we need to fetch a new header */
1944
0
    if (!attr_beg) {
1945
      /* For Set-Cookie, we need to fetch the entire header line (set flag to 1) */
1946
0
      if (!http_find_header(htx, hdr, &ctx, !is_req))
1947
0
        break;
1948
0
      attr_beg = ctx.value.ptr;
1949
0
      attr_end = attr_beg + ctx.value.len;
1950
0
    }
1951
1952
0
    while (1) {
1953
0
      attr_beg = http_extract_next_cookie_name(attr_beg, attr_end, is_req, &ptr, &len);
1954
0
      if (!attr_beg)
1955
0
        break;
1956
1957
      /* prepend delimiter if this is not the first cookie name found */
1958
0
      if (temp->data)
1959
0
        temp->area[temp->data++] = del;
1960
1961
      /* At this point ptr should point to the start of the cookie name and len would be the length of the cookie name */
1962
0
      if (!chunk_memcat(temp, ptr, len))
1963
0
        return 0;
1964
0
    }
1965
0
  }
1966
0
  smp->data.type = SMP_T_STR;
1967
0
  smp->data.u.str = *temp;
1968
0
  return 1;
1969
0
}
1970
1971
/************************************************************************/
1972
/*           The code below is dedicated to sample fetches              */
1973
/************************************************************************/
1974
1975
/* This scans a URL-encoded query string. It takes an optionally wrapping
1976
 * string whose first contiguous chunk has its beginning in ctx->a[0] and end
1977
 * in ctx->a[1], and the optional second part in (ctx->a[2]..ctx->a[3]). The
1978
 * pointers are updated for next iteration before leaving.
1979
 */
1980
static int smp_fetch_param(char delim, const char *name, int name_len, const struct arg *args, struct sample *smp, const char *kw, void *private, char insensitive)
1981
0
{
1982
0
  const char *vstart, *vend;
1983
0
  struct buffer *temp;
1984
0
  const char **chunks = (const char **)smp->ctx.a;
1985
1986
0
  if (!http_find_next_url_param(chunks, name, name_len,
1987
0
                           &vstart, &vend, delim, insensitive))
1988
0
    return 0;
1989
1990
  /* Create sample. If the value is contiguous, return the pointer as CONST,
1991
   * if the value is wrapped, copy-it in a buffer.
1992
   */
1993
0
  smp->data.type = SMP_T_STR;
1994
0
  if (chunks[2] &&
1995
0
      vstart >= chunks[0] && vstart <= chunks[1] &&
1996
0
      vend >= chunks[2] && vend <= chunks[3]) {
1997
    /* Wrapped case. */
1998
0
    size_t len1 = ( chunks[1] - vstart );
1999
0
    size_t len2 = ( vend - chunks[2] );
2000
2001
0
    temp = get_trash_chunk_sz(len1 + len2);
2002
0
    if (!temp)
2003
0
      return 0;
2004
0
    memcpy(temp->area, vstart, len1);
2005
0
    memcpy(temp->area + len1, chunks[2], len2);
2006
0
    smp->data.u.str.area = temp->area;
2007
0
    smp->data.u.str.data = len1 + len2;
2008
0
  } else {
2009
    /* Contiguous case. */
2010
0
    smp->data.u.str.area = (char *)vstart;
2011
0
    smp->data.u.str.data = vend - vstart;
2012
0
    smp->flags = SMP_F_VOL_1ST | SMP_F_CONST;
2013
0
  }
2014
2015
  /* Update context, check wrapping. */
2016
0
  chunks[0] = vend;
2017
0
  if (chunks[2] && vend >= chunks[2] && vend <= chunks[3]) {
2018
0
    chunks[1] = chunks[3];
2019
0
    chunks[2] = NULL;
2020
0
  }
2021
2022
0
  if (chunks[0] < chunks[1])
2023
0
    smp->flags |= SMP_F_NOT_LAST;
2024
2025
0
  return 1;
2026
0
}
2027
2028
/* This function iterates over each parameter of the query string. It uses
2029
 * ctx->a[0] and ctx->a[1] to store the beginning and end of the current
2030
 * parameter. Since it uses smp_fetch_param(), ctx->a[2..3] are both NULL.
2031
 * An optional parameter name is passed in args[0], otherwise any parameter is
2032
 * considered. It supports an optional delimiter argument for the beginning of
2033
 * the string in args[1], which defaults to "?".
2034
 */
2035
static int smp_fetch_url_param(const struct arg *args, struct sample *smp, const char *kw, void *private)
2036
0
{
2037
0
  struct channel *chn = SMP_REQ_CHN(smp);
2038
0
  char delim = '?';
2039
0
  const char *name;
2040
0
  int name_len;
2041
0
  char insensitive = 0;
2042
2043
0
  if ((args[0].type && args[0].type != ARGT_STR) ||
2044
0
    (args[1].type && args[1].type != ARGT_STR) ||
2045
0
      (args[2].type && args[2].type != ARGT_STR))
2046
0
    return 0;
2047
2048
0
  name = "";
2049
0
  name_len = 0;
2050
0
  if (args->type == ARGT_STR) {
2051
0
    name     = args->data.str.area;
2052
0
    name_len = args->data.str.data;
2053
0
  }
2054
2055
0
  if (args[1].type && *args[1].data.str.area)
2056
0
    delim = *args[1].data.str.area;
2057
0
  if (args[2].type && *args[2].data.str.area == 'i')
2058
0
    insensitive = 1;
2059
2060
0
  if (!smp->ctx.a[0]) { // first call, find the query string
2061
0
    struct htx *htx = smp_prefetch_htx(smp, chn, NULL, 1);
2062
0
    struct htx_sl *sl;
2063
2064
0
    if (!htx)
2065
0
      return 0;
2066
2067
0
    sl = http_get_stline(htx);
2068
0
    smp->ctx.a[0] = http_find_param_list(HTX_SL_REQ_UPTR(sl), HTX_SL_REQ_ULEN(sl), delim);
2069
0
    if (!smp->ctx.a[0])
2070
0
      return 0;
2071
2072
0
    smp->ctx.a[1] = HTX_SL_REQ_UPTR(sl) + HTX_SL_REQ_ULEN(sl);
2073
2074
    /* Assume that the context is filled with NULL pointer
2075
     * before the first call.
2076
     * smp->ctx.a[2] = NULL;
2077
     * smp->ctx.a[3] = NULL;
2078
     */
2079
0
  }
2080
2081
0
  return smp_fetch_param(delim, name, name_len, args, smp, kw, private, insensitive);
2082
0
}
2083
2084
/* This function iterates over each parameter of the body. This requires
2085
 * that the body has been waited for using http-buffer-request. It uses
2086
 * ctx->a[0] and ctx->a[1] to store the beginning and end of the first
2087
 * contiguous part of the body, and optionally ctx->a[2..3] to reference the
2088
 * optional second part if the body wraps at the end of the buffer. An optional
2089
 * parameter name is passed in args[0], otherwise any parameter is considered.
2090
 */
2091
static int smp_fetch_body_param(const struct arg *args, struct sample *smp, const char *kw, void *private)
2092
0
{
2093
0
  struct channel *chn = SMP_REQ_CHN(smp);
2094
0
  const char *name;
2095
0
  int name_len;
2096
0
  char insensitive = 0;
2097
2098
0
  if ((args[0].type && args[0].type != ARGT_STR) ||
2099
0
      (args[1].type && args[1].type != ARGT_STR))
2100
0
    return 0;
2101
2102
0
  name = "";
2103
0
  name_len = 0;
2104
0
  if (args[0].type == ARGT_STR) {
2105
0
    name     = args[0].data.str.area;
2106
0
    name_len = args[0].data.str.data;
2107
0
  }
2108
2109
0
  if (args[1].type && *args[1].data.str.area == 'i')
2110
0
    insensitive = 1;
2111
2112
0
  if (!smp->ctx.a[0]) { // first call, find the query string
2113
0
    struct htx *htx = smp_prefetch_htx(smp, chn, NULL, 1);
2114
0
    struct buffer *chk = NULL;
2115
0
    struct ist body = IST_NULL;
2116
0
    int32_t pos;
2117
2118
0
    if (!htx)
2119
0
      return 0;
2120
2121
0
    if ((htx->flags & (HTX_FL_FRAGMENTED|HTX_FL_UNORDERED)) || htx_space_wraps(htx))
2122
0
      htx_defrag(htx, NULL, 0);
2123
2124
0
    for (pos = htx_get_first(htx); pos != -1; pos = htx_get_next(htx, pos)) {
2125
0
      struct htx_blk   *blk  = htx_get_blk(htx, pos);
2126
0
      enum htx_blk_type type = htx_get_blk_type(blk);
2127
2128
0
      if (type == HTX_BLK_TLR || type == HTX_BLK_EOT)
2129
0
        break;
2130
0
      if (type == HTX_BLK_DATA) {
2131
0
        if (isttest(body)) {
2132
          /* More than one DATA block we must use a trash */
2133
0
          if (!chk) {
2134
0
            chk = get_best_trash_chunk(&chn->buf, htx->data);
2135
0
            if (!chk || !chunk_istcat(chk, body))
2136
0
              break;
2137
0
          }
2138
0
          if (!chunk_istcat(chk, htx_get_blk_value(htx, blk)))
2139
0
            break;
2140
0
          body = ist2(b_orig(chk), b_data(chk));
2141
0
        }
2142
0
        else
2143
0
          body = htx_get_blk_value(htx, blk);
2144
0
      }
2145
0
    }
2146
2147
0
    smp->ctx.a[0] = istptr(body);
2148
0
    smp->ctx.a[1] = istend(body);
2149
2150
    /* Assume that the context is filled with NULL pointer
2151
     * before the first call.
2152
     * smp->ctx.a[2] = NULL;
2153
     * smp->ctx.a[3] = NULL;
2154
     */
2155
0
  }
2156
2157
0
  return smp_fetch_param('&', name, name_len, args, smp, kw, private, insensitive);
2158
0
}
2159
2160
/* Return the signed integer value for the specified url parameter (see url_param
2161
 * above).
2162
 */
2163
static int smp_fetch_url_param_val(const struct arg *args, struct sample *smp, const char *kw, void *private)
2164
0
{
2165
0
  int ret = smp_fetch_url_param(args, smp, kw, private);
2166
2167
0
  if (ret > 0) {
2168
0
    smp->data.type = SMP_T_SINT;
2169
0
    smp->data.u.sint = strl2ic(smp->data.u.str.area,
2170
0
             smp->data.u.str.data);
2171
0
  }
2172
2173
0
  return ret;
2174
0
}
2175
2176
/* This produces a 32-bit hash of the concatenation of the first occurrence of
2177
 * the Host header followed by the path component if it begins with a slash ('/').
2178
 * This means that '*' will not be added, resulting in exactly the first Host
2179
 * entry. If no Host header is found, then the path is used. The resulting value
2180
 * is hashed using the url hash followed by a full avalanche hash and provides a
2181
 * 32-bit integer value. This fetch is useful for tracking per-URL activity on
2182
 * high-traffic sites without having to store whole paths.
2183
 * this differs from the base32 functions in that it includes the url parameters
2184
 * as well as the path
2185
 */
2186
static int smp_fetch_url32(const struct arg *args, struct sample *smp, const char *kw, void *private)
2187
0
{
2188
0
  struct channel *chn = SMP_REQ_CHN(smp);
2189
0
  struct htx *htx = smp_prefetch_htx(smp, chn, NULL, 1);
2190
0
  struct http_hdr_ctx ctx;
2191
0
  struct htx_sl *sl;
2192
0
  struct ist path;
2193
0
  unsigned int hash = 0;
2194
0
  struct http_uri_parser parser;
2195
2196
0
  if (!htx)
2197
0
    return 0;
2198
2199
0
  ctx.blk = NULL;
2200
0
  if (http_find_header(htx, ist("Host"), &ctx, 1)) {
2201
    /* OK we have the header value in ctx.value */
2202
0
    while (ctx.value.len--)
2203
0
      hash = *(ctx.value.ptr++) + (hash << 6) + (hash << 16) - hash;
2204
0
  }
2205
2206
  /* now retrieve the path */
2207
0
  sl = http_get_stline(htx);
2208
0
  parser = http_uri_parser_init(htx_sl_req_uri(sl));
2209
0
  path = http_parse_path(&parser);
2210
0
  if (path.len && *(path.ptr) == '/') {
2211
0
    while (path.len--)
2212
0
      hash = *(path.ptr++) + (hash << 6) + (hash << 16) - hash;
2213
0
  }
2214
2215
0
  hash = full_hash(hash);
2216
2217
0
  smp->data.type = SMP_T_SINT;
2218
0
  smp->data.u.sint = hash;
2219
0
  smp->flags = SMP_F_VOL_1ST;
2220
0
  return 1;
2221
0
}
2222
2223
/* This concatenates the source address with the 32-bit hash of the Host and
2224
 * URL as returned by smp_fetch_url32(). The idea is to have per-source and
2225
 * per-url counters. The result is a binary block from 8 to 20 bytes depending
2226
 * on the source address length. The URL hash is stored before the address so
2227
 * that in environments where IPv6 is insignificant, truncating the output to
2228
 * 8 bytes would still work.
2229
 */
2230
static int smp_fetch_url32_src(const struct arg *args, struct sample *smp, const char *kw, void *private)
2231
0
{
2232
0
  const struct sockaddr_storage *src = (smp->strm ? sc_src(smp->strm->scf) : NULL);
2233
0
  struct buffer *temp;
2234
2235
0
  if (!src)
2236
0
    return 0;
2237
2238
0
  if (!smp_fetch_url32(args, smp, kw, private))
2239
0
    return 0;
2240
2241
0
  temp = get_trash_chunk();
2242
0
  *(unsigned int *) temp->area = htonl(smp->data.u.sint);
2243
0
  temp->data += sizeof(unsigned int);
2244
2245
0
  switch (src->ss_family) {
2246
0
  case AF_INET:
2247
0
    memcpy(temp->area + temp->data,
2248
0
           &((struct sockaddr_in *)src)->sin_addr,
2249
0
           4);
2250
0
    temp->data += 4;
2251
0
    break;
2252
0
  case AF_INET6:
2253
0
    memcpy(temp->area + temp->data,
2254
0
           &((struct sockaddr_in6 *)src)->sin6_addr,
2255
0
           16);
2256
0
    temp->data += 16;
2257
0
    break;
2258
0
  default:
2259
0
    return 0;
2260
0
  }
2261
2262
0
  smp->data.u.str = *temp;
2263
0
  smp->data.type = SMP_T_BIN;
2264
0
  return 1;
2265
0
}
2266
2267
/************************************************************************/
2268
/*                          Other utility functions                     */
2269
/************************************************************************/
2270
2271
/* This function is used to validate the arguments passed to any "hdr" fetch
2272
 * keyword. These keywords support an optional positive or negative occurrence
2273
 * number. We must ensure that the number is greater than -MAX_HDR_HISTORY. It
2274
 * is assumed that the types are already the correct ones. Returns 0 on error,
2275
 * non-zero if OK. If <err> is not NULL, it will be filled with a pointer to an
2276
 * error message in case of error, that the caller is responsible for freeing.
2277
 * The initial location must either be freeable or NULL.
2278
 * Note: this function's pointer is checked from Lua.
2279
 */
2280
int val_hdr(struct arg *arg, char **err_msg)
2281
0
{
2282
0
  if (arg && arg[1].type == ARGT_SINT && arg[1].data.sint < -MAX_HDR_HISTORY) {
2283
0
    memprintf(err_msg, "header occurrence must be >= %d", -MAX_HDR_HISTORY);
2284
0
    return 0;
2285
0
  }
2286
0
  return 1;
2287
0
}
2288
2289
/* This function is used to validate the argument passed to the
2290
 * "capture.req.hdr" and "capture.res.hdr" fetch keywords. The capture
2291
 * identifier is used as an index in the stream's captures array, so it must not
2292
 * be negative. It is assumed that the type is already the correct one. Returns
2293
 * 0 on error, non-zero if OK. If <err_msg> is not NULL, it will be filled with a
2294
 * pointer to an error message in case of error, that the caller is responsible
2295
 * for freeing. The initial location must either be freeable or NULL.
2296
 */
2297
static int val_cap_id(struct arg *arg, char **err_msg)
2298
0
{
2299
0
  if (arg && arg[0].type == ARGT_SINT && arg[0].data.sint < 0) {
2300
0
    memprintf(err_msg, "capture identifier must be >= 0");
2301
0
    return 0;
2302
0
  }
2303
0
  return 1;
2304
0
}
2305
2306
int val_query(struct arg *args, char **err_msg)
2307
0
{
2308
0
  int val = 0;
2309
2310
0
  if (args[0].type == ARGT_STOP)
2311
0
    return 1;
2312
2313
0
  if (args[0].type != ARGT_STR) {
2314
0
    memprintf(err_msg, "first argument must be a string");
2315
0
    return 0;
2316
0
  }
2317
2318
0
  if (args[0].data.str.data != 0) {
2319
0
    if (chunk_strcmp(&args[0].data.str, "with_qm") != 0) {
2320
0
      memprintf(err_msg, "supported options are: 'with_qm'");
2321
0
      return 0;
2322
0
    }
2323
0
    val = 1;
2324
0
  }
2325
2326
0
  chunk_destroy(&args[0].data.str);
2327
0
  args[0].type = ARGT_SINT;
2328
0
  args[0].data.sint = val;
2329
0
  return 1;
2330
2331
0
}
2332
/************************************************************************/
2333
/*      All supported sample fetch keywords must be declared here.      */
2334
/************************************************************************/
2335
2336
/* Note: must not be declared <const> as its list will be overwritten */
2337
static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, {
2338
  { "base",               smp_fetch_base,               0,                NULL,   SMP_T_STR,  SMP_USE_HRQHV },
2339
  { "base32",             smp_fetch_base32,             0,                NULL,   SMP_T_SINT, SMP_USE_HRQHV },
2340
  { "base32+src",         smp_fetch_base32_src,         0,                NULL,   SMP_T_BIN,  SMP_USE_HRQHV },
2341
  { "baseq",              smp_fetch_base,               0,                NULL,   SMP_T_STR,  SMP_USE_HRQHV },
2342
2343
  /* capture are allocated and are permanent in the stream */
2344
  { "capture.req.hdr",    smp_fetch_capture_req_hdr,    ARG1(1,SINT),     val_cap_id, SMP_T_STR,  SMP_USE_HRQHP },
2345
2346
  /* retrieve these captures from the HTTP logs */
2347
  { "capture.req.method", smp_fetch_capture_req_method, 0,                NULL,   SMP_T_STR,  SMP_USE_HRQHP },
2348
  { "capture.req.uri",    smp_fetch_capture_req_uri,    0,                NULL,   SMP_T_STR,  SMP_USE_HRQHP },
2349
  { "capture.req.ver",    smp_fetch_capture_req_ver,    0,                NULL,   SMP_T_STR,  SMP_USE_HRQHP },
2350
2351
  { "capture.res.hdr",    smp_fetch_capture_res_hdr,    ARG1(1,SINT),     val_cap_id, SMP_T_STR,  SMP_USE_HRSHP },
2352
  { "capture.res.ver",    smp_fetch_capture_res_ver,    0,                NULL,   SMP_T_STR,  SMP_USE_HRQHP },
2353
2354
  /* cookie is valid in both directions (eg: for "stick ...") but cook*
2355
   * are only here to match the ACL's name, are request-only and are used
2356
   * for ACL compatibility only.
2357
   */
2358
  { "cook",               smp_fetch_cookie,             ARG1(0,STR),      NULL,    SMP_T_STR,  SMP_USE_HRQHV },
2359
  { "cookie",             smp_fetch_chn_cookie,         ARG1(0,STR),      NULL,    SMP_T_STR,  SMP_USE_HRQHV|SMP_USE_HRSHV },
2360
  { "cook_cnt",           smp_fetch_cookie_cnt,         ARG1(0,STR),      NULL,    SMP_T_SINT, SMP_USE_HRQHV },
2361
  { "cook_val",           smp_fetch_cookie_val,         ARG1(0,STR),      NULL,    SMP_T_SINT, SMP_USE_HRQHV },
2362
2363
  /* hdr is valid in both directions (eg: for "stick ...") but hdr_* are
2364
   * only here to match the ACL's name, are request-only and are used for
2365
   * ACL compatibility only.
2366
   */
2367
  { "hdr",                smp_fetch_chn_hdr,            ARG2(0,STR,SINT), val_hdr, SMP_T_STR,  SMP_USE_HRQHV|SMP_USE_HRSHV },
2368
  { "hdr_cnt",            smp_fetch_hdr_cnt,            ARG1(0,STR),      NULL,    SMP_T_SINT, SMP_USE_HRQHV },
2369
  { "hdr_ip",             smp_fetch_hdr_ip,             ARG2(0,STR,SINT), val_hdr, SMP_T_ADDR, SMP_USE_HRQHV },
2370
  { "hdr_val",            smp_fetch_hdr_val,            ARG2(0,STR,SINT), val_hdr, SMP_T_SINT, SMP_USE_HRQHV },
2371
2372
  { "http_auth_type",     smp_fetch_http_auth_type,     0,                NULL,    SMP_T_STR,  SMP_USE_HRQHV },
2373
  { "http_auth_user",     smp_fetch_http_auth_user,     0,                NULL,    SMP_T_STR,  SMP_USE_HRQHV },
2374
  { "http_auth_pass",     smp_fetch_http_auth_pass,     0,                NULL,    SMP_T_STR,  SMP_USE_HRQHV },
2375
  { "http_auth_bearer",   smp_fetch_http_auth_bearer,   ARG1(0,STR),      NULL,    SMP_T_STR,  SMP_USE_HRQHV },
2376
  { "http_auth",          smp_fetch_http_auth,          ARG1(1,USR),      NULL,    SMP_T_BOOL, SMP_USE_HRQHV },
2377
  { "http_auth_group",    smp_fetch_http_auth_grp,      ARG1(1,USR),      NULL,    SMP_T_STR,  SMP_USE_HRQHV },
2378
  { "http_first_req",     smp_fetch_http_first_req,     0,                NULL,    SMP_T_BOOL, SMP_USE_HRQHP },
2379
  { "method",             smp_fetch_meth,               0,                NULL,    SMP_T_METH, SMP_USE_HRQHP },
2380
  { "path",               smp_fetch_path,               0,                NULL,    SMP_T_STR,  SMP_USE_HRQHV },
2381
  { "pathq",              smp_fetch_path,               0,                NULL,    SMP_T_STR,  SMP_USE_HRQHV },
2382
  { "query",              smp_fetch_query,              ARG1(0,STR), val_query,    SMP_T_STR,  SMP_USE_HRQHV },
2383
2384
  /* HTTP protocol on the request path */
2385
  { "req.proto_http",     smp_fetch_proto_http,         0,                NULL,    SMP_T_BOOL, SMP_USE_HRQHP },
2386
  { "req_proto_http",     smp_fetch_proto_http,         0,                NULL,    SMP_T_BOOL, SMP_USE_HRQHP },
2387
2388
  /* HTTP version on the request path */
2389
  { "req.ver",            smp_fetch_rqver,              0,                NULL,    SMP_T_STR,  SMP_USE_HRQHP },
2390
  { "req_ver",            smp_fetch_rqver,              0,                NULL,    SMP_T_STR,  SMP_USE_HRQHP },
2391
2392
  { "req.body",           smp_fetch_body,               0,                NULL,    SMP_T_BIN,  SMP_USE_HRQHV },
2393
  { "req.body_len",       smp_fetch_body_len,           0,                NULL,    SMP_T_SINT, SMP_USE_HRQHV },
2394
  { "req.body_size",      smp_fetch_body_size,          0,                NULL,    SMP_T_SINT, SMP_USE_HRQHV },
2395
  { "req.body_param",     smp_fetch_body_param,         ARG2(0,STR,STR),  NULL,    SMP_T_BIN,  SMP_USE_HRQHV },
2396
2397
  { "req.hdrs",           smp_fetch_hdrs,               0,                NULL,    SMP_T_BIN,  SMP_USE_HRQHV },
2398
  { "req.hdrs_bin",       smp_fetch_hdrs_bin,           0,                NULL,    SMP_T_BIN,  SMP_USE_HRQHV },
2399
2400
  /* HTTP version on the response path */
2401
  { "res.ver",            smp_fetch_stver,              0,                NULL,    SMP_T_STR,  SMP_USE_HRSHP },
2402
  { "resp_ver",           smp_fetch_stver,              0,                NULL,    SMP_T_STR,  SMP_USE_HRSHP },
2403
2404
  { "res.body",           smp_fetch_body,               0,                NULL,    SMP_T_BIN,  SMP_USE_HRSHV },
2405
  { "res.body_len",       smp_fetch_body_len,           0,                NULL,    SMP_T_SINT, SMP_USE_HRSHV },
2406
  { "res.body_size",      smp_fetch_body_size,          0,                NULL,    SMP_T_SINT, SMP_USE_HRSHV },
2407
2408
  { "res.hdrs",           smp_fetch_hdrs,               0,                NULL,    SMP_T_BIN,  SMP_USE_HRSHV },
2409
  { "res.hdrs_bin",       smp_fetch_hdrs_bin,           0,                NULL,    SMP_T_BIN,  SMP_USE_HRSHV },
2410
2411
  /* explicit req.{cook,hdr} are used to force the fetch direction to be request-only */
2412
  { "req.cook",           smp_fetch_cookie,             ARG1(0,STR),      NULL,    SMP_T_STR,  SMP_USE_HRQHV },
2413
  { "req.cook_cnt",       smp_fetch_cookie_cnt,         ARG1(0,STR),      NULL,    SMP_T_SINT, SMP_USE_HRQHV },
2414
  { "req.cook_val",       smp_fetch_cookie_val,         ARG1(0,STR),      NULL,    SMP_T_SINT, SMP_USE_HRQHV },
2415
  { "req.cook_names",     smp_fetch_cookie_names,       ARG1(0,STR),      NULL,    SMP_T_STR,  SMP_USE_HRQHV },
2416
2417
  { "req.fhdr",           smp_fetch_fhdr,               ARG2(0,STR,SINT), val_hdr, SMP_T_STR,  SMP_USE_HRQHV },
2418
  { "req.fhdr_cnt",       smp_fetch_fhdr_cnt,           ARG1(0,STR),      NULL,    SMP_T_SINT, SMP_USE_HRQHV },
2419
  { "req.hdr",            smp_fetch_hdr,                ARG2(0,STR,SINT), val_hdr, SMP_T_STR,  SMP_USE_HRQHV },
2420
  { "req.hdr_cnt",        smp_fetch_hdr_cnt,            ARG1(0,STR),      NULL,    SMP_T_SINT, SMP_USE_HRQHV },
2421
  { "req.hdr_ip",         smp_fetch_hdr_ip,             ARG2(0,STR,SINT), val_hdr, SMP_T_ADDR, SMP_USE_HRQHV },
2422
  { "req.hdr_names",      smp_fetch_hdr_names,          ARG1(0,STR),      NULL,    SMP_T_STR,  SMP_USE_HRQHV },
2423
  { "req.hdr_val",        smp_fetch_hdr_val,            ARG2(0,STR,SINT), val_hdr, SMP_T_SINT, SMP_USE_HRQHV },
2424
2425
  /* explicit req.{cook,hdr} are used to force the fetch direction to be response-only */
2426
  { "res.cook",           smp_fetch_cookie,             ARG1(0,STR),      NULL,    SMP_T_STR,  SMP_USE_HRSHV },
2427
  { "res.cook_cnt",       smp_fetch_cookie_cnt,         ARG1(0,STR),      NULL,    SMP_T_SINT, SMP_USE_HRSHV },
2428
  { "res.cook_val",       smp_fetch_cookie_val,         ARG1(0,STR),      NULL,    SMP_T_SINT, SMP_USE_HRSHV },
2429
  { "res.cook_names",     smp_fetch_cookie_names,       ARG1(0,STR),      NULL,    SMP_T_STR,  SMP_USE_HRSHV },
2430
2431
  { "res.fhdr",           smp_fetch_fhdr,               ARG2(0,STR,SINT), val_hdr, SMP_T_STR,  SMP_USE_HRSHV },
2432
  { "res.fhdr_cnt",       smp_fetch_fhdr_cnt,           ARG1(0,STR),      NULL,    SMP_T_SINT, SMP_USE_HRSHV },
2433
  { "res.hdr",            smp_fetch_hdr,                ARG2(0,STR,SINT), val_hdr, SMP_T_STR,  SMP_USE_HRSHV },
2434
  { "res.hdr_cnt",        smp_fetch_hdr_cnt,            ARG1(0,STR),      NULL,    SMP_T_SINT, SMP_USE_HRSHV },
2435
  { "res.hdr_ip",         smp_fetch_hdr_ip,             ARG2(0,STR,SINT), val_hdr, SMP_T_ADDR, SMP_USE_HRSHV },
2436
  { "res.hdr_names",      smp_fetch_hdr_names,          ARG1(0,STR),      NULL,    SMP_T_STR,  SMP_USE_HRSHV },
2437
  { "res.hdr_val",        smp_fetch_hdr_val,            ARG2(0,STR,SINT), val_hdr, SMP_T_SINT, SMP_USE_HRSHV },
2438
2439
  { "server_status",      smp_fetch_srv_status,         0,                NULL,    SMP_T_SINT, SMP_USE_HRSHP },
2440
2441
  /* scook is valid only on the response and is used for ACL compatibility */
2442
  { "scook",              smp_fetch_cookie,             ARG1(0,STR),      NULL,    SMP_T_STR,  SMP_USE_HRSHV },
2443
  { "scook_cnt",          smp_fetch_cookie_cnt,         ARG1(0,STR),      NULL,    SMP_T_SINT, SMP_USE_HRSHV },
2444
  { "scook_val",          smp_fetch_cookie_val,         ARG1(0,STR),      NULL,    SMP_T_SINT, SMP_USE_HRSHV },
2445
2446
  /* shdr is valid only on the response and is used for ACL compatibility */
2447
  { "shdr",               smp_fetch_hdr,                ARG2(0,STR,SINT), val_hdr, SMP_T_STR,  SMP_USE_HRSHV },
2448
  { "shdr_cnt",           smp_fetch_hdr_cnt,            ARG1(0,STR),      NULL,    SMP_T_SINT, SMP_USE_HRSHV },
2449
  { "shdr_ip",            smp_fetch_hdr_ip,             ARG2(0,STR,SINT), val_hdr, SMP_T_ADDR, SMP_USE_HRSHV },
2450
  { "shdr_val",           smp_fetch_hdr_val,            ARG2(0,STR,SINT), val_hdr, SMP_T_SINT, SMP_USE_HRSHV },
2451
2452
  { "status",             smp_fetch_stcode,             0,                NULL,    SMP_T_SINT, SMP_USE_HRSHP },
2453
  { "txn.status",         smp_fetch_srv_status,         0,                NULL,    SMP_T_SINT, SMP_USE_HRSHP },
2454
  { "unique-id",          smp_fetch_uniqueid,           0,                NULL,    SMP_T_STR,  SMP_SRC_L4SRV },
2455
  { "url",                smp_fetch_url,                0,                NULL,    SMP_T_STR,  SMP_USE_HRQHV },
2456
  { "url32",              smp_fetch_url32,              0,                NULL,    SMP_T_SINT, SMP_USE_HRQHV },
2457
  { "url32+src",          smp_fetch_url32_src,          0,                NULL,    SMP_T_BIN,  SMP_USE_HRQHV },
2458
  { "url_ip",             smp_fetch_url_ip,             0,                NULL,    SMP_T_IPV4, SMP_USE_HRQHV },
2459
  { "url_port",           smp_fetch_url_port,           0,                NULL,    SMP_T_SINT, SMP_USE_HRQHV },
2460
  { "url_param",          smp_fetch_url_param,          ARG3(0,STR,STR,STR),  NULL,    SMP_T_STR,  SMP_USE_HRQHV },
2461
  { "urlp",               smp_fetch_url_param,          ARG3(0,STR,STR,STR),  NULL,    SMP_T_STR,  SMP_USE_HRQHV },
2462
  { "urlp_val",           smp_fetch_url_param_val,      ARG3(0,STR,STR,STR),  NULL,    SMP_T_SINT, SMP_USE_HRQHV },
2463
2464
  { /* END */ },
2465
}};
2466
2467
INITCALL1(STG_REGISTER, sample_register_fetches, &sample_fetch_keywords);
2468
2469
/*
2470
 * Local variables:
2471
 *  c-indent-level: 8
2472
 *  c-basic-offset: 8
2473
 * End:
2474
 */