Coverage Report

Created: 2026-07-16 07:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/haproxy/src/sample.c
Line
Count
Source
1
/*
2
 * Sample management functions.
3
 *
4
 * Copyright 2009-2010 EXCELIANCE, Emeric Brun <ebrun@exceliance.fr>
5
 * Copyright (C) 2012 Willy Tarreau <w@1wt.eu>
6
 *
7
 * This program is free software; you can redistribute it and/or
8
 * modify it under the terms of the GNU General Public License
9
 * as published by the Free Software Foundation; either version
10
 * 2 of the License, or (at your option) any later version.
11
 *
12
 */
13
14
#include <ctype.h>
15
#include <string.h>
16
#include <arpa/inet.h>
17
#include <stdio.h>
18
19
#include <import/mjson.h>
20
#include <import/sha1.h>
21
22
#include <haproxy/acl.h>
23
#include <haproxy/api.h>
24
#include <haproxy/arg.h>
25
#include <haproxy/auth.h>
26
#include <haproxy/base64.h>
27
#include <haproxy/buf.h>
28
#include <haproxy/cfgparse.h>
29
#include <haproxy/chunk.h>
30
#include <haproxy/clock.h>
31
#include <haproxy/errors.h>
32
#include <haproxy/fix.h>
33
#include <haproxy/global.h>
34
#include <haproxy/hash.h>
35
#include <haproxy/http.h>
36
#include <haproxy/http_ana-t.h>
37
#include <haproxy/istbuf.h>
38
#include <haproxy/mqtt.h>
39
#include <haproxy/net_helper.h>
40
#include <haproxy/protobuf.h>
41
#include <haproxy/proxy.h>
42
#include <haproxy/quic_tune.h>
43
#include <haproxy/regex.h>
44
#include <haproxy/sample.h>
45
#include <haproxy/sc_strm.h>
46
#include <haproxy/sink.h>
47
#include <haproxy/stick_table.h>
48
#include <haproxy/time.h>
49
#include <haproxy/tools.h>
50
#include <haproxy/uri_auth-t.h>
51
#include <haproxy/vars.h>
52
#include <haproxy/xxhash.h>
53
#include <haproxy/jwt.h>
54
55
/* sample type names */
56
const char *smp_to_type[SMP_TYPES] = {
57
  [SMP_T_ANY]  = "any",
58
  [SMP_T_SAME] = "same",
59
  [SMP_T_BOOL] = "bool",
60
  [SMP_T_SINT] = "sint",
61
  [SMP_T_ADDR] = "addr",
62
  [SMP_T_IPV4] = "ipv4",
63
  [SMP_T_IPV6] = "ipv6",
64
  [SMP_T_STR]  = "str",
65
  [SMP_T_BIN]  = "bin",
66
  [SMP_T_METH] = "meth",
67
};
68
69
/* Returns SMP_T_* smp matching with <type> name or SMP_TYPES if
70
 * not found.
71
 */
72
int type_to_smp(const char *type)
73
0
{
74
0
  int it = 0;
75
76
0
  while (it < SMP_TYPES) {
77
0
    if (strcmp(type, smp_to_type[it]) == 0)
78
0
      break; // found
79
0
    it += 1;
80
0
  }
81
0
  return it;
82
0
}
83
84
/* static sample used in sample_process() when <p> is NULL */
85
static THREAD_LOCAL struct sample temp_smp;
86
87
/* list head of all known sample fetch keywords */
88
static struct sample_fetch_kw_list sample_fetches = {
89
  .list = LIST_HEAD_INIT(sample_fetches.list)
90
};
91
92
/* list head of all known sample format conversion keywords */
93
static struct sample_conv_kw_list sample_convs = {
94
  .list = LIST_HEAD_INIT(sample_convs.list)
95
};
96
97
const unsigned int fetch_cap[SMP_SRC_ENTRIES] = {
98
  [SMP_SRC_CONST] = (SMP_VAL_FE_CON_ACC | SMP_VAL_FE_SES_ACC | SMP_VAL_FE_REQ_CNT |
99
                     SMP_VAL_FE_HRQ_HDR | SMP_VAL_FE_HRQ_BDY | SMP_VAL_FE_SET_BCK |
100
                     SMP_VAL_BE_REQ_CNT | SMP_VAL_BE_HRQ_HDR | SMP_VAL_BE_HRQ_BDY |
101
                     SMP_VAL_BE_SET_SRV | SMP_VAL_BE_SRV_CON | SMP_VAL_BE_RES_CNT |
102
                     SMP_VAL_BE_HRS_HDR | SMP_VAL_BE_HRS_BDY | SMP_VAL_BE_STO_RUL |
103
                     SMP_VAL_FE_RES_CNT | SMP_VAL_FE_HRS_HDR | SMP_VAL_FE_HRS_BDY |
104
                     SMP_VAL_FE_LOG_END | SMP_VAL_BE_CHK_RUL | SMP_VAL_CFG_PARSER |
105
                     SMP_VAL_CLI_PARSER ),
106
107
  [SMP_SRC_INTRN] = (SMP_VAL_FE_CON_ACC | SMP_VAL_FE_SES_ACC | SMP_VAL_FE_REQ_CNT |
108
                     SMP_VAL_FE_HRQ_HDR | SMP_VAL_FE_HRQ_BDY | SMP_VAL_FE_SET_BCK |
109
                     SMP_VAL_BE_REQ_CNT | SMP_VAL_BE_HRQ_HDR | SMP_VAL_BE_HRQ_BDY |
110
                     SMP_VAL_BE_SET_SRV | SMP_VAL_BE_SRV_CON | SMP_VAL_BE_RES_CNT |
111
                     SMP_VAL_BE_HRS_HDR | SMP_VAL_BE_HRS_BDY | SMP_VAL_BE_STO_RUL |
112
                     SMP_VAL_FE_RES_CNT | SMP_VAL_FE_HRS_HDR | SMP_VAL_FE_HRS_BDY |
113
                     SMP_VAL_FE_LOG_END | SMP_VAL_BE_CHK_RUL | SMP_VAL___________ |
114
                     SMP_VAL_CLI_PARSER ),
115
116
  [SMP_SRC_LISTN] = (SMP_VAL_FE_CON_ACC | SMP_VAL_FE_SES_ACC | SMP_VAL_FE_REQ_CNT |
117
                     SMP_VAL_FE_HRQ_HDR | SMP_VAL_FE_HRQ_BDY | SMP_VAL_FE_SET_BCK |
118
                     SMP_VAL_BE_REQ_CNT | SMP_VAL_BE_HRQ_HDR | SMP_VAL_BE_HRQ_BDY |
119
                     SMP_VAL_BE_SET_SRV | SMP_VAL_BE_SRV_CON | SMP_VAL_BE_RES_CNT |
120
                     SMP_VAL_BE_HRS_HDR | SMP_VAL_BE_HRS_BDY | SMP_VAL_BE_STO_RUL |
121
                     SMP_VAL_FE_RES_CNT | SMP_VAL_FE_HRS_HDR | SMP_VAL_FE_HRS_BDY |
122
                     SMP_VAL_FE_LOG_END | SMP_VAL___________ | SMP_VAL___________ |
123
                     SMP_VAL___________ ),
124
125
  [SMP_SRC_FTEND] = (SMP_VAL_FE_CON_ACC | SMP_VAL_FE_SES_ACC | SMP_VAL_FE_REQ_CNT |
126
                     SMP_VAL_FE_HRQ_HDR | SMP_VAL_FE_HRQ_BDY | SMP_VAL_FE_SET_BCK |
127
                     SMP_VAL_BE_REQ_CNT | SMP_VAL_BE_HRQ_HDR | SMP_VAL_BE_HRQ_BDY |
128
                     SMP_VAL_BE_SET_SRV | SMP_VAL_BE_SRV_CON | SMP_VAL_BE_RES_CNT |
129
                     SMP_VAL_BE_HRS_HDR | SMP_VAL_BE_HRS_BDY | SMP_VAL_BE_STO_RUL |
130
                     SMP_VAL_FE_RES_CNT | SMP_VAL_FE_HRS_HDR | SMP_VAL_FE_HRS_BDY |
131
                     SMP_VAL_FE_LOG_END | SMP_VAL___________ | SMP_VAL___________ |
132
                     SMP_VAL___________ ),
133
134
  [SMP_SRC_L4CLI] = (SMP_VAL_FE_CON_ACC | SMP_VAL_FE_SES_ACC | SMP_VAL_FE_REQ_CNT |
135
                     SMP_VAL_FE_HRQ_HDR | SMP_VAL_FE_HRQ_BDY | SMP_VAL_FE_SET_BCK |
136
                     SMP_VAL_BE_REQ_CNT | SMP_VAL_BE_HRQ_HDR | SMP_VAL_BE_HRQ_BDY |
137
                     SMP_VAL_BE_SET_SRV | SMP_VAL_BE_SRV_CON | SMP_VAL_BE_RES_CNT |
138
                     SMP_VAL_BE_HRS_HDR | SMP_VAL_BE_HRS_BDY | SMP_VAL_BE_STO_RUL |
139
                     SMP_VAL_FE_RES_CNT | SMP_VAL_FE_HRS_HDR | SMP_VAL_FE_HRS_BDY |
140
                     SMP_VAL_FE_LOG_END | SMP_VAL_BE_CHK_RUL | SMP_VAL___________ |
141
                     SMP_VAL___________ ),
142
143
  [SMP_SRC_L5CLI] = (SMP_VAL___________ | SMP_VAL_FE_SES_ACC | SMP_VAL_FE_REQ_CNT |
144
                     SMP_VAL_FE_HRQ_HDR | SMP_VAL_FE_HRQ_BDY | SMP_VAL_FE_SET_BCK |
145
                     SMP_VAL_BE_REQ_CNT | SMP_VAL_BE_HRQ_HDR | SMP_VAL_BE_HRQ_BDY |
146
                     SMP_VAL_BE_SET_SRV | SMP_VAL_BE_SRV_CON | SMP_VAL_BE_RES_CNT |
147
                     SMP_VAL_BE_HRS_HDR | SMP_VAL_BE_HRS_BDY | SMP_VAL_BE_STO_RUL |
148
                     SMP_VAL_FE_RES_CNT | SMP_VAL_FE_HRS_HDR | SMP_VAL_FE_HRS_BDY |
149
                     SMP_VAL_FE_LOG_END | SMP_VAL___________ | SMP_VAL___________ |
150
                     SMP_VAL___________ ),
151
152
  [SMP_SRC_TRACK] = (SMP_VAL_FE_CON_ACC | SMP_VAL_FE_SES_ACC | SMP_VAL_FE_REQ_CNT |
153
                     SMP_VAL_FE_HRQ_HDR | SMP_VAL_FE_HRQ_BDY | SMP_VAL_FE_SET_BCK |
154
                     SMP_VAL_BE_REQ_CNT | SMP_VAL_BE_HRQ_HDR | SMP_VAL_BE_HRQ_BDY |
155
                     SMP_VAL_BE_SET_SRV | SMP_VAL_BE_SRV_CON | SMP_VAL_BE_RES_CNT |
156
                     SMP_VAL_BE_HRS_HDR | SMP_VAL_BE_HRS_BDY | SMP_VAL_BE_STO_RUL |
157
                     SMP_VAL_FE_RES_CNT | SMP_VAL_FE_HRS_HDR | SMP_VAL_FE_HRS_BDY |
158
                     SMP_VAL_FE_LOG_END | SMP_VAL___________ | SMP_VAL___________ |
159
                     SMP_VAL___________ ),
160
161
  [SMP_SRC_L6REQ] = (SMP_VAL___________ | SMP_VAL___________ | SMP_VAL_FE_REQ_CNT |
162
                     SMP_VAL_FE_HRQ_HDR | SMP_VAL_FE_HRQ_BDY | SMP_VAL_FE_SET_BCK |
163
                     SMP_VAL_BE_REQ_CNT | SMP_VAL_BE_HRQ_HDR | SMP_VAL_BE_HRQ_BDY |
164
                     SMP_VAL_BE_SET_SRV | SMP_VAL_BE_SRV_CON | SMP_VAL___________ |
165
                     SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
166
                     SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
167
                     SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
168
                     SMP_VAL___________ ),
169
170
  [SMP_SRC_HRQHV] = (SMP_VAL___________ | SMP_VAL___________ | SMP_VAL_FE_REQ_CNT |
171
                     SMP_VAL_FE_HRQ_HDR | SMP_VAL_FE_HRQ_BDY | SMP_VAL_FE_SET_BCK |
172
                     SMP_VAL_BE_REQ_CNT | SMP_VAL_BE_HRQ_HDR | SMP_VAL_BE_HRQ_BDY |
173
                     SMP_VAL_BE_SET_SRV | SMP_VAL_BE_SRV_CON | SMP_VAL___________ |
174
                     SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
175
                     SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
176
                     SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
177
                     SMP_VAL___________ ),
178
179
  [SMP_SRC_HRQHP] = (SMP_VAL___________ | SMP_VAL___________ | SMP_VAL_FE_REQ_CNT |
180
                     SMP_VAL_FE_HRQ_HDR | SMP_VAL_FE_HRQ_BDY | SMP_VAL_FE_SET_BCK |
181
                     SMP_VAL_BE_REQ_CNT | SMP_VAL_BE_HRQ_HDR | SMP_VAL_BE_HRQ_BDY |
182
                     SMP_VAL_BE_SET_SRV | SMP_VAL_BE_SRV_CON | SMP_VAL_BE_RES_CNT |
183
                     SMP_VAL_BE_HRS_HDR | SMP_VAL_BE_HRS_BDY | SMP_VAL_BE_STO_RUL |
184
                     SMP_VAL_FE_RES_CNT | SMP_VAL_FE_HRS_HDR | SMP_VAL_FE_HRS_BDY |
185
                     SMP_VAL_FE_LOG_END | SMP_VAL___________ | SMP_VAL___________ |
186
                     SMP_VAL___________ ),
187
188
  [SMP_SRC_HRQBO] = (SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
189
                     SMP_VAL___________ | SMP_VAL_FE_HRQ_BDY | SMP_VAL_FE_SET_BCK |
190
                     SMP_VAL_BE_REQ_CNT | SMP_VAL_BE_HRQ_HDR | SMP_VAL_BE_HRQ_BDY |
191
                     SMP_VAL_BE_SET_SRV | SMP_VAL_BE_SRV_CON | SMP_VAL___________ |
192
                     SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
193
                     SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
194
                     SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
195
                     SMP_VAL___________ ),
196
197
  [SMP_SRC_BKEND] = (SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
198
                     SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
199
                     SMP_VAL_BE_REQ_CNT | SMP_VAL_BE_HRQ_HDR | SMP_VAL_BE_HRQ_BDY |
200
                     SMP_VAL_BE_SET_SRV | SMP_VAL_BE_SRV_CON | SMP_VAL_BE_RES_CNT |
201
                     SMP_VAL_BE_HRS_HDR | SMP_VAL_BE_HRS_BDY | SMP_VAL_BE_STO_RUL |
202
                     SMP_VAL_FE_RES_CNT | SMP_VAL_FE_HRS_HDR | SMP_VAL_FE_HRS_BDY |
203
                     SMP_VAL_FE_LOG_END | SMP_VAL_BE_CHK_RUL | SMP_VAL___________ |
204
                     SMP_VAL___________ ),
205
206
  [SMP_SRC_SERVR] = (SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
207
                     SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
208
                     SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
209
                     SMP_VAL___________ | SMP_VAL_BE_SRV_CON | SMP_VAL_BE_RES_CNT |
210
                     SMP_VAL_BE_HRS_HDR | SMP_VAL_BE_HRS_BDY | SMP_VAL_BE_STO_RUL |
211
                     SMP_VAL_FE_RES_CNT | SMP_VAL_FE_HRS_HDR | SMP_VAL_FE_HRS_BDY |
212
                     SMP_VAL_FE_LOG_END | SMP_VAL_BE_CHK_RUL | SMP_VAL___________ |
213
                     SMP_VAL___________ ),
214
215
  [SMP_SRC_L4SRV] = (SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
216
                     SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
217
                     SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
218
                     SMP_VAL___________ | SMP_VAL___________ | SMP_VAL_BE_RES_CNT |
219
                     SMP_VAL_BE_HRS_HDR | SMP_VAL_BE_HRS_BDY | SMP_VAL_BE_STO_RUL |
220
                     SMP_VAL_FE_RES_CNT | SMP_VAL_FE_HRS_HDR | SMP_VAL_FE_HRS_BDY |
221
                     SMP_VAL_FE_LOG_END | SMP_VAL_BE_CHK_RUL | SMP_VAL___________ |
222
                     SMP_VAL___________ ),
223
224
  [SMP_SRC_L5SRV] = (SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
225
                     SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
226
                     SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
227
                     SMP_VAL___________ | SMP_VAL___________ | SMP_VAL_BE_RES_CNT |
228
                     SMP_VAL_BE_HRS_HDR | SMP_VAL_BE_HRS_BDY | SMP_VAL_BE_STO_RUL |
229
                     SMP_VAL_FE_RES_CNT | SMP_VAL_FE_HRS_HDR | SMP_VAL_FE_HRS_BDY |
230
                     SMP_VAL_FE_LOG_END | SMP_VAL_BE_CHK_RUL | SMP_VAL___________ |
231
                     SMP_VAL___________ ),
232
233
  [SMP_SRC_L6RES] = (SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
234
                     SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
235
                     SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
236
                     SMP_VAL___________ | SMP_VAL___________ | SMP_VAL_BE_RES_CNT |
237
                     SMP_VAL_BE_HRS_HDR | SMP_VAL_BE_HRS_BDY | SMP_VAL_BE_STO_RUL |
238
                     SMP_VAL_FE_RES_CNT | SMP_VAL_FE_HRS_HDR | SMP_VAL_FE_HRS_BDY |
239
                     SMP_VAL___________ | SMP_VAL_BE_CHK_RUL | SMP_VAL___________ |
240
                     SMP_VAL___________ ),
241
242
  [SMP_SRC_HRSHV] = (SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
243
                     SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
244
                     SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
245
                     SMP_VAL___________ | SMP_VAL___________ | SMP_VAL_BE_RES_CNT |
246
                     SMP_VAL_BE_HRS_HDR | SMP_VAL_BE_HRS_BDY | SMP_VAL_BE_STO_RUL |
247
                     SMP_VAL_FE_RES_CNT | SMP_VAL_FE_HRS_HDR | SMP_VAL_FE_HRS_BDY |
248
                     SMP_VAL___________ | SMP_VAL_BE_CHK_RUL | SMP_VAL___________ |
249
                     SMP_VAL___________ ),
250
251
  [SMP_SRC_HRSHP] = (SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
252
                     SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
253
                     SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
254
                     SMP_VAL___________ | SMP_VAL___________ | SMP_VAL_BE_RES_CNT |
255
                     SMP_VAL_BE_HRS_HDR | SMP_VAL_BE_HRS_BDY | SMP_VAL_BE_STO_RUL |
256
                     SMP_VAL_FE_RES_CNT | SMP_VAL_FE_HRS_HDR | SMP_VAL_FE_HRS_BDY |
257
                     SMP_VAL_FE_LOG_END | SMP_VAL_BE_CHK_RUL | SMP_VAL___________ |
258
                     SMP_VAL___________ ),
259
260
  [SMP_SRC_HRSBO] = (SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
261
                     SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
262
                     SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
263
                     SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
264
                     SMP_VAL___________ | SMP_VAL_BE_HRS_BDY | SMP_VAL_BE_STO_RUL |
265
                     SMP_VAL_FE_RES_CNT | SMP_VAL_FE_HRS_HDR | SMP_VAL_FE_HRS_BDY |
266
                     SMP_VAL___________ | SMP_VAL_BE_CHK_RUL | SMP_VAL___________ |
267
                     SMP_VAL___________ ),
268
269
  [SMP_SRC_RQFIN] = (SMP_VAL___________ | SMP_VAL___________ | SMP_VAL_FE_REQ_CNT |
270
                     SMP_VAL_FE_HRQ_HDR | SMP_VAL_FE_HRQ_BDY | SMP_VAL_FE_SET_BCK |
271
                     SMP_VAL_BE_REQ_CNT | SMP_VAL_BE_HRQ_HDR | SMP_VAL_BE_HRQ_BDY |
272
                     SMP_VAL_BE_SET_SRV | SMP_VAL_BE_SRV_CON | SMP_VAL_BE_RES_CNT |
273
                     SMP_VAL_BE_HRS_HDR | SMP_VAL_BE_HRS_BDY | SMP_VAL_BE_STO_RUL |
274
                     SMP_VAL_FE_RES_CNT | SMP_VAL_FE_HRS_HDR | SMP_VAL_FE_HRS_BDY |
275
                     SMP_VAL_FE_LOG_END | SMP_VAL___________ | SMP_VAL___________ |
276
                     SMP_VAL___________ ),
277
278
  [SMP_SRC_RSFIN] = (SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
279
                     SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
280
                     SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
281
                     SMP_VAL_BE_SET_SRV | SMP_VAL_BE_SRV_CON | SMP_VAL_BE_RES_CNT |
282
                     SMP_VAL_BE_HRS_HDR | SMP_VAL_BE_HRS_BDY | SMP_VAL_BE_STO_RUL |
283
                     SMP_VAL_FE_RES_CNT | SMP_VAL_FE_HRS_HDR | SMP_VAL_FE_HRS_BDY |
284
                     SMP_VAL_FE_LOG_END | SMP_VAL___________ | SMP_VAL___________ |
285
                     SMP_VAL___________ ),
286
287
  [SMP_SRC_TXFIN] = (SMP_VAL___________ | SMP_VAL___________ | SMP_VAL_FE_REQ_CNT |
288
                     SMP_VAL_FE_HRQ_HDR | SMP_VAL_FE_HRQ_BDY | SMP_VAL_FE_SET_BCK |
289
                     SMP_VAL_BE_REQ_CNT | SMP_VAL_BE_HRQ_HDR | SMP_VAL_BE_HRQ_BDY |
290
                     SMP_VAL_BE_SET_SRV | SMP_VAL_BE_SRV_CON | SMP_VAL_BE_RES_CNT |
291
                     SMP_VAL_BE_HRS_HDR | SMP_VAL_BE_HRS_BDY | SMP_VAL_BE_STO_RUL |
292
                     SMP_VAL_FE_RES_CNT | SMP_VAL_FE_HRS_HDR | SMP_VAL_FE_HRS_BDY |
293
                     SMP_VAL_FE_LOG_END | SMP_VAL___________ | SMP_VAL___________ |
294
                     SMP_VAL___________ ),
295
296
  [SMP_SRC_SSFIN] = (SMP_VAL_FE_CON_ACC | SMP_VAL_FE_SES_ACC | SMP_VAL_FE_REQ_CNT |
297
                     SMP_VAL_FE_HRQ_HDR | SMP_VAL_FE_HRQ_BDY | SMP_VAL_FE_SET_BCK |
298
                     SMP_VAL_BE_REQ_CNT | SMP_VAL_BE_HRQ_HDR | SMP_VAL_BE_HRQ_BDY |
299
                     SMP_VAL_BE_SET_SRV | SMP_VAL_BE_SRV_CON | SMP_VAL_BE_RES_CNT |
300
                     SMP_VAL_BE_HRS_HDR | SMP_VAL_BE_HRS_BDY | SMP_VAL_BE_STO_RUL |
301
                     SMP_VAL_FE_RES_CNT | SMP_VAL_FE_HRS_HDR | SMP_VAL_FE_HRS_BDY |
302
                     SMP_VAL_FE_LOG_END | SMP_VAL___________ | SMP_VAL___________ |
303
                     SMP_VAL___________ ),
304
};
305
306
static const char *fetch_src_names[SMP_SRC_ENTRIES] = {
307
  [SMP_SRC_INTRN] = "internal state",
308
  [SMP_SRC_LISTN] = "listener",
309
  [SMP_SRC_FTEND] = "frontend",
310
  [SMP_SRC_L4CLI] = "client address",
311
  [SMP_SRC_L5CLI] = "client-side connection",
312
  [SMP_SRC_TRACK] = "track counters",
313
  [SMP_SRC_L6REQ] = "request buffer",
314
  [SMP_SRC_HRQHV] = "HTTP request headers",
315
  [SMP_SRC_HRQHP] = "HTTP request",
316
  [SMP_SRC_HRQBO] = "HTTP request body",
317
  [SMP_SRC_BKEND] = "backend",
318
  [SMP_SRC_SERVR] = "server",
319
  [SMP_SRC_L4SRV] = "server address",
320
  [SMP_SRC_L5SRV] = "server-side connection",
321
  [SMP_SRC_L6RES] = "response buffer",
322
  [SMP_SRC_HRSHV] = "HTTP response headers",
323
  [SMP_SRC_HRSHP] = "HTTP response",
324
  [SMP_SRC_HRSBO] = "HTTP response body",
325
  [SMP_SRC_RQFIN] = "request buffer statistics",
326
  [SMP_SRC_RSFIN] = "response buffer statistics",
327
  [SMP_SRC_TXFIN] = "transaction statistics",
328
  [SMP_SRC_SSFIN] = "session statistics",
329
};
330
331
static const char *fetch_ckp_names[SMP_CKP_ENTRIES] = {
332
  [SMP_CKP_FE_CON_ACC] = "frontend tcp-request connection rule",
333
  [SMP_CKP_FE_SES_ACC] = "frontend tcp-request session rule",
334
  [SMP_CKP_FE_REQ_CNT] = "frontend tcp-request content rule",
335
  [SMP_CKP_FE_HRQ_HDR] = "frontend http-request header rule",
336
  [SMP_CKP_FE_HRQ_BDY] = "frontend http-request body rule",
337
  [SMP_CKP_FE_SET_BCK] = "frontend use-backend rule",
338
  [SMP_CKP_BE_REQ_CNT] = "backend tcp-request content rule",
339
  [SMP_CKP_BE_HRQ_HDR] = "backend http-request header rule",
340
  [SMP_CKP_BE_HRQ_BDY] = "backend http-request body rule",
341
  [SMP_CKP_BE_SET_SRV] = "backend use-server, balance or stick-match rule",
342
  [SMP_CKP_BE_SRV_CON] = "server source selection",
343
  [SMP_CKP_BE_RES_CNT] = "backend tcp-response content rule",
344
  [SMP_CKP_BE_HRS_HDR] = "backend http-response header rule",
345
  [SMP_CKP_BE_HRS_BDY] = "backend http-response body rule",
346
  [SMP_CKP_BE_STO_RUL] = "backend stick-store rule",
347
  [SMP_CKP_FE_RES_CNT] = "frontend tcp-response content rule",
348
  [SMP_CKP_FE_HRS_HDR] = "frontend http-response header rule",
349
  [SMP_CKP_FE_HRS_BDY] = "frontend http-response body rule",
350
  [SMP_CKP_FE_LOG_END] = "logs",
351
  [SMP_CKP_BE_CHK_RUL] = "backend tcp-check rule",
352
  [SMP_CKP_CFG_PARSER] = "configuration parser",
353
  [SMP_CKP_CLI_PARSER] = "CLI parser",
354
};
355
356
/* This function returns the most accurate expected type of the data returned
357
 * by the sample_expr. It assumes that the <expr> and all of its converters are
358
 * properly initialized.
359
 */
360
int smp_expr_output_type(struct sample_expr *expr)
361
0
{
362
0
  struct sample_conv_expr *cur_smp = NULL;
363
0
  int cur_type = SMP_T_ANY;  /* current type in the chain */
364
0
  int next_type = SMP_T_ANY; /* next type in the chain */
365
366
0
  if (!LIST_ISEMPTY(&expr->conv_exprs)) {
367
    /* Ignore converters that output SMP_T_SAME if switching to them is
368
     * conversion-free. (such converter's output match with input, thus only
369
     * their input is considered)
370
     *
371
     * We start looking at the end of conv list and then loop back until the
372
     * sample fetch for better performance (it is more likely to find the last
373
     * effective output type near the end of the chain)
374
     */
375
0
    do {
376
0
      struct list *cur_head = (cur_smp) ? &cur_smp->list : &expr->conv_exprs;
377
378
0
      cur_smp = LIST_PREV(cur_head, struct sample_conv_expr *, list);
379
0
      if (cur_smp->conv->out_type != SMP_T_SAME) {
380
        /* current converter has effective out_type */
381
0
        cur_type = cur_smp->conv->out_type;
382
0
        goto out;
383
0
      }
384
0
      else if (sample_casts[cur_type][next_type] != c_none)
385
0
        return next_type; /* switching to next type is not conversion-free */
386
387
0
      next_type = cur_smp->conv->in_type;
388
0
    } while (cur_smp != LIST_NEXT(&expr->conv_exprs, struct sample_conv_expr *, list));
389
0
  }
390
  /* conv list empty or doesn't have effective out_type,
391
   * falling back to sample fetch out_type
392
   */
393
0
  cur_type = expr->fetch->out_type;
394
0
 out:
395
0
  if (sample_casts[cur_type][next_type] != c_none)
396
0
    return next_type; /* switching to next type is not conversion-free */
397
0
  return cur_type;
398
0
}
399
400
401
/* fill the trash with a comma-delimited list of source names for the <use> bit
402
 * field which must be composed of a non-null set of SMP_USE_* flags. The return
403
 * value is the pointer to the string in the trash buffer.
404
 */
405
const char *sample_src_names(unsigned int use)
406
0
{
407
0
  int bit;
408
409
0
  trash.data = 0;
410
0
  trash.area[0] = '\0';
411
0
  for (bit = 0; bit < SMP_SRC_ENTRIES; bit++) {
412
0
    if (!(use & ~((1 << bit) - 1)))
413
0
      break; /* no more bits */
414
415
0
    if (!(use & (1 << bit)))
416
0
      continue; /* bit not set */
417
418
0
    trash.data += snprintf(trash.area + trash.data,
419
0
               trash.size - trash.data, "%s%s",
420
0
               (use & ((1 << bit) - 1)) ? "," : "",
421
0
               fetch_src_names[bit]);
422
0
  }
423
0
  return trash.area;
424
0
}
425
426
/* return a pointer to the correct sample checkpoint name, or "unknown" when
427
 * the flags are invalid. Only the lowest bit is used, higher bits are ignored
428
 * if set.
429
 */
430
const char *sample_ckp_names(unsigned int use)
431
0
{
432
0
  int bit;
433
434
0
  for (bit = 0; bit < SMP_CKP_ENTRIES; bit++)
435
0
    if (use & (1 << bit))
436
0
      return fetch_ckp_names[bit];
437
0
  return "unknown sample check place, please report this bug";
438
0
}
439
440
/*
441
 * Registers the sample fetch keyword list <kwl> as a list of valid keywords
442
 * for next parsing sessions. The fetch keywords capabilities are also computed
443
 * from their ->use field.
444
 */
445
void sample_register_fetches(struct sample_fetch_kw_list *kwl)
446
0
{
447
0
  struct sample_fetch *sf;
448
0
  int bit;
449
450
0
  for (sf = kwl->kw; sf->kw != NULL; sf++) {
451
0
    for (bit = 0; bit < SMP_SRC_ENTRIES; bit++)
452
0
      if (sf->use & (1 << bit))
453
0
        sf->val |= fetch_cap[bit];
454
    /* store declaration file/line if known */
455
0
    if (sf->exec_ctx.type)
456
0
      continue;
457
458
0
    if (caller_initcall) {
459
0
      sf->exec_ctx.type = TH_EX_CTX_INITCALL;
460
0
      sf->exec_ctx.initcall = caller_initcall;
461
0
    } else {
462
0
      sf->exec_ctx.type = TH_EX_CTX_SMPF;
463
0
      sf->exec_ctx.smpf_kwl = kwl;
464
0
    }
465
0
  }
466
0
  LIST_APPEND(&sample_fetches.list, &kwl->list);
467
0
}
468
469
/*
470
 * Registers the sample format coverstion keyword list <pckl> as a list of valid keywords for next
471
 * parsing sessions.
472
 */
473
void sample_register_convs(struct sample_conv_kw_list *pckl)
474
0
{
475
0
  struct sample_conv *sc;
476
477
  /* store declaration file/line if known */
478
0
  for (sc = pckl->kw; sc->kw != NULL; sc++) {
479
0
    if (sc->exec_ctx.type)
480
0
      continue;
481
482
0
    if (caller_initcall) {
483
0
      sc->exec_ctx.type = TH_EX_CTX_INITCALL;
484
0
      sc->exec_ctx.initcall = caller_initcall;
485
0
    } else {
486
0
      sc->exec_ctx.type = TH_EX_CTX_CONV;
487
0
      sc->exec_ctx.conv_kwl = pckl;
488
0
    }
489
0
  }
490
0
  LIST_APPEND(&sample_convs.list, &pckl->list);
491
0
}
492
493
/*
494
 * Returns the pointer on sample fetch keyword structure identified by
495
 * string of <len> in buffer <kw>.
496
 *
497
 */
