blob: 52b77c604f7f0b25280d224b0b98551414293d85 [file] [log] [blame]
Willy Tarreau61c112a2018-10-02 16:43:32 +02001/*
2 * HTTP rules parsing and registration
3 *
4 * Copyright 2000-2018 Willy Tarreau <w@1wt.eu>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 *
11 */
12
13#include <sys/types.h>
14
15#include <ctype.h>
16#include <string.h>
17#include <time.h>
18
Willy Tarreaudcc048a2020-06-04 19:11:43 +020019#include <haproxy/acl.h>
Willy Tarreau122eba92020-06-04 10:15:32 +020020#include <haproxy/action.h>
Willy Tarreau4c7e4b72020-05-27 12:58:42 +020021#include <haproxy/api.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020022#include <haproxy/arg.h>
23#include <haproxy/capture-t.h>
Willy Tarreau6be78492020-06-05 00:00:29 +020024#include <haproxy/cfgparse.h>
Willy Tarreauc13ed532020-06-02 10:22:45 +020025#include <haproxy/chunk.h>
Willy Tarreaudfd3de82020-06-04 23:46:14 +020026#include <haproxy/global.h>
Willy Tarreaucd72d8c2020-06-02 19:11:26 +020027#include <haproxy/http.h>
Willy Tarreauc761f842020-06-04 11:40:28 +020028#include <haproxy/http_rules.h>
Willy Tarreau36979d92020-06-05 17:27:29 +020029#include <haproxy/log.h>
Willy Tarreaud0ef4392020-06-02 09:38:52 +020030#include <haproxy/pool.h>
Willy Tarreaud1dd2502021-05-08 20:30:37 +020031#include <haproxy/proxy.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020032#include <haproxy/sample.h>
Willy Tarreau48fbcae2020-06-03 18:09:46 +020033#include <haproxy/tools.h>
Willy Tarreaud6788052020-05-27 15:59:00 +020034#include <haproxy/version.h>
Willy Tarreau61c112a2018-10-02 16:43:32 +020035
Willy Tarreau61c112a2018-10-02 16:43:32 +020036
37/* List head of all known action keywords for "http-request" */
38struct action_kw_list http_req_keywords = {
39 .list = LIST_HEAD_INIT(http_req_keywords.list)
40};
41
42/* List head of all known action keywords for "http-response" */
43struct action_kw_list http_res_keywords = {
44 .list = LIST_HEAD_INIT(http_res_keywords.list)
45};
46
Christopher Faulet6d0c3df2020-01-22 09:26:35 +010047/* List head of all known action keywords for "http-after-response" */
48struct action_kw_list http_after_res_keywords = {
49 .list = LIST_HEAD_INIT(http_after_res_keywords.list)
50};
51
Willy Tarreau61c112a2018-10-02 16:43:32 +020052/*
53 * Return the struct http_req_action_kw associated to a keyword.
54 */
Thierry Fournier7a71a6d2020-11-28 17:40:24 +010055struct action_kw *action_http_req_custom(const char *kw)
Willy Tarreau61c112a2018-10-02 16:43:32 +020056{
57 return action_lookup(&http_req_keywords.list, kw);
58}
59
60/*
61 * Return the struct http_res_action_kw associated to a keyword.
62 */
Thierry Fournier7a71a6d2020-11-28 17:40:24 +010063struct action_kw *action_http_res_custom(const char *kw)
Willy Tarreau61c112a2018-10-02 16:43:32 +020064{
65 return action_lookup(&http_res_keywords.list, kw);
66}
67
Christopher Faulet6d0c3df2020-01-22 09:26:35 +010068/*
69 * Return the struct http_after_res_action_kw associated to a keyword.
70 */
Thierry Fournier7a71a6d2020-11-28 17:40:24 +010071struct action_kw *action_http_after_res_custom(const char *kw)
Christopher Faulet6d0c3df2020-01-22 09:26:35 +010072{
73 return action_lookup(&http_after_res_keywords.list, kw);
74}
75
Willy Tarreau61c112a2018-10-02 16:43:32 +020076/* parse an "http-request" rule */
77struct act_rule *parse_http_req_cond(const char **args, const char *file, int linenum, struct proxy *proxy)
78{
79 struct act_rule *rule;
Willy Tarreau49bf7be2021-03-12 12:01:34 +010080 const struct action_kw *custom = NULL;
Willy Tarreau61c112a2018-10-02 16:43:32 +020081 int cur_arg;
Willy Tarreau61c112a2018-10-02 16:43:32 +020082
83 rule = calloc(1, sizeof(*rule));
84 if (!rule) {
85 ha_alert("parsing [%s:%d]: out of memory.\n", file, linenum);
86 goto out_err;
87 }
Christopher Faulet81e20172019-12-12 16:40:30 +010088 rule->from = ACT_F_HTTP_REQ;
Willy Tarreau61c112a2018-10-02 16:43:32 +020089
Christopher Faulet81e20172019-12-12 16:40:30 +010090 if (((custom = action_http_req_custom(args[0])) != NULL)) {
Willy Tarreau61c112a2018-10-02 16:43:32 +020091 char *errmsg = NULL;
92
Willy Tarreau61c112a2018-10-02 16:43:32 +020093 cur_arg = 1;
94 /* try in the module list */
Willy Tarreau61c112a2018-10-02 16:43:32 +020095 rule->kw = custom;
Amaury Denoyelle03517732021-05-07 14:25:01 +020096
97 if (custom->flags & KWF_EXPERIMENTAL) {
98 if (!experimental_directives_allowed) {
99 ha_alert("parsing [%s:%d] : '%s' action is experimental, must be allowed via a global 'expose-experimental-directives'\n",
100 file, linenum, custom->kw);
101 goto out_err;
102 }
103 mark_tainted(TAINTED_CONFIG_EXP_KW_DECLARED);
104 }
105
Willy Tarreau61c112a2018-10-02 16:43:32 +0200106 if (custom->parse(args, &cur_arg, proxy, rule, &errmsg) == ACT_RET_PRS_ERR) {
107 ha_alert("parsing [%s:%d] : error detected in %s '%s' while parsing 'http-request %s' rule : %s.\n",
108 file, linenum, proxy_type_str(proxy), proxy->id, args[0], errmsg);
109 free(errmsg);
110 goto out_err;
111 }
Christopher Faulet81e20172019-12-12 16:40:30 +0100112 else if (errmsg) {
113 ha_warning("parsing [%s:%d] : %s.\n", file, linenum, errmsg);
114 free(errmsg);
115 }
116 }
117 else {
Willy Tarreau49bf7be2021-03-12 12:01:34 +0100118 const char *best = action_suggest(args[0], &http_req_keywords.list, NULL);
119
Willy Tarreau61c112a2018-10-02 16:43:32 +0200120 action_build_list(&http_req_keywords.list, &trash);
Willy Tarreau49bf7be2021-03-12 12:01:34 +0100121 ha_alert("parsing [%s:%d]: 'http-request' expects %s, but got '%s'%s.%s%s%s\n",
122 file, linenum, trash.area,
123 args[0], *args[0] ? "" : " (missing argument)",
124 best ? " Did you mean '" : "",
125 best ? best : "",
126 best ? "' maybe ?" : "");
Willy Tarreau61c112a2018-10-02 16:43:32 +0200127 goto out_err;
128 }
129
130 if (strcmp(args[cur_arg], "if") == 0 || strcmp(args[cur_arg], "unless") == 0) {
131 struct acl_cond *cond;
132 char *errmsg = NULL;
133
134 if ((cond = build_acl_cond(file, linenum, &proxy->acl, proxy, args+cur_arg, &errmsg)) == NULL) {
135 ha_alert("parsing [%s:%d] : error detected while parsing an 'http-request %s' condition : %s.\n",
136 file, linenum, args[0], errmsg);
137 free(errmsg);
138 goto out_err;
139 }
140 rule->cond = cond;
141 }
142 else if (*args[cur_arg]) {
Christopher Faulet81e20172019-12-12 16:40:30 +0100143 ha_alert("parsing [%s:%d]: 'http-request %s' expects"
Willy Tarreau61c112a2018-10-02 16:43:32 +0200144 " either 'if' or 'unless' followed by a condition but found '%s'.\n",
145 file, linenum, args[0], args[cur_arg]);
146 goto out_err;
147 }
148
149 return rule;
150 out_err:
151 free(rule);
152 return NULL;
153}
154
155/* parse an "http-respose" rule */
156struct act_rule *parse_http_res_cond(const char **args, const char *file, int linenum, struct proxy *proxy)
157{
158 struct act_rule *rule;
Willy Tarreau49bf7be2021-03-12 12:01:34 +0100159 const struct action_kw *custom = NULL;
Willy Tarreau61c112a2018-10-02 16:43:32 +0200160 int cur_arg;
Willy Tarreau61c112a2018-10-02 16:43:32 +0200161
162 rule = calloc(1, sizeof(*rule));
163 if (!rule) {
164 ha_alert("parsing [%s:%d]: out of memory.\n", file, linenum);
165 goto out_err;
166 }
Christopher Faulet81e20172019-12-12 16:40:30 +0100167 rule->from = ACT_F_HTTP_RES;
Willy Tarreau61c112a2018-10-02 16:43:32 +0200168
Christopher Faulet81e20172019-12-12 16:40:30 +0100169 if (((custom = action_http_res_custom(args[0])) != NULL)) {
Willy Tarreau61c112a2018-10-02 16:43:32 +0200170 char *errmsg = NULL;
171
Willy Tarreau61c112a2018-10-02 16:43:32 +0200172 cur_arg = 1;
173 /* try in the module list */
Willy Tarreau61c112a2018-10-02 16:43:32 +0200174 rule->kw = custom;
Amaury Denoyelle03517732021-05-07 14:25:01 +0200175
176 if (custom->flags & KWF_EXPERIMENTAL) {
177 if (!experimental_directives_allowed) {
178 ha_alert("parsing [%s:%d] : '%s' action is experimental, must be allowed via a global 'expose-experimental-directives'\n",
179 file, linenum, custom->kw);
180 goto out_err;
181 }
182 mark_tainted(TAINTED_CONFIG_EXP_KW_DECLARED);
183 }
184
Willy Tarreau61c112a2018-10-02 16:43:32 +0200185 if (custom->parse(args, &cur_arg, proxy, rule, &errmsg) == ACT_RET_PRS_ERR) {
186 ha_alert("parsing [%s:%d] : error detected in %s '%s' while parsing 'http-response %s' rule : %s.\n",
187 file, linenum, proxy_type_str(proxy), proxy->id, args[0], errmsg);
188 free(errmsg);
189 goto out_err;
190 }
Christopher Faulet81e20172019-12-12 16:40:30 +0100191 else if (errmsg) {
192 ha_warning("parsing [%s:%d] : %s.\n", file, linenum, errmsg);
193 free(errmsg);
194 }
195 }
196 else {
Willy Tarreau49bf7be2021-03-12 12:01:34 +0100197 const char *best = action_suggest(args[0], &http_res_keywords.list, NULL);
198
Willy Tarreau61c112a2018-10-02 16:43:32 +0200199 action_build_list(&http_res_keywords.list, &trash);
Willy Tarreau49bf7be2021-03-12 12:01:34 +0100200 ha_alert("parsing [%s:%d]: 'http-response' expects %s, but got '%s'%s.%s%s%s\n",
201 file, linenum, trash.area,
202 args[0], *args[0] ? "" : " (missing argument)",
203 best ? " Did you mean '" : "",
204 best ? best : "",
205 best ? "' maybe ?" : "");
Willy Tarreau61c112a2018-10-02 16:43:32 +0200206 goto out_err;
207 }
208
209 if (strcmp(args[cur_arg], "if") == 0 || strcmp(args[cur_arg], "unless") == 0) {
210 struct acl_cond *cond;
211 char *errmsg = NULL;
212
213 if ((cond = build_acl_cond(file, linenum, &proxy->acl, proxy, args+cur_arg, &errmsg)) == NULL) {
214 ha_alert("parsing [%s:%d] : error detected while parsing an 'http-response %s' condition : %s.\n",
215 file, linenum, args[0], errmsg);
216 free(errmsg);
217 goto out_err;
218 }
219 rule->cond = cond;
220 }
221 else if (*args[cur_arg]) {
222 ha_alert("parsing [%s:%d]: 'http-response %s' expects"
223 " either 'if' or 'unless' followed by a condition but found '%s'.\n",
224 file, linenum, args[0], args[cur_arg]);
225 goto out_err;
226 }
227
228 return rule;
229 out_err:
230 free(rule);
231 return NULL;
232}
233
Christopher Faulet6d0c3df2020-01-22 09:26:35 +0100234
235/* parse an "http-after-response" rule */
236struct act_rule *parse_http_after_res_cond(const char **args, const char *file, int linenum, struct proxy *proxy)
237{
238 struct act_rule *rule;
Willy Tarreau49bf7be2021-03-12 12:01:34 +0100239 const struct action_kw *custom = NULL;
Christopher Faulet6d0c3df2020-01-22 09:26:35 +0100240 int cur_arg;
241
242 rule = calloc(1, sizeof(*rule));
243 if (!rule) {
244 ha_alert("parsing [%s:%d]: out of memory.\n", file, linenum);
245 goto out_err;
246 }
247 rule->from = ACT_F_HTTP_RES;
248
249 if (((custom = action_http_after_res_custom(args[0])) != NULL)) {
250 char *errmsg = NULL;
251
252 cur_arg = 1;
253 /* try in the module list */
254 rule->kw = custom;
255 if (custom->parse(args, &cur_arg, proxy, rule, &errmsg) == ACT_RET_PRS_ERR) {
256 ha_alert("parsing [%s:%d] : error detected in %s '%s' while parsing 'http-after-response %s' rule : %s.\n",
257 file, linenum, proxy_type_str(proxy), proxy->id, args[0], errmsg);
258 free(errmsg);
259 goto out_err;
260 }
261 else if (errmsg) {
262 ha_warning("parsing [%s:%d] : %s.\n", file, linenum, errmsg);
263 free(errmsg);
264 }
265 }
266 else {
Willy Tarreau49bf7be2021-03-12 12:01:34 +0100267 const char *best = action_suggest(args[0], &http_after_res_keywords.list, NULL);
268
Christopher Faulet6d0c3df2020-01-22 09:26:35 +0100269 action_build_list(&http_after_res_keywords.list, &trash);
Willy Tarreau49bf7be2021-03-12 12:01:34 +0100270 ha_alert("parsing [%s:%d]: 'http-after-response' expects %s, but got '%s'%s.%s%s%s\n",
271 file, linenum, trash.area,
272 args[0], *args[0] ? "" : " (missing argument)",
273 best ? " Did you mean '" : "",
274 best ? best : "",
275 best ? "' maybe ?" : "");
Christopher Faulet6d0c3df2020-01-22 09:26:35 +0100276 goto out_err;
277 }
278
279 if (strcmp(args[cur_arg], "if") == 0 || strcmp(args[cur_arg], "unless") == 0) {
280 struct acl_cond *cond;
281 char *errmsg = NULL;
282
283 if ((cond = build_acl_cond(file, linenum, &proxy->acl, proxy, args+cur_arg, &errmsg)) == NULL) {
284 ha_alert("parsing [%s:%d] : error detected while parsing an 'http-after-response %s' condition : %s.\n",
285 file, linenum, args[0], errmsg);
286 free(errmsg);
287 goto out_err;
288 }
289 rule->cond = cond;
290 }
291 else if (*args[cur_arg]) {
292 ha_alert("parsing [%s:%d]: 'http-after-response %s' expects"
293 " either 'if' or 'unless' followed by a condition but found '%s'.\n",
294 file, linenum, args[0], args[cur_arg]);
295 goto out_err;
296 }
297
298 return rule;
299 out_err:
300 free(rule);
301 return NULL;
302}
303
Aurelien DARRAGON83dd38e2023-05-11 10:30:27 +0200304/* completely free redirect rule */
305void http_free_redirect_rule(struct redirect_rule *rdr)
306{
307 struct logformat_node *lf, *lfb;
308
309 if (rdr->cond) {
310 prune_acl_cond(rdr->cond);
311 free(rdr->cond);
312 }
313 free(rdr->rdr_str);
314 free(rdr->cookie_str);
315 list_for_each_entry_safe(lf, lfb, &rdr->rdr_fmt, list) {
316 LIST_DELETE(&lf->list);
317 release_sample_expr(lf->expr);
318 free(lf->arg);
319 free(lf);
320 }
321 free(rdr);
322}
323
Willy Tarreau61c112a2018-10-02 16:43:32 +0200324/* Parses a redirect rule. Returns the redirect rule on success or NULL on error,
325 * with <err> filled with the error message. If <use_fmt> is not null, builds a
326 * dynamic log-format rule instead of a static string. Parameter <dir> indicates
327 * the direction of the rule, and equals 0 for request, non-zero for responses.
328 */
329struct redirect_rule *http_parse_redirect_rule(const char *file, int linenum, struct proxy *curproxy,
330 const char **args, char **errmsg, int use_fmt, int dir)
331{
Aurelien DARRAGON2369a5e2023-05-11 10:34:49 +0200332 struct redirect_rule *rule = NULL;
Willy Tarreau61c112a2018-10-02 16:43:32 +0200333 int cur_arg;
334 int type = REDIRECT_TYPE_NONE;
335 int code = 302;
336 const char *destination = NULL;
337 const char *cookie = NULL;
338 int cookie_set = 0;
Christopher Fauletc87e4682020-01-28 09:13:41 +0100339 unsigned int flags = (!dir ? REDIRECT_FLAG_FROM_REQ : REDIRECT_FLAG_NONE);
Willy Tarreau61c112a2018-10-02 16:43:32 +0200340 struct acl_cond *cond = NULL;
341
342 cur_arg = 0;
343 while (*(args[cur_arg])) {
344 if (strcmp(args[cur_arg], "location") == 0) {
345 if (!*args[cur_arg + 1])
346 goto missing_arg;
347
348 type = REDIRECT_TYPE_LOCATION;
349 cur_arg++;
350 destination = args[cur_arg];
351 }
352 else if (strcmp(args[cur_arg], "prefix") == 0) {
353 if (!*args[cur_arg + 1])
354 goto missing_arg;
355 type = REDIRECT_TYPE_PREFIX;
356 cur_arg++;
357 destination = args[cur_arg];
358 }
359 else if (strcmp(args[cur_arg], "scheme") == 0) {
360 if (!*args[cur_arg + 1])
361 goto missing_arg;
362
363 type = REDIRECT_TYPE_SCHEME;
364 cur_arg++;
365 destination = args[cur_arg];
366 }
367 else if (strcmp(args[cur_arg], "set-cookie") == 0) {
368 if (!*args[cur_arg + 1])
369 goto missing_arg;
370
371 cur_arg++;
372 cookie = args[cur_arg];
373 cookie_set = 1;
374 }
375 else if (strcmp(args[cur_arg], "clear-cookie") == 0) {
376 if (!*args[cur_arg + 1])
377 goto missing_arg;
378
379 cur_arg++;
380 cookie = args[cur_arg];
381 cookie_set = 0;
382 }
383 else if (strcmp(args[cur_arg], "code") == 0) {
384 if (!*args[cur_arg + 1])
385 goto missing_arg;
386
387 cur_arg++;
388 code = atol(args[cur_arg]);
389 if (code < 301 || code > 308 || (code > 303 && code < 307)) {
390 memprintf(errmsg,
391 "'%s': unsupported HTTP code '%s' (must be one of 301, 302, 303, 307 or 308)",
392 args[cur_arg - 1], args[cur_arg]);
Aurelien DARRAGON2369a5e2023-05-11 10:34:49 +0200393 goto err;
Willy Tarreau61c112a2018-10-02 16:43:32 +0200394 }
395 }
Tim Duesterhuse5ff1412021-01-02 22:31:53 +0100396 else if (strcmp(args[cur_arg], "drop-query") == 0) {
Willy Tarreau61c112a2018-10-02 16:43:32 +0200397 flags |= REDIRECT_FLAG_DROP_QS;
398 }
Tim Duesterhuse5ff1412021-01-02 22:31:53 +0100399 else if (strcmp(args[cur_arg], "append-slash") == 0) {
Willy Tarreau61c112a2018-10-02 16:43:32 +0200400 flags |= REDIRECT_FLAG_APPEND_SLASH;
401 }
402 else if (strcmp(args[cur_arg], "if") == 0 ||
403 strcmp(args[cur_arg], "unless") == 0) {
404 cond = build_acl_cond(file, linenum, &curproxy->acl, curproxy, (const char **)args + cur_arg, errmsg);
405 if (!cond) {
406 memprintf(errmsg, "error in condition: %s", *errmsg);
Aurelien DARRAGON2369a5e2023-05-11 10:34:49 +0200407 goto err;
Willy Tarreau61c112a2018-10-02 16:43:32 +0200408 }
409 break;
410 }
411 else {
412 memprintf(errmsg,
413 "expects 'code', 'prefix', 'location', 'scheme', 'set-cookie', 'clear-cookie', 'drop-query' or 'append-slash' (was '%s')",
414 args[cur_arg]);
Aurelien DARRAGON2369a5e2023-05-11 10:34:49 +0200415 goto err;
Willy Tarreau61c112a2018-10-02 16:43:32 +0200416 }
417 cur_arg++;
418 }
419
420 if (type == REDIRECT_TYPE_NONE) {
421 memprintf(errmsg, "redirection type expected ('prefix', 'location', or 'scheme')");
Aurelien DARRAGON2369a5e2023-05-11 10:34:49 +0200422 goto err;
Willy Tarreau61c112a2018-10-02 16:43:32 +0200423 }
424
425 if (dir && type != REDIRECT_TYPE_LOCATION) {
426 memprintf(errmsg, "response only supports redirect type 'location'");
Aurelien DARRAGON2369a5e2023-05-11 10:34:49 +0200427 goto err;
Willy Tarreau61c112a2018-10-02 16:43:32 +0200428 }
429
430 rule = calloc(1, sizeof(*rule));
Aurelien DARRAGON2369a5e2023-05-11 10:34:49 +0200431 if (!rule)
432 goto out_of_memory;
Willy Tarreau61c112a2018-10-02 16:43:32 +0200433 rule->cond = cond;
434 LIST_INIT(&rule->rdr_fmt);
435
436 if (!use_fmt) {
437 /* old-style static redirect rule */
438 rule->rdr_str = strdup(destination);
Aurelien DARRAGON2369a5e2023-05-11 10:34:49 +0200439 if (!rule->rdr_str)
440 goto out_of_memory;
Willy Tarreau61c112a2018-10-02 16:43:32 +0200441 rule->rdr_len = strlen(destination);
442 }
443 else {
444 /* log-format based redirect rule */
Christopher Faulet5f802b32021-10-13 17:22:17 +0200445 int cap = 0;
Willy Tarreau61c112a2018-10-02 16:43:32 +0200446
447 /* Parse destination. Note that in the REDIRECT_TYPE_PREFIX case,
448 * if prefix == "/", we don't want to add anything, otherwise it
449 * makes it hard for the user to configure a self-redirection.
450 */
451 curproxy->conf.args.ctx = ARGC_RDR;
Christopher Faulet5f802b32021-10-13 17:22:17 +0200452 if (curproxy->cap & PR_CAP_FE)
453 cap |= (dir ? SMP_VAL_FE_HRS_HDR : SMP_VAL_FE_HRQ_HDR);
454 if (curproxy->cap & PR_CAP_BE)
455 cap |= (dir ? SMP_VAL_BE_HRS_HDR : SMP_VAL_BE_HRQ_HDR);
Willy Tarreau61c112a2018-10-02 16:43:32 +0200456 if (!(type == REDIRECT_TYPE_PREFIX && destination[0] == '/' && destination[1] == '\0')) {
Christopher Faulet5f802b32021-10-13 17:22:17 +0200457 if (!parse_logformat_string(destination, curproxy, &rule->rdr_fmt, LOG_OPT_HTTP, cap, errmsg)) {
Aurelien DARRAGON2369a5e2023-05-11 10:34:49 +0200458 goto err;
Willy Tarreau61c112a2018-10-02 16:43:32 +0200459 }
460 free(curproxy->conf.lfs_file);
461 curproxy->conf.lfs_file = strdup(curproxy->conf.args.file);
462 curproxy->conf.lfs_line = curproxy->conf.args.line;
463 }
464 }
465
466 if (cookie) {
467 /* depending on cookie_set, either we want to set the cookie, or to clear it.
468 * a clear consists in appending "; path=/; Max-Age=0;" at the end.
469 */
470 rule->cookie_len = strlen(cookie);
471 if (cookie_set) {
472 rule->cookie_str = malloc(rule->cookie_len + 10);
Aurelien DARRAGON2369a5e2023-05-11 10:34:49 +0200473 if (!rule->cookie_str)
474 goto out_of_memory;
Willy Tarreau61c112a2018-10-02 16:43:32 +0200475 memcpy(rule->cookie_str, cookie, rule->cookie_len);
476 memcpy(rule->cookie_str + rule->cookie_len, "; path=/;", 10);
477 rule->cookie_len += 9;
478 } else {
479 rule->cookie_str = malloc(rule->cookie_len + 21);
Aurelien DARRAGON2369a5e2023-05-11 10:34:49 +0200480 if (!rule->cookie_str)
481 goto out_of_memory;
Willy Tarreau61c112a2018-10-02 16:43:32 +0200482 memcpy(rule->cookie_str, cookie, rule->cookie_len);
483 memcpy(rule->cookie_str + rule->cookie_len, "; path=/; Max-Age=0;", 21);
484 rule->cookie_len += 20;
485 }
486 }
487 rule->type = type;
488 rule->code = code;
489 rule->flags = flags;
490 LIST_INIT(&rule->list);
491 return rule;
492
493 missing_arg:
494 memprintf(errmsg, "missing argument for '%s'", args[cur_arg]);
Aurelien DARRAGON2369a5e2023-05-11 10:34:49 +0200495 goto err;
496 out_of_memory:
497 memprintf(errmsg, "parsing [%s:%d]: out of memory.", file, linenum);
498 err:
499 if (rule)
500 http_free_redirect_rule(rule);
501 else if (cond) {
502 /* rule not yet allocated, but cond already is */
503 prune_acl_cond(cond);
504 free(cond);
505 }
506
Willy Tarreau61c112a2018-10-02 16:43:32 +0200507 return NULL;
508}
509
Willy Tarreau61c112a2018-10-02 16:43:32 +0200510__attribute__((constructor))
511static void __http_rules_init(void)
512{
513}
514
515/*
516 * Local variables:
517 * c-indent-level: 8
518 * c-basic-offset: 8
519 * End:
520 */