2010-01-04 10:16:05 -05:00
|
|
|
/*
|
2012-04-27 15:52:18 -04:00
|
|
|
* Sample management functions.
|
2010-01-04 10:16:05 -05:00
|
|
|
*
|
|
|
|
|
* Copyright 2009-2010 EXCELIANCE, Emeric Brun <ebrun@exceliance.fr>
|
2012-04-27 15:52:18 -04:00
|
|
|
* Copyright (C) 2012 Willy Tarreau <w@1wt.eu>
|
2010-01-04 10:16:05 -05:00
|
|
|
*
|
|
|
|
|
* 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.
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
|
MINOR: sample: add "json" converter
This converter escapes string to use it as json/ascii escaped string.
It can read UTF-8 with differents behavior on errors and encode it in
json/ascii.
json([<input-code>])
Escapes the input string and produces an ASCII ouput string ready to use as a
JSON string. The converter tries to decode the input string according to the
<input-code> parameter. It can be "ascii", "utf8", "utf8s", "utf8"" or
"utf8ps". The "ascii" decoder never fails. The "utf8" decoder detects 3 types
of errors:
- bad UTF-8 sequence (lone continuation byte, bad number of continuation
bytes, ...)
- invalid range (the decoded value is within a UTF-8 prohibited range),
- code overlong (the value is encoded with more bytes than necessary).
The UTF-8 JSON encoding can produce a "too long value" error when the UTF-8
character is greater than 0xffff because the JSON string escape specification
only authorizes 4 hex digits for the value encoding. The UTF-8 decoder exists
in 4 variants designated by a combination of two suffix letters : "p" for
"permissive" and "s" for "silently ignore". The behaviors of the decoders
are :
- "ascii" : never fails ;
- "utf8" : fails on any detected errors ;
- "utf8s" : never fails, but removes characters corresponding to errors ;
- "utf8p" : accepts and fixes the overlong errors, but fails on any other
error ;
- "utf8ps" : never fails, accepts and fixes the overlong errors, but removes
characters corresponding to the other errors.
This converter is particularly useful for building properly escaped JSON for
logging to servers which consume JSON-formated traffic logs.
Example:
capture request header user-agent len 150
capture request header Host len 15
log-format {"ip":"%[src]","user-agent":"%[capture.req.hdr(1),json]"}
Input request from client 127.0.0.1:
GET / HTTP/1.0
User-Agent: Very "Ugly" UA 1/2
Output log:
{"ip":"127.0.0.1","user-agent":"Very \"Ugly\" UA 1\/2"}
2014-08-12 04:20:47 -04:00
|
|
|
#include <ctype.h>
|
2010-01-04 10:16:05 -05:00
|
|
|
#include <string.h>
|
|
|
|
|
#include <arpa/inet.h>
|
2012-09-02 16:34:23 -04:00
|
|
|
#include <stdio.h>
|
2010-01-04 10:16:05 -05:00
|
|
|
|
2012-10-29 15:44:36 -04:00
|
|
|
#include <types/global.h>
|
|
|
|
|
|
2012-08-24 13:22:53 -04:00
|
|
|
#include <common/chunk.h>
|
2014-07-15 14:15:37 -04:00
|
|
|
#include <common/hash.h>
|
2018-09-10 09:38:55 -04:00
|
|
|
#include <common/http.h>
|
2018-11-25 13:14:37 -05:00
|
|
|
#include <common/initcall.h>
|
2020-02-25 03:43:22 -05:00
|
|
|
#include <common/net_helper.h>
|
2012-04-27 15:52:18 -04:00
|
|
|
#include <common/standard.h>
|
MAJOR: sample: maintain a per-proxy list of the fetch args to resolve
While ACL args were resolved after all the config was parsed, it was not the
case with sample fetch args because they're almost everywhere now.
The issue is that ACLs now solely rely on sample fetches, so their args
resolving doesn't work anymore. And many fetches involving a server, a
proxy or a userlist don't work at all.
The real issue is that at the bottom layers we have no information about
proxies, line numbers, even ACLs in order to report understandable errors,
and that at the top layers we have no visibility over the locations where
fetches are referenced (think log node).
After failing multiple unsatisfying solutions attempts, we now have a new
concept of args list. The principle is that every proxy has a list head
which contains a number of indications such as the config keyword, the
context where it's used, the file and line number, etc... and a list of
arguments. This list head is of the same type as the elements, so it
serves as a template for adding new elements. This way, it is filled from
top to bottom by the callers with the information they have (eg: line
numbers, ACL name, ...) and the lower layers just have to duplicate it and
add an element when they face an argument they cannot resolve yet.
Then at the end of the configuration parsing, a loop passes over each
proxy's list and resolves all the args in sequence. And this way there is
all necessary information to report verbose errors.
The first immediate benefit is that for the first time we got very precise
location of issues (arg number in a keyword in its context, ...). Second,
in order to do this we had to parse log-format and unique-id-format a bit
earlier, so that was a great opportunity for doing so when the directives
are encountered (unless it's a default section). This way, the recorded
line numbers for these args are the ones of the place where the log format
is declared, not the end of the file.
Userlists report slightly more information now. They're the only remaining
ones in the ACL resolving function.
2013-04-02 10:34:32 -04:00
|
|
|
#include <common/uri_auth.h>
|
2014-04-30 12:21:37 -04:00
|
|
|
#include <common/base64.h>
|
2012-04-27 15:52:18 -04:00
|
|
|
|
2012-04-20 08:45:49 -04:00
|
|
|
#include <proto/arg.h>
|
MAJOR: sample: maintain a per-proxy list of the fetch args to resolve
While ACL args were resolved after all the config was parsed, it was not the
case with sample fetch args because they're almost everywhere now.
The issue is that ACLs now solely rely on sample fetches, so their args
resolving doesn't work anymore. And many fetches involving a server, a
proxy or a userlist don't work at all.
The real issue is that at the bottom layers we have no information about
proxies, line numbers, even ACLs in order to report understandable errors,
and that at the top layers we have no visibility over the locations where
fetches are referenced (think log node).
After failing multiple unsatisfying solutions attempts, we now have a new
concept of args list. The principle is that every proxy has a list head
which contains a number of indications such as the config keyword, the
context where it's used, the file and line number, etc... and a list of
arguments. This list head is of the same type as the elements, so it
serves as a template for adding new elements. This way, it is filled from
top to bottom by the callers with the information they have (eg: line
numbers, ACL name, ...) and the lower layers just have to duplicate it and
add an element when they face an argument they cannot resolve yet.
Then at the end of the configuration parsing, a loop passes over each
proxy's list and resolves all the args in sequence. And this way there is
all necessary information to report verbose errors.
The first immediate benefit is that for the first time we got very precise
location of issues (arg number in a keyword in its context, ...). Second,
in order to do this we had to parse log-format and unique-id-format a bit
earlier, so that was a great opportunity for doing so when the directives
are encountered (unless it's a default section). This way, the recorded
line numbers for these args are the ones of the place where the log format
is declared, not the end of the file.
Userlists report slightly more information now. They're the only remaining
ones in the ACL resolving function.
2013-04-02 10:34:32 -04:00
|
|
|
#include <proto/auth.h>
|
|
|
|
|
#include <proto/log.h>
|
|
|
|
|
#include <proto/proxy.h>
|
2019-02-26 08:09:08 -05:00
|
|
|
#include <proto/protocol_buffers.h>
|
2012-04-27 15:52:18 -04:00
|
|
|
#include <proto/sample.h>
|
2019-12-17 04:07:25 -05:00
|
|
|
#include <proto/sink.h>
|
MAJOR: sample: maintain a per-proxy list of the fetch args to resolve
While ACL args were resolved after all the config was parsed, it was not the
case with sample fetch args because they're almost everywhere now.
The issue is that ACLs now solely rely on sample fetches, so their args
resolving doesn't work anymore. And many fetches involving a server, a
proxy or a userlist don't work at all.
The real issue is that at the bottom layers we have no information about
proxies, line numbers, even ACLs in order to report understandable errors,
and that at the top layers we have no visibility over the locations where
fetches are referenced (think log node).
After failing multiple unsatisfying solutions attempts, we now have a new
concept of args list. The principle is that every proxy has a list head
which contains a number of indications such as the config keyword, the
context where it's used, the file and line number, etc... and a list of
arguments. This list head is of the same type as the elements, so it
serves as a template for adding new elements. This way, it is filled from
top to bottom by the callers with the information they have (eg: line
numbers, ACL name, ...) and the lower layers just have to duplicate it and
add an element when they face an argument they cannot resolve yet.
Then at the end of the configuration parsing, a loop passes over each
proxy's list and resolves all the args in sequence. And this way there is
all necessary information to report verbose errors.
The first immediate benefit is that for the first time we got very precise
location of issues (arg number in a keyword in its context, ...). Second,
in order to do this we had to parse log-format and unique-id-format a bit
earlier, so that was a great opportunity for doing so when the directives
are encountered (unless it's a default section). This way, the recorded
line numbers for these args are the ones of the place where the log format
is declared, not the end of the file.
Userlists report slightly more information now. They're the only remaining
ones in the ACL resolving function.
2013-04-02 10:34:32 -04:00
|
|
|
#include <proto/stick_table.h>
|
2015-07-07 15:10:16 -04:00
|
|
|
#include <proto/vars.h>
|
2010-01-04 10:16:05 -05:00
|
|
|
|
2017-10-24 03:18:23 -04:00
|
|
|
#include <import/sha1.h>
|
2016-12-26 05:46:11 -05:00
|
|
|
#include <import/xxhash.h>
|
|
|
|
|
|
2014-02-07 06:14:54 -05:00
|
|
|
/* sample type names */
|
|
|
|
|
const char *smp_to_type[SMP_TYPES] = {
|
2015-06-03 14:12:35 -04:00
|
|
|
[SMP_T_ANY] = "any",
|
2014-02-07 06:14:54 -05:00
|
|
|
[SMP_T_BOOL] = "bool",
|
|
|
|
|
[SMP_T_SINT] = "sint",
|
|
|
|
|
[SMP_T_ADDR] = "addr",
|
|
|
|
|
[SMP_T_IPV4] = "ipv4",
|
|
|
|
|
[SMP_T_IPV6] = "ipv6",
|
|
|
|
|
[SMP_T_STR] = "str",
|
|
|
|
|
[SMP_T_BIN] = "bin",
|
2015-06-03 14:12:04 -04:00
|
|
|
[SMP_T_METH] = "meth",
|
2014-02-07 06:14:54 -05:00
|
|
|
};
|
|
|
|
|
|
2012-04-27 15:37:17 -04:00
|
|
|
/* static sample used in sample_process() when <p> is NULL */
|
2017-06-14 08:15:36 -04:00
|
|
|
static THREAD_LOCAL struct sample temp_smp;
|
2010-01-04 10:16:05 -05:00
|
|
|
|
2012-04-27 15:37:17 -04:00
|
|
|
/* list head of all known sample fetch keywords */
|
|
|
|
|
static struct sample_fetch_kw_list sample_fetches = {
|
|
|
|
|
.list = LIST_HEAD_INIT(sample_fetches.list)
|
2010-01-04 10:16:05 -05:00
|
|
|
};
|
|
|
|
|
|
2012-04-27 15:37:17 -04:00
|
|
|
/* list head of all known sample format conversion keywords */
|
|
|
|
|
static struct sample_conv_kw_list sample_convs = {
|
|
|
|
|
.list = LIST_HEAD_INIT(sample_convs.list)
|
2010-01-04 10:16:05 -05:00
|
|
|
};
|
|
|
|
|
|
MEDIUM: samples: use new flags to describe compatibility between fetches and their usages
Samples fetches were relying on two flags SMP_CAP_REQ/SMP_CAP_RES to describe
whether they were compatible with requests rules or with response rules. This
was never reliable because we need a finer granularity (eg: an HTTP request
method needs to parse an HTTP request, and is available past this point).
Some fetches are also dependant on the context (eg: "hdr" uses request or
response depending where it's involved, causing some abiguity).
In order to solve this, we need to precisely indicate in fetches what they
use, and their users will have to compare with what they have.
So now we have a bunch of bits indicating where the sample is fetched in the
processing chain, with a few variants indicating for some of them if it is
permanent or volatile (eg: an HTTP status is stored into the transaction so
it is permanent, despite being caught in the response contents).
The fetches also have a second mask indicating their validity domain. This one
is computed from a conversion table at registration time, so there is no need
for doing it by hand. This validity domain consists in a bitmask with one bit
set for each usage point in the processing chain. Some provisions were made
for upcoming controls such as connection-based TCP rules which apply on top of
the connection layer but before instantiating the session.
Then everywhere a fetch is used, the bit for the control point is checked in
the fetch's validity domain, and it becomes possible to finely ensure that a
fetch will work or not.
Note that we need these two separate bitfields because some fetches are usable
both in request and response (eg: "hdr", "payload"). So the keyword will have
a "use" field made of a combination of several SMP_USE_* values, which will be
converted into a wider list of SMP_VAL_* flags.
The knowledge of permanent vs dynamic information has disappeared for now, as
it was never used. Later we'll probably reintroduce it differently when
dealing with variables. Its only use at the moment could have been to avoid
caching a dynamic rate measurement, but nothing is cached as of now.
2013-01-07 09:42:20 -05:00
|
|
|
const unsigned int fetch_cap[SMP_SRC_ENTRIES] = {
|
|
|
|
|
[SMP_SRC_INTRN] = (SMP_VAL_FE_CON_ACC | SMP_VAL_FE_SES_ACC | SMP_VAL_FE_REQ_CNT |
|
|
|
|
|
SMP_VAL_FE_HRQ_HDR | SMP_VAL_FE_HRQ_BDY | SMP_VAL_FE_SET_BCK |
|
|
|
|
|
SMP_VAL_BE_REQ_CNT | SMP_VAL_BE_HRQ_HDR | SMP_VAL_BE_HRQ_BDY |
|
|
|
|
|
SMP_VAL_BE_SET_SRV | SMP_VAL_BE_SRV_CON | SMP_VAL_BE_RES_CNT |
|
|
|
|
|
SMP_VAL_BE_HRS_HDR | SMP_VAL_BE_HRS_BDY | SMP_VAL_BE_STO_RUL |
|
|
|
|
|
SMP_VAL_FE_RES_CNT | SMP_VAL_FE_HRS_HDR | SMP_VAL_FE_HRS_BDY |
|
2020-02-21 12:14:59 -05:00
|
|
|
SMP_VAL_FE_LOG_END | SMP_VAL_BE_CHK_RUL),
|
MEDIUM: samples: use new flags to describe compatibility between fetches and their usages
Samples fetches were relying on two flags SMP_CAP_REQ/SMP_CAP_RES to describe
whether they were compatible with requests rules or with response rules. This
was never reliable because we need a finer granularity (eg: an HTTP request
method needs to parse an HTTP request, and is available past this point).
Some fetches are also dependant on the context (eg: "hdr" uses request or
response depending where it's involved, causing some abiguity).
In order to solve this, we need to precisely indicate in fetches what they
use, and their users will have to compare with what they have.
So now we have a bunch of bits indicating where the sample is fetched in the
processing chain, with a few variants indicating for some of them if it is
permanent or volatile (eg: an HTTP status is stored into the transaction so
it is permanent, despite being caught in the response contents).
The fetches also have a second mask indicating their validity domain. This one
is computed from a conversion table at registration time, so there is no need
for doing it by hand. This validity domain consists in a bitmask with one bit
set for each usage point in the processing chain. Some provisions were made
for upcoming controls such as connection-based TCP rules which apply on top of
the connection layer but before instantiating the session.
Then everywhere a fetch is used, the bit for the control point is checked in
the fetch's validity domain, and it becomes possible to finely ensure that a
fetch will work or not.
Note that we need these two separate bitfields because some fetches are usable
both in request and response (eg: "hdr", "payload"). So the keyword will have
a "use" field made of a combination of several SMP_USE_* values, which will be
converted into a wider list of SMP_VAL_* flags.
The knowledge of permanent vs dynamic information has disappeared for now, as
it was never used. Later we'll probably reintroduce it differently when
dealing with variables. Its only use at the moment could have been to avoid
caching a dynamic rate measurement, but nothing is cached as of now.
2013-01-07 09:42:20 -05:00
|
|
|
|
|
|
|
|
[SMP_SRC_LISTN] = (SMP_VAL_FE_CON_ACC | SMP_VAL_FE_SES_ACC | SMP_VAL_FE_REQ_CNT |
|
|
|
|
|
SMP_VAL_FE_HRQ_HDR | SMP_VAL_FE_HRQ_BDY | SMP_VAL_FE_SET_BCK |
|
|
|
|
|
SMP_VAL_BE_REQ_CNT | SMP_VAL_BE_HRQ_HDR | SMP_VAL_BE_HRQ_BDY |
|
|
|
|
|
SMP_VAL_BE_SET_SRV | SMP_VAL_BE_SRV_CON | SMP_VAL_BE_RES_CNT |
|
|
|
|
|
SMP_VAL_BE_HRS_HDR | SMP_VAL_BE_HRS_BDY | SMP_VAL_BE_STO_RUL |
|
|
|
|
|
SMP_VAL_FE_RES_CNT | SMP_VAL_FE_HRS_HDR | SMP_VAL_FE_HRS_BDY |
|
2020-02-21 12:14:59 -05:00
|
|
|
SMP_VAL_FE_LOG_END | SMP_VAL___________),
|
MEDIUM: samples: use new flags to describe compatibility between fetches and their usages
Samples fetches were relying on two flags SMP_CAP_REQ/SMP_CAP_RES to describe
whether they were compatible with requests rules or with response rules. This
was never reliable because we need a finer granularity (eg: an HTTP request
method needs to parse an HTTP request, and is available past this point).
Some fetches are also dependant on the context (eg: "hdr" uses request or
response depending where it's involved, causing some abiguity).
In order to solve this, we need to precisely indicate in fetches what they
use, and their users will have to compare with what they have.
So now we have a bunch of bits indicating where the sample is fetched in the
processing chain, with a few variants indicating for some of them if it is
permanent or volatile (eg: an HTTP status is stored into the transaction so
it is permanent, despite being caught in the response contents).
The fetches also have a second mask indicating their validity domain. This one
is computed from a conversion table at registration time, so there is no need
for doing it by hand. This validity domain consists in a bitmask with one bit
set for each usage point in the processing chain. Some provisions were made
for upcoming controls such as connection-based TCP rules which apply on top of
the connection layer but before instantiating the session.
Then everywhere a fetch is used, the bit for the control point is checked in
the fetch's validity domain, and it becomes possible to finely ensure that a
fetch will work or not.
Note that we need these two separate bitfields because some fetches are usable
both in request and response (eg: "hdr", "payload"). So the keyword will have
a "use" field made of a combination of several SMP_USE_* values, which will be
converted into a wider list of SMP_VAL_* flags.
The knowledge of permanent vs dynamic information has disappeared for now, as
it was never used. Later we'll probably reintroduce it differently when
dealing with variables. Its only use at the moment could have been to avoid
caching a dynamic rate measurement, but nothing is cached as of now.
2013-01-07 09:42:20 -05:00
|
|
|
|
|
|
|
|
[SMP_SRC_FTEND] = (SMP_VAL_FE_CON_ACC | SMP_VAL_FE_SES_ACC | SMP_VAL_FE_REQ_CNT |
|
|
|
|
|
SMP_VAL_FE_HRQ_HDR | SMP_VAL_FE_HRQ_BDY | SMP_VAL_FE_SET_BCK |
|
|
|
|
|
SMP_VAL_BE_REQ_CNT | SMP_VAL_BE_HRQ_HDR | SMP_VAL_BE_HRQ_BDY |
|
|
|
|
|
SMP_VAL_BE_SET_SRV | SMP_VAL_BE_SRV_CON | SMP_VAL_BE_RES_CNT |
|
|
|
|
|
SMP_VAL_BE_HRS_HDR | SMP_VAL_BE_HRS_BDY | SMP_VAL_BE_STO_RUL |
|
|
|
|
|
SMP_VAL_FE_RES_CNT | SMP_VAL_FE_HRS_HDR | SMP_VAL_FE_HRS_BDY |
|
2020-02-21 12:14:59 -05:00
|
|
|
SMP_VAL_FE_LOG_END | SMP_VAL___________),
|
MEDIUM: samples: use new flags to describe compatibility between fetches and their usages
Samples fetches were relying on two flags SMP_CAP_REQ/SMP_CAP_RES to describe
whether they were compatible with requests rules or with response rules. This
was never reliable because we need a finer granularity (eg: an HTTP request
method needs to parse an HTTP request, and is available past this point).
Some fetches are also dependant on the context (eg: "hdr" uses request or
response depending where it's involved, causing some abiguity).
In order to solve this, we need to precisely indicate in fetches what they
use, and their users will have to compare with what they have.
So now we have a bunch of bits indicating where the sample is fetched in the
processing chain, with a few variants indicating for some of them if it is
permanent or volatile (eg: an HTTP status is stored into the transaction so
it is permanent, despite being caught in the response contents).
The fetches also have a second mask indicating their validity domain. This one
is computed from a conversion table at registration time, so there is no need
for doing it by hand. This validity domain consists in a bitmask with one bit
set for each usage point in the processing chain. Some provisions were made
for upcoming controls such as connection-based TCP rules which apply on top of
the connection layer but before instantiating the session.
Then everywhere a fetch is used, the bit for the control point is checked in
the fetch's validity domain, and it becomes possible to finely ensure that a
fetch will work or not.
Note that we need these two separate bitfields because some fetches are usable
both in request and response (eg: "hdr", "payload"). So the keyword will have
a "use" field made of a combination of several SMP_USE_* values, which will be
converted into a wider list of SMP_VAL_* flags.
The knowledge of permanent vs dynamic information has disappeared for now, as
it was never used. Later we'll probably reintroduce it differently when
dealing with variables. Its only use at the moment could have been to avoid
caching a dynamic rate measurement, but nothing is cached as of now.
2013-01-07 09:42:20 -05:00
|
|
|
|
|
|
|
|
[SMP_SRC_L4CLI] = (SMP_VAL_FE_CON_ACC | SMP_VAL_FE_SES_ACC | SMP_VAL_FE_REQ_CNT |
|
|
|
|
|
SMP_VAL_FE_HRQ_HDR | SMP_VAL_FE_HRQ_BDY | SMP_VAL_FE_SET_BCK |
|
|
|
|
|
SMP_VAL_BE_REQ_CNT | SMP_VAL_BE_HRQ_HDR | SMP_VAL_BE_HRQ_BDY |
|
|
|
|
|
SMP_VAL_BE_SET_SRV | SMP_VAL_BE_SRV_CON | SMP_VAL_BE_RES_CNT |
|
|
|
|
|
SMP_VAL_BE_HRS_HDR | SMP_VAL_BE_HRS_BDY | SMP_VAL_BE_STO_RUL |
|
|
|
|
|
SMP_VAL_FE_RES_CNT | SMP_VAL_FE_HRS_HDR | SMP_VAL_FE_HRS_BDY |
|
2020-02-21 12:14:59 -05:00
|
|
|
SMP_VAL_FE_LOG_END | SMP_VAL_BE_CHK_RUL),
|
MEDIUM: samples: use new flags to describe compatibility between fetches and their usages
Samples fetches were relying on two flags SMP_CAP_REQ/SMP_CAP_RES to describe
whether they were compatible with requests rules or with response rules. This
was never reliable because we need a finer granularity (eg: an HTTP request
method needs to parse an HTTP request, and is available past this point).
Some fetches are also dependant on the context (eg: "hdr" uses request or
response depending where it's involved, causing some abiguity).
In order to solve this, we need to precisely indicate in fetches what they
use, and their users will have to compare with what they have.
So now we have a bunch of bits indicating where the sample is fetched in the
processing chain, with a few variants indicating for some of them if it is
permanent or volatile (eg: an HTTP status is stored into the transaction so
it is permanent, despite being caught in the response contents).
The fetches also have a second mask indicating their validity domain. This one
is computed from a conversion table at registration time, so there is no need
for doing it by hand. This validity domain consists in a bitmask with one bit
set for each usage point in the processing chain. Some provisions were made
for upcoming controls such as connection-based TCP rules which apply on top of
the connection layer but before instantiating the session.
Then everywhere a fetch is used, the bit for the control point is checked in
the fetch's validity domain, and it becomes possible to finely ensure that a
fetch will work or not.
Note that we need these two separate bitfields because some fetches are usable
both in request and response (eg: "hdr", "payload"). So the keyword will have
a "use" field made of a combination of several SMP_USE_* values, which will be
converted into a wider list of SMP_VAL_* flags.
The knowledge of permanent vs dynamic information has disappeared for now, as
it was never used. Later we'll probably reintroduce it differently when
dealing with variables. Its only use at the moment could have been to avoid
caching a dynamic rate measurement, but nothing is cached as of now.
2013-01-07 09:42:20 -05:00
|
|
|
|
|
|
|
|
[SMP_SRC_L5CLI] = (SMP_VAL___________ | SMP_VAL_FE_SES_ACC | SMP_VAL_FE_REQ_CNT |
|
|
|
|
|
SMP_VAL_FE_HRQ_HDR | SMP_VAL_FE_HRQ_BDY | SMP_VAL_FE_SET_BCK |
|
|
|
|
|
SMP_VAL_BE_REQ_CNT | SMP_VAL_BE_HRQ_HDR | SMP_VAL_BE_HRQ_BDY |
|
|
|
|
|
SMP_VAL_BE_SET_SRV | SMP_VAL_BE_SRV_CON | SMP_VAL_BE_RES_CNT |
|
|
|
|
|
SMP_VAL_BE_HRS_HDR | SMP_VAL_BE_HRS_BDY | SMP_VAL_BE_STO_RUL |
|
|
|
|
|
SMP_VAL_FE_RES_CNT | SMP_VAL_FE_HRS_HDR | SMP_VAL_FE_HRS_BDY |
|
2020-02-21 12:14:59 -05:00
|
|
|
SMP_VAL_FE_LOG_END | SMP_VAL___________),
|
MEDIUM: samples: use new flags to describe compatibility between fetches and their usages
Samples fetches were relying on two flags SMP_CAP_REQ/SMP_CAP_RES to describe
whether they were compatible with requests rules or with response rules. This
was never reliable because we need a finer granularity (eg: an HTTP request
method needs to parse an HTTP request, and is available past this point).
Some fetches are also dependant on the context (eg: "hdr" uses request or
response depending where it's involved, causing some abiguity).
In order to solve this, we need to precisely indicate in fetches what they
use, and their users will have to compare with what they have.
So now we have a bunch of bits indicating where the sample is fetched in the
processing chain, with a few variants indicating for some of them if it is
permanent or volatile (eg: an HTTP status is stored into the transaction so
it is permanent, despite being caught in the response contents).
The fetches also have a second mask indicating their validity domain. This one
is computed from a conversion table at registration time, so there is no need
for doing it by hand. This validity domain consists in a bitmask with one bit
set for each usage point in the processing chain. Some provisions were made
for upcoming controls such as connection-based TCP rules which apply on top of
the connection layer but before instantiating the session.
Then everywhere a fetch is used, the bit for the control point is checked in
the fetch's validity domain, and it becomes possible to finely ensure that a
fetch will work or not.
Note that we need these two separate bitfields because some fetches are usable
both in request and response (eg: "hdr", "payload"). So the keyword will have
a "use" field made of a combination of several SMP_USE_* values, which will be
converted into a wider list of SMP_VAL_* flags.
The knowledge of permanent vs dynamic information has disappeared for now, as
it was never used. Later we'll probably reintroduce it differently when
dealing with variables. Its only use at the moment could have been to avoid
caching a dynamic rate measurement, but nothing is cached as of now.
2013-01-07 09:42:20 -05:00
|
|
|
|
|
|
|
|
[SMP_SRC_TRACK] = (SMP_VAL_FE_CON_ACC | SMP_VAL_FE_SES_ACC | SMP_VAL_FE_REQ_CNT |
|
|
|
|
|
SMP_VAL_FE_HRQ_HDR | SMP_VAL_FE_HRQ_BDY | SMP_VAL_FE_SET_BCK |
|
|
|
|
|
SMP_VAL_BE_REQ_CNT | SMP_VAL_BE_HRQ_HDR | SMP_VAL_BE_HRQ_BDY |
|
|
|
|
|
SMP_VAL_BE_SET_SRV | SMP_VAL_BE_SRV_CON | SMP_VAL_BE_RES_CNT |
|
|
|
|
|
SMP_VAL_BE_HRS_HDR | SMP_VAL_BE_HRS_BDY | SMP_VAL_BE_STO_RUL |
|
|
|
|
|
SMP_VAL_FE_RES_CNT | SMP_VAL_FE_HRS_HDR | SMP_VAL_FE_HRS_BDY |
|
2020-02-21 12:14:59 -05:00
|
|
|
SMP_VAL_FE_LOG_END | SMP_VAL___________),
|
MEDIUM: samples: use new flags to describe compatibility between fetches and their usages
Samples fetches were relying on two flags SMP_CAP_REQ/SMP_CAP_RES to describe
whether they were compatible with requests rules or with response rules. This
was never reliable because we need a finer granularity (eg: an HTTP request
method needs to parse an HTTP request, and is available past this point).
Some fetches are also dependant on the context (eg: "hdr" uses request or
response depending where it's involved, causing some abiguity).
In order to solve this, we need to precisely indicate in fetches what they
use, and their users will have to compare with what they have.
So now we have a bunch of bits indicating where the sample is fetched in the
processing chain, with a few variants indicating for some of them if it is
permanent or volatile (eg: an HTTP status is stored into the transaction so
it is permanent, despite being caught in the response contents).
The fetches also have a second mask indicating their validity domain. This one
is computed from a conversion table at registration time, so there is no need
for doing it by hand. This validity domain consists in a bitmask with one bit
set for each usage point in the processing chain. Some provisions were made
for upcoming controls such as connection-based TCP rules which apply on top of
the connection layer but before instantiating the session.
Then everywhere a fetch is used, the bit for the control point is checked in
the fetch's validity domain, and it becomes possible to finely ensure that a
fetch will work or not.
Note that we need these two separate bitfields because some fetches are usable
both in request and response (eg: "hdr", "payload"). So the keyword will have
a "use" field made of a combination of several SMP_USE_* values, which will be
converted into a wider list of SMP_VAL_* flags.
The knowledge of permanent vs dynamic information has disappeared for now, as
it was never used. Later we'll probably reintroduce it differently when
dealing with variables. Its only use at the moment could have been to avoid
caching a dynamic rate measurement, but nothing is cached as of now.
2013-01-07 09:42:20 -05:00
|
|
|
|
|
|
|
|
[SMP_SRC_L6REQ] = (SMP_VAL___________ | SMP_VAL___________ | SMP_VAL_FE_REQ_CNT |
|
|
|
|
|
SMP_VAL_FE_HRQ_HDR | SMP_VAL_FE_HRQ_BDY | SMP_VAL_FE_SET_BCK |
|
|
|
|
|
SMP_VAL_BE_REQ_CNT | SMP_VAL_BE_HRQ_HDR | SMP_VAL_BE_HRQ_BDY |
|
|
|
|
|
SMP_VAL_BE_SET_SRV | SMP_VAL_BE_SRV_CON | SMP_VAL___________ |
|
|
|
|
|
SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
|
|
|
|
|
SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
|
2020-02-21 12:14:59 -05:00
|
|
|
SMP_VAL___________ | SMP_VAL___________),
|
MEDIUM: samples: use new flags to describe compatibility between fetches and their usages
Samples fetches were relying on two flags SMP_CAP_REQ/SMP_CAP_RES to describe
whether they were compatible with requests rules or with response rules. This
was never reliable because we need a finer granularity (eg: an HTTP request
method needs to parse an HTTP request, and is available past this point).
Some fetches are also dependant on the context (eg: "hdr" uses request or
response depending where it's involved, causing some abiguity).
In order to solve this, we need to precisely indicate in fetches what they
use, and their users will have to compare with what they have.
So now we have a bunch of bits indicating where the sample is fetched in the
processing chain, with a few variants indicating for some of them if it is
permanent or volatile (eg: an HTTP status is stored into the transaction so
it is permanent, despite being caught in the response contents).
The fetches also have a second mask indicating their validity domain. This one
is computed from a conversion table at registration time, so there is no need
for doing it by hand. This validity domain consists in a bitmask with one bit
set for each usage point in the processing chain. Some provisions were made
for upcoming controls such as connection-based TCP rules which apply on top of
the connection layer but before instantiating the session.
Then everywhere a fetch is used, the bit for the control point is checked in
the fetch's validity domain, and it becomes possible to finely ensure that a
fetch will work or not.
Note that we need these two separate bitfields because some fetches are usable
both in request and response (eg: "hdr", "payload"). So the keyword will have
a "use" field made of a combination of several SMP_USE_* values, which will be
converted into a wider list of SMP_VAL_* flags.
The knowledge of permanent vs dynamic information has disappeared for now, as
it was never used. Later we'll probably reintroduce it differently when
dealing with variables. Its only use at the moment could have been to avoid
caching a dynamic rate measurement, but nothing is cached as of now.
2013-01-07 09:42:20 -05:00
|
|
|
|
|
|
|
|
[SMP_SRC_HRQHV] = (SMP_VAL___________ | SMP_VAL___________ | SMP_VAL_FE_REQ_CNT |
|
|
|
|
|
SMP_VAL_FE_HRQ_HDR | SMP_VAL_FE_HRQ_BDY | SMP_VAL_FE_SET_BCK |
|
|
|
|
|
SMP_VAL_BE_REQ_CNT | SMP_VAL_BE_HRQ_HDR | SMP_VAL_BE_HRQ_BDY |
|
|
|
|
|
SMP_VAL_BE_SET_SRV | SMP_VAL_BE_SRV_CON | SMP_VAL___________ |
|
|
|
|
|
SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
|
|
|
|
|
SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
|
2020-02-21 12:14:59 -05:00
|
|
|
SMP_VAL___________ | SMP_VAL___________),
|
MEDIUM: samples: use new flags to describe compatibility between fetches and their usages
Samples fetches were relying on two flags SMP_CAP_REQ/SMP_CAP_RES to describe
whether they were compatible with requests rules or with response rules. This
was never reliable because we need a finer granularity (eg: an HTTP request
method needs to parse an HTTP request, and is available past this point).
Some fetches are also dependant on the context (eg: "hdr" uses request or
response depending where it's involved, causing some abiguity).
In order to solve this, we need to precisely indicate in fetches what they
use, and their users will have to compare with what they have.
So now we have a bunch of bits indicating where the sample is fetched in the
processing chain, with a few variants indicating for some of them if it is
permanent or volatile (eg: an HTTP status is stored into the transaction so
it is permanent, despite being caught in the response contents).
The fetches also have a second mask indicating their validity domain. This one
is computed from a conversion table at registration time, so there is no need
for doing it by hand. This validity domain consists in a bitmask with one bit
set for each usage point in the processing chain. Some provisions were made
for upcoming controls such as connection-based TCP rules which apply on top of
the connection layer but before instantiating the session.
Then everywhere a fetch is used, the bit for the control point is checked in
the fetch's validity domain, and it becomes possible to finely ensure that a
fetch will work or not.
Note that we need these two separate bitfields because some fetches are usable
both in request and response (eg: "hdr", "payload"). So the keyword will have
a "use" field made of a combination of several SMP_USE_* values, which will be
converted into a wider list of SMP_VAL_* flags.
The knowledge of permanent vs dynamic information has disappeared for now, as
it was never used. Later we'll probably reintroduce it differently when
dealing with variables. Its only use at the moment could have been to avoid
caching a dynamic rate measurement, but nothing is cached as of now.
2013-01-07 09:42:20 -05:00
|
|
|
|
|
|
|
|
[SMP_SRC_HRQHP] = (SMP_VAL___________ | SMP_VAL___________ | SMP_VAL_FE_REQ_CNT |
|
|
|
|
|
SMP_VAL_FE_HRQ_HDR | SMP_VAL_FE_HRQ_BDY | SMP_VAL_FE_SET_BCK |
|
|
|
|
|
SMP_VAL_BE_REQ_CNT | SMP_VAL_BE_HRQ_HDR | SMP_VAL_BE_HRQ_BDY |
|
|
|
|
|
SMP_VAL_BE_SET_SRV | SMP_VAL_BE_SRV_CON | SMP_VAL_BE_RES_CNT |
|
|
|
|
|
SMP_VAL_BE_HRS_HDR | SMP_VAL_BE_HRS_BDY | SMP_VAL_BE_STO_RUL |
|
|
|
|
|
SMP_VAL_FE_RES_CNT | SMP_VAL_FE_HRS_HDR | SMP_VAL_FE_HRS_BDY |
|
2020-02-21 12:14:59 -05:00
|
|
|
SMP_VAL_FE_LOG_END | SMP_VAL___________),
|
MEDIUM: samples: use new flags to describe compatibility between fetches and their usages
Samples fetches were relying on two flags SMP_CAP_REQ/SMP_CAP_RES to describe
whether they were compatible with requests rules or with response rules. This
was never reliable because we need a finer granularity (eg: an HTTP request
method needs to parse an HTTP request, and is available past this point).
Some fetches are also dependant on the context (eg: "hdr" uses request or
response depending where it's involved, causing some abiguity).
In order to solve this, we need to precisely indicate in fetches what they
use, and their users will have to compare with what they have.
So now we have a bunch of bits indicating where the sample is fetched in the
processing chain, with a few variants indicating for some of them if it is
permanent or volatile (eg: an HTTP status is stored into the transaction so
it is permanent, despite being caught in the response contents).
The fetches also have a second mask indicating their validity domain. This one
is computed from a conversion table at registration time, so there is no need
for doing it by hand. This validity domain consists in a bitmask with one bit
set for each usage point in the processing chain. Some provisions were made
for upcoming controls such as connection-based TCP rules which apply on top of
the connection layer but before instantiating the session.
Then everywhere a fetch is used, the bit for the control point is checked in
the fetch's validity domain, and it becomes possible to finely ensure that a
fetch will work or not.
Note that we need these two separate bitfields because some fetches are usable
both in request and response (eg: "hdr", "payload"). So the keyword will have
a "use" field made of a combination of several SMP_USE_* values, which will be
converted into a wider list of SMP_VAL_* flags.
The knowledge of permanent vs dynamic information has disappeared for now, as
it was never used. Later we'll probably reintroduce it differently when
dealing with variables. Its only use at the moment could have been to avoid
caching a dynamic rate measurement, but nothing is cached as of now.
2013-01-07 09:42:20 -05:00
|
|
|
|
|
|
|
|
[SMP_SRC_HRQBO] = (SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
|
|
|
|
|
SMP_VAL___________ | SMP_VAL_FE_HRQ_BDY | SMP_VAL_FE_SET_BCK |
|
|
|
|
|
SMP_VAL_BE_REQ_CNT | SMP_VAL_BE_HRQ_HDR | SMP_VAL_BE_HRQ_BDY |
|
|
|
|
|
SMP_VAL_BE_SET_SRV | SMP_VAL_BE_SRV_CON | SMP_VAL___________ |
|
|
|
|
|
SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
|
|
|
|
|
SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
|
2020-02-21 12:14:59 -05:00
|
|
|
SMP_VAL___________ | SMP_VAL___________),
|
MEDIUM: samples: use new flags to describe compatibility between fetches and their usages
Samples fetches were relying on two flags SMP_CAP_REQ/SMP_CAP_RES to describe
whether they were compatible with requests rules or with response rules. This
was never reliable because we need a finer granularity (eg: an HTTP request
method needs to parse an HTTP request, and is available past this point).
Some fetches are also dependant on the context (eg: "hdr" uses request or
response depending where it's involved, causing some abiguity).
In order to solve this, we need to precisely indicate in fetches what they
use, and their users will have to compare with what they have.
So now we have a bunch of bits indicating where the sample is fetched in the
processing chain, with a few variants indicating for some of them if it is
permanent or volatile (eg: an HTTP status is stored into the transaction so
it is permanent, despite being caught in the response contents).
The fetches also have a second mask indicating their validity domain. This one
is computed from a conversion table at registration time, so there is no need
for doing it by hand. This validity domain consists in a bitmask with one bit
set for each usage point in the processing chain. Some provisions were made
for upcoming controls such as connection-based TCP rules which apply on top of
the connection layer but before instantiating the session.
Then everywhere a fetch is used, the bit for the control point is checked in
the fetch's validity domain, and it becomes possible to finely ensure that a
fetch will work or not.
Note that we need these two separate bitfields because some fetches are usable
both in request and response (eg: "hdr", "payload"). So the keyword will have
a "use" field made of a combination of several SMP_USE_* values, which will be
converted into a wider list of SMP_VAL_* flags.
The knowledge of permanent vs dynamic information has disappeared for now, as
it was never used. Later we'll probably reintroduce it differently when
dealing with variables. Its only use at the moment could have been to avoid
caching a dynamic rate measurement, but nothing is cached as of now.
2013-01-07 09:42:20 -05:00
|
|
|
|
|
|
|
|
[SMP_SRC_BKEND] = (SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
|
|
|
|
|
SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
|
|
|
|
|
SMP_VAL_BE_REQ_CNT | SMP_VAL_BE_HRQ_HDR | SMP_VAL_BE_HRQ_BDY |
|
|
|
|
|
SMP_VAL_BE_SET_SRV | SMP_VAL_BE_SRV_CON | SMP_VAL_BE_RES_CNT |
|
|
|
|
|
SMP_VAL_BE_HRS_HDR | SMP_VAL_BE_HRS_BDY | SMP_VAL_BE_STO_RUL |
|
|
|
|
|
SMP_VAL_FE_RES_CNT | SMP_VAL_FE_HRS_HDR | SMP_VAL_FE_HRS_BDY |
|
2020-02-21 12:14:59 -05:00
|
|
|
SMP_VAL_FE_LOG_END | SMP_VAL_BE_CHK_RUL),
|
MEDIUM: samples: use new flags to describe compatibility between fetches and their usages
Samples fetches were relying on two flags SMP_CAP_REQ/SMP_CAP_RES to describe
whether they were compatible with requests rules or with response rules. This
was never reliable because we need a finer granularity (eg: an HTTP request
method needs to parse an HTTP request, and is available past this point).
Some fetches are also dependant on the context (eg: "hdr" uses request or
response depending where it's involved, causing some abiguity).
In order to solve this, we need to precisely indicate in fetches what they
use, and their users will have to compare with what they have.
So now we have a bunch of bits indicating where the sample is fetched in the
processing chain, with a few variants indicating for some of them if it is
permanent or volatile (eg: an HTTP status is stored into the transaction so
it is permanent, despite being caught in the response contents).
The fetches also have a second mask indicating their validity domain. This one
is computed from a conversion table at registration time, so there is no need
for doing it by hand. This validity domain consists in a bitmask with one bit
set for each usage point in the processing chain. Some provisions were made
for upcoming controls such as connection-based TCP rules which apply on top of
the connection layer but before instantiating the session.
Then everywhere a fetch is used, the bit for the control point is checked in
the fetch's validity domain, and it becomes possible to finely ensure that a
fetch will work or not.
Note that we need these two separate bitfields because some fetches are usable
both in request and response (eg: "hdr", "payload"). So the keyword will have
a "use" field made of a combination of several SMP_USE_* values, which will be
converted into a wider list of SMP_VAL_* flags.
The knowledge of permanent vs dynamic information has disappeared for now, as
it was never used. Later we'll probably reintroduce it differently when
dealing with variables. Its only use at the moment could have been to avoid
caching a dynamic rate measurement, but nothing is cached as of now.
2013-01-07 09:42:20 -05:00
|
|
|
|
|
|
|
|
[SMP_SRC_SERVR] = (SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
|
|
|
|
|
SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
|
|
|
|
|
SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
|
|
|
|
|
SMP_VAL___________ | SMP_VAL_BE_SRV_CON | SMP_VAL_BE_RES_CNT |
|
|
|
|
|
SMP_VAL_BE_HRS_HDR | SMP_VAL_BE_HRS_BDY | SMP_VAL_BE_STO_RUL |
|
|
|
|
|
SMP_VAL_FE_RES_CNT | SMP_VAL_FE_HRS_HDR | SMP_VAL_FE_HRS_BDY |
|
2020-02-21 12:14:59 -05:00
|
|
|
SMP_VAL_FE_LOG_END | SMP_VAL_BE_CHK_RUL),
|
MEDIUM: samples: use new flags to describe compatibility between fetches and their usages
Samples fetches were relying on two flags SMP_CAP_REQ/SMP_CAP_RES to describe
whether they were compatible with requests rules or with response rules. This
was never reliable because we need a finer granularity (eg: an HTTP request
method needs to parse an HTTP request, and is available past this point).
Some fetches are also dependant on the context (eg: "hdr" uses request or
response depending where it's involved, causing some abiguity).
In order to solve this, we need to precisely indicate in fetches what they
use, and their users will have to compare with what they have.
So now we have a bunch of bits indicating where the sample is fetched in the
processing chain, with a few variants indicating for some of them if it is
permanent or volatile (eg: an HTTP status is stored into the transaction so
it is permanent, despite being caught in the response contents).
The fetches also have a second mask indicating their validity domain. This one
is computed from a conversion table at registration time, so there is no need
for doing it by hand. This validity domain consists in a bitmask with one bit
set for each usage point in the processing chain. Some provisions were made
for upcoming controls such as connection-based TCP rules which apply on top of
the connection layer but before instantiating the session.
Then everywhere a fetch is used, the bit for the control point is checked in
the fetch's validity domain, and it becomes possible to finely ensure that a
fetch will work or not.
Note that we need these two separate bitfields because some fetches are usable
both in request and response (eg: "hdr", "payload"). So the keyword will have
a "use" field made of a combination of several SMP_USE_* values, which will be
converted into a wider list of SMP_VAL_* flags.
The knowledge of permanent vs dynamic information has disappeared for now, as
it was never used. Later we'll probably reintroduce it differently when
dealing with variables. Its only use at the moment could have been to avoid
caching a dynamic rate measurement, but nothing is cached as of now.
2013-01-07 09:42:20 -05:00
|
|
|
|
|
|
|
|
[SMP_SRC_L4SRV] = (SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
|
|
|
|
|
SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
|
|
|
|
|
SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
|
|
|
|
|
SMP_VAL___________ | SMP_VAL___________ | SMP_VAL_BE_RES_CNT |
|
|
|
|
|
SMP_VAL_BE_HRS_HDR | SMP_VAL_BE_HRS_BDY | SMP_VAL_BE_STO_RUL |
|
|
|
|
|
SMP_VAL_FE_RES_CNT | SMP_VAL_FE_HRS_HDR | SMP_VAL_FE_HRS_BDY |
|
2020-02-21 12:14:59 -05:00
|
|
|
SMP_VAL_FE_LOG_END | SMP_VAL_BE_CHK_RUL),
|
MEDIUM: samples: use new flags to describe compatibility between fetches and their usages
Samples fetches were relying on two flags SMP_CAP_REQ/SMP_CAP_RES to describe
whether they were compatible with requests rules or with response rules. This
was never reliable because we need a finer granularity (eg: an HTTP request
method needs to parse an HTTP request, and is available past this point).
Some fetches are also dependant on the context (eg: "hdr" uses request or
response depending where it's involved, causing some abiguity).
In order to solve this, we need to precisely indicate in fetches what they
use, and their users will have to compare with what they have.
So now we have a bunch of bits indicating where the sample is fetched in the
processing chain, with a few variants indicating for some of them if it is
permanent or volatile (eg: an HTTP status is stored into the transaction so
it is permanent, despite being caught in the response contents).
The fetches also have a second mask indicating their validity domain. This one
is computed from a conversion table at registration time, so there is no need
for doing it by hand. This validity domain consists in a bitmask with one bit
set for each usage point in the processing chain. Some provisions were made
for upcoming controls such as connection-based TCP rules which apply on top of
the connection layer but before instantiating the session.
Then everywhere a fetch is used, the bit for the control point is checked in
the fetch's validity domain, and it becomes possible to finely ensure that a
fetch will work or not.
Note that we need these two separate bitfields because some fetches are usable
both in request and response (eg: "hdr", "payload"). So the keyword will have
a "use" field made of a combination of several SMP_USE_* values, which will be
converted into a wider list of SMP_VAL_* flags.
The knowledge of permanent vs dynamic information has disappeared for now, as
it was never used. Later we'll probably reintroduce it differently when
dealing with variables. Its only use at the moment could have been to avoid
caching a dynamic rate measurement, but nothing is cached as of now.
2013-01-07 09:42:20 -05:00
|
|
|
|
|
|
|
|
[SMP_SRC_L5SRV] = (SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
|
|
|
|
|
SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
|
|
|
|
|
SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
|
|
|
|
|
SMP_VAL___________ | SMP_VAL___________ | SMP_VAL_BE_RES_CNT |
|
|
|
|
|
SMP_VAL_BE_HRS_HDR | SMP_VAL_BE_HRS_BDY | SMP_VAL_BE_STO_RUL |
|
|
|
|
|
SMP_VAL_FE_RES_CNT | SMP_VAL_FE_HRS_HDR | SMP_VAL_FE_HRS_BDY |
|
2020-02-21 12:14:59 -05:00
|
|
|
SMP_VAL_FE_LOG_END | SMP_VAL_BE_CHK_RUL),
|
MEDIUM: samples: use new flags to describe compatibility between fetches and their usages
Samples fetches were relying on two flags SMP_CAP_REQ/SMP_CAP_RES to describe
whether they were compatible with requests rules or with response rules. This
was never reliable because we need a finer granularity (eg: an HTTP request
method needs to parse an HTTP request, and is available past this point).
Some fetches are also dependant on the context (eg: "hdr" uses request or
response depending where it's involved, causing some abiguity).
In order to solve this, we need to precisely indicate in fetches what they
use, and their users will have to compare with what they have.
So now we have a bunch of bits indicating where the sample is fetched in the
processing chain, with a few variants indicating for some of them if it is
permanent or volatile (eg: an HTTP status is stored into the transaction so
it is permanent, despite being caught in the response contents).
The fetches also have a second mask indicating their validity domain. This one
is computed from a conversion table at registration time, so there is no need
for doing it by hand. This validity domain consists in a bitmask with one bit
set for each usage point in the processing chain. Some provisions were made
for upcoming controls such as connection-based TCP rules which apply on top of
the connection layer but before instantiating the session.
Then everywhere a fetch is used, the bit for the control point is checked in
the fetch's validity domain, and it becomes possible to finely ensure that a
fetch will work or not.
Note that we need these two separate bitfields because some fetches are usable
both in request and response (eg: "hdr", "payload"). So the keyword will have
a "use" field made of a combination of several SMP_USE_* values, which will be
converted into a wider list of SMP_VAL_* flags.
The knowledge of permanent vs dynamic information has disappeared for now, as
it was never used. Later we'll probably reintroduce it differently when
dealing with variables. Its only use at the moment could have been to avoid
caching a dynamic rate measurement, but nothing is cached as of now.
2013-01-07 09:42:20 -05:00
|
|
|
|
|
|
|
|
[SMP_SRC_L6RES] = (SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
|
|
|
|
|
SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
|
|
|
|
|
SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
|
|
|
|
|
SMP_VAL___________ | SMP_VAL___________ | SMP_VAL_BE_RES_CNT |
|
|
|
|
|
SMP_VAL_BE_HRS_HDR | SMP_VAL_BE_HRS_BDY | SMP_VAL_BE_STO_RUL |
|
|
|
|
|
SMP_VAL_FE_RES_CNT | SMP_VAL_FE_HRS_HDR | SMP_VAL_FE_HRS_BDY |
|
2020-02-21 12:14:59 -05:00
|
|
|
SMP_VAL___________ | SMP_VAL___________),
|
MEDIUM: samples: use new flags to describe compatibility between fetches and their usages
Samples fetches were relying on two flags SMP_CAP_REQ/SMP_CAP_RES to describe
whether they were compatible with requests rules or with response rules. This
was never reliable because we need a finer granularity (eg: an HTTP request
method needs to parse an HTTP request, and is available past this point).
Some fetches are also dependant on the context (eg: "hdr" uses request or
response depending where it's involved, causing some abiguity).
In order to solve this, we need to precisely indicate in fetches what they
use, and their users will have to compare with what they have.
So now we have a bunch of bits indicating where the sample is fetched in the
processing chain, with a few variants indicating for some of them if it is
permanent or volatile (eg: an HTTP status is stored into the transaction so
it is permanent, despite being caught in the response contents).
The fetches also have a second mask indicating their validity domain. This one
is computed from a conversion table at registration time, so there is no need
for doing it by hand. This validity domain consists in a bitmask with one bit
set for each usage point in the processing chain. Some provisions were made
for upcoming controls such as connection-based TCP rules which apply on top of
the connection layer but before instantiating the session.
Then everywhere a fetch is used, the bit for the control point is checked in
the fetch's validity domain, and it becomes possible to finely ensure that a
fetch will work or not.
Note that we need these two separate bitfields because some fetches are usable
both in request and response (eg: "hdr", "payload"). So the keyword will have
a "use" field made of a combination of several SMP_USE_* values, which will be
converted into a wider list of SMP_VAL_* flags.
The knowledge of permanent vs dynamic information has disappeared for now, as
it was never used. Later we'll probably reintroduce it differently when
dealing with variables. Its only use at the moment could have been to avoid
caching a dynamic rate measurement, but nothing is cached as of now.
2013-01-07 09:42:20 -05:00
|
|
|
|
|
|
|
|
[SMP_SRC_HRSHV] = (SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
|
|
|
|
|
SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
|
|
|
|
|
SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
|
|
|
|
|
SMP_VAL___________ | SMP_VAL___________ | SMP_VAL_BE_RES_CNT |
|
|
|
|
|
SMP_VAL_BE_HRS_HDR | SMP_VAL_BE_HRS_BDY | SMP_VAL_BE_STO_RUL |
|
|
|
|
|
SMP_VAL_FE_RES_CNT | SMP_VAL_FE_HRS_HDR | SMP_VAL_FE_HRS_BDY |
|
2020-02-21 12:14:59 -05:00
|
|
|
SMP_VAL___________ | SMP_VAL___________),
|
MEDIUM: samples: use new flags to describe compatibility between fetches and their usages
Samples fetches were relying on two flags SMP_CAP_REQ/SMP_CAP_RES to describe
whether they were compatible with requests rules or with response rules. This
was never reliable because we need a finer granularity (eg: an HTTP request
method needs to parse an HTTP request, and is available past this point).
Some fetches are also dependant on the context (eg: "hdr" uses request or
response depending where it's involved, causing some abiguity).
In order to solve this, we need to precisely indicate in fetches what they
use, and their users will have to compare with what they have.
So now we have a bunch of bits indicating where the sample is fetched in the
processing chain, with a few variants indicating for some of them if it is
permanent or volatile (eg: an HTTP status is stored into the transaction so
it is permanent, despite being caught in the response contents).
The fetches also have a second mask indicating their validity domain. This one
is computed from a conversion table at registration time, so there is no need
for doing it by hand. This validity domain consists in a bitmask with one bit
set for each usage point in the processing chain. Some provisions were made
for upcoming controls such as connection-based TCP rules which apply on top of
the connection layer but before instantiating the session.
Then everywhere a fetch is used, the bit for the control point is checked in
the fetch's validity domain, and it becomes possible to finely ensure that a
fetch will work or not.
Note that we need these two separate bitfields because some fetches are usable
both in request and response (eg: "hdr", "payload"). So the keyword will have
a "use" field made of a combination of several SMP_USE_* values, which will be
converted into a wider list of SMP_VAL_* flags.
The knowledge of permanent vs dynamic information has disappeared for now, as
it was never used. Later we'll probably reintroduce it differently when
dealing with variables. Its only use at the moment could have been to avoid
caching a dynamic rate measurement, but nothing is cached as of now.
2013-01-07 09:42:20 -05:00
|
|
|
|
|
|
|
|
[SMP_SRC_HRSHP] = (SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
|
|
|
|
|
SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
|
|
|
|
|
SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
|
|
|
|
|
SMP_VAL___________ | SMP_VAL___________ | SMP_VAL_BE_RES_CNT |
|
|
|
|
|
SMP_VAL_BE_HRS_HDR | SMP_VAL_BE_HRS_BDY | SMP_VAL_BE_STO_RUL |
|
|
|
|
|
SMP_VAL_FE_RES_CNT | SMP_VAL_FE_HRS_HDR | SMP_VAL_FE_HRS_BDY |
|
2020-02-21 12:14:59 -05:00
|
|
|
SMP_VAL_FE_LOG_END | SMP_VAL___________),
|
MEDIUM: samples: use new flags to describe compatibility between fetches and their usages
Samples fetches were relying on two flags SMP_CAP_REQ/SMP_CAP_RES to describe
whether they were compatible with requests rules or with response rules. This
was never reliable because we need a finer granularity (eg: an HTTP request
method needs to parse an HTTP request, and is available past this point).
Some fetches are also dependant on the context (eg: "hdr" uses request or
response depending where it's involved, causing some abiguity).
In order to solve this, we need to precisely indicate in fetches what they
use, and their users will have to compare with what they have.
So now we have a bunch of bits indicating where the sample is fetched in the
processing chain, with a few variants indicating for some of them if it is
permanent or volatile (eg: an HTTP status is stored into the transaction so
it is permanent, despite being caught in the response contents).
The fetches also have a second mask indicating their validity domain. This one
is computed from a conversion table at registration time, so there is no need
for doing it by hand. This validity domain consists in a bitmask with one bit
set for each usage point in the processing chain. Some provisions were made
for upcoming controls such as connection-based TCP rules which apply on top of
the connection layer but before instantiating the session.
Then everywhere a fetch is used, the bit for the control point is checked in
the fetch's validity domain, and it becomes possible to finely ensure that a
fetch will work or not.
Note that we need these two separate bitfields because some fetches are usable
both in request and response (eg: "hdr", "payload"). So the keyword will have
a "use" field made of a combination of several SMP_USE_* values, which will be
converted into a wider list of SMP_VAL_* flags.
The knowledge of permanent vs dynamic information has disappeared for now, as
it was never used. Later we'll probably reintroduce it differently when
dealing with variables. Its only use at the moment could have been to avoid
caching a dynamic rate measurement, but nothing is cached as of now.
2013-01-07 09:42:20 -05:00
|
|
|
|
|
|
|
|
[SMP_SRC_HRSBO] = (SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
|
|
|
|
|
SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
|
|
|
|
|
SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
|
|
|
|
|
SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
|
|
|
|
|
SMP_VAL___________ | SMP_VAL_BE_HRS_BDY | SMP_VAL_BE_STO_RUL |
|
|
|
|
|
SMP_VAL_FE_RES_CNT | SMP_VAL_FE_HRS_HDR | SMP_VAL_FE_HRS_BDY |
|
2020-02-21 12:14:59 -05:00
|
|
|
SMP_VAL___________ | SMP_VAL___________),
|
MEDIUM: samples: use new flags to describe compatibility between fetches and their usages
Samples fetches were relying on two flags SMP_CAP_REQ/SMP_CAP_RES to describe
whether they were compatible with requests rules or with response rules. This
was never reliable because we need a finer granularity (eg: an HTTP request
method needs to parse an HTTP request, and is available past this point).
Some fetches are also dependant on the context (eg: "hdr" uses request or
response depending where it's involved, causing some abiguity).
In order to solve this, we need to precisely indicate in fetches what they
use, and their users will have to compare with what they have.
So now we have a bunch of bits indicating where the sample is fetched in the
processing chain, with a few variants indicating for some of them if it is
permanent or volatile (eg: an HTTP status is stored into the transaction so
it is permanent, despite being caught in the response contents).
The fetches also have a second mask indicating their validity domain. This one
is computed from a conversion table at registration time, so there is no need
for doing it by hand. This validity domain consists in a bitmask with one bit
set for each usage point in the processing chain. Some provisions were made
for upcoming controls such as connection-based TCP rules which apply on top of
the connection layer but before instantiating the session.
Then everywhere a fetch is used, the bit for the control point is checked in
the fetch's validity domain, and it becomes possible to finely ensure that a
fetch will work or not.
Note that we need these two separate bitfields because some fetches are usable
both in request and response (eg: "hdr", "payload"). So the keyword will have
a "use" field made of a combination of several SMP_USE_* values, which will be
converted into a wider list of SMP_VAL_* flags.
The knowledge of permanent vs dynamic information has disappeared for now, as
it was never used. Later we'll probably reintroduce it differently when
dealing with variables. Its only use at the moment could have been to avoid
caching a dynamic rate measurement, but nothing is cached as of now.
2013-01-07 09:42:20 -05:00
|
|
|
|
|
|
|
|
[SMP_SRC_RQFIN] = (SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
|
|
|
|
|
SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
|
|
|
|
|
SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
|
|
|
|
|
SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
|
|
|
|
|
SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
|
|
|
|
|
SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
|
2020-02-21 12:14:59 -05:00
|
|
|
SMP_VAL_FE_LOG_END | SMP_VAL___________),
|
MEDIUM: samples: use new flags to describe compatibility between fetches and their usages
Samples fetches were relying on two flags SMP_CAP_REQ/SMP_CAP_RES to describe
whether they were compatible with requests rules or with response rules. This
was never reliable because we need a finer granularity (eg: an HTTP request
method needs to parse an HTTP request, and is available past this point).
Some fetches are also dependant on the context (eg: "hdr" uses request or
response depending where it's involved, causing some abiguity).
In order to solve this, we need to precisely indicate in fetches what they
use, and their users will have to compare with what they have.
So now we have a bunch of bits indicating where the sample is fetched in the
processing chain, with a few variants indicating for some of them if it is
permanent or volatile (eg: an HTTP status is stored into the transaction so
it is permanent, despite being caught in the response contents).
The fetches also have a second mask indicating their validity domain. This one
is computed from a conversion table at registration time, so there is no need
for doing it by hand. This validity domain consists in a bitmask with one bit
set for each usage point in the processing chain. Some provisions were made
for upcoming controls such as connection-based TCP rules which apply on top of
the connection layer but before instantiating the session.
Then everywhere a fetch is used, the bit for the control point is checked in
the fetch's validity domain, and it becomes possible to finely ensure that a
fetch will work or not.
Note that we need these two separate bitfields because some fetches are usable
both in request and response (eg: "hdr", "payload"). So the keyword will have
a "use" field made of a combination of several SMP_USE_* values, which will be
converted into a wider list of SMP_VAL_* flags.
The knowledge of permanent vs dynamic information has disappeared for now, as
it was never used. Later we'll probably reintroduce it differently when
dealing with variables. Its only use at the moment could have been to avoid
caching a dynamic rate measurement, but nothing is cached as of now.
2013-01-07 09:42:20 -05:00
|
|
|
|
|
|
|
|
[SMP_SRC_RSFIN] = (SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
|
|
|
|
|
SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
|
|
|
|
|
SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
|
|
|
|
|
SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
|
|
|
|
|
SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
|
|
|
|
|
SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
|
2020-02-21 12:14:59 -05:00
|
|
|
SMP_VAL_FE_LOG_END | SMP_VAL___________),
|
MEDIUM: samples: use new flags to describe compatibility between fetches and their usages
Samples fetches were relying on two flags SMP_CAP_REQ/SMP_CAP_RES to describe
whether they were compatible with requests rules or with response rules. This
was never reliable because we need a finer granularity (eg: an HTTP request
method needs to parse an HTTP request, and is available past this point).
Some fetches are also dependant on the context (eg: "hdr" uses request or
response depending where it's involved, causing some abiguity).
In order to solve this, we need to precisely indicate in fetches what they
use, and their users will have to compare with what they have.
So now we have a bunch of bits indicating where the sample is fetched in the
processing chain, with a few variants indicating for some of them if it is
permanent or volatile (eg: an HTTP status is stored into the transaction so
it is permanent, despite being caught in the response contents).
The fetches also have a second mask indicating their validity domain. This one
is computed from a conversion table at registration time, so there is no need
for doing it by hand. This validity domain consists in a bitmask with one bit
set for each usage point in the processing chain. Some provisions were made
for upcoming controls such as connection-based TCP rules which apply on top of
the connection layer but before instantiating the session.
Then everywhere a fetch is used, the bit for the control point is checked in
the fetch's validity domain, and it becomes possible to finely ensure that a
fetch will work or not.
Note that we need these two separate bitfields because some fetches are usable
both in request and response (eg: "hdr", "payload"). So the keyword will have
a "use" field made of a combination of several SMP_USE_* values, which will be
converted into a wider list of SMP_VAL_* flags.
The knowledge of permanent vs dynamic information has disappeared for now, as
it was never used. Later we'll probably reintroduce it differently when
dealing with variables. Its only use at the moment could have been to avoid
caching a dynamic rate measurement, but nothing is cached as of now.
2013-01-07 09:42:20 -05:00
|
|
|
|
|
|
|
|
[SMP_SRC_TXFIN] = (SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
|
|
|
|
|
SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
|
|
|
|
|
SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
|
|
|
|
|
SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
|
|
|
|
|
SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
|
|
|
|
|
SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
|
2020-02-21 12:14:59 -05:00
|
|
|
SMP_VAL_FE_LOG_END | SMP_VAL___________),
|
MEDIUM: samples: use new flags to describe compatibility between fetches and their usages
Samples fetches were relying on two flags SMP_CAP_REQ/SMP_CAP_RES to describe
whether they were compatible with requests rules or with response rules. This
was never reliable because we need a finer granularity (eg: an HTTP request
method needs to parse an HTTP request, and is available past this point).
Some fetches are also dependant on the context (eg: "hdr" uses request or
response depending where it's involved, causing some abiguity).
In order to solve this, we need to precisely indicate in fetches what they
use, and their users will have to compare with what they have.
So now we have a bunch of bits indicating where the sample is fetched in the
processing chain, with a few variants indicating for some of them if it is
permanent or volatile (eg: an HTTP status is stored into the transaction so
it is permanent, despite being caught in the response contents).
The fetches also have a second mask indicating their validity domain. This one
is computed from a conversion table at registration time, so there is no need
for doing it by hand. This validity domain consists in a bitmask with one bit
set for each usage point in the processing chain. Some provisions were made
for upcoming controls such as connection-based TCP rules which apply on top of
the connection layer but before instantiating the session.
Then everywhere a fetch is used, the bit for the control point is checked in
the fetch's validity domain, and it becomes possible to finely ensure that a
fetch will work or not.
Note that we need these two separate bitfields because some fetches are usable
both in request and response (eg: "hdr", "payload"). So the keyword will have
a "use" field made of a combination of several SMP_USE_* values, which will be
converted into a wider list of SMP_VAL_* flags.
The knowledge of permanent vs dynamic information has disappeared for now, as
it was never used. Later we'll probably reintroduce it differently when
dealing with variables. Its only use at the moment could have been to avoid
caching a dynamic rate measurement, but nothing is cached as of now.
2013-01-07 09:42:20 -05:00
|
|
|
|
|
|
|
|
[SMP_SRC_SSFIN] = (SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
|
|
|
|
|
SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
|
|
|
|
|
SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
|
|
|
|
|
SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
|
|
|
|
|
SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
|
|
|
|
|
SMP_VAL___________ | SMP_VAL___________ | SMP_VAL___________ |
|
2020-02-21 12:14:59 -05:00
|
|
|
SMP_VAL_FE_LOG_END | SMP_VAL___________),
|
MEDIUM: samples: use new flags to describe compatibility between fetches and their usages
Samples fetches were relying on two flags SMP_CAP_REQ/SMP_CAP_RES to describe
whether they were compatible with requests rules or with response rules. This
was never reliable because we need a finer granularity (eg: an HTTP request
method needs to parse an HTTP request, and is available past this point).
Some fetches are also dependant on the context (eg: "hdr" uses request or
response depending where it's involved, causing some abiguity).
In order to solve this, we need to precisely indicate in fetches what they
use, and their users will have to compare with what they have.
So now we have a bunch of bits indicating where the sample is fetched in the
processing chain, with a few variants indicating for some of them if it is
permanent or volatile (eg: an HTTP status is stored into the transaction so
it is permanent, despite being caught in the response contents).
The fetches also have a second mask indicating their validity domain. This one
is computed from a conversion table at registration time, so there is no need
for doing it by hand. This validity domain consists in a bitmask with one bit
set for each usage point in the processing chain. Some provisions were made
for upcoming controls such as connection-based TCP rules which apply on top of
the connection layer but before instantiating the session.
Then everywhere a fetch is used, the bit for the control point is checked in
the fetch's validity domain, and it becomes possible to finely ensure that a
fetch will work or not.
Note that we need these two separate bitfields because some fetches are usable
both in request and response (eg: "hdr", "payload"). So the keyword will have
a "use" field made of a combination of several SMP_USE_* values, which will be
converted into a wider list of SMP_VAL_* flags.
The knowledge of permanent vs dynamic information has disappeared for now, as
it was never used. Later we'll probably reintroduce it differently when
dealing with variables. Its only use at the moment could have been to avoid
caching a dynamic rate measurement, but nothing is cached as of now.
2013-01-07 09:42:20 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const char *fetch_src_names[SMP_SRC_ENTRIES] = {
|
|
|
|
|
[SMP_SRC_INTRN] = "internal state",
|
|
|
|
|
[SMP_SRC_LISTN] = "listener",
|
|
|
|
|
[SMP_SRC_FTEND] = "frontend",
|
|
|
|
|
[SMP_SRC_L4CLI] = "client address",
|
|
|
|
|
[SMP_SRC_L5CLI] = "client-side connection",
|
|
|
|
|
[SMP_SRC_TRACK] = "track counters",
|
|
|
|
|
[SMP_SRC_L6REQ] = "request buffer",
|
|
|
|
|
[SMP_SRC_HRQHV] = "HTTP request headers",
|
|
|
|
|
[SMP_SRC_HRQHP] = "HTTP request",
|
|
|
|
|
[SMP_SRC_HRQBO] = "HTTP request body",
|
|
|
|
|
[SMP_SRC_BKEND] = "backend",
|
|
|
|
|
[SMP_SRC_SERVR] = "server",
|
|
|
|
|
[SMP_SRC_L4SRV] = "server address",
|
|
|
|
|
[SMP_SRC_L5SRV] = "server-side connection",
|
|
|
|
|
[SMP_SRC_L6RES] = "response buffer",
|
|
|
|
|
[SMP_SRC_HRSHV] = "HTTP response headers",
|
|
|
|
|
[SMP_SRC_HRSHP] = "HTTP response",
|
|
|
|
|
[SMP_SRC_HRSBO] = "HTTP response body",
|
|
|
|
|
[SMP_SRC_RQFIN] = "request buffer statistics",
|
|
|
|
|
[SMP_SRC_RSFIN] = "response buffer statistics",
|
|
|
|
|
[SMP_SRC_TXFIN] = "transaction statistics",
|
|
|
|
|
[SMP_SRC_SSFIN] = "session statistics",
|
|
|
|
|
};
|
|
|
|
|
|
2013-03-25 09:52:41 -04:00
|
|
|
static const char *fetch_ckp_names[SMP_CKP_ENTRIES] = {
|
|
|
|
|
[SMP_CKP_FE_CON_ACC] = "frontend tcp-request connection rule",
|
|
|
|
|
[SMP_CKP_FE_SES_ACC] = "frontend tcp-request session rule",
|
|
|
|
|
[SMP_CKP_FE_REQ_CNT] = "frontend tcp-request content rule",
|
|
|
|
|
[SMP_CKP_FE_HRQ_HDR] = "frontend http-request header rule",
|
|
|
|
|
[SMP_CKP_FE_HRQ_BDY] = "frontend http-request body rule",
|
|
|
|
|
[SMP_CKP_FE_SET_BCK] = "frontend use-backend rule",
|
|
|
|
|
[SMP_CKP_BE_REQ_CNT] = "backend tcp-request content rule",
|
|
|
|
|
[SMP_CKP_BE_HRQ_HDR] = "backend http-request header rule",
|
|
|
|
|
[SMP_CKP_BE_HRQ_BDY] = "backend http-request body rule",
|
|
|
|
|
[SMP_CKP_BE_SET_SRV] = "backend use-server, balance or stick-match rule",
|
|
|
|
|
[SMP_CKP_BE_SRV_CON] = "server source selection",
|
|
|
|
|
[SMP_CKP_BE_RES_CNT] = "backend tcp-response content rule",
|
|
|
|
|
[SMP_CKP_BE_HRS_HDR] = "backend http-response header rule",
|
|
|
|
|
[SMP_CKP_BE_HRS_BDY] = "backend http-response body rule",
|
|
|
|
|
[SMP_CKP_BE_STO_RUL] = "backend stick-store rule",
|
|
|
|
|
[SMP_CKP_FE_RES_CNT] = "frontend tcp-response content rule",
|
|
|
|
|
[SMP_CKP_FE_HRS_HDR] = "frontend http-response header rule",
|
|
|
|
|
[SMP_CKP_FE_HRS_BDY] = "frontend http-response body rule",
|
|
|
|
|
[SMP_CKP_FE_LOG_END] = "logs",
|
2020-02-21 12:14:59 -05:00
|
|
|
[SMP_CKP_BE_CHK_RUL] = "backend tcp-check rule",
|
2013-03-25 09:52:41 -04:00
|
|
|
};
|
|
|
|
|
|
2013-11-21 04:50:10 -05:00
|
|
|
/* This function returns the type of the data returned by the sample_expr.
|
|
|
|
|
* It assumes that the <expr> and all of its converters are properly
|
|
|
|
|
* initialized.
|
|
|
|
|
*/
|
|
|
|
|
inline
|
|
|
|
|
int smp_expr_output_type(struct sample_expr *expr)
|
|
|
|
|
{
|
|
|
|
|
struct sample_conv_expr *smp_expr;
|
|
|
|
|
|
|
|
|
|
if (!LIST_ISEMPTY(&expr->conv_exprs)) {
|
|
|
|
|
smp_expr = LIST_PREV(&expr->conv_exprs, struct sample_conv_expr *, list);
|
|
|
|
|
return smp_expr->conv->out_type;
|
|
|
|
|
}
|
|
|
|
|
return expr->fetch->out_type;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
MEDIUM: samples: use new flags to describe compatibility between fetches and their usages
Samples fetches were relying on two flags SMP_CAP_REQ/SMP_CAP_RES to describe
whether they were compatible with requests rules or with response rules. This
was never reliable because we need a finer granularity (eg: an HTTP request
method needs to parse an HTTP request, and is available past this point).
Some fetches are also dependant on the context (eg: "hdr" uses request or
response depending where it's involved, causing some abiguity).
In order to solve this, we need to precisely indicate in fetches what they
use, and their users will have to compare with what they have.
So now we have a bunch of bits indicating where the sample is fetched in the
processing chain, with a few variants indicating for some of them if it is
permanent or volatile (eg: an HTTP status is stored into the transaction so
it is permanent, despite being caught in the response contents).
The fetches also have a second mask indicating their validity domain. This one
is computed from a conversion table at registration time, so there is no need
for doing it by hand. This validity domain consists in a bitmask with one bit
set for each usage point in the processing chain. Some provisions were made
for upcoming controls such as connection-based TCP rules which apply on top of
the connection layer but before instantiating the session.
Then everywhere a fetch is used, the bit for the control point is checked in
the fetch's validity domain, and it becomes possible to finely ensure that a
fetch will work or not.
Note that we need these two separate bitfields because some fetches are usable
both in request and response (eg: "hdr", "payload"). So the keyword will have
a "use" field made of a combination of several SMP_USE_* values, which will be
converted into a wider list of SMP_VAL_* flags.
The knowledge of permanent vs dynamic information has disappeared for now, as
it was never used. Later we'll probably reintroduce it differently when
dealing with variables. Its only use at the moment could have been to avoid
caching a dynamic rate measurement, but nothing is cached as of now.
2013-01-07 09:42:20 -05:00
|
|
|
/* fill the trash with a comma-delimited list of source names for the <use> bit
|
|
|
|
|
* field which must be composed of a non-null set of SMP_USE_* flags. The return
|
|
|
|
|
* value is the pointer to the string in the trash buffer.
|
|
|
|
|
*/
|
|
|
|
|
const char *sample_src_names(unsigned int use)
|
|
|
|
|
{
|
|
|
|
|
int bit;
|
|
|
|
|
|
2018-07-13 04:54:26 -04:00
|
|
|
trash.data = 0;
|
|
|
|
|
trash.area[0] = '\0';
|
MEDIUM: samples: use new flags to describe compatibility between fetches and their usages
Samples fetches were relying on two flags SMP_CAP_REQ/SMP_CAP_RES to describe
whether they were compatible with requests rules or with response rules. This
was never reliable because we need a finer granularity (eg: an HTTP request
method needs to parse an HTTP request, and is available past this point).
Some fetches are also dependant on the context (eg: "hdr" uses request or
response depending where it's involved, causing some abiguity).
In order to solve this, we need to precisely indicate in fetches what they
use, and their users will have to compare with what they have.
So now we have a bunch of bits indicating where the sample is fetched in the
processing chain, with a few variants indicating for some of them if it is
permanent or volatile (eg: an HTTP status is stored into the transaction so
it is permanent, despite being caught in the response contents).
The fetches also have a second mask indicating their validity domain. This one
is computed from a conversion table at registration time, so there is no need
for doing it by hand. This validity domain consists in a bitmask with one bit
set for each usage point in the processing chain. Some provisions were made
for upcoming controls such as connection-based TCP rules which apply on top of
the connection layer but before instantiating the session.
Then everywhere a fetch is used, the bit for the control point is checked in
the fetch's validity domain, and it becomes possible to finely ensure that a
fetch will work or not.
Note that we need these two separate bitfields because some fetches are usable
both in request and response (eg: "hdr", "payload"). So the keyword will have
a "use" field made of a combination of several SMP_USE_* values, which will be
converted into a wider list of SMP_VAL_* flags.
The knowledge of permanent vs dynamic information has disappeared for now, as
it was never used. Later we'll probably reintroduce it differently when
dealing with variables. Its only use at the moment could have been to avoid
caching a dynamic rate measurement, but nothing is cached as of now.
2013-01-07 09:42:20 -05:00
|
|
|
for (bit = 0; bit < SMP_SRC_ENTRIES; bit++) {
|
|
|
|
|
if (!(use & ~((1 << bit) - 1)))
|
|
|
|
|
break; /* no more bits */
|
|
|
|
|
|
|
|
|
|
if (!(use & (1 << bit)))
|
|
|
|
|
continue; /* bit not set */
|
|
|
|
|
|
2018-07-13 04:54:26 -04:00
|
|
|
trash.data += snprintf(trash.area + trash.data,
|
|
|
|
|
trash.size - trash.data, "%s%s",
|
|
|
|
|
(use & ((1 << bit) - 1)) ? "," : "",
|
|
|
|
|
fetch_src_names[bit]);
|
MEDIUM: samples: use new flags to describe compatibility between fetches and their usages
Samples fetches were relying on two flags SMP_CAP_REQ/SMP_CAP_RES to describe
whether they were compatible with requests rules or with response rules. This
was never reliable because we need a finer granularity (eg: an HTTP request
method needs to parse an HTTP request, and is available past this point).
Some fetches are also dependant on the context (eg: "hdr" uses request or
response depending where it's involved, causing some abiguity).
In order to solve this, we need to precisely indicate in fetches what they
use, and their users will have to compare with what they have.
So now we have a bunch of bits indicating where the sample is fetched in the
processing chain, with a few variants indicating for some of them if it is
permanent or volatile (eg: an HTTP status is stored into the transaction so
it is permanent, despite being caught in the response contents).
The fetches also have a second mask indicating their validity domain. This one
is computed from a conversion table at registration time, so there is no need
for doing it by hand. This validity domain consists in a bitmask with one bit
set for each usage point in the processing chain. Some provisions were made
for upcoming controls such as connection-based TCP rules which apply on top of
the connection layer but before instantiating the session.
Then everywhere a fetch is used, the bit for the control point is checked in
the fetch's validity domain, and it becomes possible to finely ensure that a
fetch will work or not.
Note that we need these two separate bitfields because some fetches are usable
both in request and response (eg: "hdr", "payload"). So the keyword will have
a "use" field made of a combination of several SMP_USE_* values, which will be
converted into a wider list of SMP_VAL_* flags.
The knowledge of permanent vs dynamic information has disappeared for now, as
it was never used. Later we'll probably reintroduce it differently when
dealing with variables. Its only use at the moment could have been to avoid
caching a dynamic rate measurement, but nothing is cached as of now.
2013-01-07 09:42:20 -05:00
|
|
|
}
|
2018-07-13 04:54:26 -04:00
|
|
|
return trash.area;
|
MEDIUM: samples: use new flags to describe compatibility between fetches and their usages
Samples fetches were relying on two flags SMP_CAP_REQ/SMP_CAP_RES to describe
whether they were compatible with requests rules or with response rules. This
was never reliable because we need a finer granularity (eg: an HTTP request
method needs to parse an HTTP request, and is available past this point).
Some fetches are also dependant on the context (eg: "hdr" uses request or
response depending where it's involved, causing some abiguity).
In order to solve this, we need to precisely indicate in fetches what they
use, and their users will have to compare with what they have.
So now we have a bunch of bits indicating where the sample is fetched in the
processing chain, with a few variants indicating for some of them if it is
permanent or volatile (eg: an HTTP status is stored into the transaction so
it is permanent, despite being caught in the response contents).
The fetches also have a second mask indicating their validity domain. This one
is computed from a conversion table at registration time, so there is no need
for doing it by hand. This validity domain consists in a bitmask with one bit
set for each usage point in the processing chain. Some provisions were made
for upcoming controls such as connection-based TCP rules which apply on top of
the connection layer but before instantiating the session.
Then everywhere a fetch is used, the bit for the control point is checked in
the fetch's validity domain, and it becomes possible to finely ensure that a
fetch will work or not.
Note that we need these two separate bitfields because some fetches are usable
both in request and response (eg: "hdr", "payload"). So the keyword will have
a "use" field made of a combination of several SMP_USE_* values, which will be
converted into a wider list of SMP_VAL_* flags.
The knowledge of permanent vs dynamic information has disappeared for now, as
it was never used. Later we'll probably reintroduce it differently when
dealing with variables. Its only use at the moment could have been to avoid
caching a dynamic rate measurement, but nothing is cached as of now.
2013-01-07 09:42:20 -05:00
|
|
|
}
|
|
|
|
|
|
2013-03-25 09:52:41 -04:00
|
|
|
/* return a pointer to the correct sample checkpoint name, or "unknown" when
|
|
|
|
|
* the flags are invalid. Only the lowest bit is used, higher bits are ignored
|
|
|
|
|
* if set.
|
|
|
|
|
*/
|
|
|
|
|
const char *sample_ckp_names(unsigned int use)
|
|
|
|
|
{
|
|
|
|
|
int bit;
|
|
|
|
|
|
|
|
|
|
for (bit = 0; bit < SMP_CKP_ENTRIES; bit++)
|
|
|
|
|
if (use & (1 << bit))
|
|
|
|
|
return fetch_ckp_names[bit];
|
|
|
|
|
return "unknown sample check place, please report this bug";
|
|
|
|
|
}
|
|
|
|
|
|
2010-01-04 10:16:05 -05:00
|
|
|
/*
|
MEDIUM: samples: use new flags to describe compatibility between fetches and their usages
Samples fetches were relying on two flags SMP_CAP_REQ/SMP_CAP_RES to describe
whether they were compatible with requests rules or with response rules. This
was never reliable because we need a finer granularity (eg: an HTTP request
method needs to parse an HTTP request, and is available past this point).
Some fetches are also dependant on the context (eg: "hdr" uses request or
response depending where it's involved, causing some abiguity).
In order to solve this, we need to precisely indicate in fetches what they
use, and their users will have to compare with what they have.
So now we have a bunch of bits indicating where the sample is fetched in the
processing chain, with a few variants indicating for some of them if it is
permanent or volatile (eg: an HTTP status is stored into the transaction so
it is permanent, despite being caught in the response contents).
The fetches also have a second mask indicating their validity domain. This one
is computed from a conversion table at registration time, so there is no need
for doing it by hand. This validity domain consists in a bitmask with one bit
set for each usage point in the processing chain. Some provisions were made
for upcoming controls such as connection-based TCP rules which apply on top of
the connection layer but before instantiating the session.
Then everywhere a fetch is used, the bit for the control point is checked in
the fetch's validity domain, and it becomes possible to finely ensure that a
fetch will work or not.
Note that we need these two separate bitfields because some fetches are usable
both in request and response (eg: "hdr", "payload"). So the keyword will have
a "use" field made of a combination of several SMP_USE_* values, which will be
converted into a wider list of SMP_VAL_* flags.
The knowledge of permanent vs dynamic information has disappeared for now, as
it was never used. Later we'll probably reintroduce it differently when
dealing with variables. Its only use at the moment could have been to avoid
caching a dynamic rate measurement, but nothing is cached as of now.
2013-01-07 09:42:20 -05:00
|
|
|
* Registers the sample fetch keyword list <kwl> as a list of valid keywords
|
|
|
|
|
* for next parsing sessions. The fetch keywords capabilities are also computed
|
|
|
|
|
* from their ->use field.
|
2010-01-04 10:16:05 -05:00
|
|
|
*/
|
MEDIUM: samples: use new flags to describe compatibility between fetches and their usages
Samples fetches were relying on two flags SMP_CAP_REQ/SMP_CAP_RES to describe
whether they were compatible with requests rules or with response rules. This
was never reliable because we need a finer granularity (eg: an HTTP request
method needs to parse an HTTP request, and is available past this point).
Some fetches are also dependant on the context (eg: "hdr" uses request or
response depending where it's involved, causing some abiguity).
In order to solve this, we need to precisely indicate in fetches what they
use, and their users will have to compare with what they have.
So now we have a bunch of bits indicating where the sample is fetched in the
processing chain, with a few variants indicating for some of them if it is
permanent or volatile (eg: an HTTP status is stored into the transaction so
it is permanent, despite being caught in the response contents).
The fetches also have a second mask indicating their validity domain. This one
is computed from a conversion table at registration time, so there is no need
for doing it by hand. This validity domain consists in a bitmask with one bit
set for each usage point in the processing chain. Some provisions were made
for upcoming controls such as connection-based TCP rules which apply on top of
the connection layer but before instantiating the session.
Then everywhere a fetch is used, the bit for the control point is checked in
the fetch's validity domain, and it becomes possible to finely ensure that a
fetch will work or not.
Note that we need these two separate bitfields because some fetches are usable
both in request and response (eg: "hdr", "payload"). So the keyword will have
a "use" field made of a combination of several SMP_USE_* values, which will be
converted into a wider list of SMP_VAL_* flags.
The knowledge of permanent vs dynamic information has disappeared for now, as
it was never used. Later we'll probably reintroduce it differently when
dealing with variables. Its only use at the moment could have been to avoid
caching a dynamic rate measurement, but nothing is cached as of now.
2013-01-07 09:42:20 -05:00
|
|
|
void sample_register_fetches(struct sample_fetch_kw_list *kwl)
|
2010-01-04 10:16:05 -05:00
|
|
|
{
|
MEDIUM: samples: use new flags to describe compatibility between fetches and their usages
Samples fetches were relying on two flags SMP_CAP_REQ/SMP_CAP_RES to describe
whether they were compatible with requests rules or with response rules. This
was never reliable because we need a finer granularity (eg: an HTTP request
method needs to parse an HTTP request, and is available past this point).
Some fetches are also dependant on the context (eg: "hdr" uses request or
response depending where it's involved, causing some abiguity).
In order to solve this, we need to precisely indicate in fetches what they
use, and their users will have to compare with what they have.
So now we have a bunch of bits indicating where the sample is fetched in the
processing chain, with a few variants indicating for some of them if it is
permanent or volatile (eg: an HTTP status is stored into the transaction so
it is permanent, despite being caught in the response contents).
The fetches also have a second mask indicating their validity domain. This one
is computed from a conversion table at registration time, so there is no need
for doing it by hand. This validity domain consists in a bitmask with one bit
set for each usage point in the processing chain. Some provisions were made
for upcoming controls such as connection-based TCP rules which apply on top of
the connection layer but before instantiating the session.
Then everywhere a fetch is used, the bit for the control point is checked in
the fetch's validity domain, and it becomes possible to finely ensure that a
fetch will work or not.
Note that we need these two separate bitfields because some fetches are usable
both in request and response (eg: "hdr", "payload"). So the keyword will have
a "use" field made of a combination of several SMP_USE_* values, which will be
converted into a wider list of SMP_VAL_* flags.
The knowledge of permanent vs dynamic information has disappeared for now, as
it was never used. Later we'll probably reintroduce it differently when
dealing with variables. Its only use at the moment could have been to avoid
caching a dynamic rate measurement, but nothing is cached as of now.
2013-01-07 09:42:20 -05:00
|
|
|
struct sample_fetch *sf;
|
|
|
|
|
int bit;
|
|
|
|
|
|
|
|
|
|
for (sf = kwl->kw; sf->kw != NULL; sf++) {
|
|
|
|
|
for (bit = 0; bit < SMP_SRC_ENTRIES; bit++)
|
|
|
|
|
if (sf->use & (1 << bit))
|
|
|
|
|
sf->val |= fetch_cap[bit];
|
|
|
|
|
}
|
|
|
|
|
LIST_ADDQ(&sample_fetches.list, &kwl->list);
|
2010-01-04 10:16:05 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
2012-04-27 15:37:17 -04:00
|
|
|
* Registers the sample format coverstion keyword list <pckl> as a list of valid keywords for next
|
2010-01-04 10:16:05 -05:00
|
|
|
* parsing sessions.
|
|
|
|
|
*/
|
2012-04-27 15:37:17 -04:00
|
|
|
void sample_register_convs(struct sample_conv_kw_list *pckl)
|
2010-01-04 10:16:05 -05:00
|
|
|
{
|
2012-04-27 15:37:17 -04:00
|
|
|
LIST_ADDQ(&sample_convs.list, &pckl->list);
|
2010-01-04 10:16:05 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
2012-04-27 15:37:17 -04:00
|
|
|
* Returns the pointer on sample fetch keyword structure identified by
|
2010-01-04 10:16:05 -05:00
|
|
|
* string of <len> in buffer <kw>.
|
|
|
|
|
*
|
|
|
|
|
*/
|
2012-04-27 15:37:17 -04:00
|
|
|
struct sample_fetch *find_sample_fetch(const char *kw, int len)
|
2010-01-04 10:16:05 -05:00
|
|
|
{
|
|
|
|
|
int index;
|
2012-04-27 15:37:17 -04:00
|
|
|
struct sample_fetch_kw_list *kwl;
|
2010-01-04 10:16:05 -05:00
|
|
|
|
2012-04-27 15:37:17 -04:00
|
|
|
list_for_each_entry(kwl, &sample_fetches.list, list) {
|
2010-01-04 10:16:05 -05:00
|
|
|
for (index = 0; kwl->kw[index].kw != NULL; index++) {
|
|
|
|
|
if (strncmp(kwl->kw[index].kw, kw, len) == 0 &&
|
|
|
|
|
kwl->kw[index].kw[len] == '\0')
|
|
|
|
|
return &kwl->kw[index];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-25 10:24:44 -05:00
|
|
|
/* This function browses the list of available sample fetches. <current> is
|
2014-12-08 08:49:19 -05:00
|
|
|
* the last used sample fetch. If it is the first call, it must set to NULL.
|
2018-01-25 10:24:44 -05:00
|
|
|
* <idx> is the index of the next sample fetch entry. It is used as private
|
|
|
|
|
* value. It is useless to initiate it.
|
2014-12-08 08:49:19 -05:00
|
|
|
*
|
2018-01-25 10:24:44 -05:00
|
|
|
* It returns always the new fetch_sample entry, and NULL when the end of
|
2014-12-08 08:49:19 -05:00
|
|
|
* the list is reached.
|
|
|
|
|
*/
|
|
|
|
|
struct sample_fetch *sample_fetch_getnext(struct sample_fetch *current, int *idx)
|
|
|
|
|
{
|
|
|
|
|
struct sample_fetch_kw_list *kwl;
|
|
|
|
|
struct sample_fetch *base;
|
|
|
|
|
|
|
|
|
|
if (!current) {
|
|
|
|
|
/* Get first kwl entry. */
|
|
|
|
|
kwl = LIST_NEXT(&sample_fetches.list, struct sample_fetch_kw_list *, list);
|
|
|
|
|
(*idx) = 0;
|
|
|
|
|
} else {
|
|
|
|
|
/* Get kwl corresponding to the curret entry. */
|
|
|
|
|
base = current + 1 - (*idx);
|
|
|
|
|
kwl = container_of(base, struct sample_fetch_kw_list, kw);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
|
|
|
|
|
|
/* Check if kwl is the last entry. */
|
|
|
|
|
if (&kwl->list == &sample_fetches.list)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
/* idx contain the next keyword. If it is available, return it. */
|
|
|
|
|
if (kwl->kw[*idx].kw) {
|
|
|
|
|
(*idx)++;
|
|
|
|
|
return &kwl->kw[(*idx)-1];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* get next entry in the main list, and return NULL if the end is reached. */
|
|
|
|
|
kwl = LIST_NEXT(&kwl->list, struct sample_fetch_kw_list *, list);
|
|
|
|
|
|
|
|
|
|
/* Set index to 0, ans do one other loop. */
|
|
|
|
|
(*idx) = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-10 18:56:48 -04:00
|
|
|
/* This function browses the list of available converters. <current> is
|
|
|
|
|
* the last used converter. If it is the first call, it must set to NULL.
|
|
|
|
|
* <idx> is the index of the next converter entry. It is used as private
|
|
|
|
|
* value. It is useless to initiate it.
|
|
|
|
|
*
|
|
|
|
|
* It returns always the next sample_conv entry, and NULL when the end of
|
|
|
|
|
* the list is reached.
|
|
|
|
|
*/
|
|
|
|
|
struct sample_conv *sample_conv_getnext(struct sample_conv *current, int *idx)
|
|
|
|
|
{
|
|
|
|
|
struct sample_conv_kw_list *kwl;
|
|
|
|
|
struct sample_conv *base;
|
|
|
|
|
|
|
|
|
|
if (!current) {
|
|
|
|
|
/* Get first kwl entry. */
|
|
|
|
|
kwl = LIST_NEXT(&sample_convs.list, struct sample_conv_kw_list *, list);
|
|
|
|
|
(*idx) = 0;
|
|
|
|
|
} else {
|
|
|
|
|
/* Get kwl corresponding to the curret entry. */
|
|
|
|
|
base = current + 1 - (*idx);
|
|
|
|
|
kwl = container_of(base, struct sample_conv_kw_list, kw);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
|
/* Check if kwl is the last entry. */
|
|
|
|
|
if (&kwl->list == &sample_convs.list)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
/* idx contain the next keyword. If it is available, return it. */
|
|
|
|
|
if (kwl->kw[*idx].kw) {
|
|
|
|
|
(*idx)++;
|
|
|
|
|
return &kwl->kw[(*idx)-1];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* get next entry in the main list, and return NULL if the end is reached. */
|
|
|
|
|
kwl = LIST_NEXT(&kwl->list, struct sample_conv_kw_list *, list);
|
|
|
|
|
|
|
|
|
|
/* Set index to 0, ans do one other loop. */
|
|
|
|
|
(*idx) = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-01-04 10:16:05 -05:00
|
|
|
/*
|
2012-04-27 15:37:17 -04:00
|
|
|
* Returns the pointer on sample format conversion keyword structure identified by
|
2010-01-04 10:16:05 -05:00
|
|
|
* string of <len> in buffer <kw>.
|
|
|
|
|
*
|
|
|
|
|
*/
|
2012-04-27 15:37:17 -04:00
|
|
|
struct sample_conv *find_sample_conv(const char *kw, int len)
|
2010-01-04 10:16:05 -05:00
|
|
|
{
|
|
|
|
|
int index;
|
2012-04-27 15:37:17 -04:00
|
|
|
struct sample_conv_kw_list *kwl;
|
2010-01-04 10:16:05 -05:00
|
|
|
|
2012-04-27 15:37:17 -04:00
|
|
|
list_for_each_entry(kwl, &sample_convs.list, list) {
|
2010-01-04 10:16:05 -05:00
|
|
|
for (index = 0; kwl->kw[index].kw != NULL; index++) {
|
|
|
|
|
if (strncmp(kwl->kw[index].kw, kw, len) == 0 &&
|
|
|
|
|
kwl->kw[index].kw[len] == '\0')
|
|
|
|
|
return &kwl->kw[index];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/******************************************************************/
|
2012-04-27 15:37:17 -04:00
|
|
|
/* Sample casts functions */
|
2010-01-04 10:16:05 -05:00
|
|
|
/******************************************************************/
|
|
|
|
|
|
2012-04-23 16:03:39 -04:00
|
|
|
static int c_ip2int(struct sample *smp)
|
2010-01-04 10:16:05 -05:00
|
|
|
{
|
2015-08-19 03:07:19 -04:00
|
|
|
smp->data.u.sint = ntohl(smp->data.u.ipv4.s_addr);
|
2015-08-19 03:00:18 -04:00
|
|
|
smp->data.type = SMP_T_SINT;
|
2010-01-04 10:16:05 -05:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2012-04-23 16:03:39 -04:00
|
|
|
static int c_ip2str(struct sample *smp)
|
2010-01-04 10:16:05 -05:00
|
|
|
{
|
2018-07-13 05:56:34 -04:00
|
|
|
struct buffer *trash = get_trash_chunk();
|
2010-01-04 10:16:05 -05:00
|
|
|
|
2018-07-13 04:54:26 -04:00
|
|
|
if (!inet_ntop(AF_INET, (void *)&smp->data.u.ipv4, trash->area, trash->size))
|
2010-01-04 10:16:05 -05:00
|
|
|
return 0;
|
|
|
|
|
|
2018-07-13 04:54:26 -04:00
|
|
|
trash->data = strlen(trash->area);
|
2015-08-19 03:07:19 -04:00
|
|
|
smp->data.u.str = *trash;
|
2015-08-19 03:00:18 -04:00
|
|
|
smp->data.type = SMP_T_STR;
|
2013-12-16 18:20:33 -05:00
|
|
|
smp->flags &= ~SMP_F_CONST;
|
2010-01-04 10:16:05 -05:00
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2012-04-23 16:03:39 -04:00
|
|
|
static int c_ip2ipv6(struct sample *smp)
|
2011-03-24 06:09:31 -04:00
|
|
|
{
|
2015-08-19 03:07:19 -04:00
|
|
|
v4tov6(&smp->data.u.ipv6, &smp->data.u.ipv4);
|
2015-08-19 03:00:18 -04:00
|
|
|
smp->data.type = SMP_T_IPV6;
|
2011-03-24 06:09:31 -04:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-24 03:04:56 -04:00
|
|
|
static int c_ipv62ip(struct sample *smp)
|
|
|
|
|
{
|
2015-08-19 03:07:19 -04:00
|
|
|
if (!v6tov4(&smp->data.u.ipv4, &smp->data.u.ipv6))
|
2015-07-24 03:04:56 -04:00
|
|
|
return 0;
|
2018-01-25 10:24:46 -05:00
|
|
|
smp->data.type = SMP_T_IPV4;
|
2015-07-24 03:04:56 -04:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2012-04-23 16:03:39 -04:00
|
|
|
static int c_ipv62str(struct sample *smp)
|
2011-03-24 06:09:31 -04:00
|
|
|
{
|
2018-07-13 05:56:34 -04:00
|
|
|
struct buffer *trash = get_trash_chunk();
|
2011-03-24 06:09:31 -04:00
|
|
|
|
2018-07-13 04:54:26 -04:00
|
|
|
if (!inet_ntop(AF_INET6, (void *)&smp->data.u.ipv6, trash->area, trash->size))
|
2011-03-24 06:09:31 -04:00
|
|
|
return 0;
|
|
|
|
|
|
2018-07-13 04:54:26 -04:00
|
|
|
trash->data = strlen(trash->area);
|
2015-08-19 03:07:19 -04:00
|
|
|
smp->data.u.str = *trash;
|
2015-08-19 03:00:18 -04:00
|
|
|
smp->data.type = SMP_T_STR;
|
2013-12-16 18:20:33 -05:00
|
|
|
smp->flags &= ~SMP_F_CONST;
|
2011-03-24 06:09:31 -04:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
2012-04-23 16:03:39 -04:00
|
|
|
static int c_ipv62ip(struct sample *smp)
|
2011-03-24 06:09:31 -04:00
|
|
|
{
|
2015-08-19 03:07:19 -04:00
|
|
|
return v6tov4(&smp->data.u.ipv4, &smp->data.u.ipv6);
|
2011-03-24 06:09:31 -04:00
|
|
|
}
|
|
|
|
|
*/
|
|
|
|
|
|
2012-04-23 16:03:39 -04:00
|
|
|
static int c_int2ip(struct sample *smp)
|
2010-01-04 10:16:05 -05:00
|
|
|
{
|
2015-08-19 03:07:19 -04:00
|
|
|
smp->data.u.ipv4.s_addr = htonl((unsigned int)smp->data.u.sint);
|
2015-08-19 03:00:18 -04:00
|
|
|
smp->data.type = SMP_T_IPV4;
|
2013-11-26 14:47:54 -05:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-24 03:04:56 -04:00
|
|
|
static int c_int2ipv6(struct sample *smp)
|
|
|
|
|
{
|
2015-08-19 03:07:19 -04:00
|
|
|
smp->data.u.ipv4.s_addr = htonl((unsigned int)smp->data.u.sint);
|
|
|
|
|
v4tov6(&smp->data.u.ipv6, &smp->data.u.ipv4);
|
2015-08-19 03:00:18 -04:00
|
|
|
smp->data.type = SMP_T_IPV6;
|
2015-07-24 03:04:56 -04:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2013-11-26 14:47:54 -05:00
|
|
|
static int c_str2addr(struct sample *smp)
|
|
|
|
|
{
|
2018-07-13 04:54:26 -04:00
|
|
|
if (!buf2ip(smp->data.u.str.area, smp->data.u.str.data, &smp->data.u.ipv4)) {
|
|
|
|
|
if (!buf2ip6(smp->data.u.str.area, smp->data.u.str.data, &smp->data.u.ipv6))
|
2013-12-11 06:38:57 -05:00
|
|
|
return 0;
|
2015-08-19 03:00:18 -04:00
|
|
|
smp->data.type = SMP_T_IPV6;
|
2013-12-16 18:20:33 -05:00
|
|
|
smp->flags &= ~SMP_F_CONST;
|
2013-12-11 06:38:57 -05:00
|
|
|
return 1;
|
2013-11-26 14:47:54 -05:00
|
|
|
}
|
2015-08-19 03:00:18 -04:00
|
|
|
smp->data.type = SMP_T_IPV4;
|
2013-12-16 18:20:33 -05:00
|
|
|
smp->flags &= ~SMP_F_CONST;
|
2010-01-04 10:16:05 -05:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2012-04-23 16:03:39 -04:00
|
|
|
static int c_str2ip(struct sample *smp)
|
2010-01-04 10:16:05 -05:00
|
|
|
{
|
2018-07-13 04:54:26 -04:00
|
|
|
if (!buf2ip(smp->data.u.str.area, smp->data.u.str.data, &smp->data.u.ipv4))
|
2010-01-04 10:16:05 -05:00
|
|
|
return 0;
|
2015-08-19 03:00:18 -04:00
|
|
|
smp->data.type = SMP_T_IPV4;
|
2013-12-16 18:20:33 -05:00
|
|
|
smp->flags &= ~SMP_F_CONST;
|
2010-01-04 10:16:05 -05:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2012-04-23 16:03:39 -04:00
|
|
|
static int c_str2ipv6(struct sample *smp)
|
2011-03-24 06:09:31 -04:00
|
|
|
{
|
2018-07-13 04:54:26 -04:00
|
|
|
if (!buf2ip6(smp->data.u.str.area, smp->data.u.str.data, &smp->data.u.ipv6))
|
2013-12-11 06:38:57 -05:00
|
|
|
return 0;
|
2015-08-19 03:00:18 -04:00
|
|
|
smp->data.type = SMP_T_IPV6;
|
2013-12-16 18:20:33 -05:00
|
|
|
smp->flags &= ~SMP_F_CONST;
|
2013-12-11 06:38:57 -05:00
|
|
|
return 1;
|
2011-03-24 06:09:31 -04:00
|
|
|
}
|
|
|
|
|
|
2014-11-03 12:17:10 -05:00
|
|
|
/*
|
|
|
|
|
* The NULL char always enforces the end of string if it is met.
|
|
|
|
|
* Data is never changed, so we can ignore the CONST case
|
MEDIUM: sample: change the behavior of the bin2str cast
The bin2str cast gives the hexadecimal representation of the binary
content when it is used as string. This was inherited from the
stick-table casts without realizing that it was a mistake. Indeed,
it breaks string processing on binary contents, preventing any _reg,
_beg, etc from working.
For example, with an HTTP GET request, the fetch "req.payload(0,3)"
returns the 3 bytes "G", "E", and "T" in binary. If this fetch is
used with regex, it is automatically converted to "474554" and the
regex is applied on this string, so it never matches.
This commit changes the cast so that bin2str does not convert the
contents anymore, and returns a string type. The contents can thus
be matched as is, and the NULL character continues to mark the end
of the string to avoid any issue with some string-based functions.
This commit could almost have been marked as a bug fix since it
does what the doc says.
Note that in case someone would rely on the hex encoding, then the
same behaviour could be achieved by appending ",hex" after the sample
fetch function (brought by previous patch).
2014-03-12 10:07:59 -04:00
|
|
|
*/
|
2012-10-17 07:36:06 -04:00
|
|
|
static int c_bin2str(struct sample *smp)
|
|
|
|
|
{
|
2014-11-03 12:17:10 -05:00
|
|
|
int i;
|
2012-10-17 07:36:06 -04:00
|
|
|
|
2018-07-13 04:54:26 -04:00
|
|
|
for (i = 0; i < smp->data.u.str.data; i++) {
|
|
|
|
|
if (!smp->data.u.str.area[i]) {
|
|
|
|
|
smp->data.u.str.data = i;
|
MEDIUM: sample: change the behavior of the bin2str cast
The bin2str cast gives the hexadecimal representation of the binary
content when it is used as string. This was inherited from the
stick-table casts without realizing that it was a mistake. Indeed,
it breaks string processing on binary contents, preventing any _reg,
_beg, etc from working.
For example, with an HTTP GET request, the fetch "req.payload(0,3)"
returns the 3 bytes "G", "E", and "T" in binary. If this fetch is
used with regex, it is automatically converted to "474554" and the
regex is applied on this string, so it never matches.
This commit changes the cast so that bin2str does not convert the
contents anymore, and returns a string type. The contents can thus
be matched as is, and the NULL character continues to mark the end
of the string to avoid any issue with some string-based functions.
This commit could almost have been marked as a bug fix since it
does what the doc says.
Note that in case someone would rely on the hex encoding, then the
same behaviour could be achieved by appending ",hex" after the sample
fetch function (brought by previous patch).
2014-03-12 10:07:59 -04:00
|
|
|
break;
|
2014-11-03 12:17:10 -05:00
|
|
|
}
|
2012-10-17 07:36:06 -04:00
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2012-04-23 16:03:39 -04:00
|
|
|
static int c_int2str(struct sample *smp)
|
2010-01-04 10:16:05 -05:00
|
|
|
{
|
2018-07-13 05:56:34 -04:00
|
|
|
struct buffer *trash = get_trash_chunk();
|
2010-01-04 10:16:05 -05:00
|
|
|
char *pos;
|
|
|
|
|
|
2018-07-13 04:54:26 -04:00
|
|
|
pos = lltoa_r(smp->data.u.sint, trash->area, trash->size);
|
2010-01-04 10:16:05 -05:00
|
|
|
if (!pos)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2018-07-13 04:54:26 -04:00
|
|
|
trash->size = trash->size - (pos - trash->area);
|
|
|
|
|
trash->area = pos;
|
|
|
|
|
trash->data = strlen(pos);
|
2015-08-19 03:07:19 -04:00
|
|
|
smp->data.u.str = *trash;
|
2015-08-19 03:00:18 -04:00
|
|
|
smp->data.type = SMP_T_STR;
|
2013-12-16 18:20:33 -05:00
|
|
|
smp->flags &= ~SMP_F_CONST;
|
2010-01-04 10:16:05 -05:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-15 15:14:56 -05:00
|
|
|
/* This function unconditionally duplicates data and removes the "const" flag.
|
BUG/MEDIUM: samples: make smp_dup() always duplicate the sample
Vedran Furac reported a strange problem where the "base" sample fetch
would not always work for tracking purposes.
In fact, it happens that commit bc8c404 ("MAJOR: stick-tables: use sample
types in place of dedicated types") merged in 1.6 exposed a fundamental
bug related to the way samples use chunks as strings. The problem is that
chunks convey a base pointer, a length and an optional size, which may be
zero when unknown or when the chunk is allocated from a read-only location.
The sole purpose of this size is to know whether or not the chunk may be
appended new data. This size cause some semantics issue in the sample,
which has its own SMP_F_CONST flag to indicate read-only contents.
The problem was emphasized by the commit above because it made use of new
calls to smp_dup() to convert a sample to a table key. And since smp_dup()
would only check the SMP_F_CONST flag, it would happily return read-write
samples indicating size=0.
So some tests were added upon smp_dup() return to ensure that the actual
length is smaller than size, but this in fact made things even worse. For
example, the "sni" server directive does some bad stuff on many occasions
because it limits len to size-1 and effectively sets it to -1 and writes
the zero byte before the beginning of the string!
It is therefore obvious that smp_dup() needs to be modified to take this
nature of the chunks into account. It's not enough but is needed. The core
of the problem comes from the fact that smp_dup() is called for 5 distinct
needs which are not always fulfilled :
1) duplicate a sample to keep a copy of it during some operations
2) ensure that the sample is rewritable for a converter like upper()
3) ensure that the sample is terminated with a \0
4) set a correct size on the sample
5) grow the sample in case it was extracted from a partial chunk
Case 1 is not used for now, so we can ignore it. Case 2 indicates the wish
to modify the sample, so its R/O status must be removed if any, but there's
no implied requirement that the chunk becomes larger. Case 3 is used when
the sample has to be made compatible with libc's str* functions. There's no
need to make it R/W nor to duplicate it if it is already correct. Case 4
can happen when the sample's size is required (eg: before performing some
changes that must fit in the buffer). Case 5 is more or less similar but
will happen when the sample by be grown but we want to ensure we're not
bound by the current small size.
So the proposal is to have different functions for various operations. One
will ensure a sample is safe for use with str* functions. Another one will
ensure it may be rewritten in place. And smp_dup() will have to perform an
inconditional duplication to guarantee at least #5 above, and implicitly
all other ones.
This patch only modifies smp_dup() to make the duplication inconditional. It
is enough to fix both the "base" sample fetch and the "sni" server directive,
and all use cases in general though not always optimally. More patches will
follow to address them more optimally and even better than the current
situation (eg: avoid a dup just to add a \0 when possible).
The bug comes from an ambiguous design, so its roots are old. 1.6 is affected
and a backport is needed. In 1.5, the function already existed but was only
used by two converters modifying the data in place, so the bug has no effect
there.
2016-08-08 13:21:09 -04:00
|
|
|
* For strings and binary blocks, it also provides a known allocated size with
|
|
|
|
|
* a length that is capped to the size, and ensures a trailing zero is always
|
|
|
|
|
* appended for strings. This is necessary for some operations which may
|
|
|
|
|
* require to extend the length. It returns 0 if it fails, 1 on success.
|
|
|
|
|
*/
|
2013-12-16 18:20:33 -05:00
|
|
|
int smp_dup(struct sample *smp)
|
2010-09-23 12:02:19 -04:00
|
|
|
{
|
2018-07-13 05:56:34 -04:00
|
|
|
struct buffer *trash;
|
2010-09-23 12:02:19 -04:00
|
|
|
|
2015-08-19 03:00:18 -04:00
|
|
|
switch (smp->data.type) {
|
2013-12-16 18:20:33 -05:00
|
|
|
case SMP_T_BOOL:
|
|
|
|
|
case SMP_T_SINT:
|
|
|
|
|
case SMP_T_ADDR:
|
|
|
|
|
case SMP_T_IPV4:
|
|
|
|
|
case SMP_T_IPV6:
|
|
|
|
|
/* These type are not const. */
|
|
|
|
|
break;
|
BUG/MEDIUM: samples: make smp_dup() always duplicate the sample
Vedran Furac reported a strange problem where the "base" sample fetch
would not always work for tracking purposes.
In fact, it happens that commit bc8c404 ("MAJOR: stick-tables: use sample
types in place of dedicated types") merged in 1.6 exposed a fundamental
bug related to the way samples use chunks as strings. The problem is that
chunks convey a base pointer, a length and an optional size, which may be
zero when unknown or when the chunk is allocated from a read-only location.
The sole purpose of this size is to know whether or not the chunk may be
appended new data. This size cause some semantics issue in the sample,
which has its own SMP_F_CONST flag to indicate read-only contents.
The problem was emphasized by the commit above because it made use of new
calls to smp_dup() to convert a sample to a table key. And since smp_dup()
would only check the SMP_F_CONST flag, it would happily return read-write
samples indicating size=0.
So some tests were added upon smp_dup() return to ensure that the actual
length is smaller than size, but this in fact made things even worse. For
example, the "sni" server directive does some bad stuff on many occasions
because it limits len to size-1 and effectively sets it to -1 and writes
the zero byte before the beginning of the string!
It is therefore obvious that smp_dup() needs to be modified to take this
nature of the chunks into account. It's not enough but is needed. The core
of the problem comes from the fact that smp_dup() is called for 5 distinct
needs which are not always fulfilled :
1) duplicate a sample to keep a copy of it during some operations
2) ensure that the sample is rewritable for a converter like upper()
3) ensure that the sample is terminated with a \0
4) set a correct size on the sample
5) grow the sample in case it was extracted from a partial chunk
Case 1 is not used for now, so we can ignore it. Case 2 indicates the wish
to modify the sample, so its R/O status must be removed if any, but there's
no implied requirement that the chunk becomes larger. Case 3 is used when
the sample has to be made compatible with libc's str* functions. There's no
need to make it R/W nor to duplicate it if it is already correct. Case 4
can happen when the sample's size is required (eg: before performing some
changes that must fit in the buffer). Case 5 is more or less similar but
will happen when the sample by be grown but we want to ensure we're not
bound by the current small size.
So the proposal is to have different functions for various operations. One
will ensure a sample is safe for use with str* functions. Another one will
ensure it may be rewritten in place. And smp_dup() will have to perform an
inconditional duplication to guarantee at least #5 above, and implicitly
all other ones.
This patch only modifies smp_dup() to make the duplication inconditional. It
is enough to fix both the "base" sample fetch and the "sni" server directive,
and all use cases in general though not always optimally. More patches will
follow to address them more optimally and even better than the current
situation (eg: avoid a dup just to add a \0 when possible).
The bug comes from an ambiguous design, so its roots are old. 1.6 is affected
and a backport is needed. In 1.5, the function already existed but was only
used by two converters modifying the data in place, so the bug has no effect
there.
2016-08-08 13:21:09 -04:00
|
|
|
|
2017-07-24 09:38:41 -04:00
|
|
|
case SMP_T_METH:
|
|
|
|
|
if (smp->data.u.meth.meth != HTTP_METH_OTHER)
|
|
|
|
|
break;
|
|
|
|
|
/* Fall through */
|
|
|
|
|
|
2013-12-16 18:20:33 -05:00
|
|
|
case SMP_T_STR:
|
BUG/MEDIUM: samples: make smp_dup() always duplicate the sample
Vedran Furac reported a strange problem where the "base" sample fetch
would not always work for tracking purposes.
In fact, it happens that commit bc8c404 ("MAJOR: stick-tables: use sample
types in place of dedicated types") merged in 1.6 exposed a fundamental
bug related to the way samples use chunks as strings. The problem is that
chunks convey a base pointer, a length and an optional size, which may be
zero when unknown or when the chunk is allocated from a read-only location.
The sole purpose of this size is to know whether or not the chunk may be
appended new data. This size cause some semantics issue in the sample,
which has its own SMP_F_CONST flag to indicate read-only contents.
The problem was emphasized by the commit above because it made use of new
calls to smp_dup() to convert a sample to a table key. And since smp_dup()
would only check the SMP_F_CONST flag, it would happily return read-write
samples indicating size=0.
So some tests were added upon smp_dup() return to ensure that the actual
length is smaller than size, but this in fact made things even worse. For
example, the "sni" server directive does some bad stuff on many occasions
because it limits len to size-1 and effectively sets it to -1 and writes
the zero byte before the beginning of the string!
It is therefore obvious that smp_dup() needs to be modified to take this
nature of the chunks into account. It's not enough but is needed. The core
of the problem comes from the fact that smp_dup() is called for 5 distinct
needs which are not always fulfilled :
1) duplicate a sample to keep a copy of it during some operations
2) ensure that the sample is rewritable for a converter like upper()
3) ensure that the sample is terminated with a \0
4) set a correct size on the sample
5) grow the sample in case it was extracted from a partial chunk
Case 1 is not used for now, so we can ignore it. Case 2 indicates the wish
to modify the sample, so its R/O status must be removed if any, but there's
no implied requirement that the chunk becomes larger. Case 3 is used when
the sample has to be made compatible with libc's str* functions. There's no
need to make it R/W nor to duplicate it if it is already correct. Case 4
can happen when the sample's size is required (eg: before performing some
changes that must fit in the buffer). Case 5 is more or less similar but
will happen when the sample by be grown but we want to ensure we're not
bound by the current small size.
So the proposal is to have different functions for various operations. One
will ensure a sample is safe for use with str* functions. Another one will
ensure it may be rewritten in place. And smp_dup() will have to perform an
inconditional duplication to guarantee at least #5 above, and implicitly
all other ones.
This patch only modifies smp_dup() to make the duplication inconditional. It
is enough to fix both the "base" sample fetch and the "sni" server directive,
and all use cases in general though not always optimally. More patches will
follow to address them more optimally and even better than the current
situation (eg: avoid a dup just to add a \0 when possible).
The bug comes from an ambiguous design, so its roots are old. 1.6 is affected
and a backport is needed. In 1.5, the function already existed but was only
used by two converters modifying the data in place, so the bug has no effect
there.
2016-08-08 13:21:09 -04:00
|
|
|
trash = get_trash_chunk();
|
2018-12-07 09:23:41 -05:00
|
|
|
trash->data = smp->data.type == SMP_T_STR ?
|
|
|
|
|
smp->data.u.str.data : smp->data.u.meth.str.data;
|
2018-07-13 04:54:26 -04:00
|
|
|
if (trash->data > trash->size - 1)
|
|
|
|
|
trash->data = trash->size - 1;
|
BUG/MEDIUM: samples: make smp_dup() always duplicate the sample
Vedran Furac reported a strange problem where the "base" sample fetch
would not always work for tracking purposes.
In fact, it happens that commit bc8c404 ("MAJOR: stick-tables: use sample
types in place of dedicated types") merged in 1.6 exposed a fundamental
bug related to the way samples use chunks as strings. The problem is that
chunks convey a base pointer, a length and an optional size, which may be
zero when unknown or when the chunk is allocated from a read-only location.
The sole purpose of this size is to know whether or not the chunk may be
appended new data. This size cause some semantics issue in the sample,
which has its own SMP_F_CONST flag to indicate read-only contents.
The problem was emphasized by the commit above because it made use of new
calls to smp_dup() to convert a sample to a table key. And since smp_dup()
would only check the SMP_F_CONST flag, it would happily return read-write
samples indicating size=0.
So some tests were added upon smp_dup() return to ensure that the actual
length is smaller than size, but this in fact made things even worse. For
example, the "sni" server directive does some bad stuff on many occasions
because it limits len to size-1 and effectively sets it to -1 and writes
the zero byte before the beginning of the string!
It is therefore obvious that smp_dup() needs to be modified to take this
nature of the chunks into account. It's not enough but is needed. The core
of the problem comes from the fact that smp_dup() is called for 5 distinct
needs which are not always fulfilled :
1) duplicate a sample to keep a copy of it during some operations
2) ensure that the sample is rewritable for a converter like upper()
3) ensure that the sample is terminated with a \0
4) set a correct size on the sample
5) grow the sample in case it was extracted from a partial chunk
Case 1 is not used for now, so we can ignore it. Case 2 indicates the wish
to modify the sample, so its R/O status must be removed if any, but there's
no implied requirement that the chunk becomes larger. Case 3 is used when
the sample has to be made compatible with libc's str* functions. There's no
need to make it R/W nor to duplicate it if it is already correct. Case 4
can happen when the sample's size is required (eg: before performing some
changes that must fit in the buffer). Case 5 is more or less similar but
will happen when the sample by be grown but we want to ensure we're not
bound by the current small size.
So the proposal is to have different functions for various operations. One
will ensure a sample is safe for use with str* functions. Another one will
ensure it may be rewritten in place. And smp_dup() will have to perform an
inconditional duplication to guarantee at least #5 above, and implicitly
all other ones.
This patch only modifies smp_dup() to make the duplication inconditional. It
is enough to fix both the "base" sample fetch and the "sni" server directive,
and all use cases in general though not always optimally. More patches will
follow to address them more optimally and even better than the current
situation (eg: avoid a dup just to add a \0 when possible).
The bug comes from an ambiguous design, so its roots are old. 1.6 is affected
and a backport is needed. In 1.5, the function already existed but was only
used by two converters modifying the data in place, so the bug has no effect
there.
2016-08-08 13:21:09 -04:00
|
|
|
|
2018-12-07 09:23:41 -05:00
|
|
|
memcpy(trash->area, smp->data.type == SMP_T_STR ?
|
|
|
|
|
smp->data.u.str.area : smp->data.u.meth.str.area,
|
|
|
|
|
trash->data);
|
2018-07-13 04:54:26 -04:00
|
|
|
trash->area[trash->data] = 0;
|
BUG/MEDIUM: samples: make smp_dup() always duplicate the sample
Vedran Furac reported a strange problem where the "base" sample fetch
would not always work for tracking purposes.
In fact, it happens that commit bc8c404 ("MAJOR: stick-tables: use sample
types in place of dedicated types") merged in 1.6 exposed a fundamental
bug related to the way samples use chunks as strings. The problem is that
chunks convey a base pointer, a length and an optional size, which may be
zero when unknown or when the chunk is allocated from a read-only location.
The sole purpose of this size is to know whether or not the chunk may be
appended new data. This size cause some semantics issue in the sample,
which has its own SMP_F_CONST flag to indicate read-only contents.
The problem was emphasized by the commit above because it made use of new
calls to smp_dup() to convert a sample to a table key. And since smp_dup()
would only check the SMP_F_CONST flag, it would happily return read-write
samples indicating size=0.
So some tests were added upon smp_dup() return to ensure that the actual
length is smaller than size, but this in fact made things even worse. For
example, the "sni" server directive does some bad stuff on many occasions
because it limits len to size-1 and effectively sets it to -1 and writes
the zero byte before the beginning of the string!
It is therefore obvious that smp_dup() needs to be modified to take this
nature of the chunks into account. It's not enough but is needed. The core
of the problem comes from the fact that smp_dup() is called for 5 distinct
needs which are not always fulfilled :
1) duplicate a sample to keep a copy of it during some operations
2) ensure that the sample is rewritable for a converter like upper()
3) ensure that the sample is terminated with a \0
4) set a correct size on the sample
5) grow the sample in case it was extracted from a partial chunk
Case 1 is not used for now, so we can ignore it. Case 2 indicates the wish
to modify the sample, so its R/O status must be removed if any, but there's
no implied requirement that the chunk becomes larger. Case 3 is used when
the sample has to be made compatible with libc's str* functions. There's no
need to make it R/W nor to duplicate it if it is already correct. Case 4
can happen when the sample's size is required (eg: before performing some
changes that must fit in the buffer). Case 5 is more or less similar but
will happen when the sample by be grown but we want to ensure we're not
bound by the current small size.
So the proposal is to have different functions for various operations. One
will ensure a sample is safe for use with str* functions. Another one will
ensure it may be rewritten in place. And smp_dup() will have to perform an
inconditional duplication to guarantee at least #5 above, and implicitly
all other ones.
This patch only modifies smp_dup() to make the duplication inconditional. It
is enough to fix both the "base" sample fetch and the "sni" server directive,
and all use cases in general though not always optimally. More patches will
follow to address them more optimally and even better than the current
situation (eg: avoid a dup just to add a \0 when possible).
The bug comes from an ambiguous design, so its roots are old. 1.6 is affected
and a backport is needed. In 1.5, the function already existed but was only
used by two converters modifying the data in place, so the bug has no effect
there.
2016-08-08 13:21:09 -04:00
|
|
|
smp->data.u.str = *trash;
|
|
|
|
|
break;
|
|
|
|
|
|
2013-12-16 18:20:33 -05:00
|
|
|
case SMP_T_BIN:
|
|
|
|
|
trash = get_trash_chunk();
|
2018-07-13 04:54:26 -04:00
|
|
|
trash->data = smp->data.u.str.data;
|
|
|
|
|
if (trash->data > trash->size)
|
|
|
|
|
trash->data = trash->size;
|
BUG/MEDIUM: samples: make smp_dup() always duplicate the sample
Vedran Furac reported a strange problem where the "base" sample fetch
would not always work for tracking purposes.
In fact, it happens that commit bc8c404 ("MAJOR: stick-tables: use sample
types in place of dedicated types") merged in 1.6 exposed a fundamental
bug related to the way samples use chunks as strings. The problem is that
chunks convey a base pointer, a length and an optional size, which may be
zero when unknown or when the chunk is allocated from a read-only location.
The sole purpose of this size is to know whether or not the chunk may be
appended new data. This size cause some semantics issue in the sample,
which has its own SMP_F_CONST flag to indicate read-only contents.
The problem was emphasized by the commit above because it made use of new
calls to smp_dup() to convert a sample to a table key. And since smp_dup()
would only check the SMP_F_CONST flag, it would happily return read-write
samples indicating size=0.
So some tests were added upon smp_dup() return to ensure that the actual
length is smaller than size, but this in fact made things even worse. For
example, the "sni" server directive does some bad stuff on many occasions
because it limits len to size-1 and effectively sets it to -1 and writes
the zero byte before the beginning of the string!
It is therefore obvious that smp_dup() needs to be modified to take this
nature of the chunks into account. It's not enough but is needed. The core
of the problem comes from the fact that smp_dup() is called for 5 distinct
needs which are not always fulfilled :
1) duplicate a sample to keep a copy of it during some operations
2) ensure that the sample is rewritable for a converter like upper()
3) ensure that the sample is terminated with a \0
4) set a correct size on the sample
5) grow the sample in case it was extracted from a partial chunk
Case 1 is not used for now, so we can ignore it. Case 2 indicates the wish
to modify the sample, so its R/O status must be removed if any, but there's
no implied requirement that the chunk becomes larger. Case 3 is used when
the sample has to be made compatible with libc's str* functions. There's no
need to make it R/W nor to duplicate it if it is already correct. Case 4
can happen when the sample's size is required (eg: before performing some
changes that must fit in the buffer). Case 5 is more or less similar but
will happen when the sample by be grown but we want to ensure we're not
bound by the current small size.
So the proposal is to have different functions for various operations. One
will ensure a sample is safe for use with str* functions. Another one will
ensure it may be rewritten in place. And smp_dup() will have to perform an
inconditional duplication to guarantee at least #5 above, and implicitly
all other ones.
This patch only modifies smp_dup() to make the duplication inconditional. It
is enough to fix both the "base" sample fetch and the "sni" server directive,
and all use cases in general though not always optimally. More patches will
follow to address them more optimally and even better than the current
situation (eg: avoid a dup just to add a \0 when possible).
The bug comes from an ambiguous design, so its roots are old. 1.6 is affected
and a backport is needed. In 1.5, the function already existed but was only
used by two converters modifying the data in place, so the bug has no effect
there.
2016-08-08 13:21:09 -04:00
|
|
|
|
2018-07-13 04:54:26 -04:00
|
|
|
memcpy(trash->area, smp->data.u.str.area, trash->data);
|
2015-08-19 03:07:19 -04:00
|
|
|
smp->data.u.str = *trash;
|
2013-12-16 18:20:33 -05:00
|
|
|
break;
|
2017-07-24 09:38:41 -04:00
|
|
|
|
2013-12-16 18:20:33 -05:00
|
|
|
default:
|
|
|
|
|
/* Other cases are unexpected. */
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2013-11-26 14:47:54 -05:00
|
|
|
|
2013-12-16 18:20:33 -05:00
|
|
|
/* remove const flag */
|
|
|
|
|
smp->flags &= ~SMP_F_CONST;
|
2010-09-23 12:02:19 -04:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-14 08:55:04 -05:00
|
|
|
int c_none(struct sample *smp)
|
2010-01-04 10:16:05 -05:00
|
|
|
{
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2012-04-23 16:03:39 -04:00
|
|
|
static int c_str2int(struct sample *smp)
|
2010-01-04 10:16:05 -05:00
|
|
|
{
|
2015-07-06 17:43:03 -04:00
|
|
|
const char *str;
|
|
|
|
|
const char *end;
|
2010-01-04 10:16:05 -05:00
|
|
|
|
2018-07-13 04:54:26 -04:00
|
|
|
if (smp->data.u.str.data == 0)
|
2014-01-27 12:20:48 -05:00
|
|
|
return 0;
|
|
|
|
|
|
2018-07-13 04:54:26 -04:00
|
|
|
str = smp->data.u.str.area;
|
|
|
|
|
end = smp->data.u.str.area + smp->data.u.str.data;
|
2010-01-04 10:16:05 -05:00
|
|
|
|
2015-08-19 03:07:19 -04:00
|
|
|
smp->data.u.sint = read_int64(&str, end);
|
2015-08-19 03:00:18 -04:00
|
|
|
smp->data.type = SMP_T_SINT;
|
2013-12-16 18:20:33 -05:00
|
|
|
smp->flags &= ~SMP_F_CONST;
|
2010-01-04 10:16:05 -05:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-16 19:10:10 -05:00
|
|
|
static int c_str2meth(struct sample *smp)
|
|
|
|
|
{
|
|
|
|
|
enum http_meth_t meth;
|
|
|
|
|
int len;
|
|
|
|
|
|
2018-07-13 04:54:26 -04:00
|
|
|
meth = find_http_meth(smp->data.u.str.area, smp->data.u.str.data);
|
2013-12-16 19:10:10 -05:00
|
|
|
if (meth == HTTP_METH_OTHER) {
|
2018-07-13 04:54:26 -04:00
|
|
|
len = smp->data.u.str.data;
|
|
|
|
|
smp->data.u.meth.str.area = smp->data.u.str.area;
|
|
|
|
|
smp->data.u.meth.str.data = len;
|
2013-12-16 19:10:10 -05:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
smp->flags &= ~SMP_F_CONST;
|
2015-08-19 03:07:19 -04:00
|
|
|
smp->data.u.meth.meth = meth;
|
2015-08-19 03:00:18 -04:00
|
|
|
smp->data.type = SMP_T_METH;
|
2013-12-16 19:10:10 -05:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int c_meth2str(struct sample *smp)
|
|
|
|
|
{
|
|
|
|
|
int len;
|
|
|
|
|
enum http_meth_t meth;
|
|
|
|
|
|
2015-08-19 03:07:19 -04:00
|
|
|
if (smp->data.u.meth.meth == HTTP_METH_OTHER) {
|
2013-12-16 19:10:10 -05:00
|
|
|
/* The method is unknown. Copy the original pointer. */
|
2018-07-13 04:54:26 -04:00
|
|
|
len = smp->data.u.meth.str.data;
|
|
|
|
|
smp->data.u.str.area = smp->data.u.meth.str.area;
|
|
|
|
|
smp->data.u.str.data = len;
|
2015-08-19 03:00:18 -04:00
|
|
|
smp->data.type = SMP_T_STR;
|
2013-12-16 19:10:10 -05:00
|
|
|
}
|
2015-08-19 03:07:19 -04:00
|
|
|
else if (smp->data.u.meth.meth < HTTP_METH_OTHER) {
|
2013-12-16 19:10:10 -05:00
|
|
|
/* The method is known, copy the pointer containing the string. */
|
2015-08-19 03:07:19 -04:00
|
|
|
meth = smp->data.u.meth.meth;
|
2018-09-10 09:38:55 -04:00
|
|
|
smp->data.u.str.area = http_known_methods[meth].ptr;
|
2018-07-13 04:54:26 -04:00
|
|
|
smp->data.u.str.data = http_known_methods[meth].len;
|
2013-12-16 19:10:10 -05:00
|
|
|
smp->flags |= SMP_F_CONST;
|
2015-08-19 03:00:18 -04:00
|
|
|
smp->data.type = SMP_T_STR;
|
2013-12-16 19:10:10 -05:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* Unknown method */
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-15 15:03:26 -04:00
|
|
|
static int c_addr2bin(struct sample *smp)
|
|
|
|
|
{
|
2018-07-13 05:56:34 -04:00
|
|
|
struct buffer *chk = get_trash_chunk();
|
2014-07-15 15:03:26 -04:00
|
|
|
|
2015-08-19 03:00:18 -04:00
|
|
|
if (smp->data.type == SMP_T_IPV4) {
|
2018-07-13 04:54:26 -04:00
|
|
|
chk->data = 4;
|
|
|
|
|
memcpy(chk->area, &smp->data.u.ipv4, chk->data);
|
2014-07-15 15:03:26 -04:00
|
|
|
}
|
2015-08-19 03:00:18 -04:00
|
|
|
else if (smp->data.type == SMP_T_IPV6) {
|
2018-07-13 04:54:26 -04:00
|
|
|
chk->data = 16;
|
|
|
|
|
memcpy(chk->area, &smp->data.u.ipv6, chk->data);
|
2014-07-15 15:03:26 -04:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return 0;
|
|
|
|
|
|
2015-08-19 03:07:19 -04:00
|
|
|
smp->data.u.str = *chk;
|
2015-08-19 03:00:18 -04:00
|
|
|
smp->data.type = SMP_T_BIN;
|
2014-07-15 15:03:26 -04:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-15 15:19:08 -04:00
|
|
|
static int c_int2bin(struct sample *smp)
|
|
|
|
|
{
|
2018-07-13 05:56:34 -04:00
|
|
|
struct buffer *chk = get_trash_chunk();
|
2014-07-15 15:19:08 -04:00
|
|
|
|
2018-07-13 04:54:26 -04:00
|
|
|
*(unsigned long long int *) chk->area = my_htonll(smp->data.u.sint);
|
|
|
|
|
chk->data = 8;
|
2014-07-15 15:19:08 -04:00
|
|
|
|
2015-08-19 03:07:19 -04:00
|
|
|
smp->data.u.str = *chk;
|
2015-08-19 03:00:18 -04:00
|
|
|
smp->data.type = SMP_T_BIN;
|
2014-07-15 15:19:08 -04:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-15 15:03:26 -04:00
|
|
|
|
2010-01-04 10:16:05 -05:00
|
|
|
/*****************************************************************/
|
2012-04-27 15:37:17 -04:00
|
|
|
/* Sample casts matrix: */
|
|
|
|
|
/* sample_casts[from type][to type] */
|
|
|
|
|
/* NULL pointer used for impossible sample casts */
|
2010-01-04 10:16:05 -05:00
|
|
|
/*****************************************************************/
|
|
|
|
|
|
2013-11-21 04:53:12 -05:00
|
|
|
sample_cast_fct sample_casts[SMP_TYPES][SMP_TYPES] = {
|
2015-07-06 17:43:03 -04:00
|
|
|
/* to: ANY BOOL SINT ADDR IPV4 IPV6 STR BIN METH */
|
|
|
|
|
/* from: ANY */ { c_none, c_none, c_none, c_none, c_none, c_none, c_none, c_none, c_none, },
|
|
|
|
|
/* BOOL */ { c_none, c_none, c_none, NULL, NULL, NULL, c_int2str, NULL, NULL, },
|
2015-07-24 03:04:56 -04:00
|
|
|
/* SINT */ { c_none, c_none, c_none, c_int2ip, c_int2ip, c_int2ipv6, c_int2str, c_int2bin, NULL, },
|
2015-07-06 17:43:03 -04:00
|
|
|
/* ADDR */ { c_none, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, },
|
|
|
|
|
/* IPV4 */ { c_none, NULL, c_ip2int, c_none, c_none, c_ip2ipv6, c_ip2str, c_addr2bin, NULL, },
|
2015-07-24 03:04:56 -04:00
|
|
|
/* IPV6 */ { c_none, NULL, NULL, c_none, c_ipv62ip,c_none, c_ipv62str, c_addr2bin, NULL, },
|
2015-07-06 17:43:03 -04:00
|
|
|
/* STR */ { c_none, c_str2int, c_str2int, c_str2addr, c_str2ip, c_str2ipv6, c_none, c_none, c_str2meth, },
|
|
|
|
|
/* BIN */ { c_none, NULL, NULL, NULL, NULL, NULL, c_bin2str, c_none, c_str2meth, },
|
|
|
|
|
/* METH */ { c_none, NULL, NULL, NULL, NULL, NULL, c_meth2str, c_meth2str, c_none, }
|
2010-06-06 07:22:23 -04:00
|
|
|
};
|
2010-01-04 10:16:05 -05:00
|
|
|
|
|
|
|
|
/*
|
2012-04-27 15:37:17 -04:00
|
|
|
* Parse a sample expression configuration:
|
2010-01-04 10:16:05 -05:00
|
|
|
* fetch keyword followed by format conversion keywords.
|
2012-04-27 15:37:17 -04:00
|
|
|
* Returns a pointer on allocated sample expression structure.
|
MAJOR: sample: maintain a per-proxy list of the fetch args to resolve
While ACL args were resolved after all the config was parsed, it was not the
case with sample fetch args because they're almost everywhere now.
The issue is that ACLs now solely rely on sample fetches, so their args
resolving doesn't work anymore. And many fetches involving a server, a
proxy or a userlist don't work at all.
The real issue is that at the bottom layers we have no information about
proxies, line numbers, even ACLs in order to report understandable errors,
and that at the top layers we have no visibility over the locations where
fetches are referenced (think log node).
After failing multiple unsatisfying solutions attempts, we now have a new
concept of args list. The principle is that every proxy has a list head
which contains a number of indications such as the config keyword, the
context where it's used, the file and line number, etc... and a list of
arguments. This list head is of the same type as the elements, so it
serves as a template for adding new elements. This way, it is filled from
top to bottom by the callers with the information they have (eg: line
numbers, ACL name, ...) and the lower layers just have to duplicate it and
add an element when they face an argument they cannot resolve yet.
Then at the end of the configuration parsing, a loop passes over each
proxy's list and resolves all the args in sequence. And this way there is
all necessary information to report verbose errors.
The first immediate benefit is that for the first time we got very precise
location of issues (arg number in a keyword in its context, ...). Second,
in order to do this we had to parse log-format and unique-id-format a bit
earlier, so that was a great opportunity for doing so when the directives
are encountered (unless it's a default section). This way, the recorded
line numbers for these args are the ones of the place where the log format
is declared, not the end of the file.
Userlists report slightly more information now. They're the only remaining
ones in the ACL resolving function.
2013-04-02 10:34:32 -04:00
|
|
|
* The caller must have set al->ctx.
|
2020-02-14 10:50:14 -05:00
|
|
|
* If <endptr> is non-nul, it will be set to the first unparsed character
|
|
|
|
|
* (which may be the final '\0') on success. If it is nul, the expression
|
|
|
|
|
* must be properly terminated by a '\0' otherwise an error is reported.
|
2010-01-04 10:16:05 -05:00
|
|
|
*/
|
2020-02-14 10:50:14 -05:00
|
|
|
struct sample_expr *sample_parse_expr(char **str, int *idx, const char *file, int line, char **err_msg, struct arg_list *al, char **endptr)
|
2010-01-04 10:16:05 -05:00
|
|
|
{
|
2013-07-24 09:34:19 -04:00
|
|
|
const char *begw; /* beginning of word */
|
|
|
|
|
const char *endw; /* end of word */
|
|
|
|
|
const char *endt; /* end of term */
|
2012-04-27 15:37:17 -04:00
|
|
|
struct sample_expr *expr;
|
|
|
|
|
struct sample_fetch *fetch;
|
|
|
|
|
struct sample_conv *conv;
|
2010-01-04 10:16:05 -05:00
|
|
|
unsigned long prev_type;
|
2013-07-24 09:34:19 -04:00
|
|
|
char *fkw = NULL;
|
|
|
|
|
char *ckw = NULL;
|
2013-12-12 18:40:11 -05:00
|
|
|
int err_arg;
|
2010-01-04 10:16:05 -05:00
|
|
|
|
2013-07-24 09:34:19 -04:00
|
|
|
begw = str[*idx];
|
2020-02-14 12:27:10 -05:00
|
|
|
for (endw = begw; is_idchar(*endw); endw++)
|
|
|
|
|
;
|
2013-07-24 09:34:19 -04:00
|
|
|
|
|
|
|
|
if (endw == begw) {
|
2013-12-12 17:16:54 -05:00
|
|
|
memprintf(err_msg, "missing fetch method");
|
2010-01-04 10:16:05 -05:00
|
|
|
goto out_error;
|
2010-09-23 12:02:19 -04:00
|
|
|
}
|
2010-01-04 10:16:05 -05:00
|
|
|
|
2013-07-24 09:34:19 -04:00
|
|
|
/* keep a copy of the current fetch keyword for error reporting */
|
|
|
|
|
fkw = my_strndup(begw, endw - begw);
|
2010-01-04 10:16:05 -05:00
|
|
|
|
2013-07-24 09:34:19 -04:00
|
|
|
fetch = find_sample_fetch(begw, endw - begw);
|
|
|
|
|
if (!fetch) {
|
2013-12-12 17:16:54 -05:00
|
|
|
memprintf(err_msg, "unknown fetch method '%s'", fkw);
|
2010-01-04 10:16:05 -05:00
|
|
|
goto out_error;
|
2010-09-23 12:02:19 -04:00
|
|
|
}
|
2010-01-04 10:16:05 -05:00
|
|
|
|
2013-07-24 09:34:19 -04:00
|
|
|
/* At this point, we have :
|
|
|
|
|
* - begw : beginning of the keyword
|
2013-12-12 18:40:11 -05:00
|
|
|
* - endw : end of the keyword, first character not part of keyword
|
2013-07-24 09:34:19 -04:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if (fetch->out_type >= SMP_TYPES) {
|
2013-12-12 17:16:54 -05:00
|
|
|
memprintf(err_msg, "returns type of fetch method '%s' is unknown", fkw);
|
2010-01-04 10:16:05 -05:00
|
|
|
goto out_error;
|
2010-09-23 12:02:19 -04:00
|
|
|
}
|
2010-01-04 10:16:05 -05:00
|
|
|
prev_type = fetch->out_type;
|
2013-07-24 09:34:19 -04:00
|
|
|
|
2016-04-03 07:48:43 -04:00
|
|
|
expr = calloc(1, sizeof(*expr));
|
2010-09-23 12:02:19 -04:00
|
|
|
if (!expr)
|
|
|
|
|
goto out_error;
|
2010-01-04 10:16:05 -05:00
|
|
|
|
|
|
|
|
LIST_INIT(&(expr->conv_exprs));
|
|
|
|
|
expr->fetch = fetch;
|
2012-10-19 13:49:09 -04:00
|
|
|
expr->arg_p = empty_arg_list;
|
2010-01-04 10:16:05 -05:00
|
|
|
|
2013-12-12 18:40:11 -05:00
|
|
|
/* Note that we call the argument parser even with an empty string,
|
|
|
|
|
* this allows it to automatically create entries for mandatory
|
|
|
|
|
* implicit arguments (eg: local proxy name).
|
|
|
|
|
*/
|
|
|
|
|
al->kw = expr->fetch->kw;
|
|
|
|
|
al->conv = NULL;
|
2020-02-14 02:40:37 -05:00
|
|
|
if (make_arg_list(endw, -1, fetch->arg_mask, &expr->arg_p, err_msg, &endt, &err_arg, al) < 0) {
|
2013-12-12 18:40:11 -05:00
|
|
|
memprintf(err_msg, "fetch method '%s' : %s", fkw, *err_msg);
|
|
|
|
|
goto out_error;
|
|
|
|
|
}
|
2012-10-19 13:49:09 -04:00
|
|
|
|
2020-02-14 02:40:37 -05:00
|
|
|
/* now endt is our first char not part of the arg list, typically the
|
|
|
|
|
* comma after the sample fetch name or after the closing parenthesis,
|
|
|
|
|
* or the NUL char.
|
|
|
|
|
*/
|
|
|
|
|
|
2013-12-12 18:40:11 -05:00
|
|
|
if (!expr->arg_p) {
|
|
|
|
|
expr->arg_p = empty_arg_list;
|
2010-09-23 12:02:19 -04:00
|
|
|
}
|
2013-12-12 18:40:11 -05:00
|
|
|
else if (fetch->val_args && !fetch->val_args(expr->arg_p, err_msg)) {
|
|
|
|
|
memprintf(err_msg, "invalid args in fetch method '%s' : %s", fkw, *err_msg);
|
2010-09-23 12:02:19 -04:00
|
|
|
goto out_error;
|
2010-01-04 10:16:05 -05:00
|
|
|
}
|
|
|
|
|
|
2013-07-24 09:34:19 -04:00
|
|
|
/* Now process the converters if any. We have two supported syntaxes
|
|
|
|
|
* for the converters, which can be combined :
|
|
|
|
|
* - comma-delimited list of converters just after the keyword and args ;
|
|
|
|
|
* - one converter per keyword
|
|
|
|
|
* The combination allows to have each keyword being a comma-delimited
|
|
|
|
|
* series of converters.
|
|
|
|
|
*
|
|
|
|
|
* We want to process the former first, then the latter. For this we start
|
|
|
|
|
* from the beginning of the supposed place in the exiting conv chain, which
|
|
|
|
|
* starts at the last comma (endt).
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
while (1) {
|
2012-04-27 15:37:17 -04:00
|
|
|
struct sample_conv_expr *conv_expr;
|
2019-12-17 04:25:29 -05:00
|
|
|
int err_arg;
|
|
|
|
|
int argcnt;
|
2010-01-04 10:16:05 -05:00
|
|
|
|
2013-07-24 09:34:19 -04:00
|
|
|
if (*endt && *endt != ',') {
|
2020-02-14 10:50:14 -05:00
|
|
|
if (endptr) {
|
|
|
|
|
/* end found, let's stop here */
|
|
|
|
|
break;
|
|
|
|
|
}
|
2013-07-24 09:34:19 -04:00
|
|
|
if (ckw)
|
2016-11-25 01:33:24 -05:00
|
|
|
memprintf(err_msg, "missing comma after converter '%s'", ckw);
|
2013-07-24 09:34:19 -04:00
|
|
|
else
|
2013-12-12 17:16:54 -05:00
|
|
|
memprintf(err_msg, "missing comma after fetch keyword '%s'", fkw);
|
2010-01-04 10:16:05 -05:00
|
|
|
goto out_error;
|
2010-09-23 12:02:19 -04:00
|
|
|
}
|
2010-01-04 10:16:05 -05:00
|
|
|
|
2020-02-14 02:40:37 -05:00
|
|
|
/* FIXME: how long should we support such idiocies ? Maybe we
|
|
|
|
|
* should already warn ?
|
|
|
|
|
*/
|
2013-07-24 09:34:19 -04:00
|
|
|
while (*endt == ',') /* then trailing commas */
|
|
|
|
|
endt++;
|
|
|
|
|
|
2016-11-25 01:33:24 -05:00
|
|
|
begw = endt; /* start of converter */
|
2013-07-24 09:34:19 -04:00
|
|
|
|
|
|
|
|
if (!*begw) {
|
|
|
|
|
/* none ? skip to next string */
|
|
|
|
|
(*idx)++;
|
|
|
|
|
begw = str[*idx];
|
|
|
|
|
if (!begw || !*begw)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-14 12:27:10 -05:00
|
|
|
for (endw = begw; is_idchar(*endw); endw++)
|
|
|
|
|
;
|
2013-07-24 09:34:19 -04:00
|
|
|
|
|
|
|
|
free(ckw);
|
|
|
|
|
ckw = my_strndup(begw, endw - begw);
|
|
|
|
|
|
|
|
|
|
conv = find_sample_conv(begw, endw - begw);
|
|
|
|
|
if (!conv) {
|
|
|
|
|
/* we found an isolated keyword that we don't know, it's not ours */
|
2020-02-14 10:50:14 -05:00
|
|
|
if (begw == str[*idx]) {
|
|
|
|
|
endt = begw;
|
2013-07-24 09:34:19 -04:00
|
|
|
break;
|
2020-02-14 10:50:14 -05:00
|
|
|
}
|
2016-11-25 01:33:24 -05:00
|
|
|
memprintf(err_msg, "unknown converter '%s'", ckw);
|
2013-07-24 09:34:19 -04:00
|
|
|
goto out_error;
|
|
|
|
|
}
|
2010-01-04 10:16:05 -05:00
|
|
|
|
2013-07-24 09:34:19 -04:00
|
|
|
if (conv->in_type >= SMP_TYPES || conv->out_type >= SMP_TYPES) {
|
2016-11-25 01:33:24 -05:00
|
|
|
memprintf(err_msg, "returns type of converter '%s' is unknown", ckw);
|
2010-01-04 10:16:05 -05:00
|
|
|
goto out_error;
|
2010-09-23 12:02:19 -04:00
|
|
|
}
|
2010-01-04 10:16:05 -05:00
|
|
|
|
|
|
|
|
/* If impossible type conversion */
|
2012-04-27 15:37:17 -04:00
|
|
|
if (!sample_casts[prev_type][conv->in_type]) {
|
2016-11-25 01:33:24 -05:00
|
|
|
memprintf(err_msg, "converter '%s' cannot be applied", ckw);
|
2010-01-04 10:16:05 -05:00
|
|
|
goto out_error;
|
2010-09-23 12:02:19 -04:00
|
|
|
}
|
2010-01-04 10:16:05 -05:00
|
|
|
|
|
|
|
|
prev_type = conv->out_type;
|
2016-04-03 07:48:43 -04:00
|
|
|
conv_expr = calloc(1, sizeof(*conv_expr));
|
2010-09-23 12:02:19 -04:00
|
|
|
if (!conv_expr)
|
|
|
|
|
goto out_error;
|
2010-01-04 10:16:05 -05:00
|
|
|
|
|
|
|
|
LIST_ADDQ(&(expr->conv_exprs), &(conv_expr->list));
|
|
|
|
|
conv_expr->conv = conv;
|
|
|
|
|
|
2019-12-17 04:25:29 -05:00
|
|
|
al->kw = expr->fetch->kw;
|
|
|
|
|
al->conv = conv_expr->conv->kw;
|
2020-02-14 02:40:37 -05:00
|
|
|
argcnt = make_arg_list(endw, -1, conv->arg_mask, &conv_expr->arg_p, err_msg, &endt, &err_arg, al);
|
2019-12-17 04:25:29 -05:00
|
|
|
if (argcnt < 0) {
|
|
|
|
|
memprintf(err_msg, "invalid arg %d in converter '%s' : %s", err_arg+1, ckw, *err_msg);
|
|
|
|
|
goto out_error;
|
|
|
|
|
}
|
2010-09-23 12:02:19 -04:00
|
|
|
|
2019-12-17 04:25:29 -05:00
|
|
|
if (argcnt && !conv->arg_mask) {
|
|
|
|
|
memprintf(err_msg, "converter '%s' does not support any args", ckw);
|
|
|
|
|
goto out_error;
|
|
|
|
|
}
|
2012-04-20 09:52:36 -04:00
|
|
|
|
2019-12-17 04:25:29 -05:00
|
|
|
if (!conv_expr->arg_p)
|
|
|
|
|
conv_expr->arg_p = empty_arg_list;
|
2012-10-19 13:49:09 -04:00
|
|
|
|
2019-12-17 04:25:29 -05:00
|
|
|
if (conv->val_args && !conv->val_args(conv_expr->arg_p, conv, file, line, err_msg)) {
|
|
|
|
|
memprintf(err_msg, "invalid args in converter '%s' : %s", ckw, *err_msg);
|
2010-09-23 12:02:19 -04:00
|
|
|
goto out_error;
|
2010-01-04 10:16:05 -05:00
|
|
|
}
|
|
|
|
|
}
|
2010-09-23 12:02:19 -04:00
|
|
|
|
2020-02-14 10:50:14 -05:00
|
|
|
if (endptr) {
|
|
|
|
|
/* end found, let's stop here */
|
|
|
|
|
*endptr = (char *)endt;
|
|
|
|
|
}
|
|
|
|
|
|
2013-07-24 09:34:19 -04:00
|
|
|
out:
|
|
|
|
|
free(fkw);
|
|
|
|
|
free(ckw);
|
2010-01-04 10:16:05 -05:00
|
|
|
return expr;
|
|
|
|
|
|
|
|
|
|
out_error:
|
2012-04-27 15:37:17 -04:00
|
|
|
/* TODO: prune_sample_expr(expr); */
|
2013-07-24 09:34:19 -04:00
|
|
|
expr = NULL;
|
|
|
|
|
goto out;
|
2010-01-04 10:16:05 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
2012-04-27 15:37:17 -04:00
|
|
|
* Process a fetch + format conversion of defined by the sample expression <expr>
|
2012-04-25 04:13:36 -04:00
|
|
|
* on request or response considering the <opt> parameter.
|
2012-04-27 15:37:17 -04:00
|
|
|
* Returns a pointer on a typed sample structure containing the result or NULL if
|
|
|
|
|
* sample is not found or when format conversion failed.
|
2010-01-04 10:16:05 -05:00
|
|
|
* If <p> is not null, function returns results in structure pointed by <p>.
|
2012-04-27 15:37:17 -04:00
|
|
|
* If <p> is null, functions returns a pointer on a static sample structure.
|
2012-04-23 16:38:26 -04:00
|
|
|
*
|
|
|
|
|
* Note: the fetch functions are required to properly set the return type. The
|
|
|
|
|
* conversion functions must do so too. However the cast functions do not need
|
|
|
|
|
* to since they're made to cast mutiple types according to what is required.
|
2014-07-30 02:56:35 -04:00
|
|
|
*
|
|
|
|
|
* The caller may indicate in <opt> if it considers the result final or not.
|
|
|
|
|
* The caller needs to check the SMP_F_MAY_CHANGE flag in p->flags to verify
|
|
|
|
|
* if the result is stable or not, according to the following table :
|
|
|
|
|
*
|
|
|
|
|
* return MAY_CHANGE FINAL Meaning for the sample
|
|
|
|
|
* NULL 0 * Not present and will never be (eg: header)
|
|
|
|
|
* NULL 1 0 Not present yet, could change (eg: POST param)
|
|
|
|
|
* NULL 1 1 Not present yet, will not change anymore
|
|
|
|
|
* smp 0 * Present and will not change (eg: header)
|
|
|
|
|
* smp 1 0 Present, may change (eg: request length)
|
|
|
|
|
* smp 1 1 Present, last known value (eg: request length)
|
2010-01-04 10:16:05 -05:00
|
|
|
*/
|
2015-04-03 19:47:55 -04:00
|
|
|
struct sample *sample_process(struct proxy *px, struct session *sess,
|
|
|
|
|
struct stream *strm, unsigned int opt,
|
2012-04-27 15:37:17 -04:00
|
|
|
struct sample_expr *expr, struct sample *p)
|
2010-01-04 10:16:05 -05:00
|
|
|
{
|
2012-04-27 15:37:17 -04:00
|
|
|
struct sample_conv_expr *conv_expr;
|
2010-01-04 10:16:05 -05:00
|
|
|
|
2013-07-25 06:02:38 -04:00
|
|
|
if (p == NULL) {
|
2012-04-23 15:35:11 -04:00
|
|
|
p = &temp_smp;
|
2014-06-25 10:56:41 -04:00
|
|
|
memset(p, 0, sizeof(*p));
|
2013-07-25 06:02:38 -04:00
|
|
|
}
|
2010-01-04 10:16:05 -05:00
|
|
|
|
2016-03-10 10:15:46 -05:00
|
|
|
smp_set_owner(p, px, sess, strm, opt);
|
2015-05-11 09:42:45 -04:00
|
|
|
if (!expr->fetch->process(expr->arg_p, p, expr->fetch->kw, expr->fetch->private))
|
2010-01-04 10:16:05 -05:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
list_for_each_entry(conv_expr, &expr->conv_exprs, list) {
|
2012-04-25 11:21:49 -04:00
|
|
|
/* we want to ensure that p->type can be casted into
|
|
|
|
|
* conv_expr->conv->in_type. We have 3 possibilities :
|
|
|
|
|
* - NULL => not castable.
|
|
|
|
|
* - c_none => nothing to do (let's optimize it)
|
|
|
|
|
* - other => apply cast and prepare to fail
|
|
|
|
|
*/
|
2015-08-19 03:00:18 -04:00
|
|
|
if (!sample_casts[p->data.type][conv_expr->conv->in_type])
|
2010-01-04 10:16:05 -05:00
|
|
|
return NULL;
|
|
|
|
|
|
2015-08-19 03:00:18 -04:00
|
|
|
if (sample_casts[p->data.type][conv_expr->conv->in_type] != c_none &&
|
|
|
|
|
!sample_casts[p->data.type][conv_expr->conv->in_type](p))
|
2012-04-25 11:21:49 -04:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
/* OK cast succeeded */
|
|
|
|
|
|
2015-05-11 09:20:49 -04:00
|
|
|
if (!conv_expr->conv->process(conv_expr->arg_p, p, conv_expr->conv->private))
|
2010-01-04 10:16:05 -05:00
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
return p;
|
|
|
|
|
}
|
|
|
|
|
|
MAJOR: sample: maintain a per-proxy list of the fetch args to resolve
While ACL args were resolved after all the config was parsed, it was not the
case with sample fetch args because they're almost everywhere now.
The issue is that ACLs now solely rely on sample fetches, so their args
resolving doesn't work anymore. And many fetches involving a server, a
proxy or a userlist don't work at all.
The real issue is that at the bottom layers we have no information about
proxies, line numbers, even ACLs in order to report understandable errors,
and that at the top layers we have no visibility over the locations where
fetches are referenced (think log node).
After failing multiple unsatisfying solutions attempts, we now have a new
concept of args list. The principle is that every proxy has a list head
which contains a number of indications such as the config keyword, the
context where it's used, the file and line number, etc... and a list of
arguments. This list head is of the same type as the elements, so it
serves as a template for adding new elements. This way, it is filled from
top to bottom by the callers with the information they have (eg: line
numbers, ACL name, ...) and the lower layers just have to duplicate it and
add an element when they face an argument they cannot resolve yet.
Then at the end of the configuration parsing, a loop passes over each
proxy's list and resolves all the args in sequence. And this way there is
all necessary information to report verbose errors.
The first immediate benefit is that for the first time we got very precise
location of issues (arg number in a keyword in its context, ...). Second,
in order to do this we had to parse log-format and unique-id-format a bit
earlier, so that was a great opportunity for doing so when the directives
are encountered (unless it's a default section). This way, the recorded
line numbers for these args are the ones of the place where the log format
is declared, not the end of the file.
Userlists report slightly more information now. They're the only remaining
ones in the ACL resolving function.
2013-04-02 10:34:32 -04:00
|
|
|
/*
|
|
|
|
|
* Resolve all remaining arguments in proxy <p>. Returns the number of
|
|
|
|
|
* errors or 0 if everything is fine.
|
|
|
|
|
*/
|
|
|
|
|
int smp_resolve_args(struct proxy *p)
|
|
|
|
|
{
|
|
|
|
|
struct arg_list *cur, *bak;
|
|
|
|
|
const char *ctx, *where;
|
|
|
|
|
const char *conv_ctx, *conv_pre, *conv_pos;
|
|
|
|
|
struct userlist *ul;
|
2015-01-19 13:00:58 -05:00
|
|
|
struct my_regex *reg;
|
MAJOR: sample: maintain a per-proxy list of the fetch args to resolve
While ACL args were resolved after all the config was parsed, it was not the
case with sample fetch args because they're almost everywhere now.
The issue is that ACLs now solely rely on sample fetches, so their args
resolving doesn't work anymore. And many fetches involving a server, a
proxy or a userlist don't work at all.
The real issue is that at the bottom layers we have no information about
proxies, line numbers, even ACLs in order to report understandable errors,
and that at the top layers we have no visibility over the locations where
fetches are referenced (think log node).
After failing multiple unsatisfying solutions attempts, we now have a new
concept of args list. The principle is that every proxy has a list head
which contains a number of indications such as the config keyword, the
context where it's used, the file and line number, etc... and a list of
arguments. This list head is of the same type as the elements, so it
serves as a template for adding new elements. This way, it is filled from
top to bottom by the callers with the information they have (eg: line
numbers, ACL name, ...) and the lower layers just have to duplicate it and
add an element when they face an argument they cannot resolve yet.
Then at the end of the configuration parsing, a loop passes over each
proxy's list and resolves all the args in sequence. And this way there is
all necessary information to report verbose errors.
The first immediate benefit is that for the first time we got very precise
location of issues (arg number in a keyword in its context, ...). Second,
in order to do this we had to parse log-format and unique-id-format a bit
earlier, so that was a great opportunity for doing so when the directives
are encountered (unless it's a default section). This way, the recorded
line numbers for these args are the ones of the place where the log format
is declared, not the end of the file.
Userlists report slightly more information now. They're the only remaining
ones in the ACL resolving function.
2013-04-02 10:34:32 -04:00
|
|
|
struct arg *arg;
|
|
|
|
|
int cfgerr = 0;
|
2015-01-19 13:00:58 -05:00
|
|
|
int rflags;
|
MAJOR: sample: maintain a per-proxy list of the fetch args to resolve
While ACL args were resolved after all the config was parsed, it was not the
case with sample fetch args because they're almost everywhere now.
The issue is that ACLs now solely rely on sample fetches, so their args
resolving doesn't work anymore. And many fetches involving a server, a
proxy or a userlist don't work at all.
The real issue is that at the bottom layers we have no information about
proxies, line numbers, even ACLs in order to report understandable errors,
and that at the top layers we have no visibility over the locations where
fetches are referenced (think log node).
After failing multiple unsatisfying solutions attempts, we now have a new
concept of args list. The principle is that every proxy has a list head
which contains a number of indications such as the config keyword, the
context where it's used, the file and line number, etc... and a list of
arguments. This list head is of the same type as the elements, so it
serves as a template for adding new elements. This way, it is filled from
top to bottom by the callers with the information they have (eg: line
numbers, ACL name, ...) and the lower layers just have to duplicate it and
add an element when they face an argument they cannot resolve yet.
Then at the end of the configuration parsing, a loop passes over each
proxy's list and resolves all the args in sequence. And this way there is
all necessary information to report verbose errors.
The first immediate benefit is that for the first time we got very precise
location of issues (arg number in a keyword in its context, ...). Second,
in order to do this we had to parse log-format and unique-id-format a bit
earlier, so that was a great opportunity for doing so when the directives
are encountered (unless it's a default section). This way, the recorded
line numbers for these args are the ones of the place where the log format
is declared, not the end of the file.
Userlists report slightly more information now. They're the only remaining
ones in the ACL resolving function.
2013-04-02 10:34:32 -04:00
|
|
|
|
|
|
|
|
list_for_each_entry_safe(cur, bak, &p->conf.args.list, list) {
|
|
|
|
|
struct proxy *px;
|
|
|
|
|
struct server *srv;
|
2019-03-14 02:07:41 -04:00
|
|
|
struct stktable *t;
|
|
|
|
|
char *pname, *sname, *stktname;
|
2015-01-19 13:00:58 -05:00
|
|
|
char *err;
|
MAJOR: sample: maintain a per-proxy list of the fetch args to resolve
While ACL args were resolved after all the config was parsed, it was not the
case with sample fetch args because they're almost everywhere now.
The issue is that ACLs now solely rely on sample fetches, so their args
resolving doesn't work anymore. And many fetches involving a server, a
proxy or a userlist don't work at all.
The real issue is that at the bottom layers we have no information about
proxies, line numbers, even ACLs in order to report understandable errors,
and that at the top layers we have no visibility over the locations where
fetches are referenced (think log node).
After failing multiple unsatisfying solutions attempts, we now have a new
concept of args list. The principle is that every proxy has a list head
which contains a number of indications such as the config keyword, the
context where it's used, the file and line number, etc... and a list of
arguments. This list head is of the same type as the elements, so it
serves as a template for adding new elements. This way, it is filled from
top to bottom by the callers with the information they have (eg: line
numbers, ACL name, ...) and the lower layers just have to duplicate it and
add an element when they face an argument they cannot resolve yet.
Then at the end of the configuration parsing, a loop passes over each
proxy's list and resolves all the args in sequence. And this way there is
all necessary information to report verbose errors.
The first immediate benefit is that for the first time we got very precise
location of issues (arg number in a keyword in its context, ...). Second,
in order to do this we had to parse log-format and unique-id-format a bit
earlier, so that was a great opportunity for doing so when the directives
are encountered (unless it's a default section). This way, the recorded
line numbers for these args are the ones of the place where the log format
is declared, not the end of the file.
Userlists report slightly more information now. They're the only remaining
ones in the ACL resolving function.
2013-04-02 10:34:32 -04:00
|
|
|
|
|
|
|
|
arg = cur->arg;
|
|
|
|
|
|
|
|
|
|
/* prepare output messages */
|
|
|
|
|
conv_pre = conv_pos = conv_ctx = "";
|
|
|
|
|
if (cur->conv) {
|
|
|
|
|
conv_ctx = cur->conv;
|
|
|
|
|
conv_pre = "conversion keyword '";
|
|
|
|
|
conv_pos = "' for ";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
where = "in";
|
|
|
|
|
ctx = "sample fetch keyword";
|
|
|
|
|
switch (cur->ctx) {
|
2015-09-25 13:17:44 -04:00
|
|
|
case ARGC_STK: where = "in stick rule in"; break;
|
|
|
|
|
case ARGC_TRK: where = "in tracking rule in"; break;
|
|
|
|
|
case ARGC_LOG: where = "in log-format string in"; break;
|
|
|
|
|
case ARGC_LOGSD: where = "in log-format-sd string in"; break;
|
|
|
|
|
case ARGC_HRQ: where = "in http-request header format string in"; break;
|
|
|
|
|
case ARGC_HRS: where = "in http-response header format string in"; break;
|
|
|
|
|
case ARGC_UIF: where = "in unique-id-format string in"; break;
|
|
|
|
|
case ARGC_RDR: where = "in redirect format string in"; break;
|
|
|
|
|
case ARGC_CAP: where = "in capture rule in"; break;
|
|
|
|
|
case ARGC_ACL: ctx = "ACL keyword"; break;
|
|
|
|
|
case ARGC_SRV: where = "in server directive in"; break;
|
MAJOR: spoe: Add an experimental Stream Processing Offload Engine
SPOE makes possible the communication with external components to retrieve some
info using an in-house binary protocol, the Stream Processing Offload Protocol
(SPOP). In the long term, its aim is to allow any kind of offloading on the
streams. This first version, besides being experimental, won't do lot of
things. The most important today is to validate the protocol design and lay the
foundations of what will, one day, be a full offload engine for the stream
processing.
So, for now, the SPOE can offload the stream processing before "tcp-request
content", "tcp-response content", "http-request" and "http-response" rules. And
it only supports variables creation/suppression. But, in spite of these limited
features, we can easily imagine to implement a SSO solution, an ip reputation
service or an ip geolocation service.
Internally, the SPOE is implemented as a filter. So, to use it, you must use
following line in a proxy proxy section:
frontend my-front
...
filter spoe [engine <name>] config <file>
...
It uses its own configuration file to keep the HAProxy configuration clean. It
is also a easy way to disable it by commenting out the filter line.
See "doc/SPOE.txt" for all details about the SPOE configuration.
2016-10-27 16:29:49 -04:00
|
|
|
case ARGC_SPOE: where = "in spoe-message directive in"; break;
|
MAJOR: sample: maintain a per-proxy list of the fetch args to resolve
While ACL args were resolved after all the config was parsed, it was not the
case with sample fetch args because they're almost everywhere now.
The issue is that ACLs now solely rely on sample fetches, so their args
resolving doesn't work anymore. And many fetches involving a server, a
proxy or a userlist don't work at all.
The real issue is that at the bottom layers we have no information about
proxies, line numbers, even ACLs in order to report understandable errors,
and that at the top layers we have no visibility over the locations where
fetches are referenced (think log node).
After failing multiple unsatisfying solutions attempts, we now have a new
concept of args list. The principle is that every proxy has a list head
which contains a number of indications such as the config keyword, the
context where it's used, the file and line number, etc... and a list of
arguments. This list head is of the same type as the elements, so it
serves as a template for adding new elements. This way, it is filled from
top to bottom by the callers with the information they have (eg: line
numbers, ACL name, ...) and the lower layers just have to duplicate it and
add an element when they face an argument they cannot resolve yet.
Then at the end of the configuration parsing, a loop passes over each
proxy's list and resolves all the args in sequence. And this way there is
all necessary information to report verbose errors.
The first immediate benefit is that for the first time we got very precise
location of issues (arg number in a keyword in its context, ...). Second,
in order to do this we had to parse log-format and unique-id-format a bit
earlier, so that was a great opportunity for doing so when the directives
are encountered (unless it's a default section). This way, the recorded
line numbers for these args are the ones of the place where the log format
is declared, not the end of the file.
Userlists report slightly more information now. They're the only remaining
ones in the ACL resolving function.
2013-04-02 10:34:32 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* set a few default settings */
|
|
|
|
|
px = p;
|
|
|
|
|
pname = p->id;
|
|
|
|
|
|
|
|
|
|
switch (arg->type) {
|
|
|
|
|
case ARGT_SRV:
|
2018-07-13 04:54:26 -04:00
|
|
|
if (!arg->data.str.data) {
|
2017-11-24 10:50:31 -05:00
|
|
|
ha_alert("parsing [%s:%d] : missing server name in arg %d of %s%s%s%s '%s' %s proxy '%s'.\n",
|
|
|
|
|
cur->file, cur->line,
|
|
|
|
|
cur->arg_pos + 1, conv_pre, conv_ctx, conv_pos, ctx, cur->kw, where, p->id);
|
MAJOR: sample: maintain a per-proxy list of the fetch args to resolve
While ACL args were resolved after all the config was parsed, it was not the
case with sample fetch args because they're almost everywhere now.
The issue is that ACLs now solely rely on sample fetches, so their args
resolving doesn't work anymore. And many fetches involving a server, a
proxy or a userlist don't work at all.
The real issue is that at the bottom layers we have no information about
proxies, line numbers, even ACLs in order to report understandable errors,
and that at the top layers we have no visibility over the locations where
fetches are referenced (think log node).
After failing multiple unsatisfying solutions attempts, we now have a new
concept of args list. The principle is that every proxy has a list head
which contains a number of indications such as the config keyword, the
context where it's used, the file and line number, etc... and a list of
arguments. This list head is of the same type as the elements, so it
serves as a template for adding new elements. This way, it is filled from
top to bottom by the callers with the information they have (eg: line
numbers, ACL name, ...) and the lower layers just have to duplicate it and
add an element when they face an argument they cannot resolve yet.
Then at the end of the configuration parsing, a loop passes over each
proxy's list and resolves all the args in sequence. And this way there is
all necessary information to report verbose errors.
The first immediate benefit is that for the first time we got very precise
location of issues (arg number in a keyword in its context, ...). Second,
in order to do this we had to parse log-format and unique-id-format a bit
earlier, so that was a great opportunity for doing so when the directives
are encountered (unless it's a default section). This way, the recorded
line numbers for these args are the ones of the place where the log format
is declared, not the end of the file.
Userlists report slightly more information now. They're the only remaining
ones in the ACL resolving function.
2013-04-02 10:34:32 -04:00
|
|
|
cfgerr++;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* we support two formats : "bck/srv" and "srv" */
|
2018-07-13 04:54:26 -04:00
|
|
|
sname = strrchr(arg->data.str.area, '/');
|
MAJOR: sample: maintain a per-proxy list of the fetch args to resolve
While ACL args were resolved after all the config was parsed, it was not the
case with sample fetch args because they're almost everywhere now.
The issue is that ACLs now solely rely on sample fetches, so their args
resolving doesn't work anymore. And many fetches involving a server, a
proxy or a userlist don't work at all.
The real issue is that at the bottom layers we have no information about
proxies, line numbers, even ACLs in order to report understandable errors,
and that at the top layers we have no visibility over the locations where
fetches are referenced (think log node).
After failing multiple unsatisfying solutions attempts, we now have a new
concept of args list. The principle is that every proxy has a list head
which contains a number of indications such as the config keyword, the
context where it's used, the file and line number, etc... and a list of
arguments. This list head is of the same type as the elements, so it
serves as a template for adding new elements. This way, it is filled from
top to bottom by the callers with the information they have (eg: line
numbers, ACL name, ...) and the lower layers just have to duplicate it and
add an element when they face an argument they cannot resolve yet.
Then at the end of the configuration parsing, a loop passes over each
proxy's list and resolves all the args in sequence. And this way there is
all necessary information to report verbose errors.
The first immediate benefit is that for the first time we got very precise
location of issues (arg number in a keyword in its context, ...). Second,
in order to do this we had to parse log-format and unique-id-format a bit
earlier, so that was a great opportunity for doing so when the directives
are encountered (unless it's a default section). This way, the recorded
line numbers for these args are the ones of the place where the log format
is declared, not the end of the file.
Userlists report slightly more information now. They're the only remaining
ones in the ACL resolving function.
2013-04-02 10:34:32 -04:00
|
|
|
|
|
|
|
|
if (sname) {
|
|
|
|
|
*sname++ = '\0';
|
2018-07-13 04:54:26 -04:00
|
|
|
pname = arg->data.str.area;
|
MAJOR: sample: maintain a per-proxy list of the fetch args to resolve
While ACL args were resolved after all the config was parsed, it was not the
case with sample fetch args because they're almost everywhere now.
The issue is that ACLs now solely rely on sample fetches, so their args
resolving doesn't work anymore. And many fetches involving a server, a
proxy or a userlist don't work at all.
The real issue is that at the bottom layers we have no information about
proxies, line numbers, even ACLs in order to report understandable errors,
and that at the top layers we have no visibility over the locations where
fetches are referenced (think log node).
After failing multiple unsatisfying solutions attempts, we now have a new
concept of args list. The principle is that every proxy has a list head
which contains a number of indications such as the config keyword, the
context where it's used, the file and line number, etc... and a list of
arguments. This list head is of the same type as the elements, so it
serves as a template for adding new elements. This way, it is filled from
top to bottom by the callers with the information they have (eg: line
numbers, ACL name, ...) and the lower layers just have to duplicate it and
add an element when they face an argument they cannot resolve yet.
Then at the end of the configuration parsing, a loop passes over each
proxy's list and resolves all the args in sequence. And this way there is
all necessary information to report verbose errors.
The first immediate benefit is that for the first time we got very precise
location of issues (arg number in a keyword in its context, ...). Second,
in order to do this we had to parse log-format and unique-id-format a bit
earlier, so that was a great opportunity for doing so when the directives
are encountered (unless it's a default section). This way, the recorded
line numbers for these args are the ones of the place where the log format
is declared, not the end of the file.
Userlists report slightly more information now. They're the only remaining
ones in the ACL resolving function.
2013-04-02 10:34:32 -04:00
|
|
|
|
2015-05-26 05:24:42 -04:00
|
|
|
px = proxy_be_by_name(pname);
|
MAJOR: sample: maintain a per-proxy list of the fetch args to resolve
While ACL args were resolved after all the config was parsed, it was not the
case with sample fetch args because they're almost everywhere now.
The issue is that ACLs now solely rely on sample fetches, so their args
resolving doesn't work anymore. And many fetches involving a server, a
proxy or a userlist don't work at all.
The real issue is that at the bottom layers we have no information about
proxies, line numbers, even ACLs in order to report understandable errors,
and that at the top layers we have no visibility over the locations where
fetches are referenced (think log node).
After failing multiple unsatisfying solutions attempts, we now have a new
concept of args list. The principle is that every proxy has a list head
which contains a number of indications such as the config keyword, the
context where it's used, the file and line number, etc... and a list of
arguments. This list head is of the same type as the elements, so it
serves as a template for adding new elements. This way, it is filled from
top to bottom by the callers with the information they have (eg: line
numbers, ACL name, ...) and the lower layers just have to duplicate it and
add an element when they face an argument they cannot resolve yet.
Then at the end of the configuration parsing, a loop passes over each
proxy's list and resolves all the args in sequence. And this way there is
all necessary information to report verbose errors.
The first immediate benefit is that for the first time we got very precise
location of issues (arg number in a keyword in its context, ...). Second,
in order to do this we had to parse log-format and unique-id-format a bit
earlier, so that was a great opportunity for doing so when the directives
are encountered (unless it's a default section). This way, the recorded
line numbers for these args are the ones of the place where the log format
is declared, not the end of the file.
Userlists report slightly more information now. They're the only remaining
ones in the ACL resolving function.
2013-04-02 10:34:32 -04:00
|
|
|
if (!px) {
|
2017-11-24 10:50:31 -05:00
|
|
|
ha_alert("parsing [%s:%d] : unable to find proxy '%s' referenced in arg %d of %s%s%s%s '%s' %s proxy '%s'.\n",
|
|
|
|
|
cur->file, cur->line, pname,
|
|
|
|
|
cur->arg_pos + 1, conv_pre, conv_ctx, conv_pos, ctx, cur->kw, where, p->id);
|
MAJOR: sample: maintain a per-proxy list of the fetch args to resolve
While ACL args were resolved after all the config was parsed, it was not the
case with sample fetch args because they're almost everywhere now.
The issue is that ACLs now solely rely on sample fetches, so their args
resolving doesn't work anymore. And many fetches involving a server, a
proxy or a userlist don't work at all.
The real issue is that at the bottom layers we have no information about
proxies, line numbers, even ACLs in order to report understandable errors,
and that at the top layers we have no visibility over the locations where
fetches are referenced (think log node).
After failing multiple unsatisfying solutions attempts, we now have a new
concept of args list. The principle is that every proxy has a list head
which contains a number of indications such as the config keyword, the
context where it's used, the file and line number, etc... and a list of
arguments. This list head is of the same type as the elements, so it
serves as a template for adding new elements. This way, it is filled from
top to bottom by the callers with the information they have (eg: line
numbers, ACL name, ...) and the lower layers just have to duplicate it and
add an element when they face an argument they cannot resolve yet.
Then at the end of the configuration parsing, a loop passes over each
proxy's list and resolves all the args in sequence. And this way there is
all necessary information to report verbose errors.
The first immediate benefit is that for the first time we got very precise
location of issues (arg number in a keyword in its context, ...). Second,
in order to do this we had to parse log-format and unique-id-format a bit
earlier, so that was a great opportunity for doing so when the directives
are encountered (unless it's a default section). This way, the recorded
line numbers for these args are the ones of the place where the log format
is declared, not the end of the file.
Userlists report slightly more information now. They're the only remaining
ones in the ACL resolving function.
2013-04-02 10:34:32 -04:00
|
|
|
cfgerr++;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
2018-07-13 04:54:26 -04:00
|
|
|
sname = arg->data.str.area;
|
MAJOR: sample: maintain a per-proxy list of the fetch args to resolve
While ACL args were resolved after all the config was parsed, it was not the
case with sample fetch args because they're almost everywhere now.
The issue is that ACLs now solely rely on sample fetches, so their args
resolving doesn't work anymore. And many fetches involving a server, a
proxy or a userlist don't work at all.
The real issue is that at the bottom layers we have no information about
proxies, line numbers, even ACLs in order to report understandable errors,
and that at the top layers we have no visibility over the locations where
fetches are referenced (think log node).
After failing multiple unsatisfying solutions attempts, we now have a new
concept of args list. The principle is that every proxy has a list head
which contains a number of indications such as the config keyword, the
context where it's used, the file and line number, etc... and a list of
arguments. This list head is of the same type as the elements, so it
serves as a template for adding new elements. This way, it is filled from
top to bottom by the callers with the information they have (eg: line
numbers, ACL name, ...) and the lower layers just have to duplicate it and
add an element when they face an argument they cannot resolve yet.
Then at the end of the configuration parsing, a loop passes over each
proxy's list and resolves all the args in sequence. And this way there is
all necessary information to report verbose errors.
The first immediate benefit is that for the first time we got very precise
location of issues (arg number in a keyword in its context, ...). Second,
in order to do this we had to parse log-format and unique-id-format a bit
earlier, so that was a great opportunity for doing so when the directives
are encountered (unless it's a default section). This way, the recorded
line numbers for these args are the ones of the place where the log format
is declared, not the end of the file.
Userlists report slightly more information now. They're the only remaining
ones in the ACL resolving function.
2013-04-02 10:34:32 -04:00
|
|
|
|
|
|
|
|
srv = findserver(px, sname);
|
|
|
|
|
if (!srv) {
|
2017-11-24 10:50:31 -05:00
|
|
|
ha_alert("parsing [%s:%d] : unable to find server '%s' in proxy '%s', referenced in arg %d of %s%s%s%s '%s' %s proxy '%s'.\n",
|
|
|
|
|
cur->file, cur->line, sname, pname,
|
|
|
|
|
cur->arg_pos + 1, conv_pre, conv_ctx, conv_pos, ctx, cur->kw, where, p->id);
|
MAJOR: sample: maintain a per-proxy list of the fetch args to resolve
While ACL args were resolved after all the config was parsed, it was not the
case with sample fetch args because they're almost everywhere now.
The issue is that ACLs now solely rely on sample fetches, so their args
resolving doesn't work anymore. And many fetches involving a server, a
proxy or a userlist don't work at all.
The real issue is that at the bottom layers we have no information about
proxies, line numbers, even ACLs in order to report understandable errors,
and that at the top layers we have no visibility over the locations where
fetches are referenced (think log node).
After failing multiple unsatisfying solutions attempts, we now have a new
concept of args list. The principle is that every proxy has a list head
which contains a number of indications such as the config keyword, the
context where it's used, the file and line number, etc... and a list of
arguments. This list head is of the same type as the elements, so it
serves as a template for adding new elements. This way, it is filled from
top to bottom by the callers with the information they have (eg: line
numbers, ACL name, ...) and the lower layers just have to duplicate it and
add an element when they face an argument they cannot resolve yet.
Then at the end of the configuration parsing, a loop passes over each
proxy's list and resolves all the args in sequence. And this way there is
all necessary information to report verbose errors.
The first immediate benefit is that for the first time we got very precise
location of issues (arg number in a keyword in its context, ...). Second,
in order to do this we had to parse log-format and unique-id-format a bit
earlier, so that was a great opportunity for doing so when the directives
are encountered (unless it's a default section). This way, the recorded
line numbers for these args are the ones of the place where the log format
is declared, not the end of the file.
Userlists report slightly more information now. They're the only remaining
ones in the ACL resolving function.
2013-04-02 10:34:32 -04:00
|
|
|
cfgerr++;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-13 04:54:26 -04:00
|
|
|
free(arg->data.str.area);
|
|
|
|
|
arg->data.str.area = NULL;
|
MAJOR: sample: maintain a per-proxy list of the fetch args to resolve
While ACL args were resolved after all the config was parsed, it was not the
case with sample fetch args because they're almost everywhere now.
The issue is that ACLs now solely rely on sample fetches, so their args
resolving doesn't work anymore. And many fetches involving a server, a
proxy or a userlist don't work at all.
The real issue is that at the bottom layers we have no information about
proxies, line numbers, even ACLs in order to report understandable errors,
and that at the top layers we have no visibility over the locations where
fetches are referenced (think log node).
After failing multiple unsatisfying solutions attempts, we now have a new
concept of args list. The principle is that every proxy has a list head
which contains a number of indications such as the config keyword, the
context where it's used, the file and line number, etc... and a list of
arguments. This list head is of the same type as the elements, so it
serves as a template for adding new elements. This way, it is filled from
top to bottom by the callers with the information they have (eg: line
numbers, ACL name, ...) and the lower layers just have to duplicate it and
add an element when they face an argument they cannot resolve yet.
Then at the end of the configuration parsing, a loop passes over each
proxy's list and resolves all the args in sequence. And this way there is
all necessary information to report verbose errors.
The first immediate benefit is that for the first time we got very precise
location of issues (arg number in a keyword in its context, ...). Second,
in order to do this we had to parse log-format and unique-id-format a bit
earlier, so that was a great opportunity for doing so when the directives
are encountered (unless it's a default section). This way, the recorded
line numbers for these args are the ones of the place where the log format
is declared, not the end of the file.
Userlists report slightly more information now. They're the only remaining
ones in the ACL resolving function.
2013-04-02 10:34:32 -04:00
|
|
|
arg->unresolved = 0;
|
|
|
|
|
arg->data.srv = srv;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ARGT_FE:
|
2018-07-13 04:54:26 -04:00
|
|
|
if (arg->data.str.data) {
|
|
|
|
|
pname = arg->data.str.area;
|
2015-05-26 05:24:42 -04:00
|
|
|
px = proxy_fe_by_name(pname);
|
MAJOR: sample: maintain a per-proxy list of the fetch args to resolve
While ACL args were resolved after all the config was parsed, it was not the
case with sample fetch args because they're almost everywhere now.
The issue is that ACLs now solely rely on sample fetches, so their args
resolving doesn't work anymore. And many fetches involving a server, a
proxy or a userlist don't work at all.
The real issue is that at the bottom layers we have no information about
proxies, line numbers, even ACLs in order to report understandable errors,
and that at the top layers we have no visibility over the locations where
fetches are referenced (think log node).
After failing multiple unsatisfying solutions attempts, we now have a new
concept of args list. The principle is that every proxy has a list head
which contains a number of indications such as the config keyword, the
context where it's used, the file and line number, etc... and a list of
arguments. This list head is of the same type as the elements, so it
serves as a template for adding new elements. This way, it is filled from
top to bottom by the callers with the information they have (eg: line
numbers, ACL name, ...) and the lower layers just have to duplicate it and
add an element when they face an argument they cannot resolve yet.
Then at the end of the configuration parsing, a loop passes over each
proxy's list and resolves all the args in sequence. And this way there is
all necessary information to report verbose errors.
The first immediate benefit is that for the first time we got very precise
location of issues (arg number in a keyword in its context, ...). Second,
in order to do this we had to parse log-format and unique-id-format a bit
earlier, so that was a great opportunity for doing so when the directives
are encountered (unless it's a default section). This way, the recorded
line numbers for these args are the ones of the place where the log format
is declared, not the end of the file.
Userlists report slightly more information now. They're the only remaining
ones in the ACL resolving function.
2013-04-02 10:34:32 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!px) {
|
2017-11-24 10:50:31 -05:00
|
|
|
ha_alert("parsing [%s:%d] : unable to find frontend '%s' referenced in arg %d of %s%s%s%s '%s' %s proxy '%s'.\n",
|
|
|
|
|
cur->file, cur->line, pname,
|
|
|
|
|
cur->arg_pos + 1, conv_pre, conv_ctx, conv_pos, ctx, cur->kw, where, p->id);
|
MAJOR: sample: maintain a per-proxy list of the fetch args to resolve
While ACL args were resolved after all the config was parsed, it was not the
case with sample fetch args because they're almost everywhere now.
The issue is that ACLs now solely rely on sample fetches, so their args
resolving doesn't work anymore. And many fetches involving a server, a
proxy or a userlist don't work at all.
The real issue is that at the bottom layers we have no information about
proxies, line numbers, even ACLs in order to report understandable errors,
and that at the top layers we have no visibility over the locations where
fetches are referenced (think log node).
After failing multiple unsatisfying solutions attempts, we now have a new
concept of args list. The principle is that every proxy has a list head
which contains a number of indications such as the config keyword, the
context where it's used, the file and line number, etc... and a list of
arguments. This list head is of the same type as the elements, so it
serves as a template for adding new elements. This way, it is filled from
top to bottom by the callers with the information they have (eg: line
numbers, ACL name, ...) and the lower layers just have to duplicate it and
add an element when they face an argument they cannot resolve yet.
Then at the end of the configuration parsing, a loop passes over each
proxy's list and resolves all the args in sequence. And this way there is
all necessary information to report verbose errors.
The first immediate benefit is that for the first time we got very precise
location of issues (arg number in a keyword in its context, ...). Second,
in order to do this we had to parse log-format and unique-id-format a bit
earlier, so that was a great opportunity for doing so when the directives
are encountered (unless it's a default section). This way, the recorded
line numbers for these args are the ones of the place where the log format
is declared, not the end of the file.
Userlists report slightly more information now. They're the only remaining
ones in the ACL resolving function.
2013-04-02 10:34:32 -04:00
|
|
|
cfgerr++;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!(px->cap & PR_CAP_FE)) {
|
2017-11-24 10:50:31 -05:00
|
|
|
ha_alert("parsing [%s:%d] : proxy '%s', referenced in arg %d of %s%s%s%s '%s' %s proxy '%s', has not frontend capability.\n",
|
|
|
|
|
cur->file, cur->line, pname,
|
|
|
|
|
cur->arg_pos + 1, conv_pre, conv_ctx, conv_pos, ctx, cur->kw, where, p->id);
|
MAJOR: sample: maintain a per-proxy list of the fetch args to resolve
While ACL args were resolved after all the config was parsed, it was not the
case with sample fetch args because they're almost everywhere now.
The issue is that ACLs now solely rely on sample fetches, so their args
resolving doesn't work anymore. And many fetches involving a server, a
proxy or a userlist don't work at all.
The real issue is that at the bottom layers we have no information about
proxies, line numbers, even ACLs in order to report understandable errors,
and that at the top layers we have no visibility over the locations where
fetches are referenced (think log node).
After failing multiple unsatisfying solutions attempts, we now have a new
concept of args list. The principle is that every proxy has a list head
which contains a number of indications such as the config keyword, the
context where it's used, the file and line number, etc... and a list of
arguments. This list head is of the same type as the elements, so it
serves as a template for adding new elements. This way, it is filled from
top to bottom by the callers with the information they have (eg: line
numbers, ACL name, ...) and the lower layers just have to duplicate it and
add an element when they face an argument they cannot resolve yet.
Then at the end of the configuration parsing, a loop passes over each
proxy's list and resolves all the args in sequence. And this way there is
all necessary information to report verbose errors.
The first immediate benefit is that for the first time we got very precise
location of issues (arg number in a keyword in its context, ...). Second,
in order to do this we had to parse log-format and unique-id-format a bit
earlier, so that was a great opportunity for doing so when the directives
are encountered (unless it's a default section). This way, the recorded
line numbers for these args are the ones of the place where the log format
is declared, not the end of the file.
Userlists report slightly more information now. They're the only remaining
ones in the ACL resolving function.
2013-04-02 10:34:32 -04:00
|
|
|
cfgerr++;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-13 04:54:26 -04:00
|
|
|
free(arg->data.str.area);
|
|
|
|
|
arg->data.str.area = NULL;
|
MAJOR: sample: maintain a per-proxy list of the fetch args to resolve
While ACL args were resolved after all the config was parsed, it was not the
case with sample fetch args because they're almost everywhere now.
The issue is that ACLs now solely rely on sample fetches, so their args
resolving doesn't work anymore. And many fetches involving a server, a
proxy or a userlist don't work at all.
The real issue is that at the bottom layers we have no information about
proxies, line numbers, even ACLs in order to report understandable errors,
and that at the top layers we have no visibility over the locations where
fetches are referenced (think log node).
After failing multiple unsatisfying solutions attempts, we now have a new
concept of args list. The principle is that every proxy has a list head
which contains a number of indications such as the config keyword, the
context where it's used, the file and line number, etc... and a list of
arguments. This list head is of the same type as the elements, so it
serves as a template for adding new elements. This way, it is filled from
top to bottom by the callers with the information they have (eg: line
numbers, ACL name, ...) and the lower layers just have to duplicate it and
add an element when they face an argument they cannot resolve yet.
Then at the end of the configuration parsing, a loop passes over each
proxy's list and resolves all the args in sequence. And this way there is
all necessary information to report verbose errors.
The first immediate benefit is that for the first time we got very precise
location of issues (arg number in a keyword in its context, ...). Second,
in order to do this we had to parse log-format and unique-id-format a bit
earlier, so that was a great opportunity for doing so when the directives
are encountered (unless it's a default section). This way, the recorded
line numbers for these args are the ones of the place where the log format
is declared, not the end of the file.
Userlists report slightly more information now. They're the only remaining
ones in the ACL resolving function.
2013-04-02 10:34:32 -04:00
|
|
|
arg->unresolved = 0;
|
|
|
|
|
arg->data.prx = px;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ARGT_BE:
|
2018-07-13 04:54:26 -04:00
|
|
|
if (arg->data.str.data) {
|
|
|
|
|
pname = arg->data.str.area;
|
2015-05-26 05:24:42 -04:00
|
|
|
px = proxy_be_by_name(pname);
|
MAJOR: sample: maintain a per-proxy list of the fetch args to resolve
While ACL args were resolved after all the config was parsed, it was not the
case with sample fetch args because they're almost everywhere now.
The issue is that ACLs now solely rely on sample fetches, so their args
resolving doesn't work anymore. And many fetches involving a server, a
proxy or a userlist don't work at all.
The real issue is that at the bottom layers we have no information about
proxies, line numbers, even ACLs in order to report understandable errors,
and that at the top layers we have no visibility over the locations where
fetches are referenced (think log node).
After failing multiple unsatisfying solutions attempts, we now have a new
concept of args list. The principle is that every proxy has a list head
which contains a number of indications such as the config keyword, the
context where it's used, the file and line number, etc... and a list of
arguments. This list head is of the same type as the elements, so it
serves as a template for adding new elements. This way, it is filled from
top to bottom by the callers with the information they have (eg: line
numbers, ACL name, ...) and the lower layers just have to duplicate it and
add an element when they face an argument they cannot resolve yet.
Then at the end of the configuration parsing, a loop passes over each
proxy's list and resolves all the args in sequence. And this way there is
all necessary information to report verbose errors.
The first immediate benefit is that for the first time we got very precise
location of issues (arg number in a keyword in its context, ...). Second,
in order to do this we had to parse log-format and unique-id-format a bit
earlier, so that was a great opportunity for doing so when the directives
are encountered (unless it's a default section). This way, the recorded
line numbers for these args are the ones of the place where the log format
is declared, not the end of the file.
Userlists report slightly more information now. They're the only remaining
ones in the ACL resolving function.
2013-04-02 10:34:32 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!px) {
|
2017-11-24 10:50:31 -05:00
|
|
|
ha_alert("parsing [%s:%d] : unable to find backend '%s' referenced in arg %d of %s%s%s%s '%s' %s proxy '%s'.\n",
|
|
|
|
|
cur->file, cur->line, pname,
|
|
|
|
|
cur->arg_pos + 1, conv_pre, conv_ctx, conv_pos, ctx, cur->kw, where, p->id);
|
MAJOR: sample: maintain a per-proxy list of the fetch args to resolve
While ACL args were resolved after all the config was parsed, it was not the
case with sample fetch args because they're almost everywhere now.
The issue is that ACLs now solely rely on sample fetches, so their args
resolving doesn't work anymore. And many fetches involving a server, a
proxy or a userlist don't work at all.
The real issue is that at the bottom layers we have no information about
proxies, line numbers, even ACLs in order to report understandable errors,
and that at the top layers we have no visibility over the locations where
fetches are referenced (think log node).
After failing multiple unsatisfying solutions attempts, we now have a new
concept of args list. The principle is that every proxy has a list head
which contains a number of indications such as the config keyword, the
context where it's used, the file and line number, etc... and a list of
arguments. This list head is of the same type as the elements, so it
serves as a template for adding new elements. This way, it is filled from
top to bottom by the callers with the information they have (eg: line
numbers, ACL name, ...) and the lower layers just have to duplicate it and
add an element when they face an argument they cannot resolve yet.
Then at the end of the configuration parsing, a loop passes over each
proxy's list and resolves all the args in sequence. And this way there is
all necessary information to report verbose errors.
The first immediate benefit is that for the first time we got very precise
location of issues (arg number in a keyword in its context, ...). Second,
in order to do this we had to parse log-format and unique-id-format a bit
earlier, so that was a great opportunity for doing so when the directives
are encountered (unless it's a default section). This way, the recorded
line numbers for these args are the ones of the place where the log format
is declared, not the end of the file.
Userlists report slightly more information now. They're the only remaining
ones in the ACL resolving function.
2013-04-02 10:34:32 -04:00
|
|
|
cfgerr++;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!(px->cap & PR_CAP_BE)) {
|
2017-11-24 10:50:31 -05:00
|
|
|
ha_alert("parsing [%s:%d] : proxy '%s', referenced in arg %d of %s%s%s%s '%s' %s proxy '%s', has not backend capability.\n",
|
|
|
|
|
cur->file, cur->line, pname,
|
|
|
|
|
cur->arg_pos + 1, conv_pre, conv_ctx, conv_pos, ctx, cur->kw, where, p->id);
|
MAJOR: sample: maintain a per-proxy list of the fetch args to resolve
While ACL args were resolved after all the config was parsed, it was not the
case with sample fetch args because they're almost everywhere now.
The issue is that ACLs now solely rely on sample fetches, so their args
resolving doesn't work anymore. And many fetches involving a server, a
proxy or a userlist don't work at all.
The real issue is that at the bottom layers we have no information about
proxies, line numbers, even ACLs in order to report understandable errors,
and that at the top layers we have no visibility over the locations where
fetches are referenced (think log node).
After failing multiple unsatisfying solutions attempts, we now have a new
concept of args list. The principle is that every proxy has a list head
which contains a number of indications such as the config keyword, the
context where it's used, the file and line number, etc... and a list of
arguments. This list head is of the same type as the elements, so it
serves as a template for adding new elements. This way, it is filled from
top to bottom by the callers with the information they have (eg: line
numbers, ACL name, ...) and the lower layers just have to duplicate it and
add an element when they face an argument they cannot resolve yet.
Then at the end of the configuration parsing, a loop passes over each
proxy's list and resolves all the args in sequence. And this way there is
all necessary information to report verbose errors.
The first immediate benefit is that for the first time we got very precise
location of issues (arg number in a keyword in its context, ...). Second,
in order to do this we had to parse log-format and unique-id-format a bit
earlier, so that was a great opportunity for doing so when the directives
are encountered (unless it's a default section). This way, the recorded
line numbers for these args are the ones of the place where the log format
is declared, not the end of the file.
Userlists report slightly more information now. They're the only remaining
ones in the ACL resolving function.
2013-04-02 10:34:32 -04:00
|
|
|
cfgerr++;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-13 04:54:26 -04:00
|
|
|
free(arg->data.str.area);
|
|
|
|
|
arg->data.str.area = NULL;
|
MAJOR: sample: maintain a per-proxy list of the fetch args to resolve
While ACL args were resolved after all the config was parsed, it was not the
case with sample fetch args because they're almost everywhere now.
The issue is that ACLs now solely rely on sample fetches, so their args
resolving doesn't work anymore. And many fetches involving a server, a
proxy or a userlist don't work at all.
The real issue is that at the bottom layers we have no information about
proxies, line numbers, even ACLs in order to report understandable errors,
and that at the top layers we have no visibility over the locations where
fetches are referenced (think log node).
After failing multiple unsatisfying solutions attempts, we now have a new
concept of args list. The principle is that every proxy has a list head
which contains a number of indications such as the config keyword, the
context where it's used, the file and line number, etc... and a list of
arguments. This list head is of the same type as the elements, so it
serves as a template for adding new elements. This way, it is filled from
top to bottom by the callers with the information they have (eg: line
numbers, ACL name, ...) and the lower layers just have to duplicate it and
add an element when they face an argument they cannot resolve yet.
Then at the end of the configuration parsing, a loop passes over each
proxy's list and resolves all the args in sequence. And this way there is
all necessary information to report verbose errors.
The first immediate benefit is that for the first time we got very precise
location of issues (arg number in a keyword in its context, ...). Second,
in order to do this we had to parse log-format and unique-id-format a bit
earlier, so that was a great opportunity for doing so when the directives
are encountered (unless it's a default section). This way, the recorded
line numbers for these args are the ones of the place where the log format
is declared, not the end of the file.
Userlists report slightly more information now. They're the only remaining
ones in the ACL resolving function.
2013-04-02 10:34:32 -04:00
|
|
|
arg->unresolved = 0;
|
|
|
|
|
arg->data.prx = px;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ARGT_TAB:
|
2019-06-20 03:31:04 -04:00
|
|
|
if (arg->data.str.data)
|
|
|
|
|
stktname = arg->data.str.area;
|
|
|
|
|
else
|
|
|
|
|
stktname = px->id;
|
MAJOR: sample: maintain a per-proxy list of the fetch args to resolve
While ACL args were resolved after all the config was parsed, it was not the
case with sample fetch args because they're almost everywhere now.
The issue is that ACLs now solely rely on sample fetches, so their args
resolving doesn't work anymore. And many fetches involving a server, a
proxy or a userlist don't work at all.
The real issue is that at the bottom layers we have no information about
proxies, line numbers, even ACLs in order to report understandable errors,
and that at the top layers we have no visibility over the locations where
fetches are referenced (think log node).
After failing multiple unsatisfying solutions attempts, we now have a new
concept of args list. The principle is that every proxy has a list head
which contains a number of indications such as the config keyword, the
context where it's used, the file and line number, etc... and a list of
arguments. This list head is of the same type as the elements, so it
serves as a template for adding new elements. This way, it is filled from
top to bottom by the callers with the information they have (eg: line
numbers, ACL name, ...) and the lower layers just have to duplicate it and
add an element when they face an argument they cannot resolve yet.
Then at the end of the configuration parsing, a loop passes over each
proxy's list and resolves all the args in sequence. And this way there is
all necessary information to report verbose errors.
The first immediate benefit is that for the first time we got very precise
location of issues (arg number in a keyword in its context, ...). Second,
in order to do this we had to parse log-format and unique-id-format a bit
earlier, so that was a great opportunity for doing so when the directives
are encountered (unless it's a default section). This way, the recorded
line numbers for these args are the ones of the place where the log format
is declared, not the end of the file.
Userlists report slightly more information now. They're the only remaining
ones in the ACL resolving function.
2013-04-02 10:34:32 -04:00
|
|
|
|
2019-03-14 02:07:41 -04:00
|
|
|
t = stktable_find_by_name(stktname);
|
|
|
|
|
if (!t) {
|
2017-11-24 10:50:31 -05:00
|
|
|
ha_alert("parsing [%s:%d] : unable to find table '%s' referenced in arg %d of %s%s%s%s '%s' %s proxy '%s'.\n",
|
2019-03-14 02:07:41 -04:00
|
|
|
cur->file, cur->line, stktname,
|
2017-11-24 10:50:31 -05:00
|
|
|
cur->arg_pos + 1, conv_pre, conv_ctx, conv_pos, ctx, cur->kw, where, p->id);
|
MAJOR: sample: maintain a per-proxy list of the fetch args to resolve
While ACL args were resolved after all the config was parsed, it was not the
case with sample fetch args because they're almost everywhere now.
The issue is that ACLs now solely rely on sample fetches, so their args
resolving doesn't work anymore. And many fetches involving a server, a
proxy or a userlist don't work at all.
The real issue is that at the bottom layers we have no information about
proxies, line numbers, even ACLs in order to report understandable errors,
and that at the top layers we have no visibility over the locations where
fetches are referenced (think log node).
After failing multiple unsatisfying solutions attempts, we now have a new
concept of args list. The principle is that every proxy has a list head
which contains a number of indications such as the config keyword, the
context where it's used, the file and line number, etc... and a list of
arguments. This list head is of the same type as the elements, so it
serves as a template for adding new elements. This way, it is filled from
top to bottom by the callers with the information they have (eg: line
numbers, ACL name, ...) and the lower layers just have to duplicate it and
add an element when they face an argument they cannot resolve yet.
Then at the end of the configuration parsing, a loop passes over each
proxy's list and resolves all the args in sequence. And this way there is
all necessary information to report verbose errors.
The first immediate benefit is that for the first time we got very precise
location of issues (arg number in a keyword in its context, ...). Second,
in order to do this we had to parse log-format and unique-id-format a bit
earlier, so that was a great opportunity for doing so when the directives
are encountered (unless it's a default section). This way, the recorded
line numbers for these args are the ones of the place where the log format
is declared, not the end of the file.
Userlists report slightly more information now. They're the only remaining
ones in the ACL resolving function.
2013-04-02 10:34:32 -04:00
|
|
|
cfgerr++;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-14 02:07:41 -04:00
|
|
|
if (!t->size) {
|
2017-11-24 10:50:31 -05:00
|
|
|
ha_alert("parsing [%s:%d] : no table in proxy '%s' referenced in arg %d of %s%s%s%s '%s' %s proxy '%s'.\n",
|
2019-03-14 02:07:41 -04:00
|
|
|
cur->file, cur->line, stktname,
|
2017-11-24 10:50:31 -05:00
|
|
|
cur->arg_pos + 1, conv_pre, conv_ctx, conv_pos, ctx, cur->kw, where, p->id);
|
MAJOR: sample: maintain a per-proxy list of the fetch args to resolve
While ACL args were resolved after all the config was parsed, it was not the
case with sample fetch args because they're almost everywhere now.
The issue is that ACLs now solely rely on sample fetches, so their args
resolving doesn't work anymore. And many fetches involving a server, a
proxy or a userlist don't work at all.
The real issue is that at the bottom layers we have no information about
proxies, line numbers, even ACLs in order to report understandable errors,
and that at the top layers we have no visibility over the locations where
fetches are referenced (think log node).
After failing multiple unsatisfying solutions attempts, we now have a new
concept of args list. The principle is that every proxy has a list head
which contains a number of indications such as the config keyword, the
context where it's used, the file and line number, etc... and a list of
arguments. This list head is of the same type as the elements, so it
serves as a template for adding new elements. This way, it is filled from
top to bottom by the callers with the information they have (eg: line
numbers, ACL name, ...) and the lower layers just have to duplicate it and
add an element when they face an argument they cannot resolve yet.
Then at the end of the configuration parsing, a loop passes over each
proxy's list and resolves all the args in sequence. And this way there is
all necessary information to report verbose errors.
The first immediate benefit is that for the first time we got very precise
location of issues (arg number in a keyword in its context, ...). Second,
in order to do this we had to parse log-format and unique-id-format a bit
earlier, so that was a great opportunity for doing so when the directives
are encountered (unless it's a default section). This way, the recorded
line numbers for these args are the ones of the place where the log format
is declared, not the end of the file.
Userlists report slightly more information now. They're the only remaining
ones in the ACL resolving function.
2013-04-02 10:34:32 -04:00
|
|
|
cfgerr++;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-14 02:07:41 -04:00
|
|
|
if (t->proxy && (p->bind_proc & ~t->proxy->bind_proc)) {
|
2019-02-05 05:38:38 -05:00
|
|
|
ha_alert("parsing [%s:%d] : stick-table '%s' not present on all processes covered by proxy '%s'.\n",
|
2019-03-14 02:07:41 -04:00
|
|
|
cur->file, cur->line, t->proxy->id, p->id);
|
2019-02-06 04:25:07 -05:00
|
|
|
cfgerr++;
|
|
|
|
|
break;
|
2019-02-05 05:38:38 -05:00
|
|
|
}
|
|
|
|
|
|
2019-08-07 03:28:39 -04:00
|
|
|
if (!in_proxies_list(t->proxies_list, p)) {
|
2019-03-19 09:55:01 -04:00
|
|
|
p->next_stkt_ref = t->proxies_list;
|
|
|
|
|
t->proxies_list = p;
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-13 04:54:26 -04:00
|
|
|
free(arg->data.str.area);
|
|
|
|
|
arg->data.str.area = NULL;
|
MAJOR: sample: maintain a per-proxy list of the fetch args to resolve
While ACL args were resolved after all the config was parsed, it was not the
case with sample fetch args because they're almost everywhere now.
The issue is that ACLs now solely rely on sample fetches, so their args
resolving doesn't work anymore. And many fetches involving a server, a
proxy or a userlist don't work at all.
The real issue is that at the bottom layers we have no information about
proxies, line numbers, even ACLs in order to report understandable errors,
and that at the top layers we have no visibility over the locations where
fetches are referenced (think log node).
After failing multiple unsatisfying solutions attempts, we now have a new
concept of args list. The principle is that every proxy has a list head
which contains a number of indications such as the config keyword, the
context where it's used, the file and line number, etc... and a list of
arguments. This list head is of the same type as the elements, so it
serves as a template for adding new elements. This way, it is filled from
top to bottom by the callers with the information they have (eg: line
numbers, ACL name, ...) and the lower layers just have to duplicate it and
add an element when they face an argument they cannot resolve yet.
Then at the end of the configuration parsing, a loop passes over each
proxy's list and resolves all the args in sequence. And this way there is
all necessary information to report verbose errors.
The first immediate benefit is that for the first time we got very precise
location of issues (arg number in a keyword in its context, ...). Second,
in order to do this we had to parse log-format and unique-id-format a bit
earlier, so that was a great opportunity for doing so when the directives
are encountered (unless it's a default section). This way, the recorded
line numbers for these args are the ones of the place where the log format
is declared, not the end of the file.
Userlists report slightly more information now. They're the only remaining
ones in the ACL resolving function.
2013-04-02 10:34:32 -04:00
|
|
|
arg->unresolved = 0;
|
2019-03-14 02:07:41 -04:00
|
|
|
arg->data.t = t;
|
MAJOR: sample: maintain a per-proxy list of the fetch args to resolve
While ACL args were resolved after all the config was parsed, it was not the
case with sample fetch args because they're almost everywhere now.
The issue is that ACLs now solely rely on sample fetches, so their args
resolving doesn't work anymore. And many fetches involving a server, a
proxy or a userlist don't work at all.
The real issue is that at the bottom layers we have no information about
proxies, line numbers, even ACLs in order to report understandable errors,
and that at the top layers we have no visibility over the locations where
fetches are referenced (think log node).
After failing multiple unsatisfying solutions attempts, we now have a new
concept of args list. The principle is that every proxy has a list head
which contains a number of indications such as the config keyword, the
context where it's used, the file and line number, etc... and a list of
arguments. This list head is of the same type as the elements, so it
serves as a template for adding new elements. This way, it is filled from
top to bottom by the callers with the information they have (eg: line
numbers, ACL name, ...) and the lower layers just have to duplicate it and
add an element when they face an argument they cannot resolve yet.
Then at the end of the configuration parsing, a loop passes over each
proxy's list and resolves all the args in sequence. And this way there is
all necessary information to report verbose errors.
The first immediate benefit is that for the first time we got very precise
location of issues (arg number in a keyword in its context, ...). Second,
in order to do this we had to parse log-format and unique-id-format a bit
earlier, so that was a great opportunity for doing so when the directives
are encountered (unless it's a default section). This way, the recorded
line numbers for these args are the ones of the place where the log format
is declared, not the end of the file.
Userlists report slightly more information now. They're the only remaining
ones in the ACL resolving function.
2013-04-02 10:34:32 -04:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ARGT_USR:
|
2018-07-13 04:54:26 -04:00
|
|
|
if (!arg->data.str.data) {
|
2017-11-24 10:50:31 -05:00
|
|
|
ha_alert("parsing [%s:%d] : missing userlist name in arg %d of %s%s%s%s '%s' %s proxy '%s'.\n",
|
|
|
|
|
cur->file, cur->line,
|
|
|
|
|
cur->arg_pos + 1, conv_pre, conv_ctx, conv_pos, ctx, cur->kw, where, p->id);
|
MAJOR: sample: maintain a per-proxy list of the fetch args to resolve
While ACL args were resolved after all the config was parsed, it was not the
case with sample fetch args because they're almost everywhere now.
The issue is that ACLs now solely rely on sample fetches, so their args
resolving doesn't work anymore. And many fetches involving a server, a
proxy or a userlist don't work at all.
The real issue is that at the bottom layers we have no information about
proxies, line numbers, even ACLs in order to report understandable errors,
and that at the top layers we have no visibility over the locations where
fetches are referenced (think log node).
After failing multiple unsatisfying solutions attempts, we now have a new
concept of args list. The principle is that every proxy has a list head
which contains a number of indications such as the config keyword, the
context where it's used, the file and line number, etc... and a list of
arguments. This list head is of the same type as the elements, so it
serves as a template for adding new elements. This way, it is filled from
top to bottom by the callers with the information they have (eg: line
numbers, ACL name, ...) and the lower layers just have to duplicate it and
add an element when they face an argument they cannot resolve yet.
Then at the end of the configuration parsing, a loop passes over each
proxy's list and resolves all the args in sequence. And this way there is
all necessary information to report verbose errors.
The first immediate benefit is that for the first time we got very precise
location of issues (arg number in a keyword in its context, ...). Second,
in order to do this we had to parse log-format and unique-id-format a bit
earlier, so that was a great opportunity for doing so when the directives
are encountered (unless it's a default section). This way, the recorded
line numbers for these args are the ones of the place where the log format
is declared, not the end of the file.
Userlists report slightly more information now. They're the only remaining
ones in the ACL resolving function.
2013-04-02 10:34:32 -04:00
|
|
|
cfgerr++;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (p->uri_auth && p->uri_auth->userlist &&
|
2018-07-13 04:54:26 -04:00
|
|
|
!strcmp(p->uri_auth->userlist->name, arg->data.str.area))
|
MAJOR: sample: maintain a per-proxy list of the fetch args to resolve
While ACL args were resolved after all the config was parsed, it was not the
case with sample fetch args because they're almost everywhere now.
The issue is that ACLs now solely rely on sample fetches, so their args
resolving doesn't work anymore. And many fetches involving a server, a
proxy or a userlist don't work at all.
The real issue is that at the bottom layers we have no information about
proxies, line numbers, even ACLs in order to report understandable errors,
and that at the top layers we have no visibility over the locations where
fetches are referenced (think log node).
After failing multiple unsatisfying solutions attempts, we now have a new
concept of args list. The principle is that every proxy has a list head
which contains a number of indications such as the config keyword, the
context where it's used, the file and line number, etc... and a list of
arguments. This list head is of the same type as the elements, so it
serves as a template for adding new elements. This way, it is filled from
top to bottom by the callers with the information they have (eg: line
numbers, ACL name, ...) and the lower layers just have to duplicate it and
add an element when they face an argument they cannot resolve yet.
Then at the end of the configuration parsing, a loop passes over each
proxy's list and resolves all the args in sequence. And this way there is
all necessary information to report verbose errors.
The first immediate benefit is that for the first time we got very precise
location of issues (arg number in a keyword in its context, ...). Second,
in order to do this we had to parse log-format and unique-id-format a bit
earlier, so that was a great opportunity for doing so when the directives
are encountered (unless it's a default section). This way, the recorded
line numbers for these args are the ones of the place where the log format
is declared, not the end of the file.
Userlists report slightly more information now. They're the only remaining
ones in the ACL resolving function.
2013-04-02 10:34:32 -04:00
|
|
|
ul = p->uri_auth->userlist;
|
|
|
|
|
else
|
2018-07-13 04:54:26 -04:00
|
|
|
ul = auth_find_userlist(arg->data.str.area);
|
MAJOR: sample: maintain a per-proxy list of the fetch args to resolve
While ACL args were resolved after all the config was parsed, it was not the
case with sample fetch args because they're almost everywhere now.
The issue is that ACLs now solely rely on sample fetches, so their args
resolving doesn't work anymore. And many fetches involving a server, a
proxy or a userlist don't work at all.
The real issue is that at the bottom layers we have no information about
proxies, line numbers, even ACLs in order to report understandable errors,
and that at the top layers we have no visibility over the locations where
fetches are referenced (think log node).
After failing multiple unsatisfying solutions attempts, we now have a new
concept of args list. The principle is that every proxy has a list head
which contains a number of indications such as the config keyword, the
context where it's used, the file and line number, etc... and a list of
arguments. This list head is of the same type as the elements, so it
serves as a template for adding new elements. This way, it is filled from
top to bottom by the callers with the information they have (eg: line
numbers, ACL name, ...) and the lower layers just have to duplicate it and
add an element when they face an argument they cannot resolve yet.
Then at the end of the configuration parsing, a loop passes over each
proxy's list and resolves all the args in sequence. And this way there is
all necessary information to report verbose errors.
The first immediate benefit is that for the first time we got very precise
location of issues (arg number in a keyword in its context, ...). Second,
in order to do this we had to parse log-format and unique-id-format a bit
earlier, so that was a great opportunity for doing so when the directives
are encountered (unless it's a default section). This way, the recorded
line numbers for these args are the ones of the place where the log format
is declared, not the end of the file.
Userlists report slightly more information now. They're the only remaining
ones in the ACL resolving function.
2013-04-02 10:34:32 -04:00
|
|
|
|
|
|
|
|
if (!ul) {
|
2017-11-24 10:50:31 -05:00
|
|
|
ha_alert("parsing [%s:%d] : unable to find userlist '%s' referenced in arg %d of %s%s%s%s '%s' %s proxy '%s'.\n",
|
2018-07-13 04:54:26 -04:00
|
|
|
cur->file, cur->line,
|
|
|
|
|
arg->data.str.area,
|
2017-11-24 10:50:31 -05:00
|
|
|
cur->arg_pos + 1, conv_pre, conv_ctx, conv_pos, ctx, cur->kw, where, p->id);
|
MAJOR: sample: maintain a per-proxy list of the fetch args to resolve
While ACL args were resolved after all the config was parsed, it was not the
case with sample fetch args because they're almost everywhere now.
The issue is that ACLs now solely rely on sample fetches, so their args
resolving doesn't work anymore. And many fetches involving a server, a
proxy or a userlist don't work at all.
The real issue is that at the bottom layers we have no information about
proxies, line numbers, even ACLs in order to report understandable errors,
and that at the top layers we have no visibility over the locations where
fetches are referenced (think log node).
After failing multiple unsatisfying solutions attempts, we now have a new
concept of args list. The principle is that every proxy has a list head
which contains a number of indications such as the config keyword, the
context where it's used, the file and line number, etc... and a list of
arguments. This list head is of the same type as the elements, so it
serves as a template for adding new elements. This way, it is filled from
top to bottom by the callers with the information they have (eg: line
numbers, ACL name, ...) and the lower layers just have to duplicate it and
add an element when they face an argument they cannot resolve yet.
Then at the end of the configuration parsing, a loop passes over each
proxy's list and resolves all the args in sequence. And this way there is
all necessary information to report verbose errors.
The first immediate benefit is that for the first time we got very precise
location of issues (arg number in a keyword in its context, ...). Second,
in order to do this we had to parse log-format and unique-id-format a bit
earlier, so that was a great opportunity for doing so when the directives
are encountered (unless it's a default section). This way, the recorded
line numbers for these args are the ones of the place where the log format
is declared, not the end of the file.
Userlists report slightly more information now. They're the only remaining
ones in the ACL resolving function.
2013-04-02 10:34:32 -04:00
|
|
|
cfgerr++;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-13 04:54:26 -04:00
|
|
|
free(arg->data.str.area);
|
|
|
|
|
arg->data.str.area = NULL;
|
MAJOR: sample: maintain a per-proxy list of the fetch args to resolve
While ACL args were resolved after all the config was parsed, it was not the
case with sample fetch args because they're almost everywhere now.
The issue is that ACLs now solely rely on sample fetches, so their args
resolving doesn't work anymore. And many fetches involving a server, a
proxy or a userlist don't work at all.
The real issue is that at the bottom layers we have no information about
proxies, line numbers, even ACLs in order to report understandable errors,
and that at the top layers we have no visibility over the locations where
fetches are referenced (think log node).
After failing multiple unsatisfying solutions attempts, we now have a new
concept of args list. The principle is that every proxy has a list head
which contains a number of indications such as the config keyword, the
context where it's used, the file and line number, etc... and a list of
arguments. This list head is of the same type as the elements, so it
serves as a template for adding new elements. This way, it is filled from
top to bottom by the callers with the information they have (eg: line
numbers, ACL name, ...) and the lower layers just have to duplicate it and
add an element when they face an argument they cannot resolve yet.
Then at the end of the configuration parsing, a loop passes over each
proxy's list and resolves all the args in sequence. And this way there is
all necessary information to report verbose errors.
The first immediate benefit is that for the first time we got very precise
location of issues (arg number in a keyword in its context, ...). Second,
in order to do this we had to parse log-format and unique-id-format a bit
earlier, so that was a great opportunity for doing so when the directives
are encountered (unless it's a default section). This way, the recorded
line numbers for these args are the ones of the place where the log format
is declared, not the end of the file.
Userlists report slightly more information now. They're the only remaining
ones in the ACL resolving function.
2013-04-02 10:34:32 -04:00
|
|
|
arg->unresolved = 0;
|
|
|
|
|
arg->data.usr = ul;
|
|
|
|
|
break;
|
2015-01-19 13:00:58 -05:00
|
|
|
|
|
|
|
|
case ARGT_REG:
|
2018-07-13 04:54:26 -04:00
|
|
|
if (!arg->data.str.data) {
|
2017-11-24 10:50:31 -05:00
|
|
|
ha_alert("parsing [%s:%d] : missing regex in arg %d of %s%s%s%s '%s' %s proxy '%s'.\n",
|
|
|
|
|
cur->file, cur->line,
|
|
|
|
|
cur->arg_pos + 1, conv_pre, conv_ctx, conv_pos, ctx, cur->kw, where, p->id);
|
2015-01-19 13:00:58 -05:00
|
|
|
cfgerr++;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rflags = 0;
|
|
|
|
|
rflags |= (arg->type_flags & ARGF_REG_ICASE) ? REG_ICASE : 0;
|
|
|
|
|
err = NULL;
|
|
|
|
|
|
2019-04-30 09:54:36 -04:00
|
|
|
if (!(reg = regex_comp(arg->data.str.area, !(rflags & REG_ICASE), 1 /* capture substr */, &err))) {
|
2017-11-24 10:50:31 -05:00
|
|
|
ha_alert("parsing [%s:%d] : error in regex '%s' in arg %d of %s%s%s%s '%s' %s proxy '%s' : %s.\n",
|
|
|
|
|
cur->file, cur->line,
|
2018-07-13 04:54:26 -04:00
|
|
|
arg->data.str.area,
|
2017-11-24 10:50:31 -05:00
|
|
|
cur->arg_pos + 1, conv_pre, conv_ctx, conv_pos, ctx, cur->kw, where, p->id, err);
|
2015-01-19 13:00:58 -05:00
|
|
|
cfgerr++;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-13 04:54:26 -04:00
|
|
|
free(arg->data.str.area);
|
|
|
|
|
arg->data.str.area = NULL;
|
2015-01-19 13:00:58 -05:00
|
|
|
arg->unresolved = 0;
|
|
|
|
|
arg->data.reg = reg;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
MAJOR: sample: maintain a per-proxy list of the fetch args to resolve
While ACL args were resolved after all the config was parsed, it was not the
case with sample fetch args because they're almost everywhere now.
The issue is that ACLs now solely rely on sample fetches, so their args
resolving doesn't work anymore. And many fetches involving a server, a
proxy or a userlist don't work at all.
The real issue is that at the bottom layers we have no information about
proxies, line numbers, even ACLs in order to report understandable errors,
and that at the top layers we have no visibility over the locations where
fetches are referenced (think log node).
After failing multiple unsatisfying solutions attempts, we now have a new
concept of args list. The principle is that every proxy has a list head
which contains a number of indications such as the config keyword, the
context where it's used, the file and line number, etc... and a list of
arguments. This list head is of the same type as the elements, so it
serves as a template for adding new elements. This way, it is filled from
top to bottom by the callers with the information they have (eg: line
numbers, ACL name, ...) and the lower layers just have to duplicate it and
add an element when they face an argument they cannot resolve yet.
Then at the end of the configuration parsing, a loop passes over each
proxy's list and resolves all the args in sequence. And this way there is
all necessary information to report verbose errors.
The first immediate benefit is that for the first time we got very precise
location of issues (arg number in a keyword in its context, ...). Second,
in order to do this we had to parse log-format and unique-id-format a bit
earlier, so that was a great opportunity for doing so when the directives
are encountered (unless it's a default section). This way, the recorded
line numbers for these args are the ones of the place where the log format
is declared, not the end of the file.
Userlists report slightly more information now. They're the only remaining
ones in the ACL resolving function.
2013-04-02 10:34:32 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LIST_DEL(&cur->list);
|
|
|
|
|
free(cur);
|
|
|
|
|
} /* end of args processing */
|
|
|
|
|
|
|
|
|
|
return cfgerr;
|
|
|
|
|
}
|
|
|
|
|
|
2012-12-20 18:02:32 -05:00
|
|
|
/*
|
2014-06-13 10:04:35 -04:00
|
|
|
* Process a fetch + format conversion as defined by the sample expression
|
|
|
|
|
* <expr> on request or response considering the <opt> parameter. The output is
|
2015-07-06 09:41:02 -04:00
|
|
|
* not explicitly set to <smp_type>, but shall be compatible with it as
|
|
|
|
|
* specified by 'sample_casts' table. If a stable sample can be fetched, or an
|
|
|
|
|
* unstable one when <opt> contains SMP_OPT_FINAL, the sample is converted and
|
2014-06-13 10:04:35 -04:00
|
|
|
* returned without the SMP_F_MAY_CHANGE flag. If an unstable sample is found
|
|
|
|
|
* and <opt> does not contain SMP_OPT_FINAL, then the sample is returned as-is
|
|
|
|
|
* with its SMP_F_MAY_CHANGE flag so that the caller can check it and decide to
|
|
|
|
|
* take actions (eg: wait longer). If a sample could not be found or could not
|
2014-07-30 02:56:35 -04:00
|
|
|
* be converted, NULL is returned. The caller MUST NOT use the sample if the
|
|
|
|
|
* SMP_F_MAY_CHANGE flag is present, as it is used only as a hint that there is
|
|
|
|
|
* still hope to get it after waiting longer, and is not converted to string.
|
|
|
|
|
* The possible output combinations are the following :
|
|
|
|
|
*
|
|
|
|
|
* return MAY_CHANGE FINAL Meaning for the sample
|
|
|
|
|
* NULL * * Not present and will never be (eg: header)
|
|
|
|
|
* smp 0 * Final value converted (eg: header)
|
|
|
|
|
* smp 1 0 Not present yet, may appear later (eg: header)
|
|
|
|
|
* smp 1 1 never happens (either flag is cleared on output)
|
2012-12-20 18:02:32 -05:00
|
|
|
*/
|
2015-07-06 09:41:02 -04:00
|
|
|
struct sample *sample_fetch_as_type(struct proxy *px, struct session *sess,
|
2015-04-03 19:47:55 -04:00
|
|
|
struct stream *strm, unsigned int opt,
|
2015-07-06 09:41:02 -04:00
|
|
|
struct sample_expr *expr, int smp_type)
|
2012-12-20 18:02:32 -05:00
|
|
|
{
|
2014-06-13 10:04:35 -04:00
|
|
|
struct sample *smp = &temp_smp;
|
2012-12-20 18:02:32 -05:00
|
|
|
|
2014-06-25 10:56:41 -04:00
|
|
|
memset(smp, 0, sizeof(*smp));
|
|
|
|
|
|
2015-04-03 19:47:55 -04:00
|
|
|
if (!sample_process(px, sess, strm, opt, expr, smp)) {
|
2014-06-13 10:04:35 -04:00
|
|
|
if ((smp->flags & SMP_F_MAY_CHANGE) && !(opt & SMP_OPT_FINAL))
|
|
|
|
|
return smp;
|
2012-12-20 18:02:32 -05:00
|
|
|
return NULL;
|
2014-06-13 10:04:35 -04:00
|
|
|
}
|
2012-12-20 18:02:32 -05:00
|
|
|
|
2015-08-19 03:00:18 -04:00
|
|
|
if (!sample_casts[smp->data.type][smp_type])
|
2012-12-20 18:02:32 -05:00
|
|
|
return NULL;
|
|
|
|
|
|
2015-08-19 03:00:18 -04:00
|
|
|
if (!sample_casts[smp->data.type][smp_type](smp))
|
2012-12-20 18:02:32 -05:00
|
|
|
return NULL;
|
|
|
|
|
|
2014-06-13 10:04:35 -04:00
|
|
|
smp->flags &= ~SMP_F_MAY_CHANGE;
|
2012-12-20 18:02:32 -05:00
|
|
|
return smp;
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-26 05:34:47 -04:00
|
|
|
static void release_sample_arg(struct arg *p)
|
|
|
|
|
{
|
|
|
|
|
struct arg *p_back = p;
|
|
|
|
|
|
|
|
|
|
if (!p)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
while (p->type != ARGT_STOP) {
|
|
|
|
|
if (p->type == ARGT_STR || p->unresolved) {
|
2018-07-13 04:54:26 -04:00
|
|
|
free(p->data.str.area);
|
|
|
|
|
p->data.str.area = NULL;
|
2016-10-26 05:34:47 -04:00
|
|
|
p->unresolved = 0;
|
|
|
|
|
}
|
|
|
|
|
else if (p->type == ARGT_REG) {
|
2019-04-30 09:54:36 -04:00
|
|
|
regex_free(p->data.reg);
|
|
|
|
|
p->data.reg = NULL;
|
2016-10-26 05:34:47 -04:00
|
|
|
}
|
|
|
|
|
p++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (p_back != empty_arg_list)
|
|
|
|
|
free(p_back);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void release_sample_expr(struct sample_expr *expr)
|
|
|
|
|
{
|
|
|
|
|
struct sample_conv_expr *conv_expr, *conv_exprb;
|
|
|
|
|
|
|
|
|
|
if (!expr)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
list_for_each_entry_safe(conv_expr, conv_exprb, &expr->conv_exprs, list)
|
|
|
|
|
release_sample_arg(conv_expr->arg_p);
|
|
|
|
|
release_sample_arg(expr->arg_p);
|
|
|
|
|
free(expr);
|
|
|
|
|
}
|
|
|
|
|
|
2010-01-04 10:16:05 -05:00
|
|
|
/*****************************************************************/
|
2012-04-27 15:37:17 -04:00
|
|
|
/* Sample format convert functions */
|
2012-04-23 16:38:26 -04:00
|
|
|
/* These functions set the data type on return. */
|
2010-01-04 10:16:05 -05:00
|
|
|
/*****************************************************************/
|
|
|
|
|
|
2015-05-07 09:46:29 -04:00
|
|
|
static int sample_conv_debug(const struct arg *arg_p, struct sample *smp, void *private)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
struct sample tmp;
|
2019-12-17 04:07:25 -05:00
|
|
|
struct buffer *buf;
|
|
|
|
|
struct sink *sink;
|
|
|
|
|
struct ist line;
|
|
|
|
|
char *pfx;
|
2015-05-07 09:46:29 -04:00
|
|
|
|
2019-12-17 04:07:25 -05:00
|
|
|
buf = alloc_trash_chunk();
|
|
|
|
|
if (!buf)
|
|
|
|
|
goto end;
|
2015-05-07 09:46:29 -04:00
|
|
|
|
2019-12-17 04:07:25 -05:00
|
|
|
sink = (struct sink *)arg_p[1].data.str.area;
|
|
|
|
|
BUG_ON(!sink);
|
2015-05-07 09:46:29 -04:00
|
|
|
|
2019-12-17 04:07:25 -05:00
|
|
|
pfx = arg_p[0].data.str.area;
|
|
|
|
|
BUG_ON(!pfx);
|
2015-05-07 09:46:29 -04:00
|
|
|
|
2019-12-17 04:07:25 -05:00
|
|
|
chunk_printf(buf, "[debug] %s: type=%s ", pfx, smp_to_type[smp->data.type]);
|
|
|
|
|
if (!sample_casts[smp->data.type][SMP_T_STR])
|
|
|
|
|
goto nocast;
|
|
|
|
|
|
|
|
|
|
/* Copy sample fetch. This puts the sample as const, the
|
|
|
|
|
* cast will copy data if a transformation is required.
|
|
|
|
|
*/
|
|
|
|
|
memcpy(&tmp, smp, sizeof(struct sample));
|
|
|
|
|
tmp.flags = SMP_F_CONST;
|
|
|
|
|
|
|
|
|
|
if (!sample_casts[smp->data.type][SMP_T_STR](&tmp))
|
|
|
|
|
goto nocast;
|
|
|
|
|
|
|
|
|
|
/* Display the displayable chars*. */
|
|
|
|
|
b_putchr(buf, '<');
|
|
|
|
|
for (i = 0; i < tmp.data.u.str.data; i++) {
|
2020-02-25 02:16:33 -05:00
|
|
|
if (isprint((unsigned char)tmp.data.u.str.area[i]))
|
2019-12-17 04:07:25 -05:00
|
|
|
b_putchr(buf, tmp.data.u.str.area[i]);
|
|
|
|
|
else
|
|
|
|
|
b_putchr(buf, '.');
|
2015-05-07 09:46:29 -04:00
|
|
|
}
|
2019-12-17 04:07:25 -05:00
|
|
|
b_putchr(buf, '>');
|
|
|
|
|
|
|
|
|
|
done:
|
|
|
|
|
line = ist2(buf->area, buf->data);
|
|
|
|
|
sink_write(sink, &line, 1);
|
|
|
|
|
end:
|
|
|
|
|
free_trash_chunk(buf);
|
|
|
|
|
return 1;
|
|
|
|
|
nocast:
|
|
|
|
|
chunk_appendf(buf, "(undisplayable)");
|
|
|
|
|
goto done;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This function checks the "debug" converter's arguments.
|
|
|
|
|
static int smp_check_debug(struct arg *args, struct sample_conv *conv,
|
|
|
|
|
const char *file, int line, char **err)
|
|
|
|
|
{
|
|
|
|
|
const char *name = "buf0";
|
|
|
|
|
struct sink *sink = NULL;
|
|
|
|
|
|
|
|
|
|
if (args[0].type != ARGT_STR) {
|
|
|
|
|
/* optional prefix */
|
|
|
|
|
args[0].data.str.area = "";
|
|
|
|
|
args[0].data.str.data = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (args[1].type == ARGT_STR)
|
|
|
|
|
name = args[1].data.str.area;
|
|
|
|
|
|
|
|
|
|
sink = sink_find(name);
|
|
|
|
|
if (!sink) {
|
|
|
|
|
memprintf(err, "No such sink '%s'", name);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
args[1].data.str.area = (char *)sink;
|
|
|
|
|
args[1].data.str.data = 0; // that's not a string anymore
|
2015-05-07 09:46:29 -04:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-05 18:56:53 -04:00
|
|
|
static int sample_conv_base642bin(const struct arg *arg_p, struct sample *smp, void *private)
|
|
|
|
|
{
|
2018-07-13 05:56:34 -04:00
|
|
|
struct buffer *trash = get_trash_chunk();
|
2017-05-05 18:56:53 -04:00
|
|
|
int bin_len;
|
|
|
|
|
|
2018-07-13 04:54:26 -04:00
|
|
|
trash->data = 0;
|
|
|
|
|
bin_len = base64dec(smp->data.u.str.area, smp->data.u.str.data,
|
|
|
|
|
trash->area, trash->size);
|
2017-05-05 18:56:53 -04:00
|
|
|
if (bin_len < 0)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2018-07-13 04:54:26 -04:00
|
|
|
trash->data = bin_len;
|
2017-05-05 18:56:53 -04:00
|
|
|
smp->data.u.str = *trash;
|
|
|
|
|
smp->data.type = SMP_T_BIN;
|
|
|
|
|
smp->flags &= ~SMP_F_CONST;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-11 09:20:49 -04:00
|
|
|
static int sample_conv_bin2base64(const struct arg *arg_p, struct sample *smp, void *private)
|
2014-04-30 12:21:37 -04:00
|
|
|
{
|
2018-07-13 05:56:34 -04:00
|
|
|
struct buffer *trash = get_trash_chunk();
|
2014-04-30 12:21:37 -04:00
|
|
|
int b64_len;
|
|
|
|
|
|
2018-07-13 04:54:26 -04:00
|
|
|
trash->data = 0;
|
|
|
|
|
b64_len = a2base64(smp->data.u.str.area, smp->data.u.str.data,
|
|
|
|
|
trash->area, trash->size);
|
2014-04-30 12:21:37 -04:00
|
|
|
if (b64_len < 0)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2018-07-13 04:54:26 -04:00
|
|
|
trash->data = b64_len;
|
2015-08-19 03:07:19 -04:00
|
|
|
smp->data.u.str = *trash;
|
2015-08-19 03:00:18 -04:00
|
|
|
smp->data.type = SMP_T_STR;
|
2014-04-30 12:21:37 -04:00
|
|
|
smp->flags &= ~SMP_F_CONST;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-24 03:18:23 -04:00
|
|
|
static int sample_conv_sha1(const struct arg *arg_p, struct sample *smp, void *private)
|
|
|
|
|
{
|
|
|
|
|
blk_SHA_CTX ctx;
|
2018-07-13 05:56:34 -04:00
|
|
|
struct buffer *trash = get_trash_chunk();
|
2017-10-24 03:18:23 -04:00
|
|
|
|
|
|
|
|
memset(&ctx, 0, sizeof(ctx));
|
|
|
|
|
|
|
|
|
|
blk_SHA1_Init(&ctx);
|
2018-07-13 04:54:26 -04:00
|
|
|
blk_SHA1_Update(&ctx, smp->data.u.str.area, smp->data.u.str.data);
|
|
|
|
|
blk_SHA1_Final((unsigned char *) trash->area, &ctx);
|
2017-10-24 03:18:23 -04:00
|
|
|
|
2018-07-13 04:54:26 -04:00
|
|
|
trash->data = 20;
|
2017-10-24 03:18:23 -04:00
|
|
|
smp->data.u.str = *trash;
|
|
|
|
|
smp->data.type = SMP_T_BIN;
|
|
|
|
|
smp->flags &= ~SMP_F_CONST;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-17 06:41:44 -04:00
|
|
|
#ifdef USE_OPENSSL
|
2019-12-17 06:31:20 -05:00
|
|
|
static int smp_check_sha2(struct arg *args, struct sample_conv *conv,
|
|
|
|
|
const char *file, int line, char **err)
|
|
|
|
|
{
|
|
|
|
|
if (args[0].type == ARGT_STOP)
|
|
|
|
|
return 1;
|
|
|
|
|
if (args[0].type != ARGT_SINT) {
|
|
|
|
|
memprintf(err, "Invalid type '%s'", arg_type_names[args[0].type]);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (args[0].data.sint) {
|
|
|
|
|
case 224:
|
|
|
|
|
case 256:
|
|
|
|
|
case 384:
|
|
|
|
|
case 512:
|
|
|
|
|
/* this is okay */
|
|
|
|
|
return 1;
|
|
|
|
|
default:
|
|
|
|
|
memprintf(err, "Unsupported number of bits: '%lld'", args[0].data.sint);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-17 06:41:44 -04:00
|
|
|
static int sample_conv_sha2(const struct arg *arg_p, struct sample *smp, void *private)
|
|
|
|
|
{
|
|
|
|
|
struct buffer *trash = get_trash_chunk();
|
|
|
|
|
int bits = 256;
|
|
|
|
|
if (arg_p && arg_p->data.sint)
|
|
|
|
|
bits = arg_p->data.sint;
|
|
|
|
|
|
|
|
|
|
switch (bits) {
|
|
|
|
|
case 224: {
|
|
|
|
|
SHA256_CTX ctx;
|
|
|
|
|
|
|
|
|
|
memset(&ctx, 0, sizeof(ctx));
|
|
|
|
|
|
|
|
|
|
SHA224_Init(&ctx);
|
|
|
|
|
SHA224_Update(&ctx, smp->data.u.str.area, smp->data.u.str.data);
|
|
|
|
|
SHA224_Final((unsigned char *) trash->area, &ctx);
|
|
|
|
|
trash->data = SHA224_DIGEST_LENGTH;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case 256: {
|
|
|
|
|
SHA256_CTX ctx;
|
|
|
|
|
|
|
|
|
|
memset(&ctx, 0, sizeof(ctx));
|
|
|
|
|
|
|
|
|
|
SHA256_Init(&ctx);
|
|
|
|
|
SHA256_Update(&ctx, smp->data.u.str.area, smp->data.u.str.data);
|
|
|
|
|
SHA256_Final((unsigned char *) trash->area, &ctx);
|
|
|
|
|
trash->data = SHA256_DIGEST_LENGTH;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case 384: {
|
|
|
|
|
SHA512_CTX ctx;
|
|
|
|
|
|
|
|
|
|
memset(&ctx, 0, sizeof(ctx));
|
|
|
|
|
|
|
|
|
|
SHA384_Init(&ctx);
|
|
|
|
|
SHA384_Update(&ctx, smp->data.u.str.area, smp->data.u.str.data);
|
|
|
|
|
SHA384_Final((unsigned char *) trash->area, &ctx);
|
|
|
|
|
trash->data = SHA384_DIGEST_LENGTH;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case 512: {
|
|
|
|
|
SHA512_CTX ctx;
|
|
|
|
|
|
|
|
|
|
memset(&ctx, 0, sizeof(ctx));
|
|
|
|
|
|
|
|
|
|
SHA512_Init(&ctx);
|
|
|
|
|
SHA512_Update(&ctx, smp->data.u.str.area, smp->data.u.str.data);
|
|
|
|
|
SHA512_Final((unsigned char *) trash->area, &ctx);
|
|
|
|
|
trash->data = SHA512_DIGEST_LENGTH;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
smp->data.u.str = *trash;
|
|
|
|
|
smp->data.type = SMP_T_BIN;
|
|
|
|
|
smp->flags &= ~SMP_F_CONST;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2015-05-11 09:20:49 -04:00
|
|
|
static int sample_conv_bin2hex(const struct arg *arg_p, struct sample *smp, void *private)
|
2014-03-12 10:01:52 -04:00
|
|
|
{
|
2018-07-13 05:56:34 -04:00
|
|
|
struct buffer *trash = get_trash_chunk();
|
2014-03-12 10:01:52 -04:00
|
|
|
unsigned char c;
|
|
|
|
|
int ptr = 0;
|
|
|
|
|
|
2018-07-13 04:54:26 -04:00
|
|
|
trash->data = 0;
|
|
|
|
|
while (ptr < smp->data.u.str.data && trash->data <= trash->size - 2) {
|
|
|
|
|
c = smp->data.u.str.area[ptr++];
|
|
|
|
|
trash->area[trash->data++] = hextab[(c >> 4) & 0xF];
|
|
|
|
|
trash->area[trash->data++] = hextab[c & 0xF];
|
2014-03-12 10:01:52 -04:00
|
|
|
}
|
2015-08-19 03:07:19 -04:00
|
|
|
smp->data.u.str = *trash;
|
2015-08-19 03:00:18 -04:00
|
|
|
smp->data.type = SMP_T_STR;
|
2013-12-16 18:20:33 -05:00
|
|
|
smp->flags &= ~SMP_F_CONST;
|
2014-03-12 10:01:52 -04:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-24 03:27:34 -04:00
|
|
|
static int sample_conv_hex2int(const struct arg *arg_p, struct sample *smp, void *private)
|
|
|
|
|
{
|
|
|
|
|
long long int n = 0;
|
|
|
|
|
int i, c;
|
|
|
|
|
|
2018-07-13 04:54:26 -04:00
|
|
|
for (i = 0; i < smp->data.u.str.data; i++) {
|
|
|
|
|
if ((c = hex2i(smp->data.u.str.area[i])) < 0)
|
2017-10-24 03:27:34 -04:00
|
|
|
return 0;
|
|
|
|
|
n = (n << 4) + c;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
smp->data.u.sint = n;
|
|
|
|
|
smp->data.type = SMP_T_SINT;
|
|
|
|
|
smp->flags &= ~SMP_F_CONST;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-15 14:15:37 -04:00
|
|
|
/* hashes the binary input into a 32-bit unsigned int */
|
2015-05-11 09:20:49 -04:00
|
|
|
static int sample_conv_djb2(const struct arg *arg_p, struct sample *smp, void *private)
|
2014-07-15 14:15:37 -04:00
|
|
|
{
|
2018-07-13 04:54:26 -04:00
|
|
|
smp->data.u.sint = hash_djb2(smp->data.u.str.area,
|
|
|
|
|
smp->data.u.str.data);
|
2015-07-20 11:45:02 -04:00
|
|
|
if (arg_p && arg_p->data.sint)
|
2015-08-19 03:07:19 -04:00
|
|
|
smp->data.u.sint = full_hash(smp->data.u.sint);
|
2015-08-19 03:00:18 -04:00
|
|
|
smp->data.type = SMP_T_SINT;
|
2014-07-15 14:15:37 -04:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2017-12-15 01:13:48 -05:00
|
|
|
static int sample_conv_length(const struct arg *arg_p, struct sample *smp, void *private)
|
2017-12-13 07:41:34 -05:00
|
|
|
{
|
2018-07-13 04:54:26 -04:00
|
|
|
int i = smp->data.u.str.data;
|
2017-12-13 07:41:34 -05:00
|
|
|
smp->data.u.sint = i;
|
|
|
|
|
smp->data.type = SMP_T_SINT;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2015-05-11 09:20:49 -04:00
|
|
|
static int sample_conv_str2lower(const struct arg *arg_p, struct sample *smp, void *private)
|
2010-01-04 10:16:05 -05:00
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
2016-08-09 08:29:38 -04:00
|
|
|
if (!smp_make_rw(smp))
|
2010-09-23 12:02:19 -04:00
|
|
|
return 0;
|
|
|
|
|
|
2018-07-13 04:54:26 -04:00
|
|
|
for (i = 0; i < smp->data.u.str.data; i++) {
|
|
|
|
|
if ((smp->data.u.str.area[i] >= 'A') && (smp->data.u.str.area[i] <= 'Z'))
|
|
|
|
|
smp->data.u.str.area[i] += 'a' - 'A';
|
2010-01-04 10:16:05 -05:00
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-11 09:20:49 -04:00
|
|
|
static int sample_conv_str2upper(const struct arg *arg_p, struct sample *smp, void *private)
|
2010-01-04 10:16:05 -05:00
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
2016-08-09 08:29:38 -04:00
|
|
|
if (!smp_make_rw(smp))
|
2010-09-23 12:02:19 -04:00
|
|
|
return 0;
|
|
|
|
|
|
2018-07-13 04:54:26 -04:00
|
|
|
for (i = 0; i < smp->data.u.str.data; i++) {
|
|
|
|
|
if ((smp->data.u.str.area[i] >= 'a') && (smp->data.u.str.area[i] <= 'z'))
|
|
|
|
|
smp->data.u.str.area[i] += 'A' - 'a';
|
2010-01-04 10:16:05 -05:00
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-25 10:24:51 -05:00
|
|
|
/* takes the IPv4 mask in args[0] and an optional IPv6 mask in args[1] */
|
|
|
|
|
static int sample_conv_ipmask(const struct arg *args, struct sample *smp, void *private)
|
2010-01-26 12:01:41 -05:00
|
|
|
{
|
2018-01-25 10:24:51 -05:00
|
|
|
/* Attempt to convert to IPv4 to apply the correct mask. */
|
|
|
|
|
c_ipv62ip(smp);
|
|
|
|
|
|
|
|
|
|
if (smp->data.type == SMP_T_IPV4) {
|
|
|
|
|
smp->data.u.ipv4.s_addr &= args[0].data.ipv4.s_addr;
|
|
|
|
|
smp->data.type = SMP_T_IPV4;
|
|
|
|
|
}
|
|
|
|
|
else if (smp->data.type == SMP_T_IPV6) {
|
|
|
|
|
/* IPv6 cannot be converted without an IPv6 mask. */
|
|
|
|
|
if (args[1].type != ARGT_IPV6)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2020-02-25 03:43:22 -05:00
|
|
|
write_u64(&smp->data.u.ipv6.s6_addr[0],
|
|
|
|
|
read_u64(&smp->data.u.ipv6.s6_addr[0]) & read_u64(&args[1].data.ipv6.s6_addr[0]));
|
|
|
|
|
write_u64(&smp->data.u.ipv6.s6_addr[8],
|
|
|
|
|
read_u64(&smp->data.u.ipv6.s6_addr[8]) & read_u64(&args[1].data.ipv6.s6_addr[8]));
|
2018-01-25 10:24:51 -05:00
|
|
|
smp->data.type = SMP_T_IPV6;
|
|
|
|
|
}
|
|
|
|
|
|
2010-01-26 12:01:41 -05:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-10 10:37:47 -04:00
|
|
|
/* takes an UINT value on input supposed to represent the time since EPOCH,
|
|
|
|
|
* adds an optional offset found in args[1] and emits a string representing
|
|
|
|
|
* the local time in the format specified in args[1] using strftime().
|
|
|
|
|
*/
|
2015-05-11 09:20:49 -04:00
|
|
|
static int sample_conv_ltime(const struct arg *args, struct sample *smp, void *private)
|
2014-07-10 10:37:47 -04:00
|
|
|
{
|
2018-07-13 05:56:34 -04:00
|
|
|
struct buffer *temp;
|
2015-07-20 11:45:02 -04:00
|
|
|
/* With high numbers, the date returned can be negative, the 55 bits mask prevent this. */
|
2015-08-19 03:07:19 -04:00
|
|
|
time_t curr_date = smp->data.u.sint & 0x007fffffffffffffLL;
|
2015-07-07 18:15:20 -04:00
|
|
|
struct tm *tm;
|
2014-07-10 10:37:47 -04:00
|
|
|
|
|
|
|
|
/* add offset */
|
2015-07-20 11:45:02 -04:00
|
|
|
if (args[1].type == ARGT_SINT)
|
2014-07-10 10:37:47 -04:00
|
|
|
curr_date += args[1].data.sint;
|
|
|
|
|
|
2015-07-07 18:15:20 -04:00
|
|
|
tm = localtime(&curr_date);
|
|
|
|
|
if (!tm)
|
|
|
|
|
return 0;
|
2014-07-10 10:37:47 -04:00
|
|
|
temp = get_trash_chunk();
|
2018-07-13 04:54:26 -04:00
|
|
|
temp->data = strftime(temp->area, temp->size, args[0].data.str.area,
|
|
|
|
|
tm);
|
2015-08-19 03:07:19 -04:00
|
|
|
smp->data.u.str = *temp;
|
2015-08-19 03:00:18 -04:00
|
|
|
smp->data.type = SMP_T_STR;
|
2014-07-10 10:37:47 -04:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-15 14:15:37 -04:00
|
|
|
/* hashes the binary input into a 32-bit unsigned int */
|
2015-05-11 09:20:49 -04:00
|
|
|
static int sample_conv_sdbm(const struct arg *arg_p, struct sample *smp, void *private)
|
2014-07-15 14:15:37 -04:00
|
|
|
{
|
2018-07-13 04:54:26 -04:00
|
|
|
smp->data.u.sint = hash_sdbm(smp->data.u.str.area,
|
|
|
|
|
smp->data.u.str.data);
|
2015-07-20 11:45:02 -04:00
|
|
|
if (arg_p && arg_p->data.sint)
|
2015-08-19 03:07:19 -04:00
|
|
|
smp->data.u.sint = full_hash(smp->data.u.sint);
|
2015-08-19 03:00:18 -04:00
|
|
|
smp->data.type = SMP_T_SINT;
|
2014-07-15 14:15:37 -04:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-10 10:37:47 -04:00
|
|
|
/* takes an UINT value on input supposed to represent the time since EPOCH,
|
|
|
|
|
* adds an optional offset found in args[1] and emits a string representing
|
|
|
|
|
* the UTC date in the format specified in args[1] using strftime().
|
|
|
|
|
*/
|
2015-05-11 09:20:49 -04:00
|
|
|
static int sample_conv_utime(const struct arg *args, struct sample *smp, void *private)
|
2014-07-10 10:37:47 -04:00
|
|
|
{
|
2018-07-13 05:56:34 -04:00
|
|
|
struct buffer *temp;
|
2015-07-20 11:45:02 -04:00
|
|
|
/* With high numbers, the date returned can be negative, the 55 bits mask prevent this. */
|
2015-08-19 03:07:19 -04:00
|
|
|
time_t curr_date = smp->data.u.sint & 0x007fffffffffffffLL;
|
2015-07-07 18:15:20 -04:00
|
|
|
struct tm *tm;
|
2014-07-10 10:37:47 -04:00
|
|
|
|
|
|
|
|
/* add offset */
|
2015-07-20 11:45:02 -04:00
|
|
|
if (args[1].type == ARGT_SINT)
|
2014-07-10 10:37:47 -04:00
|
|
|
curr_date += args[1].data.sint;
|
|
|
|
|
|
2015-07-07 18:15:20 -04:00
|
|
|
tm = gmtime(&curr_date);
|
|
|
|
|
if (!tm)
|
|
|
|
|
return 0;
|
2014-07-10 10:37:47 -04:00
|
|
|
temp = get_trash_chunk();
|
2018-07-13 04:54:26 -04:00
|
|
|
temp->data = strftime(temp->area, temp->size, args[0].data.str.area,
|
|
|
|
|
tm);
|
2015-08-19 03:07:19 -04:00
|
|
|
smp->data.u.str = *temp;
|
2015-08-19 03:00:18 -04:00
|
|
|
smp->data.type = SMP_T_STR;
|
2014-07-10 10:37:47 -04:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-15 14:15:37 -04:00
|
|
|
/* hashes the binary input into a 32-bit unsigned int */
|
2015-05-11 09:20:49 -04:00
|
|
|
static int sample_conv_wt6(const struct arg *arg_p, struct sample *smp, void *private)
|
2014-07-15 14:15:37 -04:00
|
|
|
{
|
2018-07-13 04:54:26 -04:00
|
|
|
smp->data.u.sint = hash_wt6(smp->data.u.str.area,
|
|
|
|
|
smp->data.u.str.data);
|
2015-07-20 11:45:02 -04:00
|
|
|
if (arg_p && arg_p->data.sint)
|
2015-08-19 03:07:19 -04:00
|
|
|
smp->data.u.sint = full_hash(smp->data.u.sint);
|
2015-08-19 03:00:18 -04:00
|
|
|
smp->data.type = SMP_T_SINT;
|
2014-07-15 14:15:37 -04:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-26 05:46:11 -05:00
|
|
|
/* hashes the binary input into a 32-bit unsigned int using xxh.
|
|
|
|
|
* The seed of the hash defaults to 0 but can be changd in argument 1.
|
|
|
|
|
*/
|
|
|
|
|
static int sample_conv_xxh32(const struct arg *arg_p, struct sample *smp, void *private)
|
|
|
|
|
{
|
|
|
|
|
unsigned int seed;
|
|
|
|
|
|
|
|
|
|
if (arg_p && arg_p->data.sint)
|
|
|
|
|
seed = arg_p->data.sint;
|
|
|
|
|
else
|
|
|
|
|
seed = 0;
|
2018-07-13 04:54:26 -04:00
|
|
|
smp->data.u.sint = XXH32(smp->data.u.str.area, smp->data.u.str.data,
|
|
|
|
|
seed);
|
2016-12-26 05:46:11 -05:00
|
|
|
smp->data.type = SMP_T_SINT;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* hashes the binary input into a 64-bit unsigned int using xxh.
|
|
|
|
|
* In fact, the function returns a 64 bit unsigned, but the sample
|
|
|
|
|
* storage of haproxy only proposes 64-bits signed, so the value is
|
|
|
|
|
* cast as signed. This cast doesn't impact the hash repartition.
|
|
|
|
|
* The seed of the hash defaults to 0 but can be changd in argument 1.
|
|
|
|
|
*/
|
|
|
|
|
static int sample_conv_xxh64(const struct arg *arg_p, struct sample *smp, void *private)
|
|
|
|
|
{
|
|
|
|
|
unsigned long long int seed;
|
|
|
|
|
|
|
|
|
|
if (arg_p && arg_p->data.sint)
|
|
|
|
|
seed = (unsigned long long int)arg_p->data.sint;
|
|
|
|
|
else
|
|
|
|
|
seed = 0;
|
2018-07-13 04:54:26 -04:00
|
|
|
smp->data.u.sint = (long long int)XXH64(smp->data.u.str.area,
|
|
|
|
|
smp->data.u.str.data, seed);
|
2016-12-26 05:46:11 -05:00
|
|
|
smp->data.type = SMP_T_SINT;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-20 13:35:24 -05:00
|
|
|
/* hashes the binary input into a 32-bit unsigned int */
|
2015-05-11 09:20:49 -04:00
|
|
|
static int sample_conv_crc32(const struct arg *arg_p, struct sample *smp, void *private)
|
2015-01-20 13:35:24 -05:00
|
|
|
{
|
2018-07-13 04:54:26 -04:00
|
|
|
smp->data.u.sint = hash_crc32(smp->data.u.str.area,
|
|
|
|
|
smp->data.u.str.data);
|
2015-07-20 11:45:02 -04:00
|
|
|
if (arg_p && arg_p->data.sint)
|
2015-08-19 03:07:19 -04:00
|
|
|
smp->data.u.sint = full_hash(smp->data.u.sint);
|
2015-08-19 03:00:18 -04:00
|
|
|
smp->data.type = SMP_T_SINT;
|
2015-01-20 13:35:24 -05:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-21 06:19:01 -04:00
|
|
|
/* hashes the binary input into crc32c (RFC4960, Appendix B [8].) */
|
|
|
|
|
static int sample_conv_crc32c(const struct arg *arg_p, struct sample *smp, void *private)
|
|
|
|
|
{
|
2018-07-13 04:54:26 -04:00
|
|
|
smp->data.u.sint = hash_crc32c(smp->data.u.str.area,
|
|
|
|
|
smp->data.u.str.data);
|
2018-03-21 06:19:01 -04:00
|
|
|
if (arg_p && arg_p->data.sint)
|
|
|
|
|
smp->data.u.sint = full_hash(smp->data.u.sint);
|
|
|
|
|
smp->data.type = SMP_T_SINT;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
MINOR: sample: add "json" converter
This converter escapes string to use it as json/ascii escaped string.
It can read UTF-8 with differents behavior on errors and encode it in
json/ascii.
json([<input-code>])
Escapes the input string and produces an ASCII ouput string ready to use as a
JSON string. The converter tries to decode the input string according to the
<input-code> parameter. It can be "ascii", "utf8", "utf8s", "utf8"" or
"utf8ps". The "ascii" decoder never fails. The "utf8" decoder detects 3 types
of errors:
- bad UTF-8 sequence (lone continuation byte, bad number of continuation
bytes, ...)
- invalid range (the decoded value is within a UTF-8 prohibited range),
- code overlong (the value is encoded with more bytes than necessary).
The UTF-8 JSON encoding can produce a "too long value" error when the UTF-8
character is greater than 0xffff because the JSON string escape specification
only authorizes 4 hex digits for the value encoding. The UTF-8 decoder exists
in 4 variants designated by a combination of two suffix letters : "p" for
"permissive" and "s" for "silently ignore". The behaviors of the decoders
are :
- "ascii" : never fails ;
- "utf8" : fails on any detected errors ;
- "utf8s" : never fails, but removes characters corresponding to errors ;
- "utf8p" : accepts and fixes the overlong errors, but fails on any other
error ;
- "utf8ps" : never fails, accepts and fixes the overlong errors, but removes
characters corresponding to the other errors.
This converter is particularly useful for building properly escaped JSON for
logging to servers which consume JSON-formated traffic logs.
Example:
capture request header user-agent len 150
capture request header Host len 15
log-format {"ip":"%[src]","user-agent":"%[capture.req.hdr(1),json]"}
Input request from client 127.0.0.1:
GET / HTTP/1.0
User-Agent: Very "Ugly" UA 1/2
Output log:
{"ip":"127.0.0.1","user-agent":"Very \"Ugly\" UA 1\/2"}
2014-08-12 04:20:47 -04:00
|
|
|
/* This function escape special json characters. The returned string can be
|
|
|
|
|
* safely set between two '"' and used as json string. The json string is
|
|
|
|
|
* defined like this:
|
|
|
|
|
*
|
|
|
|
|
* any Unicode character except '"' or '\' or control character
|
|
|
|
|
* \", \\, \/, \b, \f, \n, \r, \t, \u + four-hex-digits
|
|
|
|
|
*
|
|
|
|
|
* The enum input_type contain all the allowed mode for decoding the input
|
|
|
|
|
* string.
|
|
|
|
|
*/
|
|
|
|
|
enum input_type {
|
|
|
|
|
IT_ASCII = 0,
|
|
|
|
|
IT_UTF8,
|
|
|
|
|
IT_UTF8S,
|
|
|
|
|
IT_UTF8P,
|
|
|
|
|
IT_UTF8PS,
|
|
|
|
|
};
|
|
|
|
|
static int sample_conv_json_check(struct arg *arg, struct sample_conv *conv,
|
|
|
|
|
const char *file, int line, char **err)
|
|
|
|
|
{
|
|
|
|
|
if (!arg) {
|
|
|
|
|
memprintf(err, "Unexpected empty arg list");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (arg->type != ARGT_STR) {
|
|
|
|
|
memprintf(err, "Unexpected arg type");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-13 04:54:26 -04:00
|
|
|
if (strcmp(arg->data.str.area, "") == 0) {
|
2015-07-20 11:45:02 -04:00
|
|
|
arg->type = ARGT_SINT;
|
|
|
|
|
arg->data.sint = IT_ASCII;
|
MINOR: sample: add "json" converter
This converter escapes string to use it as json/ascii escaped string.
It can read UTF-8 with differents behavior on errors and encode it in
json/ascii.
json([<input-code>])
Escapes the input string and produces an ASCII ouput string ready to use as a
JSON string. The converter tries to decode the input string according to the
<input-code> parameter. It can be "ascii", "utf8", "utf8s", "utf8"" or
"utf8ps". The "ascii" decoder never fails. The "utf8" decoder detects 3 types
of errors:
- bad UTF-8 sequence (lone continuation byte, bad number of continuation
bytes, ...)
- invalid range (the decoded value is within a UTF-8 prohibited range),
- code overlong (the value is encoded with more bytes than necessary).
The UTF-8 JSON encoding can produce a "too long value" error when the UTF-8
character is greater than 0xffff because the JSON string escape specification
only authorizes 4 hex digits for the value encoding. The UTF-8 decoder exists
in 4 variants designated by a combination of two suffix letters : "p" for
"permissive" and "s" for "silently ignore". The behaviors of the decoders
are :
- "ascii" : never fails ;
- "utf8" : fails on any detected errors ;
- "utf8s" : never fails, but removes characters corresponding to errors ;
- "utf8p" : accepts and fixes the overlong errors, but fails on any other
error ;
- "utf8ps" : never fails, accepts and fixes the overlong errors, but removes
characters corresponding to the other errors.
This converter is particularly useful for building properly escaped JSON for
logging to servers which consume JSON-formated traffic logs.
Example:
capture request header user-agent len 150
capture request header Host len 15
log-format {"ip":"%[src]","user-agent":"%[capture.req.hdr(1),json]"}
Input request from client 127.0.0.1:
GET / HTTP/1.0
User-Agent: Very "Ugly" UA 1/2
Output log:
{"ip":"127.0.0.1","user-agent":"Very \"Ugly\" UA 1\/2"}
2014-08-12 04:20:47 -04:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-13 04:54:26 -04:00
|
|
|
else if (strcmp(arg->data.str.area, "ascii") == 0) {
|
2015-07-20 11:45:02 -04:00
|
|
|
arg->type = ARGT_SINT;
|
|
|
|
|
arg->data.sint = IT_ASCII;
|
MINOR: sample: add "json" converter
This converter escapes string to use it as json/ascii escaped string.
It can read UTF-8 with differents behavior on errors and encode it in
json/ascii.
json([<input-code>])
Escapes the input string and produces an ASCII ouput string ready to use as a
JSON string. The converter tries to decode the input string according to the
<input-code> parameter. It can be "ascii", "utf8", "utf8s", "utf8"" or
"utf8ps". The "ascii" decoder never fails. The "utf8" decoder detects 3 types
of errors:
- bad UTF-8 sequence (lone continuation byte, bad number of continuation
bytes, ...)
- invalid range (the decoded value is within a UTF-8 prohibited range),
- code overlong (the value is encoded with more bytes than necessary).
The UTF-8 JSON encoding can produce a "too long value" error when the UTF-8
character is greater than 0xffff because the JSON string escape specification
only authorizes 4 hex digits for the value encoding. The UTF-8 decoder exists
in 4 variants designated by a combination of two suffix letters : "p" for
"permissive" and "s" for "silently ignore". The behaviors of the decoders
are :
- "ascii" : never fails ;
- "utf8" : fails on any detected errors ;
- "utf8s" : never fails, but removes characters corresponding to errors ;
- "utf8p" : accepts and fixes the overlong errors, but fails on any other
error ;
- "utf8ps" : never fails, accepts and fixes the overlong errors, but removes
characters corresponding to the other errors.
This converter is particularly useful for building properly escaped JSON for
logging to servers which consume JSON-formated traffic logs.
Example:
capture request header user-agent len 150
capture request header Host len 15
log-format {"ip":"%[src]","user-agent":"%[capture.req.hdr(1),json]"}
Input request from client 127.0.0.1:
GET / HTTP/1.0
User-Agent: Very "Ugly" UA 1/2
Output log:
{"ip":"127.0.0.1","user-agent":"Very \"Ugly\" UA 1\/2"}
2014-08-12 04:20:47 -04:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-13 04:54:26 -04:00
|
|
|
else if (strcmp(arg->data.str.area, "utf8") == 0) {
|
2015-07-20 11:45:02 -04:00
|
|
|
arg->type = ARGT_SINT;
|
|
|
|
|
arg->data.sint = IT_UTF8;
|
MINOR: sample: add "json" converter
This converter escapes string to use it as json/ascii escaped string.
It can read UTF-8 with differents behavior on errors and encode it in
json/ascii.
json([<input-code>])
Escapes the input string and produces an ASCII ouput string ready to use as a
JSON string. The converter tries to decode the input string according to the
<input-code> parameter. It can be "ascii", "utf8", "utf8s", "utf8"" or
"utf8ps". The "ascii" decoder never fails. The "utf8" decoder detects 3 types
of errors:
- bad UTF-8 sequence (lone continuation byte, bad number of continuation
bytes, ...)
- invalid range (the decoded value is within a UTF-8 prohibited range),
- code overlong (the value is encoded with more bytes than necessary).
The UTF-8 JSON encoding can produce a "too long value" error when the UTF-8
character is greater than 0xffff because the JSON string escape specification
only authorizes 4 hex digits for the value encoding. The UTF-8 decoder exists
in 4 variants designated by a combination of two suffix letters : "p" for
"permissive" and "s" for "silently ignore". The behaviors of the decoders
are :
- "ascii" : never fails ;
- "utf8" : fails on any detected errors ;
- "utf8s" : never fails, but removes characters corresponding to errors ;
- "utf8p" : accepts and fixes the overlong errors, but fails on any other
error ;
- "utf8ps" : never fails, accepts and fixes the overlong errors, but removes
characters corresponding to the other errors.
This converter is particularly useful for building properly escaped JSON for
logging to servers which consume JSON-formated traffic logs.
Example:
capture request header user-agent len 150
capture request header Host len 15
log-format {"ip":"%[src]","user-agent":"%[capture.req.hdr(1),json]"}
Input request from client 127.0.0.1:
GET / HTTP/1.0
User-Agent: Very "Ugly" UA 1/2
Output log:
{"ip":"127.0.0.1","user-agent":"Very \"Ugly\" UA 1\/2"}
2014-08-12 04:20:47 -04:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-13 04:54:26 -04:00
|
|
|
else if (strcmp(arg->data.str.area, "utf8s") == 0) {
|
2015-07-20 11:45:02 -04:00
|
|
|
arg->type = ARGT_SINT;
|
|
|
|
|
arg->data.sint = IT_UTF8S;
|
MINOR: sample: add "json" converter
This converter escapes string to use it as json/ascii escaped string.
It can read UTF-8 with differents behavior on errors and encode it in
json/ascii.
json([<input-code>])
Escapes the input string and produces an ASCII ouput string ready to use as a
JSON string. The converter tries to decode the input string according to the
<input-code> parameter. It can be "ascii", "utf8", "utf8s", "utf8"" or
"utf8ps". The "ascii" decoder never fails. The "utf8" decoder detects 3 types
of errors:
- bad UTF-8 sequence (lone continuation byte, bad number of continuation
bytes, ...)
- invalid range (the decoded value is within a UTF-8 prohibited range),
- code overlong (the value is encoded with more bytes than necessary).
The UTF-8 JSON encoding can produce a "too long value" error when the UTF-8
character is greater than 0xffff because the JSON string escape specification
only authorizes 4 hex digits for the value encoding. The UTF-8 decoder exists
in 4 variants designated by a combination of two suffix letters : "p" for
"permissive" and "s" for "silently ignore". The behaviors of the decoders
are :
- "ascii" : never fails ;
- "utf8" : fails on any detected errors ;
- "utf8s" : never fails, but removes characters corresponding to errors ;
- "utf8p" : accepts and fixes the overlong errors, but fails on any other
error ;
- "utf8ps" : never fails, accepts and fixes the overlong errors, but removes
characters corresponding to the other errors.
This converter is particularly useful for building properly escaped JSON for
logging to servers which consume JSON-formated traffic logs.
Example:
capture request header user-agent len 150
capture request header Host len 15
log-format {"ip":"%[src]","user-agent":"%[capture.req.hdr(1),json]"}
Input request from client 127.0.0.1:
GET / HTTP/1.0
User-Agent: Very "Ugly" UA 1/2
Output log:
{"ip":"127.0.0.1","user-agent":"Very \"Ugly\" UA 1\/2"}
2014-08-12 04:20:47 -04:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-13 04:54:26 -04:00
|
|
|
else if (strcmp(arg->data.str.area, "utf8p") == 0) {
|
2015-07-20 11:45:02 -04:00
|
|
|
arg->type = ARGT_SINT;
|
|
|
|
|
arg->data.sint = IT_UTF8P;
|
MINOR: sample: add "json" converter
This converter escapes string to use it as json/ascii escaped string.
It can read UTF-8 with differents behavior on errors and encode it in
json/ascii.
json([<input-code>])
Escapes the input string and produces an ASCII ouput string ready to use as a
JSON string. The converter tries to decode the input string according to the
<input-code> parameter. It can be "ascii", "utf8", "utf8s", "utf8"" or
"utf8ps". The "ascii" decoder never fails. The "utf8" decoder detects 3 types
of errors:
- bad UTF-8 sequence (lone continuation byte, bad number of continuation
bytes, ...)
- invalid range (the decoded value is within a UTF-8 prohibited range),
- code overlong (the value is encoded with more bytes than necessary).
The UTF-8 JSON encoding can produce a "too long value" error when the UTF-8
character is greater than 0xffff because the JSON string escape specification
only authorizes 4 hex digits for the value encoding. The UTF-8 decoder exists
in 4 variants designated by a combination of two suffix letters : "p" for
"permissive" and "s" for "silently ignore". The behaviors of the decoders
are :
- "ascii" : never fails ;
- "utf8" : fails on any detected errors ;
- "utf8s" : never fails, but removes characters corresponding to errors ;
- "utf8p" : accepts and fixes the overlong errors, but fails on any other
error ;
- "utf8ps" : never fails, accepts and fixes the overlong errors, but removes
characters corresponding to the other errors.
This converter is particularly useful for building properly escaped JSON for
logging to servers which consume JSON-formated traffic logs.
Example:
capture request header user-agent len 150
capture request header Host len 15
log-format {"ip":"%[src]","user-agent":"%[capture.req.hdr(1),json]"}
Input request from client 127.0.0.1:
GET / HTTP/1.0
User-Agent: Very "Ugly" UA 1/2
Output log:
{"ip":"127.0.0.1","user-agent":"Very \"Ugly\" UA 1\/2"}
2014-08-12 04:20:47 -04:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-13 04:54:26 -04:00
|
|
|
else if (strcmp(arg->data.str.area, "utf8ps") == 0) {
|
2015-07-20 11:45:02 -04:00
|
|
|
arg->type = ARGT_SINT;
|
|
|
|
|
arg->data.sint = IT_UTF8PS;
|
MINOR: sample: add "json" converter
This converter escapes string to use it as json/ascii escaped string.
It can read UTF-8 with differents behavior on errors and encode it in
json/ascii.
json([<input-code>])
Escapes the input string and produces an ASCII ouput string ready to use as a
JSON string. The converter tries to decode the input string according to the
<input-code> parameter. It can be "ascii", "utf8", "utf8s", "utf8"" or
"utf8ps". The "ascii" decoder never fails. The "utf8" decoder detects 3 types
of errors:
- bad UTF-8 sequence (lone continuation byte, bad number of continuation
bytes, ...)
- invalid range (the decoded value is within a UTF-8 prohibited range),
- code overlong (the value is encoded with more bytes than necessary).
The UTF-8 JSON encoding can produce a "too long value" error when the UTF-8
character is greater than 0xffff because the JSON string escape specification
only authorizes 4 hex digits for the value encoding. The UTF-8 decoder exists
in 4 variants designated by a combination of two suffix letters : "p" for
"permissive" and "s" for "silently ignore". The behaviors of the decoders
are :
- "ascii" : never fails ;
- "utf8" : fails on any detected errors ;
- "utf8s" : never fails, but removes characters corresponding to errors ;
- "utf8p" : accepts and fixes the overlong errors, but fails on any other
error ;
- "utf8ps" : never fails, accepts and fixes the overlong errors, but removes
characters corresponding to the other errors.
This converter is particularly useful for building properly escaped JSON for
logging to servers which consume JSON-formated traffic logs.
Example:
capture request header user-agent len 150
capture request header Host len 15
log-format {"ip":"%[src]","user-agent":"%[capture.req.hdr(1),json]"}
Input request from client 127.0.0.1:
GET / HTTP/1.0
User-Agent: Very "Ugly" UA 1/2
Output log:
{"ip":"127.0.0.1","user-agent":"Very \"Ugly\" UA 1\/2"}
2014-08-12 04:20:47 -04:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
CLEANUP: log-format: useless file and line in json converter
The caller must log location information, so this information is
provided two times in the log line. The error log is like this:
[ALERT] 327/011513 (14291) : parsing [o3.conf:38]: 'http-response
set-header': Sample fetch <method,json(rrr)> failed with : invalid
args in conv method 'json' : Unexpected input code type at file
'o3.conf', line 38. Allowed value are 'ascii', 'utf8', 'utf8s',
'utf8p' and 'utf8ps'.
This patch removes the second location indication, the the same error
becomes:
[ALERT] 327/011637 (14367) : parsing [o3.conf:38]: 'http-response
set-header': Sample fetch <method,json(rrr)> failed with : invalid
args in conv method 'json' : Unexpected input code type. Allowed
value are 'ascii', 'utf8', 'utf8s', 'utf8p' and 'utf8ps'.
2016-11-22 19:13:57 -05:00
|
|
|
memprintf(err, "Unexpected input code type. "
|
|
|
|
|
"Allowed value are 'ascii', 'utf8', 'utf8s', 'utf8p' and 'utf8ps'");
|
MINOR: sample: add "json" converter
This converter escapes string to use it as json/ascii escaped string.
It can read UTF-8 with differents behavior on errors and encode it in
json/ascii.
json([<input-code>])
Escapes the input string and produces an ASCII ouput string ready to use as a
JSON string. The converter tries to decode the input string according to the
<input-code> parameter. It can be "ascii", "utf8", "utf8s", "utf8"" or
"utf8ps". The "ascii" decoder never fails. The "utf8" decoder detects 3 types
of errors:
- bad UTF-8 sequence (lone continuation byte, bad number of continuation
bytes, ...)
- invalid range (the decoded value is within a UTF-8 prohibited range),
- code overlong (the value is encoded with more bytes than necessary).
The UTF-8 JSON encoding can produce a "too long value" error when the UTF-8
character is greater than 0xffff because the JSON string escape specification
only authorizes 4 hex digits for the value encoding. The UTF-8 decoder exists
in 4 variants designated by a combination of two suffix letters : "p" for
"permissive" and "s" for "silently ignore". The behaviors of the decoders
are :
- "ascii" : never fails ;
- "utf8" : fails on any detected errors ;
- "utf8s" : never fails, but removes characters corresponding to errors ;
- "utf8p" : accepts and fixes the overlong errors, but fails on any other
error ;
- "utf8ps" : never fails, accepts and fixes the overlong errors, but removes
characters corresponding to the other errors.
This converter is particularly useful for building properly escaped JSON for
logging to servers which consume JSON-formated traffic logs.
Example:
capture request header user-agent len 150
capture request header Host len 15
log-format {"ip":"%[src]","user-agent":"%[capture.req.hdr(1),json]"}
Input request from client 127.0.0.1:
GET / HTTP/1.0
User-Agent: Very "Ugly" UA 1/2
Output log:
{"ip":"127.0.0.1","user-agent":"Very \"Ugly\" UA 1\/2"}
2014-08-12 04:20:47 -04:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-11 09:20:49 -04:00
|
|
|
static int sample_conv_json(const struct arg *arg_p, struct sample *smp, void *private)
|
MINOR: sample: add "json" converter
This converter escapes string to use it as json/ascii escaped string.
It can read UTF-8 with differents behavior on errors and encode it in
json/ascii.
json([<input-code>])
Escapes the input string and produces an ASCII ouput string ready to use as a
JSON string. The converter tries to decode the input string according to the
<input-code> parameter. It can be "ascii", "utf8", "utf8s", "utf8"" or
"utf8ps". The "ascii" decoder never fails. The "utf8" decoder detects 3 types
of errors:
- bad UTF-8 sequence (lone continuation byte, bad number of continuation
bytes, ...)
- invalid range (the decoded value is within a UTF-8 prohibited range),
- code overlong (the value is encoded with more bytes than necessary).
The UTF-8 JSON encoding can produce a "too long value" error when the UTF-8
character is greater than 0xffff because the JSON string escape specification
only authorizes 4 hex digits for the value encoding. The UTF-8 decoder exists
in 4 variants designated by a combination of two suffix letters : "p" for
"permissive" and "s" for "silently ignore". The behaviors of the decoders
are :
- "ascii" : never fails ;
- "utf8" : fails on any detected errors ;
- "utf8s" : never fails, but removes characters corresponding to errors ;
- "utf8p" : accepts and fixes the overlong errors, but fails on any other
error ;
- "utf8ps" : never fails, accepts and fixes the overlong errors, but removes
characters corresponding to the other errors.
This converter is particularly useful for building properly escaped JSON for
logging to servers which consume JSON-formated traffic logs.
Example:
capture request header user-agent len 150
capture request header Host len 15
log-format {"ip":"%[src]","user-agent":"%[capture.req.hdr(1),json]"}
Input request from client 127.0.0.1:
GET / HTTP/1.0
User-Agent: Very "Ugly" UA 1/2
Output log:
{"ip":"127.0.0.1","user-agent":"Very \"Ugly\" UA 1\/2"}
2014-08-12 04:20:47 -04:00
|
|
|
{
|
2018-07-13 05:56:34 -04:00
|
|
|
struct buffer *temp;
|
MINOR: sample: add "json" converter
This converter escapes string to use it as json/ascii escaped string.
It can read UTF-8 with differents behavior on errors and encode it in
json/ascii.
json([<input-code>])
Escapes the input string and produces an ASCII ouput string ready to use as a
JSON string. The converter tries to decode the input string according to the
<input-code> parameter. It can be "ascii", "utf8", "utf8s", "utf8"" or
"utf8ps". The "ascii" decoder never fails. The "utf8" decoder detects 3 types
of errors:
- bad UTF-8 sequence (lone continuation byte, bad number of continuation
bytes, ...)
- invalid range (the decoded value is within a UTF-8 prohibited range),
- code overlong (the value is encoded with more bytes than necessary).
The UTF-8 JSON encoding can produce a "too long value" error when the UTF-8
character is greater than 0xffff because the JSON string escape specification
only authorizes 4 hex digits for the value encoding. The UTF-8 decoder exists
in 4 variants designated by a combination of two suffix letters : "p" for
"permissive" and "s" for "silently ignore". The behaviors of the decoders
are :
- "ascii" : never fails ;
- "utf8" : fails on any detected errors ;
- "utf8s" : never fails, but removes characters corresponding to errors ;
- "utf8p" : accepts and fixes the overlong errors, but fails on any other
error ;
- "utf8ps" : never fails, accepts and fixes the overlong errors, but removes
characters corresponding to the other errors.
This converter is particularly useful for building properly escaped JSON for
logging to servers which consume JSON-formated traffic logs.
Example:
capture request header user-agent len 150
capture request header Host len 15
log-format {"ip":"%[src]","user-agent":"%[capture.req.hdr(1),json]"}
Input request from client 127.0.0.1:
GET / HTTP/1.0
User-Agent: Very "Ugly" UA 1/2
Output log:
{"ip":"127.0.0.1","user-agent":"Very \"Ugly\" UA 1\/2"}
2014-08-12 04:20:47 -04:00
|
|
|
char _str[7]; /* \u + 4 hex digit + null char for sprintf. */
|
|
|
|
|
const char *str;
|
|
|
|
|
int len;
|
|
|
|
|
enum input_type input_type = IT_ASCII;
|
|
|
|
|
unsigned int c;
|
|
|
|
|
unsigned int ret;
|
|
|
|
|
char *p;
|
|
|
|
|
|
|
|
|
|
if (arg_p)
|
2015-07-20 11:45:02 -04:00
|
|
|
input_type = arg_p->data.sint;
|
MINOR: sample: add "json" converter
This converter escapes string to use it as json/ascii escaped string.
It can read UTF-8 with differents behavior on errors and encode it in
json/ascii.
json([<input-code>])
Escapes the input string and produces an ASCII ouput string ready to use as a
JSON string. The converter tries to decode the input string according to the
<input-code> parameter. It can be "ascii", "utf8", "utf8s", "utf8"" or
"utf8ps". The "ascii" decoder never fails. The "utf8" decoder detects 3 types
of errors:
- bad UTF-8 sequence (lone continuation byte, bad number of continuation
bytes, ...)
- invalid range (the decoded value is within a UTF-8 prohibited range),
- code overlong (the value is encoded with more bytes than necessary).
The UTF-8 JSON encoding can produce a "too long value" error when the UTF-8
character is greater than 0xffff because the JSON string escape specification
only authorizes 4 hex digits for the value encoding. The UTF-8 decoder exists
in 4 variants designated by a combination of two suffix letters : "p" for
"permissive" and "s" for "silently ignore". The behaviors of the decoders
are :
- "ascii" : never fails ;
- "utf8" : fails on any detected errors ;
- "utf8s" : never fails, but removes characters corresponding to errors ;
- "utf8p" : accepts and fixes the overlong errors, but fails on any other
error ;
- "utf8ps" : never fails, accepts and fixes the overlong errors, but removes
characters corresponding to the other errors.
This converter is particularly useful for building properly escaped JSON for
logging to servers which consume JSON-formated traffic logs.
Example:
capture request header user-agent len 150
capture request header Host len 15
log-format {"ip":"%[src]","user-agent":"%[capture.req.hdr(1),json]"}
Input request from client 127.0.0.1:
GET / HTTP/1.0
User-Agent: Very "Ugly" UA 1/2
Output log:
{"ip":"127.0.0.1","user-agent":"Very \"Ugly\" UA 1\/2"}
2014-08-12 04:20:47 -04:00
|
|
|
|
|
|
|
|
temp = get_trash_chunk();
|
2018-07-13 04:54:26 -04:00
|
|
|
temp->data = 0;
|
MINOR: sample: add "json" converter
This converter escapes string to use it as json/ascii escaped string.
It can read UTF-8 with differents behavior on errors and encode it in
json/ascii.
json([<input-code>])
Escapes the input string and produces an ASCII ouput string ready to use as a
JSON string. The converter tries to decode the input string according to the
<input-code> parameter. It can be "ascii", "utf8", "utf8s", "utf8"" or
"utf8ps". The "ascii" decoder never fails. The "utf8" decoder detects 3 types
of errors:
- bad UTF-8 sequence (lone continuation byte, bad number of continuation
bytes, ...)
- invalid range (the decoded value is within a UTF-8 prohibited range),
- code overlong (the value is encoded with more bytes than necessary).
The UTF-8 JSON encoding can produce a "too long value" error when the UTF-8
character is greater than 0xffff because the JSON string escape specification
only authorizes 4 hex digits for the value encoding. The UTF-8 decoder exists
in 4 variants designated by a combination of two suffix letters : "p" for
"permissive" and "s" for "silently ignore". The behaviors of the decoders
are :
- "ascii" : never fails ;
- "utf8" : fails on any detected errors ;
- "utf8s" : never fails, but removes characters corresponding to errors ;
- "utf8p" : accepts and fixes the overlong errors, but fails on any other
error ;
- "utf8ps" : never fails, accepts and fixes the overlong errors, but removes
characters corresponding to the other errors.
This converter is particularly useful for building properly escaped JSON for
logging to servers which consume JSON-formated traffic logs.
Example:
capture request header user-agent len 150
capture request header Host len 15
log-format {"ip":"%[src]","user-agent":"%[capture.req.hdr(1),json]"}
Input request from client 127.0.0.1:
GET / HTTP/1.0
User-Agent: Very "Ugly" UA 1/2
Output log:
{"ip":"127.0.0.1","user-agent":"Very \"Ugly\" UA 1\/2"}
2014-08-12 04:20:47 -04:00
|
|
|
|
2018-07-13 04:54:26 -04:00
|
|
|
p = smp->data.u.str.area;
|
|
|
|
|
while (p < smp->data.u.str.area + smp->data.u.str.data) {
|
MINOR: sample: add "json" converter
This converter escapes string to use it as json/ascii escaped string.
It can read UTF-8 with differents behavior on errors and encode it in
json/ascii.
json([<input-code>])
Escapes the input string and produces an ASCII ouput string ready to use as a
JSON string. The converter tries to decode the input string according to the
<input-code> parameter. It can be "ascii", "utf8", "utf8s", "utf8"" or
"utf8ps". The "ascii" decoder never fails. The "utf8" decoder detects 3 types
of errors:
- bad UTF-8 sequence (lone continuation byte, bad number of continuation
bytes, ...)
- invalid range (the decoded value is within a UTF-8 prohibited range),
- code overlong (the value is encoded with more bytes than necessary).
The UTF-8 JSON encoding can produce a "too long value" error when the UTF-8
character is greater than 0xffff because the JSON string escape specification
only authorizes 4 hex digits for the value encoding. The UTF-8 decoder exists
in 4 variants designated by a combination of two suffix letters : "p" for
"permissive" and "s" for "silently ignore". The behaviors of the decoders
are :
- "ascii" : never fails ;
- "utf8" : fails on any detected errors ;
- "utf8s" : never fails, but removes characters corresponding to errors ;
- "utf8p" : accepts and fixes the overlong errors, but fails on any other
error ;
- "utf8ps" : never fails, accepts and fixes the overlong errors, but removes
characters corresponding to the other errors.
This converter is particularly useful for building properly escaped JSON for
logging to servers which consume JSON-formated traffic logs.
Example:
capture request header user-agent len 150
capture request header Host len 15
log-format {"ip":"%[src]","user-agent":"%[capture.req.hdr(1),json]"}
Input request from client 127.0.0.1:
GET / HTTP/1.0
User-Agent: Very "Ugly" UA 1/2
Output log:
{"ip":"127.0.0.1","user-agent":"Very \"Ugly\" UA 1\/2"}
2014-08-12 04:20:47 -04:00
|
|
|
|
|
|
|
|
if (input_type == IT_ASCII) {
|
|
|
|
|
/* Read input as ASCII. */
|
|
|
|
|
c = *(unsigned char *)p;
|
|
|
|
|
p++;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* Read input as UTF8. */
|
2018-07-13 04:54:26 -04:00
|
|
|
ret = utf8_next(p,
|
|
|
|
|
smp->data.u.str.data - ( p - smp->data.u.str.area),
|
|
|
|
|
&c);
|
MINOR: sample: add "json" converter
This converter escapes string to use it as json/ascii escaped string.
It can read UTF-8 with differents behavior on errors and encode it in
json/ascii.
json([<input-code>])
Escapes the input string and produces an ASCII ouput string ready to use as a
JSON string. The converter tries to decode the input string according to the
<input-code> parameter. It can be "ascii", "utf8", "utf8s", "utf8"" or
"utf8ps". The "ascii" decoder never fails. The "utf8" decoder detects 3 types
of errors:
- bad UTF-8 sequence (lone continuation byte, bad number of continuation
bytes, ...)
- invalid range (the decoded value is within a UTF-8 prohibited range),
- code overlong (the value is encoded with more bytes than necessary).
The UTF-8 JSON encoding can produce a "too long value" error when the UTF-8
character is greater than 0xffff because the JSON string escape specification
only authorizes 4 hex digits for the value encoding. The UTF-8 decoder exists
in 4 variants designated by a combination of two suffix letters : "p" for
"permissive" and "s" for "silently ignore". The behaviors of the decoders
are :
- "ascii" : never fails ;
- "utf8" : fails on any detected errors ;
- "utf8s" : never fails, but removes characters corresponding to errors ;
- "utf8p" : accepts and fixes the overlong errors, but fails on any other
error ;
- "utf8ps" : never fails, accepts and fixes the overlong errors, but removes
characters corresponding to the other errors.
This converter is particularly useful for building properly escaped JSON for
logging to servers which consume JSON-formated traffic logs.
Example:
capture request header user-agent len 150
capture request header Host len 15
log-format {"ip":"%[src]","user-agent":"%[capture.req.hdr(1),json]"}
Input request from client 127.0.0.1:
GET / HTTP/1.0
User-Agent: Very "Ugly" UA 1/2
Output log:
{"ip":"127.0.0.1","user-agent":"Very \"Ugly\" UA 1\/2"}
2014-08-12 04:20:47 -04:00
|
|
|
p += utf8_return_length(ret);
|
|
|
|
|
|
|
|
|
|
if (input_type == IT_UTF8 && utf8_return_code(ret) != UTF8_CODE_OK)
|
|
|
|
|
return 0;
|
|
|
|
|
if (input_type == IT_UTF8S && utf8_return_code(ret) != UTF8_CODE_OK)
|
|
|
|
|
continue;
|
|
|
|
|
if (input_type == IT_UTF8P && utf8_return_code(ret) & (UTF8_CODE_INVRANGE|UTF8_CODE_BADSEQ))
|
|
|
|
|
return 0;
|
|
|
|
|
if (input_type == IT_UTF8PS && utf8_return_code(ret) & (UTF8_CODE_INVRANGE|UTF8_CODE_BADSEQ))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
/* Check too big values. */
|
|
|
|
|
if ((unsigned int)c > 0xffff) {
|
|
|
|
|
if (input_type == IT_UTF8 || input_type == IT_UTF8P)
|
|
|
|
|
return 0;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Convert character. */
|
|
|
|
|
if (c == '"') {
|
|
|
|
|
len = 2;
|
|
|
|
|
str = "\\\"";
|
|
|
|
|
}
|
|
|
|
|
else if (c == '\\') {
|
|
|
|
|
len = 2;
|
|
|
|
|
str = "\\\\";
|
|
|
|
|
}
|
|
|
|
|
else if (c == '/') {
|
|
|
|
|
len = 2;
|
|
|
|
|
str = "\\/";
|
|
|
|
|
}
|
|
|
|
|
else if (c == '\b') {
|
|
|
|
|
len = 2;
|
|
|
|
|
str = "\\b";
|
|
|
|
|
}
|
|
|
|
|
else if (c == '\f') {
|
|
|
|
|
len = 2;
|
|
|
|
|
str = "\\f";
|
|
|
|
|
}
|
|
|
|
|
else if (c == '\r') {
|
|
|
|
|
len = 2;
|
|
|
|
|
str = "\\r";
|
|
|
|
|
}
|
|
|
|
|
else if (c == '\n') {
|
|
|
|
|
len = 2;
|
|
|
|
|
str = "\\n";
|
|
|
|
|
}
|
|
|
|
|
else if (c == '\t') {
|
|
|
|
|
len = 2;
|
|
|
|
|
str = "\\t";
|
|
|
|
|
}
|
2020-02-25 02:16:33 -05:00
|
|
|
else if (c > 0xff || !isprint((unsigned char)c)) {
|
MINOR: sample: add "json" converter
This converter escapes string to use it as json/ascii escaped string.
It can read UTF-8 with differents behavior on errors and encode it in
json/ascii.
json([<input-code>])
Escapes the input string and produces an ASCII ouput string ready to use as a
JSON string. The converter tries to decode the input string according to the
<input-code> parameter. It can be "ascii", "utf8", "utf8s", "utf8"" or
"utf8ps". The "ascii" decoder never fails. The "utf8" decoder detects 3 types
of errors:
- bad UTF-8 sequence (lone continuation byte, bad number of continuation
bytes, ...)
- invalid range (the decoded value is within a UTF-8 prohibited range),
- code overlong (the value is encoded with more bytes than necessary).
The UTF-8 JSON encoding can produce a "too long value" error when the UTF-8
character is greater than 0xffff because the JSON string escape specification
only authorizes 4 hex digits for the value encoding. The UTF-8 decoder exists
in 4 variants designated by a combination of two suffix letters : "p" for
"permissive" and "s" for "silently ignore". The behaviors of the decoders
are :
- "ascii" : never fails ;
- "utf8" : fails on any detected errors ;
- "utf8s" : never fails, but removes characters corresponding to errors ;
- "utf8p" : accepts and fixes the overlong errors, but fails on any other
error ;
- "utf8ps" : never fails, accepts and fixes the overlong errors, but removes
characters corresponding to the other errors.
This converter is particularly useful for building properly escaped JSON for
logging to servers which consume JSON-formated traffic logs.
Example:
capture request header user-agent len 150
capture request header Host len 15
log-format {"ip":"%[src]","user-agent":"%[capture.req.hdr(1),json]"}
Input request from client 127.0.0.1:
GET / HTTP/1.0
User-Agent: Very "Ugly" UA 1/2
Output log:
{"ip":"127.0.0.1","user-agent":"Very \"Ugly\" UA 1\/2"}
2014-08-12 04:20:47 -04:00
|
|
|
/* isprint generate a segfault if c is too big. The man says that
|
|
|
|
|
* c must have the value of an unsigned char or EOF.
|
|
|
|
|
*/
|
|
|
|
|
len = 6;
|
|
|
|
|
_str[0] = '\\';
|
|
|
|
|
_str[1] = 'u';
|
|
|
|
|
snprintf(&_str[2], 5, "%04x", (unsigned short)c);
|
|
|
|
|
str = _str;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
len = 1;
|
2020-02-25 02:37:37 -05:00
|
|
|
_str[0] = c;
|
|
|
|
|
str = _str;
|
MINOR: sample: add "json" converter
This converter escapes string to use it as json/ascii escaped string.
It can read UTF-8 with differents behavior on errors and encode it in
json/ascii.
json([<input-code>])
Escapes the input string and produces an ASCII ouput string ready to use as a
JSON string. The converter tries to decode the input string according to the
<input-code> parameter. It can be "ascii", "utf8", "utf8s", "utf8"" or
"utf8ps". The "ascii" decoder never fails. The "utf8" decoder detects 3 types
of errors:
- bad UTF-8 sequence (lone continuation byte, bad number of continuation
bytes, ...)
- invalid range (the decoded value is within a UTF-8 prohibited range),
- code overlong (the value is encoded with more bytes than necessary).
The UTF-8 JSON encoding can produce a "too long value" error when the UTF-8
character is greater than 0xffff because the JSON string escape specification
only authorizes 4 hex digits for the value encoding. The UTF-8 decoder exists
in 4 variants designated by a combination of two suffix letters : "p" for
"permissive" and "s" for "silently ignore". The behaviors of the decoders
are :
- "ascii" : never fails ;
- "utf8" : fails on any detected errors ;
- "utf8s" : never fails, but removes characters corresponding to errors ;
- "utf8p" : accepts and fixes the overlong errors, but fails on any other
error ;
- "utf8ps" : never fails, accepts and fixes the overlong errors, but removes
characters corresponding to the other errors.
This converter is particularly useful for building properly escaped JSON for
logging to servers which consume JSON-formated traffic logs.
Example:
capture request header user-agent len 150
capture request header Host len 15
log-format {"ip":"%[src]","user-agent":"%[capture.req.hdr(1),json]"}
Input request from client 127.0.0.1:
GET / HTTP/1.0
User-Agent: Very "Ugly" UA 1/2
Output log:
{"ip":"127.0.0.1","user-agent":"Very \"Ugly\" UA 1\/2"}
2014-08-12 04:20:47 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Check length */
|
2018-07-13 04:54:26 -04:00
|
|
|
if (temp->data + len > temp->size)
|
MINOR: sample: add "json" converter
This converter escapes string to use it as json/ascii escaped string.
It can read UTF-8 with differents behavior on errors and encode it in
json/ascii.
json([<input-code>])
Escapes the input string and produces an ASCII ouput string ready to use as a
JSON string. The converter tries to decode the input string according to the
<input-code> parameter. It can be "ascii", "utf8", "utf8s", "utf8"" or
"utf8ps". The "ascii" decoder never fails. The "utf8" decoder detects 3 types
of errors:
- bad UTF-8 sequence (lone continuation byte, bad number of continuation
bytes, ...)
- invalid range (the decoded value is within a UTF-8 prohibited range),
- code overlong (the value is encoded with more bytes than necessary).
The UTF-8 JSON encoding can produce a "too long value" error when the UTF-8
character is greater than 0xffff because the JSON string escape specification
only authorizes 4 hex digits for the value encoding. The UTF-8 decoder exists
in 4 variants designated by a combination of two suffix letters : "p" for
"permissive" and "s" for "silently ignore". The behaviors of the decoders
are :
- "ascii" : never fails ;
- "utf8" : fails on any detected errors ;
- "utf8s" : never fails, but removes characters corresponding to errors ;
- "utf8p" : accepts and fixes the overlong errors, but fails on any other
error ;
- "utf8ps" : never fails, accepts and fixes the overlong errors, but removes
characters corresponding to the other errors.
This converter is particularly useful for building properly escaped JSON for
logging to servers which consume JSON-formated traffic logs.
Example:
capture request header user-agent len 150
capture request header Host len 15
log-format {"ip":"%[src]","user-agent":"%[capture.req.hdr(1),json]"}
Input request from client 127.0.0.1:
GET / HTTP/1.0
User-Agent: Very "Ugly" UA 1/2
Output log:
{"ip":"127.0.0.1","user-agent":"Very \"Ugly\" UA 1\/2"}
2014-08-12 04:20:47 -04:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
/* Copy string. */
|
2018-07-13 04:54:26 -04:00
|
|
|
memcpy(temp->area + temp->data, str, len);
|
|
|
|
|
temp->data += len;
|
MINOR: sample: add "json" converter
This converter escapes string to use it as json/ascii escaped string.
It can read UTF-8 with differents behavior on errors and encode it in
json/ascii.
json([<input-code>])
Escapes the input string and produces an ASCII ouput string ready to use as a
JSON string. The converter tries to decode the input string according to the
<input-code> parameter. It can be "ascii", "utf8", "utf8s", "utf8"" or
"utf8ps". The "ascii" decoder never fails. The "utf8" decoder detects 3 types
of errors:
- bad UTF-8 sequence (lone continuation byte, bad number of continuation
bytes, ...)
- invalid range (the decoded value is within a UTF-8 prohibited range),
- code overlong (the value is encoded with more bytes than necessary).
The UTF-8 JSON encoding can produce a "too long value" error when the UTF-8
character is greater than 0xffff because the JSON string escape specification
only authorizes 4 hex digits for the value encoding. The UTF-8 decoder exists
in 4 variants designated by a combination of two suffix letters : "p" for
"permissive" and "s" for "silently ignore". The behaviors of the decoders
are :
- "ascii" : never fails ;
- "utf8" : fails on any detected errors ;
- "utf8s" : never fails, but removes characters corresponding to errors ;
- "utf8p" : accepts and fixes the overlong errors, but fails on any other
error ;
- "utf8ps" : never fails, accepts and fixes the overlong errors, but removes
characters corresponding to the other errors.
This converter is particularly useful for building properly escaped JSON for
logging to servers which consume JSON-formated traffic logs.
Example:
capture request header user-agent len 150
capture request header Host len 15
log-format {"ip":"%[src]","user-agent":"%[capture.req.hdr(1),json]"}
Input request from client 127.0.0.1:
GET / HTTP/1.0
User-Agent: Very "Ugly" UA 1/2
Output log:
{"ip":"127.0.0.1","user-agent":"Very \"Ugly\" UA 1\/2"}
2014-08-12 04:20:47 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
smp->flags &= ~SMP_F_CONST;
|
2015-08-19 03:07:19 -04:00
|
|
|
smp->data.u.str = *temp;
|
2015-08-19 03:00:18 -04:00
|
|
|
smp->data.type = SMP_T_STR;
|
MINOR: sample: add "json" converter
This converter escapes string to use it as json/ascii escaped string.
It can read UTF-8 with differents behavior on errors and encode it in
json/ascii.
json([<input-code>])
Escapes the input string and produces an ASCII ouput string ready to use as a
JSON string. The converter tries to decode the input string according to the
<input-code> parameter. It can be "ascii", "utf8", "utf8s", "utf8"" or
"utf8ps". The "ascii" decoder never fails. The "utf8" decoder detects 3 types
of errors:
- bad UTF-8 sequence (lone continuation byte, bad number of continuation
bytes, ...)
- invalid range (the decoded value is within a UTF-8 prohibited range),
- code overlong (the value is encoded with more bytes than necessary).
The UTF-8 JSON encoding can produce a "too long value" error when the UTF-8
character is greater than 0xffff because the JSON string escape specification
only authorizes 4 hex digits for the value encoding. The UTF-8 decoder exists
in 4 variants designated by a combination of two suffix letters : "p" for
"permissive" and "s" for "silently ignore". The behaviors of the decoders
are :
- "ascii" : never fails ;
- "utf8" : fails on any detected errors ;
- "utf8s" : never fails, but removes characters corresponding to errors ;
- "utf8p" : accepts and fixes the overlong errors, but fails on any other
error ;
- "utf8ps" : never fails, accepts and fixes the overlong errors, but removes
characters corresponding to the other errors.
This converter is particularly useful for building properly escaped JSON for
logging to servers which consume JSON-formated traffic logs.
Example:
capture request header user-agent len 150
capture request header Host len 15
log-format {"ip":"%[src]","user-agent":"%[capture.req.hdr(1),json]"}
Input request from client 127.0.0.1:
GET / HTTP/1.0
User-Agent: Very "Ugly" UA 1/2
Output log:
{"ip":"127.0.0.1","user-agent":"Very \"Ugly\" UA 1\/2"}
2014-08-12 04:20:47 -04:00
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2014-11-03 09:32:43 -05:00
|
|
|
/* This sample function is designed to extract some bytes from an input buffer.
|
|
|
|
|
* First arg is the offset.
|
|
|
|
|
* Optional second arg is the length to truncate */
|
2015-05-11 09:20:49 -04:00
|
|
|
static int sample_conv_bytes(const struct arg *arg_p, struct sample *smp, void *private)
|
2014-11-03 09:32:43 -05:00
|
|
|
{
|
2018-07-13 04:54:26 -04:00
|
|
|
if (smp->data.u.str.data <= arg_p[0].data.sint) {
|
|
|
|
|
smp->data.u.str.data = 0;
|
2014-11-03 09:32:43 -05:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-19 03:07:19 -04:00
|
|
|
if (smp->data.u.str.size)
|
|
|
|
|
smp->data.u.str.size -= arg_p[0].data.sint;
|
2018-07-13 04:54:26 -04:00
|
|
|
smp->data.u.str.data -= arg_p[0].data.sint;
|
|
|
|
|
smp->data.u.str.area += arg_p[0].data.sint;
|
2014-11-03 09:32:43 -05:00
|
|
|
|
2018-07-13 04:54:26 -04:00
|
|
|
if ((arg_p[1].type == ARGT_SINT) && (arg_p[1].data.sint < smp->data.u.str.data))
|
|
|
|
|
smp->data.u.str.data = arg_p[1].data.sint;
|
2014-11-03 09:32:43 -05:00
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2014-11-03 11:07:03 -05:00
|
|
|
static int sample_conv_field_check(struct arg *args, struct sample_conv *conv,
|
|
|
|
|
const char *file, int line, char **err)
|
|
|
|
|
{
|
|
|
|
|
struct arg *arg = args;
|
|
|
|
|
|
|
|
|
|
if (!arg) {
|
|
|
|
|
memprintf(err, "Unexpected empty arg list");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-20 11:45:02 -04:00
|
|
|
if (arg->type != ARGT_SINT) {
|
2014-11-03 11:07:03 -05:00
|
|
|
memprintf(err, "Unexpected arg type");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-20 11:45:02 -04:00
|
|
|
if (!arg->data.sint) {
|
2014-11-03 11:07:03 -05:00
|
|
|
memprintf(err, "Unexpected value 0 for index");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
arg++;
|
|
|
|
|
|
|
|
|
|
if (arg->type != ARGT_STR) {
|
|
|
|
|
memprintf(err, "Unexpected arg type");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-13 04:54:26 -04:00
|
|
|
if (!arg->data.str.data) {
|
2014-11-03 11:07:03 -05:00
|
|
|
memprintf(err, "Empty separators list");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* This sample function is designed to a return selected part of a string (field).
|
|
|
|
|
* First arg is the index of the field (start at 1)
|
|
|
|
|
* Second arg is a char list of separators (type string)
|
|
|
|
|
*/
|
2015-05-11 09:20:49 -04:00
|
|
|
static int sample_conv_field(const struct arg *arg_p, struct sample *smp, void *private)
|
2014-11-03 11:07:03 -05:00
|
|
|
{
|
MEDIUM: sample: Extend functionality for field/word converters
Extend functionality of field/word converters, so it's possible
to extract field(s)/word(s) counting from the beginning/end and/or
extract multiple fields/words (including separators) eg.
str(f1_f2_f3__f5),field(2,_,2) # f2_f3
str(f1_f2_f3__f5),field(2,_,0) # f2_f3__f5
str(f1_f2_f3__f5),field(-2,_,3) # f2_f3_
str(f1_f2_f3__f5),field(-3,_,0) # f1_f2_f3
str(w1_w2_w3___w4),word(3,_,2) # w3___w4
str(w1_w2_w3___w4),word(2,_,0) # w2_w3___w4
str(w1_w2_w3___w4),word(-2,_,3) # w1_w2_w3
str(w1_w2_w3___w4),word(-3,_,0) # w1_w2
Change is backward compatible.
2018-04-16 08:30:46 -04:00
|
|
|
int field;
|
2014-11-03 11:07:03 -05:00
|
|
|
char *start, *end;
|
|
|
|
|
int i;
|
MEDIUM: sample: Extend functionality for field/word converters
Extend functionality of field/word converters, so it's possible
to extract field(s)/word(s) counting from the beginning/end and/or
extract multiple fields/words (including separators) eg.
str(f1_f2_f3__f5),field(2,_,2) # f2_f3
str(f1_f2_f3__f5),field(2,_,0) # f2_f3__f5
str(f1_f2_f3__f5),field(-2,_,3) # f2_f3_
str(f1_f2_f3__f5),field(-3,_,0) # f1_f2_f3
str(w1_w2_w3___w4),word(3,_,2) # w3___w4
str(w1_w2_w3___w4),word(2,_,0) # w2_w3___w4
str(w1_w2_w3___w4),word(-2,_,3) # w1_w2_w3
str(w1_w2_w3___w4),word(-3,_,0) # w1_w2
Change is backward compatible.
2018-04-16 08:30:46 -04:00
|
|
|
int count = (arg_p[2].type == ARGT_SINT) ? arg_p[2].data.sint : 1;
|
2014-11-03 11:07:03 -05:00
|
|
|
|
2015-07-20 11:45:02 -04:00
|
|
|
if (!arg_p[0].data.sint)
|
2014-11-03 11:07:03 -05:00
|
|
|
return 0;
|
|
|
|
|
|
MEDIUM: sample: Extend functionality for field/word converters
Extend functionality of field/word converters, so it's possible
to extract field(s)/word(s) counting from the beginning/end and/or
extract multiple fields/words (including separators) eg.
str(f1_f2_f3__f5),field(2,_,2) # f2_f3
str(f1_f2_f3__f5),field(2,_,0) # f2_f3__f5
str(f1_f2_f3__f5),field(-2,_,3) # f2_f3_
str(f1_f2_f3__f5),field(-3,_,0) # f1_f2_f3
str(w1_w2_w3___w4),word(3,_,2) # w3___w4
str(w1_w2_w3___w4),word(2,_,0) # w2_w3___w4
str(w1_w2_w3___w4),word(-2,_,3) # w1_w2_w3
str(w1_w2_w3___w4),word(-3,_,0) # w1_w2
Change is backward compatible.
2018-04-16 08:30:46 -04:00
|
|
|
if (arg_p[0].data.sint < 0) {
|
|
|
|
|
field = -1;
|
2018-07-13 04:54:26 -04:00
|
|
|
end = start = smp->data.u.str.area + smp->data.u.str.data;
|
|
|
|
|
while (start > smp->data.u.str.area) {
|
|
|
|
|
for (i = 0 ; i < arg_p[1].data.str.data; i++) {
|
|
|
|
|
if (*(start-1) == arg_p[1].data.str.area[i]) {
|
MEDIUM: sample: Extend functionality for field/word converters
Extend functionality of field/word converters, so it's possible
to extract field(s)/word(s) counting from the beginning/end and/or
extract multiple fields/words (including separators) eg.
str(f1_f2_f3__f5),field(2,_,2) # f2_f3
str(f1_f2_f3__f5),field(2,_,0) # f2_f3__f5
str(f1_f2_f3__f5),field(-2,_,3) # f2_f3_
str(f1_f2_f3__f5),field(-3,_,0) # f1_f2_f3
str(w1_w2_w3___w4),word(3,_,2) # w3___w4
str(w1_w2_w3___w4),word(2,_,0) # w2_w3___w4
str(w1_w2_w3___w4),word(-2,_,3) # w1_w2_w3
str(w1_w2_w3___w4),word(-3,_,0) # w1_w2
Change is backward compatible.
2018-04-16 08:30:46 -04:00
|
|
|
if (field == arg_p[0].data.sint) {
|
|
|
|
|
if (count == 1)
|
|
|
|
|
goto found;
|
|
|
|
|
else if (count > 1)
|
|
|
|
|
count--;
|
|
|
|
|
} else {
|
|
|
|
|
end = start-1;
|
|
|
|
|
field--;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
2014-11-03 11:07:03 -05:00
|
|
|
}
|
MEDIUM: sample: Extend functionality for field/word converters
Extend functionality of field/word converters, so it's possible
to extract field(s)/word(s) counting from the beginning/end and/or
extract multiple fields/words (including separators) eg.
str(f1_f2_f3__f5),field(2,_,2) # f2_f3
str(f1_f2_f3__f5),field(2,_,0) # f2_f3__f5
str(f1_f2_f3__f5),field(-2,_,3) # f2_f3_
str(f1_f2_f3__f5),field(-3,_,0) # f1_f2_f3
str(w1_w2_w3___w4),word(3,_,2) # w3___w4
str(w1_w2_w3___w4),word(2,_,0) # w2_w3___w4
str(w1_w2_w3___w4),word(-2,_,3) # w1_w2_w3
str(w1_w2_w3___w4),word(-3,_,0) # w1_w2
Change is backward compatible.
2018-04-16 08:30:46 -04:00
|
|
|
start--;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
field = 1;
|
2018-07-13 04:54:26 -04:00
|
|
|
end = start = smp->data.u.str.area;
|
|
|
|
|
while (end - smp->data.u.str.area < smp->data.u.str.data) {
|
|
|
|
|
for (i = 0 ; i < arg_p[1].data.str.data; i++) {
|
|
|
|
|
if (*end == arg_p[1].data.str.area[i]) {
|
MEDIUM: sample: Extend functionality for field/word converters
Extend functionality of field/word converters, so it's possible
to extract field(s)/word(s) counting from the beginning/end and/or
extract multiple fields/words (including separators) eg.
str(f1_f2_f3__f5),field(2,_,2) # f2_f3
str(f1_f2_f3__f5),field(2,_,0) # f2_f3__f5
str(f1_f2_f3__f5),field(-2,_,3) # f2_f3_
str(f1_f2_f3__f5),field(-3,_,0) # f1_f2_f3
str(w1_w2_w3___w4),word(3,_,2) # w3___w4
str(w1_w2_w3___w4),word(2,_,0) # w2_w3___w4
str(w1_w2_w3___w4),word(-2,_,3) # w1_w2_w3
str(w1_w2_w3___w4),word(-3,_,0) # w1_w2
Change is backward compatible.
2018-04-16 08:30:46 -04:00
|
|
|
if (field == arg_p[0].data.sint) {
|
|
|
|
|
if (count == 1)
|
|
|
|
|
goto found;
|
|
|
|
|
else if (count > 1)
|
|
|
|
|
count--;
|
|
|
|
|
} else {
|
|
|
|
|
start = end+1;
|
|
|
|
|
field++;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
end++;
|
2014-11-03 11:07:03 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Field not found */
|
2015-07-20 11:45:02 -04:00
|
|
|
if (field != arg_p[0].data.sint) {
|
2018-07-13 04:54:26 -04:00
|
|
|
smp->data.u.str.data = 0;
|
2019-10-16 09:11:15 -04:00
|
|
|
return 0;
|
2014-11-03 11:07:03 -05:00
|
|
|
}
|
|
|
|
|
found:
|
2018-07-13 04:54:26 -04:00
|
|
|
smp->data.u.str.data = end - start;
|
2014-11-03 11:07:03 -05:00
|
|
|
/* If ret string is len 0, no need to
|
|
|
|
|
change pointers or to update size */
|
2018-07-13 04:54:26 -04:00
|
|
|
if (!smp->data.u.str.data)
|
2014-11-03 11:07:03 -05:00
|
|
|
return 1;
|
|
|
|
|
|
2018-07-13 04:54:26 -04:00
|
|
|
smp->data.u.str.area = start;
|
2014-11-03 11:07:03 -05:00
|
|
|
|
|
|
|
|
/* Compute remaining size if needed
|
2015-08-19 03:07:19 -04:00
|
|
|
Note: smp->data.u.str.size cannot be set to 0 */
|
|
|
|
|
if (smp->data.u.str.size)
|
2018-07-13 04:54:26 -04:00
|
|
|
smp->data.u.str.size -= start - smp->data.u.str.area;
|
2014-11-03 11:07:03 -05:00
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2014-11-25 08:09:01 -05:00
|
|
|
/* This sample function is designed to return a word from a string.
|
|
|
|
|
* First arg is the index of the word (start at 1)
|
|
|
|
|
* Second arg is a char list of words separators (type string)
|
|
|
|
|
*/
|
2015-05-11 09:20:49 -04:00
|
|
|
static int sample_conv_word(const struct arg *arg_p, struct sample *smp, void *private)
|
2014-11-25 08:09:01 -05:00
|
|
|
{
|
MEDIUM: sample: Extend functionality for field/word converters
Extend functionality of field/word converters, so it's possible
to extract field(s)/word(s) counting from the beginning/end and/or
extract multiple fields/words (including separators) eg.
str(f1_f2_f3__f5),field(2,_,2) # f2_f3
str(f1_f2_f3__f5),field(2,_,0) # f2_f3__f5
str(f1_f2_f3__f5),field(-2,_,3) # f2_f3_
str(f1_f2_f3__f5),field(-3,_,0) # f1_f2_f3
str(w1_w2_w3___w4),word(3,_,2) # w3___w4
str(w1_w2_w3___w4),word(2,_,0) # w2_w3___w4
str(w1_w2_w3___w4),word(-2,_,3) # w1_w2_w3
str(w1_w2_w3___w4),word(-3,_,0) # w1_w2
Change is backward compatible.
2018-04-16 08:30:46 -04:00
|
|
|
int word;
|
2014-11-25 08:09:01 -05:00
|
|
|
char *start, *end;
|
|
|
|
|
int i, issep, inword;
|
MEDIUM: sample: Extend functionality for field/word converters
Extend functionality of field/word converters, so it's possible
to extract field(s)/word(s) counting from the beginning/end and/or
extract multiple fields/words (including separators) eg.
str(f1_f2_f3__f5),field(2,_,2) # f2_f3
str(f1_f2_f3__f5),field(2,_,0) # f2_f3__f5
str(f1_f2_f3__f5),field(-2,_,3) # f2_f3_
str(f1_f2_f3__f5),field(-3,_,0) # f1_f2_f3
str(w1_w2_w3___w4),word(3,_,2) # w3___w4
str(w1_w2_w3___w4),word(2,_,0) # w2_w3___w4
str(w1_w2_w3___w4),word(-2,_,3) # w1_w2_w3
str(w1_w2_w3___w4),word(-3,_,0) # w1_w2
Change is backward compatible.
2018-04-16 08:30:46 -04:00
|
|
|
int count = (arg_p[2].type == ARGT_SINT) ? arg_p[2].data.sint : 1;
|
2014-11-25 08:09:01 -05:00
|
|
|
|
2015-07-20 11:45:02 -04:00
|
|
|
if (!arg_p[0].data.sint)
|
2014-11-25 08:09:01 -05:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
word = 0;
|
|
|
|
|
inword = 0;
|
MEDIUM: sample: Extend functionality for field/word converters
Extend functionality of field/word converters, so it's possible
to extract field(s)/word(s) counting from the beginning/end and/or
extract multiple fields/words (including separators) eg.
str(f1_f2_f3__f5),field(2,_,2) # f2_f3
str(f1_f2_f3__f5),field(2,_,0) # f2_f3__f5
str(f1_f2_f3__f5),field(-2,_,3) # f2_f3_
str(f1_f2_f3__f5),field(-3,_,0) # f1_f2_f3
str(w1_w2_w3___w4),word(3,_,2) # w3___w4
str(w1_w2_w3___w4),word(2,_,0) # w2_w3___w4
str(w1_w2_w3___w4),word(-2,_,3) # w1_w2_w3
str(w1_w2_w3___w4),word(-3,_,0) # w1_w2
Change is backward compatible.
2018-04-16 08:30:46 -04:00
|
|
|
if (arg_p[0].data.sint < 0) {
|
2018-07-13 04:54:26 -04:00
|
|
|
end = start = smp->data.u.str.area + smp->data.u.str.data;
|
|
|
|
|
while (start > smp->data.u.str.area) {
|
MEDIUM: sample: Extend functionality for field/word converters
Extend functionality of field/word converters, so it's possible
to extract field(s)/word(s) counting from the beginning/end and/or
extract multiple fields/words (including separators) eg.
str(f1_f2_f3__f5),field(2,_,2) # f2_f3
str(f1_f2_f3__f5),field(2,_,0) # f2_f3__f5
str(f1_f2_f3__f5),field(-2,_,3) # f2_f3_
str(f1_f2_f3__f5),field(-3,_,0) # f1_f2_f3
str(w1_w2_w3___w4),word(3,_,2) # w3___w4
str(w1_w2_w3___w4),word(2,_,0) # w2_w3___w4
str(w1_w2_w3___w4),word(-2,_,3) # w1_w2_w3
str(w1_w2_w3___w4),word(-3,_,0) # w1_w2
Change is backward compatible.
2018-04-16 08:30:46 -04:00
|
|
|
issep = 0;
|
2018-07-13 04:54:26 -04:00
|
|
|
for (i = 0 ; i < arg_p[1].data.str.data; i++) {
|
|
|
|
|
if (*(start-1) == arg_p[1].data.str.area[i]) {
|
MEDIUM: sample: Extend functionality for field/word converters
Extend functionality of field/word converters, so it's possible
to extract field(s)/word(s) counting from the beginning/end and/or
extract multiple fields/words (including separators) eg.
str(f1_f2_f3__f5),field(2,_,2) # f2_f3
str(f1_f2_f3__f5),field(2,_,0) # f2_f3__f5
str(f1_f2_f3__f5),field(-2,_,3) # f2_f3_
str(f1_f2_f3__f5),field(-3,_,0) # f1_f2_f3
str(w1_w2_w3___w4),word(3,_,2) # w3___w4
str(w1_w2_w3___w4),word(2,_,0) # w2_w3___w4
str(w1_w2_w3___w4),word(-2,_,3) # w1_w2_w3
str(w1_w2_w3___w4),word(-3,_,0) # w1_w2
Change is backward compatible.
2018-04-16 08:30:46 -04:00
|
|
|
issep = 1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2014-11-25 08:09:01 -05:00
|
|
|
}
|
MEDIUM: sample: Extend functionality for field/word converters
Extend functionality of field/word converters, so it's possible
to extract field(s)/word(s) counting from the beginning/end and/or
extract multiple fields/words (including separators) eg.
str(f1_f2_f3__f5),field(2,_,2) # f2_f3
str(f1_f2_f3__f5),field(2,_,0) # f2_f3__f5
str(f1_f2_f3__f5),field(-2,_,3) # f2_f3_
str(f1_f2_f3__f5),field(-3,_,0) # f1_f2_f3
str(w1_w2_w3___w4),word(3,_,2) # w3___w4
str(w1_w2_w3___w4),word(2,_,0) # w2_w3___w4
str(w1_w2_w3___w4),word(-2,_,3) # w1_w2_w3
str(w1_w2_w3___w4),word(-3,_,0) # w1_w2
Change is backward compatible.
2018-04-16 08:30:46 -04:00
|
|
|
if (!inword) {
|
|
|
|
|
if (!issep) {
|
|
|
|
|
if (word != arg_p[0].data.sint) {
|
|
|
|
|
word--;
|
|
|
|
|
end = start;
|
|
|
|
|
}
|
|
|
|
|
inword = 1;
|
|
|
|
|
}
|
2014-11-25 08:09:01 -05:00
|
|
|
}
|
MEDIUM: sample: Extend functionality for field/word converters
Extend functionality of field/word converters, so it's possible
to extract field(s)/word(s) counting from the beginning/end and/or
extract multiple fields/words (including separators) eg.
str(f1_f2_f3__f5),field(2,_,2) # f2_f3
str(f1_f2_f3__f5),field(2,_,0) # f2_f3__f5
str(f1_f2_f3__f5),field(-2,_,3) # f2_f3_
str(f1_f2_f3__f5),field(-3,_,0) # f1_f2_f3
str(w1_w2_w3___w4),word(3,_,2) # w3___w4
str(w1_w2_w3___w4),word(2,_,0) # w2_w3___w4
str(w1_w2_w3___w4),word(-2,_,3) # w1_w2_w3
str(w1_w2_w3___w4),word(-3,_,0) # w1_w2
Change is backward compatible.
2018-04-16 08:30:46 -04:00
|
|
|
else if (issep) {
|
2018-04-19 04:33:28 -04:00
|
|
|
if (word == arg_p[0].data.sint) {
|
MEDIUM: sample: Extend functionality for field/word converters
Extend functionality of field/word converters, so it's possible
to extract field(s)/word(s) counting from the beginning/end and/or
extract multiple fields/words (including separators) eg.
str(f1_f2_f3__f5),field(2,_,2) # f2_f3
str(f1_f2_f3__f5),field(2,_,0) # f2_f3__f5
str(f1_f2_f3__f5),field(-2,_,3) # f2_f3_
str(f1_f2_f3__f5),field(-3,_,0) # f1_f2_f3
str(w1_w2_w3___w4),word(3,_,2) # w3___w4
str(w1_w2_w3___w4),word(2,_,0) # w2_w3___w4
str(w1_w2_w3___w4),word(-2,_,3) # w1_w2_w3
str(w1_w2_w3___w4),word(-3,_,0) # w1_w2
Change is backward compatible.
2018-04-16 08:30:46 -04:00
|
|
|
if (count == 1)
|
|
|
|
|
goto found;
|
|
|
|
|
else if (count > 1)
|
|
|
|
|
count--;
|
2018-04-19 04:33:28 -04:00
|
|
|
}
|
MEDIUM: sample: Extend functionality for field/word converters
Extend functionality of field/word converters, so it's possible
to extract field(s)/word(s) counting from the beginning/end and/or
extract multiple fields/words (including separators) eg.
str(f1_f2_f3__f5),field(2,_,2) # f2_f3
str(f1_f2_f3__f5),field(2,_,0) # f2_f3__f5
str(f1_f2_f3__f5),field(-2,_,3) # f2_f3_
str(f1_f2_f3__f5),field(-3,_,0) # f1_f2_f3
str(w1_w2_w3___w4),word(3,_,2) # w3___w4
str(w1_w2_w3___w4),word(2,_,0) # w2_w3___w4
str(w1_w2_w3___w4),word(-2,_,3) # w1_w2_w3
str(w1_w2_w3___w4),word(-3,_,0) # w1_w2
Change is backward compatible.
2018-04-16 08:30:46 -04:00
|
|
|
inword = 0;
|
|
|
|
|
}
|
|
|
|
|
start--;
|
2014-11-25 08:09:01 -05:00
|
|
|
}
|
MEDIUM: sample: Extend functionality for field/word converters
Extend functionality of field/word converters, so it's possible
to extract field(s)/word(s) counting from the beginning/end and/or
extract multiple fields/words (including separators) eg.
str(f1_f2_f3__f5),field(2,_,2) # f2_f3
str(f1_f2_f3__f5),field(2,_,0) # f2_f3__f5
str(f1_f2_f3__f5),field(-2,_,3) # f2_f3_
str(f1_f2_f3__f5),field(-3,_,0) # f1_f2_f3
str(w1_w2_w3___w4),word(3,_,2) # w3___w4
str(w1_w2_w3___w4),word(2,_,0) # w2_w3___w4
str(w1_w2_w3___w4),word(-2,_,3) # w1_w2_w3
str(w1_w2_w3___w4),word(-3,_,0) # w1_w2
Change is backward compatible.
2018-04-16 08:30:46 -04:00
|
|
|
} else {
|
2018-07-13 04:54:26 -04:00
|
|
|
end = start = smp->data.u.str.area;
|
|
|
|
|
while (end - smp->data.u.str.area < smp->data.u.str.data) {
|
MEDIUM: sample: Extend functionality for field/word converters
Extend functionality of field/word converters, so it's possible
to extract field(s)/word(s) counting from the beginning/end and/or
extract multiple fields/words (including separators) eg.
str(f1_f2_f3__f5),field(2,_,2) # f2_f3
str(f1_f2_f3__f5),field(2,_,0) # f2_f3__f5
str(f1_f2_f3__f5),field(-2,_,3) # f2_f3_
str(f1_f2_f3__f5),field(-3,_,0) # f1_f2_f3
str(w1_w2_w3___w4),word(3,_,2) # w3___w4
str(w1_w2_w3___w4),word(2,_,0) # w2_w3___w4
str(w1_w2_w3___w4),word(-2,_,3) # w1_w2_w3
str(w1_w2_w3___w4),word(-3,_,0) # w1_w2
Change is backward compatible.
2018-04-16 08:30:46 -04:00
|
|
|
issep = 0;
|
2018-07-13 04:54:26 -04:00
|
|
|
for (i = 0 ; i < arg_p[1].data.str.data; i++) {
|
|
|
|
|
if (*end == arg_p[1].data.str.area[i]) {
|
MEDIUM: sample: Extend functionality for field/word converters
Extend functionality of field/word converters, so it's possible
to extract field(s)/word(s) counting from the beginning/end and/or
extract multiple fields/words (including separators) eg.
str(f1_f2_f3__f5),field(2,_,2) # f2_f3
str(f1_f2_f3__f5),field(2,_,0) # f2_f3__f5
str(f1_f2_f3__f5),field(-2,_,3) # f2_f3_
str(f1_f2_f3__f5),field(-3,_,0) # f1_f2_f3
str(w1_w2_w3___w4),word(3,_,2) # w3___w4
str(w1_w2_w3___w4),word(2,_,0) # w2_w3___w4
str(w1_w2_w3___w4),word(-2,_,3) # w1_w2_w3
str(w1_w2_w3___w4),word(-3,_,0) # w1_w2
Change is backward compatible.
2018-04-16 08:30:46 -04:00
|
|
|
issep = 1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!inword) {
|
|
|
|
|
if (!issep) {
|
|
|
|
|
if (word != arg_p[0].data.sint) {
|
|
|
|
|
word++;
|
|
|
|
|
start = end;
|
|
|
|
|
}
|
|
|
|
|
inword = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (issep) {
|
2018-04-19 04:33:28 -04:00
|
|
|
if (word == arg_p[0].data.sint) {
|
MEDIUM: sample: Extend functionality for field/word converters
Extend functionality of field/word converters, so it's possible
to extract field(s)/word(s) counting from the beginning/end and/or
extract multiple fields/words (including separators) eg.
str(f1_f2_f3__f5),field(2,_,2) # f2_f3
str(f1_f2_f3__f5),field(2,_,0) # f2_f3__f5
str(f1_f2_f3__f5),field(-2,_,3) # f2_f3_
str(f1_f2_f3__f5),field(-3,_,0) # f1_f2_f3
str(w1_w2_w3___w4),word(3,_,2) # w3___w4
str(w1_w2_w3___w4),word(2,_,0) # w2_w3___w4
str(w1_w2_w3___w4),word(-2,_,3) # w1_w2_w3
str(w1_w2_w3___w4),word(-3,_,0) # w1_w2
Change is backward compatible.
2018-04-16 08:30:46 -04:00
|
|
|
if (count == 1)
|
|
|
|
|
goto found;
|
|
|
|
|
else if (count > 1)
|
|
|
|
|
count--;
|
2018-04-19 04:33:28 -04:00
|
|
|
}
|
MEDIUM: sample: Extend functionality for field/word converters
Extend functionality of field/word converters, so it's possible
to extract field(s)/word(s) counting from the beginning/end and/or
extract multiple fields/words (including separators) eg.
str(f1_f2_f3__f5),field(2,_,2) # f2_f3
str(f1_f2_f3__f5),field(2,_,0) # f2_f3__f5
str(f1_f2_f3__f5),field(-2,_,3) # f2_f3_
str(f1_f2_f3__f5),field(-3,_,0) # f1_f2_f3
str(w1_w2_w3___w4),word(3,_,2) # w3___w4
str(w1_w2_w3___w4),word(2,_,0) # w2_w3___w4
str(w1_w2_w3___w4),word(-2,_,3) # w1_w2_w3
str(w1_w2_w3___w4),word(-3,_,0) # w1_w2
Change is backward compatible.
2018-04-16 08:30:46 -04:00
|
|
|
inword = 0;
|
|
|
|
|
}
|
|
|
|
|
end++;
|
2014-11-25 08:09:01 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Field not found */
|
2015-07-20 11:45:02 -04:00
|
|
|
if (word != arg_p[0].data.sint) {
|
2018-07-13 04:54:26 -04:00
|
|
|
smp->data.u.str.data = 0;
|
2014-11-25 08:09:01 -05:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
found:
|
2018-07-13 04:54:26 -04:00
|
|
|
smp->data.u.str.data = end - start;
|
2014-11-25 08:09:01 -05:00
|
|
|
/* If ret string is len 0, no need to
|
|
|
|
|
change pointers or to update size */
|
2018-07-13 04:54:26 -04:00
|
|
|
if (!smp->data.u.str.data)
|
2014-11-25 08:09:01 -05:00
|
|
|
return 1;
|
|
|
|
|
|
2018-07-13 04:54:26 -04:00
|
|
|
smp->data.u.str.area = start;
|
2014-11-25 08:09:01 -05:00
|
|
|
|
|
|
|
|
/* Compute remaining size if needed
|
2015-08-19 03:07:19 -04:00
|
|
|
Note: smp->data.u.str.size cannot be set to 0 */
|
|
|
|
|
if (smp->data.u.str.size)
|
2018-07-13 04:54:26 -04:00
|
|
|
smp->data.u.str.size -= start - smp->data.u.str.area;
|
2014-11-25 08:09:01 -05:00
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-20 13:47:06 -05:00
|
|
|
static int sample_conv_regsub_check(struct arg *args, struct sample_conv *conv,
|
|
|
|
|
const char *file, int line, char **err)
|
|
|
|
|
{
|
|
|
|
|
struct arg *arg = args;
|
|
|
|
|
char *p;
|
|
|
|
|
int len;
|
|
|
|
|
|
|
|
|
|
/* arg0 is a regex, it uses type_flag for ICASE and global match */
|
|
|
|
|
arg[0].type_flags = 0;
|
|
|
|
|
|
|
|
|
|
if (arg[2].type != ARGT_STR)
|
|
|
|
|
return 1;
|
|
|
|
|
|
2018-07-13 04:54:26 -04:00
|
|
|
p = arg[2].data.str.area;
|
|
|
|
|
len = arg[2].data.str.data;
|
2015-01-20 13:47:06 -05:00
|
|
|
while (len) {
|
|
|
|
|
if (*p == 'i') {
|
|
|
|
|
arg[0].type_flags |= ARGF_REG_ICASE;
|
|
|
|
|
}
|
|
|
|
|
else if (*p == 'g') {
|
|
|
|
|
arg[0].type_flags |= ARGF_REG_GLOB;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
memprintf(err, "invalid regex flag '%c', only 'i' and 'g' are supported", *p);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
p++;
|
|
|
|
|
len--;
|
|
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* This sample function is designed to do the equivalent of s/match/replace/ on
|
|
|
|
|
* the input string. It applies a regex and restarts from the last matched
|
|
|
|
|
* location until nothing matches anymore. First arg is the regex to apply to
|
|
|
|
|
* the input string, second arg is the replacement expression.
|
|
|
|
|
*/
|
2015-05-11 09:20:49 -04:00
|
|
|
static int sample_conv_regsub(const struct arg *arg_p, struct sample *smp, void *private)
|
2015-01-20 13:47:06 -05:00
|
|
|
{
|
|
|
|
|
char *start, *end;
|
|
|
|
|
struct my_regex *reg = arg_p[0].data.reg;
|
|
|
|
|
regmatch_t pmatch[MAX_MATCH];
|
2018-07-13 05:56:34 -04:00
|
|
|
struct buffer *trash = get_trash_chunk();
|
2020-02-16 13:20:19 -05:00
|
|
|
struct buffer *output;
|
2015-01-20 13:47:06 -05:00
|
|
|
int flag, max;
|
|
|
|
|
int found;
|
|
|
|
|
|
2018-07-13 04:54:26 -04:00
|
|
|
start = smp->data.u.str.area;
|
|
|
|
|
end = start + smp->data.u.str.data;
|
2015-01-20 13:47:06 -05:00
|
|
|
|
|
|
|
|
flag = 0;
|
|
|
|
|
while (1) {
|
|
|
|
|
/* check for last round which is used to copy remaining parts
|
|
|
|
|
* when not running in global replacement mode.
|
|
|
|
|
*/
|
|
|
|
|
found = 0;
|
|
|
|
|
if ((arg_p[0].type_flags & ARGF_REG_GLOB) || !(flag & REG_NOTBOL)) {
|
|
|
|
|
/* Note: we can have start == end on empty strings or at the end */
|
|
|
|
|
found = regex_exec_match2(reg, start, end - start, MAX_MATCH, pmatch, flag);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!found)
|
|
|
|
|
pmatch[0].rm_so = end - start;
|
|
|
|
|
|
|
|
|
|
/* copy the heading non-matching part (which may also be the tail if nothing matches) */
|
2018-07-13 04:54:26 -04:00
|
|
|
max = trash->size - trash->data;
|
2015-01-20 13:47:06 -05:00
|
|
|
if (max && pmatch[0].rm_so > 0) {
|
|
|
|
|
if (max > pmatch[0].rm_so)
|
|
|
|
|
max = pmatch[0].rm_so;
|
2018-07-13 04:54:26 -04:00
|
|
|
memcpy(trash->area + trash->data, start, max);
|
|
|
|
|
trash->data += max;
|
2015-01-20 13:47:06 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!found)
|
|
|
|
|
break;
|
|
|
|
|
|
2020-02-16 13:20:19 -05:00
|
|
|
output = alloc_trash_chunk();
|
2020-02-18 08:27:44 -05:00
|
|
|
if (!output)
|
|
|
|
|
break;
|
|
|
|
|
|
2020-02-16 13:20:19 -05:00
|
|
|
output->data = exp_replace(output->area, output->size, start, arg_p[1].data.str.area, pmatch);
|
|
|
|
|
|
2015-01-20 13:47:06 -05:00
|
|
|
/* replace the matching part */
|
2020-02-16 13:20:19 -05:00
|
|
|
max = output->size - output->data;
|
2015-01-20 13:47:06 -05:00
|
|
|
if (max) {
|
2020-02-16 13:20:19 -05:00
|
|
|
if (max > output->data)
|
|
|
|
|
max = output->data;
|
2018-07-13 04:54:26 -04:00
|
|
|
memcpy(trash->area + trash->data,
|
2020-02-16 13:20:19 -05:00
|
|
|
output->area, max);
|
2018-07-13 04:54:26 -04:00
|
|
|
trash->data += max;
|
2015-01-20 13:47:06 -05:00
|
|
|
}
|
|
|
|
|
|
2020-02-16 13:20:19 -05:00
|
|
|
free_trash_chunk(output);
|
|
|
|
|
|
2015-01-20 13:47:06 -05:00
|
|
|
/* stop here if we're done with this string */
|
|
|
|
|
if (start >= end)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/* We have a special case for matches of length 0 (eg: "x*y*").
|
|
|
|
|
* These ones are considered to match in front of a character,
|
|
|
|
|
* so we have to copy that character and skip to the next one.
|
|
|
|
|
*/
|
|
|
|
|
if (!pmatch[0].rm_eo) {
|
2018-07-13 04:54:26 -04:00
|
|
|
if (trash->data < trash->size)
|
|
|
|
|
trash->area[trash->data++] = start[pmatch[0].rm_eo];
|
2015-01-20 13:47:06 -05:00
|
|
|
pmatch[0].rm_eo++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
start += pmatch[0].rm_eo;
|
|
|
|
|
flag |= REG_NOTBOL;
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-19 03:07:19 -04:00
|
|
|
smp->data.u.str = *trash;
|
2015-01-20 13:47:06 -05:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-07 15:10:16 -04:00
|
|
|
/* This function check an operator entry. It expects a string.
|
|
|
|
|
* The string can be an integer or a variable name.
|
|
|
|
|
*/
|
|
|
|
|
static int check_operator(struct arg *args, struct sample_conv *conv,
|
|
|
|
|
const char *file, int line, char **err)
|
|
|
|
|
{
|
|
|
|
|
const char *str;
|
|
|
|
|
const char *end;
|
|
|
|
|
|
|
|
|
|
/* Try to decode a variable. */
|
|
|
|
|
if (vars_check_arg(&args[0], NULL))
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
/* Try to convert an integer */
|
2018-07-13 04:54:26 -04:00
|
|
|
str = args[0].data.str.area;
|
2015-07-07 15:10:16 -04:00
|
|
|
end = str + strlen(str);
|
|
|
|
|
args[0].data.sint = read_int64(&str, end);
|
|
|
|
|
if (*str != '\0') {
|
|
|
|
|
memprintf(err, "expects an integer or a variable name");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
args[0].type = ARGT_SINT;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-10 10:33:04 -05:00
|
|
|
/* This function returns a sample struct filled with an arg content.
|
2015-07-07 15:10:16 -04:00
|
|
|
* If the arg contain an integer, the integer is returned in the
|
|
|
|
|
* sample. If the arg contains a variable descriptor, it returns the
|
|
|
|
|
* variable value.
|
|
|
|
|
*
|
|
|
|
|
* This function returns 0 if an error occurs, otherwise it returns 1.
|
|
|
|
|
*/
|
2016-03-10 10:33:04 -05:00
|
|
|
static inline int sample_conv_var2smp(const struct arg *arg, struct sample *smp)
|
2015-07-07 15:10:16 -04:00
|
|
|
{
|
|
|
|
|
switch (arg->type) {
|
|
|
|
|
case ARGT_SINT:
|
2015-08-19 03:00:18 -04:00
|
|
|
smp->data.type = SMP_T_SINT;
|
2015-08-19 03:07:19 -04:00
|
|
|
smp->data.u.sint = arg->data.sint;
|
2015-07-07 15:10:16 -04:00
|
|
|
return 1;
|
|
|
|
|
case ARGT_VAR:
|
2016-03-10 10:33:04 -05:00
|
|
|
if (!vars_get_by_desc(&arg->data.var, smp))
|
2015-07-07 15:10:16 -04:00
|
|
|
return 0;
|
2015-08-19 03:00:18 -04:00
|
|
|
if (!sample_casts[smp->data.type][SMP_T_SINT])
|
2015-07-07 15:10:16 -04:00
|
|
|
return 0;
|
2015-08-19 03:00:18 -04:00
|
|
|
if (!sample_casts[smp->data.type][SMP_T_SINT](smp))
|
2015-07-07 15:10:16 -04:00
|
|
|
return 0;
|
|
|
|
|
return 1;
|
|
|
|
|
default:
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-06 17:43:03 -04:00
|
|
|
/* Takes a SINT on input, applies a binary twos complement and returns the SINT
|
MEDIUM: samples: provide basic arithmetic and bitwise operators
This commit introduces a new category of converters. They are bitwise and
arithmetic operators which support performing basic operations on integers.
Some bitwise operations are supported (and, or, xor, cpl) and some arithmetic
operations are supported (add, sub, mul, div, mod, neg). Some comparators
are provided (odd, even, not, bool) which make it possible to report a match
without having to write an ACL.
The detailed list of new operators as they appear in the doc is :
add(<value>)
Adds <value> to the input value of type unsigned integer, and returns the
result as an unsigned integer.
and(<value>)
Performs a bitwise "AND" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
bool
Returns a boolean TRUE if the input value of type unsigned integer is
non-null, otherwise returns FALSE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
presence of a flag).
cpl
Takes the input value of type unsigned integer, applies a twos-complement
(flips all bits) and returns the result as an unsigned integer.
div(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
result as an unsigned integer. If <value> is null, the largest unsigned
integer is returned (typically 2^32-1).
even
Returns a boolean TRUE if the input value of type unsigned integer is even
otherwise returns FALSE. It is functionally equivalent to "not,and(1),bool".
mod(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
remainder as an unsigned integer. If <value> is null, then zero is returned.
mul(<value>)
Multiplies the input value of type unsigned integer by <value>, and returns
the product as an unsigned integer. In case of overflow, the higher bits are
lost, leading to seemingly strange values.
neg
Takes the input value of type unsigned integer, computes the opposite value,
and returns the remainder as an unsigned integer. 0 is identity. This
operator is provided for reversed subtracts : in order to subtract the input
from a constant, simply perform a "neg,add(value)".
not
Returns a boolean FALSE if the input value of type unsigned integer is
non-null, otherwise returns TRUE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
absence of a flag).
odd
Returns a boolean TRUE if the input value of type unsigned integer is odd
otherwise returns FALSE. It is functionally equivalent to "and(1),bool".
or(<value>)
Performs a bitwise "OR" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
sub(<value>)
Subtracts <value> from the input value of type unsigned integer, and returns
the result as an unsigned integer. Note: in order to subtract the input from
a constant, simply perform a "neg,add(value)".
xor(<value>)
Performs a bitwise "XOR" (exclusive OR) between <value> and the input value
of type unsigned integer, and returns the result as an unsigned integer.
2015-01-27 09:12:13 -05:00
|
|
|
* result.
|
|
|
|
|
*/
|
2015-05-11 09:20:49 -04:00
|
|
|
static int sample_conv_binary_cpl(const struct arg *arg_p, struct sample *smp, void *private)
|
MEDIUM: samples: provide basic arithmetic and bitwise operators
This commit introduces a new category of converters. They are bitwise and
arithmetic operators which support performing basic operations on integers.
Some bitwise operations are supported (and, or, xor, cpl) and some arithmetic
operations are supported (add, sub, mul, div, mod, neg). Some comparators
are provided (odd, even, not, bool) which make it possible to report a match
without having to write an ACL.
The detailed list of new operators as they appear in the doc is :
add(<value>)
Adds <value> to the input value of type unsigned integer, and returns the
result as an unsigned integer.
and(<value>)
Performs a bitwise "AND" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
bool
Returns a boolean TRUE if the input value of type unsigned integer is
non-null, otherwise returns FALSE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
presence of a flag).
cpl
Takes the input value of type unsigned integer, applies a twos-complement
(flips all bits) and returns the result as an unsigned integer.
div(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
result as an unsigned integer. If <value> is null, the largest unsigned
integer is returned (typically 2^32-1).
even
Returns a boolean TRUE if the input value of type unsigned integer is even
otherwise returns FALSE. It is functionally equivalent to "not,and(1),bool".
mod(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
remainder as an unsigned integer. If <value> is null, then zero is returned.
mul(<value>)
Multiplies the input value of type unsigned integer by <value>, and returns
the product as an unsigned integer. In case of overflow, the higher bits are
lost, leading to seemingly strange values.
neg
Takes the input value of type unsigned integer, computes the opposite value,
and returns the remainder as an unsigned integer. 0 is identity. This
operator is provided for reversed subtracts : in order to subtract the input
from a constant, simply perform a "neg,add(value)".
not
Returns a boolean FALSE if the input value of type unsigned integer is
non-null, otherwise returns TRUE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
absence of a flag).
odd
Returns a boolean TRUE if the input value of type unsigned integer is odd
otherwise returns FALSE. It is functionally equivalent to "and(1),bool".
or(<value>)
Performs a bitwise "OR" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
sub(<value>)
Subtracts <value> from the input value of type unsigned integer, and returns
the result as an unsigned integer. Note: in order to subtract the input from
a constant, simply perform a "neg,add(value)".
xor(<value>)
Performs a bitwise "XOR" (exclusive OR) between <value> and the input value
of type unsigned integer, and returns the result as an unsigned integer.
2015-01-27 09:12:13 -05:00
|
|
|
{
|
2015-08-19 03:07:19 -04:00
|
|
|
smp->data.u.sint = ~smp->data.u.sint;
|
MEDIUM: samples: provide basic arithmetic and bitwise operators
This commit introduces a new category of converters. They are bitwise and
arithmetic operators which support performing basic operations on integers.
Some bitwise operations are supported (and, or, xor, cpl) and some arithmetic
operations are supported (add, sub, mul, div, mod, neg). Some comparators
are provided (odd, even, not, bool) which make it possible to report a match
without having to write an ACL.
The detailed list of new operators as they appear in the doc is :
add(<value>)
Adds <value> to the input value of type unsigned integer, and returns the
result as an unsigned integer.
and(<value>)
Performs a bitwise "AND" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
bool
Returns a boolean TRUE if the input value of type unsigned integer is
non-null, otherwise returns FALSE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
presence of a flag).
cpl
Takes the input value of type unsigned integer, applies a twos-complement
(flips all bits) and returns the result as an unsigned integer.
div(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
result as an unsigned integer. If <value> is null, the largest unsigned
integer is returned (typically 2^32-1).
even
Returns a boolean TRUE if the input value of type unsigned integer is even
otherwise returns FALSE. It is functionally equivalent to "not,and(1),bool".
mod(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
remainder as an unsigned integer. If <value> is null, then zero is returned.
mul(<value>)
Multiplies the input value of type unsigned integer by <value>, and returns
the product as an unsigned integer. In case of overflow, the higher bits are
lost, leading to seemingly strange values.
neg
Takes the input value of type unsigned integer, computes the opposite value,
and returns the remainder as an unsigned integer. 0 is identity. This
operator is provided for reversed subtracts : in order to subtract the input
from a constant, simply perform a "neg,add(value)".
not
Returns a boolean FALSE if the input value of type unsigned integer is
non-null, otherwise returns TRUE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
absence of a flag).
odd
Returns a boolean TRUE if the input value of type unsigned integer is odd
otherwise returns FALSE. It is functionally equivalent to "and(1),bool".
or(<value>)
Performs a bitwise "OR" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
sub(<value>)
Subtracts <value> from the input value of type unsigned integer, and returns
the result as an unsigned integer. Note: in order to subtract the input from
a constant, simply perform a "neg,add(value)".
xor(<value>)
Performs a bitwise "XOR" (exclusive OR) between <value> and the input value
of type unsigned integer, and returns the result as an unsigned integer.
2015-01-27 09:12:13 -05:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-07 15:10:16 -04:00
|
|
|
/* Takes a SINT on input, applies a binary "and" with the SINT directly in
|
2018-11-15 15:14:56 -05:00
|
|
|
* arg_p or in the variable described in arg_p, and returns the SINT result.
|
MEDIUM: samples: provide basic arithmetic and bitwise operators
This commit introduces a new category of converters. They are bitwise and
arithmetic operators which support performing basic operations on integers.
Some bitwise operations are supported (and, or, xor, cpl) and some arithmetic
operations are supported (add, sub, mul, div, mod, neg). Some comparators
are provided (odd, even, not, bool) which make it possible to report a match
without having to write an ACL.
The detailed list of new operators as they appear in the doc is :
add(<value>)
Adds <value> to the input value of type unsigned integer, and returns the
result as an unsigned integer.
and(<value>)
Performs a bitwise "AND" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
bool
Returns a boolean TRUE if the input value of type unsigned integer is
non-null, otherwise returns FALSE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
presence of a flag).
cpl
Takes the input value of type unsigned integer, applies a twos-complement
(flips all bits) and returns the result as an unsigned integer.
div(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
result as an unsigned integer. If <value> is null, the largest unsigned
integer is returned (typically 2^32-1).
even
Returns a boolean TRUE if the input value of type unsigned integer is even
otherwise returns FALSE. It is functionally equivalent to "not,and(1),bool".
mod(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
remainder as an unsigned integer. If <value> is null, then zero is returned.
mul(<value>)
Multiplies the input value of type unsigned integer by <value>, and returns
the product as an unsigned integer. In case of overflow, the higher bits are
lost, leading to seemingly strange values.
neg
Takes the input value of type unsigned integer, computes the opposite value,
and returns the remainder as an unsigned integer. 0 is identity. This
operator is provided for reversed subtracts : in order to subtract the input
from a constant, simply perform a "neg,add(value)".
not
Returns a boolean FALSE if the input value of type unsigned integer is
non-null, otherwise returns TRUE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
absence of a flag).
odd
Returns a boolean TRUE if the input value of type unsigned integer is odd
otherwise returns FALSE. It is functionally equivalent to "and(1),bool".
or(<value>)
Performs a bitwise "OR" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
sub(<value>)
Subtracts <value> from the input value of type unsigned integer, and returns
the result as an unsigned integer. Note: in order to subtract the input from
a constant, simply perform a "neg,add(value)".
xor(<value>)
Performs a bitwise "XOR" (exclusive OR) between <value> and the input value
of type unsigned integer, and returns the result as an unsigned integer.
2015-01-27 09:12:13 -05:00
|
|
|
*/
|
2015-05-11 09:20:49 -04:00
|
|
|
static int sample_conv_binary_and(const struct arg *arg_p, struct sample *smp, void *private)
|
MEDIUM: samples: provide basic arithmetic and bitwise operators
This commit introduces a new category of converters. They are bitwise and
arithmetic operators which support performing basic operations on integers.
Some bitwise operations are supported (and, or, xor, cpl) and some arithmetic
operations are supported (add, sub, mul, div, mod, neg). Some comparators
are provided (odd, even, not, bool) which make it possible to report a match
without having to write an ACL.
The detailed list of new operators as they appear in the doc is :
add(<value>)
Adds <value> to the input value of type unsigned integer, and returns the
result as an unsigned integer.
and(<value>)
Performs a bitwise "AND" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
bool
Returns a boolean TRUE if the input value of type unsigned integer is
non-null, otherwise returns FALSE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
presence of a flag).
cpl
Takes the input value of type unsigned integer, applies a twos-complement
(flips all bits) and returns the result as an unsigned integer.
div(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
result as an unsigned integer. If <value> is null, the largest unsigned
integer is returned (typically 2^32-1).
even
Returns a boolean TRUE if the input value of type unsigned integer is even
otherwise returns FALSE. It is functionally equivalent to "not,and(1),bool".
mod(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
remainder as an unsigned integer. If <value> is null, then zero is returned.
mul(<value>)
Multiplies the input value of type unsigned integer by <value>, and returns
the product as an unsigned integer. In case of overflow, the higher bits are
lost, leading to seemingly strange values.
neg
Takes the input value of type unsigned integer, computes the opposite value,
and returns the remainder as an unsigned integer. 0 is identity. This
operator is provided for reversed subtracts : in order to subtract the input
from a constant, simply perform a "neg,add(value)".
not
Returns a boolean FALSE if the input value of type unsigned integer is
non-null, otherwise returns TRUE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
absence of a flag).
odd
Returns a boolean TRUE if the input value of type unsigned integer is odd
otherwise returns FALSE. It is functionally equivalent to "and(1),bool".
or(<value>)
Performs a bitwise "OR" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
sub(<value>)
Subtracts <value> from the input value of type unsigned integer, and returns
the result as an unsigned integer. Note: in order to subtract the input from
a constant, simply perform a "neg,add(value)".
xor(<value>)
Performs a bitwise "XOR" (exclusive OR) between <value> and the input value
of type unsigned integer, and returns the result as an unsigned integer.
2015-01-27 09:12:13 -05:00
|
|
|
{
|
2015-07-07 15:10:16 -04:00
|
|
|
struct sample tmp;
|
|
|
|
|
|
2016-03-10 10:28:58 -05:00
|
|
|
smp_set_owner(&tmp, smp->px, smp->sess, smp->strm, smp->opt);
|
2016-03-10 10:33:04 -05:00
|
|
|
if (!sample_conv_var2smp(arg_p, &tmp))
|
2015-07-07 15:10:16 -04:00
|
|
|
return 0;
|
2015-08-19 03:07:19 -04:00
|
|
|
smp->data.u.sint &= tmp.data.u.sint;
|
MEDIUM: samples: provide basic arithmetic and bitwise operators
This commit introduces a new category of converters. They are bitwise and
arithmetic operators which support performing basic operations on integers.
Some bitwise operations are supported (and, or, xor, cpl) and some arithmetic
operations are supported (add, sub, mul, div, mod, neg). Some comparators
are provided (odd, even, not, bool) which make it possible to report a match
without having to write an ACL.
The detailed list of new operators as they appear in the doc is :
add(<value>)
Adds <value> to the input value of type unsigned integer, and returns the
result as an unsigned integer.
and(<value>)
Performs a bitwise "AND" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
bool
Returns a boolean TRUE if the input value of type unsigned integer is
non-null, otherwise returns FALSE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
presence of a flag).
cpl
Takes the input value of type unsigned integer, applies a twos-complement
(flips all bits) and returns the result as an unsigned integer.
div(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
result as an unsigned integer. If <value> is null, the largest unsigned
integer is returned (typically 2^32-1).
even
Returns a boolean TRUE if the input value of type unsigned integer is even
otherwise returns FALSE. It is functionally equivalent to "not,and(1),bool".
mod(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
remainder as an unsigned integer. If <value> is null, then zero is returned.
mul(<value>)
Multiplies the input value of type unsigned integer by <value>, and returns
the product as an unsigned integer. In case of overflow, the higher bits are
lost, leading to seemingly strange values.
neg
Takes the input value of type unsigned integer, computes the opposite value,
and returns the remainder as an unsigned integer. 0 is identity. This
operator is provided for reversed subtracts : in order to subtract the input
from a constant, simply perform a "neg,add(value)".
not
Returns a boolean FALSE if the input value of type unsigned integer is
non-null, otherwise returns TRUE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
absence of a flag).
odd
Returns a boolean TRUE if the input value of type unsigned integer is odd
otherwise returns FALSE. It is functionally equivalent to "and(1),bool".
or(<value>)
Performs a bitwise "OR" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
sub(<value>)
Subtracts <value> from the input value of type unsigned integer, and returns
the result as an unsigned integer. Note: in order to subtract the input from
a constant, simply perform a "neg,add(value)".
xor(<value>)
Performs a bitwise "XOR" (exclusive OR) between <value> and the input value
of type unsigned integer, and returns the result as an unsigned integer.
2015-01-27 09:12:13 -05:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-07 15:10:16 -04:00
|
|
|
/* Takes a SINT on input, applies a binary "or" with the SINT directly in
|
2018-11-15 15:14:56 -05:00
|
|
|
* arg_p or in the variable described in arg_p, and returns the SINT result.
|
MEDIUM: samples: provide basic arithmetic and bitwise operators
This commit introduces a new category of converters. They are bitwise and
arithmetic operators which support performing basic operations on integers.
Some bitwise operations are supported (and, or, xor, cpl) and some arithmetic
operations are supported (add, sub, mul, div, mod, neg). Some comparators
are provided (odd, even, not, bool) which make it possible to report a match
without having to write an ACL.
The detailed list of new operators as they appear in the doc is :
add(<value>)
Adds <value> to the input value of type unsigned integer, and returns the
result as an unsigned integer.
and(<value>)
Performs a bitwise "AND" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
bool
Returns a boolean TRUE if the input value of type unsigned integer is
non-null, otherwise returns FALSE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
presence of a flag).
cpl
Takes the input value of type unsigned integer, applies a twos-complement
(flips all bits) and returns the result as an unsigned integer.
div(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
result as an unsigned integer. If <value> is null, the largest unsigned
integer is returned (typically 2^32-1).
even
Returns a boolean TRUE if the input value of type unsigned integer is even
otherwise returns FALSE. It is functionally equivalent to "not,and(1),bool".
mod(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
remainder as an unsigned integer. If <value> is null, then zero is returned.
mul(<value>)
Multiplies the input value of type unsigned integer by <value>, and returns
the product as an unsigned integer. In case of overflow, the higher bits are
lost, leading to seemingly strange values.
neg
Takes the input value of type unsigned integer, computes the opposite value,
and returns the remainder as an unsigned integer. 0 is identity. This
operator is provided for reversed subtracts : in order to subtract the input
from a constant, simply perform a "neg,add(value)".
not
Returns a boolean FALSE if the input value of type unsigned integer is
non-null, otherwise returns TRUE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
absence of a flag).
odd
Returns a boolean TRUE if the input value of type unsigned integer is odd
otherwise returns FALSE. It is functionally equivalent to "and(1),bool".
or(<value>)
Performs a bitwise "OR" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
sub(<value>)
Subtracts <value> from the input value of type unsigned integer, and returns
the result as an unsigned integer. Note: in order to subtract the input from
a constant, simply perform a "neg,add(value)".
xor(<value>)
Performs a bitwise "XOR" (exclusive OR) between <value> and the input value
of type unsigned integer, and returns the result as an unsigned integer.
2015-01-27 09:12:13 -05:00
|
|
|
*/
|
2015-05-11 09:20:49 -04:00
|
|
|
static int sample_conv_binary_or(const struct arg *arg_p, struct sample *smp, void *private)
|
MEDIUM: samples: provide basic arithmetic and bitwise operators
This commit introduces a new category of converters. They are bitwise and
arithmetic operators which support performing basic operations on integers.
Some bitwise operations are supported (and, or, xor, cpl) and some arithmetic
operations are supported (add, sub, mul, div, mod, neg). Some comparators
are provided (odd, even, not, bool) which make it possible to report a match
without having to write an ACL.
The detailed list of new operators as they appear in the doc is :
add(<value>)
Adds <value> to the input value of type unsigned integer, and returns the
result as an unsigned integer.
and(<value>)
Performs a bitwise "AND" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
bool
Returns a boolean TRUE if the input value of type unsigned integer is
non-null, otherwise returns FALSE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
presence of a flag).
cpl
Takes the input value of type unsigned integer, applies a twos-complement
(flips all bits) and returns the result as an unsigned integer.
div(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
result as an unsigned integer. If <value> is null, the largest unsigned
integer is returned (typically 2^32-1).
even
Returns a boolean TRUE if the input value of type unsigned integer is even
otherwise returns FALSE. It is functionally equivalent to "not,and(1),bool".
mod(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
remainder as an unsigned integer. If <value> is null, then zero is returned.
mul(<value>)
Multiplies the input value of type unsigned integer by <value>, and returns
the product as an unsigned integer. In case of overflow, the higher bits are
lost, leading to seemingly strange values.
neg
Takes the input value of type unsigned integer, computes the opposite value,
and returns the remainder as an unsigned integer. 0 is identity. This
operator is provided for reversed subtracts : in order to subtract the input
from a constant, simply perform a "neg,add(value)".
not
Returns a boolean FALSE if the input value of type unsigned integer is
non-null, otherwise returns TRUE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
absence of a flag).
odd
Returns a boolean TRUE if the input value of type unsigned integer is odd
otherwise returns FALSE. It is functionally equivalent to "and(1),bool".
or(<value>)
Performs a bitwise "OR" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
sub(<value>)
Subtracts <value> from the input value of type unsigned integer, and returns
the result as an unsigned integer. Note: in order to subtract the input from
a constant, simply perform a "neg,add(value)".
xor(<value>)
Performs a bitwise "XOR" (exclusive OR) between <value> and the input value
of type unsigned integer, and returns the result as an unsigned integer.
2015-01-27 09:12:13 -05:00
|
|
|
{
|
2015-07-07 15:10:16 -04:00
|
|
|
struct sample tmp;
|
|
|
|
|
|
2016-03-10 10:28:58 -05:00
|
|
|
smp_set_owner(&tmp, smp->px, smp->sess, smp->strm, smp->opt);
|
2016-03-10 10:33:04 -05:00
|
|
|
if (!sample_conv_var2smp(arg_p, &tmp))
|
2015-07-07 15:10:16 -04:00
|
|
|
return 0;
|
2015-08-19 03:07:19 -04:00
|
|
|
smp->data.u.sint |= tmp.data.u.sint;
|
MEDIUM: samples: provide basic arithmetic and bitwise operators
This commit introduces a new category of converters. They are bitwise and
arithmetic operators which support performing basic operations on integers.
Some bitwise operations are supported (and, or, xor, cpl) and some arithmetic
operations are supported (add, sub, mul, div, mod, neg). Some comparators
are provided (odd, even, not, bool) which make it possible to report a match
without having to write an ACL.
The detailed list of new operators as they appear in the doc is :
add(<value>)
Adds <value> to the input value of type unsigned integer, and returns the
result as an unsigned integer.
and(<value>)
Performs a bitwise "AND" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
bool
Returns a boolean TRUE if the input value of type unsigned integer is
non-null, otherwise returns FALSE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
presence of a flag).
cpl
Takes the input value of type unsigned integer, applies a twos-complement
(flips all bits) and returns the result as an unsigned integer.
div(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
result as an unsigned integer. If <value> is null, the largest unsigned
integer is returned (typically 2^32-1).
even
Returns a boolean TRUE if the input value of type unsigned integer is even
otherwise returns FALSE. It is functionally equivalent to "not,and(1),bool".
mod(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
remainder as an unsigned integer. If <value> is null, then zero is returned.
mul(<value>)
Multiplies the input value of type unsigned integer by <value>, and returns
the product as an unsigned integer. In case of overflow, the higher bits are
lost, leading to seemingly strange values.
neg
Takes the input value of type unsigned integer, computes the opposite value,
and returns the remainder as an unsigned integer. 0 is identity. This
operator is provided for reversed subtracts : in order to subtract the input
from a constant, simply perform a "neg,add(value)".
not
Returns a boolean FALSE if the input value of type unsigned integer is
non-null, otherwise returns TRUE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
absence of a flag).
odd
Returns a boolean TRUE if the input value of type unsigned integer is odd
otherwise returns FALSE. It is functionally equivalent to "and(1),bool".
or(<value>)
Performs a bitwise "OR" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
sub(<value>)
Subtracts <value> from the input value of type unsigned integer, and returns
the result as an unsigned integer. Note: in order to subtract the input from
a constant, simply perform a "neg,add(value)".
xor(<value>)
Performs a bitwise "XOR" (exclusive OR) between <value> and the input value
of type unsigned integer, and returns the result as an unsigned integer.
2015-01-27 09:12:13 -05:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-07 15:10:16 -04:00
|
|
|
/* Takes a SINT on input, applies a binary "xor" with the SINT directly in
|
2018-11-15 15:14:56 -05:00
|
|
|
* arg_p or in the variable described in arg_p, and returns the SINT result.
|
MEDIUM: samples: provide basic arithmetic and bitwise operators
This commit introduces a new category of converters. They are bitwise and
arithmetic operators which support performing basic operations on integers.
Some bitwise operations are supported (and, or, xor, cpl) and some arithmetic
operations are supported (add, sub, mul, div, mod, neg). Some comparators
are provided (odd, even, not, bool) which make it possible to report a match
without having to write an ACL.
The detailed list of new operators as they appear in the doc is :
add(<value>)
Adds <value> to the input value of type unsigned integer, and returns the
result as an unsigned integer.
and(<value>)
Performs a bitwise "AND" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
bool
Returns a boolean TRUE if the input value of type unsigned integer is
non-null, otherwise returns FALSE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
presence of a flag).
cpl
Takes the input value of type unsigned integer, applies a twos-complement
(flips all bits) and returns the result as an unsigned integer.
div(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
result as an unsigned integer. If <value> is null, the largest unsigned
integer is returned (typically 2^32-1).
even
Returns a boolean TRUE if the input value of type unsigned integer is even
otherwise returns FALSE. It is functionally equivalent to "not,and(1),bool".
mod(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
remainder as an unsigned integer. If <value> is null, then zero is returned.
mul(<value>)
Multiplies the input value of type unsigned integer by <value>, and returns
the product as an unsigned integer. In case of overflow, the higher bits are
lost, leading to seemingly strange values.
neg
Takes the input value of type unsigned integer, computes the opposite value,
and returns the remainder as an unsigned integer. 0 is identity. This
operator is provided for reversed subtracts : in order to subtract the input
from a constant, simply perform a "neg,add(value)".
not
Returns a boolean FALSE if the input value of type unsigned integer is
non-null, otherwise returns TRUE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
absence of a flag).
odd
Returns a boolean TRUE if the input value of type unsigned integer is odd
otherwise returns FALSE. It is functionally equivalent to "and(1),bool".
or(<value>)
Performs a bitwise "OR" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
sub(<value>)
Subtracts <value> from the input value of type unsigned integer, and returns
the result as an unsigned integer. Note: in order to subtract the input from
a constant, simply perform a "neg,add(value)".
xor(<value>)
Performs a bitwise "XOR" (exclusive OR) between <value> and the input value
of type unsigned integer, and returns the result as an unsigned integer.
2015-01-27 09:12:13 -05:00
|
|
|
*/
|
2015-05-11 09:20:49 -04:00
|
|
|
static int sample_conv_binary_xor(const struct arg *arg_p, struct sample *smp, void *private)
|
MEDIUM: samples: provide basic arithmetic and bitwise operators
This commit introduces a new category of converters. They are bitwise and
arithmetic operators which support performing basic operations on integers.
Some bitwise operations are supported (and, or, xor, cpl) and some arithmetic
operations are supported (add, sub, mul, div, mod, neg). Some comparators
are provided (odd, even, not, bool) which make it possible to report a match
without having to write an ACL.
The detailed list of new operators as they appear in the doc is :
add(<value>)
Adds <value> to the input value of type unsigned integer, and returns the
result as an unsigned integer.
and(<value>)
Performs a bitwise "AND" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
bool
Returns a boolean TRUE if the input value of type unsigned integer is
non-null, otherwise returns FALSE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
presence of a flag).
cpl
Takes the input value of type unsigned integer, applies a twos-complement
(flips all bits) and returns the result as an unsigned integer.
div(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
result as an unsigned integer. If <value> is null, the largest unsigned
integer is returned (typically 2^32-1).
even
Returns a boolean TRUE if the input value of type unsigned integer is even
otherwise returns FALSE. It is functionally equivalent to "not,and(1),bool".
mod(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
remainder as an unsigned integer. If <value> is null, then zero is returned.
mul(<value>)
Multiplies the input value of type unsigned integer by <value>, and returns
the product as an unsigned integer. In case of overflow, the higher bits are
lost, leading to seemingly strange values.
neg
Takes the input value of type unsigned integer, computes the opposite value,
and returns the remainder as an unsigned integer. 0 is identity. This
operator is provided for reversed subtracts : in order to subtract the input
from a constant, simply perform a "neg,add(value)".
not
Returns a boolean FALSE if the input value of type unsigned integer is
non-null, otherwise returns TRUE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
absence of a flag).
odd
Returns a boolean TRUE if the input value of type unsigned integer is odd
otherwise returns FALSE. It is functionally equivalent to "and(1),bool".
or(<value>)
Performs a bitwise "OR" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
sub(<value>)
Subtracts <value> from the input value of type unsigned integer, and returns
the result as an unsigned integer. Note: in order to subtract the input from
a constant, simply perform a "neg,add(value)".
xor(<value>)
Performs a bitwise "XOR" (exclusive OR) between <value> and the input value
of type unsigned integer, and returns the result as an unsigned integer.
2015-01-27 09:12:13 -05:00
|
|
|
{
|
2015-07-07 15:10:16 -04:00
|
|
|
struct sample tmp;
|
|
|
|
|
|
2016-03-10 10:28:58 -05:00
|
|
|
smp_set_owner(&tmp, smp->px, smp->sess, smp->strm, smp->opt);
|
2016-03-10 10:33:04 -05:00
|
|
|
if (!sample_conv_var2smp(arg_p, &tmp))
|
2015-07-07 15:10:16 -04:00
|
|
|
return 0;
|
2015-08-19 03:07:19 -04:00
|
|
|
smp->data.u.sint ^= tmp.data.u.sint;
|
MEDIUM: samples: provide basic arithmetic and bitwise operators
This commit introduces a new category of converters. They are bitwise and
arithmetic operators which support performing basic operations on integers.
Some bitwise operations are supported (and, or, xor, cpl) and some arithmetic
operations are supported (add, sub, mul, div, mod, neg). Some comparators
are provided (odd, even, not, bool) which make it possible to report a match
without having to write an ACL.
The detailed list of new operators as they appear in the doc is :
add(<value>)
Adds <value> to the input value of type unsigned integer, and returns the
result as an unsigned integer.
and(<value>)
Performs a bitwise "AND" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
bool
Returns a boolean TRUE if the input value of type unsigned integer is
non-null, otherwise returns FALSE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
presence of a flag).
cpl
Takes the input value of type unsigned integer, applies a twos-complement
(flips all bits) and returns the result as an unsigned integer.
div(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
result as an unsigned integer. If <value> is null, the largest unsigned
integer is returned (typically 2^32-1).
even
Returns a boolean TRUE if the input value of type unsigned integer is even
otherwise returns FALSE. It is functionally equivalent to "not,and(1),bool".
mod(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
remainder as an unsigned integer. If <value> is null, then zero is returned.
mul(<value>)
Multiplies the input value of type unsigned integer by <value>, and returns
the product as an unsigned integer. In case of overflow, the higher bits are
lost, leading to seemingly strange values.
neg
Takes the input value of type unsigned integer, computes the opposite value,
and returns the remainder as an unsigned integer. 0 is identity. This
operator is provided for reversed subtracts : in order to subtract the input
from a constant, simply perform a "neg,add(value)".
not
Returns a boolean FALSE if the input value of type unsigned integer is
non-null, otherwise returns TRUE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
absence of a flag).
odd
Returns a boolean TRUE if the input value of type unsigned integer is odd
otherwise returns FALSE. It is functionally equivalent to "and(1),bool".
or(<value>)
Performs a bitwise "OR" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
sub(<value>)
Subtracts <value> from the input value of type unsigned integer, and returns
the result as an unsigned integer. Note: in order to subtract the input from
a constant, simply perform a "neg,add(value)".
xor(<value>)
Performs a bitwise "XOR" (exclusive OR) between <value> and the input value
of type unsigned integer, and returns the result as an unsigned integer.
2015-01-27 09:12:13 -05:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-07 19:10:21 -04:00
|
|
|
static inline long long int arith_add(long long int a, long long int b)
|
|
|
|
|
{
|
|
|
|
|
/* Prevent overflow and makes capped calculus.
|
|
|
|
|
* We must ensure that the check calculus doesn't
|
|
|
|
|
* exceed the signed 64 bits limits.
|
|
|
|
|
*
|
|
|
|
|
* +----------+----------+
|
|
|
|
|
* | a<0 | a>=0 |
|
|
|
|
|
* +------+----------+----------+
|
|
|
|
|
* | b<0 | MIN-a>b | no check |
|
|
|
|
|
* +------+----------+----------+
|
|
|
|
|
* | b>=0 | no check | MAX-a<b |
|
|
|
|
|
* +------+----------+----------+
|
|
|
|
|
*/
|
|
|
|
|
if ((a ^ b) >= 0) {
|
|
|
|
|
/* signs are differents. */
|
|
|
|
|
if (a < 0) {
|
|
|
|
|
if (LLONG_MIN - a > b)
|
|
|
|
|
return LLONG_MIN;
|
|
|
|
|
}
|
|
|
|
|
if (LLONG_MAX - a < b)
|
|
|
|
|
return LLONG_MAX;
|
|
|
|
|
}
|
|
|
|
|
return a + b;
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-07 15:10:16 -04:00
|
|
|
/* Takes a SINT on input, applies an arithmetic "add" with the SINT directly in
|
2018-11-15 15:14:56 -05:00
|
|
|
* arg_p or in the variable described in arg_p, and returns the SINT result.
|
MEDIUM: samples: provide basic arithmetic and bitwise operators
This commit introduces a new category of converters. They are bitwise and
arithmetic operators which support performing basic operations on integers.
Some bitwise operations are supported (and, or, xor, cpl) and some arithmetic
operations are supported (add, sub, mul, div, mod, neg). Some comparators
are provided (odd, even, not, bool) which make it possible to report a match
without having to write an ACL.
The detailed list of new operators as they appear in the doc is :
add(<value>)
Adds <value> to the input value of type unsigned integer, and returns the
result as an unsigned integer.
and(<value>)
Performs a bitwise "AND" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
bool
Returns a boolean TRUE if the input value of type unsigned integer is
non-null, otherwise returns FALSE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
presence of a flag).
cpl
Takes the input value of type unsigned integer, applies a twos-complement
(flips all bits) and returns the result as an unsigned integer.
div(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
result as an unsigned integer. If <value> is null, the largest unsigned
integer is returned (typically 2^32-1).
even
Returns a boolean TRUE if the input value of type unsigned integer is even
otherwise returns FALSE. It is functionally equivalent to "not,and(1),bool".
mod(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
remainder as an unsigned integer. If <value> is null, then zero is returned.
mul(<value>)
Multiplies the input value of type unsigned integer by <value>, and returns
the product as an unsigned integer. In case of overflow, the higher bits are
lost, leading to seemingly strange values.
neg
Takes the input value of type unsigned integer, computes the opposite value,
and returns the remainder as an unsigned integer. 0 is identity. This
operator is provided for reversed subtracts : in order to subtract the input
from a constant, simply perform a "neg,add(value)".
not
Returns a boolean FALSE if the input value of type unsigned integer is
non-null, otherwise returns TRUE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
absence of a flag).
odd
Returns a boolean TRUE if the input value of type unsigned integer is odd
otherwise returns FALSE. It is functionally equivalent to "and(1),bool".
or(<value>)
Performs a bitwise "OR" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
sub(<value>)
Subtracts <value> from the input value of type unsigned integer, and returns
the result as an unsigned integer. Note: in order to subtract the input from
a constant, simply perform a "neg,add(value)".
xor(<value>)
Performs a bitwise "XOR" (exclusive OR) between <value> and the input value
of type unsigned integer, and returns the result as an unsigned integer.
2015-01-27 09:12:13 -05:00
|
|
|
*/
|
2015-05-11 09:20:49 -04:00
|
|
|
static int sample_conv_arith_add(const struct arg *arg_p, struct sample *smp, void *private)
|
MEDIUM: samples: provide basic arithmetic and bitwise operators
This commit introduces a new category of converters. They are bitwise and
arithmetic operators which support performing basic operations on integers.
Some bitwise operations are supported (and, or, xor, cpl) and some arithmetic
operations are supported (add, sub, mul, div, mod, neg). Some comparators
are provided (odd, even, not, bool) which make it possible to report a match
without having to write an ACL.
The detailed list of new operators as they appear in the doc is :
add(<value>)
Adds <value> to the input value of type unsigned integer, and returns the
result as an unsigned integer.
and(<value>)
Performs a bitwise "AND" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
bool
Returns a boolean TRUE if the input value of type unsigned integer is
non-null, otherwise returns FALSE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
presence of a flag).
cpl
Takes the input value of type unsigned integer, applies a twos-complement
(flips all bits) and returns the result as an unsigned integer.
div(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
result as an unsigned integer. If <value> is null, the largest unsigned
integer is returned (typically 2^32-1).
even
Returns a boolean TRUE if the input value of type unsigned integer is even
otherwise returns FALSE. It is functionally equivalent to "not,and(1),bool".
mod(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
remainder as an unsigned integer. If <value> is null, then zero is returned.
mul(<value>)
Multiplies the input value of type unsigned integer by <value>, and returns
the product as an unsigned integer. In case of overflow, the higher bits are
lost, leading to seemingly strange values.
neg
Takes the input value of type unsigned integer, computes the opposite value,
and returns the remainder as an unsigned integer. 0 is identity. This
operator is provided for reversed subtracts : in order to subtract the input
from a constant, simply perform a "neg,add(value)".
not
Returns a boolean FALSE if the input value of type unsigned integer is
non-null, otherwise returns TRUE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
absence of a flag).
odd
Returns a boolean TRUE if the input value of type unsigned integer is odd
otherwise returns FALSE. It is functionally equivalent to "and(1),bool".
or(<value>)
Performs a bitwise "OR" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
sub(<value>)
Subtracts <value> from the input value of type unsigned integer, and returns
the result as an unsigned integer. Note: in order to subtract the input from
a constant, simply perform a "neg,add(value)".
xor(<value>)
Performs a bitwise "XOR" (exclusive OR) between <value> and the input value
of type unsigned integer, and returns the result as an unsigned integer.
2015-01-27 09:12:13 -05:00
|
|
|
{
|
2015-07-07 15:10:16 -04:00
|
|
|
struct sample tmp;
|
|
|
|
|
|
2016-03-10 10:28:58 -05:00
|
|
|
smp_set_owner(&tmp, smp->px, smp->sess, smp->strm, smp->opt);
|
2016-03-10 10:33:04 -05:00
|
|
|
if (!sample_conv_var2smp(arg_p, &tmp))
|
2015-07-07 15:10:16 -04:00
|
|
|
return 0;
|
2015-08-19 03:07:19 -04:00
|
|
|
smp->data.u.sint = arith_add(smp->data.u.sint, tmp.data.u.sint);
|
MEDIUM: samples: provide basic arithmetic and bitwise operators
This commit introduces a new category of converters. They are bitwise and
arithmetic operators which support performing basic operations on integers.
Some bitwise operations are supported (and, or, xor, cpl) and some arithmetic
operations are supported (add, sub, mul, div, mod, neg). Some comparators
are provided (odd, even, not, bool) which make it possible to report a match
without having to write an ACL.
The detailed list of new operators as they appear in the doc is :
add(<value>)
Adds <value> to the input value of type unsigned integer, and returns the
result as an unsigned integer.
and(<value>)
Performs a bitwise "AND" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
bool
Returns a boolean TRUE if the input value of type unsigned integer is
non-null, otherwise returns FALSE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
presence of a flag).
cpl
Takes the input value of type unsigned integer, applies a twos-complement
(flips all bits) and returns the result as an unsigned integer.
div(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
result as an unsigned integer. If <value> is null, the largest unsigned
integer is returned (typically 2^32-1).
even
Returns a boolean TRUE if the input value of type unsigned integer is even
otherwise returns FALSE. It is functionally equivalent to "not,and(1),bool".
mod(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
remainder as an unsigned integer. If <value> is null, then zero is returned.
mul(<value>)
Multiplies the input value of type unsigned integer by <value>, and returns
the product as an unsigned integer. In case of overflow, the higher bits are
lost, leading to seemingly strange values.
neg
Takes the input value of type unsigned integer, computes the opposite value,
and returns the remainder as an unsigned integer. 0 is identity. This
operator is provided for reversed subtracts : in order to subtract the input
from a constant, simply perform a "neg,add(value)".
not
Returns a boolean FALSE if the input value of type unsigned integer is
non-null, otherwise returns TRUE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
absence of a flag).
odd
Returns a boolean TRUE if the input value of type unsigned integer is odd
otherwise returns FALSE. It is functionally equivalent to "and(1),bool".
or(<value>)
Performs a bitwise "OR" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
sub(<value>)
Subtracts <value> from the input value of type unsigned integer, and returns
the result as an unsigned integer. Note: in order to subtract the input from
a constant, simply perform a "neg,add(value)".
xor(<value>)
Performs a bitwise "XOR" (exclusive OR) between <value> and the input value
of type unsigned integer, and returns the result as an unsigned integer.
2015-01-27 09:12:13 -05:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-07 15:10:16 -04:00
|
|
|
/* Takes a SINT on input, applies an arithmetic "sub" with the SINT directly in
|
2018-11-15 15:14:56 -05:00
|
|
|
* arg_p or in the variable described in arg_p, and returns the SINT result.
|
MEDIUM: samples: provide basic arithmetic and bitwise operators
This commit introduces a new category of converters. They are bitwise and
arithmetic operators which support performing basic operations on integers.
Some bitwise operations are supported (and, or, xor, cpl) and some arithmetic
operations are supported (add, sub, mul, div, mod, neg). Some comparators
are provided (odd, even, not, bool) which make it possible to report a match
without having to write an ACL.
The detailed list of new operators as they appear in the doc is :
add(<value>)
Adds <value> to the input value of type unsigned integer, and returns the
result as an unsigned integer.
and(<value>)
Performs a bitwise "AND" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
bool
Returns a boolean TRUE if the input value of type unsigned integer is
non-null, otherwise returns FALSE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
presence of a flag).
cpl
Takes the input value of type unsigned integer, applies a twos-complement
(flips all bits) and returns the result as an unsigned integer.
div(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
result as an unsigned integer. If <value> is null, the largest unsigned
integer is returned (typically 2^32-1).
even
Returns a boolean TRUE if the input value of type unsigned integer is even
otherwise returns FALSE. It is functionally equivalent to "not,and(1),bool".
mod(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
remainder as an unsigned integer. If <value> is null, then zero is returned.
mul(<value>)
Multiplies the input value of type unsigned integer by <value>, and returns
the product as an unsigned integer. In case of overflow, the higher bits are
lost, leading to seemingly strange values.
neg
Takes the input value of type unsigned integer, computes the opposite value,
and returns the remainder as an unsigned integer. 0 is identity. This
operator is provided for reversed subtracts : in order to subtract the input
from a constant, simply perform a "neg,add(value)".
not
Returns a boolean FALSE if the input value of type unsigned integer is
non-null, otherwise returns TRUE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
absence of a flag).
odd
Returns a boolean TRUE if the input value of type unsigned integer is odd
otherwise returns FALSE. It is functionally equivalent to "and(1),bool".
or(<value>)
Performs a bitwise "OR" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
sub(<value>)
Subtracts <value> from the input value of type unsigned integer, and returns
the result as an unsigned integer. Note: in order to subtract the input from
a constant, simply perform a "neg,add(value)".
xor(<value>)
Performs a bitwise "XOR" (exclusive OR) between <value> and the input value
of type unsigned integer, and returns the result as an unsigned integer.
2015-01-27 09:12:13 -05:00
|
|
|
*/
|
2015-05-11 09:20:49 -04:00
|
|
|
static int sample_conv_arith_sub(const struct arg *arg_p,
|
2015-02-23 09:11:11 -05:00
|
|
|
struct sample *smp, void *private)
|
MEDIUM: samples: provide basic arithmetic and bitwise operators
This commit introduces a new category of converters. They are bitwise and
arithmetic operators which support performing basic operations on integers.
Some bitwise operations are supported (and, or, xor, cpl) and some arithmetic
operations are supported (add, sub, mul, div, mod, neg). Some comparators
are provided (odd, even, not, bool) which make it possible to report a match
without having to write an ACL.
The detailed list of new operators as they appear in the doc is :
add(<value>)
Adds <value> to the input value of type unsigned integer, and returns the
result as an unsigned integer.
and(<value>)
Performs a bitwise "AND" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
bool
Returns a boolean TRUE if the input value of type unsigned integer is
non-null, otherwise returns FALSE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
presence of a flag).
cpl
Takes the input value of type unsigned integer, applies a twos-complement
(flips all bits) and returns the result as an unsigned integer.
div(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
result as an unsigned integer. If <value> is null, the largest unsigned
integer is returned (typically 2^32-1).
even
Returns a boolean TRUE if the input value of type unsigned integer is even
otherwise returns FALSE. It is functionally equivalent to "not,and(1),bool".
mod(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
remainder as an unsigned integer. If <value> is null, then zero is returned.
mul(<value>)
Multiplies the input value of type unsigned integer by <value>, and returns
the product as an unsigned integer. In case of overflow, the higher bits are
lost, leading to seemingly strange values.
neg
Takes the input value of type unsigned integer, computes the opposite value,
and returns the remainder as an unsigned integer. 0 is identity. This
operator is provided for reversed subtracts : in order to subtract the input
from a constant, simply perform a "neg,add(value)".
not
Returns a boolean FALSE if the input value of type unsigned integer is
non-null, otherwise returns TRUE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
absence of a flag).
odd
Returns a boolean TRUE if the input value of type unsigned integer is odd
otherwise returns FALSE. It is functionally equivalent to "and(1),bool".
or(<value>)
Performs a bitwise "OR" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
sub(<value>)
Subtracts <value> from the input value of type unsigned integer, and returns
the result as an unsigned integer. Note: in order to subtract the input from
a constant, simply perform a "neg,add(value)".
xor(<value>)
Performs a bitwise "XOR" (exclusive OR) between <value> and the input value
of type unsigned integer, and returns the result as an unsigned integer.
2015-01-27 09:12:13 -05:00
|
|
|
{
|
2015-07-07 15:10:16 -04:00
|
|
|
struct sample tmp;
|
|
|
|
|
|
2016-03-10 10:28:58 -05:00
|
|
|
smp_set_owner(&tmp, smp->px, smp->sess, smp->strm, smp->opt);
|
2016-03-10 10:33:04 -05:00
|
|
|
if (!sample_conv_var2smp(arg_p, &tmp))
|
2015-07-07 15:10:16 -04:00
|
|
|
return 0;
|
|
|
|
|
|
2015-07-07 19:10:21 -04:00
|
|
|
/* We cannot represent -LLONG_MIN because abs(LLONG_MIN) is greater
|
|
|
|
|
* than abs(LLONG_MAX). So, the following code use LLONG_MAX in place
|
|
|
|
|
* of -LLONG_MIN and correct the result.
|
|
|
|
|
*/
|
2015-08-19 03:07:19 -04:00
|
|
|
if (tmp.data.u.sint == LLONG_MIN) {
|
|
|
|
|
smp->data.u.sint = arith_add(smp->data.u.sint, LLONG_MAX);
|
|
|
|
|
if (smp->data.u.sint < LLONG_MAX)
|
|
|
|
|
smp->data.u.sint++;
|
2015-07-07 19:10:21 -04:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-15 15:14:56 -05:00
|
|
|
/* standard subtraction: we use the "add" function and negate
|
2015-07-07 19:10:21 -04:00
|
|
|
* the second operand.
|
|
|
|
|
*/
|
2015-08-19 03:07:19 -04:00
|
|
|
smp->data.u.sint = arith_add(smp->data.u.sint, -tmp.data.u.sint);
|
MEDIUM: samples: provide basic arithmetic and bitwise operators
This commit introduces a new category of converters. They are bitwise and
arithmetic operators which support performing basic operations on integers.
Some bitwise operations are supported (and, or, xor, cpl) and some arithmetic
operations are supported (add, sub, mul, div, mod, neg). Some comparators
are provided (odd, even, not, bool) which make it possible to report a match
without having to write an ACL.
The detailed list of new operators as they appear in the doc is :
add(<value>)
Adds <value> to the input value of type unsigned integer, and returns the
result as an unsigned integer.
and(<value>)
Performs a bitwise "AND" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
bool
Returns a boolean TRUE if the input value of type unsigned integer is
non-null, otherwise returns FALSE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
presence of a flag).
cpl
Takes the input value of type unsigned integer, applies a twos-complement
(flips all bits) and returns the result as an unsigned integer.
div(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
result as an unsigned integer. If <value> is null, the largest unsigned
integer is returned (typically 2^32-1).
even
Returns a boolean TRUE if the input value of type unsigned integer is even
otherwise returns FALSE. It is functionally equivalent to "not,and(1),bool".
mod(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
remainder as an unsigned integer. If <value> is null, then zero is returned.
mul(<value>)
Multiplies the input value of type unsigned integer by <value>, and returns
the product as an unsigned integer. In case of overflow, the higher bits are
lost, leading to seemingly strange values.
neg
Takes the input value of type unsigned integer, computes the opposite value,
and returns the remainder as an unsigned integer. 0 is identity. This
operator is provided for reversed subtracts : in order to subtract the input
from a constant, simply perform a "neg,add(value)".
not
Returns a boolean FALSE if the input value of type unsigned integer is
non-null, otherwise returns TRUE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
absence of a flag).
odd
Returns a boolean TRUE if the input value of type unsigned integer is odd
otherwise returns FALSE. It is functionally equivalent to "and(1),bool".
or(<value>)
Performs a bitwise "OR" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
sub(<value>)
Subtracts <value> from the input value of type unsigned integer, and returns
the result as an unsigned integer. Note: in order to subtract the input from
a constant, simply perform a "neg,add(value)".
xor(<value>)
Performs a bitwise "XOR" (exclusive OR) between <value> and the input value
of type unsigned integer, and returns the result as an unsigned integer.
2015-01-27 09:12:13 -05:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-07 15:10:16 -04:00
|
|
|
/* Takes a SINT on input, applies an arithmetic "mul" with the SINT directly in
|
2018-11-15 15:14:56 -05:00
|
|
|
* arg_p or in the variable described in arg_p, and returns the SINT result.
|
2015-07-07 15:10:16 -04:00
|
|
|
* If the result makes an overflow, then the largest possible quantity is
|
|
|
|
|
* returned.
|
MEDIUM: samples: provide basic arithmetic and bitwise operators
This commit introduces a new category of converters. They are bitwise and
arithmetic operators which support performing basic operations on integers.
Some bitwise operations are supported (and, or, xor, cpl) and some arithmetic
operations are supported (add, sub, mul, div, mod, neg). Some comparators
are provided (odd, even, not, bool) which make it possible to report a match
without having to write an ACL.
The detailed list of new operators as they appear in the doc is :
add(<value>)
Adds <value> to the input value of type unsigned integer, and returns the
result as an unsigned integer.
and(<value>)
Performs a bitwise "AND" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
bool
Returns a boolean TRUE if the input value of type unsigned integer is
non-null, otherwise returns FALSE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
presence of a flag).
cpl
Takes the input value of type unsigned integer, applies a twos-complement
(flips all bits) and returns the result as an unsigned integer.
div(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
result as an unsigned integer. If <value> is null, the largest unsigned
integer is returned (typically 2^32-1).
even
Returns a boolean TRUE if the input value of type unsigned integer is even
otherwise returns FALSE. It is functionally equivalent to "not,and(1),bool".
mod(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
remainder as an unsigned integer. If <value> is null, then zero is returned.
mul(<value>)
Multiplies the input value of type unsigned integer by <value>, and returns
the product as an unsigned integer. In case of overflow, the higher bits are
lost, leading to seemingly strange values.
neg
Takes the input value of type unsigned integer, computes the opposite value,
and returns the remainder as an unsigned integer. 0 is identity. This
operator is provided for reversed subtracts : in order to subtract the input
from a constant, simply perform a "neg,add(value)".
not
Returns a boolean FALSE if the input value of type unsigned integer is
non-null, otherwise returns TRUE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
absence of a flag).
odd
Returns a boolean TRUE if the input value of type unsigned integer is odd
otherwise returns FALSE. It is functionally equivalent to "and(1),bool".
or(<value>)
Performs a bitwise "OR" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
sub(<value>)
Subtracts <value> from the input value of type unsigned integer, and returns
the result as an unsigned integer. Note: in order to subtract the input from
a constant, simply perform a "neg,add(value)".
xor(<value>)
Performs a bitwise "XOR" (exclusive OR) between <value> and the input value
of type unsigned integer, and returns the result as an unsigned integer.
2015-01-27 09:12:13 -05:00
|
|
|
*/
|
2015-05-11 09:20:49 -04:00
|
|
|
static int sample_conv_arith_mul(const struct arg *arg_p,
|
2015-02-23 09:11:11 -05:00
|
|
|
struct sample *smp, void *private)
|
MEDIUM: samples: provide basic arithmetic and bitwise operators
This commit introduces a new category of converters. They are bitwise and
arithmetic operators which support performing basic operations on integers.
Some bitwise operations are supported (and, or, xor, cpl) and some arithmetic
operations are supported (add, sub, mul, div, mod, neg). Some comparators
are provided (odd, even, not, bool) which make it possible to report a match
without having to write an ACL.
The detailed list of new operators as they appear in the doc is :
add(<value>)
Adds <value> to the input value of type unsigned integer, and returns the
result as an unsigned integer.
and(<value>)
Performs a bitwise "AND" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
bool
Returns a boolean TRUE if the input value of type unsigned integer is
non-null, otherwise returns FALSE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
presence of a flag).
cpl
Takes the input value of type unsigned integer, applies a twos-complement
(flips all bits) and returns the result as an unsigned integer.
div(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
result as an unsigned integer. If <value> is null, the largest unsigned
integer is returned (typically 2^32-1).
even
Returns a boolean TRUE if the input value of type unsigned integer is even
otherwise returns FALSE. It is functionally equivalent to "not,and(1),bool".
mod(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
remainder as an unsigned integer. If <value> is null, then zero is returned.
mul(<value>)
Multiplies the input value of type unsigned integer by <value>, and returns
the product as an unsigned integer. In case of overflow, the higher bits are
lost, leading to seemingly strange values.
neg
Takes the input value of type unsigned integer, computes the opposite value,
and returns the remainder as an unsigned integer. 0 is identity. This
operator is provided for reversed subtracts : in order to subtract the input
from a constant, simply perform a "neg,add(value)".
not
Returns a boolean FALSE if the input value of type unsigned integer is
non-null, otherwise returns TRUE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
absence of a flag).
odd
Returns a boolean TRUE if the input value of type unsigned integer is odd
otherwise returns FALSE. It is functionally equivalent to "and(1),bool".
or(<value>)
Performs a bitwise "OR" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
sub(<value>)
Subtracts <value> from the input value of type unsigned integer, and returns
the result as an unsigned integer. Note: in order to subtract the input from
a constant, simply perform a "neg,add(value)".
xor(<value>)
Performs a bitwise "XOR" (exclusive OR) between <value> and the input value
of type unsigned integer, and returns the result as an unsigned integer.
2015-01-27 09:12:13 -05:00
|
|
|
{
|
2015-07-07 15:10:16 -04:00
|
|
|
struct sample tmp;
|
2015-07-07 19:10:21 -04:00
|
|
|
long long int c;
|
|
|
|
|
|
2016-03-10 10:28:58 -05:00
|
|
|
smp_set_owner(&tmp, smp->px, smp->sess, smp->strm, smp->opt);
|
2016-03-10 10:33:04 -05:00
|
|
|
if (!sample_conv_var2smp(arg_p, &tmp))
|
2015-07-07 15:10:16 -04:00
|
|
|
return 0;
|
|
|
|
|
|
2015-07-07 19:10:21 -04:00
|
|
|
/* prevent divide by 0 during the check */
|
2015-08-19 03:07:19 -04:00
|
|
|
if (!smp->data.u.sint || !tmp.data.u.sint) {
|
|
|
|
|
smp->data.u.sint = 0;
|
2015-07-07 19:10:21 -04:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* The multiply between LLONG_MIN and -1 returns a
|
|
|
|
|
* "floting point exception".
|
|
|
|
|
*/
|
2015-08-19 03:07:19 -04:00
|
|
|
if (smp->data.u.sint == LLONG_MIN && tmp.data.u.sint == -1) {
|
|
|
|
|
smp->data.u.sint = LLONG_MAX;
|
2015-07-07 19:10:21 -04:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* execute standard multiplication. */
|
2015-08-19 03:07:19 -04:00
|
|
|
c = smp->data.u.sint * tmp.data.u.sint;
|
2015-07-07 19:10:21 -04:00
|
|
|
|
|
|
|
|
/* check for overflow and makes capped multiply. */
|
2015-08-19 03:07:19 -04:00
|
|
|
if (smp->data.u.sint != c / tmp.data.u.sint) {
|
|
|
|
|
if ((smp->data.u.sint < 0) == (tmp.data.u.sint < 0)) {
|
|
|
|
|
smp->data.u.sint = LLONG_MAX;
|
2015-07-07 19:10:21 -04:00
|
|
|
return 1;
|
|
|
|
|
}
|
2015-08-19 03:07:19 -04:00
|
|
|
smp->data.u.sint = LLONG_MIN;
|
2015-07-07 19:10:21 -04:00
|
|
|
return 1;
|
|
|
|
|
}
|
2015-08-19 03:07:19 -04:00
|
|
|
smp->data.u.sint = c;
|
MEDIUM: samples: provide basic arithmetic and bitwise operators
This commit introduces a new category of converters. They are bitwise and
arithmetic operators which support performing basic operations on integers.
Some bitwise operations are supported (and, or, xor, cpl) and some arithmetic
operations are supported (add, sub, mul, div, mod, neg). Some comparators
are provided (odd, even, not, bool) which make it possible to report a match
without having to write an ACL.
The detailed list of new operators as they appear in the doc is :
add(<value>)
Adds <value> to the input value of type unsigned integer, and returns the
result as an unsigned integer.
and(<value>)
Performs a bitwise "AND" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
bool
Returns a boolean TRUE if the input value of type unsigned integer is
non-null, otherwise returns FALSE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
presence of a flag).
cpl
Takes the input value of type unsigned integer, applies a twos-complement
(flips all bits) and returns the result as an unsigned integer.
div(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
result as an unsigned integer. If <value> is null, the largest unsigned
integer is returned (typically 2^32-1).
even
Returns a boolean TRUE if the input value of type unsigned integer is even
otherwise returns FALSE. It is functionally equivalent to "not,and(1),bool".
mod(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
remainder as an unsigned integer. If <value> is null, then zero is returned.
mul(<value>)
Multiplies the input value of type unsigned integer by <value>, and returns
the product as an unsigned integer. In case of overflow, the higher bits are
lost, leading to seemingly strange values.
neg
Takes the input value of type unsigned integer, computes the opposite value,
and returns the remainder as an unsigned integer. 0 is identity. This
operator is provided for reversed subtracts : in order to subtract the input
from a constant, simply perform a "neg,add(value)".
not
Returns a boolean FALSE if the input value of type unsigned integer is
non-null, otherwise returns TRUE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
absence of a flag).
odd
Returns a boolean TRUE if the input value of type unsigned integer is odd
otherwise returns FALSE. It is functionally equivalent to "and(1),bool".
or(<value>)
Performs a bitwise "OR" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
sub(<value>)
Subtracts <value> from the input value of type unsigned integer, and returns
the result as an unsigned integer. Note: in order to subtract the input from
a constant, simply perform a "neg,add(value)".
xor(<value>)
Performs a bitwise "XOR" (exclusive OR) between <value> and the input value
of type unsigned integer, and returns the result as an unsigned integer.
2015-01-27 09:12:13 -05:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-07 15:10:16 -04:00
|
|
|
/* Takes a SINT on input, applies an arithmetic "div" with the SINT directly in
|
2018-11-15 15:14:56 -05:00
|
|
|
* arg_p or in the variable described in arg_p, and returns the SINT result.
|
2015-07-07 15:10:16 -04:00
|
|
|
* If arg_p makes the result overflow, then the largest possible quantity is
|
|
|
|
|
* returned.
|
MEDIUM: samples: provide basic arithmetic and bitwise operators
This commit introduces a new category of converters. They are bitwise and
arithmetic operators which support performing basic operations on integers.
Some bitwise operations are supported (and, or, xor, cpl) and some arithmetic
operations are supported (add, sub, mul, div, mod, neg). Some comparators
are provided (odd, even, not, bool) which make it possible to report a match
without having to write an ACL.
The detailed list of new operators as they appear in the doc is :
add(<value>)
Adds <value> to the input value of type unsigned integer, and returns the
result as an unsigned integer.
and(<value>)
Performs a bitwise "AND" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
bool
Returns a boolean TRUE if the input value of type unsigned integer is
non-null, otherwise returns FALSE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
presence of a flag).
cpl
Takes the input value of type unsigned integer, applies a twos-complement
(flips all bits) and returns the result as an unsigned integer.
div(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
result as an unsigned integer. If <value> is null, the largest unsigned
integer is returned (typically 2^32-1).
even
Returns a boolean TRUE if the input value of type unsigned integer is even
otherwise returns FALSE. It is functionally equivalent to "not,and(1),bool".
mod(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
remainder as an unsigned integer. If <value> is null, then zero is returned.
mul(<value>)
Multiplies the input value of type unsigned integer by <value>, and returns
the product as an unsigned integer. In case of overflow, the higher bits are
lost, leading to seemingly strange values.
neg
Takes the input value of type unsigned integer, computes the opposite value,
and returns the remainder as an unsigned integer. 0 is identity. This
operator is provided for reversed subtracts : in order to subtract the input
from a constant, simply perform a "neg,add(value)".
not
Returns a boolean FALSE if the input value of type unsigned integer is
non-null, otherwise returns TRUE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
absence of a flag).
odd
Returns a boolean TRUE if the input value of type unsigned integer is odd
otherwise returns FALSE. It is functionally equivalent to "and(1),bool".
or(<value>)
Performs a bitwise "OR" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
sub(<value>)
Subtracts <value> from the input value of type unsigned integer, and returns
the result as an unsigned integer. Note: in order to subtract the input from
a constant, simply perform a "neg,add(value)".
xor(<value>)
Performs a bitwise "XOR" (exclusive OR) between <value> and the input value
of type unsigned integer, and returns the result as an unsigned integer.
2015-01-27 09:12:13 -05:00
|
|
|
*/
|
2015-05-11 09:20:49 -04:00
|
|
|
static int sample_conv_arith_div(const struct arg *arg_p,
|
2015-02-23 09:11:11 -05:00
|
|
|
struct sample *smp, void *private)
|
MEDIUM: samples: provide basic arithmetic and bitwise operators
This commit introduces a new category of converters. They are bitwise and
arithmetic operators which support performing basic operations on integers.
Some bitwise operations are supported (and, or, xor, cpl) and some arithmetic
operations are supported (add, sub, mul, div, mod, neg). Some comparators
are provided (odd, even, not, bool) which make it possible to report a match
without having to write an ACL.
The detailed list of new operators as they appear in the doc is :
add(<value>)
Adds <value> to the input value of type unsigned integer, and returns the
result as an unsigned integer.
and(<value>)
Performs a bitwise "AND" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
bool
Returns a boolean TRUE if the input value of type unsigned integer is
non-null, otherwise returns FALSE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
presence of a flag).
cpl
Takes the input value of type unsigned integer, applies a twos-complement
(flips all bits) and returns the result as an unsigned integer.
div(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
result as an unsigned integer. If <value> is null, the largest unsigned
integer is returned (typically 2^32-1).
even
Returns a boolean TRUE if the input value of type unsigned integer is even
otherwise returns FALSE. It is functionally equivalent to "not,and(1),bool".
mod(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
remainder as an unsigned integer. If <value> is null, then zero is returned.
mul(<value>)
Multiplies the input value of type unsigned integer by <value>, and returns
the product as an unsigned integer. In case of overflow, the higher bits are
lost, leading to seemingly strange values.
neg
Takes the input value of type unsigned integer, computes the opposite value,
and returns the remainder as an unsigned integer. 0 is identity. This
operator is provided for reversed subtracts : in order to subtract the input
from a constant, simply perform a "neg,add(value)".
not
Returns a boolean FALSE if the input value of type unsigned integer is
non-null, otherwise returns TRUE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
absence of a flag).
odd
Returns a boolean TRUE if the input value of type unsigned integer is odd
otherwise returns FALSE. It is functionally equivalent to "and(1),bool".
or(<value>)
Performs a bitwise "OR" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
sub(<value>)
Subtracts <value> from the input value of type unsigned integer, and returns
the result as an unsigned integer. Note: in order to subtract the input from
a constant, simply perform a "neg,add(value)".
xor(<value>)
Performs a bitwise "XOR" (exclusive OR) between <value> and the input value
of type unsigned integer, and returns the result as an unsigned integer.
2015-01-27 09:12:13 -05:00
|
|
|
{
|
2015-07-07 15:10:16 -04:00
|
|
|
struct sample tmp;
|
|
|
|
|
|
2016-03-10 10:28:58 -05:00
|
|
|
smp_set_owner(&tmp, smp->px, smp->sess, smp->strm, smp->opt);
|
2016-03-10 10:33:04 -05:00
|
|
|
if (!sample_conv_var2smp(arg_p, &tmp))
|
2015-07-07 15:10:16 -04:00
|
|
|
return 0;
|
|
|
|
|
|
2015-08-19 03:07:19 -04:00
|
|
|
if (tmp.data.u.sint) {
|
2015-07-07 19:10:21 -04:00
|
|
|
/* The divide between LLONG_MIN and -1 returns a
|
|
|
|
|
* "floting point exception".
|
|
|
|
|
*/
|
2015-08-19 03:07:19 -04:00
|
|
|
if (smp->data.u.sint == LLONG_MIN && tmp.data.u.sint == -1) {
|
|
|
|
|
smp->data.u.sint = LLONG_MAX;
|
2015-07-07 19:10:21 -04:00
|
|
|
return 1;
|
|
|
|
|
}
|
2015-08-19 03:07:19 -04:00
|
|
|
smp->data.u.sint /= tmp.data.u.sint;
|
2015-07-07 19:10:21 -04:00
|
|
|
return 1;
|
|
|
|
|
}
|
2015-08-19 03:07:19 -04:00
|
|
|
smp->data.u.sint = LLONG_MAX;
|
MEDIUM: samples: provide basic arithmetic and bitwise operators
This commit introduces a new category of converters. They are bitwise and
arithmetic operators which support performing basic operations on integers.
Some bitwise operations are supported (and, or, xor, cpl) and some arithmetic
operations are supported (add, sub, mul, div, mod, neg). Some comparators
are provided (odd, even, not, bool) which make it possible to report a match
without having to write an ACL.
The detailed list of new operators as they appear in the doc is :
add(<value>)
Adds <value> to the input value of type unsigned integer, and returns the
result as an unsigned integer.
and(<value>)
Performs a bitwise "AND" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
bool
Returns a boolean TRUE if the input value of type unsigned integer is
non-null, otherwise returns FALSE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
presence of a flag).
cpl
Takes the input value of type unsigned integer, applies a twos-complement
(flips all bits) and returns the result as an unsigned integer.
div(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
result as an unsigned integer. If <value> is null, the largest unsigned
integer is returned (typically 2^32-1).
even
Returns a boolean TRUE if the input value of type unsigned integer is even
otherwise returns FALSE. It is functionally equivalent to "not,and(1),bool".
mod(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
remainder as an unsigned integer. If <value> is null, then zero is returned.
mul(<value>)
Multiplies the input value of type unsigned integer by <value>, and returns
the product as an unsigned integer. In case of overflow, the higher bits are
lost, leading to seemingly strange values.
neg
Takes the input value of type unsigned integer, computes the opposite value,
and returns the remainder as an unsigned integer. 0 is identity. This
operator is provided for reversed subtracts : in order to subtract the input
from a constant, simply perform a "neg,add(value)".
not
Returns a boolean FALSE if the input value of type unsigned integer is
non-null, otherwise returns TRUE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
absence of a flag).
odd
Returns a boolean TRUE if the input value of type unsigned integer is odd
otherwise returns FALSE. It is functionally equivalent to "and(1),bool".
or(<value>)
Performs a bitwise "OR" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
sub(<value>)
Subtracts <value> from the input value of type unsigned integer, and returns
the result as an unsigned integer. Note: in order to subtract the input from
a constant, simply perform a "neg,add(value)".
xor(<value>)
Performs a bitwise "XOR" (exclusive OR) between <value> and the input value
of type unsigned integer, and returns the result as an unsigned integer.
2015-01-27 09:12:13 -05:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-07 15:10:16 -04:00
|
|
|
/* Takes a SINT on input, applies an arithmetic "mod" with the SINT directly in
|
2018-11-15 15:14:56 -05:00
|
|
|
* arg_p or in the variable described in arg_p, and returns the SINT result.
|
2015-07-07 15:10:16 -04:00
|
|
|
* If arg_p makes the result overflow, then 0 is returned.
|
MEDIUM: samples: provide basic arithmetic and bitwise operators
This commit introduces a new category of converters. They are bitwise and
arithmetic operators which support performing basic operations on integers.
Some bitwise operations are supported (and, or, xor, cpl) and some arithmetic
operations are supported (add, sub, mul, div, mod, neg). Some comparators
are provided (odd, even, not, bool) which make it possible to report a match
without having to write an ACL.
The detailed list of new operators as they appear in the doc is :
add(<value>)
Adds <value> to the input value of type unsigned integer, and returns the
result as an unsigned integer.
and(<value>)
Performs a bitwise "AND" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
bool
Returns a boolean TRUE if the input value of type unsigned integer is
non-null, otherwise returns FALSE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
presence of a flag).
cpl
Takes the input value of type unsigned integer, applies a twos-complement
(flips all bits) and returns the result as an unsigned integer.
div(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
result as an unsigned integer. If <value> is null, the largest unsigned
integer is returned (typically 2^32-1).
even
Returns a boolean TRUE if the input value of type unsigned integer is even
otherwise returns FALSE. It is functionally equivalent to "not,and(1),bool".
mod(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
remainder as an unsigned integer. If <value> is null, then zero is returned.
mul(<value>)
Multiplies the input value of type unsigned integer by <value>, and returns
the product as an unsigned integer. In case of overflow, the higher bits are
lost, leading to seemingly strange values.
neg
Takes the input value of type unsigned integer, computes the opposite value,
and returns the remainder as an unsigned integer. 0 is identity. This
operator is provided for reversed subtracts : in order to subtract the input
from a constant, simply perform a "neg,add(value)".
not
Returns a boolean FALSE if the input value of type unsigned integer is
non-null, otherwise returns TRUE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
absence of a flag).
odd
Returns a boolean TRUE if the input value of type unsigned integer is odd
otherwise returns FALSE. It is functionally equivalent to "and(1),bool".
or(<value>)
Performs a bitwise "OR" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
sub(<value>)
Subtracts <value> from the input value of type unsigned integer, and returns
the result as an unsigned integer. Note: in order to subtract the input from
a constant, simply perform a "neg,add(value)".
xor(<value>)
Performs a bitwise "XOR" (exclusive OR) between <value> and the input value
of type unsigned integer, and returns the result as an unsigned integer.
2015-01-27 09:12:13 -05:00
|
|
|
*/
|
2015-05-11 09:20:49 -04:00
|
|
|
static int sample_conv_arith_mod(const struct arg *arg_p,
|
2015-02-23 09:11:11 -05:00
|
|
|
struct sample *smp, void *private)
|
MEDIUM: samples: provide basic arithmetic and bitwise operators
This commit introduces a new category of converters. They are bitwise and
arithmetic operators which support performing basic operations on integers.
Some bitwise operations are supported (and, or, xor, cpl) and some arithmetic
operations are supported (add, sub, mul, div, mod, neg). Some comparators
are provided (odd, even, not, bool) which make it possible to report a match
without having to write an ACL.
The detailed list of new operators as they appear in the doc is :
add(<value>)
Adds <value> to the input value of type unsigned integer, and returns the
result as an unsigned integer.
and(<value>)
Performs a bitwise "AND" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
bool
Returns a boolean TRUE if the input value of type unsigned integer is
non-null, otherwise returns FALSE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
presence of a flag).
cpl
Takes the input value of type unsigned integer, applies a twos-complement
(flips all bits) and returns the result as an unsigned integer.
div(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
result as an unsigned integer. If <value> is null, the largest unsigned
integer is returned (typically 2^32-1).
even
Returns a boolean TRUE if the input value of type unsigned integer is even
otherwise returns FALSE. It is functionally equivalent to "not,and(1),bool".
mod(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
remainder as an unsigned integer. If <value> is null, then zero is returned.
mul(<value>)
Multiplies the input value of type unsigned integer by <value>, and returns
the product as an unsigned integer. In case of overflow, the higher bits are
lost, leading to seemingly strange values.
neg
Takes the input value of type unsigned integer, computes the opposite value,
and returns the remainder as an unsigned integer. 0 is identity. This
operator is provided for reversed subtracts : in order to subtract the input
from a constant, simply perform a "neg,add(value)".
not
Returns a boolean FALSE if the input value of type unsigned integer is
non-null, otherwise returns TRUE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
absence of a flag).
odd
Returns a boolean TRUE if the input value of type unsigned integer is odd
otherwise returns FALSE. It is functionally equivalent to "and(1),bool".
or(<value>)
Performs a bitwise "OR" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
sub(<value>)
Subtracts <value> from the input value of type unsigned integer, and returns
the result as an unsigned integer. Note: in order to subtract the input from
a constant, simply perform a "neg,add(value)".
xor(<value>)
Performs a bitwise "XOR" (exclusive OR) between <value> and the input value
of type unsigned integer, and returns the result as an unsigned integer.
2015-01-27 09:12:13 -05:00
|
|
|
{
|
2015-07-07 15:10:16 -04:00
|
|
|
struct sample tmp;
|
|
|
|
|
|
2016-03-10 10:28:58 -05:00
|
|
|
smp_set_owner(&tmp, smp->px, smp->sess, smp->strm, smp->opt);
|
2016-03-10 10:33:04 -05:00
|
|
|
if (!sample_conv_var2smp(arg_p, &tmp))
|
2015-07-07 15:10:16 -04:00
|
|
|
return 0;
|
|
|
|
|
|
2015-08-19 03:07:19 -04:00
|
|
|
if (tmp.data.u.sint) {
|
2015-07-07 19:10:21 -04:00
|
|
|
/* The divide between LLONG_MIN and -1 returns a
|
|
|
|
|
* "floting point exception".
|
|
|
|
|
*/
|
2015-08-19 03:07:19 -04:00
|
|
|
if (smp->data.u.sint == LLONG_MIN && tmp.data.u.sint == -1) {
|
|
|
|
|
smp->data.u.sint = 0;
|
2015-07-07 19:10:21 -04:00
|
|
|
return 1;
|
|
|
|
|
}
|
2015-08-19 03:07:19 -04:00
|
|
|
smp->data.u.sint %= tmp.data.u.sint;
|
2015-07-07 19:10:21 -04:00
|
|
|
return 1;
|
|
|
|
|
}
|
2015-08-19 03:07:19 -04:00
|
|
|
smp->data.u.sint = 0;
|
MEDIUM: samples: provide basic arithmetic and bitwise operators
This commit introduces a new category of converters. They are bitwise and
arithmetic operators which support performing basic operations on integers.
Some bitwise operations are supported (and, or, xor, cpl) and some arithmetic
operations are supported (add, sub, mul, div, mod, neg). Some comparators
are provided (odd, even, not, bool) which make it possible to report a match
without having to write an ACL.
The detailed list of new operators as they appear in the doc is :
add(<value>)
Adds <value> to the input value of type unsigned integer, and returns the
result as an unsigned integer.
and(<value>)
Performs a bitwise "AND" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
bool
Returns a boolean TRUE if the input value of type unsigned integer is
non-null, otherwise returns FALSE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
presence of a flag).
cpl
Takes the input value of type unsigned integer, applies a twos-complement
(flips all bits) and returns the result as an unsigned integer.
div(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
result as an unsigned integer. If <value> is null, the largest unsigned
integer is returned (typically 2^32-1).
even
Returns a boolean TRUE if the input value of type unsigned integer is even
otherwise returns FALSE. It is functionally equivalent to "not,and(1),bool".
mod(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
remainder as an unsigned integer. If <value> is null, then zero is returned.
mul(<value>)
Multiplies the input value of type unsigned integer by <value>, and returns
the product as an unsigned integer. In case of overflow, the higher bits are
lost, leading to seemingly strange values.
neg
Takes the input value of type unsigned integer, computes the opposite value,
and returns the remainder as an unsigned integer. 0 is identity. This
operator is provided for reversed subtracts : in order to subtract the input
from a constant, simply perform a "neg,add(value)".
not
Returns a boolean FALSE if the input value of type unsigned integer is
non-null, otherwise returns TRUE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
absence of a flag).
odd
Returns a boolean TRUE if the input value of type unsigned integer is odd
otherwise returns FALSE. It is functionally equivalent to "and(1),bool".
or(<value>)
Performs a bitwise "OR" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
sub(<value>)
Subtracts <value> from the input value of type unsigned integer, and returns
the result as an unsigned integer. Note: in order to subtract the input from
a constant, simply perform a "neg,add(value)".
xor(<value>)
Performs a bitwise "XOR" (exclusive OR) between <value> and the input value
of type unsigned integer, and returns the result as an unsigned integer.
2015-01-27 09:12:13 -05:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-06 17:43:03 -04:00
|
|
|
/* Takes an SINT on input, applies an arithmetic "neg" and returns the SINT
|
MEDIUM: samples: provide basic arithmetic and bitwise operators
This commit introduces a new category of converters. They are bitwise and
arithmetic operators which support performing basic operations on integers.
Some bitwise operations are supported (and, or, xor, cpl) and some arithmetic
operations are supported (add, sub, mul, div, mod, neg). Some comparators
are provided (odd, even, not, bool) which make it possible to report a match
without having to write an ACL.
The detailed list of new operators as they appear in the doc is :
add(<value>)
Adds <value> to the input value of type unsigned integer, and returns the
result as an unsigned integer.
and(<value>)
Performs a bitwise "AND" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
bool
Returns a boolean TRUE if the input value of type unsigned integer is
non-null, otherwise returns FALSE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
presence of a flag).
cpl
Takes the input value of type unsigned integer, applies a twos-complement
(flips all bits) and returns the result as an unsigned integer.
div(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
result as an unsigned integer. If <value> is null, the largest unsigned
integer is returned (typically 2^32-1).
even
Returns a boolean TRUE if the input value of type unsigned integer is even
otherwise returns FALSE. It is functionally equivalent to "not,and(1),bool".
mod(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
remainder as an unsigned integer. If <value> is null, then zero is returned.
mul(<value>)
Multiplies the input value of type unsigned integer by <value>, and returns
the product as an unsigned integer. In case of overflow, the higher bits are
lost, leading to seemingly strange values.
neg
Takes the input value of type unsigned integer, computes the opposite value,
and returns the remainder as an unsigned integer. 0 is identity. This
operator is provided for reversed subtracts : in order to subtract the input
from a constant, simply perform a "neg,add(value)".
not
Returns a boolean FALSE if the input value of type unsigned integer is
non-null, otherwise returns TRUE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
absence of a flag).
odd
Returns a boolean TRUE if the input value of type unsigned integer is odd
otherwise returns FALSE. It is functionally equivalent to "and(1),bool".
or(<value>)
Performs a bitwise "OR" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
sub(<value>)
Subtracts <value> from the input value of type unsigned integer, and returns
the result as an unsigned integer. Note: in order to subtract the input from
a constant, simply perform a "neg,add(value)".
xor(<value>)
Performs a bitwise "XOR" (exclusive OR) between <value> and the input value
of type unsigned integer, and returns the result as an unsigned integer.
2015-01-27 09:12:13 -05:00
|
|
|
* result.
|
|
|
|
|
*/
|
2015-05-11 09:20:49 -04:00
|
|
|
static int sample_conv_arith_neg(const struct arg *arg_p,
|
2015-02-23 09:11:11 -05:00
|
|
|
struct sample *smp, void *private)
|
MEDIUM: samples: provide basic arithmetic and bitwise operators
This commit introduces a new category of converters. They are bitwise and
arithmetic operators which support performing basic operations on integers.
Some bitwise operations are supported (and, or, xor, cpl) and some arithmetic
operations are supported (add, sub, mul, div, mod, neg). Some comparators
are provided (odd, even, not, bool) which make it possible to report a match
without having to write an ACL.
The detailed list of new operators as they appear in the doc is :
add(<value>)
Adds <value> to the input value of type unsigned integer, and returns the
result as an unsigned integer.
and(<value>)
Performs a bitwise "AND" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
bool
Returns a boolean TRUE if the input value of type unsigned integer is
non-null, otherwise returns FALSE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
presence of a flag).
cpl
Takes the input value of type unsigned integer, applies a twos-complement
(flips all bits) and returns the result as an unsigned integer.
div(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
result as an unsigned integer. If <value> is null, the largest unsigned
integer is returned (typically 2^32-1).
even
Returns a boolean TRUE if the input value of type unsigned integer is even
otherwise returns FALSE. It is functionally equivalent to "not,and(1),bool".
mod(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
remainder as an unsigned integer. If <value> is null, then zero is returned.
mul(<value>)
Multiplies the input value of type unsigned integer by <value>, and returns
the product as an unsigned integer. In case of overflow, the higher bits are
lost, leading to seemingly strange values.
neg
Takes the input value of type unsigned integer, computes the opposite value,
and returns the remainder as an unsigned integer. 0 is identity. This
operator is provided for reversed subtracts : in order to subtract the input
from a constant, simply perform a "neg,add(value)".
not
Returns a boolean FALSE if the input value of type unsigned integer is
non-null, otherwise returns TRUE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
absence of a flag).
odd
Returns a boolean TRUE if the input value of type unsigned integer is odd
otherwise returns FALSE. It is functionally equivalent to "and(1),bool".
or(<value>)
Performs a bitwise "OR" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
sub(<value>)
Subtracts <value> from the input value of type unsigned integer, and returns
the result as an unsigned integer. Note: in order to subtract the input from
a constant, simply perform a "neg,add(value)".
xor(<value>)
Performs a bitwise "XOR" (exclusive OR) between <value> and the input value
of type unsigned integer, and returns the result as an unsigned integer.
2015-01-27 09:12:13 -05:00
|
|
|
{
|
2015-08-19 03:07:19 -04:00
|
|
|
if (smp->data.u.sint == LLONG_MIN)
|
|
|
|
|
smp->data.u.sint = LLONG_MAX;
|
2015-07-07 19:10:21 -04:00
|
|
|
else
|
2015-08-19 03:07:19 -04:00
|
|
|
smp->data.u.sint = -smp->data.u.sint;
|
MEDIUM: samples: provide basic arithmetic and bitwise operators
This commit introduces a new category of converters. They are bitwise and
arithmetic operators which support performing basic operations on integers.
Some bitwise operations are supported (and, or, xor, cpl) and some arithmetic
operations are supported (add, sub, mul, div, mod, neg). Some comparators
are provided (odd, even, not, bool) which make it possible to report a match
without having to write an ACL.
The detailed list of new operators as they appear in the doc is :
add(<value>)
Adds <value> to the input value of type unsigned integer, and returns the
result as an unsigned integer.
and(<value>)
Performs a bitwise "AND" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
bool
Returns a boolean TRUE if the input value of type unsigned integer is
non-null, otherwise returns FALSE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
presence of a flag).
cpl
Takes the input value of type unsigned integer, applies a twos-complement
(flips all bits) and returns the result as an unsigned integer.
div(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
result as an unsigned integer. If <value> is null, the largest unsigned
integer is returned (typically 2^32-1).
even
Returns a boolean TRUE if the input value of type unsigned integer is even
otherwise returns FALSE. It is functionally equivalent to "not,and(1),bool".
mod(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
remainder as an unsigned integer. If <value> is null, then zero is returned.
mul(<value>)
Multiplies the input value of type unsigned integer by <value>, and returns
the product as an unsigned integer. In case of overflow, the higher bits are
lost, leading to seemingly strange values.
neg
Takes the input value of type unsigned integer, computes the opposite value,
and returns the remainder as an unsigned integer. 0 is identity. This
operator is provided for reversed subtracts : in order to subtract the input
from a constant, simply perform a "neg,add(value)".
not
Returns a boolean FALSE if the input value of type unsigned integer is
non-null, otherwise returns TRUE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
absence of a flag).
odd
Returns a boolean TRUE if the input value of type unsigned integer is odd
otherwise returns FALSE. It is functionally equivalent to "and(1),bool".
or(<value>)
Performs a bitwise "OR" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
sub(<value>)
Subtracts <value> from the input value of type unsigned integer, and returns
the result as an unsigned integer. Note: in order to subtract the input from
a constant, simply perform a "neg,add(value)".
xor(<value>)
Performs a bitwise "XOR" (exclusive OR) between <value> and the input value
of type unsigned integer, and returns the result as an unsigned integer.
2015-01-27 09:12:13 -05:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-06 17:43:03 -04:00
|
|
|
/* Takes a SINT on input, returns true is the value is non-null, otherwise
|
MEDIUM: samples: provide basic arithmetic and bitwise operators
This commit introduces a new category of converters. They are bitwise and
arithmetic operators which support performing basic operations on integers.
Some bitwise operations are supported (and, or, xor, cpl) and some arithmetic
operations are supported (add, sub, mul, div, mod, neg). Some comparators
are provided (odd, even, not, bool) which make it possible to report a match
without having to write an ACL.
The detailed list of new operators as they appear in the doc is :
add(<value>)
Adds <value> to the input value of type unsigned integer, and returns the
result as an unsigned integer.
and(<value>)
Performs a bitwise "AND" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
bool
Returns a boolean TRUE if the input value of type unsigned integer is
non-null, otherwise returns FALSE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
presence of a flag).
cpl
Takes the input value of type unsigned integer, applies a twos-complement
(flips all bits) and returns the result as an unsigned integer.
div(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
result as an unsigned integer. If <value> is null, the largest unsigned
integer is returned (typically 2^32-1).
even
Returns a boolean TRUE if the input value of type unsigned integer is even
otherwise returns FALSE. It is functionally equivalent to "not,and(1),bool".
mod(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
remainder as an unsigned integer. If <value> is null, then zero is returned.
mul(<value>)
Multiplies the input value of type unsigned integer by <value>, and returns
the product as an unsigned integer. In case of overflow, the higher bits are
lost, leading to seemingly strange values.
neg
Takes the input value of type unsigned integer, computes the opposite value,
and returns the remainder as an unsigned integer. 0 is identity. This
operator is provided for reversed subtracts : in order to subtract the input
from a constant, simply perform a "neg,add(value)".
not
Returns a boolean FALSE if the input value of type unsigned integer is
non-null, otherwise returns TRUE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
absence of a flag).
odd
Returns a boolean TRUE if the input value of type unsigned integer is odd
otherwise returns FALSE. It is functionally equivalent to "and(1),bool".
or(<value>)
Performs a bitwise "OR" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
sub(<value>)
Subtracts <value> from the input value of type unsigned integer, and returns
the result as an unsigned integer. Note: in order to subtract the input from
a constant, simply perform a "neg,add(value)".
xor(<value>)
Performs a bitwise "XOR" (exclusive OR) between <value> and the input value
of type unsigned integer, and returns the result as an unsigned integer.
2015-01-27 09:12:13 -05:00
|
|
|
* false. The output is a BOOL.
|
|
|
|
|
*/
|
2015-05-11 09:20:49 -04:00
|
|
|
static int sample_conv_arith_bool(const struct arg *arg_p,
|
2015-02-23 09:11:11 -05:00
|
|
|
struct sample *smp, void *private)
|
MEDIUM: samples: provide basic arithmetic and bitwise operators
This commit introduces a new category of converters. They are bitwise and
arithmetic operators which support performing basic operations on integers.
Some bitwise operations are supported (and, or, xor, cpl) and some arithmetic
operations are supported (add, sub, mul, div, mod, neg). Some comparators
are provided (odd, even, not, bool) which make it possible to report a match
without having to write an ACL.
The detailed list of new operators as they appear in the doc is :
add(<value>)
Adds <value> to the input value of type unsigned integer, and returns the
result as an unsigned integer.
and(<value>)
Performs a bitwise "AND" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
bool
Returns a boolean TRUE if the input value of type unsigned integer is
non-null, otherwise returns FALSE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
presence of a flag).
cpl
Takes the input value of type unsigned integer, applies a twos-complement
(flips all bits) and returns the result as an unsigned integer.
div(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
result as an unsigned integer. If <value> is null, the largest unsigned
integer is returned (typically 2^32-1).
even
Returns a boolean TRUE if the input value of type unsigned integer is even
otherwise returns FALSE. It is functionally equivalent to "not,and(1),bool".
mod(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
remainder as an unsigned integer. If <value> is null, then zero is returned.
mul(<value>)
Multiplies the input value of type unsigned integer by <value>, and returns
the product as an unsigned integer. In case of overflow, the higher bits are
lost, leading to seemingly strange values.
neg
Takes the input value of type unsigned integer, computes the opposite value,
and returns the remainder as an unsigned integer. 0 is identity. This
operator is provided for reversed subtracts : in order to subtract the input
from a constant, simply perform a "neg,add(value)".
not
Returns a boolean FALSE if the input value of type unsigned integer is
non-null, otherwise returns TRUE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
absence of a flag).
odd
Returns a boolean TRUE if the input value of type unsigned integer is odd
otherwise returns FALSE. It is functionally equivalent to "and(1),bool".
or(<value>)
Performs a bitwise "OR" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
sub(<value>)
Subtracts <value> from the input value of type unsigned integer, and returns
the result as an unsigned integer. Note: in order to subtract the input from
a constant, simply perform a "neg,add(value)".
xor(<value>)
Performs a bitwise "XOR" (exclusive OR) between <value> and the input value
of type unsigned integer, and returns the result as an unsigned integer.
2015-01-27 09:12:13 -05:00
|
|
|
{
|
2015-08-19 03:07:19 -04:00
|
|
|
smp->data.u.sint = !!smp->data.u.sint;
|
2015-08-19 03:00:18 -04:00
|
|
|
smp->data.type = SMP_T_BOOL;
|
MEDIUM: samples: provide basic arithmetic and bitwise operators
This commit introduces a new category of converters. They are bitwise and
arithmetic operators which support performing basic operations on integers.
Some bitwise operations are supported (and, or, xor, cpl) and some arithmetic
operations are supported (add, sub, mul, div, mod, neg). Some comparators
are provided (odd, even, not, bool) which make it possible to report a match
without having to write an ACL.
The detailed list of new operators as they appear in the doc is :
add(<value>)
Adds <value> to the input value of type unsigned integer, and returns the
result as an unsigned integer.
and(<value>)
Performs a bitwise "AND" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
bool
Returns a boolean TRUE if the input value of type unsigned integer is
non-null, otherwise returns FALSE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
presence of a flag).
cpl
Takes the input value of type unsigned integer, applies a twos-complement
(flips all bits) and returns the result as an unsigned integer.
div(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
result as an unsigned integer. If <value> is null, the largest unsigned
integer is returned (typically 2^32-1).
even
Returns a boolean TRUE if the input value of type unsigned integer is even
otherwise returns FALSE. It is functionally equivalent to "not,and(1),bool".
mod(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
remainder as an unsigned integer. If <value> is null, then zero is returned.
mul(<value>)
Multiplies the input value of type unsigned integer by <value>, and returns
the product as an unsigned integer. In case of overflow, the higher bits are
lost, leading to seemingly strange values.
neg
Takes the input value of type unsigned integer, computes the opposite value,
and returns the remainder as an unsigned integer. 0 is identity. This
operator is provided for reversed subtracts : in order to subtract the input
from a constant, simply perform a "neg,add(value)".
not
Returns a boolean FALSE if the input value of type unsigned integer is
non-null, otherwise returns TRUE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
absence of a flag).
odd
Returns a boolean TRUE if the input value of type unsigned integer is odd
otherwise returns FALSE. It is functionally equivalent to "and(1),bool".
or(<value>)
Performs a bitwise "OR" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
sub(<value>)
Subtracts <value> from the input value of type unsigned integer, and returns
the result as an unsigned integer. Note: in order to subtract the input from
a constant, simply perform a "neg,add(value)".
xor(<value>)
Performs a bitwise "XOR" (exclusive OR) between <value> and the input value
of type unsigned integer, and returns the result as an unsigned integer.
2015-01-27 09:12:13 -05:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-06 17:43:03 -04:00
|
|
|
/* Takes a SINT on input, returns false is the value is non-null, otherwise
|
MEDIUM: samples: provide basic arithmetic and bitwise operators
This commit introduces a new category of converters. They are bitwise and
arithmetic operators which support performing basic operations on integers.
Some bitwise operations are supported (and, or, xor, cpl) and some arithmetic
operations are supported (add, sub, mul, div, mod, neg). Some comparators
are provided (odd, even, not, bool) which make it possible to report a match
without having to write an ACL.
The detailed list of new operators as they appear in the doc is :
add(<value>)
Adds <value> to the input value of type unsigned integer, and returns the
result as an unsigned integer.
and(<value>)
Performs a bitwise "AND" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
bool
Returns a boolean TRUE if the input value of type unsigned integer is
non-null, otherwise returns FALSE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
presence of a flag).
cpl
Takes the input value of type unsigned integer, applies a twos-complement
(flips all bits) and returns the result as an unsigned integer.
div(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
result as an unsigned integer. If <value> is null, the largest unsigned
integer is returned (typically 2^32-1).
even
Returns a boolean TRUE if the input value of type unsigned integer is even
otherwise returns FALSE. It is functionally equivalent to "not,and(1),bool".
mod(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
remainder as an unsigned integer. If <value> is null, then zero is returned.
mul(<value>)
Multiplies the input value of type unsigned integer by <value>, and returns
the product as an unsigned integer. In case of overflow, the higher bits are
lost, leading to seemingly strange values.
neg
Takes the input value of type unsigned integer, computes the opposite value,
and returns the remainder as an unsigned integer. 0 is identity. This
operator is provided for reversed subtracts : in order to subtract the input
from a constant, simply perform a "neg,add(value)".
not
Returns a boolean FALSE if the input value of type unsigned integer is
non-null, otherwise returns TRUE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
absence of a flag).
odd
Returns a boolean TRUE if the input value of type unsigned integer is odd
otherwise returns FALSE. It is functionally equivalent to "and(1),bool".
or(<value>)
Performs a bitwise "OR" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
sub(<value>)
Subtracts <value> from the input value of type unsigned integer, and returns
the result as an unsigned integer. Note: in order to subtract the input from
a constant, simply perform a "neg,add(value)".
xor(<value>)
Performs a bitwise "XOR" (exclusive OR) between <value> and the input value
of type unsigned integer, and returns the result as an unsigned integer.
2015-01-27 09:12:13 -05:00
|
|
|
* truee. The output is a BOOL.
|
|
|
|
|
*/
|
2015-05-11 09:20:49 -04:00
|
|
|
static int sample_conv_arith_not(const struct arg *arg_p,
|
2015-02-23 09:11:11 -05:00
|
|
|
struct sample *smp, void *private)
|
MEDIUM: samples: provide basic arithmetic and bitwise operators
This commit introduces a new category of converters. They are bitwise and
arithmetic operators which support performing basic operations on integers.
Some bitwise operations are supported (and, or, xor, cpl) and some arithmetic
operations are supported (add, sub, mul, div, mod, neg). Some comparators
are provided (odd, even, not, bool) which make it possible to report a match
without having to write an ACL.
The detailed list of new operators as they appear in the doc is :
add(<value>)
Adds <value> to the input value of type unsigned integer, and returns the
result as an unsigned integer.
and(<value>)
Performs a bitwise "AND" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
bool
Returns a boolean TRUE if the input value of type unsigned integer is
non-null, otherwise returns FALSE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
presence of a flag).
cpl
Takes the input value of type unsigned integer, applies a twos-complement
(flips all bits) and returns the result as an unsigned integer.
div(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
result as an unsigned integer. If <value> is null, the largest unsigned
integer is returned (typically 2^32-1).
even
Returns a boolean TRUE if the input value of type unsigned integer is even
otherwise returns FALSE. It is functionally equivalent to "not,and(1),bool".
mod(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
remainder as an unsigned integer. If <value> is null, then zero is returned.
mul(<value>)
Multiplies the input value of type unsigned integer by <value>, and returns
the product as an unsigned integer. In case of overflow, the higher bits are
lost, leading to seemingly strange values.
neg
Takes the input value of type unsigned integer, computes the opposite value,
and returns the remainder as an unsigned integer. 0 is identity. This
operator is provided for reversed subtracts : in order to subtract the input
from a constant, simply perform a "neg,add(value)".
not
Returns a boolean FALSE if the input value of type unsigned integer is
non-null, otherwise returns TRUE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
absence of a flag).
odd
Returns a boolean TRUE if the input value of type unsigned integer is odd
otherwise returns FALSE. It is functionally equivalent to "and(1),bool".
or(<value>)
Performs a bitwise "OR" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
sub(<value>)
Subtracts <value> from the input value of type unsigned integer, and returns
the result as an unsigned integer. Note: in order to subtract the input from
a constant, simply perform a "neg,add(value)".
xor(<value>)
Performs a bitwise "XOR" (exclusive OR) between <value> and the input value
of type unsigned integer, and returns the result as an unsigned integer.
2015-01-27 09:12:13 -05:00
|
|
|
{
|
2015-08-19 03:07:19 -04:00
|
|
|
smp->data.u.sint = !smp->data.u.sint;
|
2015-08-19 03:00:18 -04:00
|
|
|
smp->data.type = SMP_T_BOOL;
|
MEDIUM: samples: provide basic arithmetic and bitwise operators
This commit introduces a new category of converters. They are bitwise and
arithmetic operators which support performing basic operations on integers.
Some bitwise operations are supported (and, or, xor, cpl) and some arithmetic
operations are supported (add, sub, mul, div, mod, neg). Some comparators
are provided (odd, even, not, bool) which make it possible to report a match
without having to write an ACL.
The detailed list of new operators as they appear in the doc is :
add(<value>)
Adds <value> to the input value of type unsigned integer, and returns the
result as an unsigned integer.
and(<value>)
Performs a bitwise "AND" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
bool
Returns a boolean TRUE if the input value of type unsigned integer is
non-null, otherwise returns FALSE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
presence of a flag).
cpl
Takes the input value of type unsigned integer, applies a twos-complement
(flips all bits) and returns the result as an unsigned integer.
div(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
result as an unsigned integer. If <value> is null, the largest unsigned
integer is returned (typically 2^32-1).
even
Returns a boolean TRUE if the input value of type unsigned integer is even
otherwise returns FALSE. It is functionally equivalent to "not,and(1),bool".
mod(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
remainder as an unsigned integer. If <value> is null, then zero is returned.
mul(<value>)
Multiplies the input value of type unsigned integer by <value>, and returns
the product as an unsigned integer. In case of overflow, the higher bits are
lost, leading to seemingly strange values.
neg
Takes the input value of type unsigned integer, computes the opposite value,
and returns the remainder as an unsigned integer. 0 is identity. This
operator is provided for reversed subtracts : in order to subtract the input
from a constant, simply perform a "neg,add(value)".
not
Returns a boolean FALSE if the input value of type unsigned integer is
non-null, otherwise returns TRUE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
absence of a flag).
odd
Returns a boolean TRUE if the input value of type unsigned integer is odd
otherwise returns FALSE. It is functionally equivalent to "and(1),bool".
or(<value>)
Performs a bitwise "OR" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
sub(<value>)
Subtracts <value> from the input value of type unsigned integer, and returns
the result as an unsigned integer. Note: in order to subtract the input from
a constant, simply perform a "neg,add(value)".
xor(<value>)
Performs a bitwise "XOR" (exclusive OR) between <value> and the input value
of type unsigned integer, and returns the result as an unsigned integer.
2015-01-27 09:12:13 -05:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-06 17:43:03 -04:00
|
|
|
/* Takes a SINT on input, returns true is the value is odd, otherwise false.
|
MEDIUM: samples: provide basic arithmetic and bitwise operators
This commit introduces a new category of converters. They are bitwise and
arithmetic operators which support performing basic operations on integers.
Some bitwise operations are supported (and, or, xor, cpl) and some arithmetic
operations are supported (add, sub, mul, div, mod, neg). Some comparators
are provided (odd, even, not, bool) which make it possible to report a match
without having to write an ACL.
The detailed list of new operators as they appear in the doc is :
add(<value>)
Adds <value> to the input value of type unsigned integer, and returns the
result as an unsigned integer.
and(<value>)
Performs a bitwise "AND" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
bool
Returns a boolean TRUE if the input value of type unsigned integer is
non-null, otherwise returns FALSE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
presence of a flag).
cpl
Takes the input value of type unsigned integer, applies a twos-complement
(flips all bits) and returns the result as an unsigned integer.
div(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
result as an unsigned integer. If <value> is null, the largest unsigned
integer is returned (typically 2^32-1).
even
Returns a boolean TRUE if the input value of type unsigned integer is even
otherwise returns FALSE. It is functionally equivalent to "not,and(1),bool".
mod(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
remainder as an unsigned integer. If <value> is null, then zero is returned.
mul(<value>)
Multiplies the input value of type unsigned integer by <value>, and returns
the product as an unsigned integer. In case of overflow, the higher bits are
lost, leading to seemingly strange values.
neg
Takes the input value of type unsigned integer, computes the opposite value,
and returns the remainder as an unsigned integer. 0 is identity. This
operator is provided for reversed subtracts : in order to subtract the input
from a constant, simply perform a "neg,add(value)".
not
Returns a boolean FALSE if the input value of type unsigned integer is
non-null, otherwise returns TRUE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
absence of a flag).
odd
Returns a boolean TRUE if the input value of type unsigned integer is odd
otherwise returns FALSE. It is functionally equivalent to "and(1),bool".
or(<value>)
Performs a bitwise "OR" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
sub(<value>)
Subtracts <value> from the input value of type unsigned integer, and returns
the result as an unsigned integer. Note: in order to subtract the input from
a constant, simply perform a "neg,add(value)".
xor(<value>)
Performs a bitwise "XOR" (exclusive OR) between <value> and the input value
of type unsigned integer, and returns the result as an unsigned integer.
2015-01-27 09:12:13 -05:00
|
|
|
* The output is a BOOL.
|
|
|
|
|
*/
|
2015-05-11 09:20:49 -04:00
|
|
|
static int sample_conv_arith_odd(const struct arg *arg_p,
|
2015-02-23 09:11:11 -05:00
|
|
|
struct sample *smp, void *private)
|
MEDIUM: samples: provide basic arithmetic and bitwise operators
This commit introduces a new category of converters. They are bitwise and
arithmetic operators which support performing basic operations on integers.
Some bitwise operations are supported (and, or, xor, cpl) and some arithmetic
operations are supported (add, sub, mul, div, mod, neg). Some comparators
are provided (odd, even, not, bool) which make it possible to report a match
without having to write an ACL.
The detailed list of new operators as they appear in the doc is :
add(<value>)
Adds <value> to the input value of type unsigned integer, and returns the
result as an unsigned integer.
and(<value>)
Performs a bitwise "AND" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
bool
Returns a boolean TRUE if the input value of type unsigned integer is
non-null, otherwise returns FALSE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
presence of a flag).
cpl
Takes the input value of type unsigned integer, applies a twos-complement
(flips all bits) and returns the result as an unsigned integer.
div(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
result as an unsigned integer. If <value> is null, the largest unsigned
integer is returned (typically 2^32-1).
even
Returns a boolean TRUE if the input value of type unsigned integer is even
otherwise returns FALSE. It is functionally equivalent to "not,and(1),bool".
mod(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
remainder as an unsigned integer. If <value> is null, then zero is returned.
mul(<value>)
Multiplies the input value of type unsigned integer by <value>, and returns
the product as an unsigned integer. In case of overflow, the higher bits are
lost, leading to seemingly strange values.
neg
Takes the input value of type unsigned integer, computes the opposite value,
and returns the remainder as an unsigned integer. 0 is identity. This
operator is provided for reversed subtracts : in order to subtract the input
from a constant, simply perform a "neg,add(value)".
not
Returns a boolean FALSE if the input value of type unsigned integer is
non-null, otherwise returns TRUE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
absence of a flag).
odd
Returns a boolean TRUE if the input value of type unsigned integer is odd
otherwise returns FALSE. It is functionally equivalent to "and(1),bool".
or(<value>)
Performs a bitwise "OR" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
sub(<value>)
Subtracts <value> from the input value of type unsigned integer, and returns
the result as an unsigned integer. Note: in order to subtract the input from
a constant, simply perform a "neg,add(value)".
xor(<value>)
Performs a bitwise "XOR" (exclusive OR) between <value> and the input value
of type unsigned integer, and returns the result as an unsigned integer.
2015-01-27 09:12:13 -05:00
|
|
|
{
|
2015-08-19 03:07:19 -04:00
|
|
|
smp->data.u.sint = smp->data.u.sint & 1;
|
2015-08-19 03:00:18 -04:00
|
|
|
smp->data.type = SMP_T_BOOL;
|
MEDIUM: samples: provide basic arithmetic and bitwise operators
This commit introduces a new category of converters. They are bitwise and
arithmetic operators which support performing basic operations on integers.
Some bitwise operations are supported (and, or, xor, cpl) and some arithmetic
operations are supported (add, sub, mul, div, mod, neg). Some comparators
are provided (odd, even, not, bool) which make it possible to report a match
without having to write an ACL.
The detailed list of new operators as they appear in the doc is :
add(<value>)
Adds <value> to the input value of type unsigned integer, and returns the
result as an unsigned integer.
and(<value>)
Performs a bitwise "AND" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
bool
Returns a boolean TRUE if the input value of type unsigned integer is
non-null, otherwise returns FALSE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
presence of a flag).
cpl
Takes the input value of type unsigned integer, applies a twos-complement
(flips all bits) and returns the result as an unsigned integer.
div(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
result as an unsigned integer. If <value> is null, the largest unsigned
integer is returned (typically 2^32-1).
even
Returns a boolean TRUE if the input value of type unsigned integer is even
otherwise returns FALSE. It is functionally equivalent to "not,and(1),bool".
mod(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
remainder as an unsigned integer. If <value> is null, then zero is returned.
mul(<value>)
Multiplies the input value of type unsigned integer by <value>, and returns
the product as an unsigned integer. In case of overflow, the higher bits are
lost, leading to seemingly strange values.
neg
Takes the input value of type unsigned integer, computes the opposite value,
and returns the remainder as an unsigned integer. 0 is identity. This
operator is provided for reversed subtracts : in order to subtract the input
from a constant, simply perform a "neg,add(value)".
not
Returns a boolean FALSE if the input value of type unsigned integer is
non-null, otherwise returns TRUE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
absence of a flag).
odd
Returns a boolean TRUE if the input value of type unsigned integer is odd
otherwise returns FALSE. It is functionally equivalent to "and(1),bool".
or(<value>)
Performs a bitwise "OR" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
sub(<value>)
Subtracts <value> from the input value of type unsigned integer, and returns
the result as an unsigned integer. Note: in order to subtract the input from
a constant, simply perform a "neg,add(value)".
xor(<value>)
Performs a bitwise "XOR" (exclusive OR) between <value> and the input value
of type unsigned integer, and returns the result as an unsigned integer.
2015-01-27 09:12:13 -05:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-06 17:43:03 -04:00
|
|
|
/* Takes a SINT on input, returns true is the value is even, otherwise false.
|
MEDIUM: samples: provide basic arithmetic and bitwise operators
This commit introduces a new category of converters. They are bitwise and
arithmetic operators which support performing basic operations on integers.
Some bitwise operations are supported (and, or, xor, cpl) and some arithmetic
operations are supported (add, sub, mul, div, mod, neg). Some comparators
are provided (odd, even, not, bool) which make it possible to report a match
without having to write an ACL.
The detailed list of new operators as they appear in the doc is :
add(<value>)
Adds <value> to the input value of type unsigned integer, and returns the
result as an unsigned integer.
and(<value>)
Performs a bitwise "AND" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
bool
Returns a boolean TRUE if the input value of type unsigned integer is
non-null, otherwise returns FALSE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
presence of a flag).
cpl
Takes the input value of type unsigned integer, applies a twos-complement
(flips all bits) and returns the result as an unsigned integer.
div(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
result as an unsigned integer. If <value> is null, the largest unsigned
integer is returned (typically 2^32-1).
even
Returns a boolean TRUE if the input value of type unsigned integer is even
otherwise returns FALSE. It is functionally equivalent to "not,and(1),bool".
mod(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
remainder as an unsigned integer. If <value> is null, then zero is returned.
mul(<value>)
Multiplies the input value of type unsigned integer by <value>, and returns
the product as an unsigned integer. In case of overflow, the higher bits are
lost, leading to seemingly strange values.
neg
Takes the input value of type unsigned integer, computes the opposite value,
and returns the remainder as an unsigned integer. 0 is identity. This
operator is provided for reversed subtracts : in order to subtract the input
from a constant, simply perform a "neg,add(value)".
not
Returns a boolean FALSE if the input value of type unsigned integer is
non-null, otherwise returns TRUE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
absence of a flag).
odd
Returns a boolean TRUE if the input value of type unsigned integer is odd
otherwise returns FALSE. It is functionally equivalent to "and(1),bool".
or(<value>)
Performs a bitwise "OR" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
sub(<value>)
Subtracts <value> from the input value of type unsigned integer, and returns
the result as an unsigned integer. Note: in order to subtract the input from
a constant, simply perform a "neg,add(value)".
xor(<value>)
Performs a bitwise "XOR" (exclusive OR) between <value> and the input value
of type unsigned integer, and returns the result as an unsigned integer.
2015-01-27 09:12:13 -05:00
|
|
|
* The output is a BOOL.
|
|
|
|
|
*/
|
2015-05-11 09:20:49 -04:00
|
|
|
static int sample_conv_arith_even(const struct arg *arg_p,
|
2015-02-23 09:11:11 -05:00
|
|
|
struct sample *smp, void *private)
|
MEDIUM: samples: provide basic arithmetic and bitwise operators
This commit introduces a new category of converters. They are bitwise and
arithmetic operators which support performing basic operations on integers.
Some bitwise operations are supported (and, or, xor, cpl) and some arithmetic
operations are supported (add, sub, mul, div, mod, neg). Some comparators
are provided (odd, even, not, bool) which make it possible to report a match
without having to write an ACL.
The detailed list of new operators as they appear in the doc is :
add(<value>)
Adds <value> to the input value of type unsigned integer, and returns the
result as an unsigned integer.
and(<value>)
Performs a bitwise "AND" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
bool
Returns a boolean TRUE if the input value of type unsigned integer is
non-null, otherwise returns FALSE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
presence of a flag).
cpl
Takes the input value of type unsigned integer, applies a twos-complement
(flips all bits) and returns the result as an unsigned integer.
div(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
result as an unsigned integer. If <value> is null, the largest unsigned
integer is returned (typically 2^32-1).
even
Returns a boolean TRUE if the input value of type unsigned integer is even
otherwise returns FALSE. It is functionally equivalent to "not,and(1),bool".
mod(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
remainder as an unsigned integer. If <value> is null, then zero is returned.
mul(<value>)
Multiplies the input value of type unsigned integer by <value>, and returns
the product as an unsigned integer. In case of overflow, the higher bits are
lost, leading to seemingly strange values.
neg
Takes the input value of type unsigned integer, computes the opposite value,
and returns the remainder as an unsigned integer. 0 is identity. This
operator is provided for reversed subtracts : in order to subtract the input
from a constant, simply perform a "neg,add(value)".
not
Returns a boolean FALSE if the input value of type unsigned integer is
non-null, otherwise returns TRUE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
absence of a flag).
odd
Returns a boolean TRUE if the input value of type unsigned integer is odd
otherwise returns FALSE. It is functionally equivalent to "and(1),bool".
or(<value>)
Performs a bitwise "OR" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
sub(<value>)
Subtracts <value> from the input value of type unsigned integer, and returns
the result as an unsigned integer. Note: in order to subtract the input from
a constant, simply perform a "neg,add(value)".
xor(<value>)
Performs a bitwise "XOR" (exclusive OR) between <value> and the input value
of type unsigned integer, and returns the result as an unsigned integer.
2015-01-27 09:12:13 -05:00
|
|
|
{
|
2015-08-19 03:07:19 -04:00
|
|
|
smp->data.u.sint = !(smp->data.u.sint & 1);
|
2015-08-19 03:00:18 -04:00
|
|
|
smp->data.type = SMP_T_BOOL;
|
MEDIUM: samples: provide basic arithmetic and bitwise operators
This commit introduces a new category of converters. They are bitwise and
arithmetic operators which support performing basic operations on integers.
Some bitwise operations are supported (and, or, xor, cpl) and some arithmetic
operations are supported (add, sub, mul, div, mod, neg). Some comparators
are provided (odd, even, not, bool) which make it possible to report a match
without having to write an ACL.
The detailed list of new operators as they appear in the doc is :
add(<value>)
Adds <value> to the input value of type unsigned integer, and returns the
result as an unsigned integer.
and(<value>)
Performs a bitwise "AND" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
bool
Returns a boolean TRUE if the input value of type unsigned integer is
non-null, otherwise returns FALSE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
presence of a flag).
cpl
Takes the input value of type unsigned integer, applies a twos-complement
(flips all bits) and returns the result as an unsigned integer.
div(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
result as an unsigned integer. If <value> is null, the largest unsigned
integer is returned (typically 2^32-1).
even
Returns a boolean TRUE if the input value of type unsigned integer is even
otherwise returns FALSE. It is functionally equivalent to "not,and(1),bool".
mod(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
remainder as an unsigned integer. If <value> is null, then zero is returned.
mul(<value>)
Multiplies the input value of type unsigned integer by <value>, and returns
the product as an unsigned integer. In case of overflow, the higher bits are
lost, leading to seemingly strange values.
neg
Takes the input value of type unsigned integer, computes the opposite value,
and returns the remainder as an unsigned integer. 0 is identity. This
operator is provided for reversed subtracts : in order to subtract the input
from a constant, simply perform a "neg,add(value)".
not
Returns a boolean FALSE if the input value of type unsigned integer is
non-null, otherwise returns TRUE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
absence of a flag).
odd
Returns a boolean TRUE if the input value of type unsigned integer is odd
otherwise returns FALSE. It is functionally equivalent to "and(1),bool".
or(<value>)
Performs a bitwise "OR" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
sub(<value>)
Subtracts <value> from the input value of type unsigned integer, and returns
the result as an unsigned integer. Note: in order to subtract the input from
a constant, simply perform a "neg,add(value)".
xor(<value>)
Performs a bitwise "XOR" (exclusive OR) between <value> and the input value
of type unsigned integer, and returns the result as an unsigned integer.
2015-01-27 09:12:13 -05:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-19 09:34:12 -05:00
|
|
|
/* appends an optional const string, an optional variable contents and another
|
|
|
|
|
* optional const string to an existing string.
|
|
|
|
|
*/
|
|
|
|
|
static int sample_conv_concat(const struct arg *arg_p, struct sample *smp, void *private)
|
|
|
|
|
{
|
2018-07-13 05:56:34 -04:00
|
|
|
struct buffer *trash;
|
2018-02-19 09:34:12 -05:00
|
|
|
struct sample tmp;
|
|
|
|
|
int max;
|
|
|
|
|
|
|
|
|
|
trash = get_trash_chunk();
|
2018-07-13 04:54:26 -04:00
|
|
|
trash->data = smp->data.u.str.data;
|
|
|
|
|
if (trash->data > trash->size - 1)
|
|
|
|
|
trash->data = trash->size - 1;
|
2018-02-19 09:34:12 -05:00
|
|
|
|
2018-07-13 04:54:26 -04:00
|
|
|
memcpy(trash->area, smp->data.u.str.area, trash->data);
|
|
|
|
|
trash->area[trash->data] = 0;
|
2018-02-19 09:34:12 -05:00
|
|
|
|
|
|
|
|
/* append first string */
|
2018-07-13 04:54:26 -04:00
|
|
|
max = arg_p[0].data.str.data;
|
|
|
|
|
if (max > trash->size - 1 - trash->data)
|
|
|
|
|
max = trash->size - 1 - trash->data;
|
2018-02-19 09:34:12 -05:00
|
|
|
|
|
|
|
|
if (max) {
|
2018-07-13 04:54:26 -04:00
|
|
|
memcpy(trash->area + trash->data, arg_p[0].data.str.area, max);
|
|
|
|
|
trash->data += max;
|
|
|
|
|
trash->area[trash->data] = 0;
|
2018-02-19 09:34:12 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* append second string (variable) if it's found and we can turn it
|
|
|
|
|
* into a string.
|
|
|
|
|
*/
|
|
|
|
|
smp_set_owner(&tmp, smp->px, smp->sess, smp->strm, smp->opt);
|
|
|
|
|
if (arg_p[1].type == ARGT_VAR && vars_get_by_desc(&arg_p[1].data.var, &tmp) &&
|
|
|
|
|
(sample_casts[tmp.data.type][SMP_T_STR] == c_none ||
|
|
|
|
|
sample_casts[tmp.data.type][SMP_T_STR](&tmp))) {
|
|
|
|
|
|
2018-07-13 04:54:26 -04:00
|
|
|
max = tmp.data.u.str.data;
|
|
|
|
|
if (max > trash->size - 1 - trash->data)
|
|
|
|
|
max = trash->size - 1 - trash->data;
|
2018-02-19 09:34:12 -05:00
|
|
|
|
|
|
|
|
if (max) {
|
2018-07-13 04:54:26 -04:00
|
|
|
memcpy(trash->area + trash->data, tmp.data.u.str.area,
|
|
|
|
|
max);
|
|
|
|
|
trash->data += max;
|
|
|
|
|
trash->area[trash->data] = 0;
|
2018-02-19 09:34:12 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* append third string */
|
2018-07-13 04:54:26 -04:00
|
|
|
max = arg_p[2].data.str.data;
|
|
|
|
|
if (max > trash->size - 1 - trash->data)
|
|
|
|
|
max = trash->size - 1 - trash->data;
|
2018-02-19 09:34:12 -05:00
|
|
|
|
|
|
|
|
if (max) {
|
2018-07-13 04:54:26 -04:00
|
|
|
memcpy(trash->area + trash->data, arg_p[2].data.str.area, max);
|
|
|
|
|
trash->data += max;
|
|
|
|
|
trash->area[trash->data] = 0;
|
2018-02-19 09:34:12 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
smp->data.u.str = *trash;
|
|
|
|
|
smp->data.type = SMP_T_STR;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* This function checks the "concat" converter's arguments and extracts the
|
|
|
|
|
* variable name and its scope.
|
|
|
|
|
*/
|
|
|
|
|
static int smp_check_concat(struct arg *args, struct sample_conv *conv,
|
|
|
|
|
const char *file, int line, char **err)
|
|
|
|
|
{
|
|
|
|
|
/* Try to decode a variable. */
|
2018-07-13 04:54:26 -04:00
|
|
|
if (args[1].data.str.data > 0 && !vars_check_arg(&args[1], NULL)) {
|
|
|
|
|
memprintf(err, "failed to register variable name '%s'",
|
|
|
|
|
args[1].data.str.area);
|
2018-02-19 09:34:12 -05:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-27 15:18:45 -04:00
|
|
|
/* compares string with a variable containing a string. Return value
|
|
|
|
|
* is compatible with strcmp(3)'s return value.
|
|
|
|
|
*/
|
|
|
|
|
static int sample_conv_strcmp(const struct arg *arg_p, struct sample *smp, void *private)
|
|
|
|
|
{
|
|
|
|
|
struct sample tmp;
|
|
|
|
|
int max, result;
|
|
|
|
|
|
|
|
|
|
smp_set_owner(&tmp, smp->px, smp->sess, smp->strm, smp->opt);
|
|
|
|
|
if (arg_p[0].type != ARGT_VAR)
|
|
|
|
|
return 0;
|
|
|
|
|
if (!vars_get_by_desc(&arg_p[0].data.var, &tmp))
|
|
|
|
|
return 0;
|
|
|
|
|
if (!sample_casts[tmp.data.type][SMP_T_STR](&tmp))
|
|
|
|
|
return 0;
|
|
|
|
|
|
2018-07-13 04:54:26 -04:00
|
|
|
max = MIN(smp->data.u.str.data, tmp.data.u.str.data);
|
|
|
|
|
result = strncmp(smp->data.u.str.area, tmp.data.u.str.area, max);
|
2018-04-27 15:18:45 -04:00
|
|
|
if (result == 0) {
|
2018-07-13 04:54:26 -04:00
|
|
|
if (smp->data.u.str.data != tmp.data.u.str.data) {
|
|
|
|
|
if (smp->data.u.str.data < tmp.data.u.str.data) {
|
2018-04-27 15:18:45 -04:00
|
|
|
result = -1;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
result = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
smp->data.u.sint = result;
|
|
|
|
|
smp->data.type = SMP_T_SINT;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-27 08:34:51 -05:00
|
|
|
#define GRPC_MSG_COMPRESS_FLAG_SZ 1 /* 1 byte */
|
|
|
|
|
#define GRPC_MSG_LENGTH_SZ 4 /* 4 bytes */
|
|
|
|
|
#define GRPC_MSG_HEADER_SZ (GRPC_MSG_COMPRESS_FLAG_SZ + GRPC_MSG_LENGTH_SZ)
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Extract the field value of an input binary sample. Takes a mandatory argument:
|
|
|
|
|
* the protocol buffers field identifier (dotted notation) internally represented
|
|
|
|
|
* as an array of unsigned integers and its size.
|
|
|
|
|
* Return 1 if the field was found, 0 if not.
|
|
|
|
|
*/
|
|
|
|
|
static int sample_conv_ungrpc(const struct arg *arg_p, struct sample *smp, void *private)
|
|
|
|
|
{
|
|
|
|
|
unsigned char *pos;
|
|
|
|
|
size_t grpc_left;
|
|
|
|
|
|
|
|
|
|
pos = (unsigned char *)smp->data.u.str.area;
|
|
|
|
|
grpc_left = smp->data.u.str.data;
|
|
|
|
|
|
2019-03-04 01:33:41 -05:00
|
|
|
while (grpc_left > GRPC_MSG_HEADER_SZ) {
|
2019-02-27 08:34:51 -05:00
|
|
|
size_t grpc_msg_len, left;
|
|
|
|
|
|
|
|
|
|
grpc_msg_len = left = ntohl(*(uint32_t *)(pos + GRPC_MSG_COMPRESS_FLAG_SZ));
|
|
|
|
|
|
|
|
|
|
pos += GRPC_MSG_HEADER_SZ;
|
|
|
|
|
grpc_left -= GRPC_MSG_HEADER_SZ;
|
|
|
|
|
|
|
|
|
|
if (grpc_left < left)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2019-03-06 02:03:44 -05:00
|
|
|
if (protobuf_field_lookup(arg_p, smp, &pos, &left))
|
|
|
|
|
return 1;
|
2019-02-27 08:34:51 -05:00
|
|
|
|
|
|
|
|
grpc_left -= grpc_msg_len;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-06 08:34:36 -05:00
|
|
|
static int sample_conv_protobuf(const struct arg *arg_p, struct sample *smp, void *private)
|
|
|
|
|
{
|
|
|
|
|
unsigned char *pos;
|
|
|
|
|
size_t left;
|
|
|
|
|
|
|
|
|
|
pos = (unsigned char *)smp->data.u.str.area;
|
|
|
|
|
left = smp->data.u.str.data;
|
|
|
|
|
|
|
|
|
|
return protobuf_field_lookup(arg_p, smp, &pos, &left);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int sample_conv_protobuf_check(struct arg *args, struct sample_conv *conv,
|
|
|
|
|
const char *file, int line, char **err)
|
2019-03-04 13:03:48 -05:00
|
|
|
{
|
|
|
|
|
if (!args[1].type) {
|
|
|
|
|
args[1].type = ARGT_SINT;
|
|
|
|
|
args[1].data.sint = PBUF_T_BINARY;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
int pbuf_type;
|
|
|
|
|
|
|
|
|
|
pbuf_type = protobuf_type(args[1].data.str.area);
|
|
|
|
|
if (pbuf_type == -1) {
|
|
|
|
|
memprintf(err, "Wrong protocol buffer type '%s'", args[1].data.str.area);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
args[1].type = ARGT_SINT;
|
|
|
|
|
args[1].data.sint = pbuf_type;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-27 15:18:45 -04:00
|
|
|
/* This function checks the "strcmp" converter's arguments and extracts the
|
|
|
|
|
* variable name and its scope.
|
|
|
|
|
*/
|
|
|
|
|
static int smp_check_strcmp(struct arg *args, struct sample_conv *conv,
|
|
|
|
|
const char *file, int line, char **err)
|
|
|
|
|
{
|
|
|
|
|
/* Try to decode a variable. */
|
|
|
|
|
if (vars_check_arg(&args[0], NULL))
|
|
|
|
|
return 1;
|
|
|
|
|
|
2018-07-13 04:54:26 -04:00
|
|
|
memprintf(err, "failed to register variable name '%s'",
|
|
|
|
|
args[0].data.str.area);
|
2018-04-27 15:18:45 -04:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-01 03:08:32 -04:00
|
|
|
/**/
|
|
|
|
|
static int sample_conv_htonl(const struct arg *arg_p, struct sample *smp, void *private)
|
|
|
|
|
{
|
|
|
|
|
struct buffer *tmp;
|
|
|
|
|
uint32_t n;
|
|
|
|
|
|
|
|
|
|
n = htonl((uint32_t)smp->data.u.sint);
|
|
|
|
|
tmp = get_trash_chunk();
|
|
|
|
|
|
|
|
|
|
memcpy(b_head(tmp), &n, 4);
|
|
|
|
|
b_add(tmp, 4);
|
|
|
|
|
|
|
|
|
|
smp->data.u.str = *tmp;
|
|
|
|
|
smp->data.type = SMP_T_BIN;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-01 10:21:44 -04:00
|
|
|
/**/
|
|
|
|
|
static int sample_conv_cut_crlf(const struct arg *arg_p, struct sample *smp, void *private)
|
|
|
|
|
{
|
|
|
|
|
char *p;
|
|
|
|
|
size_t l;
|
|
|
|
|
|
|
|
|
|
p = smp->data.u.str.area;
|
|
|
|
|
for (l = 0; l < smp->data.u.str.data; l++) {
|
|
|
|
|
if (*(p+l) == '\r' || *(p+l) == '\n')
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
smp->data.u.str.data = l;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2013-07-25 06:17:57 -04:00
|
|
|
/************************************************************************/
|
|
|
|
|
/* All supported sample fetch functions must be declared here */
|
|
|
|
|
/************************************************************************/
|
|
|
|
|
|
|
|
|
|
/* force TRUE to be returned at the fetch level */
|
|
|
|
|
static int
|
2015-05-11 09:42:45 -04:00
|
|
|
smp_fetch_true(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
2013-07-25 06:17:57 -04:00
|
|
|
{
|
2018-02-19 09:34:12 -05:00
|
|
|
if (!smp_make_rw(smp))
|
|
|
|
|
return 0;
|
|
|
|
|
|
2015-08-19 03:00:18 -04:00
|
|
|
smp->data.type = SMP_T_BOOL;
|
2015-08-19 03:07:19 -04:00
|
|
|
smp->data.u.sint = 1;
|
2013-07-25 06:17:57 -04:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* force FALSE to be returned at the fetch level */
|
|
|
|
|
static int
|
2015-05-11 09:42:45 -04:00
|
|
|
smp_fetch_false(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
2013-07-25 06:17:57 -04:00
|
|
|
{
|
2015-08-19 03:00:18 -04:00
|
|
|
smp->data.type = SMP_T_BOOL;
|
2015-08-19 03:07:19 -04:00
|
|
|
smp->data.u.sint = 0;
|
2013-07-25 06:17:57 -04:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* retrieve environment variable $1 as a string */
|
|
|
|
|
static int
|
2015-05-11 09:42:45 -04:00
|
|
|
smp_fetch_env(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
2013-07-25 06:17:57 -04:00
|
|
|
{
|
|
|
|
|
char *env;
|
|
|
|
|
|
|
|
|
|
if (!args || args[0].type != ARGT_STR)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2018-07-13 04:54:26 -04:00
|
|
|
env = getenv(args[0].data.str.area);
|
2013-07-25 06:17:57 -04:00
|
|
|
if (!env)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2015-08-19 03:00:18 -04:00
|
|
|
smp->data.type = SMP_T_STR;
|
2013-12-16 18:20:33 -05:00
|
|
|
smp->flags = SMP_F_CONST;
|
2018-07-13 04:54:26 -04:00
|
|
|
smp->data.u.str.area = env;
|
|
|
|
|
smp->data.u.str.data = strlen(env);
|
2013-07-25 06:17:57 -04:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-30 11:57:28 -04:00
|
|
|
/* Validates the data unit argument passed to "date" fetch. Argument 1 support an
|
|
|
|
|
* optional string representing the unit of the result: "s" for seconds, "ms" for
|
|
|
|
|
* milliseconds and "us" for microseconds.
|
|
|
|
|
* Returns 0 on error and non-zero if OK.
|
|
|
|
|
*/
|
|
|
|
|
int smp_check_date_unit(struct arg *args, char **err)
|
|
|
|
|
{
|
|
|
|
|
if (args[1].type == ARGT_STR) {
|
|
|
|
|
if (strcmp(args[1].data.str.area, "s") == 0) {
|
|
|
|
|
args[1].data.sint = TIME_UNIT_S;
|
|
|
|
|
}
|
|
|
|
|
else if (strcmp(args[1].data.str.area, "ms") == 0) {
|
|
|
|
|
args[1].data.sint = TIME_UNIT_MS;
|
|
|
|
|
}
|
|
|
|
|
else if (strcmp(args[1].data.str.area, "us") == 0) {
|
|
|
|
|
args[1].data.sint = TIME_UNIT_US;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
memprintf(err, "expects 's', 'ms' or 'us', got '%s'",
|
|
|
|
|
args[1].data.str.area);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
free(args[1].data.str.area);
|
|
|
|
|
args[1].data.str.area = NULL;
|
|
|
|
|
args[1].type = ARGT_SINT;
|
|
|
|
|
}
|
|
|
|
|
else if (args[1].type != ARGT_STOP) {
|
|
|
|
|
memprintf(err, "Unexpected arg type");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* retrieve the current local date in epoch time, converts it to milliseconds
|
|
|
|
|
* or microseconds if asked to in optional args[1] unit param, and applies an
|
|
|
|
|
* optional args[0] offset.
|
2013-07-25 08:28:25 -04:00
|
|
|
*/
|
|
|
|
|
static int
|
2015-05-11 09:42:45 -04:00
|
|
|
smp_fetch_date(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
2013-07-25 08:28:25 -04:00
|
|
|
{
|
2015-08-19 03:07:19 -04:00
|
|
|
smp->data.u.sint = date.tv_sec;
|
2013-07-25 08:28:25 -04:00
|
|
|
|
2019-10-30 11:57:28 -04:00
|
|
|
/* report in milliseconds */
|
|
|
|
|
if (args && args[1].type == ARGT_SINT && args[1].data.sint == TIME_UNIT_MS) {
|
|
|
|
|
smp->data.u.sint *= 1000;
|
|
|
|
|
smp->data.u.sint += date.tv_usec / 1000;
|
|
|
|
|
}
|
|
|
|
|
/* report in microseconds */
|
|
|
|
|
else if (args && args[1].type == ARGT_SINT && args[1].data.sint == TIME_UNIT_US) {
|
|
|
|
|
smp->data.u.sint *= 1000000;
|
|
|
|
|
smp->data.u.sint += date.tv_usec;
|
|
|
|
|
}
|
|
|
|
|
|
2013-07-25 08:28:25 -04:00
|
|
|
/* add offset */
|
2015-07-20 11:45:02 -04:00
|
|
|
if (args && args[0].type == ARGT_SINT)
|
2015-08-19 03:07:19 -04:00
|
|
|
smp->data.u.sint += args[0].data.sint;
|
2013-07-25 08:28:25 -04:00
|
|
|
|
2015-08-19 03:00:18 -04:00
|
|
|
smp->data.type = SMP_T_SINT;
|
2013-07-25 08:28:25 -04:00
|
|
|
smp->flags |= SMP_F_VOL_TEST | SMP_F_MAY_CHANGE;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-17 07:43:24 -05:00
|
|
|
/* retrieve the current microsecond part of the date */
|
|
|
|
|
static int
|
|
|
|
|
smp_fetch_date_us(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
|
|
|
|
{
|
|
|
|
|
smp->data.u.sint = date.tv_usec;
|
|
|
|
|
smp->data.type = SMP_T_SINT;
|
|
|
|
|
smp->flags |= SMP_F_VOL_TEST | SMP_F_MAY_CHANGE;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2017-03-12 17:00:00 -04:00
|
|
|
/* returns the hostname */
|
|
|
|
|
static int
|
|
|
|
|
smp_fetch_hostname(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
|
|
|
|
{
|
|
|
|
|
smp->data.type = SMP_T_STR;
|
|
|
|
|
smp->flags = SMP_F_CONST;
|
2018-07-13 04:54:26 -04:00
|
|
|
smp->data.u.str.area = hostname;
|
|
|
|
|
smp->data.u.str.data = strlen(hostname);
|
2017-03-12 17:00:00 -04:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2014-11-24 10:02:05 -05:00
|
|
|
/* returns the number of processes */
|
|
|
|
|
static int
|
2015-05-11 09:42:45 -04:00
|
|
|
smp_fetch_nbproc(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
2014-11-24 10:02:05 -05:00
|
|
|
{
|
2015-08-19 03:00:18 -04:00
|
|
|
smp->data.type = SMP_T_SINT;
|
2015-08-19 03:07:19 -04:00
|
|
|
smp->data.u.sint = global.nbproc;
|
2014-11-24 10:02:05 -05:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* returns the number of the current process (between 1 and nbproc */
|
|
|
|
|
static int
|
2015-05-11 09:42:45 -04:00
|
|
|
smp_fetch_proc(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
2014-11-24 10:02:05 -05:00
|
|
|
{
|
2015-08-19 03:00:18 -04:00
|
|
|
smp->data.type = SMP_T_SINT;
|
2015-08-19 03:07:19 -04:00
|
|
|
smp->data.u.sint = relative_pid;
|
2014-11-24 10:02:05 -05:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-21 15:45:38 -05:00
|
|
|
/* returns the number of the current thread (between 1 and nbthread */
|
|
|
|
|
static int
|
|
|
|
|
smp_fetch_thread(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
|
|
|
|
{
|
|
|
|
|
smp->data.type = SMP_T_SINT;
|
|
|
|
|
smp->data.u.sint = tid;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-14 05:59:04 -05:00
|
|
|
/* generate a random 32-bit integer for whatever purpose, with an optional
|
|
|
|
|
* range specified in argument.
|
|
|
|
|
*/
|
|
|
|
|
static int
|
2015-05-11 09:42:45 -04:00
|
|
|
smp_fetch_rand(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
2014-02-14 05:59:04 -05:00
|
|
|
{
|
2020-03-08 13:01:10 -04:00
|
|
|
smp->data.u.sint = ha_random32();
|
2014-02-14 05:59:04 -05:00
|
|
|
|
|
|
|
|
/* reduce if needed. Don't do a modulo, use all bits! */
|
2015-07-20 11:45:02 -04:00
|
|
|
if (args && args[0].type == ARGT_SINT)
|
2020-03-08 13:01:10 -04:00
|
|
|
smp->data.u.sint = ((u64)smp->data.u.sint * (u64)args[0].data.sint) >> 32;
|
2014-02-14 05:59:04 -05:00
|
|
|
|
2015-08-19 03:00:18 -04:00
|
|
|
smp->data.type = SMP_T_SINT;
|
2014-02-14 05:59:04 -05:00
|
|
|
smp->flags |= SMP_F_VOL_TEST | SMP_F_MAY_CHANGE;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2014-11-24 10:02:05 -05:00
|
|
|
/* returns true if the current process is stopping */
|
|
|
|
|
static int
|
2015-05-11 09:42:45 -04:00
|
|
|
smp_fetch_stopping(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
2014-11-24 10:02:05 -05:00
|
|
|
{
|
2015-08-19 03:00:18 -04:00
|
|
|
smp->data.type = SMP_T_BOOL;
|
2015-08-19 03:07:19 -04:00
|
|
|
smp->data.u.sint = stopping;
|
2014-11-24 10:02:05 -05:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-22 10:07:39 -05:00
|
|
|
/* returns the number of calls of the current stream's process_stream() */
|
|
|
|
|
static int
|
|
|
|
|
smp_fetch_cpu_calls(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
|
|
|
|
{
|
|
|
|
|
smp->data.type = SMP_T_SINT;
|
|
|
|
|
smp->data.u.sint = smp->strm->task->calls;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* returns the average number of nanoseconds spent processing the stream per call */
|
|
|
|
|
static int
|
|
|
|
|
smp_fetch_cpu_ns_avg(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
|
|
|
|
{
|
|
|
|
|
smp->data.type = SMP_T_SINT;
|
|
|
|
|
smp->data.u.sint = smp->strm->task->calls ? smp->strm->task->cpu_time / smp->strm->task->calls : 0;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* returns the total number of nanoseconds spent processing the stream */
|
|
|
|
|
static int
|
|
|
|
|
smp_fetch_cpu_ns_tot(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
|
|
|
|
{
|
|
|
|
|
smp->data.type = SMP_T_SINT;
|
|
|
|
|
smp->data.u.sint = smp->strm->task->cpu_time;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* returns the average number of nanoseconds per call spent waiting for other tasks to be processed */
|
|
|
|
|
static int
|
|
|
|
|
smp_fetch_lat_ns_avg(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
|
|
|
|
{
|
|
|
|
|
smp->data.type = SMP_T_SINT;
|
|
|
|
|
smp->data.u.sint = smp->strm->task->calls ? smp->strm->task->lat_time / smp->strm->task->calls : 0;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* returns the total number of nanoseconds per call spent waiting for other tasks to be processed */
|
|
|
|
|
static int
|
|
|
|
|
smp_fetch_lat_ns_tot(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
|
|
|
|
{
|
|
|
|
|
smp->data.type = SMP_T_SINT;
|
|
|
|
|
smp->data.u.sint = smp->strm->task->lat_time;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-06 13:30:17 -04:00
|
|
|
static int smp_fetch_const_str(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
|
|
|
|
{
|
|
|
|
|
smp->flags |= SMP_F_CONST;
|
2015-08-19 03:00:18 -04:00
|
|
|
smp->data.type = SMP_T_STR;
|
2018-07-13 04:54:26 -04:00
|
|
|
smp->data.u.str.area = args[0].data.str.area;
|
|
|
|
|
smp->data.u.str.data = args[0].data.str.data;
|
2015-06-06 13:30:17 -04:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int smp_check_const_bool(struct arg *args, char **err)
|
|
|
|
|
{
|
2018-07-13 04:54:26 -04:00
|
|
|
if (strcasecmp(args[0].data.str.area, "true") == 0 ||
|
|
|
|
|
strcasecmp(args[0].data.str.area, "1") == 0) {
|
2015-07-20 11:45:02 -04:00
|
|
|
args[0].type = ARGT_SINT;
|
|
|
|
|
args[0].data.sint = 1;
|
2015-06-06 13:30:17 -04:00
|
|
|
return 1;
|
|
|
|
|
}
|
2018-07-13 04:54:26 -04:00
|
|
|
if (strcasecmp(args[0].data.str.area, "false") == 0 ||
|
|
|
|
|
strcasecmp(args[0].data.str.area, "0") == 0) {
|
2015-07-20 11:45:02 -04:00
|
|
|
args[0].type = ARGT_SINT;
|
|
|
|
|
args[0].data.sint = 0;
|
2015-06-06 13:30:17 -04:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
memprintf(err, "Expects 'true', 'false', '0' or '1'");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int smp_fetch_const_bool(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
|
|
|
|
{
|
2015-08-19 03:00:18 -04:00
|
|
|
smp->data.type = SMP_T_BOOL;
|
2015-08-19 03:07:19 -04:00
|
|
|
smp->data.u.sint = args[0].data.sint;
|
2015-06-06 13:30:17 -04:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-06 17:43:03 -04:00
|
|
|
static int smp_fetch_const_int(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
2015-06-06 13:30:17 -04:00
|
|
|
{
|
2015-08-19 03:00:18 -04:00
|
|
|
smp->data.type = SMP_T_SINT;
|
2015-08-19 03:07:19 -04:00
|
|
|
smp->data.u.sint = args[0].data.sint;
|
2015-06-06 13:30:17 -04:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int smp_fetch_const_ipv4(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
|
|
|
|
{
|
2015-08-19 03:00:18 -04:00
|
|
|
smp->data.type = SMP_T_IPV4;
|
2015-08-19 03:07:19 -04:00
|
|
|
smp->data.u.ipv4 = args[0].data.ipv4;
|
2015-06-06 13:30:17 -04:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int smp_fetch_const_ipv6(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
|
|
|
|
{
|
2015-08-19 03:00:18 -04:00
|
|
|
smp->data.type = SMP_T_IPV6;
|
2015-08-19 03:07:19 -04:00
|
|
|
smp->data.u.ipv6 = args[0].data.ipv6;
|
2015-06-06 13:30:17 -04:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int smp_check_const_bin(struct arg *args, char **err)
|
|
|
|
|
{
|
2016-04-08 05:37:02 -04:00
|
|
|
char *binstr = NULL;
|
2015-06-06 13:30:17 -04:00
|
|
|
int binstrlen;
|
|
|
|
|
|
2018-07-13 04:54:26 -04:00
|
|
|
if (!parse_binary(args[0].data.str.area, &binstr, &binstrlen, err))
|
2015-06-06 13:30:17 -04:00
|
|
|
return 0;
|
|
|
|
|
args[0].type = ARGT_STR;
|
2018-07-13 04:54:26 -04:00
|
|
|
args[0].data.str.area = binstr;
|
|
|
|
|
args[0].data.str.data = binstrlen;
|
2015-06-06 13:30:17 -04:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int smp_fetch_const_bin(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
|
|
|
|
{
|
|
|
|
|
smp->flags |= SMP_F_CONST;
|
2015-08-19 03:00:18 -04:00
|
|
|
smp->data.type = SMP_T_BIN;
|
2018-07-13 04:54:26 -04:00
|
|
|
smp->data.u.str.area = args[0].data.str.area;
|
|
|
|
|
smp->data.u.str.data = args[0].data.str.data;
|
2015-06-06 13:30:17 -04:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int smp_check_const_meth(struct arg *args, char **err)
|
|
|
|
|
{
|
|
|
|
|
enum http_meth_t meth;
|
|
|
|
|
int i;
|
|
|
|
|
|
2018-07-13 04:54:26 -04:00
|
|
|
meth = find_http_meth(args[0].data.str.area, args[0].data.str.data);
|
2015-06-06 13:30:17 -04:00
|
|
|
if (meth != HTTP_METH_OTHER) {
|
2015-07-20 11:45:02 -04:00
|
|
|
args[0].type = ARGT_SINT;
|
|
|
|
|
args[0].data.sint = meth;
|
2015-06-06 13:30:17 -04:00
|
|
|
} else {
|
|
|
|
|
/* Check method avalaibility. A methos is a token defined as :
|
|
|
|
|
* tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "." /
|
|
|
|
|
* "^" / "_" / "`" / "|" / "~" / DIGIT / ALPHA
|
|
|
|
|
* token = 1*tchar
|
|
|
|
|
*/
|
2018-07-13 04:54:26 -04:00
|
|
|
for (i = 0; i < args[0].data.str.data; i++) {
|
|
|
|
|
if (!HTTP_IS_TOKEN(args[0].data.str.area[i])) {
|
2015-06-06 13:30:17 -04:00
|
|
|
memprintf(err, "expects valid method.");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int smp_fetch_const_meth(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
|
|
|
|
{
|
2015-08-19 03:00:18 -04:00
|
|
|
smp->data.type = SMP_T_METH;
|
2015-07-20 11:45:02 -04:00
|
|
|
if (args[0].type == ARGT_SINT) {
|
2015-06-06 13:30:17 -04:00
|
|
|
smp->flags &= ~SMP_F_CONST;
|
2015-08-19 03:07:19 -04:00
|
|
|
smp->data.u.meth.meth = args[0].data.sint;
|
2018-07-13 04:54:26 -04:00
|
|
|
smp->data.u.meth.str.area = "";
|
|
|
|
|
smp->data.u.meth.str.data = 0;
|
2015-06-06 13:30:17 -04:00
|
|
|
} else {
|
|
|
|
|
smp->flags |= SMP_F_CONST;
|
2015-08-19 03:07:19 -04:00
|
|
|
smp->data.u.meth.meth = HTTP_METH_OTHER;
|
2018-07-13 04:54:26 -04:00
|
|
|
smp->data.u.meth.str.area = args[0].data.str.area;
|
|
|
|
|
smp->data.u.meth.str.data = args[0].data.str.data;
|
2015-06-06 13:30:17 -04:00
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-10 09:42:52 -04:00
|
|
|
// This function checks the "uuid" sample's arguments.
|
|
|
|
|
// Function won't get called when no parameter is specified (maybe a bug?)
|
|
|
|
|
static int smp_check_uuid(struct arg *args, char **err)
|
|
|
|
|
{
|
|
|
|
|
if (!args[0].type) {
|
|
|
|
|
args[0].type = ARGT_SINT;
|
|
|
|
|
args[0].data.sint = 4;
|
|
|
|
|
}
|
|
|
|
|
else if (args[0].data.sint != 4) {
|
|
|
|
|
memprintf(err, "Unsupported UUID version: '%lld'", args[0].data.sint);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Generate a RFC4122 UUID (default is v4 = fully random)
|
|
|
|
|
static int smp_fetch_uuid(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
|
|
|
|
{
|
|
|
|
|
if (args[0].data.sint == 4 || !args[0].type) {
|
2020-03-08 12:48:17 -04:00
|
|
|
ha_generate_uuid(&trash);
|
2019-09-10 09:42:52 -04:00
|
|
|
smp->data.type = SMP_T_STR;
|
|
|
|
|
smp->flags = SMP_F_VOL_TEST | SMP_F_MAY_CHANGE;
|
|
|
|
|
smp->data.u.str = trash;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// more implementations of other uuid formats possible here
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-07-25 06:17:57 -04:00
|
|
|
/* Note: must not be declared <const> as its list will be overwritten.
|
|
|
|
|
* Note: fetches that may return multiple types must be declared as the lowest
|
|
|
|
|
* common denominator, the type that can be casted into all other ones. For
|
|
|
|
|
* instance IPv4/IPv6 must be declared IPv4.
|
|
|
|
|
*/
|
|
|
|
|
static struct sample_fetch_kw_list smp_kws = {ILH, {
|
|
|
|
|
{ "always_false", smp_fetch_false, 0, NULL, SMP_T_BOOL, SMP_USE_INTRN },
|
|
|
|
|
{ "always_true", smp_fetch_true, 0, NULL, SMP_T_BOOL, SMP_USE_INTRN },
|
2013-12-16 18:20:33 -05:00
|
|
|
{ "env", smp_fetch_env, ARG1(1,STR), NULL, SMP_T_STR, SMP_USE_INTRN },
|
2019-10-30 11:57:28 -04:00
|
|
|
{ "date", smp_fetch_date, ARG2(0,SINT,STR), smp_check_date_unit, SMP_T_SINT, SMP_USE_INTRN },
|
2018-01-17 07:43:24 -05:00
|
|
|
{ "date_us", smp_fetch_date_us, 0, NULL, SMP_T_SINT, SMP_USE_INTRN },
|
2017-03-12 17:00:00 -04:00
|
|
|
{ "hostname", smp_fetch_hostname, 0, NULL, SMP_T_STR, SMP_USE_INTRN },
|
2015-07-06 17:43:03 -04:00
|
|
|
{ "nbproc", smp_fetch_nbproc,0, NULL, SMP_T_SINT, SMP_USE_INTRN },
|
|
|
|
|
{ "proc", smp_fetch_proc, 0, NULL, SMP_T_SINT, SMP_USE_INTRN },
|
2017-11-21 15:45:38 -05:00
|
|
|
{ "thread", smp_fetch_thread, 0, NULL, SMP_T_SINT, SMP_USE_INTRN },
|
2015-07-20 11:45:02 -04:00
|
|
|
{ "rand", smp_fetch_rand, ARG1(0,SINT), NULL, SMP_T_SINT, SMP_USE_INTRN },
|
2014-11-24 10:02:05 -05:00
|
|
|
{ "stopping", smp_fetch_stopping, 0, NULL, SMP_T_BOOL, SMP_USE_INTRN },
|
2018-11-22 10:07:39 -05:00
|
|
|
{ "stopping", smp_fetch_stopping, 0, NULL, SMP_T_BOOL, SMP_USE_INTRN },
|
2019-09-10 09:42:52 -04:00
|
|
|
{ "uuid", smp_fetch_uuid, ARG1(0, SINT), smp_check_uuid, SMP_T_STR, SMP_USE_INTRN },
|
2018-11-22 10:07:39 -05:00
|
|
|
|
|
|
|
|
{ "cpu_calls", smp_fetch_cpu_calls, 0, NULL, SMP_T_SINT, SMP_USE_INTRN },
|
|
|
|
|
{ "cpu_ns_avg", smp_fetch_cpu_ns_avg, 0, NULL, SMP_T_SINT, SMP_USE_INTRN },
|
|
|
|
|
{ "cpu_ns_tot", smp_fetch_cpu_ns_tot, 0, NULL, SMP_T_SINT, SMP_USE_INTRN },
|
|
|
|
|
{ "lat_ns_avg", smp_fetch_lat_ns_avg, 0, NULL, SMP_T_SINT, SMP_USE_INTRN },
|
|
|
|
|
{ "lat_ns_tot", smp_fetch_lat_ns_tot, 0, NULL, SMP_T_SINT, SMP_USE_INTRN },
|
2015-06-06 13:30:17 -04:00
|
|
|
|
|
|
|
|
{ "str", smp_fetch_const_str, ARG1(1,STR), NULL , SMP_T_STR, SMP_USE_INTRN },
|
|
|
|
|
{ "bool", smp_fetch_const_bool, ARG1(1,STR), smp_check_const_bool, SMP_T_BOOL, SMP_USE_INTRN },
|
2015-07-06 17:43:03 -04:00
|
|
|
{ "int", smp_fetch_const_int, ARG1(1,SINT), NULL , SMP_T_SINT, SMP_USE_INTRN },
|
2015-06-06 13:30:17 -04:00
|
|
|
{ "ipv4", smp_fetch_const_ipv4, ARG1(1,IPV4), NULL , SMP_T_IPV4, SMP_USE_INTRN },
|
|
|
|
|
{ "ipv6", smp_fetch_const_ipv6, ARG1(1,IPV6), NULL , SMP_T_IPV6, SMP_USE_INTRN },
|
|
|
|
|
{ "bin", smp_fetch_const_bin, ARG1(1,STR), smp_check_const_bin , SMP_T_BIN, SMP_USE_INTRN },
|
|
|
|
|
{ "meth", smp_fetch_const_meth, ARG1(1,STR), smp_check_const_meth, SMP_T_METH, SMP_USE_INTRN },
|
|
|
|
|
|
2013-07-25 06:17:57 -04:00
|
|
|
{ /* END */ },
|
|
|
|
|
}};
|
|
|
|
|
|
2018-11-25 13:14:37 -05:00
|
|
|
INITCALL1(STG_REGISTER, sample_register_fetches, &smp_kws);
|
|
|
|
|
|
2010-01-04 10:16:05 -05:00
|
|
|
/* Note: must not be declared <const> as its list will be overwritten */
|
2013-06-21 17:16:39 -04:00
|
|
|
static struct sample_conv_kw_list sample_conv_kws = {ILH, {
|
2019-12-17 04:07:25 -05:00
|
|
|
{ "debug", sample_conv_debug, ARG2(0,STR,STR), smp_check_debug, SMP_T_ANY, SMP_T_ANY },
|
2017-05-05 18:56:53 -04:00
|
|
|
{ "b64dec", sample_conv_base642bin,0, NULL, SMP_T_STR, SMP_T_BIN },
|
2014-04-30 12:21:37 -04:00
|
|
|
{ "base64", sample_conv_bin2base64,0, NULL, SMP_T_BIN, SMP_T_STR },
|
2012-04-27 15:37:17 -04:00
|
|
|
{ "upper", sample_conv_str2upper, 0, NULL, SMP_T_STR, SMP_T_STR },
|
|
|
|
|
{ "lower", sample_conv_str2lower, 0, NULL, SMP_T_STR, SMP_T_STR },
|
2017-12-15 01:13:48 -05:00
|
|
|
{ "length", sample_conv_length, 0, NULL, SMP_T_STR, SMP_T_SINT },
|
2014-03-12 10:01:52 -04:00
|
|
|
{ "hex", sample_conv_bin2hex, 0, NULL, SMP_T_BIN, SMP_T_STR },
|
2017-10-24 03:27:34 -04:00
|
|
|
{ "hex2i", sample_conv_hex2int, 0, NULL, SMP_T_STR, SMP_T_SINT },
|
2018-01-25 10:24:51 -05:00
|
|
|
{ "ipmask", sample_conv_ipmask, ARG2(1,MSK4,MSK6), NULL, SMP_T_ADDR, SMP_T_IPV4 },
|
2015-07-06 17:43:03 -04:00
|
|
|
{ "ltime", sample_conv_ltime, ARG2(1,STR,SINT), NULL, SMP_T_SINT, SMP_T_STR },
|
|
|
|
|
{ "utime", sample_conv_utime, ARG2(1,STR,SINT), NULL, SMP_T_SINT, SMP_T_STR },
|
2015-07-20 11:45:02 -04:00
|
|
|
{ "crc32", sample_conv_crc32, ARG1(0,SINT), NULL, SMP_T_BIN, SMP_T_SINT },
|
2018-03-21 06:19:01 -04:00
|
|
|
{ "crc32c", sample_conv_crc32c, ARG1(0,SINT), NULL, SMP_T_BIN, SMP_T_SINT },
|
2015-07-20 11:45:02 -04:00
|
|
|
{ "djb2", sample_conv_djb2, ARG1(0,SINT), NULL, SMP_T_BIN, SMP_T_SINT },
|
|
|
|
|
{ "sdbm", sample_conv_sdbm, ARG1(0,SINT), NULL, SMP_T_BIN, SMP_T_SINT },
|
|
|
|
|
{ "wt6", sample_conv_wt6, ARG1(0,SINT), NULL, SMP_T_BIN, SMP_T_SINT },
|
2016-12-26 05:46:11 -05:00
|
|
|
{ "xxh32", sample_conv_xxh32, ARG1(0,SINT), NULL, SMP_T_BIN, SMP_T_SINT },
|
|
|
|
|
{ "xxh64", sample_conv_xxh64, ARG1(0,SINT), NULL, SMP_T_BIN, SMP_T_SINT },
|
MINOR: sample: add "json" converter
This converter escapes string to use it as json/ascii escaped string.
It can read UTF-8 with differents behavior on errors and encode it in
json/ascii.
json([<input-code>])
Escapes the input string and produces an ASCII ouput string ready to use as a
JSON string. The converter tries to decode the input string according to the
<input-code> parameter. It can be "ascii", "utf8", "utf8s", "utf8"" or
"utf8ps". The "ascii" decoder never fails. The "utf8" decoder detects 3 types
of errors:
- bad UTF-8 sequence (lone continuation byte, bad number of continuation
bytes, ...)
- invalid range (the decoded value is within a UTF-8 prohibited range),
- code overlong (the value is encoded with more bytes than necessary).
The UTF-8 JSON encoding can produce a "too long value" error when the UTF-8
character is greater than 0xffff because the JSON string escape specification
only authorizes 4 hex digits for the value encoding. The UTF-8 decoder exists
in 4 variants designated by a combination of two suffix letters : "p" for
"permissive" and "s" for "silently ignore". The behaviors of the decoders
are :
- "ascii" : never fails ;
- "utf8" : fails on any detected errors ;
- "utf8s" : never fails, but removes characters corresponding to errors ;
- "utf8p" : accepts and fixes the overlong errors, but fails on any other
error ;
- "utf8ps" : never fails, accepts and fixes the overlong errors, but removes
characters corresponding to the other errors.
This converter is particularly useful for building properly escaped JSON for
logging to servers which consume JSON-formated traffic logs.
Example:
capture request header user-agent len 150
capture request header Host len 15
log-format {"ip":"%[src]","user-agent":"%[capture.req.hdr(1),json]"}
Input request from client 127.0.0.1:
GET / HTTP/1.0
User-Agent: Very "Ugly" UA 1/2
Output log:
{"ip":"127.0.0.1","user-agent":"Very \"Ugly\" UA 1\/2"}
2014-08-12 04:20:47 -04:00
|
|
|
{ "json", sample_conv_json, ARG1(1,STR), sample_conv_json_check, SMP_T_STR, SMP_T_STR },
|
2015-07-20 11:45:02 -04:00
|
|
|
{ "bytes", sample_conv_bytes, ARG2(1,SINT,SINT), NULL, SMP_T_BIN, SMP_T_BIN },
|
MEDIUM: sample: Extend functionality for field/word converters
Extend functionality of field/word converters, so it's possible
to extract field(s)/word(s) counting from the beginning/end and/or
extract multiple fields/words (including separators) eg.
str(f1_f2_f3__f5),field(2,_,2) # f2_f3
str(f1_f2_f3__f5),field(2,_,0) # f2_f3__f5
str(f1_f2_f3__f5),field(-2,_,3) # f2_f3_
str(f1_f2_f3__f5),field(-3,_,0) # f1_f2_f3
str(w1_w2_w3___w4),word(3,_,2) # w3___w4
str(w1_w2_w3___w4),word(2,_,0) # w2_w3___w4
str(w1_w2_w3___w4),word(-2,_,3) # w1_w2_w3
str(w1_w2_w3___w4),word(-3,_,0) # w1_w2
Change is backward compatible.
2018-04-16 08:30:46 -04:00
|
|
|
{ "field", sample_conv_field, ARG3(2,SINT,STR,SINT), sample_conv_field_check, SMP_T_STR, SMP_T_STR },
|
|
|
|
|
{ "word", sample_conv_word, ARG3(2,SINT,STR,SINT), sample_conv_field_check, SMP_T_STR, SMP_T_STR },
|
2015-01-20 13:47:06 -05:00
|
|
|
{ "regsub", sample_conv_regsub, ARG3(2,REG,STR,STR), sample_conv_regsub_check, SMP_T_STR, SMP_T_STR },
|
2017-10-24 03:18:23 -04:00
|
|
|
{ "sha1", sample_conv_sha1, 0, NULL, SMP_T_BIN, SMP_T_BIN },
|
2019-06-17 06:41:44 -04:00
|
|
|
#ifdef USE_OPENSSL
|
2019-12-17 06:31:20 -05:00
|
|
|
{ "sha2", sample_conv_sha2, ARG1(0, SINT), smp_check_sha2, SMP_T_BIN, SMP_T_BIN },
|
2019-06-17 06:41:44 -04:00
|
|
|
#endif
|
2018-02-19 09:34:12 -05:00
|
|
|
{ "concat", sample_conv_concat, ARG3(1,STR,STR,STR), smp_check_concat, SMP_T_STR, SMP_T_STR },
|
2018-04-27 15:18:45 -04:00
|
|
|
{ "strcmp", sample_conv_strcmp, ARG1(1,STR), smp_check_strcmp, SMP_T_STR, SMP_T_SINT },
|
2019-02-27 08:34:51 -05:00
|
|
|
|
|
|
|
|
/* gRPC converters. */
|
2019-03-06 08:34:36 -05:00
|
|
|
{ "ungrpc", sample_conv_ungrpc, ARG2(1,PBUF_FNUM,STR), sample_conv_protobuf_check, SMP_T_BIN, SMP_T_BIN },
|
|
|
|
|
{ "protobuf", sample_conv_protobuf, ARG2(1,PBUF_FNUM,STR), sample_conv_protobuf_check, SMP_T_BIN, SMP_T_BIN },
|
MEDIUM: samples: provide basic arithmetic and bitwise operators
This commit introduces a new category of converters. They are bitwise and
arithmetic operators which support performing basic operations on integers.
Some bitwise operations are supported (and, or, xor, cpl) and some arithmetic
operations are supported (add, sub, mul, div, mod, neg). Some comparators
are provided (odd, even, not, bool) which make it possible to report a match
without having to write an ACL.
The detailed list of new operators as they appear in the doc is :
add(<value>)
Adds <value> to the input value of type unsigned integer, and returns the
result as an unsigned integer.
and(<value>)
Performs a bitwise "AND" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
bool
Returns a boolean TRUE if the input value of type unsigned integer is
non-null, otherwise returns FALSE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
presence of a flag).
cpl
Takes the input value of type unsigned integer, applies a twos-complement
(flips all bits) and returns the result as an unsigned integer.
div(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
result as an unsigned integer. If <value> is null, the largest unsigned
integer is returned (typically 2^32-1).
even
Returns a boolean TRUE if the input value of type unsigned integer is even
otherwise returns FALSE. It is functionally equivalent to "not,and(1),bool".
mod(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
remainder as an unsigned integer. If <value> is null, then zero is returned.
mul(<value>)
Multiplies the input value of type unsigned integer by <value>, and returns
the product as an unsigned integer. In case of overflow, the higher bits are
lost, leading to seemingly strange values.
neg
Takes the input value of type unsigned integer, computes the opposite value,
and returns the remainder as an unsigned integer. 0 is identity. This
operator is provided for reversed subtracts : in order to subtract the input
from a constant, simply perform a "neg,add(value)".
not
Returns a boolean FALSE if the input value of type unsigned integer is
non-null, otherwise returns TRUE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
absence of a flag).
odd
Returns a boolean TRUE if the input value of type unsigned integer is odd
otherwise returns FALSE. It is functionally equivalent to "and(1),bool".
or(<value>)
Performs a bitwise "OR" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
sub(<value>)
Subtracts <value> from the input value of type unsigned integer, and returns
the result as an unsigned integer. Note: in order to subtract the input from
a constant, simply perform a "neg,add(value)".
xor(<value>)
Performs a bitwise "XOR" (exclusive OR) between <value> and the input value
of type unsigned integer, and returns the result as an unsigned integer.
2015-01-27 09:12:13 -05:00
|
|
|
|
2015-07-07 15:10:16 -04:00
|
|
|
{ "and", sample_conv_binary_and, ARG1(1,STR), check_operator, SMP_T_SINT, SMP_T_SINT },
|
|
|
|
|
{ "or", sample_conv_binary_or, ARG1(1,STR), check_operator, SMP_T_SINT, SMP_T_SINT },
|
|
|
|
|
{ "xor", sample_conv_binary_xor, ARG1(1,STR), check_operator, SMP_T_SINT, SMP_T_SINT },
|
|
|
|
|
{ "cpl", sample_conv_binary_cpl, 0, NULL, SMP_T_SINT, SMP_T_SINT },
|
|
|
|
|
{ "bool", sample_conv_arith_bool, 0, NULL, SMP_T_SINT, SMP_T_BOOL },
|
|
|
|
|
{ "not", sample_conv_arith_not, 0, NULL, SMP_T_SINT, SMP_T_BOOL },
|
|
|
|
|
{ "odd", sample_conv_arith_odd, 0, NULL, SMP_T_SINT, SMP_T_BOOL },
|
|
|
|
|
{ "even", sample_conv_arith_even, 0, NULL, SMP_T_SINT, SMP_T_BOOL },
|
|
|
|
|
{ "add", sample_conv_arith_add, ARG1(1,STR), check_operator, SMP_T_SINT, SMP_T_SINT },
|
|
|
|
|
{ "sub", sample_conv_arith_sub, ARG1(1,STR), check_operator, SMP_T_SINT, SMP_T_SINT },
|
|
|
|
|
{ "mul", sample_conv_arith_mul, ARG1(1,STR), check_operator, SMP_T_SINT, SMP_T_SINT },
|
|
|
|
|
{ "div", sample_conv_arith_div, ARG1(1,STR), check_operator, SMP_T_SINT, SMP_T_SINT },
|
|
|
|
|
{ "mod", sample_conv_arith_mod, ARG1(1,STR), check_operator, SMP_T_SINT, SMP_T_SINT },
|
|
|
|
|
{ "neg", sample_conv_arith_neg, 0, NULL, SMP_T_SINT, SMP_T_SINT },
|
MEDIUM: samples: provide basic arithmetic and bitwise operators
This commit introduces a new category of converters. They are bitwise and
arithmetic operators which support performing basic operations on integers.
Some bitwise operations are supported (and, or, xor, cpl) and some arithmetic
operations are supported (add, sub, mul, div, mod, neg). Some comparators
are provided (odd, even, not, bool) which make it possible to report a match
without having to write an ACL.
The detailed list of new operators as they appear in the doc is :
add(<value>)
Adds <value> to the input value of type unsigned integer, and returns the
result as an unsigned integer.
and(<value>)
Performs a bitwise "AND" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
bool
Returns a boolean TRUE if the input value of type unsigned integer is
non-null, otherwise returns FALSE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
presence of a flag).
cpl
Takes the input value of type unsigned integer, applies a twos-complement
(flips all bits) and returns the result as an unsigned integer.
div(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
result as an unsigned integer. If <value> is null, the largest unsigned
integer is returned (typically 2^32-1).
even
Returns a boolean TRUE if the input value of type unsigned integer is even
otherwise returns FALSE. It is functionally equivalent to "not,and(1),bool".
mod(<value>)
Divides the input value of type unsigned integer by <value>, and returns the
remainder as an unsigned integer. If <value> is null, then zero is returned.
mul(<value>)
Multiplies the input value of type unsigned integer by <value>, and returns
the product as an unsigned integer. In case of overflow, the higher bits are
lost, leading to seemingly strange values.
neg
Takes the input value of type unsigned integer, computes the opposite value,
and returns the remainder as an unsigned integer. 0 is identity. This
operator is provided for reversed subtracts : in order to subtract the input
from a constant, simply perform a "neg,add(value)".
not
Returns a boolean FALSE if the input value of type unsigned integer is
non-null, otherwise returns TRUE. Used in conjunction with and(), it can be
used to report true/false for bit testing on input values (eg: verify the
absence of a flag).
odd
Returns a boolean TRUE if the input value of type unsigned integer is odd
otherwise returns FALSE. It is functionally equivalent to "and(1),bool".
or(<value>)
Performs a bitwise "OR" between <value> and the input value of type unsigned
integer, and returns the result as an unsigned integer.
sub(<value>)
Subtracts <value> from the input value of type unsigned integer, and returns
the result as an unsigned integer. Note: in order to subtract the input from
a constant, simply perform a "neg,add(value)".
xor(<value>)
Performs a bitwise "XOR" (exclusive OR) between <value> and the input value
of type unsigned integer, and returns the result as an unsigned integer.
2015-01-27 09:12:13 -05:00
|
|
|
|
2020-04-01 10:21:44 -04:00
|
|
|
{ "htonl", sample_conv_htonl, 0, NULL, SMP_T_SINT, SMP_T_BIN },
|
|
|
|
|
{ "cut_crlf", sample_conv_cut_crlf, 0, NULL, SMP_T_STR, SMP_T_STR },
|
2012-04-20 08:45:49 -04:00
|
|
|
{ NULL, NULL, 0, 0, 0 },
|
2010-01-04 10:16:05 -05:00
|
|
|
}};
|
|
|
|
|
|
2018-11-25 13:14:37 -05:00
|
|
|
INITCALL1(STG_REGISTER, sample_register_convs, &sample_conv_kws);
|