498
struct sample_fetch *find_sample_fetch(const char *kw, int len)
499
0
{
500
0
  int index;
501
0
  struct sample_fetch_kw_list *kwl;
502
503
0
  list_for_each_entry(kwl, &sample_fetches.list, list) {
504
0
    for (index = 0; kwl->kw[index].kw != NULL; index++) {
505
0
      if (strncmp(kwl->kw[index].kw, kw, len) == 0 &&
506
0
          kwl->kw[index].kw[len] == '\0')
507
0
        return &kwl->kw[index];
508
0
    }
509
0
  }
510
0
  return NULL;
511
0
}
512
513
/* dump list of registered sample fetch keywords on stdout */
514
void smp_dump_fetch_kw(void)
515
0
{
516
0
  struct sample_fetch_kw_list *kwl;
517
0
  struct sample_fetch *kwp, *kw;
518
0
  uint64_t mask;
519
0
  int index;
520
0
  int arg;
521
0
  int bit;
522
523
0
  for (bit = 0; bit <= SMP_CKP_ENTRIES + 1; bit++) {
524
0
    putchar('#');
525
0
    for (index = 0; bit + index <= SMP_CKP_ENTRIES; index++)
526
0
      putchar(' ');
527
0
    for (index = 0; index < bit && index < SMP_CKP_ENTRIES; index++)
528
0
      printf((bit <= SMP_CKP_ENTRIES) ? "/ " : " |");
529
0
    for (index = bit; bit < SMP_CKP_ENTRIES && index < SMP_CKP_ENTRIES + 2; index++)
530
0
      if (index == bit)
531
0
        putchar('_');
532
0
      else if (index == bit + 1)
533
0
        putchar('.');
534
0
      else
535
0
        putchar('-');
536
0
    printf(" %s\n", (bit < SMP_CKP_ENTRIES) ? fetch_ckp_names[bit] : "");
537
0
  }
538
539
0
  for (kw = kwp = NULL;; kwp = kw) {
540
0
    list_for_each_entry(kwl, &sample_fetches.list, list) {
541
0
      for (index = 0; kwl->kw[index].kw != NULL; index++) {
542
0
        if (strordered(kwp ? kwp->kw : NULL,
543
0
                 kwl->kw[index].kw,
544
0
                 kw != kwp ? kw->kw : NULL))
545
0
          kw = &kwl->kw[index];
546
0
      }
547
0
    }
548
549
0
    if (kw == kwp)
550
0
      break;
551
552
0
    printf("[ ");
553
0
    for (bit = 0; bit < SMP_CKP_ENTRIES; bit++)
554
0
      printf("%s", (kw->val & (1 << bit)) ? "Y " : ". ");
555
556
0
    printf("] %s", kw->kw);
557
0
    if (kw->arg_mask) {
558
0
      mask = kw->arg_mask >> ARGM_BITS;
559
0
      printf("(");
560
0
      for (arg = 0;
561
0
           arg < ARGM_NBARGS && ((mask >> (arg * ARGT_BITS)) & ARGT_MASK);
562
0
           arg++) {
563
0
        if (arg == (kw->arg_mask & ARGM_MASK)) {
564
          /* now dumping extra args */
565
0
          printf("[");
566
0
        }
567
0
        if (arg)
568
0
          printf(",");
569
0
        printf("%s", arg_type_names[(mask >> (arg * ARGT_BITS)) & ARGT_MASK]);
570
0
      }
571
0
      if (arg > (kw->arg_mask & ARGM_MASK)) {
572
        /* extra args were dumped */
573
0
        printf("]");
574
0
      }
575
0
      printf(")");
576
0
    }
577
0
    printf(": %s", smp_to_type[kw->out_type]);
578
0
    printf("\n");
579
0
  }
580
0
}
581
582
/* dump list of registered sample converter keywords on stdout */
583
void smp_dump_conv_kw(void)
584
0
{
585
0
  struct sample_conv_kw_list *kwl;
586
0
  struct sample_conv *kwp, *kw;
587
0
  uint64_t mask;
588
0
  int index;
589
0
  int arg;
590
591
0
  for (kw = kwp = NULL;; kwp = kw) {
592
0
    list_for_each_entry(kwl, &sample_convs.list, list) {
593
0
      for (index = 0; kwl->kw[index].kw != NULL; index++) {
594
0
        if (strordered(kwp ? kwp->kw : NULL,
595
0
                 kwl->kw[index].kw,
596
0
                 kw != kwp ? kw->kw : NULL))
597
0
          kw = &kwl->kw[index];
598
0
      }
599
0
    }
600
601
0
    if (kw == kwp)
602
0
      break;
603
604
0
    printf("%s", kw->kw);
605
0
    if (kw->arg_mask) {
606
0
      mask = kw->arg_mask >> ARGM_BITS;
607
0
      printf("(");
608
0
      for (arg = 0;
609
0
           arg < ARGM_NBARGS && ((mask >> (arg * ARGT_BITS)) & ARGT_MASK);
610
0
           arg++) {
611
0
        if (arg == (kw->arg_mask & ARGM_MASK)) {
612
          /* now dumping extra args */
613
0
          printf("[");
614
0
        }
615
0
        if (arg)
616
0
          printf(",");
617
0
        printf("%s", arg_type_names[(mask >> (arg * ARGT_BITS)) & ARGT_MASK]);
618
0
      }
619
0
      if (arg > (kw->arg_mask & ARGM_MASK)) {
620
        /* extra args were dumped */
621
0
        printf("]");
622
0
      }
623
0
      printf(")");
624
0
    }
625
0
    printf(": %s => %s", smp_to_type[kw->out_type], smp_to_type[kw->in_type]);
626
0
    printf("\n");
627
0
  }
628
0
}
629
630
/* This function browses the list of available sample fetches. <current> is
631
 * the last used sample fetch. If it is the first call, it must set to NULL.
632
 * <idx> is the index of the next sample fetch entry. It is used as private
633
 * value. It is useless to initiate it.
634
 *
635
 * It returns always the new fetch_sample entry, and NULL when the end of
636
 * the list is reached.
637
 */
638
struct sample_fetch *sample_fetch_getnext(struct sample_fetch *current, int *idx)
639
0
{
640
0
  struct sample_fetch_kw_list *kwl;
641
0
  struct sample_fetch *base;
642
643
0
  if (!current) {
644
    /* Get first kwl entry. */
645
0
    kwl = LIST_NEXT(&sample_fetches.list, struct sample_fetch_kw_list *, list);
646
0
    (*idx) = 0;
647
0
  } else {
648
    /* Get kwl corresponding to the current entry. */
649
0
    base = current + 1 - (*idx);
650
0
    kwl = container_of(base, struct sample_fetch_kw_list, kw);
651
0
  }
652
653
0
  while (1) {
654
655
    /* Check if kwl is the last entry. */
656
0
    if (&kwl->list == &sample_fetches.list)
657
0
      return NULL;
658
659
    /* idx contain the next keyword. If it is available, return it. */
660
0
    if (kwl->kw[*idx].kw) {
661
0
      (*idx)++;
662
0
      return &kwl->kw[(*idx)-1];
663
0
    }
664
665
    /* get next entry in the main list, and return NULL if the end is reached. */
666
0
    kwl = LIST_NEXT(&kwl->list, struct sample_fetch_kw_list *, list);
667
668
    /* Set index to 0, ans do one other loop. */
669
0
    (*idx) = 0;
670
0
  }
671
0
}
672
673
/* This function browses the list of available converters. <current> is
674
 * the last used converter. If it is the first call, it must set to NULL.
675
 * <idx> is the index of the next converter entry. It is used as private
676
 * value. It is useless to initiate it.
677
 *
678
 * It returns always the next sample_conv entry, and NULL when the end of
679
 * the list is reached.
680
 */
681
struct sample_conv *sample_conv_getnext(struct sample_conv *current, int *idx)
682
0
{
683
0
  struct sample_conv_kw_list *kwl;
684
0
  struct sample_conv *base;
685
686
0
  if (!current) {
687
    /* Get first kwl entry. */
688
0
    kwl = LIST_NEXT(&sample_convs.list, struct sample_conv_kw_list *, list);
689
0
    (*idx) = 0;
690
0
  } else {
691
    /* Get kwl corresponding to the current entry. */
692
0
    base = current + 1 - (*idx);
693
0
    kwl = container_of(base, struct sample_conv_kw_list, kw);
694
0
  }
695
696
0
  while (1) {
697
    /* Check if kwl is the last entry. */
698
0
    if (&kwl->list == &sample_convs.list)
699
0
      return NULL;
700
701
    /* idx contain the next keyword. If it is available, return it. */
702
0
    if (kwl->kw[*idx].kw) {
703
0
      (*idx)++;
704
0
      return &kwl->kw[(*idx)-1];
705
0
    }
706
707
    /* get next entry in the main list, and return NULL if the end is reached. */
708
0
    kwl = LIST_NEXT(&kwl->list, struct sample_conv_kw_list *, list);
709
710
    /* Set index to 0, ans do one other loop. */
711
0
    (*idx) = 0;
712
0
  }
713
0
}
714
715
/*
716
 * Returns the pointer on sample format conversion keyword structure identified by
717
 * string of <len> in buffer <kw>.
718
 *
719
 */
720
struct sample_conv *find_sample_conv(const char *kw, int len)
721
0
{
722
0
  int index;
723
0
  struct sample_conv_kw_list *kwl;
724
725
0
  list_for_each_entry(kwl, &sample_convs.list, list) {
726
0
    for (index = 0; kwl->kw[index].kw != NULL; index++) {
727
0
      if (strncmp(kwl->kw[index].kw, kw, len) == 0 &&
728
0
          kwl->kw[index].kw[len] == '\0')
729
0
        return &kwl->kw[index];
730
0
    }
731
0
  }
732
0
  return NULL;
733
0
}
734
735
/******************************************************************/
736
/*          Sample casts functions                                */
737
/******************************************************************/
738
739
static int c_ip2int(struct sample *smp)
740
0
{
741
0
  smp->data.u.sint = ntohl(smp->data.u.ipv4.s_addr);
742
0
  smp->data.type = SMP_T_SINT;
743
0
  return 1;
744
0
}
745
746
static int c_ip2str(struct sample *smp)
747
0
{
748
0
  struct buffer *trash = get_trash_chunk();
749
750
0
  if (!inet_ntop(AF_INET, (void *)&smp->data.u.ipv4, trash->area, trash->size))
751
0
    return 0;
752
753
0
  trash->data = strlen(trash->area);
754
0
  smp->data.u.str = *trash;
755
0
  smp->data.type = SMP_T_STR;
756
0
  smp->flags &= ~SMP_F_CONST;
757
758
0
  return 1;
759
0
}
760
761
static int c_ip2ipv6(struct sample *smp)
762
0
{
763
0
  v4tov6(&smp->data.u.ipv6, &smp->data.u.ipv4);
764
0
  smp->data.type = SMP_T_IPV6;
765
0
  return 1;
766
0
}
767
768
static int c_ipv62ip(struct sample *smp)
769
0
{
770
0
  if (!v6tov4(&smp->data.u.ipv4, &smp->data.u.ipv6))
771
0
    return 0;
772
0
  smp->data.type = SMP_T_IPV4;
773
0
  return 1;
774
0
}
775
776
static int c_ipv62str(struct sample *smp)
777
0
{
778
0
  struct buffer *trash = get_trash_chunk();
779
780
0
  if (!inet_ntop(AF_INET6, (void *)&smp->data.u.ipv6, trash->area, trash->size))
781
0
    return 0;
782
783
0
  trash->data = strlen(trash->area);
784
0
  smp->data.u.str = *trash;
785
0
  smp->data.type = SMP_T_STR;
786
0
  smp->flags &= ~SMP_F_CONST;
787
0
  return 1;
788
0
}
789
790
/*
791
static int c_ipv62ip(struct sample *smp)
792
{
793
  return v6tov4(&smp->data.u.ipv4, &smp->data.u.ipv6);
794
}
795
*/
796
797
static int c_int2ip(struct sample *smp)
798
0
{
799
0
  smp->data.u.ipv4.s_addr = htonl((unsigned int)smp->data.u.sint);
800
0
  smp->data.type = SMP_T_IPV4;
801
0
  return 1;
802
0
}
803
804
static int c_int2ipv6(struct sample *smp)
805
0
{
806
0
  smp->data.u.ipv4.s_addr = htonl((unsigned int)smp->data.u.sint);
807
0
  v4tov6(&smp->data.u.ipv6, &smp->data.u.ipv4);
808
0
  smp->data.type = SMP_T_IPV6;
809
0
  return 1;
810
0
}
811
812
static int c_str2addr(struct sample *smp)
813
0
{
814
0
  if (!buf2ip(smp->data.u.str.area, smp->data.u.str.data, &smp->data.u.ipv4)) {
815
0
    if (!buf2ip6(smp->data.u.str.area, smp->data.u.str.data, &smp->data.u.ipv6))
816
0
      return 0;
817
0
    smp->data.type = SMP_T_IPV6;
818
0
    smp->flags &= ~SMP_F_CONST;
819
0
    return 1;
820
0
  }
821
0
  smp->data.type = SMP_T_IPV4;
822
0
  smp->flags &= ~SMP_F_CONST;
823
0
  return 1;
824
0
}
825
826
static int c_str2ip(struct sample *smp)
827
0
{
828
0
  if (!buf2ip(smp->data.u.str.area, smp->data.u.str.data, &smp->data.u.ipv4))
829
0
    return 0;
830
0
  smp->data.type = SMP_T_IPV4;
831
0
  smp->flags &= ~SMP_F_CONST;
832
0
  return 1;
833
0
}
834
835
static int c_str2ipv6(struct sample *smp)
836
0
{
837
0
  if (!buf2ip6(smp->data.u.str.area, smp->data.u.str.data, &smp->data.u.ipv6))
838
0
    return 0;
839
0
  smp->data.type = SMP_T_IPV6;
840
0
  smp->flags &= ~SMP_F_CONST;
841
0
  return 1;
842
0
}
843
844
/*
845
 * The NULL char always enforces the end of string if it is met.
846
 * Data is never changed, so we can ignore the CONST case
847
 */
848
static int c_bin2str(struct sample *smp)
849
0
{
850
0
  int i;
851
852
0
  for (i = 0; i < smp->data.u.str.data; i++) {
853
0
    if (!smp->data.u.str.area[i]) {
854
0
      smp->data.u.str.data = i;
855
0
      break;
856
0
    }
857
0
  }
858
0
  smp->data.type = SMP_T_STR;
859
0
  return 1;
860
0
}
861
862
static int c_int2str(struct sample *smp)
863
0
{
864
0
  struct buffer *trash = get_trash_chunk();
865
0
  char *pos;
866
867
0
  pos = lltoa_r(smp->data.u.sint, trash->area, trash->size);
868
0
  if (!pos)
869
0
    return 0;
870
871
0
  trash->size = trash->size - (pos - trash->area);
872
0
  trash->area = pos;
873
0
  trash->data = strlen(pos);
874
0
  smp->data.u.str = *trash;
875
0
  smp->data.type = SMP_T_STR;
876
0
  smp->flags &= ~SMP_F_CONST;
877
0
  return 1;
878
0
}
879
880
/* This function unconditionally duplicates data and removes the "const" flag.
881
 * For strings and binary blocks, it also provides a known allocated size with
882
 * a length that is capped to the size, and ensures a trailing zero is always
883
 * appended for strings. This is necessary for some operations which may
884
 * require to extend the length. It returns 0 if it fails, 1 on success.
885
 */
886
int smp_dup(struct sample *smp)
887
0
{
888
0
  struct buffer *trash, *buf;
889
890
0
  switch (smp->data.type) {
891
0
  case SMP_T_BOOL:
892
0
  case SMP_T_SINT:
893
0
  case SMP_T_ADDR:
894
0
  case SMP_T_IPV4:
895
0
  case SMP_T_IPV6:
896
    /* These type are not const. */
897
0
    break;
898
899
0
  case SMP_T_METH:
900
0
    if (smp->data.u.meth.meth != HTTP_METH_OTHER)
901
0
      break;
902
0
    __fallthrough;
903
904
0
  case SMP_T_STR:
905
0
    buf = (smp->data.type == SMP_T_STR ? &smp->data.u.str : &smp->data.u.meth.str);
906
0
    trash = get_best_trash_chunk(buf, buf->data+1);
907
0
    if (!trash)
908
0
      return 0;
909
0
    trash->data = buf->data;
910
0
    if (trash->data > trash->size - 1)
911
0
      trash->data = trash->size - 1;
912
913
0
    memcpy(trash->area, buf->area, trash->data);
914
0
    trash->area[trash->data] = 0;
915
0
    *buf = *trash;
916
0
    break;
917
918
0
  case SMP_T_BIN:
919
0
    trash = get_trash_chunk_sz(smp->data.u.str.data);
920
0
    if (!trash)
921
0
      return 0;
922
0
    trash->data = smp->data.u.str.data;
923
0
    if (trash->data > trash->size)
924
0
      trash->data = trash->size;
925
926
0
    memcpy(trash->area, smp->data.u.str.area, trash->data);
927
0
    smp->data.u.str = *trash;
928
0
    break;
929
930
0
  default:
931
    /* Other cases are unexpected. */
932
0
    return 0;
933
0
  }
934
935
  /* remove const flag */
936
0
  smp->flags &= ~SMP_F_CONST;
937
0
  return 1;
938
0
}
939
940
int c_none(struct sample *smp)
941
0
{
942
0
  return 1;
943
0
}
944
945
/* special converter function used by pseudo types in the compatibility matrix
946
 * to inform that the conversion is theoretically allowed at parsing time.
947
 *
948
 * However, being a pseudo type, it may not be emitted by fetches or converters
949
 * so this function should never be called. If this is the case, then it means
950
 * that a pseudo type has been used as a final output type at runtime, which is
951
 * considered as a bug and should be fixed. To help spot this kind of bug, the
952
 * process will crash in this case.
953
 */
954
int c_pseudo(struct sample *smp)
955
0
{
956
0
  ABORT_NOW(); // die loudly
957
  /* never reached */
958
0
  return 0;
959
0
}
960
961
static int c_str2int(struct sample *smp)
962
0
{
963
0
  const char *str;
964
0
  const char *end;
965
966
0
  if (smp->data.u.str.data == 0)
967
0
    return 0;
968
969
0
  str = smp->data.u.str.area;
970
0
  end = smp->data.u.str.area + smp->data.u.str.data;
971
972
0
  smp->data.u.sint = read_int64(&str, end);
973
0
  smp->data.type = SMP_T_SINT;
974
0
  smp->flags &= ~SMP_F_CONST;
975
0
  return 1;
976
0
}
977
978
static int c_str2meth(struct sample *smp)
979
0
{
980
0
  enum http_meth_t meth;
981
0
  int len;
982
983
0
  meth = find_http_meth(smp->data.u.str.area, smp->data.u.str.data);
984
0
  if (meth == HTTP_METH_OTHER) {
985
0
    len = smp->data.u.str.data;
986
0
    smp->data.u.meth.str.area = smp->data.u.str.area;
987
0
    smp->data.u.meth.str.data = len;
988
0
  }
989
0
  else
990
0
    smp->flags &= ~SMP_F_CONST;
991
0
  smp->data.u.meth.meth = meth;
992
0
  smp->data.type = SMP_T_METH;
993
0
  return 1;
994
0
}
995
996
static int c_meth2str(struct sample *smp)
997
0
{
998
0
  int len;
999
0
  enum http_meth_t meth;
1000
1001
0
  if (smp->data.u.meth.meth == HTTP_METH_OTHER) {
1002
    /* The method is unknown. Copy the original pointer. */
1003
0
    len = smp->data.u.meth.str.data;
1004
0
    smp->data.u.str.area = smp->data.u.meth.str.area;
1005
0
    smp->data.u.str.data = len;
1006
0
    smp->data.type = SMP_T_STR;
1007
0
  }
1008
0
  else if (smp->data.u.meth.meth < HTTP_METH_OTHER) {
1009
    /* The method is known, copy the pointer containing the string. */
1010
0
    meth = smp->data.u.meth.meth;
1011
0
    smp->data.u.str.area = http_known_methods[meth].ptr;
1012
0
    smp->data.u.str.data = http_known_methods[meth].len;
1013
0
    smp->flags |= SMP_F_CONST;
1014
0
    smp->data.type = SMP_T_STR;
1015
0
  }
1016
0
  else {
1017
    /* Unknown method */
1018
0
    return 0;
1019
0
  }
1020
0
  return 1;
1021
0
}
1022
1023
static int c_addr2bin(struct sample *smp)
1024
0
{
1025
0
  struct buffer *chk = get_trash_chunk();
1026
1027
0
  if (smp->data.type == SMP_T_IPV4) {
1028
0
    chk->data = 4;
1029
0
    memcpy(chk->area, &smp->data.u.ipv4, chk->data);
1030
0
  }
1031
0
  else if (smp->data.type == SMP_T_IPV6) {
1032
0
    chk->data = 16;
1033
0
    memcpy(chk->area, &smp->data.u.ipv6, chk->data);
1034
0
  }
1035
0
  else
1036
0
    return 0;
1037
1038
0
  smp->data.u.str = *chk;
1039
0
  smp->data.type = SMP_T_BIN;
1040
0
  return 1;
1041
0
}
1042
1043
static int c_int2bin(struct sample *smp)
1044
0
{
1045
0
  struct buffer *chk = get_trash_chunk();
1046
1047
0
  *(unsigned long long int *) chk->area = my_htonll(smp->data.u.sint);
1048
0
  chk->data = 8;
1049
1050
0
  smp->data.u.str = *chk;
1051
0
  smp->data.type = SMP_T_BIN;
1052
0
  return 1;
1053
0
}
1054
1055
static int c_bool2bin(struct sample *smp)
1056
0
{
1057
0
  struct buffer *chk = get_trash_chunk();
1058
1059
0
  *(unsigned long long int *)chk->area = my_htonll(!!smp->data.u.sint);
1060
0
  chk->data = 8;
1061
0
  smp->data.u.str = *chk;
1062
0
  smp->data.type = SMP_T_BIN;
1063
0
  return 1;
1064
0
}
1065
1066
1067
/*****************************************************************/
1068
/*      Sample casts matrix:                                     */
1069
/*           sample_casts[from type][to type]                    */
1070
/*           NULL pointer used for impossible sample casts       */
1071
/*****************************************************************/
1072
1073
sample_cast_fct sample_casts[SMP_TYPES][SMP_TYPES] = {
1074
/*            to:  ANY     SAME      BOOL       SINT       ADDR        IPV4       IPV6        STR         BIN         METH */
1075
/* from:  ANY */ { c_none, NULL,     c_pseudo,  c_pseudo,  c_pseudo,   c_pseudo,  c_pseudo,   c_pseudo,   c_pseudo,   c_pseudo   },
1076
/*       SAME */ { NULL,   NULL,     NULL,      NULL,      NULL,       NULL,      NULL,       NULL,       NULL,       NULL       },
1077
/*       BOOL */ { c_none, NULL,     c_none,    c_none,    NULL,       NULL,      NULL,       c_int2str,  c_bool2bin, NULL       },
1078
/*       SINT */ { c_none, NULL,     c_none,    c_none,    c_int2ip,   c_int2ip,  c_int2ipv6, c_int2str,  c_int2bin,  NULL       },
1079
/*       ADDR */ { c_none, NULL,     NULL,      NULL,      c_pseudo,   c_pseudo,  c_pseudo,   c_pseudo,   c_pseudo,   NULL       },
1080
/*       IPV4 */ { c_none, NULL,     NULL,      c_ip2int,  c_none,     c_none,    c_ip2ipv6,  c_ip2str,   c_addr2bin, NULL       },
1081
/*       IPV6 */ { c_none, NULL,     NULL,      NULL,      c_none,     c_ipv62ip, c_none,     c_ipv62str, c_addr2bin, NULL       },
1082
/*        STR */ { c_none, NULL,     c_str2int, c_str2int, c_str2addr, c_str2ip,  c_str2ipv6, c_none,     c_none,     c_str2meth },
1083
/*        BIN */ { c_none, NULL,     NULL,      NULL,      NULL,       NULL,      NULL,       c_bin2str,  c_none,     c_str2meth },
1084
/*       METH */ { c_none, NULL,     NULL,      NULL,      NULL,       NULL,      NULL,       c_meth2str, c_meth2str, c_none     }
1085
};
1086
1087
/* Process the converters (if any) for a sample expr after the first fetch
1088
 * keyword. We have two supported syntaxes for the converters, which can be
1089
 * combined:
1090
 *  - comma-delimited list of converters just after the keyword and args ;
1091
 *  - one converter per keyword (if <idx> != NULL)
1092
 *    FIXME: should we continue to support this old syntax?
1093
 * The combination allows to have each keyword being a comma-delimited
1094
 * series of converters.
1095
 *
1096
 * We want to process the former first, then the latter. For this we start
1097
 * from the beginning of the supposed place in the exiting conv chain, which
1098
 * starts at the last comma (<start> which is then referred to as endt).
1099
 *
1100
 * If <endptr> is non-nul, it will be set to the first unparsed character
1101
 * (which may be the final '\0') on success. If it is nul, the expression
1102
 * must be properly terminated by a '\0' otherwise an error is reported.
1103
 *
1104
 * <expr> should point the the sample expression that is already initialized
1105
 * with the sample fetch that precedes the converters chain.
1106
 *
1107
 * The function returns a positive value for success and 0 for failure, in which
1108
 * case <err_msg> will point to an allocated string that brings some info
1109
 * about the failure. It is the caller's responsibility to free it.
1110
 */
1111
int sample_parse_expr_cnv(char **str, int *idx, char **endptr, char **err_msg, struct arg_list *al, const char *file, int line,
1112
                          struct sample_expr *expr, const char *start)
1113
0
{
1114
0
  struct sample_conv *conv;
1115
0
  const char *endt = start; /* end of term */
1116
0
  const char *begw;         /* beginning of word */
1117
0
  const char *endw;         /* end of word */
1118
0
  char *ckw = NULL;
1119
0
  unsigned long prev_type = expr->fetch->out_type;
1120
0
  int success = 1;
1121
1122
0
  while (1) {
1123
0
    struct sample_conv_expr *conv_expr;
1124
0
    int err_arg;
1125
0
    int argcnt;
1126
1127
0
    if (*endt && *endt != ',') {
1128
0
      if (endptr) {
1129
        /* end found, let's stop here */
1130
0
        break;
1131
0
      }
1132
0
      if (ckw)
1133
0
        memprintf(err_msg, "missing comma after converter '%s'", ckw);
1134
0
      else
1135
0
        memprintf(err_msg, "missing comma after fetch keyword");
1136
0
      goto out_error;
1137
0
    }
1138
1139
    /* FIXME: how long should we support such idiocies ? Maybe we
1140
     * should already warn ?
1141
     */
1142
0
    while (*endt == ',') /* then trailing commas */
1143
0
      endt++;
1144
1145
0
    begw = endt; /* start of converter */
1146
1147
0
    if (!*begw) {
1148
      /* none ? skip to next string if idx is set */
1149
0
      if (!idx)
1150
0
        break; /* end of converters */
1151
0
      (*idx)++;
1152
0
      begw = str[*idx];
1153
0
      if (!begw || !*begw)
1154
0
        break;
1155
0
    }
1156
1157
0
    for (endw = begw; is_idchar(*endw); endw++)
1158
0
      ;
1159
1160
0
    ha_free(&ckw);
1161
0
    ckw = my_strndup(begw, endw - begw);
1162
1163
0
    conv = find_sample_conv(begw, endw - begw);
1164
0
    if (!conv) {
1165
      /* we found an isolated keyword that we don't know, it's not ours */
1166
0
      if (idx && begw == str[*idx]) {
1167
0
        endt = begw;
1168
0
        break;
1169
0
      }
1170
0
      memprintf(err_msg, "unknown converter '%s'", ckw);
1171
0
      goto out_error;
1172
0
    }
1173
1174
0
    if (conv->in_type >= SMP_TYPES || conv->out_type >= SMP_TYPES) {
1175
0
      memprintf(err_msg, "return type of converter '%s' is unknown", ckw);
1176
0
      goto out_error;
1177
0
    }
1178
1179
    /* If impossible type conversion */
1180
0
    if (!sample_casts[prev_type][conv->in_type]) {
1181
0
      memprintf(err_msg, "converter '%s' cannot be applied", ckw);
1182
0
      goto out_error;
1183
0
    }
1184
1185
    /* Ignore converters that output SMP_T_SAME if switching to them is
1186
     * conversion-free. (such converter's output match with input, thus only
1187
     * their input is considered)
1188
     */
1189
0
    if (conv->out_type != SMP_T_SAME)
1190
0
      prev_type = conv->out_type;
1191
0
    else if (sample_casts[prev_type][conv->in_type] != c_none)
1192
0
      prev_type = conv->in_type;
1193
1194
0
    conv_expr = calloc(1, sizeof(*conv_expr));
1195
0
    if (!conv_expr)
1196
0
      goto out_error;
1197
1198
0
    LIST_APPEND(&(expr->conv_exprs), &(conv_expr->list));
1199
0
    conv_expr->conv = conv;
1200
1201
0
    if (al) {
1202
0
      al->kw = expr->fetch->kw;
1203
0
      al->conv = conv_expr->conv->kw;
1204
0
    }
1205
0
    argcnt = make_arg_list(endw, -1, conv->arg_mask, &conv_expr->arg_p, err_msg, &endt, &err_arg, al);
1206
0
    if (argcnt < 0) {
1207
0
      memprintf(err_msg, "invalid arg %d in converter '%s' : %s", err_arg+1, ckw, *err_msg);
1208
0
      goto out_error;
1209
0
    }
1210
1211
0
    if (argcnt && !conv->arg_mask) {
1212
0
      memprintf(err_msg, "converter '%s' does not support any args", ckw);
1213
0
      goto out_error;
1214
0
    }
1215
1216
0
    if (!conv_expr->arg_p)
1217
0
      conv_expr->arg_p = empty_arg_list;
1218
1219
0
    if (conv->val_args && !conv->val_args(conv_expr->arg_p, conv, file, line, err_msg)) {
1220
0
      memprintf(err_msg, "invalid args in converter '%s' : %s", ckw, *err_msg);
1221
0
      goto out_error;
1222
0
    }
1223
0
  }
1224
1225
0
  if (endptr) {
1226
    /* end found, let's stop here */
1227
0
    *endptr = (char *)endt;
1228
0
  }
1229
0
 out:
1230
0
  free(ckw);
1231
0
  return success;
1232
1233
0
 out_error:
1234
0
  success = 0;
1235
0
  goto out;
1236
0
}
1237
1238
/*
1239
 * Parse a sample expression configuration:
1240
 *        fetch keyword followed by format conversion keywords.
1241
 *
1242
 * <al> is an arg_list serving as a list head to report missing dependencies.
1243
 * It may be NULL if such dependencies are not allowed. Otherwise, the caller
1244
 * must have set al->ctx if al is set.
1245
 *
1246
 * Returns a pointer on allocated sample expression structure or NULL in case
1247
 * of error, in which case <err_msg> will point to an allocated string that
1248
 * brings some info about the failure. It is the caller's responsibility to
1249
 * free it.
1250
 */
1251
struct sample_expr *sample_parse_expr(char **str, int *idx, const char *file, int line, char **err_msg, struct arg_list *al, char **endptr)
1252
0
{
1253
0
  const char *begw; /* beginning of word */
1254
0
  const char *endw; /* end of word */
1255
0
  const char *endt; /* end of term */
1256
0
  struct sample_expr *expr = NULL;
1257
0
  struct sample_fetch *fetch;
1258
0
  char *fkw = NULL;
1259
0
  int err_arg;
1260
1261
0
  begw = str[*idx];
1262
0
  for (endw = begw; is_idchar(*endw); endw++)
1263
0
    ;
1264
1265
0
  if (endw == begw) {
1266
0
    memprintf(err_msg, "missing fetch method");
1267
0
    goto out_error;
1268
0
  }
1269
1270
  /* keep a copy of the current fetch keyword for error reporting */
1271
0
  fkw = my_strndup(begw, endw - begw);
1272
1273
0
  fetch = find_sample_fetch(begw, endw - begw);
1274
0
  if (!fetch) {
1275
0
    memprintf(err_msg, "unknown fetch method '%s'", fkw);
1276
0
    goto out_error;
1277
0
  }
1278
1279
  /* At this point, we have :
1280
   *   - begw : beginning of the keyword
1281
   *   - endw : end of the keyword, first character not part of keyword
1282
   */
1283
1284
0
  if (fetch->out_type >= SMP_TYPES) {
1285
0
    memprintf(err_msg, "returns type of fetch method '%s' is unknown", fkw);
1286
0
    goto out_error;
1287
0
  }
1288
1289
0
  expr = calloc(1, sizeof(*expr));
1290
0
  if (!expr)
1291
0
    goto out_error;
1292
1293
0
  LIST_INIT(&(expr->conv_exprs));
1294
0
  expr->fetch = fetch;
1295
0
  expr->arg_p = empty_arg_list;
1296
1297
  /* Note that we call the argument parser even with an empty string,
1298
   * this allows it to automatically create entries for mandatory
1299
   * implicit arguments (eg: local proxy name).
1300
   */
1301
0
  if (al) {
1302
0
    al->kw = expr->fetch->kw;
1303
0
    al->conv = NULL;
1304
0
  }
1305
0
  if (make_arg_list(endw, -1, fetch->arg_mask, &expr->arg_p, err_msg, &endt, &err_arg, al) < 0) {
1306
0
    memprintf(err_msg, "fetch method '%s' : %s", fkw, *err_msg);
1307
0
    goto out_error;
1308
0
  }
1309
1310
  /* now endt is our first char not part of the arg list, typically the
1311
   * comma after the sample fetch name or after the closing parenthesis,
1312
   * or the NUL char.
1313
   */
1314
1315
0
  if (!expr->arg_p) {
1316
0
    expr->arg_p = empty_arg_list;
1317
0
  }
1318
0
  else if (fetch->val_args && !fetch->val_args(expr->arg_p, err_msg)) {
1319
0
    memprintf(err_msg, "invalid args in fetch method '%s' : %s", fkw, *err_msg);
1320
0
    goto out_error;
1321
0
  }
1322
1323
0
  if (!sample_parse_expr_cnv(str, idx, endptr, err_msg, al, file, line, expr, endt))
1324
0
    goto out_error;
1325
1326
0
 out:
1327
0
  free(fkw);
1328
0
  return expr;
1329
1330
0
out_error:
1331
0
  release_sample_expr(expr);
1332
0
  expr = NULL;
1333
0
  goto out;
1334
0
}
1335
1336
/*
1337
 * Helper function to process the converter list of a given sample expression
1338
 * <expr> using the sample <p> (which is assumed to be properly initialized)
1339
 * as input.
1340
 *
1341
 * Returns 1 on success and 0 on failure.
1342
 */
