blob: 192f0c7d3768cd37b5ef1bb34f8f907524ebac78 [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 Tarreau0ce6dc02021-10-06 16:38:53 +020028#include <haproxy/http_ana-t.h>
Willy Tarreauc761f842020-06-04 11:40:28 +020029#include <haproxy/http_rules.h>
Willy Tarreau36979d92020-06-05 17:27:29 +020030#include <haproxy/log.h>
Willy Tarreaud0ef4392020-06-02 09:38:52 +020031#include <haproxy/pool.h>
Willy Tarreaud1dd2502021-05-08 20:30:37 +020032#include <haproxy/proxy.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020033#include <haproxy/sample.h>
Willy Tarreau48fbcae2020-06-03 18:09:46 +020034#include <haproxy/tools.h>
Willy Tarreaud6788052020-05-27 15:59:00 +020035#include <haproxy/version.h>
Willy Tarreau61c112a2018-10-02 16:43:32 +020036
Willy Tarreau61c112a2018-10-02 16:43:32 +020037
38/* List head of all known action keywords for "http-request" */
39struct action_kw_list http_req_keywords = {
40 .list = LIST_HEAD_INIT(http_req_keywords.list)
41};
42
43/* List head of all known action keywords for "http-response" */
44struct action_kw_list http_res_keywords = {
45 .list = LIST_HEAD_INIT(http_res_keywords.list)
46};
47
Christopher Faulet6d0c3df2020-01-22 09:26:35 +010048/* List head of all known action keywords for "http-after-response" */
49struct action_kw_list http_after_res_keywords = {
50 .list = LIST_HEAD_INIT(http_after_res_keywords.list)
51};
52
Willy Tarreau368479c2022-03-02 14:50:38 +010053void http_req_keywords_register(struct action_kw_list *kw_list)
54{
55 LIST_APPEND(&http_req_keywords.list, &kw_list->list);
56}
57
58void http_res_keywords_register(struct action_kw_list *kw_list)
59{
60 LIST_APPEND(&http_res_keywords.list, &kw_list->list);
61}
62
63void http_after_res_keywords_register(struct action_kw_list *kw_list)
64{
65 LIST_APPEND(&http_after_res_keywords.list, &kw_list->list);
66}
67
Willy Tarreau61c112a2018-10-02 16:43:32 +020068/*
69 * Return the struct http_req_action_kw associated to a keyword.
70 */
Thierry Fournier7a71a6d2020-11-28 17:40:24 +010071struct action_kw *action_http_req_custom(const char *kw)
Willy Tarreau61c112a2018-10-02 16:43:32 +020072{
73 return action_lookup(&http_req_keywords.list, kw);
74}
75
76/*
77 * Return the struct http_res_action_kw associated to a keyword.
78 */
Thierry Fournier7a71a6d2020-11-28 17:40:24 +010079struct action_kw *action_http_res_custom(const char *kw)
Willy Tarreau61c112a2018-10-02 16:43:32 +020080{
81 return action_lookup(&http_res_keywords.list, kw);
82}
83
Christopher Faulet6d0c3df2020-01-22 09:26:35 +010084/*
85 * Return the struct http_after_res_action_kw associated to a keyword.
86 */
Thierry Fournier7a71a6d2020-11-28 17:40:24 +010087struct action_kw *action_http_after_res_custom(const char *kw)
Christopher Faulet6d0c3df2020-01-22 09:26:35 +010088{
89 return action_lookup(&http_after_res_keywords.list, kw);
90}
91
Willy Tarreau61c112a2018-10-02 16:43:32 +020092/* parse an "http-request" rule */
93struct act_rule *parse_http_req_cond(const char **args, const char *file, int linenum, struct proxy *proxy)
94{
95 struct act_rule *rule;
Willy Tarreau49bf7be2021-03-12 12:01:34 +010096 const struct action_kw *custom = NULL;
Willy Tarreau61c112a2018-10-02 16:43:32 +020097 int cur_arg;
Willy Tarreau61c112a2018-10-02 16:43:32 +020098
Willy Tarreaud535f802021-10-11 08:49:26 +020099 rule = new_act_rule(ACT_F_HTTP_REQ, file, linenum);
Willy Tarreau61c112a2018-10-02 16:43:32 +0200100 if (!rule) {
101 ha_alert("parsing [%s:%d]: out of memory.\n", file, linenum);
Christopher Fauletab398d82022-03-21 08:21:19 +0100102 goto out;
Willy Tarreau61c112a2018-10-02 16:43:32 +0200103 }
104
Christopher Faulet81e20172019-12-12 16:40:30 +0100105 if (((custom = action_http_req_custom(args[0])) != NULL)) {
Willy Tarreau61c112a2018-10-02 16:43:32 +0200106 char *errmsg = NULL;
107
Willy Tarreau61c112a2018-10-02 16:43:32 +0200108 cur_arg = 1;
109 /* try in the module list */
Willy Tarreau61c112a2018-10-02 16:43:32 +0200110 rule->kw = custom;
Amaury Denoyelle03517732021-05-07 14:25:01 +0200111
112 if (custom->flags & KWF_EXPERIMENTAL) {
113 if (!experimental_directives_allowed) {
114 ha_alert("parsing [%s:%d] : '%s' action is experimental, must be allowed via a global 'expose-experimental-directives'\n",
115 file, linenum, custom->kw);
116 goto out_err;
117 }
118 mark_tainted(TAINTED_CONFIG_EXP_KW_DECLARED);
119 }
120
Willy Tarreau61c112a2018-10-02 16:43:32 +0200121 if (custom->parse(args, &cur_arg, proxy, rule, &errmsg) == ACT_RET_PRS_ERR) {
122 ha_alert("parsing [%s:%d] : error detected in %s '%s' while parsing 'http-request %s' rule : %s.\n",
123 file, linenum, proxy_type_str(proxy), proxy->id, args[0], errmsg);
124 free(errmsg);
125 goto out_err;
126 }
Christopher Faulet81e20172019-12-12 16:40:30 +0100127 else if (errmsg) {
128 ha_warning("parsing [%s:%d] : %s.\n", file, linenum, errmsg);
129 free(errmsg);
130 }
131 }
132 else {
Willy Tarreau49bf7be2021-03-12 12:01:34 +0100133 const char *best = action_suggest(args[0], &http_req_keywords.list, NULL);
134
Willy Tarreau61c112a2018-10-02 16:43:32 +0200135 action_build_list(&http_req_keywords.list, &trash);
Willy Tarreau49bf7be2021-03-12 12:01:34 +0100136 ha_alert("parsing [%s:%d]: 'http-request' expects %s, but got '%s'%s.%s%s%s\n",
137 file, linenum, trash.area,
138 args[0], *args[0] ? "" : " (missing argument)",
139 best ? " Did you mean '" : "",
140 best ? best : "",
141 best ? "' maybe ?" : "");
Willy Tarreau61c112a2018-10-02 16:43:32 +0200142 goto out_err;
143 }
144
145 if (strcmp(args[cur_arg], "if") == 0 || strcmp(args[cur_arg], "unless") == 0) {
146 struct acl_cond *cond;
147 char *errmsg = NULL;
148
149 if ((cond = build_acl_cond(file, linenum, &proxy->acl, proxy, args+cur_arg, &errmsg)) == NULL) {
150 ha_alert("parsing [%s:%d] : error detected while parsing an 'http-request %s' condition : %s.\n",
151 file, linenum, args[0], errmsg);
152 free(errmsg);
153 goto out_err;
154 }
155 rule->cond = cond;
156 }
157 else if (*args[cur_arg]) {
Christopher Faulet81e20172019-12-12 16:40:30 +0100158 ha_alert("parsing [%s:%d]: 'http-request %s' expects"
Willy Tarreau61c112a2018-10-02 16:43:32 +0200159 " either 'if' or 'unless' followed by a condition but found '%s'.\n",
160 file, linenum, args[0], args[cur_arg]);
161 goto out_err;
162 }
163
164 return rule;
165 out_err:
Willy Tarreaudd7e6c62022-03-17 20:29:06 +0100166 free_act_rule(rule);
Christopher Fauletab398d82022-03-21 08:21:19 +0100167 out:
Willy Tarreau61c112a2018-10-02 16:43:32 +0200168 return NULL;
169}
170
171/* parse an "http-respose" rule */
172struct act_rule *parse_http_res_cond(const char **args, const char *file, int linenum, struct proxy *proxy)
173{
174 struct act_rule *rule;
Willy Tarreau49bf7be2021-03-12 12:01:34 +0100175 const struct action_kw *custom = NULL;
Willy Tarreau61c112a2018-10-02 16:43:32 +0200176 int cur_arg;
Willy Tarreau61c112a2018-10-02 16:43:32 +0200177
Willy Tarreaud535f802021-10-11 08:49:26 +0200178 rule = new_act_rule(ACT_F_HTTP_RES, file, linenum);
Willy Tarreau61c112a2018-10-02 16:43:32 +0200179 if (!rule) {
180 ha_alert("parsing [%s:%d]: out of memory.\n", file, linenum);
Christopher Fauletab398d82022-03-21 08:21:19 +0100181 goto out;
Willy Tarreau61c112a2018-10-02 16:43:32 +0200182 }
Willy Tarreau61c112a2018-10-02 16:43:32 +0200183
Christopher Faulet81e20172019-12-12 16:40:30 +0100184 if (((custom = action_http_res_custom(args[0])) != NULL)) {
Willy Tarreau61c112a2018-10-02 16:43:32 +0200185 char *errmsg = NULL;
186
Willy Tarreau61c112a2018-10-02 16:43:32 +0200187 cur_arg = 1;
188 /* try in the module list */
Willy Tarreau61c112a2018-10-02 16:43:32 +0200189 rule->kw = custom;
Amaury Denoyelle03517732021-05-07 14:25:01 +0200190
191 if (custom->flags & KWF_EXPERIMENTAL) {
192 if (!experimental_directives_allowed) {
193 ha_alert("parsing [%s:%d] : '%s' action is experimental, must be allowed via a global 'expose-experimental-directives'\n",
194 file, linenum, custom->kw);
195 goto out_err;
196 }
197 mark_tainted(TAINTED_CONFIG_EXP_KW_DECLARED);
198 }
199
Willy Tarreau61c112a2018-10-02 16:43:32 +0200200 if (custom->parse(args, &cur_arg, proxy, rule, &errmsg) == ACT_RET_PRS_ERR) {
201 ha_alert("parsing [%s:%d] : error detected in %s '%s' while parsing 'http-response %s' rule : %s.\n",
202 file, linenum, proxy_type_str(proxy), proxy->id, args[0], errmsg);
203 free(errmsg);
204 goto out_err;
205 }
Christopher Faulet81e20172019-12-12 16:40:30 +0100206 else if (errmsg) {
207 ha_warning("parsing [%s:%d] : %s.\n", file, linenum, errmsg);
208 free(errmsg);
209 }
210 }
211 else {
Willy Tarreau49bf7be2021-03-12 12:01:34 +0100212 const char *best = action_suggest(args[0], &http_res_keywords.list, NULL);
213
Willy Tarreau61c112a2018-10-02 16:43:32 +0200214 action_build_list(&http_res_keywords.list, &trash);
Willy Tarreau49bf7be2021-03-12 12:01:34 +0100215 ha_alert("parsing [%s:%d]: 'http-response' expects %s, but got '%s'%s.%s%s%s\n",
216 file, linenum, trash.area,
217 args[0], *args[0] ? "" : " (missing argument)",
218 best ? " Did you mean '" : "",
219 best ? best : "",
220 best ? "' maybe ?" : "");
Willy Tarreau61c112a2018-10-02 16:43:32 +0200221 goto out_err;
222 }
223
224 if (strcmp(args[cur_arg], "if") == 0 || strcmp(args[cur_arg], "unless") == 0) {
225 struct acl_cond *cond;
226 char *errmsg = NULL;
227
228 if ((cond = build_acl_cond(file, linenum, &proxy->acl, proxy, args+cur_arg, &errmsg)) == NULL) {
229 ha_alert("parsing [%s:%d] : error detected while parsing an 'http-response %s' condition : %s.\n",
230 file, linenum, args[0], errmsg);
231 free(errmsg);
232 goto out_err;
233 }
234 rule->cond = cond;
235 }
236 else if (*args[cur_arg]) {
237 ha_alert("parsing [%s:%d]: 'http-response %s' expects"
238 " either 'if' or 'unless' followed by a condition but found '%s'.\n",
239 file, linenum, args[0], args[cur_arg]);
240 goto out_err;
241 }
242
243 return rule;
244 out_err:
Willy Tarreaudd7e6c62022-03-17 20:29:06 +0100245 free_act_rule(rule);
Christopher Fauletab398d82022-03-21 08:21:19 +0100246 out:
Willy Tarreau61c112a2018-10-02 16:43:32 +0200247 return NULL;
248}
249
Christopher Faulet6d0c3df2020-01-22 09:26:35 +0100250
251/* parse an "http-after-response" rule */
252struct act_rule *parse_http_after_res_cond(const char **args, const char *file, int linenum, struct proxy *proxy)
253{
254 struct act_rule *rule;
Willy Tarreau49bf7be2021-03-12 12:01:34 +0100255 const struct action_kw *custom = NULL;
Christopher Faulet6d0c3df2020-01-22 09:26:35 +0100256 int cur_arg;
257
Willy Tarreaud535f802021-10-11 08:49:26 +0200258 rule = new_act_rule(ACT_F_HTTP_RES, file, linenum);
Christopher Faulet6d0c3df2020-01-22 09:26:35 +0100259 if (!rule) {
260 ha_alert("parsing [%s:%d]: out of memory.\n", file, linenum);
Christopher Fauletab398d82022-03-21 08:21:19 +0100261 goto out;
Christopher Faulet6d0c3df2020-01-22 09:26:35 +0100262 }
Christopher Faulet6d0c3df2020-01-22 09:26:35 +0100263
264 if (((custom = action_http_after_res_custom(args[0])) != NULL)) {
265 char *errmsg = NULL;
266
267 cur_arg = 1;
268 /* try in the module list */
269 rule->kw = custom;
270 if (custom->parse(args, &cur_arg, proxy, rule, &errmsg) == ACT_RET_PRS_ERR) {
271 ha_alert("parsing [%s:%d] : error detected in %s '%s' while parsing 'http-after-response %s' rule : %s.\n",
272 file, linenum, proxy_type_str(proxy), proxy->id, args[0], errmsg);
273 free(errmsg);
274 goto out_err;
275 }
276 else if (errmsg) {
277 ha_warning("parsing [%s:%d] : %s.\n", file, linenum, errmsg);
278 free(errmsg);
279 }
280 }
281 else {
Willy Tarreau49bf7be2021-03-12 12:01:34 +0100282 const char *best = action_suggest(args[0], &http_after_res_keywords.list, NULL);
283
Christopher Faulet6d0c3df2020-01-22 09:26:35 +0100284 action_build_list(&http_after_res_keywords.list, &trash);
Willy Tarreau49bf7be2021-03-12 12:01:34 +0100285 ha_alert("parsing [%s:%d]: 'http-after-response' expects %s, but got '%s'%s.%s%s%s\n",
286 file, linenum, trash.area,
287 args[0], *args[0] ? "" : " (missing argument)",
288 best ? " Did you mean '" : "",
289 best ? best : "",
290 best ? "' maybe ?" : "");
Christopher Faulet6d0c3df2020-01-22 09:26:35 +0100291 goto out_err;
292 }
293
294 if (strcmp(args[cur_arg], "if") == 0 || strcmp(args[cur_arg], "unless") == 0) {
295 struct acl_cond *cond;
296 char *errmsg = NULL;
297
298 if ((cond = build_acl_cond(file, linenum, &proxy->acl, proxy, args+cur_arg, &errmsg)) == NULL) {
299 ha_alert("parsing [%s:%d] : error detected while parsing an 'http-after-response %s' condition : %s.\n",
300 file, linenum, args[0], errmsg);
301 free(errmsg);
302 goto out_err;
303 }
304 rule->cond = cond;
305 }
306 else if (*args[cur_arg]) {
307 ha_alert("parsing [%s:%d]: 'http-after-response %s' expects"
308 " either 'if' or 'unless' followed by a condition but found '%s'.\n",
309 file, linenum, args[0], args[cur_arg]);
310 goto out_err;
311 }
312
313 return rule;
314 out_err:
Willy Tarreaudd7e6c62022-03-17 20:29:06 +0100315 free_act_rule(rule);
Christopher Fauletab398d82022-03-21 08:21:19 +0100316 out:
Christopher Faulet6d0c3df2020-01-22 09:26:35 +0100317 return NULL;
318}
319
Aurelien DARRAGON7abc9222023-05-11 10:30:27 +0200320/* completely free redirect rule */
321void http_free_redirect_rule(struct redirect_rule *rdr)
322{
323 struct logformat_node *lf, *lfb;
324
Aurelien DARRAGONc6100952023-05-11 12:29:51 +0200325 free_acl_cond(rdr->cond);
Aurelien DARRAGON7abc9222023-05-11 10:30:27 +0200326 free(rdr->rdr_str);
327 free(rdr->cookie_str);
328 list_for_each_entry_safe(lf, lfb, &rdr->rdr_fmt, list) {
329 LIST_DELETE(&lf->list);
330 release_sample_expr(lf->expr);
331 free(lf->arg);
332 free(lf);
333 }
334 free(rdr);
335}
336
Willy Tarreau61c112a2018-10-02 16:43:32 +0200337/* Parses a redirect rule. Returns the redirect rule on success or NULL on error,
338 * with <err> filled with the error message. If <use_fmt> is not null, builds a
339 * dynamic log-format rule instead of a static string. Parameter <dir> indicates
340 * the direction of the rule, and equals 0 for request, non-zero for responses.
341 */
342struct redirect_rule *http_parse_redirect_rule(const char *file, int linenum, struct proxy *curproxy,
343 const char **args, char **errmsg, int use_fmt, int dir)
344{
Aurelien DARRAGON53135702023-05-11 10:34:49 +0200345 struct redirect_rule *rule = NULL;
Willy Tarreau61c112a2018-10-02 16:43:32 +0200346 int cur_arg;
347 int type = REDIRECT_TYPE_NONE;
348 int code = 302;
349 const char *destination = NULL;
350 const char *cookie = NULL;
351 int cookie_set = 0;
Christopher Fauletc87e4682020-01-28 09:13:41 +0100352 unsigned int flags = (!dir ? REDIRECT_FLAG_FROM_REQ : REDIRECT_FLAG_NONE);
Willy Tarreau61c112a2018-10-02 16:43:32 +0200353 struct acl_cond *cond = NULL;
354
355 cur_arg = 0;
356 while (*(args[cur_arg])) {
357 if (strcmp(args[cur_arg], "location") == 0) {
358 if (!*args[cur_arg + 1])
359 goto missing_arg;
360
361 type = REDIRECT_TYPE_LOCATION;
362 cur_arg++;
363 destination = args[cur_arg];
364 }
365 else if (strcmp(args[cur_arg], "prefix") == 0) {
366 if (!*args[cur_arg + 1])
367 goto missing_arg;
368 type = REDIRECT_TYPE_PREFIX;
369 cur_arg++;
370 destination = args[cur_arg];
371 }
372 else if (strcmp(args[cur_arg], "scheme") == 0) {
373 if (!*args[cur_arg + 1])
374 goto missing_arg;
375
376 type = REDIRECT_TYPE_SCHEME;
377 cur_arg++;
378 destination = args[cur_arg];
379 }
380 else if (strcmp(args[cur_arg], "set-cookie") == 0) {
381 if (!*args[cur_arg + 1])
382 goto missing_arg;
383
384 cur_arg++;
385 cookie = args[cur_arg];
386 cookie_set = 1;
387 }
388 else if (strcmp(args[cur_arg], "clear-cookie") == 0) {
389 if (!*args[cur_arg + 1])
390 goto missing_arg;
391
392 cur_arg++;
393 cookie = args[cur_arg];
394 cookie_set = 0;
395 }
396 else if (strcmp(args[cur_arg], "code") == 0) {
397 if (!*args[cur_arg + 1])
398 goto missing_arg;
399
400 cur_arg++;
401 code = atol(args[cur_arg]);
402 if (code < 301 || code > 308 || (code > 303 && code < 307)) {
403 memprintf(errmsg,
404 "'%s': unsupported HTTP code '%s' (must be one of 301, 302, 303, 307 or 308)",
405 args[cur_arg - 1], args[cur_arg]);
Aurelien DARRAGON53135702023-05-11 10:34:49 +0200406 goto err;
Willy Tarreau61c112a2018-10-02 16:43:32 +0200407 }
408 }
Tim Duesterhuse5ff1412021-01-02 22:31:53 +0100409 else if (strcmp(args[cur_arg], "drop-query") == 0) {
Willy Tarreau61c112a2018-10-02 16:43:32 +0200410 flags |= REDIRECT_FLAG_DROP_QS;
411 }
Tim Duesterhuse5ff1412021-01-02 22:31:53 +0100412 else if (strcmp(args[cur_arg], "append-slash") == 0) {
Willy Tarreau61c112a2018-10-02 16:43:32 +0200413 flags |= REDIRECT_FLAG_APPEND_SLASH;
414 }
Willy Tarreaubc1223b2021-09-02 16:54:33 +0200415 else if (strcmp(args[cur_arg], "ignore-empty") == 0) {
416 flags |= REDIRECT_FLAG_IGNORE_EMPTY;
417 }
Willy Tarreau61c112a2018-10-02 16:43:32 +0200418 else if (strcmp(args[cur_arg], "if") == 0 ||
419 strcmp(args[cur_arg], "unless") == 0) {
420 cond = build_acl_cond(file, linenum, &curproxy->acl, curproxy, (const char **)args + cur_arg, errmsg);
421 if (!cond) {
422 memprintf(errmsg, "error in condition: %s", *errmsg);
Aurelien DARRAGON53135702023-05-11 10:34:49 +0200423 goto err;
Willy Tarreau61c112a2018-10-02 16:43:32 +0200424 }
425 break;
426 }
427 else {
428 memprintf(errmsg,
Willy Tarreaubc1223b2021-09-02 16:54:33 +0200429 "expects 'code', 'prefix', 'location', 'scheme', 'set-cookie', 'clear-cookie', 'drop-query', 'ignore-empty' or 'append-slash' (was '%s')",
Willy Tarreau61c112a2018-10-02 16:43:32 +0200430 args[cur_arg]);
Aurelien DARRAGON53135702023-05-11 10:34:49 +0200431 goto err;
Willy Tarreau61c112a2018-10-02 16:43:32 +0200432 }
433 cur_arg++;
434 }
435
436 if (type == REDIRECT_TYPE_NONE) {
437 memprintf(errmsg, "redirection type expected ('prefix', 'location', or 'scheme')");
Aurelien DARRAGON53135702023-05-11 10:34:49 +0200438 goto err;
Willy Tarreau61c112a2018-10-02 16:43:32 +0200439 }
440
441 if (dir && type != REDIRECT_TYPE_LOCATION) {
442 memprintf(errmsg, "response only supports redirect type 'location'");
Aurelien DARRAGON53135702023-05-11 10:34:49 +0200443 goto err;
Willy Tarreau61c112a2018-10-02 16:43:32 +0200444 }
445
446 rule = calloc(1, sizeof(*rule));
Aurelien DARRAGON53135702023-05-11 10:34:49 +0200447 if (!rule)
448 goto out_of_memory;
Willy Tarreau61c112a2018-10-02 16:43:32 +0200449 rule->cond = cond;
450 LIST_INIT(&rule->rdr_fmt);
451
452 if (!use_fmt) {
453 /* old-style static redirect rule */
454 rule->rdr_str = strdup(destination);
Aurelien DARRAGON53135702023-05-11 10:34:49 +0200455 if (!rule->rdr_str)
456 goto out_of_memory;
Willy Tarreau61c112a2018-10-02 16:43:32 +0200457 rule->rdr_len = strlen(destination);
458 }
459 else {
460 /* log-format based redirect rule */
Christopher Faulet7a06ffb2021-10-13 17:22:17 +0200461 int cap = 0;
Willy Tarreau61c112a2018-10-02 16:43:32 +0200462
463 /* Parse destination. Note that in the REDIRECT_TYPE_PREFIX case,
464 * if prefix == "/", we don't want to add anything, otherwise it
465 * makes it hard for the user to configure a self-redirection.
466 */
467 curproxy->conf.args.ctx = ARGC_RDR;
Christopher Faulet7a06ffb2021-10-13 17:22:17 +0200468 if (curproxy->cap & PR_CAP_FE)
469 cap |= (dir ? SMP_VAL_FE_HRS_HDR : SMP_VAL_FE_HRQ_HDR);
470 if (curproxy->cap & PR_CAP_BE)
471 cap |= (dir ? SMP_VAL_BE_HRS_HDR : SMP_VAL_BE_HRQ_HDR);
Willy Tarreau61c112a2018-10-02 16:43:32 +0200472 if (!(type == REDIRECT_TYPE_PREFIX && destination[0] == '/' && destination[1] == '\0')) {
Christopher Faulet7a06ffb2021-10-13 17:22:17 +0200473 if (!parse_logformat_string(destination, curproxy, &rule->rdr_fmt, LOG_OPT_HTTP, cap, errmsg)) {
Aurelien DARRAGON53135702023-05-11 10:34:49 +0200474 goto err;
Willy Tarreau61c112a2018-10-02 16:43:32 +0200475 }
476 free(curproxy->conf.lfs_file);
477 curproxy->conf.lfs_file = strdup(curproxy->conf.args.file);
478 curproxy->conf.lfs_line = curproxy->conf.args.line;
479 }
480 }
481
482 if (cookie) {
483 /* depending on cookie_set, either we want to set the cookie, or to clear it.
484 * a clear consists in appending "; path=/; Max-Age=0;" at the end.
485 */
486 rule->cookie_len = strlen(cookie);
487 if (cookie_set) {
488 rule->cookie_str = malloc(rule->cookie_len + 10);
Aurelien DARRAGON53135702023-05-11 10:34:49 +0200489 if (!rule->cookie_str)
490 goto out_of_memory;
Willy Tarreau61c112a2018-10-02 16:43:32 +0200491 memcpy(rule->cookie_str, cookie, rule->cookie_len);
492 memcpy(rule->cookie_str + rule->cookie_len, "; path=/;", 10);
493 rule->cookie_len += 9;
494 } else {
495 rule->cookie_str = malloc(rule->cookie_len + 21);
Aurelien DARRAGON53135702023-05-11 10:34:49 +0200496 if (!rule->cookie_str)
497 goto out_of_memory;
Willy Tarreau61c112a2018-10-02 16:43:32 +0200498 memcpy(rule->cookie_str, cookie, rule->cookie_len);
499 memcpy(rule->cookie_str + rule->cookie_len, "; path=/; Max-Age=0;", 21);
500 rule->cookie_len += 20;
501 }
502 }
503 rule->type = type;
504 rule->code = code;
505 rule->flags = flags;
506 LIST_INIT(&rule->list);
507 return rule;
508
509 missing_arg:
510 memprintf(errmsg, "missing argument for '%s'", args[cur_arg]);
Aurelien DARRAGON53135702023-05-11 10:34:49 +0200511 goto err;
512 out_of_memory:
513 memprintf(errmsg, "parsing [%s:%d]: out of memory.", file, linenum);
514 err:
515 if (rule)
516 http_free_redirect_rule(rule);
517 else if (cond) {
518 /* rule not yet allocated, but cond already is */
Aurelien DARRAGONc6100952023-05-11 12:29:51 +0200519 free_acl_cond(cond);
Aurelien DARRAGON53135702023-05-11 10:34:49 +0200520 }
521
Willy Tarreau61c112a2018-10-02 16:43:32 +0200522 return NULL;
523}
524
Willy Tarreau61c112a2018-10-02 16:43:32 +0200525/*
526 * Local variables:
527 * c-indent-level: 8
528 * c-basic-offset: 8
529 * End:
530 */