haproxy/src/http_act.c

2508 lines
77 KiB
C
Raw Permalink Normal View History

REORG: http: move the code to different files The current proto_http.c file is huge and contains different processing domains making it very difficult to work on an alternative representation. This commit moves some parts to other files : - ACL registration code => http_acl.c This code only creates some ACL mappings and doesn't know anything about HTTP nor about the representation. This code could even have moved to acl.c but it was not worth polluting it again. - HTTP sample conversion => http_conv.c This code doesn't depend on the internal representation but definitely manipulates some HTTP elements, such as dates. It also has access to captures. - HTTP sample fetching => http_fetch.c This code does depend entirely on the internal representation but is totally independent on the analysers. Placing it into a different file will ease the transition to the new representation and the creation of a wrapper if required. An include file was created due to CHECK_HTTP_MESSAGE_FIRST() being used at various places. - HTTP action registration => http_act.c This code doesn't directly interact with the messages nor the transaction but it does so via some exported http functions like http_replace_req_line() or http_set_status() so it will be easier to change only this after the conversion. - a few very generic parts were found and moved to http.{c,h} as relevant. It is worth noting that the functions moved to these new files are not referenced anywhere outside of the files and are only called as registered callbacks, so these files do not even require associated include files.
2018-10-02 10:01:16 -04:00
/*
* HTTP actions
*
* Copyright 2000-2018 Willy Tarreau <w@1wt.eu>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
*/
#include <sys/types.h>
#include <ctype.h>
#include <string.h>
#include <time.h>
#include <haproxy/acl.h>
#include <haproxy/action.h>
#include <haproxy/api.h>
#include <haproxy/arg.h>
#include <haproxy/capture-t.h>
#include <haproxy/cfgparse.h>
#include <haproxy/chunk.h>
#include <haproxy/global.h>
#include <haproxy/http.h>
#include <haproxy/http_ana.h>
#include <haproxy/http_htx.h>
#include <haproxy/http_rules.h>
#include <haproxy/log.h>
#include <haproxy/pattern.h>
#include <haproxy/pool.h>
#include <haproxy/regex.h>
#include <haproxy/sample.h>
#include <haproxy/sc_strm.h>
#include <haproxy/stconn.h>
#include <haproxy/tools.h>
#include <haproxy/uri_auth-t.h>
#include <haproxy/uri_normalizer.h>
#include <haproxy/version.h>
REORG: http: move the code to different files The current proto_http.c file is huge and contains different processing domains making it very difficult to work on an alternative representation. This commit moves some parts to other files : - ACL registration code => http_acl.c This code only creates some ACL mappings and doesn't know anything about HTTP nor about the representation. This code could even have moved to acl.c but it was not worth polluting it again. - HTTP sample conversion => http_conv.c This code doesn't depend on the internal representation but definitely manipulates some HTTP elements, such as dates. It also has access to captures. - HTTP sample fetching => http_fetch.c This code does depend entirely on the internal representation but is totally independent on the analysers. Placing it into a different file will ease the transition to the new representation and the creation of a wrapper if required. An include file was created due to CHECK_HTTP_MESSAGE_FIRST() being used at various places. - HTTP action registration => http_act.c This code doesn't directly interact with the messages nor the transaction but it does so via some exported http functions like http_replace_req_line() or http_set_status() so it will be easier to change only this after the conversion. - a few very generic parts were found and moved to http.{c,h} as relevant. It is worth noting that the functions moved to these new files are not referenced anywhere outside of the files and are only called as registered callbacks, so these files do not even require associated include files.
2018-10-02 10:01:16 -04:00
/* Release memory allocated by most of HTTP actions. Concretely, it releases
* <arg.http>.
*/
static void release_http_action(struct act_rule *rule)
{
istfree(&rule->arg.http.str);
if (rule->arg.http.re)
regex_free(rule->arg.http.re);
MEDIUM: tree-wide: add logformat expressions wrapper log format expressions are broadly used within the code: once they are parsed from input string, they are converted to a linked list of logformat nodes. We're starting to face some limitations because we're simply storing the converted expression as a generic logformat_node list. The first issue we're facing is that storing logformat expressions that way doesn't allow us to add metadata alongside the list, which is part of the prerequites for implementing log-profiles. Another issue with storing logformat expressions as generic lists of logformat_node elements is that it's starting to become really hard to tell when we rely on logformat expressions or not in the code given that there isn't always a comment near the list declaration or manipulation to indicate that it's relying on logformat expressions under the hood, so this adds some complexity for code maintenance. This patch looks quite impressive due to changes in a lot of header and source files (since logformat expressions are broadly used), but it does a simple thing: it defines the lf_expr structure which itself holds a generic list of logformat nodes, and then declares some helpers to manipulate lf_expr elements and fixes the code so that we now exclusively manipulate logformat_node lists as lf_expr elements outside of log.c. For now, lf_expr struct only contains the list of logformat nodes (no additional metadata), but now that we have dedicated type and helpers, doing so in the future won't be problematic at all and won't require extensive code changes.
2024-02-23 09:57:21 -05:00
lf_expr_deinit(&rule->arg.http.fmt);
}
/* Release memory allocated by HTTP actions relying on an http reply. Concretely,
* it releases <.arg.http_reply>
*/
static void release_act_http_reply(struct act_rule *rule)
{
release_http_reply(rule->arg.http_reply);
rule->arg.http_reply = NULL;
}
/* Check function for HTTP actions relying on an http reply. The function
* returns 1 in success case, otherwise, it returns 0 and err is filled.
*/
static int check_act_http_reply(struct act_rule *rule, struct proxy *px, char **err)
{
struct http_reply *reply = rule->arg.http_reply;
if (!http_check_http_reply(reply, px, err)) {
release_act_http_reply(rule);
return 0;
}
return 1;
}
REORG: http: move the code to different files The current proto_http.c file is huge and contains different processing domains making it very difficult to work on an alternative representation. This commit moves some parts to other files : - ACL registration code => http_acl.c This code only creates some ACL mappings and doesn't know anything about HTTP nor about the representation. This code could even have moved to acl.c but it was not worth polluting it again. - HTTP sample conversion => http_conv.c This code doesn't depend on the internal representation but definitely manipulates some HTTP elements, such as dates. It also has access to captures. - HTTP sample fetching => http_fetch.c This code does depend entirely on the internal representation but is totally independent on the analysers. Placing it into a different file will ease the transition to the new representation and the creation of a wrapper if required. An include file was created due to CHECK_HTTP_MESSAGE_FIRST() being used at various places. - HTTP action registration => http_act.c This code doesn't directly interact with the messages nor the transaction but it does so via some exported http functions like http_replace_req_line() or http_set_status() so it will be easier to change only this after the conversion. - a few very generic parts were found and moved to http.{c,h} as relevant. It is worth noting that the functions moved to these new files are not referenced anywhere outside of the files and are only called as registered callbacks, so these files do not even require associated include files.
2018-10-02 10:01:16 -04:00
/* This function executes one of the set-{method,path,query,uri} actions. It
* builds a string in the trash from the specified format string. It finds
* the action to be performed in <.action>, previously filled by function
* parse_set_req_line(). The replacement action is executed by the function
* http_action_set_req_line(). On success, it returns ACT_RET_CONT. If an error
* occurs while soft rewrites are enabled, the action is canceled, but the rule
* processing continue. Otherwsize ACT_RET_ERR is returned.
REORG: http: move the code to different files The current proto_http.c file is huge and contains different processing domains making it very difficult to work on an alternative representation. This commit moves some parts to other files : - ACL registration code => http_acl.c This code only creates some ACL mappings and doesn't know anything about HTTP nor about the representation. This code could even have moved to acl.c but it was not worth polluting it again. - HTTP sample conversion => http_conv.c This code doesn't depend on the internal representation but definitely manipulates some HTTP elements, such as dates. It also has access to captures. - HTTP sample fetching => http_fetch.c This code does depend entirely on the internal representation but is totally independent on the analysers. Placing it into a different file will ease the transition to the new representation and the creation of a wrapper if required. An include file was created due to CHECK_HTTP_MESSAGE_FIRST() being used at various places. - HTTP action registration => http_act.c This code doesn't directly interact with the messages nor the transaction but it does so via some exported http functions like http_replace_req_line() or http_set_status() so it will be easier to change only this after the conversion. - a few very generic parts were found and moved to http.{c,h} as relevant. It is worth noting that the functions moved to these new files are not referenced anywhere outside of the files and are only called as registered callbacks, so these files do not even require associated include files.
2018-10-02 10:01:16 -04:00
*/
static enum act_return http_action_set_req_line(struct act_rule *rule, struct proxy *px,
struct session *sess, struct stream *s, int flags)
{
struct buffer *replace;
enum act_return ret = ACT_RET_CONT;
REORG: http: move the code to different files The current proto_http.c file is huge and contains different processing domains making it very difficult to work on an alternative representation. This commit moves some parts to other files : - ACL registration code => http_acl.c This code only creates some ACL mappings and doesn't know anything about HTTP nor about the representation. This code could even have moved to acl.c but it was not worth polluting it again. - HTTP sample conversion => http_conv.c This code doesn't depend on the internal representation but definitely manipulates some HTTP elements, such as dates. It also has access to captures. - HTTP sample fetching => http_fetch.c This code does depend entirely on the internal representation but is totally independent on the analysers. Placing it into a different file will ease the transition to the new representation and the creation of a wrapper if required. An include file was created due to CHECK_HTTP_MESSAGE_FIRST() being used at various places. - HTTP action registration => http_act.c This code doesn't directly interact with the messages nor the transaction but it does so via some exported http functions like http_replace_req_line() or http_set_status() so it will be easier to change only this after the conversion. - a few very generic parts were found and moved to http.{c,h} as relevant. It is worth noting that the functions moved to these new files are not referenced anywhere outside of the files and are only called as registered callbacks, so these files do not even require associated include files.
2018-10-02 10:01:16 -04:00
replace = alloc_trash_chunk();
if (!replace)
goto fail_alloc;
REORG: http: move the code to different files The current proto_http.c file is huge and contains different processing domains making it very difficult to work on an alternative representation. This commit moves some parts to other files : - ACL registration code => http_acl.c This code only creates some ACL mappings and doesn't know anything about HTTP nor about the representation. This code could even have moved to acl.c but it was not worth polluting it again. - HTTP sample conversion => http_conv.c This code doesn't depend on the internal representation but definitely manipulates some HTTP elements, such as dates. It also has access to captures. - HTTP sample fetching => http_fetch.c This code does depend entirely on the internal representation but is totally independent on the analysers. Placing it into a different file will ease the transition to the new representation and the creation of a wrapper if required. An include file was created due to CHECK_HTTP_MESSAGE_FIRST() being used at various places. - HTTP action registration => http_act.c This code doesn't directly interact with the messages nor the transaction but it does so via some exported http functions like http_replace_req_line() or http_set_status() so it will be easier to change only this after the conversion. - a few very generic parts were found and moved to http.{c,h} as relevant. It is worth noting that the functions moved to these new files are not referenced anywhere outside of the files and are only called as registered callbacks, so these files do not even require associated include files.
2018-10-02 10:01:16 -04:00
/* If we have to create a query string, prepare a '?'. */
if (rule->action == 2) // set-query
REORG: http: move the code to different files The current proto_http.c file is huge and contains different processing domains making it very difficult to work on an alternative representation. This commit moves some parts to other files : - ACL registration code => http_acl.c This code only creates some ACL mappings and doesn't know anything about HTTP nor about the representation. This code could even have moved to acl.c but it was not worth polluting it again. - HTTP sample conversion => http_conv.c This code doesn't depend on the internal representation but definitely manipulates some HTTP elements, such as dates. It also has access to captures. - HTTP sample fetching => http_fetch.c This code does depend entirely on the internal representation but is totally independent on the analysers. Placing it into a different file will ease the transition to the new representation and the creation of a wrapper if required. An include file was created due to CHECK_HTTP_MESSAGE_FIRST() being used at various places. - HTTP action registration => http_act.c This code doesn't directly interact with the messages nor the transaction but it does so via some exported http functions like http_replace_req_line() or http_set_status() so it will be easier to change only this after the conversion. - a few very generic parts were found and moved to http.{c,h} as relevant. It is worth noting that the functions moved to these new files are not referenced anywhere outside of the files and are only called as registered callbacks, so these files do not even require associated include files.
2018-10-02 10:01:16 -04:00
replace->area[replace->data++] = '?';
replace->data += build_logline(s, replace->area + replace->data,
replace->size - replace->data,
&rule->arg.http.fmt);
REORG: http: move the code to different files The current proto_http.c file is huge and contains different processing domains making it very difficult to work on an alternative representation. This commit moves some parts to other files : - ACL registration code => http_acl.c This code only creates some ACL mappings and doesn't know anything about HTTP nor about the representation. This code could even have moved to acl.c but it was not worth polluting it again. - HTTP sample conversion => http_conv.c This code doesn't depend on the internal representation but definitely manipulates some HTTP elements, such as dates. It also has access to captures. - HTTP sample fetching => http_fetch.c This code does depend entirely on the internal representation but is totally independent on the analysers. Placing it into a different file will ease the transition to the new representation and the creation of a wrapper if required. An include file was created due to CHECK_HTTP_MESSAGE_FIRST() being used at various places. - HTTP action registration => http_act.c This code doesn't directly interact with the messages nor the transaction but it does so via some exported http functions like http_replace_req_line() or http_set_status() so it will be easier to change only this after the conversion. - a few very generic parts were found and moved to http.{c,h} as relevant. It is worth noting that the functions moved to these new files are not referenced anywhere outside of the files and are only called as registered callbacks, so these files do not even require associated include files.
2018-10-02 10:01:16 -04:00
if (http_req_replace_stline(rule->action, replace->area, replace->data, px, s) == -1)
goto fail_rewrite;
REORG: http: move the code to different files The current proto_http.c file is huge and contains different processing domains making it very difficult to work on an alternative representation. This commit moves some parts to other files : - ACL registration code => http_acl.c This code only creates some ACL mappings and doesn't know anything about HTTP nor about the representation. This code could even have moved to acl.c but it was not worth polluting it again. - HTTP sample conversion => http_conv.c This code doesn't depend on the internal representation but definitely manipulates some HTTP elements, such as dates. It also has access to captures. - HTTP sample fetching => http_fetch.c This code does depend entirely on the internal representation but is totally independent on the analysers. Placing it into a different file will ease the transition to the new representation and the creation of a wrapper if required. An include file was created due to CHECK_HTTP_MESSAGE_FIRST() being used at various places. - HTTP action registration => http_act.c This code doesn't directly interact with the messages nor the transaction but it does so via some exported http functions like http_replace_req_line() or http_set_status() so it will be easier to change only this after the conversion. - a few very generic parts were found and moved to http.{c,h} as relevant. It is worth noting that the functions moved to these new files are not referenced anywhere outside of the files and are only called as registered callbacks, so these files do not even require associated include files.
2018-10-02 10:01:16 -04:00
leave:
REORG: http: move the code to different files The current proto_http.c file is huge and contains different processing domains making it very difficult to work on an alternative representation. This commit moves some parts to other files : - ACL registration code => http_acl.c This code only creates some ACL mappings and doesn't know anything about HTTP nor about the representation. This code could even have moved to acl.c but it was not worth polluting it again. - HTTP sample conversion => http_conv.c This code doesn't depend on the internal representation but definitely manipulates some HTTP elements, such as dates. It also has access to captures. - HTTP sample fetching => http_fetch.c This code does depend entirely on the internal representation but is totally independent on the analysers. Placing it into a different file will ease the transition to the new representation and the creation of a wrapper if required. An include file was created due to CHECK_HTTP_MESSAGE_FIRST() being used at various places. - HTTP action registration => http_act.c This code doesn't directly interact with the messages nor the transaction but it does so via some exported http functions like http_replace_req_line() or http_set_status() so it will be easier to change only this after the conversion. - a few very generic parts were found and moved to http.{c,h} as relevant. It is worth noting that the functions moved to these new files are not referenced anywhere outside of the files and are only called as registered callbacks, so these files do not even require associated include files.
2018-10-02 10:01:16 -04:00
free_trash_chunk(replace);
return ret;
fail_alloc:
if (!(s->flags & SF_ERR_MASK))
s->flags |= SF_ERR_RESOURCE;
ret = ACT_RET_ERR;
goto leave;
fail_rewrite:
_HA_ATOMIC_INC(&sess->fe->fe_counters.failed_rewrites);
if (s->flags & SF_BE_ASSIGNED)
_HA_ATOMIC_INC(&s->be->be_counters.failed_rewrites);
if (sess->listener && sess->listener->counters)
_HA_ATOMIC_INC(&sess->listener->counters->failed_rewrites);
if (objt_server(s->target))
_HA_ATOMIC_INC(&__objt_server(s->target)->counters.failed_rewrites);
if (!(s->txn->req.flags & HTTP_MSGF_SOFT_RW)) {
ret = ACT_RET_ERR;
if (!(s->flags & SF_ERR_MASK))
s->flags |= SF_ERR_PRXCOND;
}
goto leave;
REORG: http: move the code to different files The current proto_http.c file is huge and contains different processing domains making it very difficult to work on an alternative representation. This commit moves some parts to other files : - ACL registration code => http_acl.c This code only creates some ACL mappings and doesn't know anything about HTTP nor about the representation. This code could even have moved to acl.c but it was not worth polluting it again. - HTTP sample conversion => http_conv.c This code doesn't depend on the internal representation but definitely manipulates some HTTP elements, such as dates. It also has access to captures. - HTTP sample fetching => http_fetch.c This code does depend entirely on the internal representation but is totally independent on the analysers. Placing it into a different file will ease the transition to the new representation and the creation of a wrapper if required. An include file was created due to CHECK_HTTP_MESSAGE_FIRST() being used at various places. - HTTP action registration => http_act.c This code doesn't directly interact with the messages nor the transaction but it does so via some exported http functions like http_replace_req_line() or http_set_status() so it will be easier to change only this after the conversion. - a few very generic parts were found and moved to http.{c,h} as relevant. It is worth noting that the functions moved to these new files are not referenced anywhere outside of the files and are only called as registered callbacks, so these files do not even require associated include files.
2018-10-02 10:01:16 -04:00
}
/* parse an http-request action among :
* set-method
* set-path
* set-pathq
REORG: http: move the code to different files The current proto_http.c file is huge and contains different processing domains making it very difficult to work on an alternative representation. This commit moves some parts to other files : - ACL registration code => http_acl.c This code only creates some ACL mappings and doesn't know anything about HTTP nor about the representation. This code could even have moved to acl.c but it was not worth polluting it again. - HTTP sample conversion => http_conv.c This code doesn't depend on the internal representation but definitely manipulates some HTTP elements, such as dates. It also has access to captures. - HTTP sample fetching => http_fetch.c This code does depend entirely on the internal representation but is totally independent on the analysers. Placing it into a different file will ease the transition to the new representation and the creation of a wrapper if required. An include file was created due to CHECK_HTTP_MESSAGE_FIRST() being used at various places. - HTTP action registration => http_act.c This code doesn't directly interact with the messages nor the transaction but it does so via some exported http functions like http_replace_req_line() or http_set_status() so it will be easier to change only this after the conversion. - a few very generic parts were found and moved to http.{c,h} as relevant. It is worth noting that the functions moved to these new files are not referenced anywhere outside of the files and are only called as registered callbacks, so these files do not even require associated include files.
2018-10-02 10:01:16 -04:00
* set-query
* set-uri
*
* All of them accept a single argument of type string representing a log-format.
* The resulting rule makes use of <http.fmt> to store the log-format list head,
* and <.action> to store the action type as an int (0=method, 1=path, 2=query,
* 3=uri). It returns ACT_RET_PRS_OK on success, ACT_RET_PRS_ERR on error.
REORG: http: move the code to different files The current proto_http.c file is huge and contains different processing domains making it very difficult to work on an alternative representation. This commit moves some parts to other files : - ACL registration code => http_acl.c This code only creates some ACL mappings and doesn't know anything about HTTP nor about the representation. This code could even have moved to acl.c but it was not worth polluting it again. - HTTP sample conversion => http_conv.c This code doesn't depend on the internal representation but definitely manipulates some HTTP elements, such as dates. It also has access to captures. - HTTP sample fetching => http_fetch.c This code does depend entirely on the internal representation but is totally independent on the analysers. Placing it into a different file will ease the transition to the new representation and the creation of a wrapper if required. An include file was created due to CHECK_HTTP_MESSAGE_FIRST() being used at various places. - HTTP action registration => http_act.c This code doesn't directly interact with the messages nor the transaction but it does so via some exported http functions like http_replace_req_line() or http_set_status() so it will be easier to change only this after the conversion. - a few very generic parts were found and moved to http.{c,h} as relevant. It is worth noting that the functions moved to these new files are not referenced anywhere outside of the files and are only called as registered callbacks, so these files do not even require associated include files.
2018-10-02 10:01:16 -04:00
*/
static enum act_parse_ret parse_set_req_line(const char **args, int *orig_arg, struct proxy *px,
struct act_rule *rule, char **err)
{
int cur_arg = *orig_arg;
int cap = 0;
REORG: http: move the code to different files The current proto_http.c file is huge and contains different processing domains making it very difficult to work on an alternative representation. This commit moves some parts to other files : - ACL registration code => http_acl.c This code only creates some ACL mappings and doesn't know anything about HTTP nor about the representation. This code could even have moved to acl.c but it was not worth polluting it again. - HTTP sample conversion => http_conv.c This code doesn't depend on the internal representation but definitely manipulates some HTTP elements, such as dates. It also has access to captures. - HTTP sample fetching => http_fetch.c This code does depend entirely on the internal representation but is totally independent on the analysers. Placing it into a different file will ease the transition to the new representation and the creation of a wrapper if required. An include file was created due to CHECK_HTTP_MESSAGE_FIRST() being used at various places. - HTTP action registration => http_act.c This code doesn't directly interact with the messages nor the transaction but it does so via some exported http functions like http_replace_req_line() or http_set_status() so it will be easier to change only this after the conversion. - a few very generic parts were found and moved to http.{c,h} as relevant. It is worth noting that the functions moved to these new files are not referenced anywhere outside of the files and are only called as registered callbacks, so these files do not even require associated include files.
2018-10-02 10:01:16 -04:00
switch (args[0][4]) {
case 'm' :
rule->action = 0; // set-method
REORG: http: move the code to different files The current proto_http.c file is huge and contains different processing domains making it very difficult to work on an alternative representation. This commit moves some parts to other files : - ACL registration code => http_acl.c This code only creates some ACL mappings and doesn't know anything about HTTP nor about the representation. This code could even have moved to acl.c but it was not worth polluting it again. - HTTP sample conversion => http_conv.c This code doesn't depend on the internal representation but definitely manipulates some HTTP elements, such as dates. It also has access to captures. - HTTP sample fetching => http_fetch.c This code does depend entirely on the internal representation but is totally independent on the analysers. Placing it into a different file will ease the transition to the new representation and the creation of a wrapper if required. An include file was created due to CHECK_HTTP_MESSAGE_FIRST() being used at various places. - HTTP action registration => http_act.c This code doesn't directly interact with the messages nor the transaction but it does so via some exported http functions like http_replace_req_line() or http_set_status() so it will be easier to change only this after the conversion. - a few very generic parts were found and moved to http.{c,h} as relevant. It is worth noting that the functions moved to these new files are not referenced anywhere outside of the files and are only called as registered callbacks, so these files do not even require associated include files.
2018-10-02 10:01:16 -04:00
break;
case 'p' :
if (args[0][8] == 'q')
rule->action = 4; // set-pathq
else
rule->action = 1; // set-path
REORG: http: move the code to different files The current proto_http.c file is huge and contains different processing domains making it very difficult to work on an alternative representation. This commit moves some parts to other files : - ACL registration code => http_acl.c This code only creates some ACL mappings and doesn't know anything about HTTP nor about the representation. This code could even have moved to acl.c but it was not worth polluting it again. - HTTP sample conversion => http_conv.c This code doesn't depend on the internal representation but definitely manipulates some HTTP elements, such as dates. It also has access to captures. - HTTP sample fetching => http_fetch.c This code does depend entirely on the internal representation but is totally independent on the analysers. Placing it into a different file will ease the transition to the new representation and the creation of a wrapper if required. An include file was created due to CHECK_HTTP_MESSAGE_FIRST() being used at various places. - HTTP action registration => http_act.c This code doesn't directly interact with the messages nor the transaction but it does so via some exported http functions like http_replace_req_line() or http_set_status() so it will be easier to change only this after the conversion. - a few very generic parts were found and moved to http.{c,h} as relevant. It is worth noting that the functions moved to these new files are not referenced anywhere outside of the files and are only called as registered callbacks, so these files do not even require associated include files.
2018-10-02 10:01:16 -04:00
break;
case 'q' :
rule->action = 2; // set-query
REORG: http: move the code to different files The current proto_http.c file is huge and contains different processing domains making it very difficult to work on an alternative representation. This commit moves some parts to other files : - ACL registration code => http_acl.c This code only creates some ACL mappings and doesn't know anything about HTTP nor about the representation. This code could even have moved to acl.c but it was not worth polluting it again. - HTTP sample conversion => http_conv.c This code doesn't depend on the internal representation but definitely manipulates some HTTP elements, such as dates. It also has access to captures. - HTTP sample fetching => http_fetch.c This code does depend entirely on the internal representation but is totally independent on the analysers. Placing it into a different file will ease the transition to the new representation and the creation of a wrapper if required. An include file was created due to CHECK_HTTP_MESSAGE_FIRST() being used at various places. - HTTP action registration => http_act.c This code doesn't directly interact with the messages nor the transaction but it does so via some exported http functions like http_replace_req_line() or http_set_status() so it will be easier to change only this after the conversion. - a few very generic parts were found and moved to http.{c,h} as relevant. It is worth noting that the functions moved to these new files are not referenced anywhere outside of the files and are only called as registered callbacks, so these files do not even require associated include files.
2018-10-02 10:01:16 -04:00
break;
case 'u' :
rule->action = 3; // set-uri
REORG: http: move the code to different files The current proto_http.c file is huge and contains different processing domains making it very difficult to work on an alternative representation. This commit moves some parts to other files : - ACL registration code => http_acl.c This code only creates some ACL mappings and doesn't know anything about HTTP nor about the representation. This code could even have moved to acl.c but it was not worth polluting it again. - HTTP sample conversion => http_conv.c This code doesn't depend on the internal representation but definitely manipulates some HTTP elements, such as dates. It also has access to captures. - HTTP sample fetching => http_fetch.c This code does depend entirely on the internal representation but is totally independent on the analysers. Placing it into a different file will ease the transition to the new representation and the creation of a wrapper if required. An include file was created due to CHECK_HTTP_MESSAGE_FIRST() being used at various places. - HTTP action registration => http_act.c This code doesn't directly interact with the messages nor the transaction but it does so via some exported http functions like http_replace_req_line() or http_set_status() so it will be easier to change only this after the conversion. - a few very generic parts were found and moved to http.{c,h} as relevant. It is worth noting that the functions moved to these new files are not referenced anywhere outside of the files and are only called as registered callbacks, so these files do not even require associated include files.
2018-10-02 10:01:16 -04:00
break;
default:
memprintf(err, "internal error: unhandled action '%s'", args[0]);
return ACT_RET_PRS_ERR;
}
rule->action_ptr = http_action_set_req_line;
rule->release_ptr = release_http_action;
MEDIUM: tree-wide: add logformat expressions wrapper log format expressions are broadly used within the code: once they are parsed from input string, they are converted to a linked list of logformat nodes. We're starting to face some limitations because we're simply storing the converted expression as a generic logformat_node list. The first issue we're facing is that storing logformat expressions that way doesn't allow us to add metadata alongside the list, which is part of the prerequites for implementing log-profiles. Another issue with storing logformat expressions as generic lists of logformat_node elements is that it's starting to become really hard to tell when we rely on logformat expressions or not in the code given that there isn't always a comment near the list declaration or manipulation to indicate that it's relying on logformat expressions under the hood, so this adds some complexity for code maintenance. This patch looks quite impressive due to changes in a lot of header and source files (since logformat expressions are broadly used), but it does a simple thing: it defines the lf_expr structure which itself holds a generic list of logformat nodes, and then declares some helpers to manipulate lf_expr elements and fixes the code so that we now exclusively manipulate logformat_node lists as lf_expr elements outside of log.c. For now, lf_expr struct only contains the list of logformat nodes (no additional metadata), but now that we have dedicated type and helpers, doing so in the future won't be problematic at all and won't require extensive code changes.
2024-02-23 09:57:21 -05:00
lf_expr_init(&rule->arg.http.fmt);
REORG: http: move the code to different files The current proto_http.c file is huge and contains different processing domains making it very difficult to work on an alternative representation. This commit moves some parts to other files : - ACL registration code => http_acl.c This code only creates some ACL mappings and doesn't know anything about HTTP nor about the representation. This code could even have moved to acl.c but it was not worth polluting it again. - HTTP sample conversion => http_conv.c This code doesn't depend on the internal representation but definitely manipulates some HTTP elements, such as dates. It also has access to captures. - HTTP sample fetching => http_fetch.c This code does depend entirely on the internal representation but is totally independent on the analysers. Placing it into a different file will ease the transition to the new representation and the creation of a wrapper if required. An include file was created due to CHECK_HTTP_MESSAGE_FIRST() being used at various places. - HTTP action registration => http_act.c This code doesn't directly interact with the messages nor the transaction but it does so via some exported http functions like http_replace_req_line() or http_set_status() so it will be easier to change only this after the conversion. - a few very generic parts were found and moved to http.{c,h} as relevant. It is worth noting that the functions moved to these new files are not referenced anywhere outside of the files and are only called as registered callbacks, so these files do not even require associated include files.
2018-10-02 10:01:16 -04:00
if (!*args[cur_arg] ||
(*args[cur_arg + 1] && strcmp(args[cur_arg + 1], "if") != 0 && strcmp(args[cur_arg + 1], "unless") != 0)) {
memprintf(err, "expects exactly 1 argument <format>");
return ACT_RET_PRS_ERR;
}
px->conf.args.ctx = ARGC_HRQ;
if (px->cap & PR_CAP_FE)
cap |= SMP_VAL_FE_HRQ_HDR;
if (px->cap & PR_CAP_BE)
cap |= SMP_VAL_BE_HRQ_HDR;
if (!parse_logformat_string(args[cur_arg], px, &rule->arg.http.fmt, LOG_OPT_HTTP, cap, err)) {
REORG: http: move the code to different files The current proto_http.c file is huge and contains different processing domains making it very difficult to work on an alternative representation. This commit moves some parts to other files : - ACL registration code => http_acl.c This code only creates some ACL mappings and doesn't know anything about HTTP nor about the representation. This code could even have moved to acl.c but it was not worth polluting it again. - HTTP sample conversion => http_conv.c This code doesn't depend on the internal representation but definitely manipulates some HTTP elements, such as dates. It also has access to captures. - HTTP sample fetching => http_fetch.c This code does depend entirely on the internal representation but is totally independent on the analysers. Placing it into a different file will ease the transition to the new representation and the creation of a wrapper if required. An include file was created due to CHECK_HTTP_MESSAGE_FIRST() being used at various places. - HTTP action registration => http_act.c This code doesn't directly interact with the messages nor the transaction but it does so via some exported http functions like http_replace_req_line() or http_set_status() so it will be easier to change only this after the conversion. - a few very generic parts were found and moved to http.{c,h} as relevant. It is worth noting that the functions moved to these new files are not referenced anywhere outside of the files and are only called as registered callbacks, so these files do not even require associated include files.
2018-10-02 10:01:16 -04:00
return ACT_RET_PRS_ERR;
}
(*orig_arg)++;
return ACT_RET_PRS_OK;
}
/* This function executes the http-request normalize-uri action.
* `rule->action` is expected to be a value from `enum act_normalize_uri`.
*
* On success, it returns ACT_RET_CONT. If an error
* occurs while soft rewrites are enabled, the action is canceled, but the rule
* processing continue. Otherwsize ACT_RET_ERR is returned.
*/
static enum act_return http_action_normalize_uri(struct act_rule *rule, struct proxy *px,
struct session *sess, struct stream *s, int flags)
{
enum act_return ret = ACT_RET_CONT;
struct htx *htx = htxbuf(&s->req.buf);
const struct ist uri = htx_sl_req_uri(http_get_stline(htx));
struct buffer *replace = alloc_trash_chunk();
enum uri_normalizer_err err = URI_NORMALIZER_ERR_INTERNAL_ERROR;
if (!replace)
goto fail_alloc;
switch ((enum act_normalize_uri) rule->action) {
case ACT_NORMALIZE_URI_PATH_MERGE_SLASHES: {
struct http_uri_parser parser = http_uri_parser_init(uri);
const struct ist path = http_parse_path(&parser);
struct ist newpath = ist2(replace->area, replace->size);
if (!isttest(path))
goto leave;
err = uri_normalizer_path_merge_slashes(iststop(path, '?'), &newpath);
if (err != URI_NORMALIZER_ERR_NONE)
break;
if (!http_replace_req_path(htx, newpath, 0))
goto fail_rewrite;
break;
}
case ACT_NORMALIZE_URI_PATH_STRIP_DOT: {
struct http_uri_parser parser = http_uri_parser_init(uri);
const struct ist path = http_parse_path(&parser);
struct ist newpath = ist2(replace->area, replace->size);
if (!isttest(path))
goto leave;
err = uri_normalizer_path_dot(iststop(path, '?'), &newpath);
if (err != URI_NORMALIZER_ERR_NONE)
break;
if (!http_replace_req_path(htx, newpath, 0))
goto fail_rewrite;
break;
}
case ACT_NORMALIZE_URI_PATH_STRIP_DOTDOT:
case ACT_NORMALIZE_URI_PATH_STRIP_DOTDOT_FULL: {
struct http_uri_parser parser = http_uri_parser_init(uri);
const struct ist path = http_parse_path(&parser);
struct ist newpath = ist2(replace->area, replace->size);
if (!isttest(path))
goto leave;
err = uri_normalizer_path_dotdot(iststop(path, '?'), rule->action == ACT_NORMALIZE_URI_PATH_STRIP_DOTDOT_FULL, &newpath);
if (err != URI_NORMALIZER_ERR_NONE)
break;
if (!http_replace_req_path(htx, newpath, 0))
goto fail_rewrite;
break;
}
case ACT_NORMALIZE_URI_QUERY_SORT_BY_NAME: {
struct http_uri_parser parser = http_uri_parser_init(uri);
const struct ist path = http_parse_path(&parser);
struct ist newquery = ist2(replace->area, replace->size);
if (!isttest(path))
goto leave;
err = uri_normalizer_query_sort(istfind(path, '?'), '&', &newquery);
if (err != URI_NORMALIZER_ERR_NONE)
break;
if (!http_replace_req_query(htx, newquery))
goto fail_rewrite;
break;
}
case ACT_NORMALIZE_URI_PERCENT_TO_UPPERCASE:
case ACT_NORMALIZE_URI_PERCENT_TO_UPPERCASE_STRICT: {
struct http_uri_parser parser = http_uri_parser_init(uri);
const struct ist path = http_parse_path(&parser);
struct ist newpath = ist2(replace->area, replace->size);
if (!isttest(path))
goto leave;
err = uri_normalizer_percent_upper(path, rule->action == ACT_NORMALIZE_URI_PERCENT_TO_UPPERCASE_STRICT, &newpath);
if (err != URI_NORMALIZER_ERR_NONE)
break;
if (!http_replace_req_path(htx, newpath, 1))
goto fail_rewrite;
break;
}
case ACT_NORMALIZE_URI_PERCENT_DECODE_UNRESERVED:
case ACT_NORMALIZE_URI_PERCENT_DECODE_UNRESERVED_STRICT: {
struct http_uri_parser parser = http_uri_parser_init(uri);
const struct ist path = http_parse_path(&parser);
struct ist newpath = ist2(replace->area, replace->size);
if (!isttest(path))
goto leave;
err = uri_normalizer_percent_decode_unreserved(path, rule->action == ACT_NORMALIZE_URI_PERCENT_DECODE_UNRESERVED_STRICT, &newpath);
if (err != URI_NORMALIZER_ERR_NONE)
break;
if (!http_replace_req_path(htx, newpath, 1))
goto fail_rewrite;
break;
}
case ACT_NORMALIZE_URI_FRAGMENT_STRIP: {
struct http_uri_parser parser = http_uri_parser_init(uri);
const struct ist path = http_parse_path(&parser);
struct ist newpath = ist2(replace->area, replace->size);
if (!isttest(path))
goto leave;
err = uri_normalizer_fragment_strip(path, &newpath);
if (err != URI_NORMALIZER_ERR_NONE)
break;
if (!http_replace_req_path(htx, newpath, 1))
goto fail_rewrite;
break;
}
case ACT_NORMALIZE_URI_FRAGMENT_ENCODE: {
struct http_uri_parser parser = http_uri_parser_init(uri);
const struct ist path = http_parse_path(&parser);
struct ist newpath = ist2(replace->area, replace->size);
if (!isttest(path))
goto leave;
err = uri_normalizer_fragment_encode(path, &newpath);
if (err != URI_NORMALIZER_ERR_NONE)
break;
if (!http_replace_req_path(htx, newpath, 1))
goto fail_rewrite;
break;
}
}
switch (err) {
case URI_NORMALIZER_ERR_NONE:
break;
case URI_NORMALIZER_ERR_INTERNAL_ERROR:
ret = ACT_RET_ERR;
break;
case URI_NORMALIZER_ERR_INVALID_INPUT:
ret = ACT_RET_INV;
break;
case URI_NORMALIZER_ERR_ALLOC:
goto fail_alloc;
}
leave:
free_trash_chunk(replace);
return ret;
fail_alloc:
if (!(s->flags & SF_ERR_MASK))
s->flags |= SF_ERR_RESOURCE;
ret = ACT_RET_ERR;
goto leave;
fail_rewrite:
_HA_ATOMIC_ADD(&sess->fe->fe_counters.failed_rewrites, 1);
if (s->flags & SF_BE_ASSIGNED)
_HA_ATOMIC_ADD(&s->be->be_counters.failed_rewrites, 1);
if (sess->listener && sess->listener->counters)
_HA_ATOMIC_ADD(&sess->listener->counters->failed_rewrites, 1);
if (objt_server(s->target))
_HA_ATOMIC_ADD(&__objt_server(s->target)->counters.failed_rewrites, 1);
if (!(s->txn->req.flags & HTTP_MSGF_SOFT_RW)) {
ret = ACT_RET_ERR;
if (!(s->flags & SF_ERR_MASK))
s->flags |= SF_ERR_PRXCOND;
}
goto leave;
}
/* Parses the http-request normalize-uri action. It expects a single <normalizer>
* argument, corresponding too a value in `enum act_normalize_uri`.
*
* It returns ACT_RET_PRS_OK on success, ACT_RET_PRS_ERR on error.
*/
static enum act_parse_ret parse_http_normalize_uri(const char **args, int *orig_arg, struct proxy *px,
struct act_rule *rule, char **err)
{
int cur_arg = *orig_arg;
rule->action_ptr = http_action_normalize_uri;
rule->release_ptr = NULL;
if (!*args[cur_arg]) {
memprintf(err, "missing argument <normalizer>");
return ACT_RET_PRS_ERR;
}
if (strcmp(args[cur_arg], "path-merge-slashes") == 0) {
cur_arg++;
rule->action = ACT_NORMALIZE_URI_PATH_MERGE_SLASHES;
}
else if (strcmp(args[cur_arg], "path-strip-dot") == 0) {
cur_arg++;
rule->action = ACT_NORMALIZE_URI_PATH_STRIP_DOT;
}
else if (strcmp(args[cur_arg], "path-strip-dotdot") == 0) {
cur_arg++;
if (strcmp(args[cur_arg], "full") == 0) {
cur_arg++;
rule->action = ACT_NORMALIZE_URI_PATH_STRIP_DOTDOT_FULL;
}
else if (!*args[cur_arg]) {
rule->action = ACT_NORMALIZE_URI_PATH_STRIP_DOTDOT;
}
else if (strcmp(args[cur_arg], "if") != 0 && strcmp(args[cur_arg], "unless") != 0) {
memprintf(err, "unknown argument '%s' for 'path-strip-dotdot' normalizer", args[cur_arg]);
return ACT_RET_PRS_ERR;
}
}
else if (strcmp(args[cur_arg], "query-sort-by-name") == 0) {
cur_arg++;
rule->action = ACT_NORMALIZE_URI_QUERY_SORT_BY_NAME;
}
else if (strcmp(args[cur_arg], "percent-to-uppercase") == 0) {
cur_arg++;
if (strcmp(args[cur_arg], "strict") == 0) {
cur_arg++;
rule->action = ACT_NORMALIZE_URI_PERCENT_TO_UPPERCASE_STRICT;
}
else if (!*args[cur_arg]) {
rule->action = ACT_NORMALIZE_URI_PERCENT_TO_UPPERCASE;
}
else if (strcmp(args[cur_arg], "if") != 0 && strcmp(args[cur_arg], "unless") != 0) {
memprintf(err, "unknown argument '%s' for 'percent-to-uppercase' normalizer", args[cur_arg]);
return ACT_RET_PRS_ERR;
}
}
else if (strcmp(args[cur_arg], "percent-decode-unreserved") == 0) {
cur_arg++;
if (strcmp(args[cur_arg], "strict") == 0) {
cur_arg++;
rule->action = ACT_NORMALIZE_URI_PERCENT_DECODE_UNRESERVED_STRICT;
}
else if (!*args[cur_arg]) {
rule->action = ACT_NORMALIZE_URI_PERCENT_DECODE_UNRESERVED;
}
else if (strcmp(args[cur_arg], "if") != 0 && strcmp(args[cur_arg], "unless") != 0) {
memprintf(err, "unknown argument '%s' for 'percent-decode-unreserved' normalizer", args[cur_arg]);
return ACT_RET_PRS_ERR;
}
}
else if (strcmp(args[cur_arg], "fragment-strip") == 0) {
cur_arg++;
rule->action = ACT_NORMALIZE_URI_FRAGMENT_STRIP;
}
else if (strcmp(args[cur_arg], "fragment-encode") == 0) {
cur_arg++;
rule->action = ACT_NORMALIZE_URI_FRAGMENT_ENCODE;
}
else {
memprintf(err, "unknown normalizer '%s'", args[cur_arg]);
return ACT_RET_PRS_ERR;
}
*orig_arg = cur_arg;
return ACT_RET_PRS_OK;
}
/* This function executes a replace-uri action. It finds its arguments in
* <rule>.arg.http. It builds a string in the trash from the format string
* previously filled by function parse_replace_uri() and will execute the regex
* in <http.re> to replace the URI. It uses the format string present in
* <http.fmt>. The component to act on (path/uri) is taken from <.action> which
* contains 1 for the path or 3 for the URI (values used by
* http_req_replace_stline()). On success, it returns ACT_RET_CONT. If an error
* occurs while soft rewrites are enabled, the action is canceled, but the rule
* processing continue. Otherwsize ACT_RET_ERR is returned.
*/
static enum act_return http_action_replace_uri(struct act_rule *rule, struct proxy *px,
struct session *sess, struct stream *s, int flags)
{
enum act_return ret = ACT_RET_CONT;
struct buffer *replace, *output;
struct ist uri;
int len;
replace = alloc_trash_chunk();
output = alloc_trash_chunk();
if (!replace || !output)
goto fail_alloc;
uri = htx_sl_req_uri(http_get_stline(htxbuf(&s->req.buf)));
if (rule->action == 1) { // replace-path
struct http_uri_parser parser = http_uri_parser_init(uri);
uri = iststop(http_parse_path(&parser), '?');
}
else if (rule->action == 4) { // replace-pathq
struct http_uri_parser parser = http_uri_parser_init(uri);
uri = http_parse_path(&parser);
}
if (!istlen(uri))
goto leave;
if (!regex_exec_match2(rule->arg.http.re, uri.ptr, uri.len, MAX_MATCH, pmatch, 0))
goto leave;
replace->data = build_logline(s, replace->area, replace->size, &rule->arg.http.fmt);
/* note: uri.ptr doesn't need to be zero-terminated because it will
* only be used to pick pmatch references.
*/
len = exp_replace(output->area, output->size, uri.ptr, replace->area, pmatch);
if (len == -1)
goto fail_rewrite;
if (http_req_replace_stline(rule->action, output->area, len, px, s) == -1)
goto fail_rewrite;
leave:
free_trash_chunk(output);
free_trash_chunk(replace);
return ret;
fail_alloc:
if (!(s->flags & SF_ERR_MASK))
s->flags |= SF_ERR_RESOURCE;
ret = ACT_RET_ERR;
goto leave;
fail_rewrite:
_HA_ATOMIC_INC(&sess->fe->fe_counters.failed_rewrites);
if (s->flags & SF_BE_ASSIGNED)
_HA_ATOMIC_INC(&s->be->be_counters.failed_rewrites);
if (sess->listener && sess->listener->counters)
_HA_ATOMIC_INC(&sess->listener->counters->failed_rewrites);
if (objt_server(s->target))
_HA_ATOMIC_INC(&__objt_server(s->target)->counters.failed_rewrites);
if (!(s->txn->req.flags & HTTP_MSGF_SOFT_RW)) {
ret = ACT_RET_ERR;
if (!(s->flags & SF_ERR_MASK))
s->flags |= SF_ERR_PRXCOND;
}
goto leave;
}
/* parse a "replace-uri", "replace-path" or "replace-pathq"
* http-request action.
* This action takes 2 arguments (a regex and a replacement format string).
* The resulting rule makes use of <.action> to store the action (1/3 for now),
* <http.re> to store the compiled regex, and <http.fmt> to store the log-format
* list head. It returns ACT_RET_PRS_OK on success, ACT_RET_PRS_ERR on error.
*/
static enum act_parse_ret parse_replace_uri(const char **args, int *orig_arg, struct proxy *px,
struct act_rule *rule, char **err)
{
int cur_arg = *orig_arg;
int cap = 0;
char *error = NULL;
switch (args[0][8]) {
case 'p':
if (args[0][12] == 'q')
rule->action = 4; // replace-pathq, same as set-pathq
else
rule->action = 1; // replace-path, same as set-path
break;
case 'u':
rule->action = 3; // replace-uri, same as set-uri
break;
default:
memprintf(err, "internal error: unhandled action '%s'", args[0]);
return ACT_RET_PRS_ERR;
}
rule->action_ptr = http_action_replace_uri;
rule->release_ptr = release_http_action;
MEDIUM: tree-wide: add logformat expressions wrapper log format expressions are broadly used within the code: once they are parsed from input string, they are converted to a linked list of logformat nodes. We're starting to face some limitations because we're simply storing the converted expression as a generic logformat_node list. The first issue we're facing is that storing logformat expressions that way doesn't allow us to add metadata alongside the list, which is part of the prerequites for implementing log-profiles. Another issue with storing logformat expressions as generic lists of logformat_node elements is that it's starting to become really hard to tell when we rely on logformat expressions or not in the code given that there isn't always a comment near the list declaration or manipulation to indicate that it's relying on logformat expressions under the hood, so this adds some complexity for code maintenance. This patch looks quite impressive due to changes in a lot of header and source files (since logformat expressions are broadly used), but it does a simple thing: it defines the lf_expr structure which itself holds a generic list of logformat nodes, and then declares some helpers to manipulate lf_expr elements and fixes the code so that we now exclusively manipulate logformat_node lists as lf_expr elements outside of log.c. For now, lf_expr struct only contains the list of logformat nodes (no additional metadata), but now that we have dedicated type and helpers, doing so in the future won't be problematic at all and won't require extensive code changes.
2024-02-23 09:57:21 -05:00
lf_expr_init(&rule->arg.http.fmt);
if (!*args[cur_arg] || !*args[cur_arg+1] ||
(*args[cur_arg+2] && strcmp(args[cur_arg+2], "if") != 0 && strcmp(args[cur_arg+2], "unless") != 0)) {
memprintf(err, "expects exactly 2 arguments <match-regex> and <replace-format>");
return ACT_RET_PRS_ERR;
}
if (!(rule->arg.http.re = regex_comp(args[cur_arg], 1, 1, &error))) {
memprintf(err, "failed to parse the regex : %s", error);
free(error);
return ACT_RET_PRS_ERR;
}
px->conf.args.ctx = ARGC_HRQ;
if (px->cap & PR_CAP_FE)
cap |= SMP_VAL_FE_HRQ_HDR;
if (px->cap & PR_CAP_BE)
cap |= SMP_VAL_BE_HRQ_HDR;
if (!parse_logformat_string(args[cur_arg + 1], px, &rule->arg.http.fmt, LOG_OPT_HTTP, cap, err)) {
regex_free(rule->arg.http.re);
return ACT_RET_PRS_ERR;
}
(*orig_arg) += 2;
return ACT_RET_PRS_OK;
}
REORG: http: move the code to different files The current proto_http.c file is huge and contains different processing domains making it very difficult to work on an alternative representation. This commit moves some parts to other files : - ACL registration code => http_acl.c This code only creates some ACL mappings and doesn't know anything about HTTP nor about the representation. This code could even have moved to acl.c but it was not worth polluting it again. - HTTP sample conversion => http_conv.c This code doesn't depend on the internal representation but definitely manipulates some HTTP elements, such as dates. It also has access to captures. - HTTP sample fetching => http_fetch.c This code does depend entirely on the internal representation but is totally independent on the analysers. Placing it into a different file will ease the transition to the new representation and the creation of a wrapper if required. An include file was created due to CHECK_HTTP_MESSAGE_FIRST() being used at various places. - HTTP action registration => http_act.c This code doesn't directly interact with the messages nor the transaction but it does so via some exported http functions like http_replace_req_line() or http_set_status() so it will be easier to change only this after the conversion. - a few very generic parts were found and moved to http.{c,h} as relevant. It is worth noting that the functions moved to these new files are not referenced anywhere outside of the files and are only called as registered callbacks, so these files do not even require associated include files.
2018-10-02 10:01:16 -04:00
/* This function is just a compliant action wrapper for "set-status". */
static enum act_return action_http_set_status(struct act_rule *rule, struct proxy *px,
struct session *sess, struct stream *s, int flags)
{
if (http_res_set_status(rule->arg.http.i, rule->arg.http.str, s) == -1) {
_HA_ATOMIC_INC(&sess->fe->fe_counters.failed_rewrites);
if (s->flags & SF_BE_ASSIGNED)
_HA_ATOMIC_INC(&s->be->be_counters.failed_rewrites);
if (sess->listener && sess->listener->counters)
_HA_ATOMIC_INC(&sess->listener->counters->failed_rewrites);
if (objt_server(s->target))
_HA_ATOMIC_INC(&__objt_server(s->target)->counters.failed_rewrites);
if (!(s->txn->req.flags & HTTP_MSGF_SOFT_RW)) {
if (!(s->flags & SF_ERR_MASK))
s->flags |= SF_ERR_PRXCOND;
return ACT_RET_ERR;
}
}
REORG: http: move the code to different files The current proto_http.c file is huge and contains different processing domains making it very difficult to work on an alternative representation. This commit moves some parts to other files : - ACL registration code => http_acl.c This code only creates some ACL mappings and doesn't know anything about HTTP nor about the representation. This code could even have moved to acl.c but it was not worth polluting it again. - HTTP sample conversion => http_conv.c This code doesn't depend on the internal representation but definitely manipulates some HTTP elements, such as dates. It also has access to captures. - HTTP sample fetching => http_fetch.c This code does depend entirely on the internal representation but is totally independent on the analysers. Placing it into a different file will ease the transition to the new representation and the creation of a wrapper if required. An include file was created due to CHECK_HTTP_MESSAGE_FIRST() being used at various places. - HTTP action registration => http_act.c This code doesn't directly interact with the messages nor the transaction but it does so via some exported http functions like http_replace_req_line() or http_set_status() so it will be easier to change only this after the conversion. - a few very generic parts were found and moved to http.{c,h} as relevant. It is worth noting that the functions moved to these new files are not referenced anywhere outside of the files and are only called as registered callbacks, so these files do not even require associated include files.
2018-10-02 10:01:16 -04:00
return ACT_RET_CONT;
}
/* parse set-status action:
* This action accepts a single argument of type int representing
* an http status code. It returns ACT_RET_PRS_OK on success,
* ACT_RET_PRS_ERR on error.
*/
static enum act_parse_ret parse_http_set_status(const char **args, int *orig_arg, struct proxy *px,
struct act_rule *rule, char **err)
{
char *error;
rule->action = ACT_CUSTOM;
rule->action_ptr = action_http_set_status;
rule->release_ptr = release_http_action;
MEDIUM: tree-wide: add logformat expressions wrapper log format expressions are broadly used within the code: once they are parsed from input string, they are converted to a linked list of logformat nodes. We're starting to face some limitations because we're simply storing the converted expression as a generic logformat_node list. The first issue we're facing is that storing logformat expressions that way doesn't allow us to add metadata alongside the list, which is part of the prerequites for implementing log-profiles. Another issue with storing logformat expressions as generic lists of logformat_node elements is that it's starting to become really hard to tell when we rely on logformat expressions or not in the code given that there isn't always a comment near the list declaration or manipulation to indicate that it's relying on logformat expressions under the hood, so this adds some complexity for code maintenance. This patch looks quite impressive due to changes in a lot of header and source files (since logformat expressions are broadly used), but it does a simple thing: it defines the lf_expr structure which itself holds a generic list of logformat nodes, and then declares some helpers to manipulate lf_expr elements and fixes the code so that we now exclusively manipulate logformat_node lists as lf_expr elements outside of log.c. For now, lf_expr struct only contains the list of logformat nodes (no additional metadata), but now that we have dedicated type and helpers, doing so in the future won't be problematic at all and won't require extensive code changes.
2024-02-23 09:57:21 -05:00
lf_expr_init(&rule->arg.http.fmt);
REORG: http: move the code to different files The current proto_http.c file is huge and contains different processing domains making it very difficult to work on an alternative representation. This commit moves some parts to other files : - ACL registration code => http_acl.c This code only creates some ACL mappings and doesn't know anything about HTTP nor about the representation. This code could even have moved to acl.c but it was not worth polluting it again. - HTTP sample conversion => http_conv.c This code doesn't depend on the internal representation but definitely manipulates some HTTP elements, such as dates. It also has access to captures. - HTTP sample fetching => http_fetch.c This code does depend entirely on the internal representation but is totally independent on the analysers. Placing it into a different file will ease the transition to the new representation and the creation of a wrapper if required. An include file was created due to CHECK_HTTP_MESSAGE_FIRST() being used at various places. - HTTP action registration => http_act.c This code doesn't directly interact with the messages nor the transaction but it does so via some exported http functions like http_replace_req_line() or http_set_status() so it will be easier to change only this after the conversion. - a few very generic parts were found and moved to http.{c,h} as relevant. It is worth noting that the functions moved to these new files are not referenced anywhere outside of the files and are only called as registered callbacks, so these files do not even require associated include files.
2018-10-02 10:01:16 -04:00
/* Check if an argument is available */
if (!*args[*orig_arg]) {
memprintf(err, "expects 1 argument: <status>; or 3 arguments: <status> reason <fmt>");
return ACT_RET_PRS_ERR;
}
/* convert status code as integer */
rule->arg.http.i = strtol(args[*orig_arg], &error, 10);
if (*error != '\0' || rule->arg.http.i < 100 || rule->arg.http.i > 999) {
REORG: http: move the code to different files The current proto_http.c file is huge and contains different processing domains making it very difficult to work on an alternative representation. This commit moves some parts to other files : - ACL registration code => http_acl.c This code only creates some ACL mappings and doesn't know anything about HTTP nor about the representation. This code could even have moved to acl.c but it was not worth polluting it again. - HTTP sample conversion => http_conv.c This code doesn't depend on the internal representation but definitely manipulates some HTTP elements, such as dates. It also has access to captures. - HTTP sample fetching => http_fetch.c This code does depend entirely on the internal representation but is totally independent on the analysers. Placing it into a different file will ease the transition to the new representation and the creation of a wrapper if required. An include file was created due to CHECK_HTTP_MESSAGE_FIRST() being used at various places. - HTTP action registration => http_act.c This code doesn't directly interact with the messages nor the transaction but it does so via some exported http functions like http_replace_req_line() or http_set_status() so it will be easier to change only this after the conversion. - a few very generic parts were found and moved to http.{c,h} as relevant. It is worth noting that the functions moved to these new files are not referenced anywhere outside of the files and are only called as registered callbacks, so these files do not even require associated include files.
2018-10-02 10:01:16 -04:00
memprintf(err, "expects an integer status code between 100 and 999");
return ACT_RET_PRS_ERR;
}
(*orig_arg)++;
/* set custom reason string */
rule->arg.http.str = ist(NULL); // If null, we use the default reason for the status code.
REORG: http: move the code to different files The current proto_http.c file is huge and contains different processing domains making it very difficult to work on an alternative representation. This commit moves some parts to other files : - ACL registration code => http_acl.c This code only creates some ACL mappings and doesn't know anything about HTTP nor about the representation. This code could even have moved to acl.c but it was not worth polluting it again. - HTTP sample conversion => http_conv.c This code doesn't depend on the internal representation but definitely manipulates some HTTP elements, such as dates. It also has access to captures. - HTTP sample fetching => http_fetch.c This code does depend entirely on the internal representation but is totally independent on the analysers. Placing it into a different file will ease the transition to the new representation and the creation of a wrapper if required. An include file was created due to CHECK_HTTP_MESSAGE_FIRST() being used at various places. - HTTP action registration => http_act.c This code doesn't directly interact with the messages nor the transaction but it does so via some exported http functions like http_replace_req_line() or http_set_status() so it will be easier to change only this after the conversion. - a few very generic parts were found and moved to http.{c,h} as relevant. It is worth noting that the functions moved to these new files are not referenced anywhere outside of the files and are only called as registered callbacks, so these files do not even require associated include files.
2018-10-02 10:01:16 -04:00
if (*args[*orig_arg] && strcmp(args[*orig_arg], "reason") == 0 &&
(*args[*orig_arg + 1] && strcmp(args[*orig_arg + 1], "if") != 0 && strcmp(args[*orig_arg + 1], "unless") != 0)) {
(*orig_arg)++;
rule->arg.http.str = ist(strdup(args[*orig_arg]));
REORG: http: move the code to different files The current proto_http.c file is huge and contains different processing domains making it very difficult to work on an alternative representation. This commit moves some parts to other files : - ACL registration code => http_acl.c This code only creates some ACL mappings and doesn't know anything about HTTP nor about the representation. This code could even have moved to acl.c but it was not worth polluting it again. - HTTP sample conversion => http_conv.c This code doesn't depend on the internal representation but definitely manipulates some HTTP elements, such as dates. It also has access to captures. - HTTP sample fetching => http_fetch.c This code does depend entirely on the internal representation but is totally independent on the analysers. Placing it into a different file will ease the transition to the new representation and the creation of a wrapper if required. An include file was created due to CHECK_HTTP_MESSAGE_FIRST() being used at various places. - HTTP action registration => http_act.c This code doesn't directly interact with the messages nor the transaction but it does so via some exported http functions like http_replace_req_line() or http_set_status() so it will be easier to change only this after the conversion. - a few very generic parts were found and moved to http.{c,h} as relevant. It is worth noting that the functions moved to these new files are not referenced anywhere outside of the files and are only called as registered callbacks, so these files do not even require associated include files.
2018-10-02 10:01:16 -04:00
(*orig_arg)++;
}
return ACT_RET_PRS_OK;
}
/* This function executes the "reject" HTTP action. It clears the request and
* response buffer without sending any response. It can be useful as an HTTP
* alternative to the silent-drop action to defend against DoS attacks, and may
* also be used with HTTP/2 to close a connection instead of just a stream.
* The txn status is unchanged, indicating no response was sent. The termination
* flags will indicate "PR". It always returns ACT_RET_ABRT.
REORG: http: move the code to different files The current proto_http.c file is huge and contains different processing domains making it very difficult to work on an alternative representation. This commit moves some parts to other files : - ACL registration code => http_acl.c This code only creates some ACL mappings and doesn't know anything about HTTP nor about the representation. This code could even have moved to acl.c but it was not worth polluting it again. - HTTP sample conversion => http_conv.c This code doesn't depend on the internal representation but definitely manipulates some HTTP elements, such as dates. It also has access to captures. - HTTP sample fetching => http_fetch.c This code does depend entirely on the internal representation but is totally independent on the analysers. Placing it into a different file will ease the transition to the new representation and the creation of a wrapper if required. An include file was created due to CHECK_HTTP_MESSAGE_FIRST() being used at various places. - HTTP action registration => http_act.c This code doesn't directly interact with the messages nor the transaction but it does so via some exported http functions like http_replace_req_line() or http_set_status() so it will be easier to change only this after the conversion. - a few very generic parts were found and moved to http.{c,h} as relevant. It is worth noting that the functions moved to these new files are not referenced anywhere outside of the files and are only called as registered callbacks, so these files do not even require associated include files.
2018-10-02 10:01:16 -04:00
*/
static enum act_return http_action_reject(struct act_rule *rule, struct proxy *px,
struct session *sess, struct stream *s, int flags)
{
sc_must_kill_conn(s->scf);
stream_abort(s);
s->req.analysers &= AN_REQ_FLT_END;
s->res.analysers &= AN_RES_FLT_END;
REORG: http: move the code to different files The current proto_http.c file is huge and contains different processing domains making it very difficult to work on an alternative representation. This commit moves some parts to other files : - ACL registration code => http_acl.c This code only creates some ACL mappings and doesn't know anything about HTTP nor about the representation. This code could even have moved to acl.c but it was not worth polluting it again. - HTTP sample conversion => http_conv.c This code doesn't depend on the internal representation but definitely manipulates some HTTP elements, such as dates. It also has access to captures. - HTTP sample fetching => http_fetch.c This code does depend entirely on the internal representation but is totally independent on the analysers. Placing it into a different file will ease the transition to the new representation and the creation of a wrapper if required. An include file was created due to CHECK_HTTP_MESSAGE_FIRST() being used at various places. - HTTP action registration => http_act.c This code doesn't directly interact with the messages nor the transaction but it does so via some exported http functions like http_replace_req_line() or http_set_status() so it will be easier to change only this after the conversion. - a few very generic parts were found and moved to http.{c,h} as relevant. It is worth noting that the functions moved to these new files are not referenced anywhere outside of the files and are only called as registered callbacks, so these files do not even require associated include files.
2018-10-02 10:01:16 -04:00
_HA_ATOMIC_INC(&s->be->be_counters.denied_req);
_HA_ATOMIC_INC(&sess->fe->fe_counters.denied_req);
REORG: http: move the code to different files The current proto_http.c file is huge and contains different processing domains making it very difficult to work on an alternative representation. This commit moves some parts to other files : - ACL registration code => http_acl.c This code only creates some ACL mappings and doesn't know anything about HTTP nor about the representation. This code could even have moved to acl.c but it was not worth polluting it again. - HTTP sample conversion => http_conv.c This code doesn't depend on the internal representation but definitely manipulates some HTTP elements, such as dates. It also has access to captures. - HTTP sample fetching => http_fetch.c This code does depend entirely on the internal representation but is totally independent on the analysers. Placing it into a different file will ease the transition to the new representation and the creation of a wrapper if required. An include file was created due to CHECK_HTTP_MESSAGE_FIRST() being used at various places. - HTTP action registration => http_act.c This code doesn't directly interact with the messages nor the transaction but it does so via some exported http functions like http_replace_req_line() or http_set_status() so it will be easier to change only this after the conversion. - a few very generic parts were found and moved to http.{c,h} as relevant. It is worth noting that the functions moved to these new files are not referenced anywhere outside of the files and are only called as registered callbacks, so these files do not even require associated include files.
2018-10-02 10:01:16 -04:00
if (sess->listener && sess->listener->counters)
_HA_ATOMIC_INC(&sess->listener->counters->denied_req);
REORG: http: move the code to different files The current proto_http.c file is huge and contains different processing domains making it very difficult to work on an alternative representation. This commit moves some parts to other files : - ACL registration code => http_acl.c This code only creates some ACL mappings and doesn't know anything about HTTP nor about the representation. This code could even have moved to acl.c but it was not worth polluting it again. - HTTP sample conversion => http_conv.c This code doesn't depend on the internal representation but definitely manipulates some HTTP elements, such as dates. It also has access to captures. - HTTP sample fetching => http_fetch.c This code does depend entirely on the internal representation but is totally independent on the analysers. Placing it into a different file will ease the transition to the new representation and the creation of a wrapper if required. An include file was created due to CHECK_HTTP_MESSAGE_FIRST() being used at various places. - HTTP action registration => http_act.c This code doesn't directly interact with the messages nor the transaction but it does so via some exported http functions like http_replace_req_line() or http_set_status() so it will be easier to change only this after the conversion. - a few very generic parts were found and moved to http.{c,h} as relevant. It is worth noting that the functions moved to these new files are not referenced anywhere outside of the files and are only called as registered callbacks, so these files do not even require associated include files.
2018-10-02 10:01:16 -04:00
if (!(s->flags & SF_ERR_MASK))
s->flags |= SF_ERR_PRXCOND;
if (!(s->flags & SF_FINST_MASK))
s->flags |= SF_FINST_R;
return ACT_RET_ABRT;
REORG: http: move the code to different files The current proto_http.c file is huge and contains different processing domains making it very difficult to work on an alternative representation. This commit moves some parts to other files : - ACL registration code => http_acl.c This code only creates some ACL mappings and doesn't know anything about HTTP nor about the representation. This code could even have moved to acl.c but it was not worth polluting it again. - HTTP sample conversion => http_conv.c This code doesn't depend on the internal representation but definitely manipulates some HTTP elements, such as dates. It also has access to captures. - HTTP sample fetching => http_fetch.c This code does depend entirely on the internal representation but is totally independent on the analysers. Placing it into a different file will ease the transition to the new representation and the creation of a wrapper if required. An include file was created due to CHECK_HTTP_MESSAGE_FIRST() being used at various places. - HTTP action registration => http_act.c This code doesn't directly interact with the messages nor the transaction but it does so via some exported http functions like http_replace_req_line() or http_set_status() so it will be easier to change only this after the conversion. - a few very generic parts were found and moved to http.{c,h} as relevant. It is worth noting that the functions moved to these new files are not referenced anywhere outside of the files and are only called as registered callbacks, so these files do not even require associated include files.
2018-10-02 10:01:16 -04:00
}
/* parse the "reject" action:
* This action takes no argument and returns ACT_RET_PRS_OK on success,
* ACT_RET_PRS_ERR on error.
*/
static enum act_parse_ret parse_http_action_reject(const char **args, int *orig_arg, struct proxy *px,
struct act_rule *rule, char **err)
{
rule->action = ACT_CUSTOM;
rule->action_ptr = http_action_reject;
return ACT_RET_PRS_OK;
}
/* This function executes the "disable-l7-retry" HTTP action.
* It disables L7 retries (all retry except for a connection failure). This
* can be useful for example to avoid retrying on POST requests.
* It just removes the L7 retry flag on the HTTP transaction, and always
* return ACT_RET_CONT;
*/
static enum act_return http_req_disable_l7_retry(struct act_rule *rule, struct proxy *px,
struct session *sess, struct stream *s, int flags)
{
/* In theory, the TX_L7_RETRY flags isn't set at this point, but
* let's be future-proof and remove it anyway.
*/
s->txn->flags &= ~TX_L7_RETRY;
s->txn->flags |= TX_D_L7_RETRY;
return ACT_RET_CONT;
}
/* parse the "disable-l7-retry" action:
* This action takes no argument and returns ACT_RET_PRS_OK on success,
* ACT_RET_PRS_ERR on error.
*/
static enum act_parse_ret parse_http_req_disable_l7_retry(const char **args,
int *orig_args, struct proxy *px,
struct act_rule *rule, char **err)
{
rule->action = ACT_CUSTOM;
rule->action_ptr = http_req_disable_l7_retry;
return ACT_RET_PRS_OK;
}
REORG: http: move the code to different files The current proto_http.c file is huge and contains different processing domains making it very difficult to work on an alternative representation. This commit moves some parts to other files : - ACL registration code => http_acl.c This code only creates some ACL mappings and doesn't know anything about HTTP nor about the representation. This code could even have moved to acl.c but it was not worth polluting it again. - HTTP sample conversion => http_conv.c This code doesn't depend on the internal representation but definitely manipulates some HTTP elements, such as dates. It also has access to captures. - HTTP sample fetching => http_fetch.c This code does depend entirely on the internal representation but is totally independent on the analysers. Placing it into a different file will ease the transition to the new representation and the creation of a wrapper if required. An include file was created due to CHECK_HTTP_MESSAGE_FIRST() being used at various places. - HTTP action registration => http_act.c This code doesn't directly interact with the messages nor the transaction but it does so via some exported http functions like http_replace_req_line() or http_set_status() so it will be easier to change only this after the conversion. - a few very generic parts were found and moved to http.{c,h} as relevant. It is worth noting that the functions moved to these new files are not referenced anywhere outside of the files and are only called as registered callbacks, so these files do not even require associated include files.
2018-10-02 10:01:16 -04:00
/* This function executes the "capture" action. It executes a fetch expression,
* turns the result into a string and puts it in a capture slot. It always
* returns 1. If an error occurs the action is cancelled, but the rule
* processing continues.
*/
static enum act_return http_action_req_capture(struct act_rule *rule, struct proxy *px,
struct session *sess, struct stream *s, int flags)
{
struct sample *key;
struct cap_hdr *h = rule->arg.cap.hdr;
char **cap = s->req_cap;
int len;
key = sample_fetch_as_type(s->be, sess, s, SMP_OPT_DIR_REQ|SMP_OPT_FINAL, rule->arg.cap.expr, SMP_T_STR);
if (!key)
return ACT_RET_CONT;
if (cap[h->index] == NULL)
cap[h->index] = pool_alloc(h->pool);
if (cap[h->index] == NULL) /* no more capture memory */
return ACT_RET_CONT;
len = key->data.u.str.data;
if (len > h->len)
len = h->len;
memcpy(cap[h->index], key->data.u.str.area, len);
cap[h->index][len] = 0;
return ACT_RET_CONT;
}
/* This function executes the "capture" action and store the result in a
* capture slot if exists. It executes a fetch expression, turns the result
* into a string and puts it in a capture slot. It always returns 1. If an
* error occurs the action is cancelled, but the rule processing continues.
*/
static enum act_return http_action_req_capture_by_id(struct act_rule *rule, struct proxy *px,
struct session *sess, struct stream *s, int flags)
{
struct sample *key;
struct cap_hdr *h;
char **cap = s->req_cap;
struct proxy *fe = strm_fe(s);
int len;
int i;
/* Look for the original configuration. */
for (h = fe->req_cap, i = fe->nb_req_cap - 1;
h != NULL && i != rule->arg.capid.idx ;
i--, h = h->next);
if (!h)
return ACT_RET_CONT;
key = sample_fetch_as_type(s->be, sess, s, SMP_OPT_DIR_REQ|SMP_OPT_FINAL, rule->arg.capid.expr, SMP_T_STR);
if (!key)
return ACT_RET_CONT;
if (cap[h->index] == NULL)
cap[h->index] = pool_alloc(h->pool);
if (cap[h->index] == NULL) /* no more capture memory */
return ACT_RET_CONT;
len = key->data.u.str.data;
if (len > h->len)
len = h->len;
memcpy(cap[h->index], key->data.u.str.area, len);
cap[h->index][len] = 0;
return ACT_RET_CONT;
}
/* Check an "http-request capture" action.
*
* The function returns 1 in success case, otherwise, it returns 0 and err is
* filled.
*/
static int check_http_req_capture(struct act_rule *rule, struct proxy *px, char **err)
{
if (rule->action_ptr != http_action_req_capture_by_id)
return 1;
/* capture slots can only be declared in frontends, so we can't check their
* existence in backends at configuration parsing step
*/
if (px->cap & PR_CAP_FE && rule->arg.capid.idx >= px->nb_req_cap) {
REORG: http: move the code to different files The current proto_http.c file is huge and contains different processing domains making it very difficult to work on an alternative representation. This commit moves some parts to other files : - ACL registration code => http_acl.c This code only creates some ACL mappings and doesn't know anything about HTTP nor about the representation. This code could even have moved to acl.c but it was not worth polluting it again. - HTTP sample conversion => http_conv.c This code doesn't depend on the internal representation but definitely manipulates some HTTP elements, such as dates. It also has access to captures. - HTTP sample fetching => http_fetch.c This code does depend entirely on the internal representation but is totally independent on the analysers. Placing it into a different file will ease the transition to the new representation and the creation of a wrapper if required. An include file was created due to CHECK_HTTP_MESSAGE_FIRST() being used at various places. - HTTP action registration => http_act.c This code doesn't directly interact with the messages nor the transaction but it does so via some exported http functions like http_replace_req_line() or http_set_status() so it will be easier to change only this after the conversion. - a few very generic parts were found and moved to http.{c,h} as relevant. It is worth noting that the functions moved to these new files are not referenced anywhere outside of the files and are only called as registered callbacks, so these files do not even require associated include files.
2018-10-02 10:01:16 -04:00
memprintf(err, "unable to find capture id '%d' referenced by http-request capture rule",
rule->arg.capid.idx);
return 0;
}
return 1;
}
/* Release memory allocate by an http capture action */
static void release_http_capture(struct act_rule *rule)
{
if (rule->action_ptr == http_action_req_capture)
release_sample_expr(rule->arg.cap.expr);
else
release_sample_expr(rule->arg.capid.expr);
}
REORG: http: move the code to different files The current proto_http.c file is huge and contains different processing domains making it very difficult to work on an alternative representation. This commit moves some parts to other files : - ACL registration code => http_acl.c This code only creates some ACL mappings and doesn't know anything about HTTP nor about the representation. This code could even have moved to acl.c but it was not worth polluting it again. - HTTP sample conversion => http_conv.c This code doesn't depend on the internal representation but definitely manipulates some HTTP elements, such as dates. It also has access to captures. - HTTP sample fetching => http_fetch.c This code does depend entirely on the internal representation but is totally independent on the analysers. Placing it into a different file will ease the transition to the new representation and the creation of a wrapper if required. An include file was created due to CHECK_HTTP_MESSAGE_FIRST() being used at various places. - HTTP action registration => http_act.c This code doesn't directly interact with the messages nor the transaction but it does so via some exported http functions like http_replace_req_line() or http_set_status() so it will be easier to change only this after the conversion. - a few very generic parts were found and moved to http.{c,h} as relevant. It is worth noting that the functions moved to these new files are not referenced anywhere outside of the files and are only called as registered callbacks, so these files do not even require associated include files.
2018-10-02 10:01:16 -04:00
/* parse an "http-request capture" action. It takes a single argument which is
* a sample fetch expression. It stores the expression into arg->act.p[0] and
* the allocated hdr_cap struct or the preallocated "id" into arg->act.p[1].
* It returns ACT_RET_PRS_OK on success, ACT_RET_PRS_ERR on error.
*/
static enum act_parse_ret parse_http_req_capture(const char **args, int *orig_arg, struct proxy *px,
struct act_rule *rule, char **err)
{
struct sample_expr *expr;
struct cap_hdr *hdr;
int cur_arg;
int len = 0;
for (cur_arg = *orig_arg; cur_arg < *orig_arg + 3 && *args[cur_arg]; cur_arg++)
if (strcmp(args[cur_arg], "if") == 0 ||
strcmp(args[cur_arg], "unless") == 0)
break;
if (cur_arg < *orig_arg + 3) {
memprintf(err, "expects <expression> [ 'len' <length> | id <idx> ]");
return ACT_RET_PRS_ERR;
}
cur_arg = *orig_arg;
expr = sample_parse_expr((char **)args, &cur_arg, px->conf.args.file, px->conf.args.line, err, &px->conf.args, NULL);
REORG: http: move the code to different files The current proto_http.c file is huge and contains different processing domains making it very difficult to work on an alternative representation. This commit moves some parts to other files : - ACL registration code => http_acl.c This code only creates some ACL mappings and doesn't know anything about HTTP nor about the representation. This code could even have moved to acl.c but it was not worth polluting it again. - HTTP sample conversion => http_conv.c This code doesn't depend on the internal representation but definitely manipulates some HTTP elements, such as dates. It also has access to captures. - HTTP sample fetching => http_fetch.c This code does depend entirely on the internal representation but is totally independent on the analysers. Placing it into a different file will ease the transition to the new representation and the creation of a wrapper if required. An include file was created due to CHECK_HTTP_MESSAGE_FIRST() being used at various places. - HTTP action registration => http_act.c This code doesn't directly interact with the messages nor the transaction but it does so via some exported http functions like http_replace_req_line() or http_set_status() so it will be easier to change only this after the conversion. - a few very generic parts were found and moved to http.{c,h} as relevant. It is worth noting that the functions moved to these new files are not referenced anywhere outside of the files and are only called as registered callbacks, so these files do not even require associated include files.
2018-10-02 10:01:16 -04:00
if (!expr)
return ACT_RET_PRS_ERR;
if (!(expr->fetch->val & SMP_VAL_FE_HRQ_HDR)) {
memprintf(err,
"fetch method '%s' extracts information from '%s', none of which is available here",
args[cur_arg-1], sample_src_names(expr->fetch->use));
release_sample_expr(expr);
REORG: http: move the code to different files The current proto_http.c file is huge and contains different processing domains making it very difficult to work on an alternative representation. This commit moves some parts to other files : - ACL registration code => http_acl.c This code only creates some ACL mappings and doesn't know anything about HTTP nor about the representation. This code could even have moved to acl.c but it was not worth polluting it again. - HTTP sample conversion => http_conv.c This code doesn't depend on the internal representation but definitely manipulates some HTTP elements, such as dates. It also has access to captures. - HTTP sample fetching => http_fetch.c This code does depend entirely on the internal representation but is totally independent on the analysers. Placing it into a different file will ease the transition to the new representation and the creation of a wrapper if required. An include file was created due to CHECK_HTTP_MESSAGE_FIRST() being used at various places. - HTTP action registration => http_act.c This code doesn't directly interact with the messages nor the transaction but it does so via some exported http functions like http_replace_req_line() or http_set_status() so it will be easier to change only this after the conversion. - a few very generic parts were found and moved to http.{c,h} as relevant. It is worth noting that the functions moved to these new files are not referenced anywhere outside of the files and are only called as registered callbacks, so these files do not even require associated include files.
2018-10-02 10:01:16 -04:00
return ACT_RET_PRS_ERR;
}
if (!args[cur_arg] || !*args[cur_arg]) {
memprintf(err, "expects 'len or 'id'");
release_sample_expr(expr);
REORG: http: move the code to different files The current proto_http.c file is huge and contains different processing domains making it very difficult to work on an alternative representation. This commit moves some parts to other files : - ACL registration code => http_acl.c This code only creates some ACL mappings and doesn't know anything about HTTP nor about the representation. This code could even have moved to acl.c but it was not worth polluting it again. - HTTP sample conversion => http_conv.c This code doesn't depend on the internal representation but definitely manipulates some HTTP elements, such as dates. It also has access to captures. - HTTP sample fetching => http_fetch.c This code does depend entirely on the internal representation but is totally independent on the analysers. Placing it into a different file will ease the transition to the new representation and the creation of a wrapper if required. An include file was created due to CHECK_HTTP_MESSAGE_FIRST() being used at various places. - HTTP action registration => http_act.c This code doesn't directly interact with the messages nor the transaction but it does so via some exported http functions like http_replace_req_line() or http_set_status() so it will be easier to change only this after the conversion. - a few very generic parts were found and moved to http.{c,h} as relevant. It is worth noting that the functions moved to these new files are not referenced anywhere outside of the files and are only called as registered callbacks, so these files do not even require associated include files.
2018-10-02 10:01:16 -04:00
return ACT_RET_PRS_ERR;
}
if (strcmp(args[cur_arg], "len") == 0) {
cur_arg++;
if (!(px->cap & PR_CAP_FE)) {
memprintf(err, "proxy '%s' has no frontend capability", px->id);
release_sample_expr(expr);
REORG: http: move the code to different files The current proto_http.c file is huge and contains different processing domains making it very difficult to work on an alternative representation. This commit moves some parts to other files : - ACL registration code => http_acl.c This code only creates some ACL mappings and doesn't know anything about HTTP nor about the representation. This code could even have moved to acl.c but it was not worth polluting it again. - HTTP sample conversion => http_conv.c This code doesn't depend on the internal representation but definitely manipulates some HTTP elements, such as dates. It also has access to captures. - HTTP sample fetching => http_fetch.c This code does depend entirely on the internal representation but is totally independent on the analysers. Placing it into a different file will ease the transition to the new representation and the creation of a wrapper if required. An include file was created due to CHECK_HTTP_MESSAGE_FIRST() being used at various places. - HTTP action registration => http_act.c This code doesn't directly interact with the messages nor the transaction but it does so via some exported http functions like http_replace_req_line() or http_set_status() so it will be easier to change only this after the conversion. - a few very generic parts were found and moved to http.{c,h} as relevant. It is worth noting that the functions moved to these new files are not referenced anywhere outside of the files and are only called as registered callbacks, so these files do not even require associated include files.
2018-10-02 10:01:16 -04:00
return ACT_RET_PRS_ERR;
}
px->conf.args.ctx = ARGC_CAP;
if (!args[cur_arg]) {
memprintf(err, "missing length value");
release_sample_expr(expr);
REORG: http: move the code to different files The current proto_http.c file is huge and contains different processing domains making it very difficult to work on an alternative representation. This commit moves some parts to other files : - ACL registration code => http_acl.c This code only creates some ACL mappings and doesn't know anything about HTTP nor about the representation. This code could even have moved to acl.c but it was not worth polluting it again. - HTTP sample conversion => http_conv.c This code doesn't depend on the internal representation but definitely manipulates some HTTP elements, such as dates. It also has access to captures. - HTTP sample fetching => http_fetch.c This code does depend entirely on the internal representation but is totally independent on the analysers. Placing it into a different file will ease the transition to the new representation and the creation of a wrapper if required. An include file was created due to CHECK_HTTP_MESSAGE_FIRST() being used at various places. - HTTP action registration => http_act.c This code doesn't directly interact with the messages nor the transaction but it does so via some exported http functions like http_replace_req_line() or http_set_status() so it will be easier to change only this after the conversion. - a few very generic parts were found and moved to http.{c,h} as relevant. It is worth noting that the functions moved to these new files are not referenced anywhere outside of the files and are only called as registered callbacks, so these files do not even require associated include files.
2018-10-02 10:01:16 -04:00
return ACT_RET_PRS_ERR;
}
/* we copy the table name for now, it will be resolved later */
len = atoi(args[cur_arg]);
if (len <= 0) {
memprintf(err, "length must be > 0");
release_sample_expr(expr);
REORG: http: move the code to different files The current proto_http.c file is huge and contains different processing domains making it very difficult to work on an alternative representation. This commit moves some parts to other files : - ACL registration code => http_acl.c This code only creates some ACL mappings and doesn't know anything about HTTP nor about the representation. This code could even have moved to acl.c but it was not worth polluting it again. - HTTP sample conversion => http_conv.c This code doesn't depend on the internal representation but definitely manipulates some HTTP elements, such as dates. It also has access to captures. - HTTP sample fetching => http_fetch.c This code does depend entirely on the internal representation but is totally independent on the analysers. Placing it into a different file will ease the transition to the new representation and the creation of a wrapper if required. An include file was created due to CHECK_HTTP_MESSAGE_FIRST() being used at various places. - HTTP action registration => http_act.c This code doesn't directly interact with the messages nor the transaction but it does so via some exported http functions like http_replace_req_line() or http_set_status() so it will be easier to change only this after the conversion. - a few very generic parts were found and moved to http.{c,h} as relevant. It is worth noting that the functions moved to these new files are not referenced anywhere outside of the files and are only called as registered callbacks, so these files do not even require associated include files.
2018-10-02 10:01:16 -04:00
return ACT_RET_PRS_ERR;
}
cur_arg++;
hdr = calloc(1, sizeof(*hdr));
if (!hdr) {
memprintf(err, "out of memory");
release_sample_expr(expr);
return ACT_RET_PRS_ERR;
}
REORG: http: move the code to different files The current proto_http.c file is huge and contains different processing domains making it very difficult to work on an alternative representation. This commit moves some parts to other files : - ACL registration code => http_acl.c This code only creates some ACL mappings and doesn't know anything about HTTP nor about the representation. This code could even have moved to acl.c but it was not worth polluting it again. - HTTP sample conversion => http_conv.c This code doesn't depend on the internal representation but definitely manipulates some HTTP elements, such as dates. It also has access to captures. - HTTP sample fetching => http_fetch.c This code does depend entirely on the internal representation but is totally independent on the analysers. Placing it into a different file will ease the transition to the new representation and the creation of a wrapper if required. An include file was created due to CHECK_HTTP_MESSAGE_FIRST() being used at various places. - HTTP action registration => http_act.c This code doesn't directly interact with the messages nor the transaction but it does so via some exported http functions like http_replace_req_line() or http_set_status() so it will be easier to change only this after the conversion. - a few very generic parts were found and moved to http.{c,h} as relevant. It is worth noting that the functions moved to these new files are not referenced anywhere outside of the files and are only called as registered callbacks, so these files do not even require associated include files.
2018-10-02 10:01:16 -04:00
hdr->next = px->req_cap;
hdr->name = NULL; /* not a header capture */
hdr->namelen = 0;
hdr->len = len;
hdr->pool = create_pool("caphdr", hdr->len + 1, MEM_F_SHARED);
hdr->index = px->nb_req_cap++;
px->req_cap = hdr;
px->to_log |= LW_REQHDR;
rule->action = ACT_CUSTOM;
rule->action_ptr = http_action_req_capture;
rule->release_ptr = release_http_capture;
REORG: http: move the code to different files The current proto_http.c file is huge and contains different processing domains making it very difficult to work on an alternative representation. This commit moves some parts to other files : - ACL registration code => http_acl.c This code only creates some ACL mappings and doesn't know anything about HTTP nor about the representation. This code could even have moved to acl.c but it was not worth polluting it again. - HTTP sample conversion => http_conv.c This code doesn't depend on the internal representation but definitely manipulates some HTTP elements, such as dates. It also has access to captures. - HTTP sample fetching => http_fetch.c This code does depend entirely on the internal representation but is totally independent on the analysers. Placing it into a different file will ease the transition to the new representation and the creation of a wrapper if required. An include file was created due to CHECK_HTTP_MESSAGE_FIRST() being used at various places. - HTTP action registration => http_act.c This code doesn't directly interact with the messages nor the transaction but it does so via some exported http functions like http_replace_req_line() or http_set_status() so it will be easier to change only this after the conversion. - a few very generic parts were found and moved to http.{c,h} as relevant. It is worth noting that the functions moved to these new files are not referenced anywhere outside of the files and are only called as registered callbacks, so these files do not even require associated include files.
2018-10-02 10:01:16 -04:00
rule->arg.cap.expr = expr;
rule->arg.cap.hdr = hdr;
}
else if (strcmp(args[cur_arg], "id") == 0) {
int id;
char *error;
cur_arg++;
if (!args[cur_arg]) {
memprintf(err, "missing id value");
release_sample_expr(expr);
REORG: http: move the code to different files The current proto_http.c file is huge and contains different processing domains making it very difficult to work on an alternative representation. This commit moves some parts to other files : - ACL registration code => http_acl.c This code only creates some ACL mappings and doesn't know anything about HTTP nor about the representation. This code could even have moved to acl.c but it was not worth polluting it again. - HTTP sample conversion => http_conv.c This code doesn't depend on the internal representation but definitely manipulates some HTTP elements, such as dates. It also has access to captures. - HTTP sample fetching => http_fetch.c This code does depend entirely on the internal representation but is totally independent on the analysers. Placing it into a different file will ease the transition to the new representation and the creation of a wrapper if required. An include file was created due to CHECK_HTTP_MESSAGE_FIRST() being used at various places. - HTTP action registration => http_act.c This code doesn't directly interact with the messages nor the transaction but it does so via some exported http functions like http_replace_req_line() or http_set_status() so it will be easier to change only this after the conversion. - a few very generic parts were found and moved to http.{c,h} as relevant. It is worth noting that the functions moved to these new files are not referenced anywhere outside of the files and are only called as registered callbacks, so these files do not even require associated include files.
2018-10-02 10:01:16 -04:00
return ACT_RET_PRS_ERR;
}
id = strtol(args[cur_arg], &error, 10);
if (*error != '\0') {
memprintf(err, "cannot parse id '%s'", args[cur_arg]);
release_sample_expr(expr);
REORG: http: move the code to different files The current proto_http.c file is huge and contains different processing domains making it very difficult to work on an alternative representation. This commit moves some parts to other files : - ACL registration code => http_acl.c This code only creates some ACL mappings and doesn't know anything about HTTP nor about the representation. This code could even have moved to acl.c but it was not worth polluting it again. - HTTP sample conversion => http_conv.c This code doesn't depend on the internal representation but definitely manipulates some HTTP elements, such as dates. It also has access to captures. - HTTP sample fetching => http_fetch.c This code does depend entirely on the internal representation but is totally independent on the analysers. Placing it into a different file will ease the transition to the new representation and the creation of a wrapper if required. An include file was created due to CHECK_HTTP_MESSAGE_FIRST() being used at various places. - HTTP action registration => http_act.c This code doesn't directly interact with the messages nor the transaction but it does so via some exported http functions like http_replace_req_line() or http_set_status() so it will be easier to change only this after the conversion. - a few very generic parts were found and moved to http.{c,h} as relevant. It is worth noting that the functions moved to these new files are not referenced anywhere outside of the files and are only called as registered callbacks, so these files do not even require associated include files.
2018-10-02 10:01:16 -04:00
return ACT_RET_PRS_ERR;
}
cur_arg++;
px->conf.args.ctx = ARGC_CAP;
rule->action = ACT_CUSTOM;
rule->action_ptr = http_action_req_capture_by_id;
rule->check_ptr = check_http_req_capture;
rule->release_ptr = release_http_capture;
REORG: http: move the code to different files The current proto_http.c file is huge and contains different processing domains making it very difficult to work on an alternative representation. This commit moves some parts to other files : - ACL registration code => http_acl.c This code only creates some ACL mappings and doesn't know anything about HTTP nor about the representation. This code could even have moved to acl.c but it was not worth polluting it again. - HTTP sample conversion => http_conv.c This code doesn't depend on the internal representation but definitely manipulates some HTTP elements, such as dates. It also has access to captures. - HTTP sample fetching => http_fetch.c This code does depend entirely on the internal representation but is totally independent on the analysers. Placing it into a different file will ease the transition to the new representation and the creation of a wrapper if required. An include file was created due to CHECK_HTTP_MESSAGE_FIRST() being used at various places. - HTTP action registration => http_act.c This code doesn't directly interact with the messages nor the transaction but it does so via some exported http functions like http_replace_req_line() or http_set_status() so it will be easier to change only this after the conversion. - a few very generic parts were found and moved to http.{c,h} as relevant. It is worth noting that the functions moved to these new files are not referenced anywhere outside of the files and are only called as registered callbacks, so these files do not even require associated include files.
2018-10-02 10:01:16 -04:00
rule->arg.capid.expr = expr;
rule->arg.capid.idx = id;
}
else {
memprintf(err, "expects 'len' or 'id', found '%s'", args[cur_arg]);
release_sample_expr(expr);
REORG: http: move the code to different files The current proto_http.c file is huge and contains different processing domains making it very difficult to work on an alternative representation. This commit moves some parts to other files : - ACL registration code => http_acl.c This code only creates some ACL mappings and doesn't know anything about HTTP nor about the representation. This code could even have moved to acl.c but it was not worth polluting it again. - HTTP sample conversion => http_conv.c This code doesn't depend on the internal representation but definitely manipulates some HTTP elements, such as dates. It also has access to captures. - HTTP sample fetching => http_fetch.c This code does depend entirely on the internal representation but is totally independent on the analysers. Placing it into a different file will ease the transition to the new representation and the creation of a wrapper if required. An include file was created due to CHECK_HTTP_MESSAGE_FIRST() being used at various places. - HTTP action registration => http_act.c This code doesn't directly interact with the messages nor the transaction but it does so via some exported http functions like http_replace_req_line() or http_set_status() so it will be easier to change only this after the conversion. - a few very generic parts were found and moved to http.{c,h} as relevant. It is worth noting that the functions moved to these new files are not referenced anywhere outside of the files and are only called as registered callbacks, so these files do not even require associated include files.
2018-10-02 10:01:16 -04:00
return ACT_RET_PRS_ERR;
}
*orig_arg = cur_arg;
return ACT_RET_PRS_OK;
}
/* This function executes the "capture" action and store the result in a
* capture slot if exists. It executes a fetch expression, turns the result
* into a string and puts it in a capture slot. It always returns 1. If an
* error occurs the action is cancelled, but the rule processing continues.
*/
static enum act_return http_action_res_capture_by_id(struct act_rule *rule, struct proxy *px,
struct session *sess, struct stream *s, int flags)
{
struct sample *key;
struct cap_hdr *h;
char **cap = s->res_cap;
struct proxy *fe = strm_fe(s);
int len;
int i;
/* Look for the original configuration. */
for (h = fe->rsp_cap, i = fe->nb_rsp_cap - 1;
h != NULL && i != rule->arg.capid.idx ;
i--, h = h->next);
if (!h)
return ACT_RET_CONT;
key = sample_fetch_as_type(s->be, sess, s, SMP_OPT_DIR_RES|SMP_OPT_FINAL, rule->arg.capid.expr, SMP_T_STR);
if (!key)
return ACT_RET_CONT;
if (cap[h->index] == NULL)
cap[h->index] = pool_alloc(h->pool);
if (cap[h->index] == NULL) /* no more capture memory */
return ACT_RET_CONT;
len = key->data.u.str.data;
if (len > h->len)
len = h->len;
memcpy(cap[h->index], key->data.u.str.area, len);
cap[h->index][len] = 0;
return ACT_RET_CONT;
}
/* Check an "http-response capture" action.
*
* The function returns 1 in success case, otherwise, it returns 0 and err is
* filled.
*/
static int check_http_res_capture(struct act_rule *rule, struct proxy *px, char **err)
{
if (rule->action_ptr != http_action_res_capture_by_id)
return 1;
/* capture slots can only be declared in frontends, so we can't check their
* existence in backends at configuration parsing step
*/
if (px->cap & PR_CAP_FE && rule->arg.capid.idx >= px->nb_rsp_cap) {
REORG: http: move the code to different files The current proto_http.c file is huge and contains different processing domains making it very difficult to work on an alternative representation. This commit moves some parts to other files : - ACL registration code => http_acl.c This code only creates some ACL mappings and doesn't know anything about HTTP nor about the representation. This code could even have moved to acl.c but it was not worth polluting it again. - HTTP sample conversion => http_conv.c This code doesn't depend on the internal representation but definitely manipulates some HTTP elements, such as dates. It also has access to captures. - HTTP sample fetching => http_fetch.c This code does depend entirely on the internal representation but is totally independent on the analysers. Placing it into a different file will ease the transition to the new representation and the creation of a wrapper if required. An include file was created due to CHECK_HTTP_MESSAGE_FIRST() being used at various places. - HTTP action registration => http_act.c This code doesn't directly interact with the messages nor the transaction but it does so via some exported http functions like http_replace_req_line() or http_set_status() so it will be easier to change only this after the conversion. - a few very generic parts were found and moved to http.{c,h} as relevant. It is worth noting that the functions moved to these new files are not referenced anywhere outside of the files and are only called as registered callbacks, so these files do not even require associated include files.
2018-10-02 10:01:16 -04:00
memprintf(err, "unable to find capture id '%d' referenced by http-response capture rule",
rule->arg.capid.idx);
return 0;
}
return 1;
}
/* parse an "http-response capture" action. It takes a single argument which is
* a sample fetch expression. It stores the expression into arg->act.p[0] and
* the allocated hdr_cap struct of the preallocated id into arg->act.p[1].
REORG: http: move the code to different files The current proto_http.c file is huge and contains different processing domains making it very difficult to work on an alternative representation. This commit moves some parts to other files : - ACL registration code => http_acl.c This code only creates some ACL mappings and doesn't know anything about HTTP nor about the representation. This code could even have moved to acl.c but it was not worth polluting it again. - HTTP sample conversion => http_conv.c This code doesn't depend on the internal representation but definitely manipulates some HTTP elements, such as dates. It also has access to captures. - HTTP sample fetching => http_fetch.c This code does depend entirely on the internal representation but is totally independent on the analysers. Placing it into a different file will ease the transition to the new representation and the creation of a wrapper if required. An include file was created due to CHECK_HTTP_MESSAGE_FIRST() being used at various places. - HTTP action registration => http_act.c This code doesn't directly interact with the messages nor the transaction but it does so via some exported http functions like http_replace_req_line() or http_set_status() so it will be easier to change only this after the conversion. - a few very generic parts were found and moved to http.{c,h} as relevant. It is worth noting that the functions moved to these new files are not referenced anywhere outside of the files and are only called as registered callbacks, so these files do not even require associated include files.
2018-10-02 10:01:16 -04:00
* It returns ACT_RET_PRS_OK on success, ACT_RET_PRS_ERR on error.
*/
static enum act_parse_ret parse_http_res_capture(const char **args, int *orig_arg, struct proxy *px,
struct act_rule *rule, char **err)
{
struct sample_expr *expr;
int cur_arg;
int id;
char *error;
for (cur_arg = *orig_arg; cur_arg < *orig_arg + 3 && *args[cur_arg]; cur_arg++)
if (strcmp(args[cur_arg], "if") == 0 ||
strcmp(args[cur_arg], "unless") == 0)
break;
if (cur_arg < *orig_arg + 3) {
memprintf(err, "expects <expression> id <idx>");
return ACT_RET_PRS_ERR;
}
cur_arg = *orig_arg;
expr = sample_parse_expr((char **)args, &cur_arg, px->conf.args.file, px->conf.args.line, err, &px->conf.args, NULL);
REORG: http: move the code to different files The current proto_http.c file is huge and contains different processing domains making it very difficult to work on an alternative representation. This commit moves some parts to other files : - ACL registration code => http_acl.c This code only creates some ACL mappings and doesn't know anything about HTTP nor about the representation. This code could even have moved to acl.c but it was not worth polluting it again. - HTTP sample conversion => http_conv.c This code doesn't depend on the internal representation but definitely manipulates some HTTP elements, such as dates. It also has access to captures. - HTTP sample fetching => http_fetch.c This code does depend entirely on the internal representation but is totally independent on the analysers. Placing it into a different file will ease the transition to the new representation and the creation of a wrapper if required. An include file was created due to CHECK_HTTP_MESSAGE_FIRST() being used at various places. - HTTP action registration => http_act.c This code doesn't directly interact with the messages nor the transaction but it does so via some exported http functions like http_replace_req_line() or http_set_status() so it will be easier to change only this after the conversion. - a few very generic parts were found and moved to http.{c,h} as relevant. It is worth noting that the functions moved to these new files are not referenced anywhere outside of the files and are only called as registered callbacks, so these files do not even require associated include files.
2018-10-02 10:01:16 -04:00
if (!expr)
return ACT_RET_PRS_ERR;
if (!(expr->fetch->val & SMP_VAL_FE_HRS_HDR)) {
memprintf(err,
"fetch method '%s' extracts information from '%s', none of which is available here",
args[cur_arg-1], sample_src_names(expr->fetch->use));
release_sample_expr(expr);
REORG: http: move the code to different files The current proto_http.c file is huge and contains different processing domains making it very difficult to work on an alternative representation. This commit moves some parts to other files : - ACL registration code => http_acl.c This code only creates some ACL mappings and doesn't know anything about HTTP nor about the representation. This code could even have moved to acl.c but it was not worth polluting it again. - HTTP sample conversion => http_conv.c This code doesn't depend on the internal representation but definitely manipulates some HTTP elements, such as dates. It also has access to captures. - HTTP sample fetching => http_fetch.c This code does depend entirely on the internal representation but is totally independent on the analysers. Placing it into a different file will ease the transition to the new representation and the creation of a wrapper if required. An include file was created due to CHECK_HTTP_MESSAGE_FIRST() being used at various places. - HTTP action registration => http_act.c This code doesn't directly interact with the messages nor the transaction but it does so via some exported http functions like http_replace_req_line() or http_set_status() so it will be easier to change only this after the conversion. - a few very generic parts were found and moved to http.{c,h} as relevant. It is worth noting that the functions moved to these new files are not referenced anywhere outside of the files and are only called as registered callbacks, so these files do not even require associated include files.
2018-10-02 10:01:16 -04:00
return ACT_RET_PRS_ERR;
}
if (!args[cur_arg] || !*args[cur_arg]) {
memprintf(err, "expects 'id'");
release_sample_expr(expr);
REORG: http: move the code to different files The current proto_http.c file is huge and contains different processing domains making it very difficult to work on an alternative representation. This commit moves some parts to other files : - ACL registration code => http_acl.c This code only creates some ACL mappings and doesn't know anything about HTTP nor about the representation. This code could even have moved to acl.c but it was not worth polluting it again. - HTTP sample conversion => http_conv.c This code doesn't depend on the internal representation but definitely manipulates some HTTP elements, such as dates. It also has access to captures. - HTTP sample fetching => http_fetch.c This code does depend entirely on the internal representation but is totally independent on the analysers. Placing it into a different file will ease the transition to the new representation and the creation of a wrapper if required. An include file was created due to CHECK_HTTP_MESSAGE_FIRST() being used at various places. - HTTP action registration => http_act.c This code doesn't directly interact with the messages nor the transaction but it does so via some exported http functions like http_replace_req_line() or http_set_status() so it will be easier to change only this after the conversion. - a few very generic parts were found and moved to http.{c,h} as relevant. It is worth noting that the functions moved to these new files are not referenced anywhere outside of the files and are only called as registered callbacks, so these files do not even require associated include files.
2018-10-02 10:01:16 -04:00
return ACT_RET_PRS_ERR;
}
if (strcmp(args[cur_arg], "id") != 0) {
memprintf(err, "expects 'id', found '%s'", args[cur_arg]);
release_sample_expr(expr);
REORG: http: move the code to different files The current proto_http.c file is huge and contains different processing domains making it very difficult to work on an alternative representation. This commit moves some parts to other files : - ACL registration code => http_acl.c This code only creates some ACL mappings and doesn't know anything about HTTP nor about the representation. This code could even have moved to acl.c but it was not worth polluting it again. - HTTP sample conversion => http_conv.c This code doesn't depend on the internal representation but definitely manipulates some HTTP elements, such as dates. It also has access to captures. - HTTP sample fetching => http_fetch.c This code does depend entirely on the internal representation but is totally independent on the analysers. Placing it into a different file will ease the transition to the new representation and the creation of a wrapper if required. An include file was created due to CHECK_HTTP_MESSAGE_FIRST() being used at various places. - HTTP action registration => http_act.c This code doesn't directly interact with the messages nor the transaction but it does so via some exported http functions like http_replace_req_line() or http_set_status() so it will be easier to change only this after the conversion. - a few very generic parts were found and moved to http.{c,h} as relevant. It is worth noting that the functions moved to these new files are not referenced anywhere outside of the files and are only called as registered callbacks, so these files do not even require associated include files.
2018-10-02 10:01:16 -04:00
return ACT_RET_PRS_ERR;
}
cur_arg++;
if (!args[cur_arg]) {
memprintf(err, "missing id value");
release_sample_expr(expr);
REORG: http: move the code to different files The current proto_http.c file is huge and contains different processing domains making it very difficult to work on an alternative representation. This commit moves some parts to other files : - ACL registration code => http_acl.c This code only creates some ACL mappings and doesn't know anything about HTTP nor about the representation. This code could even have moved to acl.c but it was not worth polluting it again. - HTTP sample conversion => http_conv.c This code doesn't depend on the internal representation but definitely manipulates some HTTP elements, such as dates. It also has access to captures. - HTTP sample fetching => http_fetch.c This code does depend entirely on the internal representation but is totally independent on the analysers. Placing it into a different file will ease the transition to the new representation and the creation of a wrapper if required. An include file was created due to CHECK_HTTP_MESSAGE_FIRST() being used at various places. - HTTP action registration => http_act.c This code doesn't directly interact with the messages nor the transaction but it does so via some exported http functions like http_replace_req_line() or http_set_status() so it will be easier to change only this after the conversion. - a few very generic parts were found and moved to http.{c,h} as relevant. It is worth noting that the functions moved to these new files are not referenced anywhere outside of the files and are only called as registered callbacks, so these files do not even require associated include files.
2018-10-02 10:01:16 -04:00
return ACT_RET_PRS_ERR;
}
id = strtol(args[cur_arg], &error, 10);
if (*error != '\0') {
memprintf(err, "cannot parse id '%s'", args[cur_arg]);
release_sample_expr(expr);
REORG: http: move the code to different files The current proto_http.c file is huge and contains different processing domains making it very difficult to work on an alternative representation. This commit moves some parts to other files : - ACL registration code => http_acl.c This code only creates some ACL mappings and doesn't know anything about HTTP nor about the representation. This code could even have moved to acl.c but it was not worth polluting it again. - HTTP sample conversion => http_conv.c This code doesn't depend on the internal representation but definitely manipulates some HTTP elements, such as dates. It also has access to captures. - HTTP sample fetching => http_fetch.c This code does depend entirely on the internal representation but is totally independent on the analysers. Placing it into a different file will ease the transition to the new representation and the creation of a wrapper if required. An include file was created due to CHECK_HTTP_MESSAGE_FIRST() being used at various places. - HTTP action registration => http_act.c This code doesn't directly interact with the messages nor the transaction but it does so via some exported http functions like http_replace_req_line() or http_set_status() so it will be easier to change only this after the conversion. - a few very generic parts were found and moved to http.{c,h} as relevant. It is worth noting that the functions moved to these new files are not referenced anywhere outside of the files and are only called as registered callbacks, so these files do not even require associated include files.
2018-10-02 10:01:16 -04:00
return ACT_RET_PRS_ERR;
}
cur_arg++;
px->conf.args.ctx = ARGC_CAP;
rule->action = ACT_CUSTOM;
rule->action_ptr = http_action_res_capture_by_id;
rule->check_ptr = check_http_res_capture;
rule->release_ptr = release_http_capture;
REORG: http: move the code to different files The current proto_http.c file is huge and contains different processing domains making it very difficult to work on an alternative representation. This commit moves some parts to other files : - ACL registration code => http_acl.c This code only creates some ACL mappings and doesn't know anything about HTTP nor about the representation. This code could even have moved to acl.c but it was not worth polluting it again. - HTTP sample conversion => http_conv.c This code doesn't depend on the internal representation but definitely manipulates some HTTP elements, such as dates. It also has access to captures. - HTTP sample fetching => http_fetch.c This code does depend entirely on the internal representation but is totally independent on the analysers. Placing it into a different file will ease the transition to the new representation and the creation of a wrapper if required. An include file was created due to CHECK_HTTP_MESSAGE_FIRST() being used at various places. - HTTP action registration => http_act.c This code doesn't directly interact with the messages nor the transaction but it does so via some exported http functions like http_replace_req_line() or http_set_status() so it will be easier to change only this after the conversion. - a few very generic parts were found and moved to http.{c,h} as relevant. It is worth noting that the functions moved to these new files are not referenced anywhere outside of the files and are only called as registered callbacks, so these files do not even require associated include files.
2018-10-02 10:01:16 -04:00
rule->arg.capid.expr = expr;
rule->arg.capid.idx = id;
*orig_arg = cur_arg;
return ACT_RET_PRS_OK;
}
/* Parse a "allow" action for a request or a response rule. It takes no argument. It
* returns ACT_RET_PRS_OK on success, ACT_RET_PRS_ERR on error.
*/
static enum act_parse_ret parse_http_allow(const char **args, int *orig_arg, struct proxy *px,
struct act_rule *rule, char **err)
{
rule->action = ACT_ACTION_ALLOW;
rule->flags |= ACT_FLAG_FINAL;
return ACT_RET_PRS_OK;
}
/* Parse "deny" or "tarpit" actions for a request rule or "deny" action for a
* response rule. It returns ACT_RET_PRS_OK on success, ACT_RET_PRS_ERR on
* error. It relies on http_parse_http_reply() to set
* <.arg.http_reply>.
*/
static enum act_parse_ret parse_http_deny(const char **args, int *orig_arg, struct proxy *px,
struct act_rule *rule, char **err)
{
int default_status;
int cur_arg, arg = 0;
cur_arg = *orig_arg;
if (rule->from == ACT_F_HTTP_REQ) {
CLEANUP: Compare the return value of `XXXcmp()` functions with zero According to coding-style.txt it is recommended to use: `strcmp(a, b) == 0` instead of `!strcmp(a, b)` So let's do this. The change was performed by running the following (very long) coccinelle patch on src/: @@ statement S; expression E; expression F; @@ if ( ( dns_hostname_cmp | eb_memcmp | memcmp | strcasecmp | strcmp | strncasecmp | strncmp ) - (E, F) + (E, F) != 0 ) ( S | { ... } ) @@ statement S; expression E; expression F; @@ if ( - ! ( dns_hostname_cmp | eb_memcmp | memcmp | strcasecmp | strcmp | strncasecmp | strncmp ) - (E, F) + (E, F) == 0 ) ( S | { ... } ) @@ expression E; expression F; expression G; @@ ( G && ( dns_hostname_cmp | eb_memcmp | memcmp | strcasecmp | strcmp | strncasecmp | strncmp ) - (E, F) + (E, F) != 0 ) @@ expression E; expression F; expression G; @@ ( G || ( dns_hostname_cmp | eb_memcmp | memcmp | strcasecmp | strcmp | strncasecmp | strncmp ) - (E, F) + (E, F) != 0 ) @@ expression E; expression F; expression G; @@ ( ( dns_hostname_cmp | eb_memcmp | memcmp | strcasecmp | strcmp | strncasecmp | strncmp ) - (E, F) + (E, F) != 0 && G ) @@ expression E; expression F; expression G; @@ ( ( dns_hostname_cmp | eb_memcmp | memcmp | strcasecmp | strcmp | strncasecmp | strncmp ) - (E, F) + (E, F) != 0 || G ) @@ expression E; expression F; expression G; @@ ( G && - ! ( dns_hostname_cmp | eb_memcmp | memcmp | strcasecmp | strcmp | strncasecmp | strncmp ) - (E, F) + (E, F) == 0 ) @@ expression E; expression F; expression G; @@ ( G || - ! ( dns_hostname_cmp | eb_memcmp | memcmp | strcasecmp | strcmp | strncasecmp | strncmp ) - (E, F) + (E, F) == 0 ) @@ expression E; expression F; expression G; @@ ( - ! ( dns_hostname_cmp | eb_memcmp | memcmp | strcasecmp | strcmp | strncasecmp | strncmp ) - (E, F) + (E, F) == 0 && G ) @@ expression E; expression F; expression G; @@ ( - ! ( dns_hostname_cmp | eb_memcmp | memcmp | strcasecmp | strcmp | strncasecmp | strncmp ) - (E, F) + (E, F) == 0 || G ) @@ expression E; expression F; expression G; @@ ( - ! ( dns_hostname_cmp | eb_memcmp | memcmp | strcasecmp | strcmp | strncasecmp | strncmp ) - (E, F) + (E, F) == 0 )
2021-01-02 16:31:53 -05:00
if (strcmp(args[cur_arg - 1], "tarpit") == 0) {
rule->action = ACT_HTTP_REQ_TARPIT;
default_status = 500;
}
else {
rule->action = ACT_ACTION_DENY;
default_status = 403;
}
}
else {
rule->action = ACT_ACTION_DENY;
default_status = 502;
}
/* If no args or only a deny_status specified, fallback on the legacy
* mode and use default error files despite the fact that
* default-errorfiles is not used. Otherwise, parse an http reply.
*/
/* Prepare parsing of log-format strings */
px->conf.args.ctx = ((rule->from == ACT_F_HTTP_REQ) ? ARGC_HRQ : ARGC_HRS);
if (!*(args[cur_arg]) || strcmp(args[cur_arg], "if") == 0 || strcmp(args[cur_arg], "unless") == 0) {
rule->arg.http_reply = http_parse_http_reply((const char *[]){"default-errorfiles", ""}, &arg, px, default_status, err);
goto end;
}
if (strcmp(args[cur_arg], "deny_status") == 0) {
if (!*(args[cur_arg+2]) || strcmp(args[cur_arg+2], "if") == 0 || strcmp(args[cur_arg+2], "unless") == 0) {
rule->arg.http_reply = http_parse_http_reply((const char *[]){"status", args[cur_arg+1], "default-errorfiles", ""},
&arg, px, default_status, err);
*orig_arg += 2;
goto end;
}
args[cur_arg] += 5; /* skip "deny_" for the parsing */
}
rule->arg.http_reply = http_parse_http_reply(args, orig_arg, px, default_status, err);
end:
if (!rule->arg.http_reply)
return ACT_RET_PRS_ERR;
rule->flags |= ACT_FLAG_FINAL;
rule->check_ptr = check_act_http_reply;
rule->release_ptr = release_act_http_reply;
return ACT_RET_PRS_OK;
}
/* This function executes a auth action. It builds an 401/407 HTX message using
* the corresponding proxy's error message. On success, it returns
* ACT_RET_ABRT. If an error occurs ACT_RET_ERR is returned.
*/
static enum act_return http_action_auth(struct act_rule *rule, struct proxy *px,
struct session *sess, struct stream *s, int flags)
{
struct channel *req = &s->req;
struct channel *res = &s->res;
struct htx *htx = htx_from_buf(&res->buf);
struct http_reply *reply;
const char *auth_realm;
struct http_hdr_ctx ctx;
struct ist hdr;
/* Auth might be performed on regular http-req rules as well as on stats */
auth_realm = rule->arg.http.str.ptr;
if (!auth_realm) {
if (px->uri_auth && s->current_rule_list == &px->uri_auth->http_req_rules)
auth_realm = STATS_DEFAULT_REALM;
else
auth_realm = px->id;
}
if (!(s->txn->flags & TX_USE_PX_CONN)) {
s->txn->status = 401;
hdr = ist("WWW-Authenticate");
}
else {
s->txn->status = 407;
hdr = ist("Proxy-Authenticate");
}
reply = http_error_message(s);
channel_htx_truncate(res, htx);
if (chunk_printf(&trash, "Basic realm=\"%s\"", auth_realm) == -1)
goto fail;
/* Write the generic 40x message */
if (http_reply_to_htx(s, htx, reply) == -1)
goto fail;
/* Remove all existing occurrences of the XXX-Authenticate header */
ctx.blk = NULL;
while (http_find_header(htx, hdr, &ctx, 1))
http_remove_header(htx, &ctx);
/* Now a the right XXX-Authenticate header */
if (!http_add_header(htx, hdr, ist2(b_orig(&trash), b_data(&trash))))
goto fail;
/* Finally forward the reply */
htx_to_buf(htx, &res->buf);
if (!http_forward_proxy_resp(s, 1))
goto fail;
/* Note: Only eval on the request */
MEDIUM: clock: replace timeval "now" with integer "now_ns" This puts an end to the occasional confusion between the "now" date that is internal, monotonic and not synchronized with the system's date, and "date" which is the system's date and not necessarily monotonic. Variable "now" was removed and replaced with a 64-bit integer "now_ns" which is a counter of nanoseconds. It wraps every 585 years, so if all goes well (i.e. if humanity does not need haproxy anymore in 500 years), it will just never wrap. This implies that now_ns is never nul and that the zero value can reliably be used as "not set yet" for a timestamp if needed. This will also simplify date checks where it becomes possible again to do "date1<date2". All occurrences of "tv_to_ns(&now)" were simply replaced by "now_ns". Due to the intricacies between now, global_now and now_offset, all 3 had to be turned to nanoseconds at once. It's not a problem since all of them were solely used in 3 functions in clock.c, but they make the patch look bigger than it really is. The clock_update_local_date() and clock_update_global_date() functions are now much simpler as there's no need anymore to perform conversions nor to round the timeval up or down. The wrapping continues to happen by presetting the internal offset in the short future so that the 32-bit now_ms continues to wrap 20 seconds after boot. The start_time used to calculate uptime can still be turned to nanoseconds now. One interrogation concerns global_now_ms which is used only for the freq counters. It's unclear whether there's more value in using two variables that need to be synchronized sequentially like today or to just use global_now_ns divided by 1 million. Both approaches will work equally well on modern systems, the difference might come from smaller ones. Better not change anyhting for now. One benefit of the new approach is that we now have an internal date with a resolution of the nanosecond and the precision of the microsecond, which can be useful to extend some measurements given that timestamps also have this resolution.
2023-04-28 03:16:15 -04:00
s->logs.request_ts = now_ns;
req->analysers &= AN_REQ_FLT_END;
if (s->sess->fe == s->be) /* report it if the request was intercepted by the frontend */
_HA_ATOMIC_INC(&s->sess->fe->fe_counters.intercepted_req);
if (!(s->flags & SF_ERR_MASK))
s->flags |= SF_ERR_LOCAL;
if (!(s->flags & SF_FINST_MASK))
s->flags |= SF_FINST_R;
stream_inc_http_err_ctr(s);
return ACT_RET_ABRT;
fail:
/* If an error occurred, remove the incomplete HTTP response from the
* buffer */
channel_htx_truncate(res, htx);
return ACT_RET_ERR;
}
/* Parse a "auth" action. It may take 2 optional arguments to define a "realm"
* parameter. It returns ACT_RET_PRS_OK on success, ACT_RET_PRS_ERR on error.
*/
static enum act_parse_ret parse_http_auth(const char **args, int *orig_arg, struct proxy *px,
struct act_rule *rule, char **err)
{
int cur_arg;
rule->action = ACT_CUSTOM;
rule->flags |= ACT_FLAG_FINAL;
rule->action_ptr = http_action_auth;
rule->release_ptr = release_http_action;
MEDIUM: tree-wide: add logformat expressions wrapper log format expressions are broadly used within the code: once they are parsed from input string, they are converted to a linked list of logformat nodes. We're starting to face some limitations because we're simply storing the converted expression as a generic logformat_node list. The first issue we're facing is that storing logformat expressions that way doesn't allow us to add metadata alongside the list, which is part of the prerequites for implementing log-profiles. Another issue with storing logformat expressions as generic lists of logformat_node elements is that it's starting to become really hard to tell when we rely on logformat expressions or not in the code given that there isn't always a comment near the list declaration or manipulation to indicate that it's relying on logformat expressions under the hood, so this adds some complexity for code maintenance. This patch looks quite impressive due to changes in a lot of header and source files (since logformat expressions are broadly used), but it does a simple thing: it defines the lf_expr structure which itself holds a generic list of logformat nodes, and then declares some helpers to manipulate lf_expr elements and fixes the code so that we now exclusively manipulate logformat_node lists as lf_expr elements outside of log.c. For now, lf_expr struct only contains the list of logformat nodes (no additional metadata), but now that we have dedicated type and helpers, doing so in the future won't be problematic at all and won't require extensive code changes.
2024-02-23 09:57:21 -05:00
lf_expr_init(&rule->arg.http.fmt);
cur_arg = *orig_arg;
CLEANUP: Compare the return value of `XXXcmp()` functions with zero According to coding-style.txt it is recommended to use: `strcmp(a, b) == 0` instead of `!strcmp(a, b)` So let's do this. The change was performed by running the following (very long) coccinelle patch on src/: @@ statement S; expression E; expression F; @@ if ( ( dns_hostname_cmp | eb_memcmp | memcmp | strcasecmp | strcmp | strncasecmp | strncmp ) - (E, F) + (E, F) != 0 ) ( S | { ... } ) @@ statement S; expression E; expression F; @@ if ( - ! ( dns_hostname_cmp | eb_memcmp | memcmp | strcasecmp | strcmp | strncasecmp | strncmp ) - (E, F) + (E, F) == 0 ) ( S | { ... } ) @@ expression E; expression F; expression G; @@ ( G && ( dns_hostname_cmp | eb_memcmp | memcmp | strcasecmp | strcmp | strncasecmp | strncmp ) - (E, F) + (E, F) != 0 ) @@ expression E; expression F; expression G; @@ ( G || ( dns_hostname_cmp | eb_memcmp | memcmp | strcasecmp | strcmp | strncasecmp | strncmp ) - (E, F) + (E, F) != 0 ) @@ expression E; expression F; expression G; @@ ( ( dns_hostname_cmp | eb_memcmp | memcmp | strcasecmp | strcmp | strncasecmp | strncmp ) - (E, F) + (E, F) != 0 && G ) @@ expression E; expression F; expression G; @@ ( ( dns_hostname_cmp | eb_memcmp | memcmp | strcasecmp | strcmp | strncasecmp | strncmp ) - (E, F) + (E, F) != 0 || G ) @@ expression E; expression F; expression G; @@ ( G && - ! ( dns_hostname_cmp | eb_memcmp | memcmp | strcasecmp | strcmp | strncasecmp | strncmp ) - (E, F) + (E, F) == 0 ) @@ expression E; expression F; expression G; @@ ( G || - ! ( dns_hostname_cmp | eb_memcmp | memcmp | strcasecmp | strcmp | strncasecmp | strncmp ) - (E, F) + (E, F) == 0 ) @@ expression E; expression F; expression G; @@ ( - ! ( dns_hostname_cmp | eb_memcmp | memcmp | strcasecmp | strcmp | strncasecmp | strncmp ) - (E, F) + (E, F) == 0 && G ) @@ expression E; expression F; expression G; @@ ( - ! ( dns_hostname_cmp | eb_memcmp | memcmp | strcasecmp | strcmp | strncasecmp | strncmp ) - (E, F) + (E, F) == 0 || G ) @@ expression E; expression F; expression G; @@ ( - ! ( dns_hostname_cmp | eb_memcmp | memcmp | strcasecmp | strcmp | strncasecmp | strncmp ) - (E, F) + (E, F) == 0 )
2021-01-02 16:31:53 -05:00
if (strcmp(args[cur_arg], "realm") == 0) {
cur_arg++;
if (!*args[cur_arg]) {
memprintf(err, "missing realm value.\n");
return ACT_RET_PRS_ERR;
}
rule->arg.http.str = ist(strdup(args[cur_arg]));
cur_arg++;
}
*orig_arg = cur_arg;
return ACT_RET_PRS_OK;
}
/* This function executes a early-hint action. It adds an HTTP Early Hint HTTP
* 103 response header with <.arg.http.str> name and with a value built
* according to <.arg.http.fmt> log line format. If it is the first early-hint
* rule of series, the 103 response start-line is added first. At the end, if
* the next rule is not an early-hint rule or if it is the last rule, the EOH
* block is added to terminate the response. On success, it returns
* ACT_RET_CONT. If an error occurs while soft rewrites are enabled, the action
* is canceled, but the rule processing continue. Otherwsize ACT_RET_ERR is
* returned.
*/
static enum act_return http_action_early_hint(struct act_rule *rule, struct proxy *px,
struct session *sess, struct stream *s, int flags)
{
struct act_rule *next_rule;
struct channel *res = &s->res;
struct htx *htx = htx_from_buf(&res->buf);
struct buffer *value = alloc_trash_chunk();
enum act_return ret = ACT_RET_CONT;
if (!(s->txn->req.flags & HTTP_MSGF_VER_11))
goto leave;
if (!value) {
if (!(s->flags & SF_ERR_MASK))
s->flags |= SF_ERR_RESOURCE;
goto error;
}
/* if there is no pending 103 response, start a new response. Otherwise,
* continue to add link to a previously started response
*/
if (s->txn->status != 103) {
struct htx_sl *sl;
unsigned int flags = (HTX_SL_F_IS_RESP|HTX_SL_F_VER_11|
HTX_SL_F_XFER_LEN|HTX_SL_F_BODYLESS);
sl = htx_add_stline(htx, HTX_BLK_RES_SL, flags,
ist("HTTP/1.1"), ist("103"), ist("Early Hints"));
if (!sl)
goto error;
sl->info.res.status = 103;
s->txn->status = 103;
}
/* Add the HTTP Early Hint HTTP 103 response header */
value->data = build_logline(s, b_tail(value), b_room(value), &rule->arg.http.fmt);
if (!htx_add_header(htx, rule->arg.http.str, ist2(b_head(value), b_data(value))))
goto error;
/* if it is the last rule or the next one is not an early-hint or an
* conditional early-hint, terminate the current response.
*/
next_rule = LIST_NEXT(&rule->list, typeof(rule), list);
if (&next_rule->list == s->current_rule_list || next_rule->action_ptr != http_action_early_hint || next_rule->cond) {
if (!htx_add_endof(htx, HTX_BLK_EOH))
goto error;
if (!http_forward_proxy_resp(s, 0))
goto error;
s->txn->status = 0;
}
leave:
free_trash_chunk(value);
return ret;
error:
/* If an error occurred during an Early-hint rule, remove the incomplete
* HTTP 103 response from the buffer */
channel_htx_truncate(res, htx);
ret = ACT_RET_ERR;
s->txn->status = 0;
goto leave;
}
/* This function executes a set-header or add-header actions. It builds a string
* in the trash from the specified format string. It finds the action to be
* performed in <.action>, previously filled by function parse_set_header(). The
* replacement action is executed by the function http_action_set_header(). On
* success, it returns ACT_RET_CONT. If an error occurs while soft rewrites are
* enabled, the action is canceled, but the rule processing continue. Otherwsize
* ACT_RET_ERR is returned.
*/
static enum act_return http_action_set_header(struct act_rule *rule, struct proxy *px,
struct session *sess, struct stream *s, int flags)
{
struct http_msg *msg = ((rule->from == ACT_F_HTTP_REQ) ? &s->txn->req : &s->txn->rsp);
struct htx *htx = htxbuf(&msg->chn->buf);
enum act_return ret = ACT_RET_CONT;
struct buffer *replace;
struct http_hdr_ctx ctx;
struct ist n, v;
replace = alloc_trash_chunk();
if (!replace)
goto fail_alloc;
replace->data = build_logline(s, replace->area, replace->size, &rule->arg.http.fmt);
n = rule->arg.http.str;
v = ist2(replace->area, replace->data);
if (rule->action == 0) { // set-header
/* remove all occurrences of the header */
ctx.blk = NULL;
while (http_find_header(htx, n, &ctx, 1))
http_remove_header(htx, &ctx);
}
/* Now add header */
if (!http_add_header(htx, n, v))
goto fail_rewrite;
leave:
free_trash_chunk(replace);
return ret;
fail_alloc:
if (!(s->flags & SF_ERR_MASK))
s->flags |= SF_ERR_RESOURCE;
ret = ACT_RET_ERR;
goto leave;
fail_rewrite:
_HA_ATOMIC_INC(&sess->fe->fe_counters.failed_rewrites);
if (s->flags & SF_BE_ASSIGNED)
_HA_ATOMIC_INC(&s->be->be_counters.failed_rewrites);
if (sess->listener && sess->listener->counters)
_HA_ATOMIC_INC(&sess->listener->counters->failed_rewrites);
if (objt_server(s->target))
_HA_ATOMIC_INC(&__objt_server(s->target)->counters.failed_rewrites);
if (!(msg->flags & HTTP_MSGF_SOFT_RW)) {
ret = ACT_RET_ERR;
if (!(s->flags & SF_ERR_MASK))
s->flags |= SF_ERR_PRXCOND;
}
goto leave;
}
/* Parse a "set-header", "add-header" or "early-hint" actions. It takes an
* header name and a log-format string as arguments. It returns ACT_RET_PRS_OK
* on success, ACT_RET_PRS_ERR on error.
*
* Note: same function is used for the request and the response. However
* "early-hint" rules are only supported for request rules.
*/
static enum act_parse_ret parse_http_set_header(const char **args, int *orig_arg, struct proxy *px,
struct act_rule *rule, char **err)
{
int cap = 0, cur_arg;
const char *p;
if (args[*orig_arg-1][0] == 'e') {
rule->action = ACT_CUSTOM;
rule->action_ptr = http_action_early_hint;
}
else {
if (args[*orig_arg-1][0] == 's')
rule->action = 0; // set-header
else
rule->action = 1; // add-header
rule->action_ptr = http_action_set_header;
}
rule->release_ptr = release_http_action;
MEDIUM: tree-wide: add logformat expressions wrapper log format expressions are broadly used within the code: once they are parsed from input string, they are converted to a linked list of logformat nodes. We're starting to face some limitations because we're simply storing the converted expression as a generic logformat_node list. The first issue we're facing is that storing logformat expressions that way doesn't allow us to add metadata alongside the list, which is part of the prerequites for implementing log-profiles. Another issue with storing logformat expressions as generic lists of logformat_node elements is that it's starting to become really hard to tell when we rely on logformat expressions or not in the code given that there isn't always a comment near the list declaration or manipulation to indicate that it's relying on logformat expressions under the hood, so this adds some complexity for code maintenance. This patch looks quite impressive due to changes in a lot of header and source files (since logformat expressions are broadly used), but it does a simple thing: it defines the lf_expr structure which itself holds a generic list of logformat nodes, and then declares some helpers to manipulate lf_expr elements and fixes the code so that we now exclusively manipulate logformat_node lists as lf_expr elements outside of log.c. For now, lf_expr struct only contains the list of logformat nodes (no additional metadata), but now that we have dedicated type and helpers, doing so in the future won't be problematic at all and won't require extensive code changes.
2024-02-23 09:57:21 -05:00
lf_expr_init(&rule->arg.http.fmt);
cur_arg = *orig_arg;
if (!*args[cur_arg] || !*args[cur_arg+1]) {
memprintf(err, "expects exactly 2 arguments");
return ACT_RET_PRS_ERR;
}
rule->arg.http.str = ist(strdup(args[cur_arg]));
if (rule->from == ACT_F_HTTP_REQ) {
px->conf.args.ctx = ARGC_HRQ;
if (px->cap & PR_CAP_FE)
cap |= SMP_VAL_FE_HRQ_HDR;
if (px->cap & PR_CAP_BE)
cap |= SMP_VAL_BE_HRQ_HDR;
}
else{
px->conf.args.ctx = ARGC_HRS;
if (px->cap & PR_CAP_FE)
cap |= SMP_VAL_FE_HRS_HDR;
if (px->cap & PR_CAP_BE)
cap |= SMP_VAL_BE_HRS_HDR;
}
cur_arg++;
if (!parse_logformat_string(args[cur_arg], px, &rule->arg.http.fmt, LOG_OPT_HTTP, cap, err)) {
istfree(&rule->arg.http.str);
return ACT_RET_PRS_ERR;
}
/* some characters are totally forbidden in header names and
* may happen by accident when writing configs, causing strange
* failures in field. Better catch these ones early, nobody will
* miss them. In particular, a colon at the end (or anywhere
* after the first char) or a space/cr anywhere due to misplaced
* quotes are hard to spot.
*/
for (p = istptr(rule->arg.http.str); p < istend(rule->arg.http.str); p++) {
if (HTTP_IS_TOKEN(*p))
continue;
if (p == istptr(rule->arg.http.str) && *p == ':')
continue;
/* we only report this as-is but it will not cause an error */
memprintf(err, "header name '%s' contains forbidden character '%c'", istptr(rule->arg.http.str), *p);
break;
}
*orig_arg = cur_arg + 1;
return ACT_RET_PRS_OK;
}
/* This function executes a replace-header or replace-value actions. It
* builds a string in the trash from the specified format string. It finds
* the action to be performed in <.action>, previously filled by function
* parse_replace_header(). The replacement action is executed by the function
* http_action_replace_header(). On success, it returns ACT_RET_CONT. If an error
* occurs while soft rewrites are enabled, the action is canceled, but the rule
* processing continue. Otherwsize ACT_RET_ERR is returned.
*/
static enum act_return http_action_replace_header(struct act_rule *rule, struct proxy *px,
struct session *sess, struct stream *s, int flags)
{
struct http_msg *msg = ((rule->from == ACT_F_HTTP_REQ) ? &s->txn->req : &s->txn->rsp);
struct htx *htx = htxbuf(&msg->chn->buf);
enum act_return ret = ACT_RET_CONT;
struct buffer *replace;
int r;
replace = alloc_trash_chunk();
if (!replace)
goto fail_alloc;
replace->data = build_logline(s, replace->area, replace->size, &rule->arg.http.fmt);
r = http_replace_hdrs(s, htx, rule->arg.http.str, replace->area, rule->arg.http.re, (rule->action == 0));
if (r == -1)
goto fail_rewrite;
leave:
free_trash_chunk(replace);
return ret;
fail_alloc:
if (!(s->flags & SF_ERR_MASK))
s->flags |= SF_ERR_RESOURCE;
ret = ACT_RET_ERR;
goto leave;
fail_rewrite:
_HA_ATOMIC_INC(&sess->fe->fe_counters.failed_rewrites);
if (s->flags & SF_BE_ASSIGNED)
_HA_ATOMIC_INC(&s->be->be_counters.failed_rewrites);
if (sess->listener && sess->listener->counters)
_HA_ATOMIC_INC(&sess->listener->counters->failed_rewrites);
if (objt_server(s->target))
_HA_ATOMIC_INC(&__objt_server(s->target)->counters.failed_rewrites);
if (!(msg->flags & HTTP_MSGF_SOFT_RW)) {
ret = ACT_RET_ERR;
if (!(s->flags & SF_ERR_MASK))
s->flags |= SF_ERR_PRXCOND;
}
goto leave;
}
/* Parse a "replace-header" or "replace-value" actions. It takes an header name,
* a regex and replacement string as arguments. It returns ACT_RET_PRS_OK on
* success, ACT_RET_PRS_ERR on error.
*/
static enum act_parse_ret parse_http_replace_header(const char **args, int *orig_arg, struct proxy *px,
struct act_rule *rule, char **err)
{
int cap = 0, cur_arg;
if (args[*orig_arg-1][8] == 'h')
rule->action = 0; // replace-header
else
rule->action = 1; // replace-value
rule->action_ptr = http_action_replace_header;
rule->release_ptr = release_http_action;
MEDIUM: tree-wide: add logformat expressions wrapper log format expressions are broadly used within the code: once they are parsed from input string, they are converted to a linked list of logformat nodes. We're starting to face some limitations because we're simply storing the converted expression as a generic logformat_node list. The first issue we're facing is that storing logformat expressions that way doesn't allow us to add metadata alongside the list, which is part of the prerequites for implementing log-profiles. Another issue with storing logformat expressions as generic lists of logformat_node elements is that it's starting to become really hard to tell when we rely on logformat expressions or not in the code given that there isn't always a comment near the list declaration or manipulation to indicate that it's relying on logformat expressions under the hood, so this adds some complexity for code maintenance. This patch looks quite impressive due to changes in a lot of header and source files (since logformat expressions are broadly used), but it does a simple thing: it defines the lf_expr structure which itself holds a generic list of logformat nodes, and then declares some helpers to manipulate lf_expr elements and fixes the code so that we now exclusively manipulate logformat_node lists as lf_expr elements outside of log.c. For now, lf_expr struct only contains the list of logformat nodes (no additional metadata), but now that we have dedicated type and helpers, doing so in the future won't be problematic at all and won't require extensive code changes.
2024-02-23 09:57:21 -05:00
lf_expr_init(&rule->arg.http.fmt);
cur_arg = *orig_arg;
if (!*args[cur_arg] || !*args[cur_arg+1] || !*args[cur_arg+2]) {
memprintf(err, "expects exactly 3 arguments");
return ACT_RET_PRS_ERR;
}
rule->arg.http.str = ist(strdup(args[cur_arg]));
cur_arg++;
if (!(rule->arg.http.re = regex_comp(args[cur_arg], 1, 1, err))) {
istfree(&rule->arg.http.str);
return ACT_RET_PRS_ERR;
}
if (rule->from == ACT_F_HTTP_REQ) {
px->conf.args.ctx = ARGC_HRQ;
if (px->cap & PR_CAP_FE)
cap |= SMP_VAL_FE_HRQ_HDR;
if (px->cap & PR_CAP_BE)
cap |= SMP_VAL_BE_HRQ_HDR;
}
else{
px->conf.args.ctx = ARGC_HRS;
if (px->cap & PR_CAP_FE)
cap |= SMP_VAL_FE_HRS_HDR;
if (px->cap & PR_CAP_BE)
cap |= SMP_VAL_BE_HRS_HDR;
}
cur_arg++;
if (!parse_logformat_string(args[cur_arg], px, &rule->arg.http.fmt, LOG_OPT_HTTP, cap, err)) {
istfree(&rule->arg.http.str);
regex_free(rule->arg.http.re);
return ACT_RET_PRS_ERR;
}
*orig_arg = cur_arg + 1;
return ACT_RET_PRS_OK;
}
/* This function executes a del-header action with selected matching mode for
* header name. It finds the matching method to be performed in <.action>, previously
* filled by function parse_http_del_header(). On success, it returns ACT_RET_CONT.
* Otherwise ACT_RET_ERR is returned.
*/
static enum act_return http_action_del_header(struct act_rule *rule, struct proxy *px,
struct session *sess, struct stream *s, int flags)
{
struct http_hdr_ctx ctx;
struct http_msg *msg = ((rule->from == ACT_F_HTTP_REQ) ? &s->txn->req : &s->txn->rsp);
struct htx *htx = htxbuf(&msg->chn->buf);
enum act_return ret = ACT_RET_CONT;
/* remove all occurrences of the header */
ctx.blk = NULL;
switch (rule->action) {
case PAT_MATCH_STR:
while (http_find_header(htx, rule->arg.http.str, &ctx, 1))
http_remove_header(htx, &ctx);
break;
case PAT_MATCH_BEG:
while (http_find_pfx_header(htx, rule->arg.http.str, &ctx, 1))
http_remove_header(htx, &ctx);
break;
case PAT_MATCH_END:
while (http_find_sfx_header(htx, rule->arg.http.str, &ctx, 1))
http_remove_header(htx, &ctx);
break;
case PAT_MATCH_SUB:
while (http_find_sub_header(htx, rule->arg.http.str, &ctx, 1))
http_remove_header(htx, &ctx);
break;
case PAT_MATCH_REG:
while (http_match_header(htx, rule->arg.http.re, &ctx, 1))
http_remove_header(htx, &ctx);
break;
default:
return ACT_RET_ERR;
}
return ret;
}
/* Parse a "del-header" action. It takes string as a required argument,
* optional flag (currently only -m) and optional matching method of input string
* with header name to be deleted. Default matching method is exact match (-m str).
* It returns ACT_RET_PRS_OK on success, ACT_RET_PRS_ERR on error.
*/
static enum act_parse_ret parse_http_del_header(const char **args, int *orig_arg, struct proxy *px,
struct act_rule *rule, char **err)
{
int cur_arg;
int pat_idx;
/* set exact matching (-m str) as default */
rule->action = PAT_MATCH_STR;
rule->action_ptr = http_action_del_header;
rule->release_ptr = release_http_action;
MEDIUM: tree-wide: add logformat expressions wrapper log format expressions are broadly used within the code: once they are parsed from input string, they are converted to a linked list of logformat nodes. We're starting to face some limitations because we're simply storing the converted expression as a generic logformat_node list. The first issue we're facing is that storing logformat expressions that way doesn't allow us to add metadata alongside the list, which is part of the prerequites for implementing log-profiles. Another issue with storing logformat expressions as generic lists of logformat_node elements is that it's starting to become really hard to tell when we rely on logformat expressions or not in the code given that there isn't always a comment near the list declaration or manipulation to indicate that it's relying on logformat expressions under the hood, so this adds some complexity for code maintenance. This patch looks quite impressive due to changes in a lot of header and source files (since logformat expressions are broadly used), but it does a simple thing: it defines the lf_expr structure which itself holds a generic list of logformat nodes, and then declares some helpers to manipulate lf_expr elements and fixes the code so that we now exclusively manipulate logformat_node lists as lf_expr elements outside of log.c. For now, lf_expr struct only contains the list of logformat nodes (no additional metadata), but now that we have dedicated type and helpers, doing so in the future won't be problematic at all and won't require extensive code changes.
2024-02-23 09:57:21 -05:00
lf_expr_init(&rule->arg.http.fmt);
cur_arg = *orig_arg;
if (!*args[cur_arg]) {
memprintf(err, "expects at least 1 argument");
return ACT_RET_PRS_ERR;
}
rule->arg.http.str = ist(strdup(args[cur_arg]));
px->conf.args.ctx = (rule->from == ACT_F_HTTP_REQ ? ARGC_HRQ : ARGC_HRS);
if (strcmp(args[cur_arg+1], "-m") == 0) {
cur_arg++;
if (!*args[cur_arg+1]) {
memprintf(err, "-m flag expects exactly 1 argument");
return ACT_RET_PRS_ERR;
}
cur_arg++;
pat_idx = pat_find_match_name(args[cur_arg]);
switch (pat_idx) {
case PAT_MATCH_REG:
if (!(rule->arg.http.re = regex_comp(rule->arg.http.str.ptr, 1, 1, err)))
return ACT_RET_PRS_ERR;
__fallthrough;
case PAT_MATCH_STR:
case PAT_MATCH_BEG:
case PAT_MATCH_END:
case PAT_MATCH_SUB:
rule->action = pat_idx;
break;
default:
memprintf(err, "-m with unsupported matching method '%s'", args[cur_arg]);
return ACT_RET_PRS_ERR;
}
}
*orig_arg = cur_arg + 1;
return ACT_RET_PRS_OK;
}
/* Release memory allocated by an http redirect action. */
static void release_http_redir(struct act_rule *rule)
{
struct redirect_rule *redir;
redir = rule->arg.redir;
if (!redir)
return;
LIST_DELETE(&redir->list);
http_free_redirect_rule(redir);
}
/* Parse a "redirect" action. It returns ACT_RET_PRS_OK on success,
* ACT_RET_PRS_ERR on error.
*/
static enum act_parse_ret parse_http_redirect(const char **args, int *orig_arg, struct proxy *px,
struct act_rule *rule, char **err)
{
struct redirect_rule *redir;
int dir, cur_arg;
rule->action = ACT_HTTP_REDIR;
rule->release_ptr = release_http_redir;
cur_arg = *orig_arg;
dir = (rule->from == ACT_F_HTTP_REQ ? 0 : 1);
if ((redir = http_parse_redirect_rule(px->conf.args.file, px->conf.args.line, px, &args[cur_arg], err, 1, dir)) == NULL)
return ACT_RET_PRS_ERR;
if (!(redir->flags & REDIRECT_FLAG_IGNORE_EMPTY))
rule->flags |= ACT_FLAG_FINAL;
rule->arg.redir = redir;
rule->cond = redir->cond;
redir->cond = NULL;
/* skip all arguments */
while (*args[cur_arg])
cur_arg++;
*orig_arg = cur_arg;
return ACT_RET_PRS_OK;
}
/* This function executes a add-acl, del-acl, set-map or del-map actions. On
* success, it returns ACT_RET_CONT. Otherwsize ACT_RET_ERR is returned.
*/
static enum act_return http_action_set_map(struct act_rule *rule, struct proxy *px,
struct session *sess, struct stream *s, int flags)
{
struct pat_ref *ref;
struct buffer *key = NULL, *value = NULL;
enum act_return ret = ACT_RET_CONT;
/* collect reference */
ref = pat_ref_lookup(rule->arg.map.ref);
if (!ref)
goto leave;
/* allocate key */
key = alloc_trash_chunk();
if (!key)
goto fail_alloc;
/* collect key */
key->data = build_logline(s, key->area, key->size, &rule->arg.map.key);
key->area[key->data] = '\0';
switch (rule->action) {
case 0: // add-acl
/* add entry only if it does not already exist */
HA_RWLOCK_WRLOCK(PATREF_LOCK, &ref->lock);
if (pat_ref_find_elt(ref, key->area) == NULL)
pat_ref_add(ref, key->area, NULL, NULL);
HA_RWLOCK_WRUNLOCK(PATREF_LOCK, &ref->lock);
break;
case 1: // set-map
{
struct pat_ref_elt *elt;
/* allocate value */
value = alloc_trash_chunk();
if (!value)
goto fail_alloc;
/* collect value */
value->data = build_logline(s, value->area, value->size, &rule->arg.map.value);
value->area[value->data] = '\0';
HA_RWLOCK_WRLOCK(PATREF_LOCK, &ref->lock);
elt = pat_ref_find_elt(ref, key->area);
if (elt) {
/* update entry if it exists */
pat_ref_set_elt_duplicate(ref, elt, value->area, NULL);
}
else {
/* insert a new entry */
pat_ref_add(ref, key->area, value->area, NULL);
}
HA_RWLOCK_WRUNLOCK(PATREF_LOCK, &ref->lock);
break;
}
case 2: // del-acl
case 3: // del-map
/* returned code: 1=ok, 0=ko */
HA_RWLOCK_WRLOCK(PATREF_LOCK, &ref->lock);
pat_ref_delete(ref, key->area);
HA_RWLOCK_WRUNLOCK(PATREF_LOCK, &ref->lock);
break;
default:
ret = ACT_RET_ERR;
}
leave:
free_trash_chunk(key);
free_trash_chunk(value);
return ret;
fail_alloc:
if (!(s->flags & SF_ERR_MASK))
s->flags |= SF_ERR_RESOURCE;
ret = ACT_RET_ERR;
goto leave;
}
/* Release memory allocated by an http map/acl action. */
static void release_http_map(struct act_rule *rule)
{
free(rule->arg.map.ref);
MEDIUM: tree-wide: add logformat expressions wrapper log format expressions are broadly used within the code: once they are parsed from input string, they are converted to a linked list of logformat nodes. We're starting to face some limitations because we're simply storing the converted expression as a generic logformat_node list. The first issue we're facing is that storing logformat expressions that way doesn't allow us to add metadata alongside the list, which is part of the prerequites for implementing log-profiles. Another issue with storing logformat expressions as generic lists of logformat_node elements is that it's starting to become really hard to tell when we rely on logformat expressions or not in the code given that there isn't always a comment near the list declaration or manipulation to indicate that it's relying on logformat expressions under the hood, so this adds some complexity for code maintenance. This patch looks quite impressive due to changes in a lot of header and source files (since logformat expressions are broadly used), but it does a simple thing: it defines the lf_expr structure which itself holds a generic list of logformat nodes, and then declares some helpers to manipulate lf_expr elements and fixes the code so that we now exclusively manipulate logformat_node lists as lf_expr elements outside of log.c. For now, lf_expr struct only contains the list of logformat nodes (no additional metadata), but now that we have dedicated type and helpers, doing so in the future won't be problematic at all and won't require extensive code changes.
2024-02-23 09:57:21 -05:00
lf_expr_deinit(&rule->arg.map.key);
if (rule->action == 1)
MEDIUM: tree-wide: add logformat expressions wrapper log format expressions are broadly used within the code: once they are parsed from input string, they are converted to a linked list of logformat nodes. We're starting to face some limitations because we're simply storing the converted expression as a generic logformat_node list. The first issue we're facing is that storing logformat expressions that way doesn't allow us to add metadata alongside the list, which is part of the prerequites for implementing log-profiles. Another issue with storing logformat expressions as generic lists of logformat_node elements is that it's starting to become really hard to tell when we rely on logformat expressions or not in the code given that there isn't always a comment near the list declaration or manipulation to indicate that it's relying on logformat expressions under the hood, so this adds some complexity for code maintenance. This patch looks quite impressive due to changes in a lot of header and source files (since logformat expressions are broadly used), but it does a simple thing: it defines the lf_expr structure which itself holds a generic list of logformat nodes, and then declares some helpers to manipulate lf_expr elements and fixes the code so that we now exclusively manipulate logformat_node lists as lf_expr elements outside of log.c. For now, lf_expr struct only contains the list of logformat nodes (no additional metadata), but now that we have dedicated type and helpers, doing so in the future won't be problematic at all and won't require extensive code changes.
2024-02-23 09:57:21 -05:00
lf_expr_deinit(&rule->arg.map.value);
}
/* Parse a "add-acl", "del-acl", "set-map" or "del-map" actions. It takes one or
* two log-format string as argument depending on the action. The action is
* stored in <.action> as an int (0=add-acl, 1=set-map, 2=del-acl,
* 3=del-map). It returns ACT_RET_PRS_OK on success, ACT_RET_PRS_ERR on error.
*/
static enum act_parse_ret parse_http_set_map(const char **args, int *orig_arg, struct proxy *px,
struct act_rule *rule, char **err)
{
int cap = 0, cur_arg;
if (args[*orig_arg-1][0] == 'a') // add-acl
rule->action = 0;
else if (args[*orig_arg-1][0] == 's') // set-map
rule->action = 1;
else if (args[*orig_arg-1][4] == 'a') // del-acl
rule->action = 2;
else if (args[*orig_arg-1][4] == 'm') // del-map
rule->action = 3;
else {
memprintf(err, "internal error: unhandled action '%s'", args[0]);
return ACT_RET_PRS_ERR;
}
rule->action_ptr = http_action_set_map;
rule->release_ptr = release_http_map;
cur_arg = *orig_arg;
if (rule->action == 1 && (!*args[cur_arg] || !*args[cur_arg+1])) {
/* 2 args for set-map */
memprintf(err, "expects exactly 2 arguments");
return ACT_RET_PRS_ERR;
}
else if (!*args[cur_arg]) {
/* only one arg for other actions */
memprintf(err, "expects exactly 1 arguments");
return ACT_RET_PRS_ERR;
}
/*
* '+ 8' for 'set-map(' (same for del-map)
* '- 9' for 'set-map(' + trailing ')' (same for del-map)
*/
rule->arg.map.ref = my_strndup(args[cur_arg-1] + 8, strlen(args[cur_arg-1]) - 9);
if (rule->from == ACT_F_HTTP_REQ) {
px->conf.args.ctx = ARGC_HRQ;
if (px->cap & PR_CAP_FE)
cap |= SMP_VAL_FE_HRQ_HDR;
if (px->cap & PR_CAP_BE)
cap |= SMP_VAL_BE_HRQ_HDR;
}
else{
px->conf.args.ctx = ARGC_HRS;
if (px->cap & PR_CAP_FE)
cap |= SMP_VAL_FE_HRS_HDR;
if (px->cap & PR_CAP_BE)
cap |= SMP_VAL_BE_HRS_HDR;
}
/* key pattern */
MEDIUM: tree-wide: add logformat expressions wrapper log format expressions are broadly used within the code: once they are parsed from input string, they are converted to a linked list of logformat nodes. We're starting to face some limitations because we're simply storing the converted expression as a generic logformat_node list. The first issue we're facing is that storing logformat expressions that way doesn't allow us to add metadata alongside the list, which is part of the prerequites for implementing log-profiles. Another issue with storing logformat expressions as generic lists of logformat_node elements is that it's starting to become really hard to tell when we rely on logformat expressions or not in the code given that there isn't always a comment near the list declaration or manipulation to indicate that it's relying on logformat expressions under the hood, so this adds some complexity for code maintenance. This patch looks quite impressive due to changes in a lot of header and source files (since logformat expressions are broadly used), but it does a simple thing: it defines the lf_expr structure which itself holds a generic list of logformat nodes, and then declares some helpers to manipulate lf_expr elements and fixes the code so that we now exclusively manipulate logformat_node lists as lf_expr elements outside of log.c. For now, lf_expr struct only contains the list of logformat nodes (no additional metadata), but now that we have dedicated type and helpers, doing so in the future won't be problematic at all and won't require extensive code changes.
2024-02-23 09:57:21 -05:00
lf_expr_init(&rule->arg.map.key);
if (!parse_logformat_string(args[cur_arg], px, &rule->arg.map.key, LOG_OPT_NONE, cap, err)) {
free(rule->arg.map.ref);
return ACT_RET_PRS_ERR;
}
if (rule->action == 1) {
/* value pattern for set-map only */
cur_arg++;
MEDIUM: tree-wide: add logformat expressions wrapper log format expressions are broadly used within the code: once they are parsed from input string, they are converted to a linked list of logformat nodes. We're starting to face some limitations because we're simply storing the converted expression as a generic logformat_node list. The first issue we're facing is that storing logformat expressions that way doesn't allow us to add metadata alongside the list, which is part of the prerequites for implementing log-profiles. Another issue with storing logformat expressions as generic lists of logformat_node elements is that it's starting to become really hard to tell when we rely on logformat expressions or not in the code given that there isn't always a comment near the list declaration or manipulation to indicate that it's relying on logformat expressions under the hood, so this adds some complexity for code maintenance. This patch looks quite impressive due to changes in a lot of header and source files (since logformat expressions are broadly used), but it does a simple thing: it defines the lf_expr structure which itself holds a generic list of logformat nodes, and then declares some helpers to manipulate lf_expr elements and fixes the code so that we now exclusively manipulate logformat_node lists as lf_expr elements outside of log.c. For now, lf_expr struct only contains the list of logformat nodes (no additional metadata), but now that we have dedicated type and helpers, doing so in the future won't be problematic at all and won't require extensive code changes.
2024-02-23 09:57:21 -05:00
lf_expr_init(&rule->arg.map.value);
if (!parse_logformat_string(args[cur_arg], px, &rule->arg.map.value, LOG_OPT_NONE, cap, err)) {
free(rule->arg.map.ref);
return ACT_RET_PRS_ERR;
}
}
*orig_arg = cur_arg + 1;
return ACT_RET_PRS_OK;
}
/* This function executes a track-sc* actions. On success, it returns
* ACT_RET_CONT. Otherwsize ACT_RET_ERR is returned.
*/
static enum act_return http_action_track_sc(struct act_rule *rule, struct proxy *px,
struct session *sess, struct stream *s, int flags)
{
struct stktable *t;
struct stksess *ts;
struct stktable_key *key;
MINOR: stick-tables/counters: add http_fail_cnt and http_fail_rate data types Historically we've been counting lots of client-triggered events in stick tables to help detect misbehaving ones, but we've been missing the same on the server side, and there's been repeated requests for being able to count the server errors per URL in order to precisely monitor the quality of service or even to avoid routing requests to certain dead services, which is also called "circuit breaking" nowadays. This commit introduces http_fail_cnt and http_fail_rate, which work like http_err_cnt and http_err_rate in that they respectively count events and their frequency, but they only consider server-side issues such as network errors, unparsable and truncated responses, and 5xx status codes other than 501 and 505 (since these ones are usually triggered by the client). Note that retryable errors are purposely not accounted for, so that only what the client really sees is considered. With this it becomes very simple to put some protective measures in place to perform a redirect or return an excuse page when the error rate goes beyond a certain threshold for a given URL, and give more chances to the server to recover from this condition. Typically it could look like this to bypass a URL causing more than 10 requests per second: stick-table type string len 80 size 4k expire 1m store http_fail_rate(1m) http-request track-sc0 base # track host+path, ignore query string http-request return status 503 content-type text/html \ lf-file excuse.html if { sc0_http_fail_rate gt 10 } A more advanced mechanism using gpt0 could even implement high/low rates to disable/enable the service. Reg-test converteers_ref_cnt_never_dec.vtc was updated to test it.
2021-02-10 06:07:15 -05:00
void *ptr1, *ptr2, *ptr3, *ptr4, *ptr5, *ptr6;
int opt;
MINOR: stick-tables/counters: add http_fail_cnt and http_fail_rate data types Historically we've been counting lots of client-triggered events in stick tables to help detect misbehaving ones, but we've been missing the same on the server side, and there's been repeated requests for being able to count the server errors per URL in order to precisely monitor the quality of service or even to avoid routing requests to certain dead services, which is also called "circuit breaking" nowadays. This commit introduces http_fail_cnt and http_fail_rate, which work like http_err_cnt and http_err_rate in that they respectively count events and their frequency, but they only consider server-side issues such as network errors, unparsable and truncated responses, and 5xx status codes other than 501 and 505 (since these ones are usually triggered by the client). Note that retryable errors are purposely not accounted for, so that only what the client really sees is considered. With this it becomes very simple to put some protective measures in place to perform a redirect or return an excuse page when the error rate goes beyond a certain threshold for a given URL, and give more chances to the server to recover from this condition. Typically it could look like this to bypass a URL causing more than 10 requests per second: stick-table type string len 80 size 4k expire 1m store http_fail_rate(1m) http-request track-sc0 base # track host+path, ignore query string http-request return status 503 content-type text/html \ lf-file excuse.html if { sc0_http_fail_rate gt 10 } A more advanced mechanism using gpt0 could even implement high/low rates to disable/enable the service. Reg-test converteers_ref_cnt_never_dec.vtc was updated to test it.
2021-02-10 06:07:15 -05:00
ptr1 = ptr2 = ptr3 = ptr4 = ptr5 = ptr6 = NULL;
opt = ((rule->from == ACT_F_HTTP_REQ) ? SMP_OPT_DIR_REQ : SMP_OPT_DIR_RES) | SMP_OPT_FINAL;
t = rule->arg.trk_ctr.table.t;
if (stkctr_entry(&s->stkctr[rule->action]))
goto end;
key = stktable_fetch_key(t, s->be, sess, s, opt, rule->arg.trk_ctr.expr, NULL);
if (!key)
goto end;
ts = stktable_get_entry(t, key);
if (!ts)
goto end;
stream_track_stkctr(&s->stkctr[rule->action], t, ts);
/* let's count a new HTTP request as it's the first time we do it */
ptr1 = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_CNT);
ptr2 = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_RATE);
/* When the client triggers a 4xx from the server, it's most often due
* to a missing object or permission. These events should be tracked
* because if they happen often, it may indicate a brute force or a
* vulnerability scan. Normally this is done when receiving the response
* but here we're tracking after this ought to have been done so we have
* to do it on purpose.
*/
if (rule->from == ACT_F_HTTP_RES &&
http_status_matches(http_err_status_codes, s->txn->status)) {
ptr3 = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_CNT);
ptr4 = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_ERR_RATE);
}
if (rule->from == ACT_F_HTTP_RES &&
http_status_matches(http_fail_status_codes, s->txn->status)) {
MINOR: stick-tables/counters: add http_fail_cnt and http_fail_rate data types Historically we've been counting lots of client-triggered events in stick tables to help detect misbehaving ones, but we've been missing the same on the server side, and there's been repeated requests for being able to count the server errors per URL in order to precisely monitor the quality of service or even to avoid routing requests to certain dead services, which is also called "circuit breaking" nowadays. This commit introduces http_fail_cnt and http_fail_rate, which work like http_err_cnt and http_err_rate in that they respectively count events and their frequency, but they only consider server-side issues such as network errors, unparsable and truncated responses, and 5xx status codes other than 501 and 505 (since these ones are usually triggered by the client). Note that retryable errors are purposely not accounted for, so that only what the client really sees is considered. With this it becomes very simple to put some protective measures in place to perform a redirect or return an excuse page when the error rate goes beyond a certain threshold for a given URL, and give more chances to the server to recover from this condition. Typically it could look like this to bypass a URL causing more than 10 requests per second: stick-table type string len 80 size 4k expire 1m store http_fail_rate(1m) http-request track-sc0 base # track host+path, ignore query string http-request return status 503 content-type text/html \ lf-file excuse.html if { sc0_http_fail_rate gt 10 } A more advanced mechanism using gpt0 could even implement high/low rates to disable/enable the service. Reg-test converteers_ref_cnt_never_dec.vtc was updated to test it.
2021-02-10 06:07:15 -05:00
ptr5 = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_FAIL_CNT);
ptr6 = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_FAIL_RATE);
}
if (ptr1 || ptr2 || ptr3 || ptr4 || ptr5 || ptr6) {
HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
if (ptr1)
stktable_data_cast(ptr1, std_t_uint)++;
if (ptr2)
update_freq_ctr_period(&stktable_data_cast(ptr2, std_t_frqp),
t->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u, 1);
if (ptr3)
stktable_data_cast(ptr3, std_t_uint)++;
if (ptr4)
update_freq_ctr_period(&stktable_data_cast(ptr4, std_t_frqp),
t->data_arg[STKTABLE_DT_HTTP_ERR_RATE].u, 1);
MINOR: stick-tables/counters: add http_fail_cnt and http_fail_rate data types Historically we've been counting lots of client-triggered events in stick tables to help detect misbehaving ones, but we've been missing the same on the server side, and there's been repeated requests for being able to count the server errors per URL in order to precisely monitor the quality of service or even to avoid routing requests to certain dead services, which is also called "circuit breaking" nowadays. This commit introduces http_fail_cnt and http_fail_rate, which work like http_err_cnt and http_err_rate in that they respectively count events and their frequency, but they only consider server-side issues such as network errors, unparsable and truncated responses, and 5xx status codes other than 501 and 505 (since these ones are usually triggered by the client). Note that retryable errors are purposely not accounted for, so that only what the client really sees is considered. With this it becomes very simple to put some protective measures in place to perform a redirect or return an excuse page when the error rate goes beyond a certain threshold for a given URL, and give more chances to the server to recover from this condition. Typically it could look like this to bypass a URL causing more than 10 requests per second: stick-table type string len 80 size 4k expire 1m store http_fail_rate(1m) http-request track-sc0 base # track host+path, ignore query string http-request return status 503 content-type text/html \ lf-file excuse.html if { sc0_http_fail_rate gt 10 } A more advanced mechanism using gpt0 could even implement high/low rates to disable/enable the service. Reg-test converteers_ref_cnt_never_dec.vtc was updated to test it.
2021-02-10 06:07:15 -05:00
if (ptr5)
stktable_data_cast(ptr5, std_t_uint)++;
MINOR: stick-tables/counters: add http_fail_cnt and http_fail_rate data types Historically we've been counting lots of client-triggered events in stick tables to help detect misbehaving ones, but we've been missing the same on the server side, and there's been repeated requests for being able to count the server errors per URL in order to precisely monitor the quality of service or even to avoid routing requests to certain dead services, which is also called "circuit breaking" nowadays. This commit introduces http_fail_cnt and http_fail_rate, which work like http_err_cnt and http_err_rate in that they respectively count events and their frequency, but they only consider server-side issues such as network errors, unparsable and truncated responses, and 5xx status codes other than 501 and 505 (since these ones are usually triggered by the client). Note that retryable errors are purposely not accounted for, so that only what the client really sees is considered. With this it becomes very simple to put some protective measures in place to perform a redirect or return an excuse page when the error rate goes beyond a certain threshold for a given URL, and give more chances to the server to recover from this condition. Typically it could look like this to bypass a URL causing more than 10 requests per second: stick-table type string len 80 size 4k expire 1m store http_fail_rate(1m) http-request track-sc0 base # track host+path, ignore query string http-request return status 503 content-type text/html \ lf-file excuse.html if { sc0_http_fail_rate gt 10 } A more advanced mechanism using gpt0 could even implement high/low rates to disable/enable the service. Reg-test converteers_ref_cnt_never_dec.vtc was updated to test it.
2021-02-10 06:07:15 -05:00
if (ptr6)
update_freq_ctr_period(&stktable_data_cast(ptr6, std_t_frqp),
MINOR: stick-tables/counters: add http_fail_cnt and http_fail_rate data types Historically we've been counting lots of client-triggered events in stick tables to help detect misbehaving ones, but we've been missing the same on the server side, and there's been repeated requests for being able to count the server errors per URL in order to precisely monitor the quality of service or even to avoid routing requests to certain dead services, which is also called "circuit breaking" nowadays. This commit introduces http_fail_cnt and http_fail_rate, which work like http_err_cnt and http_err_rate in that they respectively count events and their frequency, but they only consider server-side issues such as network errors, unparsable and truncated responses, and 5xx status codes other than 501 and 505 (since these ones are usually triggered by the client). Note that retryable errors are purposely not accounted for, so that only what the client really sees is considered. With this it becomes very simple to put some protective measures in place to perform a redirect or return an excuse page when the error rate goes beyond a certain threshold for a given URL, and give more chances to the server to recover from this condition. Typically it could look like this to bypass a URL causing more than 10 requests per second: stick-table type string len 80 size 4k expire 1m store http_fail_rate(1m) http-request track-sc0 base # track host+path, ignore query string http-request return status 503 content-type text/html \ lf-file excuse.html if { sc0_http_fail_rate gt 10 } A more advanced mechanism using gpt0 could even implement high/low rates to disable/enable the service. Reg-test converteers_ref_cnt_never_dec.vtc was updated to test it.
2021-02-10 06:07:15 -05:00
t->data_arg[STKTABLE_DT_HTTP_FAIL_RATE].u, 1);
HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
/* If data was modified, we need to touch to re-schedule sync */
stktable_touch_local(t, ts, 0);
}
stkctr_set_flags(&s->stkctr[rule->action], STKCTR_TRACK_CONTENT);
if (sess->fe != s->be)
stkctr_set_flags(&s->stkctr[rule->action], STKCTR_TRACK_BACKEND);
end:
return ACT_RET_CONT;
}
static void release_http_track_sc(struct act_rule *rule)
{
release_sample_expr(rule->arg.trk_ctr.expr);
}
/* Parse a "track-sc*" actions. It returns ACT_RET_PRS_OK on success,
* ACT_RET_PRS_ERR on error.
*/
static enum act_parse_ret parse_http_track_sc(const char **args, int *orig_arg, struct proxy *px,
struct act_rule *rule, char **err)
{
struct sample_expr *expr;
unsigned int where;
unsigned int tsc_num;
const char *tsc_num_str;
int cur_arg;
tsc_num_str = &args[*orig_arg-1][8];
if (cfg_parse_track_sc_num(&tsc_num, tsc_num_str, tsc_num_str + strlen(tsc_num_str), err) == -1)
return ACT_RET_PRS_ERR;
cur_arg = *orig_arg;
expr = sample_parse_expr((char **)args, &cur_arg, px->conf.args.file, px->conf.args.line,
err, &px->conf.args, NULL);
if (!expr)
return ACT_RET_PRS_ERR;
where = 0;
if (px->cap & PR_CAP_FE)
where |= (rule->from == ACT_F_HTTP_REQ ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_FE_HRS_HDR);
if (px->cap & PR_CAP_BE)
where |= (rule->from == ACT_F_HTTP_REQ ? SMP_VAL_BE_HRQ_HDR : SMP_VAL_BE_HRS_HDR);
if (!(expr->fetch->val & where)) {
memprintf(err, "fetch method '%s' extracts information from '%s', none of which is available here",
args[cur_arg-1], sample_src_names(expr->fetch->use));
release_sample_expr(expr);
return ACT_RET_PRS_ERR;
}
if (strcmp(args[cur_arg], "table") == 0) {
cur_arg++;
if (!*args[cur_arg]) {
memprintf(err, "missing table name");
release_sample_expr(expr);
return ACT_RET_PRS_ERR;
}
/* we copy the table name for now, it will be resolved later */
rule->arg.trk_ctr.table.n = strdup(args[cur_arg]);
cur_arg++;
}
rule->action = tsc_num;
rule->arg.trk_ctr.expr = expr;
rule->action_ptr = http_action_track_sc;
rule->release_ptr = release_http_track_sc;
rule->check_ptr = check_trk_action;
*orig_arg = cur_arg;
return ACT_RET_PRS_OK;
}
static enum act_return action_timeout_set_stream_timeout(struct act_rule *rule,
struct proxy *px,
struct session *sess,
struct stream *s,
int flags)
{
struct sample *key;
if (rule->arg.timeout.expr) {
key = sample_fetch_as_type(px, sess, s, SMP_OPT_FINAL, rule->arg.timeout.expr, SMP_T_SINT);
if (!key)
return ACT_RET_CONT;
stream_set_timeout(s, rule->arg.timeout.type, MS_TO_TICKS(key->data.u.sint));
}
else {
stream_set_timeout(s, rule->arg.timeout.type, MS_TO_TICKS(rule->arg.timeout.value));
}
return ACT_RET_CONT;
}
/* Parse a "set-timeout" action. Returns ACT_RET_PRS_ERR if parsing error.
*/
static enum act_parse_ret parse_http_set_timeout(const char **args,
int *orig_arg,
struct proxy *px,
struct act_rule *rule, char **err)
{
int cur_arg;
rule->action = ACT_CUSTOM;
rule->action_ptr = action_timeout_set_stream_timeout;
rule->release_ptr = release_timeout_action;
cur_arg = *orig_arg;
if (!*args[cur_arg] || !*args[cur_arg + 1]) {
memprintf(err, "expects exactly 2 arguments");
return ACT_RET_PRS_ERR;
}
if (cfg_parse_rule_set_timeout(args, cur_arg, rule, px, err) == -1) {
return ACT_RET_PRS_ERR;
}
*orig_arg = cur_arg + 2;
return ACT_RET_PRS_OK;
}
/* This function executes a strict-mode actions. On success, it always returns
* ACT_RET_CONT
*/
static enum act_return http_action_strict_mode(struct act_rule *rule, struct proxy *px,
struct session *sess, struct stream *s, int flags)
{
struct http_msg *msg = ((rule->from == ACT_F_HTTP_REQ) ? &s->txn->req : &s->txn->rsp);
if (rule->action == 0) // strict-mode on
msg->flags &= ~HTTP_MSGF_SOFT_RW;
else // strict-mode off
msg->flags |= HTTP_MSGF_SOFT_RW;
return ACT_RET_CONT;
}
/* Parse a "strict-mode" action. It returns ACT_RET_PRS_OK on success,
* ACT_RET_PRS_ERR on error.
*/
static enum act_parse_ret parse_http_strict_mode(const char **args, int *orig_arg, struct proxy *px,
struct act_rule *rule, char **err)
{
int cur_arg;
cur_arg = *orig_arg;
if (!*args[cur_arg]) {
memprintf(err, "expects exactly 1 arguments");
return ACT_RET_PRS_ERR;
}
if (strcasecmp(args[cur_arg], "on") == 0)
rule->action = 0; // strict-mode on
else if (strcasecmp(args[cur_arg], "off") == 0)
rule->action = 1; // strict-mode off
else {
memprintf(err, "Unexpected value '%s'. Only 'on' and 'off' are supported", args[cur_arg]);
return ACT_RET_PRS_ERR;
}
rule->action_ptr = http_action_strict_mode;
*orig_arg = cur_arg + 1;
return ACT_RET_PRS_OK;
}
/* This function executes a return action. It builds an HTX message from an
* errorfile, an raw file or a log-format string, depending on <.action>
* value. On success, it returns ACT_RET_ABRT. If an error occurs ACT_RET_ERR is
* returned.
*/
static enum act_return http_action_return(struct act_rule *rule, struct proxy *px,
struct session *sess, struct stream *s, int flags)
{
struct channel *req = &s->req;
s->txn->status = rule->arg.http_reply->status;
if (!(s->flags & SF_ERR_MASK))
s->flags |= SF_ERR_LOCAL;
if (!(s->flags & SF_FINST_MASK))
s->flags |= ((rule->from == ACT_F_HTTP_REQ) ? SF_FINST_R : SF_FINST_H);
if (http_reply_message(s, rule->arg.http_reply) == -1)
return ACT_RET_ERR;
if (rule->from == ACT_F_HTTP_REQ) {
/* let's log the request time */
MEDIUM: clock: replace timeval "now" with integer "now_ns" This puts an end to the occasional confusion between the "now" date that is internal, monotonic and not synchronized with the system's date, and "date" which is the system's date and not necessarily monotonic. Variable "now" was removed and replaced with a 64-bit integer "now_ns" which is a counter of nanoseconds. It wraps every 585 years, so if all goes well (i.e. if humanity does not need haproxy anymore in 500 years), it will just never wrap. This implies that now_ns is never nul and that the zero value can reliably be used as "not set yet" for a timestamp if needed. This will also simplify date checks where it becomes possible again to do "date1<date2". All occurrences of "tv_to_ns(&now)" were simply replaced by "now_ns". Due to the intricacies between now, global_now and now_offset, all 3 had to be turned to nanoseconds at once. It's not a problem since all of them were solely used in 3 functions in clock.c, but they make the patch look bigger than it really is. The clock_update_local_date() and clock_update_global_date() functions are now much simpler as there's no need anymore to perform conversions nor to round the timeval up or down. The wrapping continues to happen by presetting the internal offset in the short future so that the 32-bit now_ms continues to wrap 20 seconds after boot. The start_time used to calculate uptime can still be turned to nanoseconds now. One interrogation concerns global_now_ms which is used only for the freq counters. It's unclear whether there's more value in using two variables that need to be synchronized sequentially like today or to just use global_now_ns divided by 1 million. Both approaches will work equally well on modern systems, the difference might come from smaller ones. Better not change anyhting for now. One benefit of the new approach is that we now have an internal date with a resolution of the nanosecond and the precision of the microsecond, which can be useful to extend some measurements given that timestamps also have this resolution.
2023-04-28 03:16:15 -04:00
s->logs.request_ts = now_ns;
req->analysers &= AN_REQ_FLT_END;
if (s->sess->fe == s->be) /* report it if the request was intercepted by the frontend */
_HA_ATOMIC_INC(&s->sess->fe->fe_counters.intercepted_req);
}
return ACT_RET_ABRT;
}
/* Parse a "return" action. It returns ACT_RET_PRS_OK on success,
* ACT_RET_PRS_ERR on error. It relies on http_parse_http_reply() to set
* <.arg.http_reply>.
*/
static enum act_parse_ret parse_http_return(const char **args, int *orig_arg, struct proxy *px,
struct act_rule *rule, char **err)
{
/* Prepare parsing of log-format strings */
px->conf.args.ctx = ((rule->from == ACT_F_HTTP_REQ) ? ARGC_HRQ : ARGC_HRS);
rule->arg.http_reply = http_parse_http_reply(args, orig_arg, px, 200, err);
if (!rule->arg.http_reply)
return ACT_RET_PRS_ERR;
rule->flags |= ACT_FLAG_FINAL;
rule->action = ACT_CUSTOM;
rule->check_ptr = check_act_http_reply;
rule->action_ptr = http_action_return;
rule->release_ptr = release_act_http_reply;
return ACT_RET_PRS_OK;
}
/* This function executes a wait-for-body action. It waits for the message
* payload for a max configured time (.arg.p[0]) and eventually for only first
* <arg.p[1]> bytes (0 means no limit). It relies on http_wait_for_msg_body()
* function. it returns ACT_RET_CONT when conditions are met to stop to wait.
* Otherwise ACT_RET_YIELD is returned to wait for more data. ACT_RET_INV is
* returned if a parsing error is raised by lower level and ACT_RET_ERR if an
* internal error occurred. Finally ACT_RET_ABRT is returned when a timeout
* occurred.
*/
static enum act_return http_action_wait_for_body(struct act_rule *rule, struct proxy *px,
struct session *sess, struct stream *s, int flags)
{
struct channel *chn = ((rule->from == ACT_F_HTTP_REQ) ? &s->req : &s->res);
unsigned int time = (uintptr_t)rule->arg.act.p[0];
unsigned int bytes = (uintptr_t)rule->arg.act.p[1];
switch (http_wait_for_msg_body(s, chn, time, bytes)) {
case HTTP_RULE_RES_CONT:
return ACT_RET_CONT;
case HTTP_RULE_RES_YIELD:
return ACT_RET_YIELD;
case HTTP_RULE_RES_BADREQ:
return ACT_RET_INV;
case HTTP_RULE_RES_ERROR:
return ACT_RET_ERR;
case HTTP_RULE_RES_ABRT:
return ACT_RET_ABRT;
default:
return ACT_RET_ERR;
}
}
/* Parse a "wait-for-body" action. It returns ACT_RET_PRS_OK on success,
* ACT_RET_PRS_ERR on error.
*/
static enum act_parse_ret parse_http_wait_for_body(const char **args, int *orig_arg, struct proxy *px,
struct act_rule *rule, char **err)
{
int cur_arg;
unsigned int time, bytes;
const char *res;
cur_arg = *orig_arg;
if (!*args[cur_arg]) {
memprintf(err, "expects time <time> [ at-least <bytes> ]");
return ACT_RET_PRS_ERR;
}
time = UINT_MAX; /* To be sure it is set */
bytes = 0; /* Default value, wait all the body */
while (*(args[cur_arg])) {
if (strcmp(args[cur_arg], "time") == 0) {
if (!*args[cur_arg + 1]) {
memprintf(err, "missing argument for '%s'", args[cur_arg]);
return ACT_RET_PRS_ERR;
}
res = parse_time_err(args[cur_arg+1], &time, TIME_UNIT_MS);
if (res == PARSE_TIME_OVER) {
memprintf(err, "time overflow (maximum value is 2147483647 ms or ~24.8 days)");
return ACT_RET_PRS_ERR;
}
if (res == PARSE_TIME_UNDER) {
memprintf(err, "time underflow (minimum non-null value is 1 ms)");
return ACT_RET_PRS_ERR;
}
if (res) {
memprintf(err, "unexpected character '%c'", *res);
return ACT_RET_PRS_ERR;
}
cur_arg++;
}
else if (strcmp(args[cur_arg], "at-least") == 0) {
if (!*args[cur_arg + 1]) {
memprintf(err, "missing argument for '%s'", args[cur_arg]);
return ACT_RET_PRS_ERR;
}
res = parse_size_err(args[cur_arg+1], &bytes);
if (res) {
memprintf(err, "unexpected character '%c'", *res);
return ACT_RET_PRS_ERR;
}
cur_arg++;
}
else
break;
cur_arg++;
}
if (time == UINT_MAX) {
memprintf(err, "expects time <time> [ at-least <bytes> ]");
return ACT_RET_PRS_ERR;
}
rule->arg.act.p[0] = (void *)(uintptr_t)time;
rule->arg.act.p[1] = (void *)(uintptr_t)bytes;
*orig_arg = cur_arg;
rule->action = ACT_CUSTOM;
rule->action_ptr = http_action_wait_for_body;
return ACT_RET_PRS_OK;
}
MINOR: action: add do-log action Thanks to the two previous commits, we can now expose the do-log action on all available action contexts, including the new quic-init context. Each context is responsible for exposing the do-log action by registering the relevant log steps, saving the idendifier, and then store it in the rule's context so that do_log_action() automatically uses it to produce the log during runtime. To use the feature, it is simply needed to use "do-log" (without argument) on an action directive, example: tcp-request connection do-log As mentioned before, each context where the action is exposed has its own log step identifier. Currently known identifiers are: quic-initial: quic-init tcp-request connection: tcp-req-conn tcp-request session: tcp-req-sess tcp-request content: tcp-req-cont tcp-response content: tcp-res-cont http-request: http-req http-response: http-res http-after-response: http-after-res Thus, these "additional" logging steps can be used as-is under log-profile section (after "on" keyword). However, although the parser will accept them, it makes no sense to use them with the "log-steps" proxy keyword, since the only path for these origins to trigger a log generation is through the explicit use of "do-log" action. This need was described in GH #401, it should help to conditionally trigger logs using ACL at specific key points.. and may either be used alone or combined with "log-steps" to add additional log "trackers" during transaction handling. Documentation was updated and some examples were added.
2024-09-20 03:34:13 -04:00
static enum log_orig_id do_log_http_req;
static enum log_orig_id do_log_http_res;
static enum log_orig_id do_log_http_after_res;
static void init_do_log(void)
{
do_log_http_req = log_orig_register("http-req");
BUG_ON(do_log_http_req == LOG_ORIG_UNSPEC);
do_log_http_res = log_orig_register("http-res");
BUG_ON(do_log_http_res == LOG_ORIG_UNSPEC);
do_log_http_after_res = log_orig_register("http-after-res");
BUG_ON(do_log_http_after_res == LOG_ORIG_UNSPEC);
}
INITCALL0(STG_PREPARE, init_do_log);
static enum act_parse_ret parse_http_req_do_log(const char **args, int *orig_arg, struct proxy *px,
struct act_rule *rule, char **err)
{
return do_log_parse_act(do_log_http_req, args, orig_arg, px, rule, err);
}
static enum act_parse_ret parse_http_res_do_log(const char **args, int *orig_arg, struct proxy *px,
struct act_rule *rule, char **err)
{
return do_log_parse_act(do_log_http_res, args, orig_arg, px, rule, err);
}
static enum act_parse_ret parse_http_after_res_do_log(const char **args, int *orig_arg, struct proxy *px,
struct act_rule *rule, char **err)
{
return do_log_parse_act(do_log_http_after_res, args, orig_arg, px, rule, err);
}
REORG: http: move the code to different files The current proto_http.c file is huge and contains different processing domains making it very difficult to work on an alternative representation. This commit moves some parts to other files : - ACL registration code => http_acl.c This code only creates some ACL mappings and doesn't know anything about HTTP nor about the representation. This code could even have moved to acl.c but it was not worth polluting it again. - HTTP sample conversion => http_conv.c This code doesn't depend on the internal representation but definitely manipulates some HTTP elements, such as dates. It also has access to captures. - HTTP sample fetching => http_fetch.c This code does depend entirely on the internal representation but is totally independent on the analysers. Placing it into a different file will ease the transition to the new representation and the creation of a wrapper if required. An include file was created due to CHECK_HTTP_MESSAGE_FIRST() being used at various places. - HTTP action registration => http_act.c This code doesn't directly interact with the messages nor the transaction but it does so via some exported http functions like http_replace_req_line() or http_set_status() so it will be easier to change only this after the conversion. - a few very generic parts were found and moved to http.{c,h} as relevant. It is worth noting that the functions moved to these new files are not referenced anywhere outside of the files and are only called as registered callbacks, so these files do not even require associated include files.
2018-10-02 10:01:16 -04:00
/************************************************************************/
/* All supported http-request action keywords must be declared here. */
/************************************************************************/
static struct action_kw_list http_req_actions = {
.kw = {
{ "add-acl", parse_http_set_map, KWF_MATCH_PREFIX },
{ "add-header", parse_http_set_header, 0 },
{ "allow", parse_http_allow, 0 },
{ "auth", parse_http_auth, 0 },
{ "capture", parse_http_req_capture, 0 },
{ "del-acl", parse_http_set_map, KWF_MATCH_PREFIX },
{ "del-header", parse_http_del_header, 0 },
{ "del-map", parse_http_set_map, KWF_MATCH_PREFIX },
{ "deny", parse_http_deny, 0 },
{ "disable-l7-retry", parse_http_req_disable_l7_retry, 0 },
MINOR: action: add do-log action Thanks to the two previous commits, we can now expose the do-log action on all available action contexts, including the new quic-init context. Each context is responsible for exposing the do-log action by registering the relevant log steps, saving the idendifier, and then store it in the rule's context so that do_log_action() automatically uses it to produce the log during runtime. To use the feature, it is simply needed to use "do-log" (without argument) on an action directive, example: tcp-request connection do-log As mentioned before, each context where the action is exposed has its own log step identifier. Currently known identifiers are: quic-initial: quic-init tcp-request connection: tcp-req-conn tcp-request session: tcp-req-sess tcp-request content: tcp-req-cont tcp-response content: tcp-res-cont http-request: http-req http-response: http-res http-after-response: http-after-res Thus, these "additional" logging steps can be used as-is under log-profile section (after "on" keyword). However, although the parser will accept them, it makes no sense to use them with the "log-steps" proxy keyword, since the only path for these origins to trigger a log generation is through the explicit use of "do-log" action. This need was described in GH #401, it should help to conditionally trigger logs using ACL at specific key points.. and may either be used alone or combined with "log-steps" to add additional log "trackers" during transaction handling. Documentation was updated and some examples were added.
2024-09-20 03:34:13 -04:00
{ "do-log", parse_http_req_do_log, 0 },
{ "early-hint", parse_http_set_header, 0 },
{ "normalize-uri", parse_http_normalize_uri, KWF_EXPERIMENTAL },
{ "redirect", parse_http_redirect, 0 },
{ "reject", parse_http_action_reject, 0 },
{ "replace-header", parse_http_replace_header, 0 },
{ "replace-path", parse_replace_uri, 0 },
{ "replace-pathq", parse_replace_uri, 0 },
{ "replace-uri", parse_replace_uri, 0 },
{ "replace-value", parse_http_replace_header, 0 },
{ "return", parse_http_return, 0 },
{ "set-header", parse_http_set_header, 0 },
{ "set-map", parse_http_set_map, KWF_MATCH_PREFIX },
{ "set-method", parse_set_req_line, 0 },
{ "set-path", parse_set_req_line, 0 },
{ "set-pathq", parse_set_req_line, 0 },
{ "set-query", parse_set_req_line, 0 },
{ "set-uri", parse_set_req_line, 0 },
{ "strict-mode", parse_http_strict_mode, 0 },
{ "tarpit", parse_http_deny, 0 },
{ "track-sc", parse_http_track_sc, KWF_MATCH_PREFIX },
{ "set-timeout", parse_http_set_timeout, 0 },
{ "wait-for-body", parse_http_wait_for_body, 0 },
REORG: http: move the code to different files The current proto_http.c file is huge and contains different processing domains making it very difficult to work on an alternative representation. This commit moves some parts to other files : - ACL registration code => http_acl.c This code only creates some ACL mappings and doesn't know anything about HTTP nor about the representation. This code could even have moved to acl.c but it was not worth polluting it again. - HTTP sample conversion => http_conv.c This code doesn't depend on the internal representation but definitely manipulates some HTTP elements, such as dates. It also has access to captures. - HTTP sample fetching => http_fetch.c This code does depend entirely on the internal representation but is totally independent on the analysers. Placing it into a different file will ease the transition to the new representation and the creation of a wrapper if required. An include file was created due to CHECK_HTTP_MESSAGE_FIRST() being used at various places. - HTTP action registration => http_act.c This code doesn't directly interact with the messages nor the transaction but it does so via some exported http functions like http_replace_req_line() or http_set_status() so it will be easier to change only this after the conversion. - a few very generic parts were found and moved to http.{c,h} as relevant. It is worth noting that the functions moved to these new files are not referenced anywhere outside of the files and are only called as registered callbacks, so these files do not even require associated include files.
2018-10-02 10:01:16 -04:00
{ NULL, NULL }
}
};
INITCALL1(STG_REGISTER, http_req_keywords_register, &http_req_actions);
REORG: http: move the code to different files The current proto_http.c file is huge and contains different processing domains making it very difficult to work on an alternative representation. This commit moves some parts to other files : - ACL registration code => http_acl.c This code only creates some ACL mappings and doesn't know anything about HTTP nor about the representation. This code could even have moved to acl.c but it was not worth polluting it again. - HTTP sample conversion => http_conv.c This code doesn't depend on the internal representation but definitely manipulates some HTTP elements, such as dates. It also has access to captures. - HTTP sample fetching => http_fetch.c This code does depend entirely on the internal representation but is totally independent on the analysers. Placing it into a different file will ease the transition to the new representation and the creation of a wrapper if required. An include file was created due to CHECK_HTTP_MESSAGE_FIRST() being used at various places. - HTTP action registration => http_act.c This code doesn't directly interact with the messages nor the transaction but it does so via some exported http functions like http_replace_req_line() or http_set_status() so it will be easier to change only this after the conversion. - a few very generic parts were found and moved to http.{c,h} as relevant. It is worth noting that the functions moved to these new files are not referenced anywhere outside of the files and are only called as registered callbacks, so these files do not even require associated include files.
2018-10-02 10:01:16 -04:00
static struct action_kw_list http_res_actions = {
.kw = {
{ "add-acl", parse_http_set_map, KWF_MATCH_PREFIX },
{ "add-header", parse_http_set_header, 0 },
{ "allow", parse_http_allow, 0 },
{ "capture", parse_http_res_capture, 0 },
{ "del-acl", parse_http_set_map, KWF_MATCH_PREFIX },
{ "del-header", parse_http_del_header, 0 },
{ "del-map", parse_http_set_map, KWF_MATCH_PREFIX },
{ "deny", parse_http_deny, 0 },
MINOR: action: add do-log action Thanks to the two previous commits, we can now expose the do-log action on all available action contexts, including the new quic-init context. Each context is responsible for exposing the do-log action by registering the relevant log steps, saving the idendifier, and then store it in the rule's context so that do_log_action() automatically uses it to produce the log during runtime. To use the feature, it is simply needed to use "do-log" (without argument) on an action directive, example: tcp-request connection do-log As mentioned before, each context where the action is exposed has its own log step identifier. Currently known identifiers are: quic-initial: quic-init tcp-request connection: tcp-req-conn tcp-request session: tcp-req-sess tcp-request content: tcp-req-cont tcp-response content: tcp-res-cont http-request: http-req http-response: http-res http-after-response: http-after-res Thus, these "additional" logging steps can be used as-is under log-profile section (after "on" keyword). However, although the parser will accept them, it makes no sense to use them with the "log-steps" proxy keyword, since the only path for these origins to trigger a log generation is through the explicit use of "do-log" action. This need was described in GH #401, it should help to conditionally trigger logs using ACL at specific key points.. and may either be used alone or combined with "log-steps" to add additional log "trackers" during transaction handling. Documentation was updated and some examples were added.
2024-09-20 03:34:13 -04:00
{ "do-log", parse_http_res_do_log, 0 },
{ "redirect", parse_http_redirect, 0 },
{ "replace-header", parse_http_replace_header, 0 },
{ "replace-value", parse_http_replace_header, 0 },
{ "return", parse_http_return, 0 },
{ "set-header", parse_http_set_header, 0 },
{ "set-map", parse_http_set_map, KWF_MATCH_PREFIX },
{ "set-status", parse_http_set_status, 0 },
{ "strict-mode", parse_http_strict_mode, 0 },
{ "track-sc", parse_http_track_sc, KWF_MATCH_PREFIX },
{ "set-timeout", parse_http_set_timeout, 0 },
{ "wait-for-body", parse_http_wait_for_body, 0 },
REORG: http: move the code to different files The current proto_http.c file is huge and contains different processing domains making it very difficult to work on an alternative representation. This commit moves some parts to other files : - ACL registration code => http_acl.c This code only creates some ACL mappings and doesn't know anything about HTTP nor about the representation. This code could even have moved to acl.c but it was not worth polluting it again. - HTTP sample conversion => http_conv.c This code doesn't depend on the internal representation but definitely manipulates some HTTP elements, such as dates. It also has access to captures. - HTTP sample fetching => http_fetch.c This code does depend entirely on the internal representation but is totally independent on the analysers. Placing it into a different file will ease the transition to the new representation and the creation of a wrapper if required. An include file was created due to CHECK_HTTP_MESSAGE_FIRST() being used at various places. - HTTP action registration => http_act.c This code doesn't directly interact with the messages nor the transaction but it does so via some exported http functions like http_replace_req_line() or http_set_status() so it will be easier to change only this after the conversion. - a few very generic parts were found and moved to http.{c,h} as relevant. It is worth noting that the functions moved to these new files are not referenced anywhere outside of the files and are only called as registered callbacks, so these files do not even require associated include files.
2018-10-02 10:01:16 -04:00
{ NULL, NULL }
}
};
INITCALL1(STG_REGISTER, http_res_keywords_register, &http_res_actions);
REORG: http: move the code to different files The current proto_http.c file is huge and contains different processing domains making it very difficult to work on an alternative representation. This commit moves some parts to other files : - ACL registration code => http_acl.c This code only creates some ACL mappings and doesn't know anything about HTTP nor about the representation. This code could even have moved to acl.c but it was not worth polluting it again. - HTTP sample conversion => http_conv.c This code doesn't depend on the internal representation but definitely manipulates some HTTP elements, such as dates. It also has access to captures. - HTTP sample fetching => http_fetch.c This code does depend entirely on the internal representation but is totally independent on the analysers. Placing it into a different file will ease the transition to the new representation and the creation of a wrapper if required. An include file was created due to CHECK_HTTP_MESSAGE_FIRST() being used at various places. - HTTP action registration => http_act.c This code doesn't directly interact with the messages nor the transaction but it does so via some exported http functions like http_replace_req_line() or http_set_status() so it will be easier to change only this after the conversion. - a few very generic parts were found and moved to http.{c,h} as relevant. It is worth noting that the functions moved to these new files are not referenced anywhere outside of the files and are only called as registered callbacks, so these files do not even require associated include files.
2018-10-02 10:01:16 -04:00
static struct action_kw_list http_after_res_actions = {
.kw = {
{ "add-header", parse_http_set_header, 0 },
{ "allow", parse_http_allow, 0 },
{ "capture", parse_http_res_capture, 0 },
{ "del-acl", parse_http_set_map, KWF_MATCH_PREFIX },
{ "del-header", parse_http_del_header, 0 },
{ "del-map", parse_http_set_map, KWF_MATCH_PREFIX },
MINOR: action: add do-log action Thanks to the two previous commits, we can now expose the do-log action on all available action contexts, including the new quic-init context. Each context is responsible for exposing the do-log action by registering the relevant log steps, saving the idendifier, and then store it in the rule's context so that do_log_action() automatically uses it to produce the log during runtime. To use the feature, it is simply needed to use "do-log" (without argument) on an action directive, example: tcp-request connection do-log As mentioned before, each context where the action is exposed has its own log step identifier. Currently known identifiers are: quic-initial: quic-init tcp-request connection: tcp-req-conn tcp-request session: tcp-req-sess tcp-request content: tcp-req-cont tcp-response content: tcp-res-cont http-request: http-req http-response: http-res http-after-response: http-after-res Thus, these "additional" logging steps can be used as-is under log-profile section (after "on" keyword). However, although the parser will accept them, it makes no sense to use them with the "log-steps" proxy keyword, since the only path for these origins to trigger a log generation is through the explicit use of "do-log" action. This need was described in GH #401, it should help to conditionally trigger logs using ACL at specific key points.. and may either be used alone or combined with "log-steps" to add additional log "trackers" during transaction handling. Documentation was updated and some examples were added.
2024-09-20 03:34:13 -04:00
{ "do-log", parse_http_after_res_do_log, 0 },
{ "replace-header", parse_http_replace_header, 0 },
{ "replace-value", parse_http_replace_header, 0 },
{ "set-header", parse_http_set_header, 0 },
{ "set-map", parse_http_set_map, KWF_MATCH_PREFIX },
{ "set-status", parse_http_set_status, 0 },
{ "strict-mode", parse_http_strict_mode, 0 },
{ NULL, NULL }
}
};
INITCALL1(STG_REGISTER, http_after_res_keywords_register, &http_after_res_actions);
REORG: http: move the code to different files The current proto_http.c file is huge and contains different processing domains making it very difficult to work on an alternative representation. This commit moves some parts to other files : - ACL registration code => http_acl.c This code only creates some ACL mappings and doesn't know anything about HTTP nor about the representation. This code could even have moved to acl.c but it was not worth polluting it again. - HTTP sample conversion => http_conv.c This code doesn't depend on the internal representation but definitely manipulates some HTTP elements, such as dates. It also has access to captures. - HTTP sample fetching => http_fetch.c This code does depend entirely on the internal representation but is totally independent on the analysers. Placing it into a different file will ease the transition to the new representation and the creation of a wrapper if required. An include file was created due to CHECK_HTTP_MESSAGE_FIRST() being used at various places. - HTTP action registration => http_act.c This code doesn't directly interact with the messages nor the transaction but it does so via some exported http functions like http_replace_req_line() or http_set_status() so it will be easier to change only this after the conversion. - a few very generic parts were found and moved to http.{c,h} as relevant. It is worth noting that the functions moved to these new files are not referenced anywhere outside of the files and are only called as registered callbacks, so these files do not even require associated include files.
2018-10-02 10:01:16 -04:00
/*
* Local variables:
* c-indent-level: 8
* c-basic-offset: 8
* End:
*/