1343
int sample_process_cnv(struct sample_expr *expr, struct sample *p)
1344
0
{
1345
0
  struct sample_conv_expr *conv_expr;
1346
1347
0
  list_for_each_entry(conv_expr, &expr->conv_exprs, list) {
1348
    /* we want to ensure that p->type can be casted into
1349
     * conv_expr->conv->in_type. We have 3 possibilities :
1350
     *  - NULL   => not castable.
1351
     *  - c_none => nothing to do (let's optimize it)
1352
     *  - other  => apply cast and prepare to fail
1353
     */
1354
0
    if (p->data.type != conv_expr->conv->in_type) {
1355
0
      if (!sample_casts[p->data.type][conv_expr->conv->in_type])
1356
0
        return 0;
1357
1358
0
      if (sample_casts[p->data.type][conv_expr->conv->in_type] != c_none &&
1359
0
          !sample_casts[p->data.type][conv_expr->conv->in_type](p))
1360
0
        return 0;
1361
0
    }
1362
1363
    /* OK cast succeeded */
1364
0
    if (!EXEC_CTX_WITH_RET(conv_expr->conv->exec_ctx,
1365
0
                           conv_expr->conv->process(conv_expr->arg_p, p, conv_expr->conv->private)))
1366
0
      return 0;
1367
0
  }
1368
0
  return 1;
1369
0
}
1370
1371
/*
1372
 * Process a fetch + format conversion of defined by the sample expression <expr>
1373
 * on request or response considering the <opt> parameter.
1374
 * Returns a pointer on a typed sample structure containing the result or NULL if
1375
 * sample is not found or when format conversion failed.
1376
 *  If <p> is not null, function returns results in structure pointed by <p>.
1377
 *  If <p> is null, functions returns a pointer on a static sample structure.
1378
 *
1379
 * Note: the fetch functions are required to properly set the return type. The
1380
 * conversion functions must do so too. However the cast functions do not need
1381
 * to since they're made to cast multiple types according to what is required.
1382
 *
1383
 * The caller may indicate in <opt> if it considers the result final or not.
1384
 * The caller needs to check the SMP_F_MAY_CHANGE flag in p->flags to verify
1385
 * if the result is stable or not, according to the following table :
1386
 *
1387
 * return MAY_CHANGE FINAL   Meaning for the sample
1388
 *  NULL      0        *     Not present and will never be (eg: header)
1389
 *  NULL      1        0     Not present yet, could change (eg: POST param)
1390
 *  NULL      1        1     Not present yet, will not change anymore
1391
 *   smp      0        *     Present and will not change (eg: header)
1392
 *   smp      1        0     Present, may change (eg: request length)
1393
 *   smp      1        1     Present, last known value (eg: request length)
1394
 */
1395
struct sample *sample_process(struct proxy *px, struct session *sess,
1396
                              struct stream *strm, unsigned int opt,
1397
                              struct sample_expr *expr, struct sample *p)
1398
0
{
1399
0
  if (p == NULL) {
1400
0
    p = &temp_smp;
1401
0
    memset(p, 0, sizeof(*p));
1402
0
  }
1403
1404
0
  smp_set_owner(p, px, sess, strm, opt);
1405
0
  if (!EXEC_CTX_WITH_RET(expr->fetch->exec_ctx,
1406
0
                         expr->fetch->process(expr->arg_p, p, expr->fetch->kw, expr->fetch->private)))
1407
0
    return NULL;
1408
1409
0
  if (!sample_process_cnv(expr, p))
1410
0
    return NULL;
1411
0
  return p;
1412
0
}
1413
1414
/*
1415
 * Resolve all remaining arguments in proxy <p>. Returns the number of
1416
 * errors or 0 if everything is fine. If at least one error is met, it will
1417
 * be appended to *err. If *err==NULL it will be allocated first.
1418
 */
1419
int smp_resolve_args(struct proxy *p, char **err)
1420
0
{
1421
0
  struct arg_list *cur, *bak;
1422
0
  const char *ctx, *where;
1423
0
  const char *conv_ctx, *conv_pre, *conv_pos;
1424
0
  struct userlist *ul;
1425
0
  struct my_regex *reg;
1426
0
  struct arg *arg;
1427
0
  int cfgerr = 0;
1428
0
  int rflags;
1429
1430
0
  list_for_each_entry_safe(cur, bak, &p->conf.args.list, list) {
1431
0
    struct proxy *px;
1432
0
    struct server *srv;
1433
0
    struct stktable *t;
1434
0
    char *pname, *sname, *stktname;
1435
0
    char *err2;
1436
1437
0
    arg = cur->arg;
1438
1439
    /* prepare output messages */
1440
0
    conv_pre = conv_pos = conv_ctx = "";
1441
0
    if (cur->conv) {
1442
0
      conv_ctx = cur->conv;
1443
0
      conv_pre = "conversion keyword '";
1444
0
      conv_pos = "' for ";
1445
0
    }
1446
1447
0
    where = "in";
1448
0
    ctx = "sample fetch keyword";
1449
0
    switch (cur->ctx) {
1450
0
    case ARGC_STK:   where = "in stick rule in"; break;
1451
0
    case ARGC_TRK:   where = "in tracking rule in"; break;
1452
0
    case ARGC_LOG:   where = "in log-format string in"; break;
1453
0
    case ARGC_LOGSD: where = "in log-format-sd string in"; break;
1454
0
    case ARGC_HRQ:   where = "in http-request expression in"; break;
1455
0
    case ARGC_HRS:   where = "in http-response response in"; break;
1456
0
    case ARGC_UIF:   where = "in unique-id-format string in"; break;
1457
0
    case ARGC_RDR:   where = "in redirect format string in"; break;
1458
0
    case ARGC_CAP:   where = "in capture rule in"; break;
1459
0
    case ARGC_ACL:   ctx = "ACL keyword"; break;
1460
0
    case ARGC_SRV:   where = "in server directive in"; break;
1461
0
    case ARGC_SPOE:  where = "in spoe-message directive in"; break;
1462
0
    case ARGC_UBK:   where = "in use_backend expression in"; break;
1463
0
    case ARGC_USRV:  where = "in use-server or balance expression in"; break;
1464
0
    case ARGC_HERR:  where = "in http-error directive in"; break;
1465
0
    case ARGC_OPT:   where = "in option directive in"; break;
1466
0
    case ARGC_TCO:   where = "in tcp-request connection expression in"; break;
1467
0
    case ARGC_TSE:   where = "in tcp-request session expression in"; break;
1468
0
    case ARGC_TRQ:   where = "in tcp-request content expression in"; break;
1469
0
    case ARGC_TRS:   where = "in tcp-response content expression in"; break;
1470
0
    case ARGC_TCK:   where = "in tcp-check expression in"; break;
1471
0
    case ARGC_CFG:   where = "in configuration expression in"; break;
1472
0
    case ARGC_CLI:   where = "in CLI expression in"; break;
1473
0
    case ARGC_OTEL:  where = "in otel-scope directive in"; break;
1474
0
    }
1475
1476
    /* set a few default settings */
1477
0
    px = p;
1478
0
    pname = p->id;
1479
1480
0
    switch (arg->type) {
1481
0
    case ARGT_ID:
1482
0
      err2 = NULL;
1483
1484
0
      if (arg->resolve_ptr && !arg->resolve_ptr(arg, &err2)) {
1485
0
        memprintf(err, "%sparsing [%s:%d]: error in identifier '%s' in arg %d of %s%s%s%s '%s' %s proxy '%s' : %s.\n",
1486
0
            *err ? *err : "", cur->file, cur->line,
1487
0
           arg->data.str.area,
1488
0
           cur->arg_pos + 1, conv_pre, conv_ctx, conv_pos, ctx, cur->kw, where, p->id, err2);
1489
0
        ha_free(&err2);
1490
0
        cfgerr++;
1491
0
        break;
1492
0
      }
1493
0
      break;
1494
1495
0
    case ARGT_SRV:
1496
0
      if (!arg->data.str.data) {
1497
0
        memprintf(err, "%sparsing [%s:%d]: missing server name in arg %d of %s%s%s%s '%s' %s proxy '%s'.\n",
1498
0
           *err ? *err : "", cur->file, cur->line,
1499
0
           cur->arg_pos + 1, conv_pre, conv_ctx, conv_pos, ctx, cur->kw, where, p->id);
1500
0
        cfgerr++;
1501
0
        break;
1502
0
      }
1503
1504
      /* we support two formats : "bck/srv" and "srv" */
1505
0
      sname = strrchr(arg->data.str.area, '/');
1506
1507
0
      if (sname) {
1508
0
        *sname++ = '\0';
1509
0
        pname = arg->data.str.area;
1510
1511
0
        px = proxy_be_by_name(pname);
1512
0
        if (!px) {
1513
0
          memprintf(err, "%sparsing [%s:%d]: unable to find proxy '%s' referenced in arg %d of %s%s%s%s '%s' %s proxy '%s'.\n",
1514
0
             *err ? *err : "", cur->file, cur->line, pname,
1515
0
             cur->arg_pos + 1, conv_pre, conv_ctx, conv_pos, ctx, cur->kw, where, p->id);
1516
0
          cfgerr++;
1517
0
          break;
1518
0
        }
1519
0
      }
1520
0
      else {
1521
0
        if (px->cap & PR_CAP_DEF) {
1522
0
          memprintf(err, "%sparsing [%s:%d]: backend name must be set in arg %d of %s%s%s%s '%s' %s proxy '%s'.\n",
1523
0
              *err ? *err : "", cur->file, cur->line,
1524
0
              cur->arg_pos + 1, conv_pre, conv_ctx, conv_pos, ctx, cur->kw, where, p->id);
1525
0
          cfgerr++;
1526
0
          break;
1527
0
        }
1528
0
        sname = arg->data.str.area;
1529
0
      }
1530
1531
0
      srv = server_find_by_name(px, sname);
1532
0
      if (!srv) {
1533
0
        memprintf(err, "%sparsing [%s:%d]: unable to find server '%s' in proxy '%s', referenced in arg %d of %s%s%s%s '%s' %s proxy '%s'.\n",
1534
0
           *err ? *err : "", cur->file, cur->line, sname, pname,
1535
0
           cur->arg_pos + 1, conv_pre, conv_ctx, conv_pos, ctx, cur->kw, where, p->id);
1536
0
        cfgerr++;
1537
0
        break;
1538
0
      }
1539
1540
      /* TODO CLI set-var should not prevent server deletion as var value is instantly resolved. */
1541
0
      srv->flags |= SRV_F_NAME_REFD;
1542
1543
0
      chunk_destroy(&arg->data.str);
1544
0
      arg->unresolved = 0;
1545
0
      arg->data.srv = srv;
1546
0
      break;
1547
1548
0
    case ARGT_FE:
1549
0
      if (arg->data.str.data) {
1550
0
        pname = arg->data.str.area;
1551
0
        px = proxy_fe_by_name(pname);
1552
0
      }
1553
1554
0
      if (!px) {
1555
0
        memprintf(err, "%sparsing [%s:%d]: unable to find frontend '%s' referenced in arg %d of %s%s%s%s '%s' %s proxy '%s'.\n",
1556
0
           *err ? *err : "", cur->file, cur->line, pname,
1557
0
           cur->arg_pos + 1, conv_pre, conv_ctx, conv_pos, ctx, cur->kw, where, p->id);
1558
0
        cfgerr++;
1559
0
        break;
1560
0
      }
1561
1562
0
      if (!(px->cap & PR_CAP_FE)) {
1563
0
        memprintf(err, "%sparsing [%s:%d]: proxy '%s', referenced in arg %d of %s%s%s%s '%s' %s proxy '%s', has not frontend capability.\n",
1564
0
           *err ? *err : "", cur->file, cur->line, pname,
1565
0
           cur->arg_pos + 1, conv_pre, conv_ctx, conv_pos, ctx, cur->kw, where, p->id);
1566
0
        cfgerr++;
1567
0
        break;
1568
0
      }
1569
1570
      /* TODO CLI set-var should not prevent proxy deletion as var value is instantly resolved. */
1571
0
      px->flags |= PR_FL_NON_PURGEABLE;
1572
1573
0
      chunk_destroy(&arg->data.str);
1574
0
      arg->unresolved = 0;
1575
0
      arg->data.prx = px;
1576
0
      break;
1577
1578
0
    case ARGT_BE:
1579
0
      if (arg->data.str.data) {
1580
0
        pname = arg->data.str.area;
1581
0
        px = proxy_be_by_name(pname);
1582
0
      }
1583
1584
0
      if (!px) {
1585
0
        memprintf(err, "%sparsing [%s:%d]: unable to find backend '%s' referenced in arg %d of %s%s%s%s '%s' %s proxy '%s'.\n",
1586
0
           *err ? *err : "", cur->file, cur->line, pname,
1587
0
           cur->arg_pos + 1, conv_pre, conv_ctx, conv_pos, ctx, cur->kw, where, p->id);
1588
0
        cfgerr++;
1589
0
        break;
1590
0
      }
1591
1592
0
      if (!(px->cap & PR_CAP_BE)) {
1593
0
        memprintf(err, "%sparsing [%s:%d]: proxy '%s', referenced in arg %d of %s%s%s%s '%s' %s proxy '%s', has not backend capability.\n",
1594
0
           *err ? *err : "", cur->file, cur->line, pname,
1595
0
           cur->arg_pos + 1, conv_pre, conv_ctx, conv_pos, ctx, cur->kw, where, p->id);
1596
0
        cfgerr++;
1597
0
        break;
1598
0
      }
1599
1600
      /* TODO CLI set-var should not prevent proxy deletion as var value is instantly resolved. */
1601
0
      px->flags |= PR_FL_NON_PURGEABLE;
1602
1603
0
      chunk_destroy(&arg->data.str);
1604
0
      arg->unresolved = 0;
1605
0
      arg->data.prx = px;
1606
0
      break;
1607
1608
0
    case ARGT_TAB:
1609
0
      if (arg->data.str.data)
1610
0
        stktname = arg->data.str.area;
1611
0
      else {
1612
0
        if (px->cap & PR_CAP_DEF) {
1613
0
          memprintf(err, "%sparsing [%s:%d]: table name must be set in arg %d of %s%s%s%s '%s' %s proxy '%s'.\n",
1614
0
              *err ? *err : "", cur->file, cur->line,
1615
0
              cur->arg_pos + 1, conv_pre, conv_ctx, conv_pos, ctx, cur->kw, where, p->id);
1616
0
          cfgerr++;
1617
0
          break;
1618
0
        }
1619
0
        stktname = px->id;
1620
0
      }
1621
1622
0
      t = stktable_find_by_name(stktname);
1623
0
      if (!t) {
1624
0
        memprintf(err, "%sparsing [%s:%d]: unable to find table '%s' referenced in arg %d of %s%s%s%s '%s' %s proxy '%s'.\n",
1625
0
           *err ? *err : "", cur->file, cur->line, stktname,
1626
0
           cur->arg_pos + 1, conv_pre, conv_ctx, conv_pos, ctx, cur->kw, where, p->id);
1627
0
        cfgerr++;
1628
0
        break;
1629
0
      }
1630
1631
0
      if (!t->size) {
1632
0
        memprintf(err, "%sparsing [%s:%d]: no table in proxy '%s' referenced in arg %d of %s%s%s%s '%s' %s proxy '%s'.\n",
1633
0
           *err ? *err : "", cur->file, cur->line, stktname,
1634
0
           cur->arg_pos + 1, conv_pre, conv_ctx, conv_pos, ctx, cur->kw, where, p->id);
1635
0
        cfgerr++;
1636
0
        break;
1637
0
      }
1638
1639
0
      if (!in_proxies_list(t->proxies_list, p)) {
1640
0
        p->next_stkt_ref = t->proxies_list;
1641
0
        t->proxies_list = p;
1642
0
      }
1643
1644
0
      chunk_destroy(&arg->data.str);
1645
0
      arg->unresolved = 0;
1646
0
      arg->data.t = t;
1647
0
      break;
1648
1649
0
    case ARGT_USR:
1650
0
      if (!arg->data.str.data) {
1651
0
        memprintf(err, "%sparsing [%s:%d]: missing userlist name in arg %d of %s%s%s%s '%s' %s proxy '%s'.\n",
1652
0
           *err ? *err : "", cur->file, cur->line,
1653
0
           cur->arg_pos + 1, conv_pre, conv_ctx, conv_pos, ctx, cur->kw, where, p->id);
1654
0
        cfgerr++;
1655
0
        break;
1656
0
      }
1657
1658
0
      if (p->uri_auth && p->uri_auth->userlist &&
1659
0
          strcmp(p->uri_auth->userlist->name, arg->data.str.area) == 0)
1660
0
        ul = p->uri_auth->userlist;
1661
0
      else
1662
0
        ul = auth_find_userlist(arg->data.str.area);
1663
1664
0
      if (!ul) {
1665
0
        memprintf(err, "%sparsing [%s:%d]: unable to find userlist '%s' referenced in arg %d of %s%s%s%s '%s' %s proxy '%s'.\n",
1666
0
           *err ? *err : "", cur->file, cur->line,
1667
0
           arg->data.str.area,
1668
0
           cur->arg_pos + 1, conv_pre, conv_ctx, conv_pos, ctx, cur->kw, where, p->id);
1669
0
        cfgerr++;
1670
0
        break;
1671
0
      }
1672
1673
0
      chunk_destroy(&arg->data.str);
1674
0
      arg->unresolved = 0;
1675
0
      arg->data.usr = ul;
1676
0
      break;
1677
1678
0
    case ARGT_REG:
1679
0
      if (!arg->data.str.data) {
1680
0
        memprintf(err, "%sparsing [%s:%d]: missing regex in arg %d of %s%s%s%s '%s' %s proxy '%s'.\n",
1681
0
           *err ? *err : "", cur->file, cur->line,
1682
0
           cur->arg_pos + 1, conv_pre, conv_ctx, conv_pos, ctx, cur->kw, where, p->id);
1683
0
        cfgerr++;
1684
0
        break;
1685
0
      }
1686
1687
0
      rflags = 0;
1688
0
      rflags |= (arg->type_flags & ARGF_REG_ICASE) ? REG_ICASE : 0;
1689
0
      err2 = NULL;
1690
1691
0
      if (!(reg = regex_comp(arg->data.str.area, !(rflags & REG_ICASE), 1 /* capture substr */, &err2))) {
1692
0
        memprintf(err, "%sparsing [%s:%d]: error in regex '%s' in arg %d of %s%s%s%s '%s' %s proxy '%s' : %s.\n",
1693
0
            *err ? *err : "", cur->file, cur->line,
1694
0
           arg->data.str.area,
1695
0
           cur->arg_pos + 1, conv_pre, conv_ctx, conv_pos, ctx, cur->kw, where, p->id, err2);
1696
0
        ha_free(&err2);
1697
0
        cfgerr++;
1698
0
        break;
1699
0
      }
1700
1701
0
      chunk_destroy(&arg->data.str);
1702
0
      arg->unresolved = 0;
1703
0
      arg->data.reg = reg;
1704
0
      break;
1705
1706
1707
0
    }
1708
1709
0
    LIST_DELETE(&cur->list);
1710
0
    free(cur);
1711
0
  } /* end of args processing */
1712
1713
0
  return cfgerr;
1714
0
}
1715
1716
/*
1717
 * Process a fetch + format conversion as defined by the sample expression
1718
 * <expr> on request or response considering the <opt> parameter. The output is
1719
 * not explicitly set to <smp_type>, but shall be compatible with it as
1720
 * specified by 'sample_casts' table. If a stable sample can be fetched, or an
1721
 * unstable one when <opt> contains SMP_OPT_FINAL, the sample is converted and
1722
 * returned without the SMP_F_MAY_CHANGE flag. If an unstable sample is found
1723
 * and <opt> does not contain SMP_OPT_FINAL, then the sample is returned as-is
1724
 * with its SMP_F_MAY_CHANGE flag so that the caller can check it and decide to
1725
 * take actions (eg: wait longer). If a sample could not be found or could not
1726
 * be converted, NULL is returned. The caller MUST NOT use the sample if the
1727
 * SMP_F_MAY_CHANGE flag is present, as it is used only as a hint that there is
1728
 * still hope to get it after waiting longer, and is not converted to string.
1729
 * The possible output combinations are the following :
1730
 *
1731
 * return MAY_CHANGE FINAL   Meaning for the sample
1732
 *  NULL      *        *     Not present and will never be (eg: header)
1733
 *   smp      0        *     Final value converted (eg: header)
1734
 *   smp      1        0     Not present yet, may appear later (eg: header)
1735
 *   smp      1        1     never happens (either flag is cleared on output)
1736
 */
1737
struct sample *sample_fetch_as_type(struct proxy *px, struct session *sess,
1738
                                   struct stream *strm, unsigned int opt,
1739
                                   struct sample_expr *expr, int smp_type)
1740
0
{
1741
0
  struct sample *smp = &temp_smp;
1742
1743
0
  memset(smp, 0, sizeof(*smp));
1744
1745
0
  if (!sample_process(px, sess, strm, opt, expr, smp)) {
1746
0
    if ((smp->flags & SMP_F_MAY_CHANGE) && !(opt & SMP_OPT_FINAL))
1747
0
      return smp;
1748
0
    return NULL;
1749
0
  }
1750
1751
0
  if (smp->data.type != smp_type) {
1752
0
    if (!sample_casts[smp->data.type][smp_type])
1753
0
      return NULL;
1754
1755
0
    if (sample_casts[smp->data.type][smp_type] != c_none &&
1756
0
        !sample_casts[smp->data.type][smp_type](smp))
1757
0
      return NULL;
1758
0
  }
1759
1760
0
  smp->flags &= ~SMP_F_MAY_CHANGE;
1761
0
  return smp;
1762
0
}
1763
1764
static void release_sample_arg(struct arg *p)
1765
0
{
1766
0
  struct arg *p_back = p;
1767
1768
0
  if (!p)
1769
0
    return;
1770
1771
0
  while (p->type != ARGT_STOP) {
1772
0
    if (p->type == ARGT_STR || p->unresolved) {
1773
0
      chunk_destroy(&p->data.str);
1774
0
      p->unresolved = 0;
1775
0
    }
1776
0
    else if (p->type == ARGT_REG) {
1777
0
      regex_free(p->data.reg);
1778
0
      p->data.reg = NULL;
1779
0
    }
1780
0
    else if (p->type == ARGT_VAR) {
1781
0
      if (p->data.var.flags & VDF_NAME_ALLOCATED)
1782
0
        ha_free((char **)&p->data.var.name);
1783
0
    }
1784
0
    p++;
1785
0
  }
1786
1787
0
  if (p_back != empty_arg_list)
1788
0
    free(p_back);
1789
0
}
1790
1791
void release_sample_expr(struct sample_expr *expr)
1792
0
{
1793
0
  struct sample_conv_expr *conv_expr, *conv_exprb;
1794
1795
0
  if (!expr)
1796
0
    return;
1797
1798
0
  list_for_each_entry_safe(conv_expr, conv_exprb, &expr->conv_exprs, list) {
1799
0
    LIST_DELETE(&conv_expr->list);
1800
0
    release_sample_arg(conv_expr->arg_p);
1801
0
    free(conv_expr);
1802
0
  }
1803
1804
0
  release_sample_arg(expr->arg_p);
1805
0
  free(expr);
1806
0
}
1807
1808
/*****************************************************************/
1809
/*    Sample format convert functions                            */
1810
/*    These functions set the data type on return.               */
1811
/*****************************************************************/
1812
1813
static int sample_conv_debug(const struct arg *arg_p, struct sample *smp, void *private)
1814
0
{
1815
0
  int i;
1816
0
  struct sample tmp;
1817
0
  struct buffer *buf;
1818
0
  struct sink *sink;
1819
0
  struct ist line;
1820
0
  char *pfx;
1821
1822
0
  buf = alloc_trash_chunk();
1823
0
  if (!buf)
1824
0
    goto end;
1825
1826
0
  sink = (struct sink *)arg_p[1].data.ptr;
1827
0
  BUG_ON(!sink);
1828
1829
0
  pfx = arg_p[0].data.str.area;
1830
0
  BUG_ON(!pfx);
1831
1832
0
  chunk_printf(buf, "[debug] %s: type=%s ", pfx, smp_to_type[smp->data.type]);
1833
0
  if (!sample_casts[smp->data.type][SMP_T_STR])
1834
0
    goto nocast;
1835
1836
  /* Copy sample fetch. This puts the sample as const, the
1837
   * cast will copy data if a transformation is required.
1838
   */
1839
0
  memcpy(&tmp, smp, sizeof(struct sample));
1840
0
  tmp.flags = SMP_F_CONST;
1841
1842
0
  if (!sample_casts[smp->data.type][SMP_T_STR](&tmp))
1843
0
    goto nocast;
1844
1845
  /* Display the displayable chars*. */
1846
0
  b_putchr(buf, '<');
1847
0
  for (i = 0; i < tmp.data.u.str.data; i++) {
1848
0
    if (isprint((unsigned char)tmp.data.u.str.area[i]))
1849
0
      b_putchr(buf, tmp.data.u.str.area[i]);
1850
0
    else
1851
0
      b_putchr(buf, '.');
1852
0
  }
1853
0
  b_putchr(buf, '>');
1854
1855
0
 done:
1856
0
  line = ist2(buf->area, buf->data);
1857
0
  sink_write(sink, LOG_HEADER_NONE, 0, &line, 1);
1858
0
 end:
1859
0
  free_trash_chunk(buf);
1860
0
  return 1;
1861
0
 nocast:
1862
0
  chunk_appendf(buf, "(undisplayable)");
1863
0
  goto done;
1864
0
}
1865
1866
// This function checks the "debug" converter's arguments.
1867
static int smp_check_debug(struct arg *args, struct sample_conv *conv,
1868
                           const char *file, int line, char **err)
1869
0
{
1870
0
  const char *name = "buf0";
1871
0
  struct sink *sink = NULL;
1872
1873
0
  if (args[0].type != ARGT_STR) {
1874
    /* optional prefix */
1875
0
    args[0].data.str.area = "";
1876
0
    args[0].data.str.data = 0;
1877
0
  }
1878
1879
0
  if (args[1].type == ARGT_STR)
1880
0
    name = args[1].data.str.area;
1881
1882
0
  sink = sink_find_early(name, "debug converter", file, line);
1883
0
  if (!sink) {
1884
0
    memprintf(err, "Memory error while setting up sink '%s'", name);
1885
0
    return 0;
1886
0
  }
1887
1888
0
  chunk_destroy(&args[1].data.str);
1889
0
  args[1].type = ARGT_PTR;
1890
0
  args[1].data.ptr = sink;
1891
0
  return 1;
1892
0
}
1893
1894
static int sample_conv_base642bin(const struct arg *arg_p, struct sample *smp, void *private)
1895
0
{
1896
0
  struct buffer *trash = get_trash_chunk_sz(smp->data.u.str.data);
1897
0
  int bin_len;
1898
1899
0
  if (!trash)
1900
0
    return 0;
1901
0
  trash->data = 0;
1902
0
  bin_len = base64dec(smp->data.u.str.area, smp->data.u.str.data,
1903
0
          trash->area, trash->size);
1904
0
  if (bin_len < 0)
1905
0
    return 0;
1906
1907
0
  trash->data = bin_len;
1908
0
  smp->data.u.str = *trash;
1909
0
  smp->data.type = SMP_T_BIN;
1910
0
  smp->flags &= ~SMP_F_CONST;
1911
0
  return 1;
1912
0
}
1913
1914
static int sample_conv_base64url2bin(const struct arg *arg_p, struct sample *smp, void *private)
1915
0
{
1916
0
  struct buffer *trash = get_trash_chunk_sz(smp->data.u.str.data);
1917
0
  int bin_len;
1918
1919
0
  if (!trash)
1920
0
    return 0;
1921
0
  trash->data = 0;
1922
0
  bin_len = base64urldec(smp->data.u.str.area, smp->data.u.str.data,
1923
0
          trash->area, trash->size);
1924
0
  if (bin_len < 0)
1925
0
    return 0;
1926
1927
0
  trash->data = bin_len;
1928
0
  smp->data.u.str = *trash;
1929
0
  smp->data.type = SMP_T_BIN;
1930
0
  smp->flags &= ~SMP_F_CONST;
1931
0
  return 1;
1932
0
}
1933
1934
static int sample_conv_bin2base64(const struct arg *arg_p, struct sample *smp, void *private)
1935
0
{
1936
0
  struct buffer *trash = get_best_trash_chunk(&smp->data.u.str, (smp->data.u.str.data+2) * 4 / 3);
1937
0
  int b64_len;
1938
1939
0
  if (!trash)
1940
0
    return 0;
1941
0
  trash->data = 0;
1942
0
  b64_len = a2base64(smp->data.u.str.area, smp->data.u.str.data,
1943
0
         trash->area, trash->size);
1944
0
  if (b64_len < 0)
1945
0
    return 0;
1946
1947
0
  trash->data = b64_len;
1948
0
  smp->data.u.str = *trash;
1949
0
  smp->data.type = SMP_T_STR;
1950
0
  smp->flags &= ~SMP_F_CONST;
1951
0
  return 1;
1952
0
}
1953
1954
static int sample_conv_bin2base64url(const struct arg *arg_p, struct sample *smp, void *private)
1955
0
{
1956
0
  struct buffer *trash = get_best_trash_chunk(&smp->data.u.str, (smp->data.u.str.data+2) * 4 / 3);
1957
0
  int b64_len;
1958
1959
0
  if (!trash)
1960
0
    return 0;
1961
0
  trash->data = 0;
1962
0
  b64_len = a2base64url(smp->data.u.str.area, smp->data.u.str.data,
1963
0
         trash->area, trash->size);
1964
0
  if (b64_len < 0)
1965
0
    return 0;
1966
1967
0
  trash->data = b64_len;
1968
0
  smp->data.u.str = *trash;
1969
0
  smp->data.type = SMP_T_STR;
1970
0
  smp->flags &= ~SMP_F_CONST;
1971
0
  return 1;
1972
0
}
1973
1974
/* This function returns a sample struct filled with the conversion of variable
1975
 * <var> to sample type <type> (SMP_T_*), via a cast to the target type. If the
1976
 * variable cannot be retrieved or casted, 0 is returned, otherwise 1.
1977
 *
1978
 * Keep in mind that the sample content may be written to a pre-allocated
1979
 * trash chunk as returned by get_trash_chunk().
1980
 */
1981
int sample_conv_var2smp(const struct var_desc *var, struct sample *smp, int type)
1982
0
{
1983
0
  if (!vars_get_by_desc(var, smp, NULL))
1984
0
    return 0;
1985
0
  if (!sample_casts[smp->data.type][type])
1986
0
    return 0;
1987
0
  if (!sample_casts[smp->data.type][type](smp))
1988
0
    return 0;
1989
0
  return 1;
1990
0
}
1991
1992
static int sample_conv_sha1(const struct arg *arg_p, struct sample *smp, void *private)
1993
0
{
1994
0
  blk_SHA_CTX ctx;
1995
0
  struct buffer *trash = get_trash_chunk();
1996
1997
0
  memset(&ctx, 0, sizeof(ctx));
1998
1999
0
  blk_SHA1_Init(&ctx);
2000
0
  blk_SHA1_Update(&ctx, smp->data.u.str.area, smp->data.u.str.data);
2001
0
  blk_SHA1_Final((unsigned char *) trash->area, &ctx);
2002
2003
0
  trash->data = 20;
2004
0
  smp->data.u.str = *trash;
2005
0
  smp->data.type = SMP_T_BIN;
2006
0
  smp->flags &= ~SMP_F_CONST;
2007
0
  return 1;
2008
0
}
2009
2010
/* This function returns a sample struct filled with an <arg> content.
2011
 * If the <arg> contains a string, it is returned in the sample flagged as
2012
 * SMP_F_CONST. If the <arg> contains a variable descriptor, the sample is
2013
 * filled with the content of the variable by using vars_get_by_desc().
2014
 *
2015
 * Keep in mind that the sample content may be written to a pre-allocated
2016
 * trash chunk as returned by get_trash_chunk().
2017
 *
2018
 * This function returns 0 if an error occurs, otherwise it returns 1.
2019
 */
2020
int sample_conv_var2smp_str(const struct arg *arg, struct sample *smp)
2021
0
{
2022
0
  switch (arg->type) {
2023
0
  case ARGT_STR:
2024
0
    smp->data.type = SMP_T_STR;
2025
0
    smp->data.u.str = arg->data.str;
2026
0
    smp->flags = SMP_F_CONST;
2027
0
    return 1;
2028
0
  case ARGT_VAR:
2029
0
    return sample_conv_var2smp(&arg->data.var, smp, SMP_T_STR);
2030
0
  default:
2031
0
    return 0;
2032
0
  }
2033
0
}
2034
2035
static int sample_conv_2dec_check(struct arg *args, struct sample_conv *conv,
2036
                                    const char *file, int line, char **err)
2037
0
{
2038
0
  if (args[1].data.sint <= 0 || args[1].data.sint > sizeof(unsigned long long)) {
2039
0
    memprintf(err, "chunk_size out of [1..%u] range (%lld)", (uint)sizeof(unsigned long long), args[1].data.sint);
2040
0
    return 0;
2041
0
  }
2042
2043
0
  if (args[2].data.sint != 0 && args[2].data.sint != 1) {
2044
0
    memprintf(err, "Unsupported truncate value (%lld)", args[2].data.sint);
2045
0
    return 0;
2046
0
  }
2047
2048
0
  return 1;
2049
0
}
2050
2051
/* Converts big-endian/little-endian binary input sample to a string containing an unsigned
2052
 * integer number per <chunk_size> input bytes separated with <separator>.
2053
 * Optional <truncate> flag indicates if input is truncated at <chunk_size>
2054
 * boundaries.
2055
 * Arguments: separator (string), chunk_size (integer), truncate (0,1), big endian (0,1)
2056
 */
