1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
|
#REGTEST_TYPE=devel
# This regtest checks the multiple conditions that can be specified to a
# set-var call (be it a converter or HTTP or TCP action). It mainly uses the
# actions but since the "var_set" function is used for the converter and for
# the actions, it should be enough to focus on one type of set-var.
# Among the variables that can be defined and the multiple scopes they can
# have, the proc scope is the only one having a specific behaviour. Proc scoped
# variables are created during init when a variable of any other scope is
# created during the first successful set-var.
# Since this test uses variables of different scopes, the validation cannot be
# based on the "show var" command of the CLI because it only displays process
# variables. It then always follows the same logic, for every sub test case :
# an HTTP header is added to the response in which we add a concatenation of
# all the tested variables (which exist in the request/response scope). These
# HTTP headers are then tested upon an expected result (which changes for every
# test case).
#
varnishtest "Test the conditional set-var converter and action"
feature cmd "$HAPROXY_PROGRAM -cc 'version_atleast(2.5-dev0)'"
feature cmd "command -v socat"
feature ignore_unknown_macro
server s1 -repeat 10 {
rxreq
txresp
} -start
haproxy h1 -conf {
global
set-var proc.int12 int(12)
set-var proc.int5 var(proc.str60,60),div(proc.int12)
defaults
mode http
timeout connect 100ms
timeout client 1s
timeout server 1s
listen main-fe
bind "fd@${mainfe}"
use_backend ifexists_be if { path_beg /ifexists }
use_backend ifnotexists_be if { path_beg /ifnotexists }
use_backend ifempty_be if { path_beg /ifempty }
use_backend ifnotempty_be if { path_beg /ifnotempty }
use_backend ifset_be if { path_beg /ifset }
use_backend ifnotset_be if { path_beg /ifnotset }
use_backend ifgt_be if { path_beg /ifgt }
use_backend iflt_be if { path_beg /iflt }
use_backend combined_be if { path_beg /combined }
use_backend converter_be if { path_beg /converter }
backend ifexists_be
server s1 ${s1_addr}:${s1_port}
# proc scope variables are created during configuration parsing so the
# ifexists condition will always be true for those variables
http-response set-var(proc.ifexists_proc,ifexists) var(proc.int12)
http-response set-var(sess.ifexists_sess,ifexists) var(proc.int5)
http-response set-var(res.ifexists_res,ifexists) str(toto)
http-response set-header x-var "proc.ifexists=%[var(proc.ifexists_proc)] sess.ifexists=%[var(sess.ifexists_sess)] res.ifexists=%[var(res.ifexists_res)]"
backend ifnotexists_be
server s1 ${s1_addr}:${s1_port}
http-response set-header x-var-init "proc.ifnotexists=%[var(proc.ifnotexists_proc)] sess.ifnotexists=%[var(sess.ifnotexists_sess)] res.ifnotexists=%[var(res.ifnotexists_res)]"
http-response set-var(proc.ifnotexists_proc,ifnotexists) var(proc.int12)
http-response set-var(sess.ifnotexists_sess,ifnotexists) var(proc.int5)
http-response set-var(res.ifnotexists_res,ifnotexists) str(toto)
http-response set-header x-var "proc.ifnotexists=%[var(proc.ifnotexists_proc)] sess.ifnotexists=%[var(sess.ifnotexists_sess)] res.ifnotexists=%[var(res.ifnotexists_res)]"
backend ifempty_be
server s1 ${s1_addr}:${s1_port}
# init
http-response set-var(proc.ifempty_proc) str(ifempty_proc)
http-response set-var(sess.ifempty_sess) bin(6966656d7074795f73657373) #ifempty_sess
http-response set-var(res.ifempty_res) str(ifempty_res)
http-response set-var(res.ifempty_res_int) int(5)
http-response set-header x-var-init "proc.ifempty=%[var(proc.ifempty_proc)] sess.ifempty=%[var(sess.ifempty_sess)] res.ifempty=%[var(res.ifempty_res)] res.ifempty_res_int=%[var(res.ifempty_res_int)]"
# None of those set-var calls should actually change their respective variables
# since none of the samples is empty
http-response set-var(proc.ifempty_proc,ifempty) int(12)
http-response set-var(sess.ifempty_sess,ifempty) bool(false)
http-response set-var(res.ifempty_res,ifempty) bin(746F746F) # "toto"
http-response set-var(res.ifempty_res_int,ifempty) str(toto)
http-response set-header x-var1 "proc.ifempty=%[var(proc.ifempty_proc)] sess.ifempty=%[var(sess.ifempty_sess)] res.ifempty=%[var(res.ifempty_res)] res.ifempty_res_int=%[var(res.ifempty_res_int)]"
http-response set-var(proc.ifempty_proc,ifempty) str()
http-response set-var(sess.ifempty_sess,ifempty) str()
http-response set-var(res.ifempty_res,ifempty) str()
http-response set-var(res.ifempty_res_int,ifempty) int(7) # should not work, scalar types are never empty
http-response set-header x-var2 "proc.ifempty=%[var(proc.ifempty_proc)] sess.ifempty=%[var(sess.ifempty_sess)] res.ifempty=%[var(res.ifempty_res)] res.ifempty_res_int=%[var(res.ifempty_res_int)]"
backend ifnotempty_be
server s1 ${s1_addr}:${s1_port}
# init
http-response set-var(proc.ifnotempty_proc) str(ifnotempty_proc)
http-response set-var(sess.ifnotempty_sess) bin(69666e6f74656d7074795f73657373) # "ifnotempty_sess"
http-response set-var(res.ifnotempty_res) str(ifnotempty_res)
http-response set-var(res.ifnotempty_res_int) int(5)
http-response set-header x-var-init "proc.ifnotempty=%[var(proc.ifnotempty_proc)] sess.ifnotempty=%[var(sess.ifnotempty_sess)] res.ifnotempty=%[var(res.ifnotempty_res)] res.ifnotempty_res_int=%[var(res.ifnotempty_res_int)]"
# None of those set-var calls should actually change their respective variables
# since none of the samples is not empty
http-response set-var(proc.ifnotempty_proc,ifnotempty) str(toto)
http-response set-var(sess.ifnotempty_sess,ifnotempty) bin(746F746F) # "toto"
http-response set-var(res.ifnotempty_res,ifnotempty) str(tata)
http-response set-var(res.ifnotempty_res_int,ifnotempty) int(6)
http-response set-header x-var1 "proc.ifnotempty=%[var(proc.ifnotempty_proc)] sess.ifnotempty=%[var(sess.ifnotempty_sess)] res.ifnotempty=%[var(res.ifnotempty_res)] res.ifnotempty_res_int=%[var(res.ifnotempty_res_int)]"
# The first three variables should remain unchanged.
http-response set-var(proc.ifnotempty_proc,ifnotempty) str()
http-response set-var(sess.ifnotempty_sess,ifnotempty) str()
http-response set-var(res.ifnotempty_res,ifnotempty) str()
http-response set-var(res.ifnotempty_res_int,ifnotempty) int(7) # should not work
http-response set-header x-var2 "proc.ifnotempty=%[var(proc.ifnotempty_proc)] sess.ifnotempty=%[var(sess.ifnotempty_sess)] res.ifnotempty=%[var(res.ifnotempty_res)] res.ifnotempty_res_int=%[var(res.ifnotempty_res_int)]"
backend ifset_be
server s1 ${s1_addr}:${s1_port}
# init
http-response set-var(proc.ifset_proc) str(ifset_proc)
http-response set-var(sess.ifset_sess) bin(69667365745f73657373) # "ifset_sess"
http-response set-var(res.ifset_res) str(ifset_res)
http-response set-var(res.ifset_res_int) int(5)
http-response set-header x-var-init "proc.ifset=%[var(proc.ifset_proc)] sess.ifset=%[var(sess.ifset_sess)] res.ifset=%[var(res.ifset_res)] res.ifset_res_int=%[var(res.ifset_res_int)]"
# All those set-var calls should succeed
http-response set-var(proc.ifset_proc,ifset) str(toto)
http-response set-var(sess.ifset_sess,ifset) bin(746F746F) # "toto"
http-response set-var(res.ifset_res,ifset) int(123)
http-response set-var(res.ifset_res_int,ifset) str(azerty)
http-response set-header x-var1 "proc.ifset=%[var(proc.ifset_proc)] sess.ifset=%[var(sess.ifset_sess)] res.ifset=%[var(res.ifset_res)] res.ifset_res_int=%[var(res.ifset_res_int)]"
http-response unset-var(proc.ifset_proc)
http-response unset-var(sess.ifset_sess)
http-response unset-var(res.ifset_res)
http-response unset-var(res.ifset_res_int)
http-response set-header x-var2 "proc.ifset=%[var(proc.ifset_proc)] sess.ifset=%[var(sess.ifset_sess)] res.ifset=%[var(res.ifset_res)] res.ifset_res_int=%[var(res.ifset_res_int)]"
# None of those set-var calls should succeed
http-response set-var(proc.ifset_proc,ifset) str(toto)
http-response set-var(sess.ifset_sess,ifset) bin(746F746F) # "toto"
http-response set-var(res.ifset_res,ifset) int(123)
http-response set-var(res.ifset_res_int,ifset) str(azerty)
http-response set-header x-var3 "proc.ifset=%[var(proc.ifset_proc)] sess.ifset=%[var(sess.ifset_sess)] res.ifset=%[var(res.ifset_res)] res.ifset_res_int=%[var(res.ifset_res_int)]"
backend ifnotset_be
server s1 ${s1_addr}:${s1_port}
# init
http-response set-var(proc.ifnotset_proc) str(ifnotset_proc)
http-response set-var(sess.ifnotset_sess) bin(69666e6f747365745f73657373) # "ifnotset_sess"
http-response set-var(res.ifnotset_res) str(ifnotset_res)
http-response set-var(res.ifnotset_res_int) int(5)
http-response set-header x-var-init "proc.ifnotset=%[var(proc.ifnotset_proc)] sess.ifnotset=%[var(sess.ifnotset_sess)] res.ifnotset=%[var(res.ifnotset_res)] res.ifnotset_res_int=%[var(res.ifnotset_res_int)]"
# None of those set-var calls should succeed
http-response set-var(proc.ifnotset_proc,ifnotset) str(toto)
http-response set-var(sess.ifnotset_sess,ifnotset) bin(746F746F) # "toto"
http-response set-var(res.ifnotset_res,ifnotset) int(123)
http-response set-var(res.ifnotset_res_int,ifnotset) str(azerty)
http-response set-header x-var1 "proc.ifnotset=%[var(proc.ifnotset_proc)] sess.ifnotset=%[var(sess.ifnotset_sess)] res.ifnotset=%[var(res.ifnotset_res)] res.ifnotset_res_int=%[var(res.ifnotset_res_int)]"
http-response unset-var(proc.ifnotset_proc)
http-response unset-var(sess.ifnotset_sess)
http-response unset-var(res.ifnotset_res)
http-response unset-var(res.ifnotset_res_int)
http-response set-header x-var2 "proc.ifnotset=%[var(proc.ifnotset_proc)] sess.ifnotset=%[var(sess.ifnotset_sess)] res.ifnotset=%[var(res.ifnotset_res)] res.ifnotset_res_int=%[var(res.ifnotset_res_int)]"
# All of those set-var calls should succeed
http-response set-var(proc.ifnotset_proc,ifnotset) str(toto)
http-response set-var(sess.ifnotset_sess,ifnotset) bin(746F746F) # "toto"
http-response set-var(res.ifnotset_res,ifnotset) int(123)
http-response set-var(res.ifnotset_res_int,ifnotset) str(azerty)
http-response set-header x-var3 "proc.ifnotset=%[var(proc.ifnotset_proc)] sess.ifnotset=%[var(sess.ifnotset_sess)] res.ifnotset=%[var(res.ifnotset_res)] res.ifnotset_res_int=%[var(res.ifnotset_res_int)]"
backend ifgt_be
server s1 ${s1_addr}:${s1_port}
# init
http-response set-var(proc.ifgt_proc) str(ifgt_proc)
http-response set-var(sess.ifgt_sess) bin(696667745f73657373) # "ifgt_sess"
http-response set-var(res.ifgt_res1) str(ifgt_res)
http-response set-var(res.ifgt_res2) int(5)
http-response set-var(res.ifgt_res_int1) int(5)
http-response set-var(res.ifgt_res_int2) int(5)
http-response set-header x-var-init "proc.ifgt=%[var(proc.ifgt_proc)] sess.ifgt=%[var(sess.ifgt_sess)] res.ifgt1=%[var(res.ifgt_res1)] res.ifgt2=%[var(res.ifgt_res2)] res.ifgt_res_int1=%[var(res.ifgt_res_int1)] res.ifgt_res_int2=%[var(res.ifgt_res_int2)]"
# ifgt does not apply on non scalar type so the two following set-var will ignore the condition
http-response set-var(proc.ifgt_proc,ifgt) str(toto)
http-response set-var(sess.ifgt_sess,ifgt) bin(746F746F) # "toto"
# ifgt can only apply when the variable and the sample are both scalar. In this case, the variable was a string so the condition is ignored
http-response set-var(res.ifgt_res1,ifgt) int(55)
# ifgt can only apply when the variable and the sample are both scalar. In this case, the sample is a string so the condition is ignored
http-response set-var(res.ifgt_res2,ifgt) str(text)
http-response set-var(res.ifgt_res_int1,ifgt) int(55) # should not work
http-response set-var(res.ifgt_res_int2,ifgt) int(2) # should work
http-response set-header x-var1 "proc.ifgt=%[var(proc.ifgt_proc)] sess.ifgt=%[var(sess.ifgt_sess)] res.ifgt1=%[var(res.ifgt_res1)] res.ifgt2=%[var(res.ifgt_res2)] res.ifgt_res_int1=%[var(res.ifgt_res_int1)] res.ifgt_res_int2=%[var(res.ifgt_res_int2)]"
backend iflt_be
server s1 ${s1_addr}:${s1_port}
# init
http-response set-var(proc.iflt_proc) str(iflt_proc)
http-response set-var(sess.iflt_sess) bin(69666c745f73657373) # "iflt_sess"
http-response set-var(res.iflt_res1) str(iflt_res)
http-response set-var(res.iflt_res2) int(5)
http-response set-var(res.iflt_res_int1) int(5)
http-response set-var(res.iflt_res_int2) int(5)
http-response set-header x-var-init "proc.iflt=%[var(proc.iflt_proc)] sess.iflt=%[var(sess.iflt_sess)] res.iflt1=%[var(res.iflt_res1)] res.iflt2=%[var(res.iflt_res2)] res.iflt_res_int1=%[var(res.iflt_res_int1)] res.iflt_res_int2=%[var(res.iflt_res_int2)]"
# iflt does not apply on non scalar type so the two following set-var will ignore the condition
http-response set-var(proc.iflt_proc,iflt) str(toto)
http-response set-var(sess.iflt_sess,iflt) bin(746F746F) # "toto"
# iflt can only apply when the variable and the sample are both scalar. In this case, the variable was a string so the condition is ignored
http-response set-var(res.iflt_res1,iflt) int(55)
# iflt can only apply when the variable and the sample are both scalar. In this case, the sample is a string so the condition is ignored
http-response set-var(res.iflt_res2,iflt) str(text)
http-response set-var(res.iflt_res_int1,iflt) int(55) # should work
http-response set-var(res.iflt_res_int2,iflt) int(2) # should not work
http-response set-header x-var1 "proc.iflt=%[var(proc.iflt_proc)] sess.iflt=%[var(sess.iflt_sess)] res.iflt1=%[var(res.iflt_res1)] res.iflt2=%[var(res.iflt_res2)] res.iflt_res_int1=%[var(res.iflt_res_int1)] res.iflt_res_int2=%[var(res.iflt_res_int2)]"
# Test multiple conditions at once
backend combined_be
server s1 ${s1_addr}:${s1_port}
# init
http-response set-var(proc.combined_proc) str(combined_proc)
http-response set-var(res.combined_res) int(5)
http-response unset-var(proc.combined_proc)
http-response set-header x-var-init "proc.combined=%[var(proc.combined_proc)] res.combined=%[var(res.combined_res)]"
http-response set-var(proc.combined_proc,ifnotset,ifnotempty) str(toto)
http-response set-var(res.combined_res,ifset,iflt) int(55)
http-response set-header x-var1 "proc.combined=%[var(proc.combined_proc)] res.combined=%[var(res.combined_res)]"
# Test the set-var converter
backend converter_be
server s1 ${s1_addr}:${s1_port}
http-request deny if { req.len,set-var(proc.req_len,ifexists) -m int 0 }
http-request deny if { req.hdr("X-Cust"),set-var(sess.x_cust,ifnotempty,ifnotset),length -m int 0 }
http-response set-header x-var "proc.req_len=%[var(proc.req_len)] sess.x_cust=%[var(sess.x_cust)]"
} -start
client c1 -connect ${h1_mainfe_sock} {
txreq -url "/ifexists"
rxresp
expect resp.status == 200
expect resp.http.x-var == "proc.ifexists=12 sess.ifexists= res.ifexists="
} -run
client c2 -connect ${h1_mainfe_sock} {
txreq -url "/ifnotexists"
rxresp
expect resp.status == 200
expect resp.http.x-var-init == "proc.ifnotexists= sess.ifnotexists= res.ifnotexists="
expect resp.http.x-var == "proc.ifnotexists= sess.ifnotexists=5 res.ifnotexists=toto"
} -run
client c3 -connect ${h1_mainfe_sock} {
txreq -url "/ifempty"
rxresp
expect resp.status == 200
expect resp.http.x-var-init == "proc.ifempty=ifempty_proc sess.ifempty=ifempty_sess res.ifempty=ifempty_res res.ifempty_res_int=5"
expect resp.http.x-var1 == "proc.ifempty=ifempty_proc sess.ifempty=ifempty_sess res.ifempty=ifempty_res res.ifempty_res_int=5"
expect resp.http.x-var2 == "proc.ifempty= sess.ifempty= res.ifempty= res.ifempty_res_int=5"
} -run
client c4 -connect ${h1_mainfe_sock} {
txreq -url "/ifnotempty"
rxresp
expect resp.status == 200
expect resp.http.x-var-init == "proc.ifnotempty=ifnotempty_proc sess.ifnotempty=ifnotempty_sess res.ifnotempty=ifnotempty_res res.ifnotempty_res_int=5"
expect resp.http.x-var1 == "proc.ifnotempty=toto sess.ifnotempty=toto res.ifnotempty=tata res.ifnotempty_res_int=6"
expect resp.http.x-var2 == "proc.ifnotempty=toto sess.ifnotempty=toto res.ifnotempty=tata res.ifnotempty_res_int=7"
} -run
client c5 -connect ${h1_mainfe_sock} {
txreq -url "/ifset"
rxresp
expect resp.status == 200
expect resp.http.x-var-init == "proc.ifset=ifset_proc sess.ifset=ifset_sess res.ifset=ifset_res res.ifset_res_int=5"
expect resp.http.x-var1 == "proc.ifset=toto sess.ifset=toto res.ifset=123 res.ifset_res_int=azerty"
expect resp.http.x-var2 == "proc.ifset= sess.ifset= res.ifset= res.ifset_res_int="
expect resp.http.x-var3 == "proc.ifset= sess.ifset= res.ifset= res.ifset_res_int="
} -run
client c6 -connect ${h1_mainfe_sock} {
txreq -url "/ifnotset"
rxresp
expect resp.status == 200
expect resp.http.x-var-init == "proc.ifnotset=ifnotset_proc sess.ifnotset=ifnotset_sess res.ifnotset=ifnotset_res res.ifnotset_res_int=5"
expect resp.http.x-var1 == "proc.ifnotset=ifnotset_proc sess.ifnotset=ifnotset_sess res.ifnotset=ifnotset_res res.ifnotset_res_int=5"
expect resp.http.x-var2 == "proc.ifnotset= sess.ifnotset= res.ifnotset= res.ifnotset_res_int="
expect resp.http.x-var3 == "proc.ifnotset=toto sess.ifnotset=toto res.ifnotset=123 res.ifnotset_res_int=azerty"
} -run
client c7 -connect ${h1_mainfe_sock} {
txreq -url "/ifgt"
rxresp
expect resp.status == 200
expect resp.http.x-var-init == "proc.ifgt=ifgt_proc sess.ifgt=ifgt_sess res.ifgt1=ifgt_res res.ifgt2=5 res.ifgt_res_int1=5 res.ifgt_res_int2=5"
expect resp.http.x-var1 == "proc.ifgt=toto sess.ifgt=toto res.ifgt1=55 res.ifgt2=text res.ifgt_res_int1=5 res.ifgt_res_int2=2"
} -run
client c8 -connect ${h1_mainfe_sock} {
txreq -url "/iflt"
rxresp
expect resp.status == 200
expect resp.http.x-var-init == "proc.iflt=iflt_proc sess.iflt=iflt_sess res.iflt1=iflt_res res.iflt2=5 res.iflt_res_int1=5 res.iflt_res_int2=5"
expect resp.http.x-var1 == "proc.iflt=toto sess.iflt=toto res.iflt1=55 res.iflt2=text res.iflt_res_int1=55 res.iflt_res_int2=5"
} -run
client c9 -connect ${h1_mainfe_sock} {
txreq -url "/combined"
rxresp
expect resp.status == 200
expect resp.http.x-var-init == "proc.combined= res.combined=5"
expect resp.http.x-var1 == "proc.combined=toto res.combined=55"
} -run
client c10 -connect ${h1_mainfe_sock} {
txreq -url "/converter" -hdr "X-Cust: foobar"
rxresp
expect resp.status == 200
expect resp.http.x-var == "proc.req_len=67 sess.x_cust=foobar"
} -run
|