2057
static int sample_conv_2dec(const struct arg *args, struct sample *smp, void *private, int be)
2058
0
{
2059
0
  struct buffer *trash = get_trash_chunk_sz(smp->data.u.str.data);
2060
0
  const int last = args[2].data.sint ? smp->data.u.str.data - args[1].data.sint + 1 : smp->data.u.str.data;
2061
0
  int max_size;
2062
0
  int i;
2063
0
  int start;
2064
0
  int ptr = 0;
2065
0
  unsigned long long number;
2066
0
  char *pos;
2067
2068
0
  if (!trash)
2069
0
    return 0;
2070
0
  max_size = trash->size - 2;
2071
0
  trash->data = 0;
2072
2073
0
  while (ptr < last && trash->data <= max_size) {
2074
0
    start = trash->data;
2075
0
    if (ptr) {
2076
      /* Add separator */
2077
0
      memcpy(trash->area + trash->data, args[0].data.str.area, args[0].data.str.data);
2078
0
      trash->data += args[0].data.str.data;
2079
0
    }
2080
0
    else
2081
0
      max_size -= args[0].data.str.data;
2082
2083
    /* Add integer */
2084
0
    for (number = 0, i = 0; i < args[1].data.sint && ptr < smp->data.u.str.data; i++) {
2085
0
      if (be)
2086
0
        number = (number << 8) + (unsigned char)smp->data.u.str.area[ptr++];
2087
0
      else
2088
0
        number |= (unsigned char)smp->data.u.str.area[ptr++] << (i*8);
2089
0
    }
2090
2091
0
    pos = ulltoa(number, trash->area + trash->data, trash->size - trash->data);
2092
0
    if (pos)
2093
0
      trash->data = pos - trash->area;
2094
0
    else {
2095
0
      trash->data = start;
2096
0
      break;
2097
0
    }
2098
0
  }
2099
2100
0
  smp->data.u.str = *trash;
2101
0
  smp->data.type = SMP_T_STR;
2102
0
  smp->flags &= ~SMP_F_CONST;
2103
0
  return 1;
2104
0
}
2105
2106
/* Converts big-endian binary input sample to a string containing an unsigned
2107
 * integer number per <chunk_size> input bytes separated with <separator>.
2108
 * Optional <truncate> flag indicates if input is truncated at <chunk_size>
2109
 * boundaries.
2110
 * Arguments: separator (string), chunk_size (integer), truncate (0,1)
2111
 */
2112
static int sample_conv_be2dec(const struct arg *args, struct sample *smp, void *private)
2113
0
{
2114
0
  return sample_conv_2dec(args, smp, private, 1);
2115
0
}
2116
2117
/* Converts little-endian binary input sample to a string containing an unsigned
2118
 * integer number per <chunk_size> input bytes separated with <separator>.
2119
 * Optional <truncate> flag indicates if input is truncated at <chunk_size>
2120
 * boundaries.
2121
 * Arguments: separator (string), chunk_size (integer), truncate (0,1)
2122
 */
2123
static int sample_conv_le2dec(const struct arg *args, struct sample *smp, void *private)
2124
0
{
2125
0
  return sample_conv_2dec(args, smp, private, 0);
2126
0
}
2127
2128
static int sample_conv_be2hex_check(struct arg *args, struct sample_conv *conv,
2129
                                    const char *file, int line, char **err)
2130
0
{
2131
0
  if (args[1].data.sint <= 0 && (args[0].data.str.data > 0 || args[2].data.sint != 0)) {
2132
0
    memprintf(err, "chunk_size needs to be positive (%lld)", args[1].data.sint);
2133
0
    return 0;
2134
0
  }
2135
2136
0
  if (args[2].data.sint != 0 && args[2].data.sint != 1) {
2137
0
    memprintf(err, "Unsupported truncate value (%lld)", args[2].data.sint);
2138
0
    return 0;
2139
0
  }
2140
2141
0
  return 1;
2142
0
}
2143
2144
/* Converts big-endian binary input sample to a hex string containing two hex
2145
 * digits per input byte. <separator> is put every <chunk_size> binary input
2146
 * bytes if specified. Optional <truncate> flag indicates if input is truncated
2147
 * at <chunk_size> boundaries.
2148
 * Arguments: separator (string), chunk_size (integer), truncate (0,1)
2149
 */
2150
static int sample_conv_be2hex(const struct arg *args, struct sample *smp, void *private)
2151
0
{
2152
0
  struct buffer *trash = get_best_trash_chunk(&smp->data.u.str, smp->data.u.str.size);
2153
0
  int chunk_size = args[1].data.sint;
2154
0
  const int last = args[2].data.sint ? smp->data.u.str.data - chunk_size + 1 : smp->data.u.str.data;
2155
0
  int i;
2156
0
  size_t max_size;
2157
0
  int ptr = 0;
2158
0
  unsigned char c;
2159
2160
0
  if (!trash)
2161
0
    return 0;
2162
0
  trash->data = 0;
2163
0
  if (args[0].data.str.data == 0 && args[2].data.sint == 0)
2164
0
    chunk_size = smp->data.u.str.data;
2165
0
  if (2 * (size_t)chunk_size + args[0].data.str.data > trash->size)
2166
0
    return 0;
2167
0
  max_size = trash->size - 2 * (size_t)chunk_size;
2168
2169
0
  while (ptr < last && trash->data <= max_size) {
2170
0
    if (ptr) {
2171
      /* Add separator */
2172
0
      memcpy(trash->area + trash->data, args[0].data.str.area, args[0].data.str.data);
2173
0
      trash->data += args[0].data.str.data;
2174
0
    }
2175
0
    else
2176
0
      max_size -= args[0].data.str.data;
2177
2178
    /* Add hex */
2179
0
    for (i = 0; i < chunk_size && ptr < smp->data.u.str.data; i++) {
2180
0
      c = smp->data.u.str.area[ptr++];
2181
0
      trash->area[trash->data++] = hextab[(c >> 4) & 0xF];
2182
0
      trash->area[trash->data++] = hextab[c & 0xF];
2183
0
    }
2184
0
  }
2185
2186
0
  smp->data.u.str = *trash;
2187
0
  smp->data.type = SMP_T_STR;
2188
0
  smp->flags &= ~SMP_F_CONST;
2189
0
  return 1;
2190
0
}
2191
2192
static int sample_conv_bin2hex(const struct arg *arg_p, struct sample *smp, void *private)
2193
0
{
2194
0
  struct buffer *trash = get_best_trash_chunk(&smp->data.u.str, smp->data.u.str.data*2);
2195
0
  unsigned char c;
2196
0
  int ptr = 0;
2197
2198
0
  if (!trash)
2199
0
    return 0;
2200
0
  trash->data = 0;
2201
0
  while (ptr < smp->data.u.str.data && trash->data <= trash->size - 2) {
2202
0
    c = smp->data.u.str.area[ptr++];
2203
0
    trash->area[trash->data++] = hextab[(c >> 4) & 0xF];
2204
0
    trash->area[trash->data++] = hextab[c & 0xF];
2205
0
  }
2206
0
  smp->data.u.str = *trash;
2207
0
  smp->data.type = SMP_T_STR;
2208
0
  smp->flags &= ~SMP_F_CONST;
2209
0
  return 1;
2210
0
}
2211
2212
static int sample_conv_bin2base2(const struct arg *arg_p, struct sample *smp, void *private)
2213
0
{
2214
0
  struct buffer *trash = get_best_trash_chunk(&smp->data.u.str, smp->data.u.str.data*8);
2215
0
  unsigned char c;
2216
0
  int ptr = 0;
2217
0
  int bit = 0;
2218
2219
0
  if (!trash)
2220
0
    return 0;
2221
0
  trash->data = 0;
2222
0
  while (ptr < smp->data.u.str.data && trash->data <= trash->size - 8) {
2223
0
    c = smp->data.u.str.area[ptr++];
2224
0
                for (bit = 7; bit >= 0; bit--)
2225
0
                        trash->area[trash->data++] = c & (1 << bit) ? '1' : '0';
2226
0
  }
2227
0
  smp->data.u.str = *trash;
2228
0
  smp->data.type = SMP_T_STR;
2229
0
  smp->flags &= ~SMP_F_CONST;
2230
0
  return 1;
2231
0
}
2232
2233
static int sample_conv_hex2int(const struct arg *arg_p, struct sample *smp, void *private)
2234
0
{
2235
0
  long long int n = 0;
2236
0
  int i, c;
2237
2238
0
  for (i = 0; i < smp->data.u.str.data; i++) {
2239
0
    if ((c = hex2i(smp->data.u.str.area[i])) < 0)
2240
0
      return 0;
2241
0
    n = (n << 4) + c;
2242
0
  }
2243
2244
0
  smp->data.u.sint = n;
2245
0
  smp->data.type = SMP_T_SINT;
2246
0
  smp->flags &= ~SMP_F_CONST;
2247
0
  return 1;
2248
0
}
2249
2250
/* hashes the binary input into a 32-bit unsigned int */
2251
static int sample_conv_djb2(const struct arg *arg_p, struct sample *smp, void *private)
2252
0
{
2253
0
  smp->data.u.sint = hash_djb2(smp->data.u.str.area,
2254
0
             smp->data.u.str.data);
2255
0
  if (arg_p->data.sint)
2256
0
    smp->data.u.sint = full_hash(smp->data.u.sint);
2257
0
  smp->data.type = SMP_T_SINT;
2258
0
  return 1;
2259
0
}
2260
2261
static int sample_conv_length(const struct arg *arg_p, struct sample *smp, void *private)
2262
0
{
2263
0
  int i = smp->data.u.str.data;
2264
0
  smp->data.u.sint = i;
2265
0
  smp->data.type = SMP_T_SINT;
2266
0
  return 1;
2267
0
}
2268
2269
2270
static int sample_conv_str2lower(const struct arg *arg_p, struct sample *smp, void *private)
2271
0
{
2272
0
  int i;
2273
2274
0
  if (!smp_make_rw(smp))
2275
0
    return 0;
2276
2277
0
  for (i = 0; i < smp->data.u.str.data; i++) {
2278
0
    if ((smp->data.u.str.area[i] >= 'A') && (smp->data.u.str.area[i] <= 'Z'))
2279
0
      smp->data.u.str.area[i] += 'a' - 'A';
2280
0
  }
2281
0
  return 1;
2282
0
}
2283
2284
static int sample_conv_str2upper(const struct arg *arg_p, struct sample *smp, void *private)
2285
0
{
2286
0
  int i;
2287
2288
0
  if (!smp_make_rw(smp))
2289
0
    return 0;
2290
2291
0
  for (i = 0; i < smp->data.u.str.data; i++) {
2292
0
    if ((smp->data.u.str.area[i] >= 'a') && (smp->data.u.str.area[i] <= 'z'))
2293
0
      smp->data.u.str.area[i] += 'A' - 'a';
2294
0
  }
2295
0
  return 1;
2296
0
}
2297
2298
/* Reverses the input string byte by byte. */
2299
static int sample_conv_reverse(const struct arg *arg_p, struct sample *smp, void *private)
2300
0
{
2301
0
  const char *input = smp->data.u.str.area;
2302
0
  struct buffer *trash;
2303
0
  int input_len = smp->data.u.str.data;
2304
0
  int i;
2305
2306
0
  trash = get_best_trash_chunk(&smp->data.u.str, input_len+1);
2307
0
  if (!trash)
2308
0
    return 0;
2309
2310
0
  for (i = 0; i < input_len; i++)
2311
0
    trash->area[i] = input[input_len - 1 - i];
2312
2313
0
  trash->area[input_len] = 0;
2314
0
  trash->data = input_len;
2315
0
  smp->data.u.str = *trash;
2316
0
  smp->data.type = SMP_T_STR;
2317
0
  smp->flags &= ~SMP_F_CONST;
2318
0
  return 1;
2319
0
}
2320
2321
/* Reverses the order of labels in an FQDN-like string. A single trailing dot
2322
 * on input is ignored. Empty labels are rejected.
2323
 */
2324
static int sample_conv_reverse_dom(const struct arg *arg_p, struct sample *smp, void *private)
2325
0
{
2326
0
  const char *input = smp->data.u.str.area;
2327
0
  struct buffer *trash;
2328
0
  int input_len = smp->data.u.str.data;
2329
0
  int out = 0;
2330
0
  int label_end;
2331
0
  int label_start;
2332
0
  int label_len;
2333
2334
0
  if (!input_len)
2335
0
    return 0;
2336
2337
0
  if (input[input_len - 1] == '.') {
2338
0
    input_len--;
2339
0
    if (!input_len)
2340
0
      return 0;
2341
0
  }
2342
2343
0
  if (input[0] == '.')
2344
0
    return 0;
2345
2346
0
  trash = get_best_trash_chunk(&smp->data.u.str, input_len+1);
2347
0
  if (!trash)
2348
0
    return 0;
2349
2350
0
  label_end = input_len;
2351
0
  while (label_end > 0) {
2352
0
    label_start = label_end - 1;
2353
0
    while (label_start >= 0 && input[label_start] != '.')
2354
0
      label_start--;
2355
0
    label_start++;
2356
2357
0
    if (label_start == label_end)
2358
0
      return 0;
2359
2360
0
    label_len = label_end - label_start;
2361
0
    memcpy(trash->area + out, input + label_start, label_len);
2362
0
    out += label_len;
2363
2364
0
    if (label_start == 0)
2365
0
      break;
2366
2367
0
    trash->area[out++] = '.';
2368
0
    label_end = label_start - 1;
2369
0
  }
2370
2371
0
  trash->area[out] = 0;
2372
0
  trash->data = out;
2373
0
  smp->data.u.str = *trash;
2374
0
  smp->data.type = SMP_T_STR;
2375
0
  smp->flags &= ~SMP_F_CONST;
2376
0
  return 1;
2377
0
}
2378
2379
/* takes the IPv4 mask in args[0] and an optional IPv6 mask in args[1] */
2380
static int sample_conv_ipmask(const struct arg *args, struct sample *smp, void *private)
2381
0
{
2382
  /* Attempt to convert to IPv4 to apply the correct mask. */
2383
0
  c_ipv62ip(smp);
2384
2385
0
  if (smp->data.type == SMP_T_IPV4) {
2386
0
    smp->data.u.ipv4.s_addr &= args[0].data.ipv4.s_addr;
2387
0
    smp->data.type = SMP_T_IPV4;
2388
0
  }
2389
0
  else if (smp->data.type == SMP_T_IPV6) {
2390
    /* IPv6 cannot be converted without an IPv6 mask. */
2391
0
    if (args[1].type != ARGT_IPV6)
2392
0
      return 0;
2393
2394
0
    write_u64(&smp->data.u.ipv6.s6_addr[0],
2395
0
        read_u64(&smp->data.u.ipv6.s6_addr[0]) & read_u64(&args[1].data.ipv6.s6_addr[0]));
2396
0
    write_u64(&smp->data.u.ipv6.s6_addr[8],
2397
0
        read_u64(&smp->data.u.ipv6.s6_addr[8]) & read_u64(&args[1].data.ipv6.s6_addr[8]));
2398
0
    smp->data.type = SMP_T_IPV6;
2399
0
  }
2400
2401
0
  return 1;
2402
0
}
2403
2404
/*
2405
 * This function implement a conversion specifier seeker for %N so it could be
2406
 * replaced before doing strftime.
2407
 *
2408
 * <format> is the input format string which is used as a haystack
2409
 *
2410
 * The function fills multiple variables:
2411
 * <skip> is the len of the conversion specifier string which was found (ex: strlen(%N):2, strlen(%3N):3 strlen(%123N): 5)
2412
 * <width> is the width argument, default width is 9 (ex: %3N: 3, %4N: 4: %N: 9, %5N: 5)
2413
 *
2414
 * Returns a ptr to the first character of the conversion specifier or NULL if not found
2415
 */
2416
static const char *lookup_convspec_N(const char *format, int *skip, int *width)
2417
0
{
2418
0
  const char *p, *needle;
2419
0
  const char *digits;
2420
0
  int state;
2421
2422
0
  p = format;
2423
2424
  /* this looks for % in loop. The iteration stops when a %N conversion
2425
   * specifier was found or there is no '%' anymore */
2426
0
lookagain:
2427
0
  while (p && *p) {
2428
0
    state = 0;
2429
0
    digits = NULL;
2430
2431
0
    p = needle = strchr(p, '%');
2432
    /* Once we find a % we try to move forward in the string
2433
     *
2434
     * state 0: found %
2435
     * state 1: digits (precision)
2436
     * state 2: N
2437
     */
2438
0
    while (p && *p) {
2439
0
      switch (state) {
2440
0
        case 0:
2441
0
          state = 1;
2442
0
          break;
2443
2444
0
        case 1:
2445
0
          if (isdigit((unsigned char)*p) && !digits) /* set the start of the digits */
2446
0
            digits = p;
2447
2448
0
          if (isdigit((unsigned char)*p))
2449
0
            break;
2450
0
          else
2451
0
            state = 2;
2452
          /* if this is not a number anymore, we
2453
          * don't want to increment p but try the
2454
          * next state directly */
2455
0
          __fallthrough;
2456
0
        case 2:
2457
0
          if (*p == 'N')
2458
0
            goto found;
2459
0
          else
2460
            /* this was not a %N, start again */
2461
0
            goto lookagain;
2462
0
          break;
2463
0
      }
2464
0
      p++;
2465
0
    }
2466
0
  }
2467
2468
0
  *skip = 0;
2469
0
  *width = 0;
2470
0
  return NULL;
2471
2472
0
found:
2473
0
  *skip = p - needle + 1;
2474
0
  if (digits)
2475
0
    *width = atoi(digits);
2476
0
  else
2477
0
    *width = 9;
2478
0
  return needle;
2479
0
}
2480
2481
 /*
2482
  * strftime(3) does not implement nanoseconds, but we still want them in our
2483
  * date format.
2484
  *
2485
  * This function implements %N like in date(1) which gives you the nanoseconds part of the timestamp
2486
  * An optional field width can be specified, a maximum width of 9 is supported (ex: %3N %6N %9N)
2487
  *
2488
  * <format> is the format string
2489
  * <curr_date> in seconds since epoch
2490
  * <ns> only the nanoseconds part of the timestamp
2491
  * <local> chose the localtime instead of UTC time
2492
  *
2493
  * Return the results of strftime in the trash buffer
2494
  */
2495
static struct buffer *conv_time_common(const char *format, time_t curr_date, uint64_t ns, int local)
2496
0
{
2497
0
  struct buffer *tmp_format = NULL;
2498
0
  struct buffer *res = NULL;
2499
0
  struct tm tm;
2500
0
  const char *p;
2501
0
  char ns_str[10] = {};
2502
0
  int set = 0;
2503
2504
0
  if (local)
2505
0
    get_localtime(curr_date, &tm);
2506
0
  else
2507
0
    get_gmtime(curr_date, &tm);
2508
2509
2510
  /* we need to iterate in order to replace all the %N in the string */
2511
2512
0
  p = format;
2513
0
  while (*p) {
2514
0
    const char *needle;
2515
0
    int skip = 0;
2516
0
    int cpy = 0;
2517
0
    int width = 0;
2518
2519
    /* look for the next %N onversion specifier */
2520
0
    if (!(needle = lookup_convspec_N(p, &skip, &width)))
2521
0
      break;
2522
2523
0
    if (width > 9) /* we don't handle more that 9 */
2524
0
      width = 9;
2525
0
    cpy = needle - p;
2526
2527
0
    if (!tmp_format)
2528
0
      tmp_format = alloc_trash_chunk();
2529
0
    if (!tmp_format)
2530
0
      goto error;
2531
2532
0
    if (set != 9) /* if the snprintf wasn't done yet */
2533
0
      set = snprintf(ns_str, sizeof(ns_str), "%.9llu", (unsigned long long)ns);
2534
2535
0
    if (chunk_istcat(tmp_format, ist2(p, cpy)) == 0) /* copy before the %N */
2536
0
      goto error;
2537
0
    if (chunk_istcat(tmp_format, ist2(ns_str, width)) == 0) /* copy the %N result with the right precision  */
2538
0
      goto error;
2539
2540
0
    p += skip + cpy; /* skip the %N */
2541
0
  }
2542
2543
2544
0
  if (tmp_format) { /* %N was found */
2545
0
    if (chunk_strcat(tmp_format, p) == 0)  /* copy the end of the string if needed or just the \0 */
2546
0
      goto error;
2547
0
    res = get_trash_chunk();
2548
0
    res->data = strftime(res->area, res->size, tmp_format->area , &tm);
2549
0
  } else {
2550
0
    res = get_trash_chunk();
2551
0
    res->data = strftime(res->area, res->size, format, &tm);
2552
0
  }
2553
2554
0
error:
2555
0
  free_trash_chunk(tmp_format);
2556
0
  return res;
2557
0
}
2558
2559
2560
2561
/*
2562
 * same as sample_conv_ltime but input is us and %N is supported
2563
 */
2564
static int sample_conv_us_ltime(const struct arg *args, struct sample *smp, void *private)
2565
0
{
2566
0
  struct buffer *temp;
2567
0
  time_t curr_date = smp->data.u.sint / 1000000; /* convert us to s */
2568
0
  uint64_t ns = (smp->data.u.sint % 1000000) * 1000; /*  us part to ns */
2569
2570
  /* add offset */
2571
0
  if (args[1].type == ARGT_SINT)
2572
0
    curr_date += args[1].data.sint;
2573
2574
0
  temp = conv_time_common(args[0].data.str.area, curr_date, ns, 1);
2575
0
  smp->data.u.str = *temp;
2576
0
  smp->data.type = SMP_T_STR;
2577
0
  return 1;
2578
0
}
2579
2580
/*
2581
 * same as sample_conv_ltime but input is ms and %N is supported
2582
 */
2583
static int sample_conv_ms_ltime(const struct arg *args, struct sample *smp, void *private)
2584
0
{
2585
0
  struct buffer *temp;
2586
0
  time_t curr_date = smp->data.u.sint / 1000; /* convert ms to s */
2587
0
  uint64_t ns = (smp->data.u.sint % 1000) * 1000000; /*  ms part to ns */
2588
2589
  /* add offset */
2590
0
  if (args[1].type == ARGT_SINT)
2591
0
    curr_date += args[1].data.sint;
2592
2593
0
  temp = conv_time_common(args[0].data.str.area, curr_date, ns, 1);
2594
0
  smp->data.u.str = *temp;
2595
0
  smp->data.type = SMP_T_STR;
2596
0
  return 1;
2597
0
}
2598
2599
2600
/* takes an UINT value on input supposed to represent the time since EPOCH,
2601
 * adds an optional offset found in args[1] and emits a string representing
2602
 * the local time in the format specified in args[1] using strftime().
2603
 */
2604
static int sample_conv_ltime(const struct arg *args, struct sample *smp, void *private)
2605
0
{
2606
0
  struct buffer *temp;
2607
  /* With high numbers, the date returned can be negative, the 55 bits mask prevent this. */
2608
0
  time_t curr_date = smp->data.u.sint & 0x007fffffffffffffLL;
2609
0
  struct tm tm;
2610
2611
  /* add offset */
2612
0
  if (args[1].type == ARGT_SINT)
2613
0
    curr_date += args[1].data.sint;
2614
2615
0
  get_localtime(curr_date, &tm);
2616
2617
0
  temp = get_trash_chunk();
2618
0
  temp->data = strftime(temp->area, temp->size, args[0].data.str.area, &tm);
2619
0
  smp->data.u.str = *temp;
2620
0
  smp->data.type = SMP_T_STR;
2621
0
  return 1;
2622
0
}
2623
2624
/* hashes the binary input into a 32-bit unsigned int */
2625
static int sample_conv_sdbm(const struct arg *arg_p, struct sample *smp, void *private)
2626
0
{
2627
0
  smp->data.u.sint = hash_sdbm(smp->data.u.str.area,
2628
0
             smp->data.u.str.data);
2629
0
  if (arg_p->data.sint)
2630
0
    smp->data.u.sint = full_hash(smp->data.u.sint);
2631
0
  smp->data.type = SMP_T_SINT;
2632
0
  return 1;
2633
0
}
2634
2635
/*
2636
 * same as sample_conv_utime but input is us and %N is supported
2637
 */
2638
static int sample_conv_us_utime(const struct arg *args, struct sample *smp, void *private)
2639
0
{
2640
0
  struct buffer *temp;
2641
0
  time_t curr_date = smp->data.u.sint / 1000000; /* convert us to s */
2642
0
  uint64_t ns = (smp->data.u.sint % 1000000) * 1000; /*  us part to ns */
2643
2644
  /* add offset */
2645
0
  if (args[1].type == ARGT_SINT)
2646
0
    curr_date += args[1].data.sint;
2647
2648
0
  temp = conv_time_common(args[0].data.str.area, curr_date, ns, 0);
2649
0
  smp->data.u.str = *temp;
2650
0
  smp->data.type = SMP_T_STR;
2651
0
  return 1;
2652
0
}
2653
2654
/*
2655
 * same as sample_conv_utime but input is ms and %N is supported
2656
 */
2657
static int sample_conv_ms_utime(const struct arg *args, struct sample *smp, void *private)
2658
0
{
2659
0
  struct buffer *temp;
2660
0
  time_t curr_date = smp->data.u.sint / 1000; /* convert ms to s */
2661
0
  uint64_t ns = (smp->data.u.sint % 1000) * 1000000; /*  ms part to ns */
2662
2663
  /* add offset */
2664
0
  if (args[1].type == ARGT_SINT)
2665
0
    curr_date += args[1].data.sint;
2666
2667
0
  temp = conv_time_common(args[0].data.str.area, curr_date, ns, 0);
2668
0
  smp->data.u.str = *temp;
2669
0
  smp->data.type = SMP_T_STR;
2670
0
  return 1;
2671
0
}
2672
2673
/* takes an UINT value on input supposed to represent the time since EPOCH,
2674
 * adds an optional offset found in args[1] and emits a string representing
2675
 * the UTC date in the format specified in args[1] using strftime().
2676
 */
2677
static int sample_conv_utime(const struct arg *args, struct sample *smp, void *private)
2678
0
{
2679
0
  struct buffer *temp;
2680
  /* With high numbers, the date returned can be negative, the 55 bits mask prevent this. */
2681
0
  time_t curr_date = smp->data.u.sint & 0x007fffffffffffffLL;
2682
0
  struct tm tm;
2683
2684
  /* add offset */
2685
0
  if (args[1].type == ARGT_SINT)
2686
0
    curr_date += args[1].data.sint;
2687
2688
0
  get_gmtime(curr_date, &tm);
2689
2690
0
  temp = get_trash_chunk();
2691
0
  temp->data = strftime(temp->area, temp->size, args[0].data.str.area, &tm);
2692
0
  smp->data.u.str = *temp;
2693
0
  smp->data.type = SMP_T_STR;
2694
0
  return 1;
2695
0
}
2696
2697
/* hashes the binary input into a 32-bit unsigned int */
2698
static int sample_conv_wt6(const struct arg *arg_p, struct sample *smp, void *private)
2699
0
{
2700
0
  smp->data.u.sint = hash_wt6(smp->data.u.str.area,
2701
0
            smp->data.u.str.data);
2702
0
  if (arg_p->data.sint)
2703
0
    smp->data.u.sint = full_hash(smp->data.u.sint);
2704
0
  smp->data.type = SMP_T_SINT;
2705
0
  return 1;
2706
0
}
2707
2708
/* hashes the binary input into a 32-bit unsigned int using xxh.
2709
 * The seed of the hash defaults to 0 but can be changd in argument 1.
2710
 */
2711
static int sample_conv_xxh32(const struct arg *arg_p, struct sample *smp, void *private)
2712
0
{
2713
0
  unsigned int seed;
2714
2715
0
  if (arg_p->data.sint)
2716
0
    seed = arg_p->data.sint;
2717
0
  else
2718
0
    seed = 0;
2719
0
  smp->data.u.sint = XXH32(smp->data.u.str.area, smp->data.u.str.data,
2720
0
         seed);
2721
0
  smp->data.type = SMP_T_SINT;
2722
0
  return 1;
2723
0
}
2724
2725
/* hashes the binary input into a 64-bit unsigned int using xxh.
2726
 * In fact, the function returns a 64 bit unsigned, but the sample
2727
 * storage of haproxy only proposes 64-bits signed, so the value is
2728
 * cast as signed. This cast doesn't impact the hash repartition.
2729
 * The seed of the hash defaults to 0 but can be changd in argument 1.
2730
 */
2731
static int sample_conv_xxh64(const struct arg *arg_p, struct sample *smp, void *private)
2732
0
{
2733
0
  unsigned long long int seed;
2734
2735
0
  if (arg_p->data.sint)
2736
0
    seed = (unsigned long long int)arg_p->data.sint;
2737
0
  else
2738
0
    seed = 0;
2739
0
  smp->data.u.sint = (long long int)XXH64(smp->data.u.str.area,
2740
0
            smp->data.u.str.data, seed);
2741
0
  smp->data.type = SMP_T_SINT;
2742
0
  return 1;
2743
0
}
2744
2745
static int sample_conv_xxh3(const struct arg *arg_p, struct sample *smp, void *private)
2746
0
{
2747
0
  unsigned long long int seed;
2748
2749
0
  if (arg_p->data.sint)
2750
0
    seed = (unsigned long long int)arg_p->data.sint;
2751
0
  else
2752
0
    seed = 0;
2753
0
  smp->data.u.sint = (long long int)XXH3(smp->data.u.str.area,
2754
0
                                         smp->data.u.str.data, seed);
2755
0
  smp->data.type = SMP_T_SINT;
2756
0
  return 1;
2757
0
}
2758
2759
/* hashes the binary input into a 32-bit unsigned int */
2760
static int sample_conv_crc32(const struct arg *arg_p, struct sample *smp, void *private)
2761
0
{
2762
0
  smp->data.u.sint = hash_crc32(smp->data.u.str.area,
2763
0
              smp->data.u.str.data);
2764
0
  if (arg_p->data.sint)
2765
0
    smp->data.u.sint = full_hash(smp->data.u.sint);
2766
0
  smp->data.type = SMP_T_SINT;
2767
0
  return 1;
2768
0
}
2769
2770
/* hashes the binary input into crc32c (RFC4960, Appendix B [8].) */
2771
static int sample_conv_crc32c(const struct arg *arg_p, struct sample *smp, void *private)
2772
0
{
2773
0
  smp->data.u.sint = hash_crc32c(smp->data.u.str.area,
2774
0
               smp->data.u.str.data);
2775
0
  if (arg_p->data.sint)
2776
0
    smp->data.u.sint = full_hash(smp->data.u.sint);
2777
0
  smp->data.type = SMP_T_SINT;
2778
0
  return 1;
2779
0
}
2780
2781
/* This function escape special json characters. The returned string can be
2782
 * safely set between two '"' and used as json string. The json string is
2783
 * defined like this:
2784
 *
2785
 *    any Unicode character except '"' or '\' or control character
2786
 *    \", \\, \/, \b, \f, \n, \r, \t, \u + four-hex-digits
2787
 *
2788
 * The enum input_type contain all the allowed mode for decoding the input
2789
 * string.
2790
 */
2791
enum input_type {
2792
  IT_ASCII = 0,
2793
  IT_UTF8,
2794
  IT_UTF8S,
2795
  IT_UTF8P,
2796
  IT_UTF8PS,
2797
};
2798
2799
static int sample_conv_json_check(struct arg *arg, struct sample_conv *conv,
2800
                                  const char *file, int line, char **err)
2801
0
{
2802
0
  enum input_type type;
2803
2804
0
  if (strcmp(arg->data.str.area, "") == 0)
2805
0
    type = IT_ASCII;
2806
0
  else if (strcmp(arg->data.str.area, "ascii") == 0)
2807
0
    type = IT_ASCII;
2808
0
  else if (strcmp(arg->data.str.area, "utf8") == 0)
2809
0
    type = IT_UTF8;
2810
0
  else if (strcmp(arg->data.str.area, "utf8s") == 0)
2811
0
    type = IT_UTF8S;
2812
0
  else if (strcmp(arg->data.str.area, "utf8p") == 0)
2813
0
    type = IT_UTF8P;
2814
0
  else if (strcmp(arg->data.str.area, "utf8ps") == 0)
2815
0
    type = IT_UTF8PS;
2816
0
  else {
2817
0
    memprintf(err, "Unexpected input code type. "
2818
0
        "Allowed value are 'ascii', 'utf8', 'utf8s', 'utf8p' and 'utf8ps'");
2819
0
    return 0;
2820
0
  }
2821
2822
0
  chunk_destroy(&arg->data.str);
2823
0
  arg->type = ARGT_SINT;
2824
0
  arg->data.sint = type;
2825
0
  return 1;
2826
0
}
2827
2828
static int sample_conv_json(const struct arg *arg_p, struct sample *smp, void *private)
2829
0
{
2830
0
  struct buffer *temp;
2831
0
  char _str[7]; /* \u + 4 hex digit + null char for sprintf. */
2832
0
  const char *str;
2833
0
  int len;
2834
0
  enum input_type input_type = IT_ASCII;
2835
0
  unsigned int c;
2836
0
  unsigned int ret;
2837
0
  char *p;
2838
2839
0
  input_type = arg_p->data.sint;
2840
2841
0
  temp = get_best_trash_chunk(&smp->data.u.str, smp->data.u.str.size);
2842
0
  if (!temp)
2843
0
    return 0;
2844
0
  temp->data = 0;
2845
2846
0
  p = smp->data.u.str.area;
2847
0
  while (p < smp->data.u.str.area + smp->data.u.str.data) {
2848
2849
0
    if (input_type == IT_ASCII) {
2850
      /* Read input as ASCII. */
2851
0
      c = *(unsigned char *)p;
2852
0
      p++;
2853
0
    }
2854
0
    else {
2855
      /* Read input as UTF8. */
2856
0
      ret = utf8_next(p,
2857
0
          smp->data.u.str.data - ( p - smp->data.u.str.area),
2858
0
          &c);
2859
0
      p += utf8_return_length(ret);
2860
2861
0
      if (input_type == IT_UTF8 && utf8_return_code(ret) != UTF8_CODE_OK)
2862
0
          return 0;
2863
0
      if (input_type == IT_UTF8S && utf8_return_code(ret) != UTF8_CODE_OK)
2864
0
          continue;
2865
0
      if (input_type == IT_UTF8P && utf8_return_code(ret) & (UTF8_CODE_INVRANGE|UTF8_CODE_BADSEQ))
2866
0
          return 0;
2867
0
      if (input_type == IT_UTF8PS && utf8_return_code(ret) & (UTF8_CODE_INVRANGE|UTF8_CODE_BADSEQ))
2868
0
          continue;
2869
2870
      /* Check too big values. */
2871
0
      if ((unsigned int)c > 0xffff) {
2872
0
        if (input_type == IT_UTF8 || input_type == IT_UTF8P)
2873
0
          return 0;
2874
0
        continue;
2875
0
      }
2876
0
    }
2877
2878
    /* Convert character. */
2879
0
    if (c == '"') {
2880
0
      len = 2;
2881
0
      str = "\\\"";
2882
0
    }
2883
0
    else if (c == '\\') {
2884
0
      len = 2;
2885
0
      str = "\\\\";
2886
0
    }
2887
0
    else if (c == '/') {
2888
0
      len = 2;
2889
0
      str = "\\/";
2890
0
    }
2891
0
    else if (c == '\b') {
2892
0
      len = 2;
2893
0
      str = "\\b";
2894
0
    }
2895
0
    else if (c == '\f') {
2896
0
      len = 2;
2897
0
      str = "\\f";
2898
0
    }
2899
0
    else if (c == '\r') {
2900
0
      len = 2;
2901
0
      str = "\\r";
2902
0
    }
2903
0
    else if (c == '\n') {
2904
0
      len = 2;
2905
0
      str = "\\n";
2906
0
    }
2907
0
    else if (c == '\t') {
2908
0
      len = 2;
2909
0
      str = "\\t";
2910
0
    }
2911
0
    else if (c > 0xff || !isprint((unsigned char)c)) {
2912
      /* isprint generate a segfault if c is too big. The man says that
2913
       * c must have the value of an unsigned char or EOF.
2914
       */
2915
0
      len = 6;
2916
0
      _str[0] = '\\';
2917
0
      _str[1] = 'u';
2918
0
      snprintf(&_str[2], 5, "%04x", (unsigned short)c);
2919
0
      str = _str;
2920
0
    }
2921
0
    else {
2922
0
      len = 1;
2923
0
      _str[0] = c;
2924
0
      str = _str;
2925
0
    }
2926
2927
    /* Check length */
2928
0
    if (temp->data + len > temp->size)
2929
0
      return 0;
2930
2931
    /* Copy string. */
2932
0
    memcpy(temp->area + temp->data, str, len);
2933
0
    temp->data += len;
2934
0
  }
2935
2936
0
  smp->flags &= ~SMP_F_CONST;
2937
0
  smp->data.u.str = *temp;
2938
0
  smp->data.type = SMP_T_STR;
2939
2940
0
  return 1;
2941
0
}
2942
2943
/* This sample function is designed to extract some bytes from an input buffer.
2944
 * First arg is the offset.
2945
 * Optional second arg is the length to truncate */
2946
static int sample_conv_bytes(const struct arg *arg_p, struct sample *smp, void *private)
2947
0
{
2948
0
  struct sample smp_arg0, smp_arg1;
2949
0
  long long start_idx, length;
2950
2951
  // determine the start_idx and length of the output
2952
0
  smp_set_owner(&smp_arg0, smp->px, smp->sess, smp->strm, smp->opt);
2953
0
  if (!sample_conv_var2smp_sint(&arg_p[0], &smp_arg0) || smp_arg0.data.u.sint < 0) {
2954
    /* invalid or negative value */
2955
0
    goto fail;
2956
0
  }
2957
2958
0
  if (smp_arg0.data.u.sint >= smp->data.u.str.data) {
2959
    // arg0 >= the input length
2960
0
    if (smp->opt & SMP_OPT_FINAL) {
2961
      // empty output value on final smp
2962
0
      smp->data.u.str.data = 0;
2963
0
      goto end;
2964
0
    }
2965
0
    goto wait;
2966
0
  }
2967
0
  start_idx = smp_arg0.data.u.sint;
2968
2969
  // length comes from arg1 if present, otherwise it's the remaining length
2970
0
  length = smp->data.u.str.data - start_idx;
2971
0
  if (arg_p[1].type != ARGT_STOP) {
2972
0
    smp_set_owner(&smp_arg1, smp->px, smp->sess, smp->strm, smp->opt);
2973
0
    if (!sample_conv_var2smp_sint(&arg_p[1], &smp_arg1) || smp_arg1.data.u.sint < 0) {
2974
      // invalid or negative value
2975
0
      goto fail;
2976
0
    }
2977
2978
0
    if (smp_arg1.data.u.sint > (smp->data.u.str.data - start_idx)) {
2979
      // arg1 value is greater than the remaining length
2980
0
      if (smp->opt & SMP_OPT_FINAL) {
2981
        // truncate to remaining length
2982
0
        length = smp->data.u.str.data - start_idx;
2983
0
        goto end;
2984
0
      }
2985
0
      goto wait;
2986
0
    }
2987
0
    length = smp_arg1.data.u.sint;
2988
0
  }
2989
2990
  // update the output using the start_idx and length
2991
0
  smp->data.u.str.area += start_idx;
2992
0
  smp->data.u.str.data = length;
2993
2994
0
  end:
2995
0
  return 1;
2996
2997
0
  fail:
2998
0
  smp->flags &= ~SMP_F_MAY_CHANGE;
2999
0
  wait:
3000
0
  smp->data.u.str.data = 0;
3001
0
  return 0;
3002
0
}
3003
3004
static int sample_conv_field_check(struct arg *args, struct sample_conv *conv,
3005
                                  const char *file, int line, char **err)
3006
0
{
3007
0
  struct arg *arg = args;
3008
3009
0
  if (arg->type != ARGT_SINT) {
3010
0
    memprintf(err, "Unexpected arg type");
3011
0
    return 0;
3012
0
  }
3013
3014
0
  if (!arg->data.sint) {
3015
0
    memprintf(err, "Unexpected value 0 for index");
3016
0
    return 0;
3017
0
  }
3018
3019
0
  arg++;
3020
3021
0
  if (arg->type != ARGT_STR) {
3022
0
    memprintf(err, "Unexpected arg type");
3023
0
    return 0;
3024
0
  }
3025
3026
0
  if (!arg->data.str.data) {
3027
0
    memprintf(err, "Empty separators list");
3028
0
    return 0;
3029
0
  }
3030
3031
0
  return 1;
3032
0
}
3033
3034
/* This sample function is designed to a return selected part of a string (field).
3035
 * First arg is the index of the field (start at 1)
3036
 * Second arg is a char list of separators (type string)
3037
 */
3038
static int sample_conv_field(const struct arg *arg_p, struct sample *smp, void *private)
3039
0
{
3040
0
  int field;
3041
0
  char *start, *end;
3042
0
  int i;
3043
0
  int count = (arg_p[2].type == ARGT_SINT) ? arg_p[2].data.sint : 1;
3044
3045
0
  if (!arg_p[0].data.sint)
3046
0
    return 0;
3047
3048
0
  if (arg_p[0].data.sint < 0) {
3049
0
    field = -1;
3050
0
    end = start = smp->data.u.str.area + smp->data.u.str.data;
3051
0
    while (start > smp->data.u.str.area) {
3052
0
      for (i = 0 ; i < arg_p[1].data.str.data; i++) {
3053
0
        if (*(start-1) == arg_p[1].data.str.area[i]) {
3054
0
          if (field == arg_p[0].data.sint) {
3055
0
            if (count == 1)
3056
0
              goto found;
3057
0
            else if (count > 1)
3058
0
              count--;
3059
0
          } else {
3060
0
            end = start-1;
3061
0
            field--;
3062
0
          }
3063
0
          break;
3064
0
        }
3065
0
      }
3066
0
      start--;
3067
0
    }
3068
0
  } else {
3069
0
    field = 1;
3070
0
    end = start = smp->data.u.str.area;
3071
0
    while (end - smp->data.u.str.area < smp->data.u.str.data) {
3072
0
      for (i = 0 ; i < arg_p[1].data.str.data; i++) {
3073
0
        if (*end == arg_p[1].data.str.area[i]) {
3074
0
          if (field == arg_p[0].data.sint) {
3075
0
            if (count == 1)
3076
0
              goto found;
3077
0
            else if (count > 1)
3078
0
              count--;
3079
0
          } else {
3080
0
            start = end+1;
3081
0
            field++;
3082
0
          }
3083
0
          break;
3084
0
        }
3085
0
      }
3086
0
      end++;
3087
0
    }
3088
0
  }
3089
3090
  /* Field not found */
3091
0
  if (field != arg_p[0].data.sint) {
3092
0
    smp->data.u.str.data = 0;
3093
0
    return 0;
3094
0
  }
3095
0
found:
3096
0
  smp->data.u.str.data = end - start;
3097
  /* If ret string is len 0, no need to
3098
           change pointers or to update size */
3099
0
  if (!smp->data.u.str.data)
3100
0
    return 1;
3101
3102
  /* Compute remaining size if needed
3103
           Note: smp->data.u.str.size cannot be set to 0 */
3104
0
  if (smp->data.u.str.size)
3105
0
    smp->data.u.str.size -= start - smp->data.u.str.area;
3106
3107
0
  smp->data.u.str.area = start;
3108
3109
0
  return 1;
3110
0
}
3111
3112
/* This sample function is designed to return a word from a string.
3113
 * First arg is the index of the word (start at 1)
3114
 * Second arg is a char list of words separators (type string)
3115
 */
3116
static int sample_conv_word(const struct arg *arg_p, struct sample *smp, void *private)
3117
0
{
3118
0
  int word;
3119
0
  char *start, *end;
3120
0
  int i, issep, inword;
3121
0
  int count = (arg_p[2].type == ARGT_SINT) ? arg_p[2].data.sint : 1;
3122
3123
0
  if (!arg_p[0].data.sint)
3124
0
    return 0;
3125
3126
0
  word = 0;
3127
0
  inword = 0;
3128
0
  if (arg_p[0].data.sint < 0) {
3129
0
    end = start = smp->data.u.str.area + smp->data.u.str.data;
3130
0
    while (start > smp->data.u.str.area) {
3131
0
      issep = 0;
3132
0
      for (i = 0 ; i < arg_p[1].data.str.data; i++) {
3133
0
        if (*(start-1) == arg_p[1].data.str.area[i]) {
3134
0
          issep = 1;
3135
0
          break;
3136
0
        }
3137
0
      }
3138
0
      if (!inword) {
3139
0
        if (!issep) {
3140
0
          if (word != arg_p[0].data.sint) {
3141
0
            word--;
3142
0
            end = start;
3143
0
          }
3144
0
          inword = 1;
3145
0
        }
3146
0
      }
3147
0
      else if (issep) {
3148
0
        if (word == arg_p[0].data.sint) {
3149
0
          if (count == 1)
3150
0
            goto found;
3151
0
          else if (count > 1)
3152
0
            count--;
3153
0
        }
3154
0
        inword = 0;
3155
0
      }
3156
0
      start--;
3157
0
    }
3158
0
  } else {
3159
0
    end = start = smp->data.u.str.area;
3160
0
    while (end - smp->data.u.str.area < smp->data.u.str.data) {
3161
0
      issep = 0;
3162
0
      for (i = 0 ; i < arg_p[1].data.str.data; i++) {
3163
0
        if (*end == arg_p[1].data.str.area[i]) {
3164
0
          issep = 1;
3165
0
          break;
3166
0
        }
3167
0
      }
3168
0
      if (!inword) {
3169
0
        if (!issep) {
3170
0
          if (word != arg_p[0].data.sint) {
3171
0
            word++;
3172
0
            start = end;
3173
0
          }
3174
0
          inword = 1;
3175
0
        }
3176
0
      }
3177
0
      else if (issep) {
3178
0
        if (word == arg_p[0].data.sint) {
3179
0
          if (count == 1)
3180
0
            goto found;
3181
0
          else if (count > 1)
3182
0
            count--;
3183
0
        }
3184
0
        inword = 0;
3185
0
      }
3186
0
      end++;
3187
0
    }
3188
0
  }
3189
3190
  /* Field not found */
3191
0
  if (word != arg_p[0].data.sint) {
3192
0
    smp->data.u.str.data = 0;
3193
0
    return 0;
3194
0
  }
3195
0
found:
3196
0
  smp->data.u.str.data = end - start;
3197
  /* If ret string is len 0, no need to
3198
           change pointers or to update size */
3199
0
  if (!smp->data.u.str.data)
3200
0
    return 1;
3201
3202
3203
  /* Compute remaining size if needed
3204
           Note: smp->data.u.str.size cannot be set to 0 */
3205
0
  if (smp->data.u.str.size)
3206
0
    smp->data.u.str.size -= start - smp->data.u.str.area;
3207
3208
0
  smp->data.u.str.area = start;
3209
3210
0
  return 1;
3211
0
}
3212
3213
static int sample_conv_param_check(struct arg *arg, struct sample_conv *conv,
3214
                                   const char *file, int line, char **err)
3215
0
{
3216
0
  if (arg[1].type == ARGT_STR && arg[1].data.str.data != 1) {
3217
0
    memprintf(err, "Delimiter must be exactly 1 character.");
3218
0
    return 0;
3219
0
  }
3220
3221
0
  return 1;
3222
0
}
3223
3224
static int sample_conv_param(const struct arg *arg_p, struct sample *smp, void *private)
3225
0
{
3226
0
  char *pos, *end, *pend, *equal;
3227
0
  char delim = '&';
3228
0
  const char *name = arg_p[0].data.str.area;
3229
0
  size_t name_l = arg_p[0].data.str.data;
3230
3231
0
  if (arg_p[1].type == ARGT_STR)
3232
0
    delim = *arg_p[1].data.str.area;
3233
3234
0
  pos = smp->data.u.str.area;
3235
0
  end = pos + smp->data.u.str.data;
3236
0
  while (pos < end) {
3237
0
    equal = pos + name_l;
3238
    /* Parameter not found */
3239
0
    if (equal > end)
3240
0
      break;
3241
3242
0
    if (equal == end || *equal == delim) {
3243
0
      if (memcmp(pos, name, name_l) == 0) {
3244
        /* input contains parameter, but no value is supplied */
3245
0
        smp->data.u.str.data = 0;
3246
0
        return 1;
3247
0
      }
3248
0
      pos = equal + 1;
3249
0
      continue;
3250
0
    }
3251
3252
0
    if (*equal == '=' && memcmp(pos, name, name_l) == 0) {
3253
0
      pos = equal + 1;
3254
0
      pend = memchr(pos, delim, end - pos);
3255
0
      if (pend == NULL)
3256
0
        pend = end;
3257
3258
0
      if (smp->data.u.str.size)
3259
0
        smp->data.u.str.size -= pos - smp->data.u.str.area;
3260
0
      smp->data.u.str.area = pos;
3261
0
      smp->data.u.str.data = pend - pos;
3262
0
      return 1;
3263
0
    }
3264
    /* find the next delimiter and set position to character after that */
3265
0
    pos = memchr(pos, delim, end - pos);
3266
0
    if (pos == NULL)
3267
0
      pos = end;
3268
0
    else
3269
0
      pos++;
3270
0
  }
3271
  /* Parameter not found */
3272
0
  smp->data.u.str.data = 0;
3273
0
  return 0;
3274
0
}
3275
3276
static int sample_conv_regsub_check(struct arg *args, struct sample_conv *conv,
3277
                                    const char *file, int line, char **err)
3278
0
{
3279
0
  struct arg *arg = args;
3280
0
  char *p;
3281
0
  int len;
3282
3283
  /* arg0 is a regex, it uses type_flag for ICASE and global match */
3284
0
  arg[0].type_flags = 0;
3285
3286
0
  if (arg[2].type != ARGT_STR)
3287
0
    return 1;
3288
3289
0
  p = arg[2].data.str.area;
3290
0
  len = arg[2].data.str.data;
3291
0
  while (len) {
3292
0
    if (*p == 'i') {
3293
0
      arg[0].type_flags |= ARGF_REG_ICASE;
3294
0
    }
3295
0
    else if (*p == 'g') {
3296
0
      arg[0].type_flags |= ARGF_REG_GLOB;
3297
0
    }
3298
0
    else {
3299
0
      memprintf(err, "invalid regex flag '%c', only 'i' and 'g' are supported", *p);
3300
0
      return 0;
3301
0
    }
3302
0
    p++;
3303
0
    len--;
3304
0
  }
3305
0
  return 1;
3306
0
}
3307
3308
/* This sample function is designed to do the equivalent of s/match/replace/ on
3309
 * the input string. It applies a regex and restarts from the last matched
3310
 * location until nothing matches anymore. First arg is the regex to apply to
3311
 * the input string, second arg is the replacement expression.
3312
 */
3313
static int sample_conv_regsub(const struct arg *arg_p, struct sample *smp, void *private)
3314
0
{
3315
0
  char *start, *end;
3316
0
  struct my_regex *reg = arg_p[0].data.reg;
3317
0
  regmatch_t pmatch[MAX_MATCH];
3318
0
  struct buffer *trash = get_trash_chunk_sz(smp->data.u.str.data);
3319
0
  struct buffer *output;
3320
0
  int flag, max;
3321
0
  int found;
3322
3323
0
  if (!trash)
3324
0
    return 0;
3325
0
  start = smp->data.u.str.area;
3326
0
  end = start + smp->data.u.str.data;
3327
3328
0
  flag = 0;
3329
0
  while (1) {
3330
    /* check for last round which is used to copy remaining parts
3331
     * when not running in global replacement mode.
3332
     */
3333
0
    found = 0;
3334
0
    if ((arg_p[0].type_flags & ARGF_REG_GLOB) || !(flag & REG_NOTBOL)) {
3335
      /* Note: we can have start == end on empty strings or at the end */
3336
0
      found = regex_exec_match2(reg, start, end - start, MAX_MATCH, pmatch, flag);
3337
0
    }
3338
3339
0
    if (!found)
3340
0
      pmatch[0].rm_so = end - start;
3341
3342
    /* copy the heading non-matching part (which may also be the tail if nothing matches) */
3343
0
    max = trash->size - trash->data;
3344
0
    if (max && pmatch[0].rm_so > 0) {
3345
0
      if (max > pmatch[0].rm_so)
3346
0
        max = pmatch[0].rm_so;
3347
0
      memcpy(trash->area + trash->data, start, max);
3348
0
      trash->data += max;
3349
0
    }
3350
3351
0
    if (!found)
3352
0
      break;
3353
3354
0
    output = alloc_trash_chunk();
3355
0
    if (!output)
3356
0
      break;
3357
3358
0
    max = exp_replace(output->area, output->size, start, arg_p[1].data.str.area, pmatch);
3359
0
    if ((int)max < 0) {
3360
0
      free_trash_chunk(output);
3361
0
      break;
3362
0
    }
3363
0
    output->data = max;
3364
3365
    /* replace the matching part */
3366
0
    max = trash->size - trash->data;
3367
0
    if (max) {
3368
0
      if (max > output->data)
3369
0
        max = output->data;
3370
0
      memcpy(trash->area + trash->data,
3371
0
             output->area, max);
3372
0
      trash->data += max;
3373
0
    }
3374
3375
0
    free_trash_chunk(output);
3376
3377
    /* stop here if we're done with this string */
3378
0
    if (start >= end)
3379
0
      break;
3380
3381
    /* We have a special case for matches of length 0 (eg: "x*y*").
3382
     * These ones are considered to match in front of a character,
3383
     * so we have to copy that character and skip to the next one.
3384
     */
3385
0
    if (!pmatch[0].rm_eo) {
3386
0
      if (trash->data < trash->size)
3387
0
        trash->area[trash->data++] = start[pmatch[0].rm_eo];
3388
0
      pmatch[0].rm_eo++;
3389
0
    }
3390
3391
0
    start += pmatch[0].rm_eo;
3392
0
    flag |= REG_NOTBOL;
3393
0
  }
3394
3395
0
  smp->data.u.str = *trash;
3396
0
  return 1;
3397
0
}
3398
3399
/* This function check an operator entry. It expects a string.
3400
 * The string can be an integer or a variable name.
3401
 */
3402
static int check_operator(struct arg *args, struct sample_conv *conv,
3403
                          const char *file, int line, char **err)
3404
0
{
3405
0
  const char *str;
3406
0
  const char *end;
3407
0
  long long int i;
3408
3409
  /* Try to decode a variable. The 'err' variable is intentionnaly left
3410
   * NULL since the operators accept an integer as argument in which case
3411
   * vars_check_arg call will fail.
3412
   */
3413
0
  if (vars_check_arg(&args[0], NULL))
3414
0
    return 1;
3415
3416
  /* Try to convert an integer */
3417
0
  str = args[0].data.str.area;
3418
0
  end = str + strlen(str);
3419
0
  i = read_int64(&str, end);
3420
0
  if (*str != '\0') {
3421
0
    memprintf(err, "expects an integer or a variable name");
3422
0
    return 0;
3423
0
  }
3424
3425
0
  chunk_destroy(&args[0].data.str);
3426
0
  args[0].type = ARGT_SINT;
3427
0
  args[0].data.sint = i;
3428
0
  return 1;
3429
0
}
3430
3431
/* This function returns a sample struct filled with an arg content.
3432
 * If the arg contain an integer, the integer is returned in the
3433
 * sample. If the arg contains a variable descriptor, it returns the
3434
 * variable value.
3435
 *
3436
 * This function returns 0 if an error occurs, otherwise it returns 1.
3437
 */
3438
int sample_conv_var2smp_sint(const struct arg *arg, struct sample *smp)
3439
0
{
3440
0
  switch (arg->type) {
3441
0
  case ARGT_SINT:
3442
0
    smp->data.type = SMP_T_SINT;
3443
0
    smp->data.u.sint = arg->data.sint;
3444
0
    return 1;
3445
0
  case ARGT_VAR:
3446
0
    return sample_conv_var2smp(&arg->data.var, smp, SMP_T_SINT);
3447
0
  default:
3448
0
    return 0;
3449
0
  }
3450
0
}
3451
3452
/* Takes a SINT on input, applies a binary twos complement and returns the SINT
3453
 * result.
3454
 */
3455
static int sample_conv_binary_cpl(const struct arg *arg_p, struct sample *smp, void *private)
3456
0
{
3457
0
  smp->data.u.sint = ~smp->data.u.sint;
3458
0
  return 1;
3459
0
}
3460
3461
/* Takes a SINT on input, applies a binary "and" with the SINT directly in
3462
 * arg_p or in the variable described in arg_p, and returns the SINT result.
3463
 */
3464
static int sample_conv_binary_and(const struct arg *arg_p, struct sample *smp, void *private)
3465
0
{
3466
0
  struct sample tmp;
3467
3468
0
  smp_set_owner(&tmp, smp->px, smp->sess, smp->strm, smp->opt);
3469
0
  if (!sample_conv_var2smp_sint(arg_p, &tmp))
3470
0
    return 0;
3471
0
  smp->data.u.sint &= tmp.data.u.sint;
3472
0
  return 1;
3473
0
}
3474
3475
/* Takes a SINT on input, applies a binary "or" with the SINT directly in
3476
 * arg_p or in the variable described in arg_p, and returns the SINT result.
3477
 */
3478
static int sample_conv_binary_or(const struct arg *arg_p, struct sample *smp, void *private)
3479
0
{
3480
0
  struct sample tmp;
3481
3482
0
  smp_set_owner(&tmp, smp->px, smp->sess, smp->strm, smp->opt);
3483
0
  if (!sample_conv_var2smp_sint(arg_p, &tmp))
3484
0
    return 0;
3485
0
  smp->data.u.sint |= tmp.data.u.sint;
3486
0
  return 1;
3487
0
}
3488
3489
/* Takes a SINT on input, applies a binary "xor" with the SINT directly in
3490
 * arg_p or in the variable described in arg_p, and returns the SINT result.
3491
 */
3492
static int sample_conv_binary_xor(const struct arg *arg_p, struct sample *smp, void *private)
3493
0
{
3494
0
  struct sample tmp;
3495
3496
0
  smp_set_owner(&tmp, smp->px, smp->sess, smp->strm, smp->opt);
3497
0
  if (!sample_conv_var2smp_sint(arg_p, &tmp))
3498
0
    return 0;
3499
0
  smp->data.u.sint ^= tmp.data.u.sint;
3500
0
  return 1;
3501
0
}
3502
3503
static inline long long int arith_add(long long int a, long long int b)
3504
0
{
3505
  /* Prevent overflow and makes capped calculus.
3506
   * We must ensure that the check calculus doesn't
3507
   * exceed the signed 64 bits limits.
3508
   *
3509
   *        +----------+----------+
3510
   *        |   a<0    |   a>=0   |
3511
   * +------+----------+----------+
3512
   * | b<0  | MIN-a>b  | no check |
3513
   * +------+----------+----------+
3514
   * | b>=0 | no check | MAX-a<b  |
3515
   * +------+----------+----------+
3516
   */
3517
0
  if ((a ^ b) >= 0) {
3518
    /* signs are same. */
3519
0
    if (a < 0) {
3520
0
      if (LLONG_MIN - a > b)
3521
0
        return LLONG_MIN;
3522
0
    }
3523
0
    else if (LLONG_MAX - a < b)
3524
0
      return LLONG_MAX;
3525
0
  }
3526
0
  return a + b;
3527
0
}
3528
3529
/* Takes a SINT on input, applies an arithmetic "add" with the SINT directly in
3530
 * arg_p or in the variable described in arg_p, and returns the SINT result.
3531
 */
3532
static int sample_conv_arith_add(const struct arg *arg_p, struct sample *smp, void *private)
3533
0
{
3534
0
  struct sample tmp;
3535
3536
0
  smp_set_owner(&tmp, smp->px, smp->sess, smp->strm, smp->opt);
3537
0
  if (!sample_conv_var2smp_sint(arg_p, &tmp))
3538
0
    return 0;
3539
0
  smp->data.u.sint = arith_add(smp->data.u.sint, tmp.data.u.sint);
3540
0
  return 1;
3541
0
}
3542
3543
/* Takes a SINT on input, applies an arithmetic "sub" with the SINT directly in
3544
 * arg_p or in the variable described in arg_p, and returns the SINT result.
3545
 */
3546
static int sample_conv_arith_sub(const struct arg *arg_p,
3547
                                 struct sample *smp, void *private)
3548
0
{
3549
0
  struct sample tmp;
3550
3551
0
  smp_set_owner(&tmp, smp->px, smp->sess, smp->strm, smp->opt);
3552
0
  if (!sample_conv_var2smp_sint(arg_p, &tmp))
3553
0
    return 0;
3554
3555
  /* We cannot represent -LLONG_MIN because abs(LLONG_MIN) is greater
3556
   * than abs(LLONG_MAX). So, the following code use LLONG_MAX in place
3557
   * of -LLONG_MIN and correct the result.
3558
   */
3559
0
  if (tmp.data.u.sint == LLONG_MIN) {
3560
0
    smp->data.u.sint = arith_add(smp->data.u.sint, LLONG_MAX);
3561
0
    if (smp->data.u.sint < LLONG_MAX)
3562
0
      smp->data.u.sint++;
3563
0
    return 1;
3564
0
  }
3565
3566
  /* standard subtraction: we use the "add" function and negate
3567
   * the second operand.
3568
   */
3569
0
  smp->data.u.sint = arith_add(smp->data.u.sint, -tmp.data.u.sint);
3570
0
  return 1;
3571
0
}
3572
3573
/* Takes a SINT on input, applies an arithmetic "mul" with the SINT directly in
3574
 * arg_p or in the variable described in arg_p, and returns the SINT result.
3575
 * If the result makes an overflow, then the largest possible quantity is
3576
 * returned.
3577
 */
3578
static int sample_conv_arith_mul(const struct arg *arg_p,
3579
                                 struct sample *smp, void *private)
3580
0
{
3581
0
  struct sample tmp;
3582
0
  long long int c;
3583
3584
0
  smp_set_owner(&tmp, smp->px, smp->sess, smp->strm, smp->opt);
3585
0
  if (!sample_conv_var2smp_sint(arg_p, &tmp))
3586
0
    return 0;
3587
3588
  /* prevent divide by 0 during the check */
3589
0
  if (!smp->data.u.sint || !tmp.data.u.sint) {
3590
0
    smp->data.u.sint = 0;
3591
0
    return 1;
3592
0
  }
3593
3594
  /* The multiply between LLONG_MIN and -1 returns a
3595
   * "floating point exception".
3596
   */
3597
0
  if (smp->data.u.sint == LLONG_MIN && tmp.data.u.sint == -1) {
3598
0
    smp->data.u.sint = LLONG_MAX;
3599
0
    return 1;
3600
0
  }
3601
3602
  /* execute standard multiplication. */
3603
0
  c = smp->data.u.sint * tmp.data.u.sint;
3604
3605
  /* check for overflow and makes capped multiply. */
3606
0
  if (smp->data.u.sint != c / tmp.data.u.sint) {
3607
0
    if ((smp->data.u.sint < 0) == (tmp.data.u.sint < 0)) {
3608
0
      smp->data.u.sint = LLONG_MAX;
3609
0
      return 1;
3610
0
    }
3611
0
    smp->data.u.sint = LLONG_MIN;
3612
0
    return 1;
3613
0
  }
3614
0
  smp->data.u.sint = c;
3615
0
  return 1;
3616
0
}
3617
3618
/* Takes a SINT on input, applies an arithmetic "div" with the SINT directly in
3619
 * arg_p or in the variable described in arg_p, and returns the SINT result.
3620
 * If arg_p makes the result overflow, then the largest possible quantity is
3621
 * returned.
3622
 */
3623
static int sample_conv_arith_div(const struct arg *arg_p,
3624
                                 struct sample *smp, void *private)
3625
0
{
3626
0
  struct sample tmp;
3627
3628
0
  smp_set_owner(&tmp, smp->px, smp->sess, smp->strm, smp->opt);
3629
0
  if (!sample_conv_var2smp_sint(arg_p, &tmp))
3630
0
    return 0;
3631
3632
0
  if (tmp.data.u.sint) {
3633
    /* The divide between LLONG_MIN and -1 returns a
3634
     * "floating point exception".
3635
     */
3636
0
    if (smp->data.u.sint == LLONG_MIN && tmp.data.u.sint == -1) {
3637
0
      smp->data.u.sint = LLONG_MAX;
3638
0
      return 1;
3639
0
    }
3640
0
    smp->data.u.sint /= tmp.data.u.sint;
3641
0
    return 1;
3642
0
  }
3643
0
  smp->data.u.sint = LLONG_MAX;
3644
0
  return 1;
3645
0
}
3646
3647
/* Takes a SINT on input, applies an arithmetic "mod" with the SINT directly in
3648
 * arg_p or in the variable described in arg_p, and returns the SINT result.
3649
 * If arg_p makes the result overflow, then 0 is returned.
3650
 */
3651
static int sample_conv_arith_mod(const struct arg *arg_p,
3652
                                 struct sample *smp, void *private)
3653
0
{
3654
0
  struct sample tmp;
3655
3656
0
  smp_set_owner(&tmp, smp->px, smp->sess, smp->strm, smp->opt);
3657
0
  if (!sample_conv_var2smp_sint(arg_p, &tmp))
3658
0
    return 0;
3659
3660
0
  if (tmp.data.u.sint) {
3661
    /* The divide between LLONG_MIN and -1 returns a
3662
     * "floating point exception".
3663
     */
3664
0
    if (smp->data.u.sint == LLONG_MIN && tmp.data.u.sint == -1) {
3665
0
      smp->data.u.sint = 0;
3666
0
      return 1;
3667
0
    }
3668
0
    smp->data.u.sint %= tmp.data.u.sint;
3669
0
    return 1;
3670
0
  }
3671
0
  smp->data.u.sint = 0;
3672
0
  return 1;
3673
0
}
3674
3675
/* Takes an SINT on input, applies an arithmetic "neg" and returns the SINT
3676
 * result.
3677
 */
3678
static int sample_conv_arith_neg(const struct arg *arg_p,
3679
                                 struct sample *smp, void *private)
3680
0
{
3681
0
  if (smp->data.u.sint == LLONG_MIN)
3682
0
    smp->data.u.sint = LLONG_MAX;
3683
0
  else
3684
0
    smp->data.u.sint = -smp->data.u.sint;
3685
0
  return 1;
3686
0
}
3687
3688
/* Takes a SINT on input, returns true is the value is non-null, otherwise
3689
 * false. The output is a BOOL.
3690
 */
3691
static int sample_conv_arith_bool(const struct arg *arg_p,
3692
                                  struct sample *smp, void *private)
3693
0
{
3694
0
  smp->data.u.sint = !!smp->data.u.sint;
3695
0
  smp->data.type = SMP_T_BOOL;
3696
0
  return 1;
3697
0
}
3698
3699
/* Takes a SINT on input, returns false is the value is non-null, otherwise
3700
 * truee. The output is a BOOL.
3701
 */
3702
static int sample_conv_arith_not(const struct arg *arg_p,
3703
                                 struct sample *smp, void *private)
3704
0
{
3705
0
  smp->data.u.sint = !smp->data.u.sint;
3706
0
  smp->data.type = SMP_T_BOOL;
3707
0
  return 1;
3708
0
}
3709
3710
/* Takes a SINT on input, returns true is the value is odd, otherwise false.
3711
 * The output is a BOOL.
3712
 */
3713
static int sample_conv_arith_odd(const struct arg *arg_p,
3714
                                 struct sample *smp, void *private)
3715
0
{
3716
0
  smp->data.u.sint = smp->data.u.sint & 1;
3717
0
  smp->data.type = SMP_T_BOOL;
3718
0
  return 1;
3719
0
}
3720
3721
/* Takes a SINT on input, returns true is the value is even, otherwise false.
3722
 * The output is a BOOL.
3723
 */
3724
static int sample_conv_arith_even(const struct arg *arg_p,
3725
                                  struct sample *smp, void *private)
3726
0
{
3727
0
  smp->data.u.sint = !(smp->data.u.sint & 1);
3728
0
  smp->data.type = SMP_T_BOOL;
3729
0
  return 1;
3730
0
}
3731
3732
/* appends an optional const string, an optional variable contents and another
3733
 * optional const string to an existing string.
3734
 */
3735
static int sample_conv_concat(const struct arg *arg_p, struct sample *smp, void *private)
3736
0
{
3737
0
  struct buffer *trash;
3738
0
  struct sample tmp;
3739
0
  struct ist var = IST_NULL;
3740
0
  int max;
3741
3742
3743
0
  smp_set_owner(&tmp, smp->px, smp->sess, smp->strm, smp->opt);
3744
0
  if (arg_p[1].type == ARGT_VAR && vars_get_by_desc(&arg_p[1].data.var, &tmp, NULL) &&
3745
0
      (sample_casts[tmp.data.type][SMP_T_STR] == c_none ||
3746
0
       sample_casts[tmp.data.type][SMP_T_STR](&tmp))) {
3747
0
    var = ist2(b_orig(&tmp.data.u.str), b_data(&tmp.data.u.str));
3748
0
  }
3749
3750
0
  trash = alloc_best_trash_chunk(&smp->data.u.str,
3751
0
               smp->data.u.str.data + arg_p[0].data.str.data + istlen(var) + arg_p[2].data.str.data);
3752
0
  if (!trash)
3753
0
    return 0;
3754
3755
0
  trash->data = smp->data.u.str.data;
3756
0
  if (trash->data > trash->size - 1)
3757
0
    trash->data = trash->size - 1;
3758
3759
0
  memcpy(trash->area, smp->data.u.str.area, trash->data);
3760
0
  trash->area[trash->data] = 0;
3761
3762
  /* append first string */
3763
0
  max = arg_p[0].data.str.data;
3764
0
  if (max > trash->size - 1 - trash->data)
3765
0
    max = trash->size - 1 - trash->data;
3766
3767
0
  if (max) {
3768
0
    memcpy(trash->area + trash->data, arg_p[0].data.str.area, max);
3769
0
    trash->data += max;
3770
0
    trash->area[trash->data] = 0;
3771
0
  }
3772
3773
  /* append second string (variable) if it's found */
3774
0
  max = istlen(var);
3775
0
  if (max > trash->size - 1 - trash->data)
3776
0
    max = trash->size - 1 - trash->data;
3777
3778
0
  if (max) {
3779
0
    memcpy(trash->area + trash->data, istptr(var), max);
3780
0
    trash->data += max;
3781
0
    trash->area[trash->data] = 0;
3782
0
  }
3783
3784
  /* append third string */
3785
0
  max = arg_p[2].data.str.data;
3786
0
  if (max > trash->size - 1 - trash->data)
3787
0
    max = trash->size - 1 - trash->data;
3788
3789
0
  if (max) {
3790
0
    memcpy(trash->area + trash->data, arg_p[2].data.str.area, max);
3791
0
    trash->data += max;
3792
0
    trash->area[trash->data] = 0;
3793
0
  }
3794
3795
0
  smp->data.u.str = *trash;
3796
0
  smp->data.type = SMP_T_STR;
3797
0
  smp_dup(smp);
3798
0
  free_trash_chunk(trash);
3799
0
  return 1;
3800
0
}
3801
3802
/* This function checks the "concat" converter's arguments and extracts the
3803
 * variable name and its scope.
3804
 */
3805
static int smp_check_concat(struct arg *args, struct sample_conv *conv,
3806
                           const char *file, int line, char **err)
3807
0
{
3808
  /* Try to decode a variable. */
3809
0
  if (args[1].data.str.data > 0 && !vars_check_arg(&args[1], NULL)) {
3810
0
    memprintf(err, "failed to register variable name '%s'",
3811
0
        args[1].data.str.area);
3812
0
    return 0;
3813
0
  }
3814
0
  return 1;
3815
0
}
3816
3817
/* Append delimiter (only to a non empty input) followed by the optional
3818
 * variable contents concatenated with the optional suffix.
3819
 */
3820
static int sample_conv_add_item(const struct arg *arg_p, struct sample *smp, void *private)
3821
0
{
3822
0
  struct buffer *tmpbuf;
3823
0
  struct sample tmp;
3824
0
  struct ist var = IST_NULL;
3825
0
  size_t max;
3826
3827
  /* Check if variable is found and we can turn into a string. */
3828
0
  smp_set_owner(&tmp, smp->px, smp->sess, smp->strm, smp->opt);
3829
0
  if (arg_p[1].type == ARGT_VAR && vars_get_by_desc(&arg_p[1].data.var, &tmp, NULL) &&
3830
0
      (sample_casts[tmp.data.type][SMP_T_STR] == c_none ||
3831
0
       sample_casts[tmp.data.type][SMP_T_STR](&tmp))) {
3832
0
    var = ist2(b_orig(&tmp.data.u.str), b_data(&tmp.data.u.str));
3833
0
  }
3834
3835
0
  tmpbuf = alloc_best_trash_chunk(&smp->data.u.str,
3836
0
          smp->data.u.str.data + arg_p[0].data.str.data + istlen(var) + arg_p[2].data.str.data);
3837
0
  if (!tmpbuf)
3838
0
    return 0;
3839
3840
0
  tmpbuf->data = smp->data.u.str.data;
3841
0
  if (tmpbuf->data > tmpbuf->size - 1)
3842
0
    tmpbuf->data = tmpbuf->size - 1;
3843
3844
0
  memcpy(tmpbuf->area, smp->data.u.str.area, tmpbuf->data);
3845
0
  tmpbuf->area[tmpbuf->data] = 0;
3846
3847
  /* Append delimiter only if input is not empty and either
3848
   * the variable or the suffix are not empty
3849
   */
3850
0
  if (smp->data.u.str.data && ((istlen(var) && tmp.data.u.str.data) || arg_p[2].data.str.data)) {
3851
0
    max = arg_p[0].data.str.data;
3852
0
    if (max > tmpbuf->size - 1 - tmpbuf->data)
3853
0
      max = tmpbuf->size - 1 - tmpbuf->data;
3854
3855
0
    if (max) {
3856
0
      memcpy(tmpbuf->area + tmpbuf->data, arg_p[0].data.str.area, max);
3857
0
      tmpbuf->data += max;
3858
0
      tmpbuf->area[tmpbuf->data] = 0;
3859
0
    }
3860
0
  }
3861
3862
  /* Append variable contents if variable is found and turned into string. */
3863
0
  if (istlen(var)) {
3864
0
    max = istlen(var);
3865
0
    if (max > tmpbuf->size - 1 - tmpbuf->data)
3866
0
      max = tmpbuf->size - 1 - tmpbuf->data;
3867
3868
0
    if (max) {
3869
0
      memcpy(tmpbuf->area + tmpbuf->data, istptr(var), max);
3870
0
      tmpbuf->data += max;
3871
0
      tmpbuf->area[tmpbuf->data] = 0;
3872
0
    }
3873
0
  }
3874
3875
  /* Append optional suffix. */
3876
0
  max = arg_p[2].data.str.data;
3877
0
  if (max > tmpbuf->size - 1 - tmpbuf->data)
3878
0
    max = tmpbuf->size - 1 - tmpbuf->data;
3879
3880
0
  if (max) {
3881
0
    memcpy(tmpbuf->area + tmpbuf->data, arg_p[2].data.str.area, max);
3882
0
    tmpbuf->data += max;
3883
0
    tmpbuf->area[tmpbuf->data] = 0;
3884
0
  }
3885
3886
0
  smp->data.u.str = *tmpbuf;
3887
0
  smp->data.type = SMP_T_STR;
3888
0
  smp_dup(smp);
3889
0
  free_trash_chunk(tmpbuf);
3890
0
  return 1;
3891
0
}
3892
3893
/* Check the "add_item" converter's arguments and extracts the
3894
 * variable name and its scope.
3895
 */
3896
static int smp_check_add_item(struct arg *args, struct sample_conv *conv,
3897
                           const char *file, int line, char **err)
3898
0
{
3899
  /* Try to decode a variable. */
3900
0
  if (args[1].data.str.data > 0 && !vars_check_arg(&args[1], NULL)) {
3901
0
    memprintf(err, "failed to register variable name '%s'",
3902
0
        args[1].data.str.area);
3903
0
    return 0;
3904
0
  }
3905
3906
0
  if (args[1].data.str.data == 0 && args[2].data.str.data == 0) {
3907
0
    memprintf(err, "one of the optional arguments has to be nonempty");
3908
0
    return 0;
3909
0
  }
3910
3911
0
  return 1;
3912
0
}
3913
3914
/* Compares string with a variable containing a string. Return value
3915
 * is compatible with strcmp(3)'s return value.
3916
 */
3917
static int sample_conv_strcmp(const struct arg *arg_p, struct sample *smp, void *private)
3918
0
{
3919
0
  struct sample tmp;
3920
0
  int max, result;
3921
3922
0
  smp_set_owner(&tmp, smp->px, smp->sess, smp->strm, smp->opt);
3923
0
  if (arg_p[0].type != ARGT_VAR)
3924
0
    return 0;
3925
3926
0
  if (!sample_conv_var2smp(&arg_p[0].data.var, &tmp, SMP_T_STR))
3927
0
    return 0;
3928
3929
0
  max = MIN(smp->data.u.str.data, tmp.data.u.str.data);
3930
0
  result = strncmp(smp->data.u.str.area, tmp.data.u.str.area, max);
3931
0
  if (result == 0) {
3932
0
    if (smp->data.u.str.data != tmp.data.u.str.data) {
3933
0
      if (smp->data.u.str.data < tmp.data.u.str.data) {
3934
0
        result = -1;
3935
0
      }
3936
0
      else {
3937
0
        result = 1;
3938
0
      }
3939
0
    }
3940
0
  }
3941
3942
0
  smp->data.u.sint = result;
3943
0
  smp->data.type = SMP_T_SINT;
3944
0
  return 1;
3945
0
}
3946
/*
3947
 * This converter can takes a Host header value as defined by rfc9110#section-7.2
3948
 * Host = uri-host [ ":" port ] ;
3949
 * It returns the uri-host value in lowecase with the port stripped.
3950
 */
3951
static int sample_conv_host_only(const struct arg *arg_p, struct sample *smp, void *private)
3952
0
{
3953
  /* Working cases: hostname00, hostname00:80, 127.0.0.1, 127.0.0.1:80, [::1], [::1]:80 */
3954
0
  char *beg = smp->data.u.str.area;
3955
0
  char *end = smp->data.u.str.area + smp->data.u.str.data - 1;
3956
0
  char *p;
3957
3958
0
  for (p = end; p >= beg; p--) {
3959
0
    if (*p == ':' || *p == ']')
3960
0
      break;
3961
0
  }
3962
3963
0
  if (p >= beg && *p == ':')
3964
0
    smp->data.u.str.data = p - beg;
3965
  /* if no port part was found, the hostname is the whole string */
3966
3967
0
  smp->data.type = SMP_T_STR;
3968
3969
0
  return sample_conv_str2lower(arg_p, smp, NULL);
3970
0
}
3971
3972
/*
3973
 * This converter can takes a Host header value as defined by rfc9110#section-7.2
3974
 * Host = uri-host [ ":" port ] ;
3975
 * It returns the port value as a int.
3976
 */
3977
static int sample_conv_port_only(const struct arg *arg_p, struct sample *smp, void *private)
3978
0
{
3979
  /* Working cases: hostname00, hostname00:80, 127.0.0.1, 127.0.0.1:80, [::1], [::1]:80 */
3980
0
  char *beg = smp->data.u.str.area;
3981
0
  char *end = smp->data.u.str.area + smp->data.u.str.data - 1;
3982
0
  char *p;
3983
3984
0
  for (p = end; p >= beg; p--) {
3985
0
    if (*p == ':' || *p == ']')
3986
0
      break;
3987
0
  }
3988
3989
0
  smp->data.type = SMP_T_SINT;
3990
0
  if (p >= beg && *p == ':' && ++p <= end) {
3991
0
    smp->data.u.sint = strl2ui(p, smp->data.u.str.data + smp->data.u.str.area - p);
3992
0
  } else {
3993
0
    smp->data.u.sint = 0;
3994
0
  }
3995
0
  return 1;
3996
0
}
3997
3998
3999
/* Takes a boolean as input. Returns the first argument if that boolean is true and
4000
 * the second argument otherwise.
4001
 */
4002
static int sample_conv_iif(const struct arg *arg_p, struct sample *smp, void *private)
4003
0
{
4004
0
  smp->data.type = SMP_T_STR;
4005
0
  smp->flags |= SMP_F_CONST;
4006
4007
0
  if (smp->data.u.sint) {
4008
0
    smp->data.u.str.data = arg_p[0].data.str.data;
4009
0
    smp->data.u.str.area = arg_p[0].data.str.area;
4010
0
  }
4011
0
  else {
4012
0
    smp->data.u.str.data = arg_p[1].data.str.data;
4013
0
    smp->data.u.str.area = arg_p[1].data.str.area;
4014
0
  }
4015
4016
0
  return 1;
4017
0
}
4018
4019
enum {
4020
  WHEN_COND_STOPPING,
4021
  WHEN_COND_NORMAL,
4022
  WHEN_COND_ERROR,
4023
  WHEN_COND_FORWARDED,
4024
  WHEN_COND_TOAPPLET,
4025
  WHEN_COND_PROCESSED,
4026
  WHEN_COND_ACL,
4027
  WHEN_COND_CONDITIONS
4028
};
4029
4030
const char *when_cond_kw[WHEN_COND_CONDITIONS] = {
4031
  [WHEN_COND_STOPPING]    = "stopping",
4032
  [WHEN_COND_NORMAL]      = "normal",
4033
  [WHEN_COND_ERROR]       = "error",
4034
  [WHEN_COND_FORWARDED] = "forwarded",
4035
  [WHEN_COND_TOAPPLET]  = "toapplet",
4036
  [WHEN_COND_PROCESSED] = "processed",
4037
  [WHEN_COND_ACL]         = "acl",
4038
};
4039
4040
/* Evaluates a condition and decides whether or not to pass the input sample
4041
 * to the output. The purpose is to hide some info when certain conditions are
4042
 * (not) met. These conditions belong to a fixed list that can verify internal
4043
 * states (debug mode, too high load, reloading, server down, stream in error
4044
 * etc). The condition's sign is placed in arg_p[0].data.int. 0=direct, 1=inv.
4045
 * The condition keyword is in arg_p[1].data.int (WHEN_COND_*).
4046
 */
4047
static int sample_conv_when(const struct arg *arg_p, struct sample *smp, void *private)
4048
0
{
4049
0
  struct session *sess = smp->sess;
4050
0
  struct stream *strm = smp->strm;
4051
0
  int neg  = arg_p[0].data.sint;
4052
0
  int cond = arg_p[1].data.sint;
4053
0
  struct acl_sample *acl_sample;
4054
0
  int ret = 0;
4055
4056
0
  switch (cond) {
4057
0
  case WHEN_COND_STOPPING:
4058
0
    ret = !!stopping;
4059
0
    break;
4060
4061
0
  case WHEN_COND_NORMAL:
4062
0
    neg = !neg;
4063
0
    __fallthrough;
4064
4065
0
  case WHEN_COND_ERROR:
4066
0
    if (strm &&
4067
0
        ((strm->flags & SF_REDISP) ||
4068
0
         ((strm->flags & SF_ERR_MASK) > SF_ERR_LOCAL) ||
4069
0
         (((strm->flags & SF_ERR_MASK) == SF_ERR_NONE) && strm->conn_retries) ||
4070
0
         ((sess->fe->mode == PR_MODE_HTTP) && strm->txn.http && strm->txn.http->status >= 500)))
4071
0
      ret = 1;
4072
0
    break;
4073
4074
0
  case WHEN_COND_FORWARDED: // true if forwarded to a connection
4075
0
    ret = strm && !!sc_conn(strm->scb);
4076
0
    break;
4077
4078
0
  case WHEN_COND_TOAPPLET:  // true if handled as an applet
4079
0
    ret = strm && !!sc_appctx(strm->scb);
4080
0
    break;
4081
4082
0
  case WHEN_COND_PROCESSED: // true if forwarded or appctx
4083
0
    ret = strm && (sc_conn(strm->scb) || sc_appctx(strm->scb));
4084
0
    break;
4085
4086
0
  case WHEN_COND_ACL: // true if the ACL pointed to by args[2] evaluates to true
4087
0
    acl_sample = arg_p[2].data.ptr;
4088
0
    ret = acl_exec_cond(&acl_sample->cond, smp->px, smp->sess, strm, smp->opt) == ACL_TEST_PASS;
4089
0
    break;
4090
0
  }
4091
4092
0
  ret = !!ret ^ !!neg;
4093
0
  if (!ret) {
4094
    /* kill the sample */
4095
0
    return 0;
4096
0
  }
4097
4098
  /* pass the sample as-is */
4099
0
  return 1;
4100
0
}
4101
4102
/* checks and resolves the type of the argument passed to when().
4103
 * It supports an optional '!' to negate the condition, followed by
4104
 * a keyword among the list above. Note that we're purposely declaring
4105
 * one extra arg because the first one will be split into two.
4106
 */
4107
static int check_when_cond(struct arg *args, struct sample_conv *conv,
4108
                             const char *file, int line, char **err)
4109
0
{
4110
0
  struct acl_sample *acl_sample;
4111
0
  const char *kw;
4112
0
  int neg = 0;
4113
0
  int i;
4114
4115
0
  kw = args[0].data.str.area;
4116
0
  if (*kw == '!') {
4117
0
    kw++;
4118
0
    neg = 1;
4119
0
  }
4120
4121
0
  for (i = 0; i < WHEN_COND_CONDITIONS; i++) {
4122
0
    if (strcmp(kw, when_cond_kw[i]) == 0)
4123
0
      break;
4124
0
  }
4125
4126
0
  if (i == WHEN_COND_CONDITIONS) {
4127
0
    memprintf(err, "expects a supported keyword among {");
4128
0
    for (i = 0; i < WHEN_COND_CONDITIONS; i++)
4129
0
      memprintf(err, "%s%s%s", *err, when_cond_kw[i],  (i == WHEN_COND_CONDITIONS - 1) ? "}" : ",");
4130
0
    memprintf(err, "%s but got '%s'", *err, kw);
4131
0
    return 0;
4132
0
  }
4133
4134
0
  if (i == WHEN_COND_ACL) {
4135
0
    if (args[1].type != ARGT_STR || !*args[1].data.str.area) {
4136
0
      memprintf(err, "'acl' selector requires an extra argument with the ACL name");
4137
0
      return 0;
4138
0
    }
4139
4140
0
    if (!curproxy) {
4141
0
      memprintf(err, "'acl' selector may only be used in the context of a proxy");
4142
0
      return 0;
4143
0
    }
4144
4145
0
    acl_sample = calloc(1, sizeof(struct acl_sample) + sizeof(struct acl_term));
4146
0
    if (!acl_sample) {
4147
0
      memprintf(err, "not enough memory for 'acl' selector");
4148
0
      return 0;
4149
0
    }
4150
4151
0
    LIST_INIT(&acl_sample->suite.terms);
4152
0
    LIST_INIT(&acl_sample->cond.suites);
4153
0
    LIST_APPEND(&acl_sample->cond.suites, &acl_sample->suite.list);
4154
0
    LIST_APPEND(&acl_sample->suite.terms, &acl_sample->terms[0].list);
4155
0
    acl_sample->cond.val = ~0U; // the keyword is valid everywhere for now.
4156
4157
    /* build one term based on the ACL kw */
4158
0
    if (!(acl_sample->terms[0].acl = find_acl_by_name(args[1].data.str.area, &curproxy->acl)) &&
4159
0
        !(acl_sample->terms[0].acl = find_acl_default(args[1].data.str.area, &curproxy->acl, err, NULL, NULL, 0))) {
4160
0
      memprintf(err, "ACL '%s' not found", args[1].data.str.area);
4161
0
      free(acl_sample);
4162
0
      return 0;
4163
0
    }
4164
4165
0
    acl_sample->cond.use |= acl_sample->terms[0].acl->use;
4166
0
    acl_sample->cond.val &= acl_sample->terms[0].acl->val;
4167
4168
0
    args[2].type = ARGT_PTR;
4169
0
    args[2].unresolved = 0;
4170
0
    args[2].resolve_ptr = NULL;
4171
0
    args[2].data.ptr = acl_sample;
4172
0
  }
4173
4174
0
  chunk_destroy(&args[0].data.str);
4175
0
  if (args[1].type == ARGT_STR)
4176
0
    chunk_destroy(&args[1].data.str);
4177
4178
0
  if (args[2].type == ARGT_STR)
4179
0
    chunk_destroy(&args[2].data.str);
4180
4181
  // store condition
4182
0
  args[0].type = ARGT_SINT;
4183
0
  args[0].data.sint = neg; // '!' present
4184
4185
  // and keyword
4186
0
  args[1].type = ARGT_SINT;
4187
0
  args[1].data.sint = i;
4188
0
  return 1;
4189
0
}
4190
4191
0
#define GRPC_MSG_COMPRESS_FLAG_SZ 1 /* 1 byte */
4192
0
#define GRPC_MSG_LENGTH_SZ        4 /* 4 bytes */
4193
0
#define GRPC_MSG_HEADER_SZ        (GRPC_MSG_COMPRESS_FLAG_SZ + GRPC_MSG_LENGTH_SZ)
4194
4195
/*
4196
 * Extract the field value of an input binary sample. Takes a mandatory argument:
4197
 * the protocol buffers field identifier (dotted notation) internally represented
4198
 * as an array of unsigned integers and its size.
4199
 * Return 1 if the field was found, 0 if not.
4200
 */
4201
static int sample_conv_ungrpc(const struct arg *arg_p, struct sample *smp, void *private)
4202
0
{
4203
0
  unsigned char *pos;
4204
0
  size_t grpc_left;
4205
4206
0
  pos = (unsigned char *)smp->data.u.str.area;
4207
0
  grpc_left = smp->data.u.str.data;
4208
4209
0
  while (grpc_left > GRPC_MSG_HEADER_SZ) {
4210
0
    size_t grpc_msg_len, left;
4211
4212
0
    grpc_msg_len = left = ntohl(read_u32(pos + GRPC_MSG_COMPRESS_FLAG_SZ));
4213
4214
0
    pos += GRPC_MSG_HEADER_SZ;
4215
0
    grpc_left -= GRPC_MSG_HEADER_SZ;
4216
4217
0
    if (grpc_left < left)
4218
0
      return 0;
4219
4220
0
    if (protobuf_field_lookup(arg_p, smp, &pos, &left))
4221
0
      return 1;
4222
4223
0
    grpc_left -= grpc_msg_len;
4224
0
  }
4225
4226
0
  return 0;
4227
0
}
4228
4229
static int sample_conv_protobuf(const struct arg *arg_p, struct sample *smp, void *private)
4230
0
{
4231
0
  unsigned char *pos;
4232
0
  size_t left;
4233
4234
0
  pos = (unsigned char *)smp->data.u.str.area;
4235
0
  left = smp->data.u.str.data;
4236
4237
0
  return protobuf_field_lookup(arg_p, smp, &pos, &left);
4238
0
}
4239
4240
static int sample_conv_protobuf_check(struct arg *args, struct sample_conv *conv,
4241
                                      const char *file, int line, char **err)
4242
0
{
4243
0
  if (!args[1].type) {
4244
0
    args[1].type = ARGT_SINT;
4245
0
    args[1].data.sint = PBUF_T_BINARY;
4246
0
  }
4247
0
  else {
4248
0
    int pbuf_type;
4249
4250
0
    pbuf_type = protobuf_type(args[1].data.str.area);
4251
0
    if (pbuf_type == -1) {
4252
0
      memprintf(err, "Wrong protocol buffer type '%s'", args[1].data.str.area);
4253
0
      return 0;
4254
0
    }
4255
4256
0
    chunk_destroy(&args[1].data.str);
4257
0
    args[1].type = ARGT_SINT;
4258
0
    args[1].data.sint = pbuf_type;
4259
0
  }
4260
4261
0
  return 1;
4262
0
}
4263
4264
/*
4265
 * Extract the tag value of an input binary sample. Takes a mandatory argument:
4266
 * the FIX protocol tag identifier.
4267
 * Return 1 if the tag was found, 0 if not.
4268
 */
4269
static int sample_conv_fix_tag_value(const struct arg *arg_p, struct sample *smp, void *private)
4270
0
{
4271
0
  struct ist value;
4272
4273
0
  smp->flags &= ~SMP_F_MAY_CHANGE;
4274
0
  value = fix_tag_value(ist2(smp->data.u.str.area, smp->data.u.str.data),
4275
0
            arg_p[0].data.sint);
4276
0
  if (!istlen(value)) {
4277
0
    if (isttest(value)) {
4278
      /* value != IST_NULL, need more data */
4279
0
      smp->flags |= SMP_F_MAY_CHANGE;
4280
0
    }
4281
0
    return 0;
4282
0
  }
4283
4284
0
  smp->data.u.str = ist2buf(value);
4285
0
  smp->flags |= SMP_F_CONST;
4286
4287
0
  return 1;
4288
0
}
4289
4290
/* This function checks the "fix_tag_value" converter configuration.
4291
 * It expects a "known" (by HAProxy) tag name or ID.
4292
 * Tag string names are converted to their ID counterpart because this is the
4293
 * format they are sent over the wire.
4294
 */
4295
static int sample_conv_fix_value_check(struct arg *args, struct sample_conv *conv,
4296
               const char *file, int line, char **err)
4297
0
{
4298
0
  struct ist str;
4299
0
  unsigned int tag;
4300
4301
0
  str = ist2(args[0].data.str.area, args[0].data.str.data);
4302
0
  tag = fix_tagid(str);
4303
0
  if (!tag) {
4304
0
    memprintf(err, "Unknown FIX tag name '%s'", args[0].data.str.area);
4305
0
    return 0;
4306
0
  }
4307
4308
0
  chunk_destroy(&args[0].data.str);
4309
0
  args[0].type = ARGT_SINT;
4310
0
  args[0].data.sint = tag;
4311
4312
0
  return 1;
4313
0
}
4314
4315
/*
4316
 * Checks that a buffer contains a valid FIX message
4317
 *
4318
 * Return 1 if the check could be run, 0 if not.
4319
 * The result of the analyse itself is stored in <smp> as a boolean
4320
 */
4321
static int sample_conv_fix_is_valid(const struct arg *arg_p, struct sample *smp, void *private)
4322
0
{
4323
0
  struct ist msg;
4324
4325
0
  msg = ist2(smp->data.u.str.area, smp->data.u.str.data);
4326
4327
0
  smp->flags &= ~SMP_F_MAY_CHANGE;
4328
0
  switch (fix_validate_message(msg)) {
4329
0
  case FIX_VALID_MESSAGE:
4330
0
    smp->data.type = SMP_T_BOOL;
4331
0
    smp->data.u.sint = 1;
4332
0
    return 1;
4333
0
  case FIX_NEED_MORE_DATA:
4334
0
    smp->flags |= SMP_F_MAY_CHANGE;
4335
0
    return 0;
4336
0
  case FIX_INVALID_MESSAGE:
4337
0
    smp->data.type = SMP_T_BOOL;
4338
0
    smp->data.u.sint = 0;
4339
0
    return 1;
4340
0
  }
4341
0
  return 0;
4342
0
}
4343
4344
/*
4345
 * Extract the field value of an input binary sample containing an MQTT packet.
4346
 * Takes 2 mandatory arguments:
4347
 * - packet type
4348
 * - field name
4349
 *
4350
 * return 1 if the field was found, 0 if not.
4351
 */
4352
static int sample_conv_mqtt_field_value(const struct arg *arg_p, struct sample *smp, void *private)
4353
0
{
4354
0
  struct ist pkt, value;
4355
0
  int type, fieldname_id;
4356
4357
0
  pkt = ist2(smp->data.u.str.area, smp->data.u.str.data);
4358
0
  type = arg_p[0].data.sint;
4359
0
  fieldname_id = arg_p[1].data.sint;
4360
4361
0
  smp->flags &= ~SMP_F_MAY_CHANGE;
4362
0
  value = mqtt_field_value(pkt, type, fieldname_id);
4363
0
  if (!istlen(value)) {
4364
0
    if (isttest(value)) {
4365
      /* value != IST_NULL, need more data */
4366
0
      smp->flags |= SMP_F_MAY_CHANGE;
4367
0
    }
4368
0
    return 0;
4369
0
  }
4370
4371
0
  smp->data.u.str = ist2buf(value);
4372
0
  smp->flags |= SMP_F_CONST;
4373
0
  return 1;
4374
0
}
4375
4376
/*
4377
 * this function checks the "mqtt_field_value" converter configuration.
4378
 * It expects a known packet type name or ID and a field name, in this order
4379
 *
4380
 * Args[0] will be turned into a MQTT_CPT_* value for direct matching when parsing
4381
 * a packet.
4382
 */
4383
static int sample_conv_mqtt_field_value_check(struct arg *args, struct sample_conv *conv,
4384
                const char *file, int line, char **err)
4385
0
{
4386
0
  int type, fieldname_id;
4387
4388
  /* check the MQTT packet type is valid */
4389
0
  type = mqtt_typeid(ist2(args[0].data.str.area, args[0].data.str.data));
4390
0
  if (type == MQTT_CPT_INVALID) {
4391
0
    memprintf(err, "Unknown MQTT type '%s'", args[0].data.str.area);
4392
0
    return 0;
4393
0
  }
4394
4395
  /* check the field name belongs to the MQTT packet type */
4396
0
  fieldname_id = mqtt_check_type_fieldname(type, ist2(args[1].data.str.area, args[1].data.str.data));
4397
0
  if (fieldname_id == MQTT_FN_INVALID) {
4398
0
    memprintf(err, "Unknown MQTT field name '%s' for packet type '%s'", args[1].data.str.area,
4399
0
        args[0].data.str.area);
4400
0
    return 0;
4401
0
  }
4402
4403
  /* save numeric counterparts of type and field name */
4404
0
  chunk_destroy(&args[0].data.str);
4405
0
  chunk_destroy(&args[1].data.str);
4406
0
  args[0].type = ARGT_SINT;
4407
0
  args[0].data.sint = type;
4408
0
  args[1].type = ARGT_SINT;
4409
0
  args[1].data.sint = fieldname_id;
4410
4411
0
  return 1;
4412
0
}
4413
4414
/*
4415
 * Checks that <smp> contains a valid MQTT message
4416
 *
4417
 * The function returns 1 if the check was run to its end, 0 otherwise.
4418
 * The result of the analyse itself is stored in <smp> as a boolean.
4419
 */
4420
static int sample_conv_mqtt_is_valid(const struct arg *arg_p, struct sample *smp, void *private)
4421
0
{
4422
0
  struct ist msg;
4423
4424
0
  msg = ist2(smp->data.u.str.area, smp->data.u.str.data);
4425
4426
0
  smp->flags &= ~SMP_F_MAY_CHANGE;
4427
0
  switch (mqtt_validate_message(msg, NULL)) {
4428
0
  case FIX_VALID_MESSAGE:
4429
0
    smp->data.type = SMP_T_BOOL;
4430
0
    smp->data.u.sint = 1;
4431
0
    return 1;
4432
0
  case FIX_NEED_MORE_DATA:
4433
0
    smp->flags |= SMP_F_MAY_CHANGE;
4434
0
    return 0;
4435
0
  case FIX_INVALID_MESSAGE:
4436
0
    smp->data.type = SMP_T_BOOL;
4437
0
    smp->data.u.sint = 0;
4438
0
    return 1;
4439
0
  }
4440
0
  return 0;
4441
0
}
4442
4443
/* This function checks the "strcmp" converter's arguments and extracts the
4444
 * variable name and its scope.
4445
 */
4446
static int smp_check_strcmp(struct arg *args, struct sample_conv *conv,
4447
                           const char *file, int line, char **err)
4448
0
{
4449
0
  if (!args[0].data.str.data) {
4450
0
    memprintf(err, "missing variable name");
4451
0
    return 0;
4452
0
  }
4453
4454
  /* Try to decode a variable. */
4455
0
  if (vars_check_arg(&args[0], NULL))
4456
0
    return 1;
4457
4458
0
  memprintf(err, "failed to register variable name '%s'",
4459
0
      args[0].data.str.area);
4460
0
  return 0;
4461
0
}
4462
4463
/**/
4464
static int sample_conv_htonl(const struct arg *arg_p, struct sample *smp, void *private)
4465
0
{
4466
0
  struct buffer *tmp;
4467
0
  uint32_t n;
4468
4469
0
  n = htonl((uint32_t)smp->data.u.sint);
4470
0
  tmp = get_trash_chunk();
4471
4472
0
  memcpy(b_head(tmp), &n, 4);
4473
0
  b_add(tmp, 4);
4474
4475
0
  smp->data.u.str = *tmp;
4476
0
  smp->data.type = SMP_T_BIN;
4477
0
  return 1;
4478
0
}
4479
4480
/**/
4481
static int sample_conv_cut_crlf(const struct arg *arg_p, struct sample *smp, void *private)
4482
0
{
4483
0
  char *p;
4484
0
  size_t l;
4485
4486
0
  p = smp->data.u.str.area;
4487
0
  for (l = 0; l < smp->data.u.str.data; l++) {
4488
0
    if (*(p+l) == '\r' || *(p+l) == '\n')
4489
0
      break;
4490
0
  }
4491
0
  smp->data.u.str.data = l;
4492
0
  return 1;
4493
0
}
4494
4495
/**/
4496
static int sample_conv_ltrim(const struct arg *arg_p, struct sample *smp, void *private)
4497
0
{
4498
0
  char *delimiters, *p;
4499
0
  size_t dlen, l;
4500
4501
0
  delimiters =  arg_p[0].data.str.area;
4502
0
  dlen = arg_p[0].data.str.data;
4503
4504
0
  l = smp->data.u.str.data;
4505
0
  p = smp->data.u.str.area;
4506
0
  while (l && memchr(delimiters, *p, dlen) != NULL) {
4507
0
    p++;
4508
0
    l--;
4509
0
  }
4510
4511
0
  smp->data.u.str.area = p;
4512
0
  smp->data.u.str.data = l;
4513
0
  return 1;
4514
0
}
4515
4516
/**/
4517
static int sample_conv_rtrim(const struct arg *arg_p, struct sample *smp, void *private)
4518
0
{
4519
0
  char *delimiters, *p;
4520
0
  size_t dlen, l;
4521
4522
0
  delimiters =  arg_p[0].data.str.area;
4523
0
  dlen = arg_p[0].data.str.data;
4524
4525
0
  l = smp->data.u.str.data;
4526
0
  p = smp->data.u.str.area + l - 1;
4527
0
  while (l && memchr(delimiters, *p, dlen) != NULL) {
4528
0
    p--;
4529
0
    l--;
4530
0
  }
4531
4532
0
  smp->data.u.str.data = l;
4533
0
  return 1;
4534
0
}
4535
4536
/* This function checks the "json_query" converter's arguments. */
4537
static int sample_check_json_query(struct arg *arg, struct sample_conv *conv,
4538
                           const char *file, int line, char **err)
4539
0
{
4540
0
  if (arg[0].data.str.data == 0) {
4541
0
    memprintf(err, "json_path must not be empty");
4542
0
    return 0;
4543
0
  }
4544
4545
0
  if (arg[1].data.str.data != 0) {
4546
0
    if (strcmp(arg[1].data.str.area, "int") != 0) {
4547
0
      memprintf(err, "output_type only supports \"int\" as argument");
4548
0
      return 0;
4549
0
    } else {
4550
0
      arg[1].type = ARGT_SINT;
4551
0
      arg[1].data.sint = 0;
4552
0
    }
4553
0
  }
4554
0
  return 1;
4555
0
}
4556
4557
/* Limit JSON integer values to the range [-(2**53)+1, (2**53)-1] as per
4558
 * the recommendation for interoperable integers in section 6 of RFC 7159.
4559
 */
4560
0
#define JSON_INT_MAX ((1LL << 53) - 1)
4561
0
#define JSON_INT_MIN (-JSON_INT_MAX)
4562
4563
/* This sample function get the value from a given json string.
4564
 * The mjson library is used to parse the JSON struct
4565
 */
4566
static int sample_conv_json_query(const struct arg *args, struct sample *smp, void *private)
4567
0
{
4568
0
  const char *token; /* holds the temporary string from mjson_find */
4569
0
  int token_size;    /* holds the length of <token> */
4570
4571
0
  enum mjson_tok token_type;
4572
4573
0
  token_type = mjson_find(smp->data.u.str.area, smp->data.u.str.data, args[0].data.str.area, &token, &token_size);
4574
4575
0
  switch (token_type) {
4576
0
    case MJSON_TOK_NUMBER:
4577
0
      if (args[1].type == ARGT_SINT) {
4578
0
        smp->data.u.sint = strtoll(token, NULL, 0);
4579
4580
0
        if (smp->data.u.sint < JSON_INT_MIN || smp->data.u.sint > JSON_INT_MAX)
4581
0
          return 0;
4582
4583
0
        smp->data.type = SMP_T_SINT;
4584
4585
0
        return 1;
4586
0
      } else {
4587
0
        struct buffer *trash = get_trash_chunk();
4588
0
        double double_val;
4589
4590
0
        if (mjson_get_number(smp->data.u.str.area, smp->data.u.str.data, args[0].data.str.area, &double_val) == 0)
4591
0
          return 0;
4592
4593
0
        trash->data = snprintf(trash->area,trash->size,"%g",double_val);
4594
0
        smp->data.u.str = *trash;
4595
0
        smp->data.type = SMP_T_STR;
4596
4597
0
        return 1;
4598
0
      }
4599
0
    case MJSON_TOK_TRUE:
4600
0
      smp->data.type = SMP_T_BOOL;
4601
0
      smp->data.u.sint = 1;
4602
4603
0
      return 1;
4604
0
    case MJSON_TOK_FALSE:
4605
0
      smp->data.type = SMP_T_BOOL;
4606
0
      smp->data.u.sint = 0;
4607
4608
0
      return 1;
4609
0
    case MJSON_TOK_STRING: {
4610
0
      struct buffer *trash = get_trash_chunk_sz(token_size);
4611
0
      int len;
4612
4613
0
      if (!trash)
4614
0
        return 0;
4615
0
      len = mjson_get_string(smp->data.u.str.area, smp->data.u.str.data, args[0].data.str.area, trash->area, trash->size);
4616
4617
0
      if (len == -1) {
4618
        /* invalid string */
4619
0
        return 0;
4620
0
      }
4621
4622
0
      trash->data = len;
4623
0
      smp->data.u.str = *trash;
4624
0
      smp->data.type = SMP_T_STR;
4625
4626
0
      return 1;
4627
0
    }
4628
0
               case MJSON_TOK_ARRAY: {
4629
0
           struct buffer *trash = get_trash_chunk_sz(token_size);
4630
4631
0
      if (!trash)
4632
0
        return 0;
4633
                       // We copy the complete array, including square brackets into the return buffer
4634
                       // result looks like: ["manage-account","manage-account-links","view-profile"]
4635
0
                       trash->data = b_putblk(trash, token, token_size);
4636
0
                       smp->data.u.str = *trash;
4637
0
                       smp->data.type = SMP_T_STR;
4638
0
                       return 1;
4639
0
               }
4640
0
    case MJSON_TOK_NULL:
4641
0
    case MJSON_TOK_OBJECT:
4642
      /* We cannot handle these. */
4643
0
      return 0;
4644
0
    case MJSON_TOK_INVALID:
4645
      /* Nothing matches the query. */
4646
0
      return 0;
4647
0
    case MJSON_TOK_KEY:
4648
      /* This is not a valid return value according to the
4649
       * mjson documentation, but we handle it to benefit
4650
       * from '-Wswitch'.
4651
       */
4652
0
      return 0;
4653
0
  }
4654
4655
0
  my_unreachable();
4656
0
  return 0;
4657
0
}
4658
4659
#ifdef USE_OPENSSL
4660
static int sample_conv_jwt_verify_check(struct arg *args, struct sample_conv *conv,
4661
          const char *file, int line, char **err)
4662
{
4663
  enum jwt_alg alg = JWT_ALG_DEFAULT;
4664
  int retval = 0;
4665
4666
  vars_check_arg(&args[0], NULL);
4667
  vars_check_arg(&args[1], NULL);
4668
4669
  if (args[0].type == ARGT_STR) {
4670
    alg = jwt_parse_alg(args[0].data.str.area, args[0].data.str.data);
4671
4672
    if (alg == JWT_ALG_DEFAULT) {
4673
      memprintf(err, "unknown JWT algorithm: %s", args[0].data.str.area);
4674
      return 0;
4675
    }
4676
  }
4677
4678
  if (args[1].type == ARGT_STR) {
4679
    switch (alg) {
4680
      case JWS_ALG_HS256:
4681
      case JWS_ALG_HS384:
4682
      case JWS_ALG_HS512:
4683
      /* don't try to load a file with HMAC algorithms */
4684
        retval = 1;
4685
        break;
4686
      default:
4687
        retval = (jwt_tree_load_cert(args[1].data.str.area, args[1].data.str.data,
4688
                                     0, file, line, err) == 0);
4689
        /* The second arg might be an HMAC secret but
4690
         * the 'alg' is stored in a var */
4691
        if (!retval && args[0].type == ARGT_VAR)
4692
          retval = 1;
4693
        break;
4694
    }
4695
  } else if (args[1].type == ARGT_VAR) {
4696
    /* We will try to resolve the var during runtime because the
4697
     * processing might work if it actually points to an already
4698
     * existing ckch_store.
4699
     */
4700
    retval = 1;
4701
  }
4702
4703
  return retval;
4704
}
4705
4706
static int sample_conv_jwt_verify_cert_check(struct arg *args, struct sample_conv *conv,
4707
                                             const char *file, int line, char **err)
4708
{
4709
  enum jwt_alg alg = JWT_ALG_DEFAULT;
4710
  int retval = 0;
4711
4712
  vars_check_arg(&args[0], NULL);
4713
  vars_check_arg(&args[1], NULL);
4714
4715
  if (args[0].type == ARGT_STR) {
4716
    alg = jwt_parse_alg(args[0].data.str.area, args[0].data.str.data);
4717
4718
    if (alg == JWT_ALG_DEFAULT) {
4719
      memprintf(err, "unknown JWT algorithm: %s", args[0].data.str.area);
4720
      return 0;
4721
    }
4722
  }
4723
4724
  if (args[1].type == ARGT_STR) {
4725
    switch (alg) {
4726
      case JWS_ALG_HS256:
4727
      case JWS_ALG_HS384:
4728
      case JWS_ALG_HS512:
4729
        /* We can't have a certificate as second parameter for
4730
         * HMAC-signed JWT tokens */
4731
        memprintf(err, "HMAC-signed tokens can't be processed by this converter");
4732
        break;
4733
      default:
4734
        retval = (jwt_tree_load_cert(args[1].data.str.area, args[1].data.str.data,
4735
                                     1, file, line, err) == 0);
4736
        break;
4737
    }
4738
  } else if (args[1].type == ARGT_VAR) {
4739
    /* We will try to resolve the var during runtime because the
4740
     * processing might work if it actually points to an already
4741
     * existing ckch_store.
4742
     */
4743
    retval = 1;
4744
  }
4745
4746
  return retval;
4747
}
4748
4749
/* Check that a JWT's signature is correct */
4750
static int sample_conv_jwt_verify(const struct arg *args, struct sample *smp, void *private)
4751
{
4752
  struct sample alg_smp, key_smp;
4753
  enum jwt_vrfy_status ret;
4754
  struct buffer *input = NULL;
4755
  struct buffer *alg = NULL;
4756
  struct buffer *key = NULL;
4757
  int retval = 0;
4758
4759
  /* The two following calls to 'sample_conv_var2smp_str' will both make
4760
   * use of the preallocated trash buffer (via get_trash_chunk call in
4761
   * smp_dup) which would end up erasing the contents of the 'smp' input
4762
   * buffer.
4763
   */
4764
  input = alloc_trash_chunk_sz(smp->data.u.str.data);
4765
  if (!input)
4766
    return 0;
4767
  alg = alloc_trash_chunk();
4768
  if (!alg)
4769
    goto end;
4770
  key = alloc_trash_chunk();
4771
  if (!key)
4772
    goto end;
4773
4774
  if (!chunk_cpy(input, &smp->data.u.str))
4775
    goto end;
4776
4777
  smp_set_owner(&alg_smp, smp->px, smp->sess, smp->strm, smp->opt);
4778
  if (!sample_conv_var2smp_str(&args[0], &alg_smp))
4779
    goto end;
4780
  if (chunk_printf(alg, "%.*s", (int)b_data(&alg_smp.data.u.str), b_orig(&alg_smp.data.u.str)) <= 0)
4781
    goto end;
4782
4783
  smp_set_owner(&key_smp, smp->px, smp->sess, smp->strm, smp->opt);
4784
  if (!sample_conv_var2smp_str(&args[1], &key_smp))
4785
    goto end;
4786
  if (chunk_printf(key, "%.*s", (int)b_data(&key_smp.data.u.str), b_orig(&key_smp.data.u.str)) <= 0)
4787
    goto end;
4788
4789
  ret = jwt_verify(input, alg, key, 0);
4790
4791
  smp->data.type = SMP_T_SINT;
4792
  smp->data.u.sint = ret;
4793
4794
  retval = 1;
4795
4796
end:
4797
  free_trash_chunk(input);
4798
  free_trash_chunk(alg);
4799
  free_trash_chunk(key);
4800
  return retval;
4801
}
4802
4803
static int sample_conv_jwt_verify_cert(const struct arg *args, struct sample *smp, void *private)
4804
{
4805
  struct sample alg_smp, key_smp;
4806
  enum jwt_vrfy_status ret;
4807
  struct buffer *input = NULL;
4808
  struct buffer *alg = NULL;
4809
  struct buffer *key = NULL;
4810
  int retval = 0;
4811
4812
  /* The two following calls to 'sample_conv_var2smp_str' will both make
4813
   * use of the preallocated trash buffer (via get_trash_chunk call in
4814
   * smp_dup) which would end up erasing the contents of the 'smp' input
4815
   * buffer.
4816
   */
4817
  input = alloc_trash_chunk_sz(smp->data.u.str.data);
4818
  if (!input)
4819
    return 0;
4820
  alg = alloc_trash_chunk();
4821
  if (!alg)
4822
    goto end;
4823
  key = alloc_trash_chunk();
4824
  if (!key)
4825
    goto end;
4826
4827
  if (!chunk_cpy(input, &smp->data.u.str))
4828
    goto end;
4829
4830
  smp_set_owner(&alg_smp, smp->px, smp->sess, smp->strm, smp->opt);
4831
  if (!sample_conv_var2smp_str(&args[0], &alg_smp))
4832
    goto end;
4833
  if (chunk_printf(alg, "%.*s", (int)b_data(&alg_smp.data.u.str), b_orig(&alg_smp.data.u.str)) <= 0)
4834
    goto end;
4835
4836
  smp_set_owner(&key_smp, smp->px, smp->sess, smp->strm, smp->opt);
4837
  if (!sample_conv_var2smp_str(&args[1], &key_smp))
4838
    goto end;
4839
  if (chunk_printf(key, "%.*s", (int)b_data(&key_smp.data.u.str), b_orig(&key_smp.data.u.str)) <= 0)
4840
    goto end;
4841
4842
  ret = jwt_verify(input, alg, key, 1);
4843
4844
  smp->data.type = SMP_T_SINT;
4845
  smp->data.u.sint = ret;
4846
4847
  retval = 1;
4848
4849
end:
4850
  free_trash_chunk(input);
4851
  free_trash_chunk(alg);
4852
  free_trash_chunk(key);
4853
  return retval;
4854
}
4855
4856
4857
/*
4858
 * Returns the decoded header or payload of a JWT if no parameter is given, or
4859
 * the value of the specified field of the corresponding JWT subpart if a
4860
 * parameter is given.
4861
 */
4862
static int sample_conv_jwt_member_query(const struct arg *args, struct sample *smp,
4863
          void *private, enum jwt_elt member)
4864
{
4865
  struct jwt_item items[JWT_ELT_MAX] = { { 0 } };
4866
  unsigned int item_num = member + 1; /* We don't need to tokenize the full token */
4867
  struct buffer *decoded_header;
4868
  int retval = 0;
4869
  int ret;
4870
4871
  /* We don't need to extract all the parts from the token, we only need a
4872
   * specific one.
4873
   */
4874
  if (jwt_tokenize(&smp->data.u.str, items, item_num) < 0)
4875
    goto end;
4876
4877
  decoded_header = get_trash_chunk_sz(items[member].length);
4878
  if (!decoded_header)
4879
    goto end;
4880
4881
  ret = base64urldec(items[member].start, items[member].length,
4882
                     decoded_header->area, decoded_header->size);
4883
  if (ret == -1)
4884
    goto end;
4885
4886
  decoded_header->data = ret;
4887
  if (args[0].type != ARGT_STR) {
4888
    smp->data.u.str = *decoded_header;
4889
    smp->data.type = SMP_T_STR;
4890
    goto end;
4891
  }
4892
4893
  /* We look for a specific field of the header or payload part of the JWT */
4894
  smp->data.u.str = *decoded_header;
4895
4896
  retval = sample_conv_json_query(args, smp, private);
4897
4898
end:
4899
  return retval;
4900
}
4901
4902
/* This function checks the "jwt_header_query" and "jwt_payload_query" converters' arguments.
4903
 * It is based on the "json_query" converter's check with the only difference
4904
 * being that the jwt converters can take 0 parameters as well.
4905
 */
4906
static int sample_conv_jwt_query_check(struct arg *arg, struct sample_conv *conv,
4907
               const char *file, int line, char **err)
4908
{
4909
  if (arg[1].data.str.data != 0) {
4910
    if (strcmp(arg[1].data.str.area, "int") != 0) {
4911
      memprintf(err, "output_type only supports \"int\" as argument");
4912
      return 0;
4913
    } else {
4914
      arg[1].type = ARGT_SINT;
4915
      arg[1].data.sint = 0;
4916
    }
4917
  }
4918
  return 1;
4919
}
4920
4921
/*
4922
 * If no parameter is given, return the decoded header part of a JWT (the first
4923
 * base64 encoded part, corresponding to the JOSE header).
4924
 * If a parameter is given, this converter acts as a "json_query" on this
4925
 * decoded JSON.
4926
 */
4927
static int sample_conv_jwt_header_query(const struct arg *args, struct sample *smp, void *private)
4928
{
4929
  return sample_conv_jwt_member_query(args, smp, private, JWT_ELT_JOSE);
4930
}
4931
4932
/*
4933
 * If no parameter is given, return the decoded payload part of a JWT (the
4934
 * second base64 encoded part, which contains all the claims).  If a parameter
4935
 * is given, this converter acts as a "json_query" on this decoded JSON.
4936
 */
4937
static int sample_conv_jwt_payload_query(const struct arg *args, struct sample *smp, void *private)
4938
{
4939
  return sample_conv_jwt_member_query(args, smp, private, JWT_ELT_CLAIMS);
4940
}
4941
4942
#endif /* USE_OPENSSL */
4943
4944
/************************************************************************/
4945
/*       All supported sample fetch functions must be declared here     */
4946
/************************************************************************/
4947
4948
4949
/* returns the actconn */
4950
static int
4951
smp_fetch_actconn(const struct arg *args, struct sample *smp, const char *kw, void *private)
4952
0
{
4953
0
  smp->data.type = SMP_T_SINT;
4954
0
  smp->data.u.sint = actconn;
4955
0
  return 1;
4956
0
}
4957
4958
4959
/* force TRUE to be returned at the fetch level */
4960
static int
4961
smp_fetch_true(const struct arg *args, struct sample *smp, const char *kw, void *private)
4962
0
{
4963
0
  if (!smp_make_rw(smp))
4964
0
    return 0;
4965
4966
0
  smp->data.type = SMP_T_BOOL;
4967
0
  smp->data.u.sint = 1;
4968
0
  return 1;
4969
0
}
4970
4971
/* force FALSE to be returned at the fetch level */
4972
static int
4973
smp_fetch_false(const struct arg *args, struct sample *smp, const char *kw, void *private)
4974
0
{
4975
0
  smp->data.type = SMP_T_BOOL;
4976
0
  smp->data.u.sint = 0;
4977
0
  return 1;
4978
0
}
4979
4980
/* retrieve environment variable $1 as a string */
4981
static int
4982
smp_fetch_env(const struct arg *args, struct sample *smp, const char *kw, void *private)
4983
0
{
4984
0
  char *env;
4985
4986
0
  if (args[0].type != ARGT_STR)
4987
0
    return 0;
4988
4989
0
  env = getenv(args[0].data.str.area);
4990
0
  if (!env)
4991
0
    return 0;
4992
4993
0
  smp->data.type = SMP_T_STR;
4994
0
  smp->flags = SMP_F_CONST;
4995
0
  smp->data.u.str.area = env;
4996
0
  smp->data.u.str.data = strlen(env);
4997
0
  return 1;
4998
0
}
4999
5000
/* Validates the data unit argument passed to "date" fetch. Argument 1 support an
5001
 * optional string representing the unit of the result: "s" for seconds, "ms" for
5002
 * milliseconds and "us" for microseconds.
5003
 * Returns 0 on error and non-zero if OK.
5004
 */
5005
int smp_check_date_unit(struct arg *args, char **err)
5006
0
{
5007
0
        if (args[1].type == ARGT_STR) {
5008
0
    long long int unit;
5009
5010
0
                if (strcmp(args[1].data.str.area, "s") == 0) {
5011
0
                        unit = TIME_UNIT_S;
5012
0
                }
5013
0
                else if (strcmp(args[1].data.str.area, "ms") == 0) {
5014
0
                        unit = TIME_UNIT_MS;
5015
0
                }
5016
0
                else if (strcmp(args[1].data.str.area, "us") == 0) {
5017
0
                        unit = TIME_UNIT_US;
5018
0
                }
5019
0
                else {
5020
0
                        memprintf(err, "expects 's', 'ms' or 'us', got '%s'",
5021
0
                                  args[1].data.str.area);
5022
0
                        return 0;
5023
0
                }
5024
5025
0
    chunk_destroy(&args[1].data.str);
5026
0
                args[1].type = ARGT_SINT;
5027
0
    args[1].data.sint = unit;
5028
0
        }
5029
0
        else if (args[1].type != ARGT_STOP) {
5030
0
                memprintf(err, "Unexpected arg type");
5031
0
                return 0;
5032
0
        }
5033
5034
0
        return 1;
5035
0
}
5036
5037
/* retrieve the current local date in epoch time, converts it to milliseconds
5038
 * or microseconds if asked to in optional args[1] unit param, and applies an
5039
 * optional args[0] offset.
5040
 */
5041
static int
5042
smp_fetch_date(const struct arg *args, struct sample *smp, const char *kw, void *private)
5043
0
{
5044
0
  smp->data.u.sint = date.tv_sec;
5045
5046
  /* report in milliseconds */
5047
0
  if (args[1].type == ARGT_SINT && args[1].data.sint == TIME_UNIT_MS) {
5048
0
    smp->data.u.sint *= 1000;
5049
0
    smp->data.u.sint += date.tv_usec / 1000;
5050
0
  }
5051
  /* report in microseconds */
5052
0
  else if (args[1].type == ARGT_SINT && args[1].data.sint == TIME_UNIT_US) {
5053
0
    smp->data.u.sint *= 1000000;
5054
0
    smp->data.u.sint += date.tv_usec;
5055
0
  }
5056
5057
  /* add offset */
5058
0
  if (args[0].type == ARGT_SINT)
5059
0
    smp->data.u.sint += args[0].data.sint;
5060
5061
0
  smp->data.type = SMP_T_SINT;
5062
0
  smp->flags |= SMP_F_VOL_TEST | SMP_F_MAY_CHANGE;
5063
0
  return 1;
5064
0
}
5065
5066
/* retrieve the current microsecond part of the date  */
5067
static int
5068
smp_fetch_date_us(const struct arg *args, struct sample *smp, const char *kw, void *private)
5069
0
{
5070
0
  smp->data.u.sint = date.tv_usec;
5071
0
  smp->data.type = SMP_T_SINT;
5072
0
  smp->flags |= SMP_F_VOL_TEST | SMP_F_MAY_CHANGE;
5073
0
  return 1;
5074
0
}
5075
5076
5077
/* returns the hostname */
5078
static int
5079
smp_fetch_hostname(const struct arg *args, struct sample *smp, const char *kw, void *private)
5080
0
{
5081
0
  smp->data.type = SMP_T_STR;
5082
0
  smp->flags = SMP_F_CONST;
5083
0
  smp->data.u.str.area = hostname;
5084
0
  smp->data.u.str.data = strlen(hostname);
5085
0
  return 1;
5086
0
}
5087
5088
/* returns the number of processes */
5089
static int
5090
smp_fetch_nbproc(const struct arg *args, struct sample *smp, const char *kw, void *private)
5091
0
{
5092
0
  smp->data.type = SMP_T_SINT;
5093
0
  smp->data.u.sint = 1;
5094
0
  return 1;
5095
0
}
5096
5097
/* returns the PID of the current process */
5098
static int
5099
smp_fetch_pid(const struct arg *args, struct sample *smp, const char *kw, void *private)
5100
0
{
5101
0
  smp->data.type = SMP_T_SINT;
5102
0
  smp->data.u.sint = pid;
5103
0
  return 1;
5104
0
}
5105
5106
5107
/* returns the number of the current process (between 1 and nbproc) */
5108
static int
5109
smp_fetch_proc(const struct arg *args, struct sample *smp, const char *kw, void *private)
5110
0
{
5111
0
  smp->data.type = SMP_T_SINT;
5112
0
  smp->data.u.sint = 1;
5113
0
  return 1;
5114
0
}
5115
5116
/* returns the number of the current thread (between 0 and nbthread-1) */
5117
static int
5118
smp_fetch_thread(const struct arg *args, struct sample *smp, const char *kw, void *private)
5119
0
{
5120
0
  smp->data.type = SMP_T_SINT;
5121
0
  smp->data.u.sint = tid;
5122
0
  return 1;
5123
0
}
5124
5125
/* returns the number of the current thread group (between 0 and nbtgroups-1) */
5126
static int
5127
smp_fetch_tgroup(const struct arg *args, struct sample *smp, const char *kw, void *private)
5128
0
{
5129
0
  smp->data.type = SMP_T_SINT;
5130
0
  smp->data.u.sint = tgid - 1; // tgid starts at 1
5131
0
  return 1;
5132
0
}
5133
5134
/* returns the last known CPU usage of the current thread */
5135
static int
5136
smp_fetch_cpu_usage_thr(const struct arg *args, struct sample *smp, const char *kw, void *private)
5137
0
{
5138
0
  smp->data.type = SMP_T_SINT;
5139
0
  smp->data.u.sint = 100 - th_ctx->idle_pct;
5140
0
  return 1;
5141
0
}
5142
5143
/* returns the last known CPU usage of the current thread group */
5144
static int
5145
smp_fetch_cpu_usage_grp(const struct arg *args, struct sample *smp, const char *kw, void *private)
5146
0
{
5147
0
  uint thr, tot = 0;
5148
5149
0
  for (thr = 0; thr < ha_tgroup_info[tgid - 1].count; thr++)
5150
0
    tot += 100 - ha_thread_ctx[ha_tgroup_info[tgid - 1].base + thr].idle_pct;
5151
5152
0
  smp->data.type = SMP_T_SINT;
5153
0
  smp->data.u.sint = (tot + thr / 2) / thr;
5154
0
  return 1;
5155
0
}
5156
5157
/* returns the last known CPU usage of the whole process */
5158
static int
5159
smp_fetch_cpu_usage_proc(const struct arg *args, struct sample *smp, const char *kw, void *private)
5160
0
{
5161
0
  int thr, tot = 0;
5162
5163
0
  for (thr = 0; thr < global.nbthread; thr++)
5164
0
    tot += 100 - ha_thread_ctx[thr].idle_pct;
5165
5166
0
  smp->data.type = SMP_T_SINT;
5167
0
  smp->data.u.sint = (tot + thr / 2) / thr;
5168
0
  return 1;
5169
0
}
5170
5171
/* generate a random 32-bit integer for whatever purpose, with an optional
5172
 * range specified in argument.
5173
 */
5174
static int
5175
smp_fetch_rand(const struct arg *args, struct sample *smp, const char *kw, void *private)
5176
0
{
5177
0
  smp->data.u.sint = statistical_prng();
5178
5179
  /* reduce if needed. Don't do a modulo, use all bits! */
5180
0
  if (args[0].type == ARGT_SINT)
5181
0
    smp->data.u.sint = ((u64)smp->data.u.sint * (u64)args[0].data.sint) >> 32;
5182
5183
0
  smp->data.type = SMP_T_SINT;
5184
0
  smp->flags |= SMP_F_VOL_TEST | SMP_F_MAY_CHANGE;
5185
0
  return 1;
5186
0
}
5187
5188
/* returns true if the current process is stopping */
5189
static int
5190
smp_fetch_stopping(const struct arg *args, struct sample *smp, const char *kw, void *private)
5191
0
{
5192
0
  smp->data.type = SMP_T_BOOL;
5193
0
  smp->data.u.sint = stopping;
5194
0
  return 1;
5195
0
}
5196
5197
/* returns the number of calls of the current stream's process_stream() */
5198
static int
5199
smp_fetch_cpu_calls(const struct arg *args, struct sample *smp, const char *kw, void *private)
5200
0
{
5201
0
  if (!smp->strm)
5202
0
    return 0;
5203
5204
0
  smp->data.type = SMP_T_SINT;
5205
0
  smp->data.u.sint = smp->strm->task->calls;
5206
0
  return 1;
5207
0
}
5208
5209
/* returns the average number of nanoseconds spent processing the stream per call */
5210
static int
5211
smp_fetch_cpu_ns_avg(const struct arg *args, struct sample *smp, const char *kw, void *private)
5212
0
{
5213
0
  if (!smp->strm)
5214
0
    return 0;
5215
5216
0
  smp->data.type = SMP_T_SINT;
5217
0
  smp->data.u.sint = smp->strm->task->calls ? smp->strm->cpu_time / smp->strm->task->calls : 0;
5218
0
  return 1;
5219
0
}
5220
5221
/* returns the total number of nanoseconds spent processing the stream */
5222
static int
5223
smp_fetch_cpu_ns_tot(const struct arg *args, struct sample *smp, const char *kw, void *private)
5224
0
{
5225
0
  if (!smp->strm)
5226
0
    return 0;
5227
5228
0
  smp->data.type = SMP_T_SINT;
5229
0
  smp->data.u.sint = smp->strm->cpu_time;
5230
0
  return 1;
5231
0
}
5232
5233
/* returns the average number of nanoseconds per call spent waiting for other tasks to be processed */
5234
static int
5235
smp_fetch_lat_ns_avg(const struct arg *args, struct sample *smp, const char *kw, void *private)
5236
0
{
5237
0
  if (!smp->strm)
5238
0
    return 0;
5239
5240
0
  smp->data.type = SMP_T_SINT;
5241
0
  smp->data.u.sint = smp->strm->task->calls ? smp->strm->lat_time / smp->strm->task->calls : 0;
5242
0
  return 1;
5243
0
}
5244
5245
/* returns the total number of nanoseconds per call spent waiting for other tasks to be processed */
5246
static int
5247
smp_fetch_lat_ns_tot(const struct arg *args, struct sample *smp, const char *kw, void *private)
5248
0
{
5249
0
  if (!smp->strm)
5250
0
    return 0;
5251
5252
0
  smp->data.type = SMP_T_SINT;
5253
0
  smp->data.u.sint = smp->strm->lat_time;
5254
0
  return 1;
5255
0
}
5256
5257
static int smp_fetch_const_str(const struct arg *args, struct sample *smp, const char *kw, void *private)
5258
0
{
5259
0
  smp->flags |= SMP_F_CONST;
5260
0
  smp->data.type = SMP_T_STR;
5261
0
  smp->data.u.str.area = args[0].data.str.area;
5262
0
  smp->data.u.str.data = args[0].data.str.data;
5263
0
  return 1;
5264
0
}
5265
5266
static int smp_check_const_bool(struct arg *args, char **err)
5267
0
{
5268
0
  if (strcasecmp(args[0].data.str.area, "true") == 0 ||
5269
0
      strcasecmp(args[0].data.str.area, "1") == 0) {
5270
0
    chunk_destroy(&args[0].data.str);
5271
0
    args[0].type = ARGT_SINT;
5272
0
    args[0].data.sint = 1;
5273
0
    return 1;
5274
0
  }
5275
0
  if (strcasecmp(args[0].data.str.area, "false") == 0 ||
5276
0
      strcasecmp(args[0].data.str.area, "0") == 0) {
5277
0
    chunk_destroy(&args[0].data.str);
5278
0
    args[0].type = ARGT_SINT;
5279
0
    args[0].data.sint = 0;
5280
0
    return 1;
5281
0
  }
5282
0
  memprintf(err, "Expects 'true', 'false', '0' or '1'");
5283
0
  return 0;
5284
0
}
5285
5286
static int smp_fetch_const_bool(const struct arg *args, struct sample *smp, const char *kw, void *private)
5287
0
{
5288
0
  smp->data.type = SMP_T_BOOL;
5289
0
  smp->data.u.sint = args[0].data.sint;
5290
0
  return 1;
5291
0
}
5292
5293
static int smp_fetch_const_int(const struct arg *args, struct sample *smp, const char *kw, void *private)
5294
0
{
5295
0
  smp->data.type = SMP_T_SINT;
5296
0
  smp->data.u.sint = args[0].data.sint;
5297
0
  return 1;
5298
0
}
5299
5300
static int smp_fetch_const_ipv4(const struct arg *args, struct sample *smp, const char *kw, void *private)
5301
0
{
5302
0
  smp->data.type = SMP_T_IPV4;
5303
0
  smp->data.u.ipv4 = args[0].data.ipv4;
5304
0
  return 1;
5305
0
}
5306
5307
static int smp_fetch_const_ipv6(const struct arg *args, struct sample *smp, const char *kw, void *private)
5308
0
{
5309
0
  smp->data.type = SMP_T_IPV6;
5310
0
  smp->data.u.ipv6 = args[0].data.ipv6;
5311
0
  return 1;
5312
0
}
5313
5314
static int smp_check_const_bin(struct arg *args, char **err)
5315
0
{
5316
0
  char *binstr = NULL;
5317
0
  int binstrlen;
5318
5319
0
  if (!parse_binary(args[0].data.str.area, &binstr, &binstrlen, err))
5320
0
    return 0;
5321
0
  chunk_destroy(&args[0].data.str);
5322
0
  args[0].type = ARGT_STR;
5323
0
  args[0].data.str.area = binstr;
5324
0
  args[0].data.str.data = binstrlen;
5325
0
  return 1;
5326
0
}
5327
5328
static int smp_fetch_const_bin(const struct arg *args, struct sample *smp, const char *kw, void *private)
5329
0
{
5330
0
  smp->flags |= SMP_F_CONST;
5331
0
  smp->data.type = SMP_T_BIN;
5332
0
  smp->data.u.str.area = args[0].data.str.area;
5333
0
  smp->data.u.str.data = args[0].data.str.data;
5334
0
  return 1;
5335
0
}
5336
5337
static int smp_check_const_meth(struct arg *args, char **err)
5338
0
{
5339
0
  enum http_meth_t meth;
5340
0
  int i;
5341
5342
0
  meth = find_http_meth(args[0].data.str.area, args[0].data.str.data);
5343
0
  if (meth != HTTP_METH_OTHER) {
5344
0
    chunk_destroy(&args[0].data.str);
5345
0
    args[0].type = ARGT_SINT;
5346
0
    args[0].data.sint = meth;
5347
0
  } else {
5348
    /* Check method availability. A method is a token defined as :
5349
     * tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "." /
5350
     *         "^" / "_" / "`" / "|" / "~" / DIGIT / ALPHA
5351
     * token = 1*tchar
5352
     */
5353
0
    for (i = 0; i < args[0].data.str.data; i++) {
5354
0
      if (!HTTP_IS_TOKEN(args[0].data.str.area[i])) {
5355
0
        memprintf(err, "expects valid method.");
5356
0
        return 0;
5357
0
      }
5358
0
    }
5359
0
  }
5360
0
  return 1;
5361
0
}
5362
5363
static int smp_fetch_const_meth(const struct arg *args, struct sample *smp, const char *kw, void *private)
5364
0
{
5365
0
  smp->data.type = SMP_T_METH;
5366
0
  if (args[0].type == ARGT_SINT) {
5367
0
    smp->flags &= ~SMP_F_CONST;
5368
0
    smp->data.u.meth.meth = args[0].data.sint;
5369
0
    smp->data.u.meth.str.area = "";
5370
0
    smp->data.u.meth.str.data = 0;
5371
0
  } else {
5372
0
    smp->flags |= SMP_F_CONST;
5373
0
    smp->data.u.meth.meth = HTTP_METH_OTHER;
5374
0
    smp->data.u.meth.str.area = args[0].data.str.area;
5375
0
    smp->data.u.meth.str.data = args[0].data.str.data;
5376
0
  }
5377
0
  return 1;
5378
0
}
5379
5380
// This function checks the "uuid" sample's arguments.
5381
// Function won't get called when no parameter is specified (maybe a bug?)
5382
static int smp_check_uuid(struct arg *args, char **err)
5383
0
{
5384
0
  if (!args[0].type) {
5385
0
    args[0].type = ARGT_SINT;
5386
0
    args[0].data.sint = 4;
5387
0
  } else {
5388
0
    switch (args[0].data.sint) {
5389
0
    case 4:
5390
0
    case 7:
5391
0
      break;
5392
0
    default:
5393
0
      memprintf(err, "Unsupported UUID version: '%lld'", args[0].data.sint);
5394
0
      return 0;
5395
0
    }
5396
0
  }
5397
5398
0
  return 1;
5399
0
}
5400
5401
// Generate a RFC 9562 UUID (default is v4 = fully random)
5402
static int smp_fetch_uuid(const struct arg *args, struct sample *smp, const char *kw, void *private)
5403
0
{
5404
0
  long long int type = -1;
5405
5406
0
  if (!args[0].type) {
5407
0
    type = 4;
5408
0
  } else {
5409
0
    type = args[0].data.sint;
5410
0
  }
5411
5412
0
  switch (type) {
5413
0
  case 4:
5414
0
    ha_generate_uuid_v4(&trash);
5415
0
    break;
5416
0
  case 7:
5417
0
    ha_generate_uuid_v7(&trash);
5418
0
    break;
5419
0
  default:
5420
0
    return 0;
5421
0
  }
5422
5423
0
  smp->data.type = SMP_T_STR;
5424
0
  smp->flags = SMP_F_VOL_TEST | SMP_F_MAY_CHANGE;
5425
0
  smp->data.u.str = trash;
5426
0
  return 1;
5427
0
}
5428
5429
/* returns the uptime in seconds */
5430
static int
5431
smp_fetch_uptime(const struct arg *args, struct sample *smp, const char *kw, void *private)
5432
0
{
5433
0
  smp->data.type = SMP_T_SINT;
5434
0
  smp->data.u.sint = ns_to_sec(now_ns - start_time_ns);
5435
0
  return 1;
5436
0
}
5437
5438
5439
/* Check if QUIC support was compiled and was not disabled by "tune.quic.listen" global option */
5440
static int smp_fetch_quic_enabled(const struct arg *args, struct sample *smp, const char *kw, void *private)
5441
0
{
5442
0
  smp->data.type = SMP_T_BOOL;
5443
0
  smp->flags = 0;
5444
#ifdef USE_QUIC
5445
  smp->data.u.sint = !(quic_tune.fe.opts & QUIC_TUNE_FE_LISTEN_OFF);
5446
#else
5447
0
  smp->data.u.sint = 0;
5448
0
#endif
5449
0
  return smp->data.u.sint;
5450
0
}
5451
5452
/* Timing events re{q,s}.timer.  */
5453
static int smp_fetch_reX_timers(const struct arg *args, struct sample *smp, const char *kw, void *private)
5454
0
{
5455
0
  struct strm_logs *logs;
5456
0
  int t_request = -1;
5457
5458
0
  if (!smp->strm)
5459
0
    return 0;
5460
5461
0
  smp->data.type = SMP_T_SINT;
5462
0
  smp->flags = 0;
5463
5464
0
  logs = &smp->strm->logs;
5465
5466
5467
0
  if ((llong)(logs->request_ts - logs->accept_ts) >= 0)
5468
0
    t_request = ns_to_ms(logs->request_ts - logs->accept_ts);
5469
5470
  /* req.timer. */
5471
0
  if (kw[2] == 'q') {
5472
5473
0
    switch (kw[10]) {
5474
5475
      /* req.timer.idle (%Ti)  */
5476
0
      case 'i':
5477
0
        smp->data.u.sint = logs->t_idle;
5478
0
        break;
5479
5480
      /* req.timer.tq (%Tq) */
5481
0
      case 't':
5482
0
        smp->data.u.sint = t_request;
5483
0
        break;
5484
5485
      /* req.timer.hdr (%TR) */
5486
0
      case 'h':
5487
0
        smp->data.u.sint = (t_request >= 0) ? t_request - logs->t_idle - logs->t_handshake : -1;
5488
0
        break;
5489
5490
      /* req.timer.queue (%Tw) */
5491
0
      case 'q':
5492
0
        smp->data.u.sint = (logs->t_queue >= 0) ? logs->t_queue - t_request : -1;
5493
0
        break;
5494
5495
0
      default:
5496
0
        goto error;
5497
5498
0
    }
5499
0
  } else {
5500
    /* res.timer. */
5501
0
    switch (kw[10]) {
5502
      /* res.timer.hdr (%Tr) */
5503
0
      case 'h':
5504
0
        smp->data.u.sint = (logs->t_data >= 0) ? logs->t_data - logs->t_connect : -1;
5505
0
      break;
5506
5507
      /* res.timer.data (%Td) */
5508
0
      case 'd':
5509
0
        smp->data.u.sint = (logs->t_data >= 0) ? logs->t_close - logs->t_data : -1;
5510
0
      break;
5511
5512
0
      default:
5513
0
        goto error;
5514
5515
0
    }
5516
5517
0
  }
5518
5519
0
    return 1;
5520
0
error:
5521
5522
0
    return 0;
5523
0
  }
5524
5525
5526
/* Timing events  txn. */
5527
static int smp_fetch_txn_timers(const struct arg *args, struct sample *smp, const char *kw, void *private)
5528
0
{
5529
0
  struct strm_logs *logs;
5530
5531
0
  if (!smp->strm)
5532
0
    return 0;
5533
5534
0
  smp->data.type = SMP_T_SINT;
5535
0
  smp->flags = 0;
5536
5537
0
  logs = &smp->strm->logs;
5538
5539
  /* txn.timer. */
5540
0
  switch (kw[10]) {
5541
5542
    /* txn.timer.total (%Ta) */
5543
0
    case 't':
5544
0
      smp->data.u.sint = logs->t_close - (logs->t_idle >= 0 ? logs->t_idle + logs->t_handshake : 0);
5545
0
    break;
5546
5547
5548
    /* txn.timer.user (%Tu) */
5549
0
    case 'u':
5550
0
      smp->data.u.sint = logs->t_close - (logs->t_idle >= 0 ? logs->t_idle : 0);
5551
0
    break;
5552
5553
0
    default:
5554
0
      goto error;
5555
5556
0
  }
5557
5558
0
  return 1;
5559
0
error:
5560
5561
0
  return 0;
5562
0
}
5563
5564
/* Server conn queueing infos - bc_{be,srv}_queue */
5565
static int smp_fetch_conn_queues(const struct arg *args, struct sample *smp, const char *kw, void *private)
5566
0
{
5567
0
  struct strm_logs *logs;
5568
5569
0
  if (!smp->strm)
5570
0
    return 0;
5571
5572
0
  smp->data.type = SMP_T_SINT;
5573
0
  smp->flags = 0;
5574
5575
0
  logs = &smp->strm->logs;
5576
5577
0
  if (kw[3] == 'b') {
5578
    /* bc_be_queue */
5579
0
    smp->data.u.sint = logs->prx_queue_pos;
5580
0
  }
5581
0
  else {
5582
    /* bc_srv_queue */
5583
0
    smp->data.u.sint = logs->srv_queue_pos;
5584
0
  }
5585
0
  return 1;
5586
0
}
5587
5588
/* Timing events {f,bc}.timer.  */
5589
static int smp_fetch_conn_timers(const struct arg *args, struct sample *smp, const char *kw, void *private)
5590
0
{
5591
0
  struct strm_logs *logs;
5592
5593
0
  smp->data.type = SMP_T_SINT;
5594
0
  smp->flags = 0;
5595
5596
0
  if (!smp->strm) {
5597
    /* no stream: only fc.timer.handshake is available via
5598
     * the session.
5599
     */
5600
0
    if (kw[0] == 'f' && kw[9] == 'h') {
5601
0
      smp->data.u.sint = smp->sess->t_handshake;
5602
0
      return 1;
5603
0
    }
5604
0
    return 0;
5605
0
  }
5606
5607
0
  logs = &smp->strm->logs;
5608
5609
0
  if (kw[0] == 'b') {
5610
    /* fc.timer. */
5611
0
    switch (kw[9]) {
5612
5613
      /* bc.timer.connect (%Tc) */
5614
0
      case 'c':
5615
0
        smp->data.u.sint = (logs->t_connect >= 0) ? logs->t_connect - logs->t_queue : -1;
5616
0
        break;
5617
5618
0
      default:
5619
0
        goto error;
5620
0
    }
5621
5622
0
  } else {
5623
5624
    /* fc.timer. */
5625
0
    switch (kw[9]) {
5626
5627
      /* fc.timer.handshake (%Th) */
5628
0
      case 'h':
5629
0
        smp->data.u.sint = logs->t_handshake;
5630
0
        break;
5631
5632
      /* fc,timer.total (%Tt) */
5633
0
      case 't':
5634
0
        smp->data.u.sint = logs->t_close;
5635
0
        break;
5636
5637
0
      default:
5638
0
        goto error;
5639
0
    }
5640
5641
0
  }
5642
5643
0
  return 1;
5644
0
error:
5645
5646
0
  return 0;
5647
0
}
5648
5649
/* bytes_{in,out} */
5650
static int smp_fetch_bytes(const struct arg *args, struct sample *smp, const char *kw, void *private)
5651
0
{
5652
0
  struct strm_logs *logs;
5653
5654
0
  if (!smp->strm)
5655
0
    return 0;
5656
5657
0
  smp->data.type = SMP_T_SINT;
5658
0
  smp->flags = 0;
5659
5660
0
  logs = &smp->strm->logs;
5661
0
  if (!logs)
5662
0
    return 0;
5663
5664
0
  if (kw[2] == 'q') /* req.bytes_in or req.bytes_out */
5665
0
    smp->data.u.sint = (kw[10] == 'i') ? logs->req_in : logs->req_out;
5666
0
  else if (kw[2] == 's') /* res.bytes_in or res.bytes_out */
5667
0
    smp->data.u.sint = (kw[10] == 'i') ? logs->res_in : logs->res_out;
5668
0
  else /* bytes_in or bytes_out */
5669
0
    smp->data.u.sint = (kw[6] == 'i') ? logs->req_in : logs->res_in;
5670
5671
0
  return 1;
5672
0
}
5673
5674
static int sample_conv_bytes_check(struct arg *args, struct sample_conv *conv,
5675
                          const char *file, int line, char **err)
5676
0
{
5677
  // arg0 is not optional, must be >= 0
5678
0
  if (!check_operator(&args[0], conv, file, line, err)) {
5679
0
    return 0;
5680
0
  }
5681
0
  if (args[0].type != ARGT_VAR) {
5682
0
    if (args[0].type != ARGT_SINT || args[0].data.sint < 0) {
5683
0
      memprintf(err, "expects a non-negative integer");
5684
0
      return 0;
5685
0
    }
5686
0
  }
5687
  // arg1 is optional, must be > 0
5688
0
  if (args[1].type != ARGT_STOP) {
5689
0
    if (!check_operator(&args[1], conv, file, line, err)) {
5690
0
      return 0;
5691
0
    }
5692
0
    if (args[1].type != ARGT_VAR) {
5693
0
      if (args[1].type != ARGT_SINT || args[1].data.sint <= 0) {
5694
0
        memprintf(err, "expects a positive integer");
5695
0
        return 0;
5696
0
      }
5697
0
    }
5698
0
  }
5699
5700
0
  return 1;
5701
0
}
5702
5703
static struct sample_fetch_kw_list smp_logs_kws = {ILH, {
5704
  { "bytes_in",             smp_fetch_bytes,        0,         NULL, SMP_T_SINT, SMP_USE_RQFIN },
5705
  { "bytes_out",            smp_fetch_bytes,        0,         NULL, SMP_T_SINT, SMP_USE_RSFIN },
5706
5707
  { "txn.timer.total",      smp_fetch_txn_timers,   0,         NULL, SMP_T_SINT, SMP_USE_TXFIN }, /* "Ta" */
5708
  { "txn.timer.user",       smp_fetch_txn_timers,   0,         NULL, SMP_T_SINT, SMP_USE_TXFIN }, /* "Tu" */
5709
5710
  { "bc.timer.connect",     smp_fetch_conn_timers,  0,         NULL, SMP_T_SINT, SMP_USE_L4SRV }, /* "Tc" */
5711
  { "bc_be_queue",          smp_fetch_conn_queues,  0,         NULL, SMP_T_SINT, SMP_USE_L4SRV }, /* "bq" */
5712
  { "bc_srv_queue",         smp_fetch_conn_queues,  0,         NULL, SMP_T_SINT, SMP_USE_L4SRV }, /* "sq" */
5713
5714
  { "fc.timer.handshake",   smp_fetch_conn_timers,  0,         NULL, SMP_T_SINT, SMP_USE_L4CLI }, /* "Th" */
5715
  { "fc.timer.total",       smp_fetch_conn_timers,  0,         NULL, SMP_T_SINT, SMP_USE_SSFIN }, /* "Tt" */
5716
5717
  { "req.bytes_in",         smp_fetch_bytes,        0,         NULL, SMP_T_SINT, SMP_USE_RQFIN },
5718
  { "req.bytes_out",        smp_fetch_bytes,        0,         NULL, SMP_T_SINT, SMP_USE_RQFIN },
5719
  { "req.timer.idle",       smp_fetch_reX_timers,   0,         NULL, SMP_T_SINT, SMP_USE_HRQHV }, /* "Ti" */
5720
  { "req.timer.tq",         smp_fetch_reX_timers,   0,         NULL, SMP_T_SINT, SMP_USE_HRQHV }, /* "Tq" */
5721
  { "req.timer.hdr",        smp_fetch_reX_timers,   0,         NULL, SMP_T_SINT, SMP_USE_HRQHV }, /* "TR" */
5722
  { "req.timer.queue",      smp_fetch_reX_timers,   0,         NULL, SMP_T_SINT, SMP_USE_L4SRV }, /* "Tw" */
5723
  { "res.bytes_in",         smp_fetch_bytes,        0,         NULL, SMP_T_SINT, SMP_USE_RSFIN },
5724
  { "res.bytes_out",        smp_fetch_bytes,        0,         NULL, SMP_T_SINT, SMP_USE_RSFIN },
5725
  { "res.timer.data",       smp_fetch_reX_timers,   0,         NULL, SMP_T_SINT, SMP_USE_RSFIN }, /* "Td" */
5726
  { "res.timer.hdr",        smp_fetch_reX_timers,   0,         NULL, SMP_T_SINT, SMP_USE_HRSHV }, /* "Tr" */
5727
  { /* END */ },
5728
}};
5729
5730
INITCALL1(STG_REGISTER, sample_register_fetches, &smp_logs_kws);
5731
5732
/* Note: must not be declared <const> as its list will be overwritten.
5733
 * Note: fetches that may return multiple types should be declared using the
5734
 * appropriate pseudo-type. If not available it must be declared as the lowest
5735
 * common denominator, the type that can be casted into all other ones.
5736
 */
5737
static struct sample_fetch_kw_list smp_kws = {ILH, {
5738
  { "act_conn",     smp_fetch_actconn, 0,          NULL, SMP_T_SINT, SMP_USE_CONST },
5739
  { "always_false", smp_fetch_false, 0,            NULL, SMP_T_BOOL, SMP_USE_CONST },
5740
  { "always_true",  smp_fetch_true,  0,            NULL, SMP_T_BOOL, SMP_USE_CONST },
5741
  { "env",          smp_fetch_env,   ARG1(1,STR),  NULL, SMP_T_STR,  SMP_USE_CONST },
5742
  { "date",         smp_fetch_date,  ARG2(0,SINT,STR), smp_check_date_unit, SMP_T_SINT, SMP_USE_CONST },
5743
  { "date_us",      smp_fetch_date_us,  0,         NULL, SMP_T_SINT, SMP_USE_CONST },
5744
  { "hostname",     smp_fetch_hostname, 0,         NULL, SMP_T_STR,  SMP_USE_CONST },
5745
  { "nbproc",       smp_fetch_nbproc,0,            NULL, SMP_T_SINT, SMP_USE_CONST },
5746
  { "pid",          smp_fetch_pid,   0,            NULL, SMP_T_SINT, SMP_USE_CONST },
5747
  { "proc",         smp_fetch_proc,  0,            NULL, SMP_T_SINT, SMP_USE_CONST },
5748
  { "quic_enabled", smp_fetch_quic_enabled, 0,     NULL, SMP_T_BOOL, SMP_USE_CONST },
5749
  { "thread",       smp_fetch_thread,  0,          NULL, SMP_T_SINT, SMP_USE_CONST },
5750
  { "tgroup",       smp_fetch_tgroup,  0,          NULL, SMP_T_SINT, SMP_USE_CONST },
5751
  { "rand",         smp_fetch_rand,  ARG1(0,SINT), NULL, SMP_T_SINT, SMP_USE_CONST },
5752
  { "stopping",     smp_fetch_stopping, 0,         NULL, SMP_T_BOOL, SMP_USE_INTRN },
5753
  { "uptime",       smp_fetch_uptime,   0,         NULL, SMP_T_SINT, SMP_USE_CONST },
5754
  { "uuid",         smp_fetch_uuid,  ARG1(0, SINT),      smp_check_uuid, SMP_T_STR, SMP_USE_CONST },
5755
5756
  { "cpu_calls",    smp_fetch_cpu_calls,  0,       NULL, SMP_T_SINT, SMP_USE_INTRN },
5757
  { "cpu_ns_avg",   smp_fetch_cpu_ns_avg, 0,       NULL, SMP_T_SINT, SMP_USE_INTRN },
5758
  { "cpu_ns_tot",   smp_fetch_cpu_ns_tot, 0,       NULL, SMP_T_SINT, SMP_USE_INTRN },
5759
  { "cpu_usage_grp", smp_fetch_cpu_usage_grp,  0,  NULL, SMP_T_SINT, SMP_USE_INTRN },
5760
  { "cpu_usage_proc",smp_fetch_cpu_usage_proc, 0,  NULL, SMP_T_SINT, SMP_USE_INTRN },
5761
  { "cpu_usage_thr", smp_fetch_cpu_usage_thr,  0,  NULL, SMP_T_SINT, SMP_USE_INTRN },
5762
  { "lat_ns_avg",   smp_fetch_lat_ns_avg, 0,       NULL, SMP_T_SINT, SMP_USE_INTRN },
5763
  { "lat_ns_tot",   smp_fetch_lat_ns_tot, 0,       NULL, SMP_T_SINT, SMP_USE_INTRN },
5764
5765
  { "str",  smp_fetch_const_str,  ARG1(1,STR),  NULL                , SMP_T_STR,  SMP_USE_CONST },
5766
  { "bool", smp_fetch_const_bool, ARG1(1,STR),  smp_check_const_bool, SMP_T_BOOL, SMP_USE_CONST },
5767
  { "int",  smp_fetch_const_int,  ARG1(1,SINT), NULL                , SMP_T_SINT, SMP_USE_CONST },
5768
  { "ipv4", smp_fetch_const_ipv4, ARG1(1,IPV4), NULL                , SMP_T_IPV4, SMP_USE_CONST },
5769
  { "ipv6", smp_fetch_const_ipv6, ARG1(1,IPV6), NULL                , SMP_T_IPV6, SMP_USE_CONST },
5770
  { "bin",  smp_fetch_const_bin,  ARG1(1,STR),  smp_check_const_bin , SMP_T_BIN,  SMP_USE_CONST },
5771
  { "meth", smp_fetch_const_meth, ARG1(1,STR),  smp_check_const_meth, SMP_T_METH, SMP_USE_CONST },
5772
5773
  { /* END */ },
5774
}};
5775
5776
INITCALL1(STG_REGISTER, sample_register_fetches, &smp_kws);
5777
5778
/* Note: must not be declared <const> as its list will be overwritten */
5779
static struct sample_conv_kw_list sample_conv_kws = {ILH, {
5780
  { "add_item",sample_conv_add_item,     ARG3(2,STR,STR,STR),   smp_check_add_item,       SMP_T_STR,  SMP_T_STR  },
5781
  { "debug",   sample_conv_debug,        ARG2(0,STR,STR),       smp_check_debug,          SMP_T_ANY,  SMP_T_SAME },
5782
  { "b64dec",  sample_conv_base642bin,   0,                     NULL,                     SMP_T_STR,  SMP_T_BIN  },
5783
  { "base64",  sample_conv_bin2base64,   0,                     NULL,                     SMP_T_BIN,  SMP_T_STR  },
5784
  { "concat",  sample_conv_concat,       ARG3(1,STR,STR,STR),   smp_check_concat,         SMP_T_STR,  SMP_T_STR  },
5785
  { "ub64enc", sample_conv_bin2base64url,0,                     NULL,                     SMP_T_BIN,  SMP_T_STR  },
5786
  { "ub64dec", sample_conv_base64url2bin,0,                     NULL,                     SMP_T_STR,  SMP_T_BIN  },
5787
  { "upper",   sample_conv_str2upper,    0,                     NULL,                     SMP_T_STR,  SMP_T_STR  },
5788
  { "lower",   sample_conv_str2lower,    0,                     NULL,                     SMP_T_STR,  SMP_T_STR  },
5789
  { "length",  sample_conv_length,       0,                     NULL,                     SMP_T_STR,  SMP_T_SINT },
5790
  { "base2",   sample_conv_bin2base2,    0,                     NULL,                     SMP_T_BIN,  SMP_T_STR  },
5791
  { "be2dec",  sample_conv_be2dec,       ARG3(1,STR,SINT,SINT), sample_conv_2dec_check,   SMP_T_BIN,  SMP_T_STR  },
5792
  { "le2dec",  sample_conv_le2dec,       ARG3(1,STR,SINT,SINT), sample_conv_2dec_check,   SMP_T_BIN,  SMP_T_STR  },
5793
  { "be2hex",  sample_conv_be2hex,       ARG3(1,STR,SINT,SINT), sample_conv_be2hex_check, SMP_T_BIN,  SMP_T_STR  },
5794
  { "hex",     sample_conv_bin2hex,      0,                     NULL,                     SMP_T_BIN,  SMP_T_STR  },
5795
  { "hex2i",   sample_conv_hex2int,      0,                     NULL,                     SMP_T_STR,  SMP_T_SINT },
5796
  { "ipmask",  sample_conv_ipmask,       ARG2(1,MSK4,MSK6),     NULL,                     SMP_T_ADDR, SMP_T_ADDR },
5797
  { "ltime",   sample_conv_ltime,        ARG2(1,STR,SINT),      NULL,                     SMP_T_SINT, SMP_T_STR  },
5798
  { "ms_ltime",   sample_conv_ms_ltime,        ARG2(1,STR,SINT),      NULL,                     SMP_T_SINT, SMP_T_STR  },
5799
  { "us_ltime",   sample_conv_us_ltime,        ARG2(1,STR,SINT),      NULL,                     SMP_T_SINT, SMP_T_STR  },
5800
  { "utime",   sample_conv_utime,        ARG2(1,STR,SINT),      NULL,                     SMP_T_SINT, SMP_T_STR  },
5801
  { "ms_utime",   sample_conv_ms_utime,        ARG2(1,STR,SINT),      NULL,                     SMP_T_SINT, SMP_T_STR  },
5802
  { "us_utime",   sample_conv_us_utime,        ARG2(1,STR,SINT),      NULL,                     SMP_T_SINT, SMP_T_STR  },
5803
  { "crc32",   sample_conv_crc32,        ARG1(0,SINT),          NULL,                     SMP_T_BIN,  SMP_T_SINT },
5804
  { "crc32c",  sample_conv_crc32c,       ARG1(0,SINT),          NULL,                     SMP_T_BIN,  SMP_T_SINT },
5805
  { "djb2",    sample_conv_djb2,         ARG1(0,SINT),          NULL,                     SMP_T_BIN,  SMP_T_SINT },
5806
  { "sdbm",    sample_conv_sdbm,         ARG1(0,SINT),          NULL,                     SMP_T_BIN,  SMP_T_SINT },
5807
  { "wt6",     sample_conv_wt6,          ARG1(0,SINT),          NULL,                     SMP_T_BIN,  SMP_T_SINT },
5808
  { "xxh3",    sample_conv_xxh3,         ARG1(0,SINT),          NULL,                     SMP_T_BIN,  SMP_T_SINT },
5809
  { "xxh32",   sample_conv_xxh32,        ARG1(0,SINT),          NULL,                     SMP_T_BIN,  SMP_T_SINT },
5810
  { "xxh64",   sample_conv_xxh64,        ARG1(0,SINT),          NULL,                     SMP_T_BIN,  SMP_T_SINT },
5811
  { "json",    sample_conv_json,         ARG1(1,STR),           sample_conv_json_check,   SMP_T_STR,  SMP_T_STR  },
5812
  { "bytes",   sample_conv_bytes,        ARG2(1,STR,STR),       sample_conv_bytes_check,  SMP_T_BIN,  SMP_T_BIN  },
5813
  { "field",   sample_conv_field,        ARG3(2,SINT,STR,SINT), sample_conv_field_check,  SMP_T_STR,  SMP_T_STR  },
5814
  { "word",    sample_conv_word,         ARG3(2,SINT,STR,SINT), sample_conv_field_check,  SMP_T_STR,  SMP_T_STR  },
5815
  { "param",   sample_conv_param,        ARG2(1,STR,STR),       sample_conv_param_check,  SMP_T_STR,  SMP_T_STR  },
5816
  { "regsub",  sample_conv_regsub,       ARG3(2,REG,STR,STR),   sample_conv_regsub_check, SMP_T_STR,  SMP_T_STR  },
5817
  { "sha1",    sample_conv_sha1,         0,                     NULL,                     SMP_T_BIN,  SMP_T_BIN  },
5818
  { "strcmp",      sample_conv_strcmp,      ARG1(1,STR),        smp_check_strcmp,         SMP_T_STR,  SMP_T_SINT },
5819
  { "host_only",   sample_conv_host_only,   0,                  NULL,                     SMP_T_STR,  SMP_T_STR  },
5820
  { "port_only",   sample_conv_port_only,   0,                  NULL,                     SMP_T_STR,  SMP_T_SINT },
5821
  { "reverse",     sample_conv_reverse,     0,                  NULL,                     SMP_T_STR,  SMP_T_STR  },
5822
  { "reverse_dom", sample_conv_reverse_dom, 0,                  NULL,                     SMP_T_STR,  SMP_T_STR  },
5823
5824
  /* gRPC converters. */
5825
  { "ungrpc", sample_conv_ungrpc,    ARG2(1,PBUF_FNUM,STR), sample_conv_protobuf_check, SMP_T_BIN, SMP_T_BIN  },
5826
  { "protobuf", sample_conv_protobuf, ARG2(1,PBUF_FNUM,STR), sample_conv_protobuf_check, SMP_T_BIN, SMP_T_BIN  },
5827
5828
  /* FIX converters */
5829
  { "fix_is_valid",  sample_conv_fix_is_valid,  0,           NULL,                        SMP_T_BIN, SMP_T_BOOL  },
5830
  { "fix_tag_value", sample_conv_fix_tag_value, ARG1(1,STR), sample_conv_fix_value_check, SMP_T_BIN, SMP_T_BIN  },
5831
5832
  /* MQTT converters */
5833
  { "mqtt_is_valid",    sample_conv_mqtt_is_valid,     0,               NULL,                               SMP_T_BIN, SMP_T_BOOL },
5834
  { "mqtt_field_value", sample_conv_mqtt_field_value,  ARG2(2,STR,STR), sample_conv_mqtt_field_value_check, SMP_T_BIN, SMP_T_STR },
5835
5836
  { "iif", sample_conv_iif, ARG2(2, STR, STR), NULL, SMP_T_BOOL, SMP_T_STR },
5837
5838
  { "and",    sample_conv_binary_and, ARG1(1,STR), check_operator, SMP_T_SINT, SMP_T_SINT  },
5839
  { "or",     sample_conv_binary_or,  ARG1(1,STR), check_operator, SMP_T_SINT, SMP_T_SINT  },
5840
  { "xor",    sample_conv_binary_xor, ARG1(1,STR), check_operator, SMP_T_SINT, SMP_T_SINT  },
5841
  { "cpl",    sample_conv_binary_cpl,           0, NULL, SMP_T_SINT, SMP_T_SINT  },
5842
  { "bool",   sample_conv_arith_bool,           0, NULL, SMP_T_SINT, SMP_T_BOOL },
5843
  { "not",    sample_conv_arith_not,            0, NULL, SMP_T_SINT, SMP_T_BOOL },
5844
  { "odd",    sample_conv_arith_odd,            0, NULL, SMP_T_SINT, SMP_T_BOOL },
5845
  { "even",   sample_conv_arith_even,           0, NULL, SMP_T_SINT, SMP_T_BOOL },
5846
  { "add",    sample_conv_arith_add,  ARG1(1,STR), check_operator, SMP_T_SINT, SMP_T_SINT  },
5847
  { "sub",    sample_conv_arith_sub,  ARG1(1,STR), check_operator, SMP_T_SINT, SMP_T_SINT  },
5848
  { "mul",    sample_conv_arith_mul,  ARG1(1,STR), check_operator, SMP_T_SINT, SMP_T_SINT  },
5849
  { "div",    sample_conv_arith_div,  ARG1(1,STR), check_operator, SMP_T_SINT, SMP_T_SINT  },
5850
  { "mod",    sample_conv_arith_mod,  ARG1(1,STR), check_operator, SMP_T_SINT, SMP_T_SINT  },
5851
  { "neg",    sample_conv_arith_neg,            0, NULL, SMP_T_SINT, SMP_T_SINT  },
5852
5853
  { "htonl",    sample_conv_htonl,              0, NULL, SMP_T_SINT, SMP_T_BIN  },
5854
  { "cut_crlf", sample_conv_cut_crlf,           0, NULL, SMP_T_STR,  SMP_T_STR  },
5855
  { "ltrim",    sample_conv_ltrim,    ARG1(1,STR), NULL, SMP_T_STR,  SMP_T_STR  },
5856
  { "rtrim",    sample_conv_rtrim,    ARG1(1,STR), NULL, SMP_T_STR,  SMP_T_STR  },
5857
  { "json_query", sample_conv_json_query, ARG2(1,STR,STR),  sample_check_json_query , SMP_T_STR, SMP_T_ANY },
5858
5859
#ifdef USE_OPENSSL
5860
  /* JSON Web Token converters */
5861
  { "jwt_header_query",  sample_conv_jwt_header_query,  ARG2(0,STR,STR), sample_conv_jwt_query_check,   SMP_T_BIN, SMP_T_ANY },
5862
  { "jwt_payload_query", sample_conv_jwt_payload_query, ARG2(0,STR,STR), sample_conv_jwt_query_check,   SMP_T_BIN, SMP_T_ANY },
5863
  { "jwt_verify",        sample_conv_jwt_verify,        ARG2(2,STR,STR), sample_conv_jwt_verify_check,  SMP_T_BIN, SMP_T_SINT },
5864
  { "jwt_verify_cert",   sample_conv_jwt_verify_cert,   ARG2(2,STR,STR), sample_conv_jwt_verify_cert_check,  SMP_T_BIN, SMP_T_SINT },
5865
#endif
5866
  { "when",              sample_conv_when,              ARG3(1,STR,STR,STR), check_when_cond,               SMP_T_ANY, SMP_T_ANY  },
5867
  { NULL, NULL, 0, 0, 0 },
5868
}};
5869
5870
INITCALL1(STG_REGISTER, sample_register_convs, &sample_conv_kws);