Compare commits

..

No commits in common. "master" and "v3.4-dev6" have entirely different histories.

161 changed files with 2495 additions and 7535 deletions

44
.github/matrix.py vendored
View File

@ -12,7 +12,6 @@ import functools
import json
import re
import sys
import urllib.error
import urllib.request
from os import environ
from packaging import version
@ -20,10 +19,9 @@ from packaging import version
#
# this CI is used for both development and stable branches of HAProxy
#
# naming convention used, if branch/tag name matches:
# naming convention used, if branch name matches:
#
# "haproxy-" - stable branches
# "vX.Y.Z" - release tags
# otherwise - development branch (i.e. "latest" ssl variants, "latest" github images)
#
@ -34,24 +32,13 @@ def get_all_github_tags(url):
headers = {}
if environ.get("GITHUB_TOKEN") is not None:
headers["Authorization"] = "token {}".format(environ.get("GITHUB_TOKEN"))
all_tags = []
page = 1
sep = "&" if "?" in url else "?"
while True:
paginated_url = "{}{}per_page=100&page={}".format(url, sep, page)
request = urllib.request.Request(paginated_url, headers=headers)
try:
response = urllib.request.urlopen(request)
except urllib.error.URLError:
return all_tags if all_tags else None
tags = json.loads(response.read().decode("utf-8"))
if not tags:
break
all_tags.extend([tag['name'] for tag in tags])
if len(tags) < 100:
break
page += 1
return all_tags if all_tags else None
request = urllib.request.Request(url, headers=headers)
try:
tags = urllib.request.urlopen(request)
except:
return None
tags = json.loads(tags.read().decode("utf-8"))
return [tag['name'] for tag in tags]
@functools.lru_cache(5)
def determine_latest_openssl(ssl):
@ -77,8 +64,6 @@ def determine_latest_aws_lc(ssl):
if not tags:
return "AWS_LC_VERSION=failed_to_detect"
valid_tags = list(filter(aws_lc_version_valid, tags))
if not valid_tags:
return "AWS_LC_VERSION=failed_to_detect"
latest_tag = max(valid_tags, key=aws_lc_version_string_to_num)
return "AWS_LC_VERSION={}".format(latest_tag[1:])
@ -90,12 +75,11 @@ def aws_lc_fips_version_valid(version_string):
@functools.lru_cache(5)
def determine_latest_aws_lc_fips(ssl):
tags = get_all_github_tags("https://api.github.com/repos/aws/aws-lc/tags")
# the AWS-LC-FIPS tags are at the end of the list, so let's get a lot
tags = get_all_github_tags("https://api.github.com/repos/aws/aws-lc/tags?per_page=200")
if not tags:
return "AWS_LC_FIPS_VERSION=failed_to_detect"
valid_tags = list(filter(aws_lc_fips_version_valid, tags))
if not valid_tags:
return "AWS_LC_FIPS_VERSION=failed_to_detect"
latest_tag = max(valid_tags, key=aws_lc_fips_version_string_to_num)
return "AWS_LC_FIPS_VERSION={}".format(latest_tag[12:])
@ -136,13 +120,11 @@ def clean_compression(compression):
def main(ref_name):
print("Generating matrix for branch '{}'.".format(ref_name))
is_stable = "haproxy-" in ref_name or re.match(r'^v\d+\.\d+\.\d+$', ref_name)
matrix = []
# Ubuntu
if is_stable:
if "haproxy-" in ref_name:
os = "ubuntu-24.04" # stable branch
os_arm = "ubuntu-24.04-arm" # stable branch
else:
@ -246,7 +228,7 @@ def main(ref_name):
# "BORINGSSL=yes",
]
if not is_stable: # development branch
if "haproxy-" not in ref_name: # development branch
ssl_versions = ssl_versions + [
"OPENSSL_VERSION=latest",
"LIBRESSL_VERSION=latest",
@ -294,7 +276,7 @@ def main(ref_name):
)
# macOS on dev branches
if not is_stable:
if "haproxy-" not in ref_name:
os = "macos-26" # development branch
TARGET = "osx"

132
CHANGELOG
View File

@ -1,138 +1,6 @@
ChangeLog :
===========
2026/03/20 : 3.4-dev7
- BUG/MINOR: stconn: Increase SC bytes_out value in se_done_ff()
- BUG/MINOR: ssl-sample: Fix sample_conv_sha2() by checking EVP_Digest* failures
- BUG/MINOR: backend: Don't get proto to use for webscoket if there is no server
- BUG/MINOR: jwt: Missing 'jwt_tokenize' return value check
- MINOR: flt_http_comp: define and use proxy_get_comp() helper function
- MEDIUM: flt_http_comp: split "compression" filter in 2 distinct filters
- CLEANUP: flt_http_comp: comp_state doesn't bother about the direction anymore
- BUG/MINOR: admin: haproxy-reload use explicit socat address type
- MEDIUM: admin: haproxy-reload conversion to POSIX sh
- BUG/MINOR: admin: haproxy-reload rename -vv long option
- SCRIPTS: git-show-backports: hide the common ancestor warning in quiet mode
- SCRIPTS: git-show-backports: add a restart-from-last option
- MINOR: mworker: add a BUG_ON() on mproxy_li in _send_status
- BUG/MINOR: mworker: don't set the PROC_O_LEAVING flag on master process
- Revert "BUG/MINOR: jwt: Missing 'jwt_tokenize' return value check"
- MINOR: jwt: Improve 'jwt_tokenize' function
- MINOR: jwt: Convert EC JWK to EVP_PKEY
- MINOR: jwt: Parse ec-specific fields in jose header
- MINOR: jwt: Manage ECDH-ES algorithm in jwt_decrypt_jwk function
- MINOR: jwt: Add ecdh-es+axxxkw support in jwt_decrypt_jwk converter
- MINOR: jwt: Manage ec certificates in jwt_decrypt_cert
- DOC: jwt: Add ECDH support in jwt_decrypt converters
- MINOR: stconn: Call sc_conn_process from the I/O callback if TASK_WOKEN_MSG state was set
- MINOR: mux-h2: Rely on h2s_notify_send() when resuming h2s for sending
- MINOR: mux-spop: Rely on spop_strm_notify_send() when resuming streams for sending
- MINOR: muxes: Wakup the data layer from a mux stream with TASK_WOKEN_IO state
- MAJOR: muxes: No longer use app_ops .wake() callback function from muxes
- MINOR: applet: Call sc_applet_process() instead of .wake() callback function
- MINOR: connection: Call sc_conn_process() instead of .wake() callback function
- MEDIUM: stconn: Remove .wake() callback function from app_ops
- MINOR: check: Remove wake_srv_chk() function
- MINOR: haterm: Remove hstream_wake() function
- MINOR: stconn: Wakup the SC with TASK_WOKEN_IO state from opposite side
- MEDIUM: stconn: Merge all .chk_rcv() callback functions in sc_chk_rcv()
- MINOR: stconn: Remove .chk_rcv() callback functions
- MEDIUM: stconn: Merge all .chk_snd() callback functions in sc_chk_snd()
- MINOR: stconn: Remove .chk_snd() callback functions
- MEDIUM: stconn: Merge all .abort() callback functions in sc_abort()
- MINOR: stconn: Remove .abort() callback functions
- MEDIUM: stconn: Merge all .shutdown() callback functions in sc_shutdown()
- MINOR: stconn: Remove .shutdown() callback functions
- MINOR: stconn: Totally app_ops from the stconns
- MINOR: stconn: Simplify sc_abort/sc_shutdown by merging calls to se_shutdown
- DEBUG: stconn: Add a CHECK_IF() when I/O are performed on a orphan SC
- MEDIUM: mworker: exiting when couldn't find the master mworker_proc element
- BUILD: ssl: use ASN1_STRING accessors for OpenSSL 4.0 compatibility
- BUILD: ssl: make X509_NAME usage OpenSSL 4.0 ready
- BUG/MINOR: tcpcheck: Fix typo in error error message for `http-check expect`
- BUG/MINOR: jws: fix memory leak in jws_b64_signature
- DOC: configuration: http-check expect example typo
- DOC/CLEANUP: config: update mentions of the old "Global parameters" section
- BUG/MEDIUM: ssl: Handle receiving early data with BoringSSL/AWS-LC
- BUG/MINOR: mworker: always stop the receiving listener
- BUG/MEDIUM: ssl: Don't report read data as early data with AWS-LC
- BUILD: makefile: fix range build without test command
- BUG/MINOR: memprof: avoid a small memory leak in "show profiling"
- BUG/MINOR: proxy: do not forget to validate quic-initial rules
- MINOR: activity: use dynamic allocation for "show profiling" entries
- MINOR: tools: extend the pointer hashing code to ease manipulations
- MINOR: tools: add a new pointer hash function that also takes an argument
- MINOR: memprof: attempt different retry slots for different hashes on collision
- MINOR: tinfo: start to add basic thread_exec_ctx
- MINOR: memprof: prepare to consider exec_ctx in reporting
- MINOR: memprof: also permit to sort output by calling context
- MINOR: tools: add a function to write a thread execution context.
- MINOR: debug: report the execution context on thread dumps
- MINOR: memprof: report the execution context on profiling output
- MINOR: initcall: record the file and line declaration of an INITCALL
- MINOR: tools: decode execution context TH_EX_CTX_INITCALL
- MINOR: tools: support decoding ha_caller type exec context
- MINOR: sample: store location for fetch/conv via initcalls
- MINOR: sample: also report contexts registered directly
- MINOR: tools: support an execution context that is just a function
- MINOR: actions: store the location of keywords registered via initcalls
- MINOR: actions: also report execution contexts registered directly
- MINOR: filters: set the exec context to the current filter config
- MINOR: ssl: set the thread execution context during message callbacks
- MINOR: connection: track mux calls to report their allocation context
- MINOR: task: set execution context on task/tasklet calls
- MINOR: applet: set execution context on applet calls
- MINOR: cli: keep the info of the current keyword being processed in the appctx
- MINOR: cli: keep track of the initcall context since kw registration
- MINOR: cli: implement execution context for manually registered keywords
- MINOR: activity: support aggregating by caller also for memprofile
- MINOR: activity: raise the default number of memprofile buckets to 4k
- DOC: internals: short explanation on how thread_exec_ctx works
- BUG/MINOR: mworker: only match worker processes when looking for unspawned proc
- MINOR: traces: defer processing of "-dt" options
- BUG/MINOR: mworker: fix typo &= instead of & in proc list serialization
- BUG/MINOR: mworker: set a timeout on the worker socketpair read at startup
- BUG/MINOR: mworker: avoid passing NULL version in proc list serialization
- BUG/MINOR: sockpair: set FD_CLOEXEC on fd received via SCM_RIGHTS
- BUG/MEDIUM: stconn: Don't forget to wakeup applets on shutdown
- BUG/MINOR: spoe: Properly switch SPOE filter to WAITING_ACK state
- BUG/MEDIUM: spoe: Properly abort processing on client abort
- BUG/MEDIUM: stconn: Fix abort on close when a large buffer is used
- BUG/MEDIUM: stconn: Don't perform L7 retries with large buffer
- BUG/MINOR: h2/h3: Only test number of trailers inserted in HTX message
- MINOR: htx: Add function to truncate all blocks after a specific block
- BUG/MINOR: h2/h3: Never insert partial headers/trailers in an HTX message
- BUG/MINOR: http-ana: Swap L7 buffer with request buffer by hand
- BUG/MINOR: stream: Fix crash in stream dump if the current rule has no keyword
- BUG/MINOR: mjson: make mystrtod() length-aware to prevent out-of-bounds reads
- MEDIUM: stats-file/clock: automatically update now_offset based on shared clock
- MINOR: promex: export "haproxy_sticktable_local_updates" metric
- BUG/MINOR: spoe: Fix condition to abort processing on client abort
- BUILD: spoe: Remove unsused variable
- MINOR: tools: add a function to create a tar file header
- MINOR: tools: add a function to load a file into a tar archive
- MINOR: config: support explicit "on" and "off" for "set-dumpable"
- MINOR: debug: read all libs in memory when set-dumpable=libs
- DEV: gdb: add a new utility to extract libs from a core dump: libs-from-core
- MINOR: debug: copy debug symbols from /usr/lib/debug when present
- MINOR: debug: opportunistically load libthread_db.so.1 with set-dumpable=libs
- BUG/MINOR: mworker: don't try to access an initializing process
- BUG/MEDIUM: peers: enforce check on incoming table key type
- BUG/MINOR: mux-h2: properly ignore R bit in GOAWAY stream ID
- BUG/MINOR: mux-h2: properly ignore R bit in WINDOW_UPDATE increments
- OPTIM: haterm: use chunk builders for generated response headers
- BUG/MAJOR: h3: check body size with content-length on empty FIN
- BUG/MEDIUM: h3: reject unaligned frames except DATA
- BUG/MINOR: mworker/cli: fix show proc pagination losing entries on resume
- CI: github: treat vX.Y.Z release tags as stable like haproxy-* branches
- MINOR: freq_ctr: add a function to add values with a peak
- MINOR: task: maintain a per-thread indicator of the peak run-queue size
- MINOR: mux-h2: store the concurrent streams hard limit in the h2c
- MINOR: mux-h2: permit to moderate the advertised streams limit depending on load
- MINOR: mux-h2: permit to fix a minimum value for the advertised streams limit
- BUG/MINOR: mworker: fix sort order of mworker_proc in 'show proc'
- CLEANUP: mworker: fix tab/space mess in mworker_env_to_proc_list()
2026/03/05 : 3.4-dev6
- CLEANUP: acme: remove duplicate includes
- BUG/MINOR: proxy: detect strdup error on server auto SNI

View File

@ -643,7 +643,7 @@ ifneq ($(USE_OPENSSL:0=),)
OPTIONS_OBJS += src/ssl_sock.o src/ssl_ckch.o src/ssl_ocsp.o src/ssl_crtlist.o \
src/ssl_sample.o src/cfgparse-ssl.o src/ssl_gencert.o \
src/ssl_utils.o src/jwt.o src/ssl_clienthello.o src/jws.o src/acme.o \
src/acme_resolvers.o src/ssl_trace.o src/jwe.o
src/ssl_trace.o src/jwe.o
endif
ifneq ($(USE_ENGINE:0=),)
@ -1043,7 +1043,7 @@ IGNORE_OPTS=help install install-man install-doc install-bin \
uninstall clean tags cscope tar git-tar version update-version \
opts reg-tests reg-tests-help unit-tests admin/halog/halog dev/flags/flags \
dev/haring/haring dev/ncpu/ncpu dev/poll/poll dev/tcploop/tcploop \
dev/term_events/term_events dev/gdb/pm-from-core dev/gdb/libs-from-core
dev/term_events/term_events dev/gdb/pm-from-core
ifneq ($(TARGET),)
ifeq ($(filter $(firstword $(MAKECMDGOALS)),$(IGNORE_OPTS)),)
@ -1077,9 +1077,6 @@ admin/dyncookie/dyncookie: admin/dyncookie/dyncookie.o
dev/flags/flags: dev/flags/flags.o
$(cmd_LD) $(ARCH_FLAGS) $(LDFLAGS) -o $@ $^ $(LDOPTS)
dev/gdb/libs-from-core: dev/gdb/libs-from-core.o
$(cmd_LD) $(ARCH_FLAGS) $(LDFLAGS) -o $@ $^ $(LDOPTS)
dev/gdb/pm-from-core: dev/gdb/pm-from-core.o
$(cmd_LD) $(ARCH_FLAGS) $(LDFLAGS) -o $@ $^ $(LDOPTS)
@ -1181,7 +1178,7 @@ distclean: clean
$(Q)rm -f admin/dyncookie/dyncookie
$(Q)rm -f dev/haring/haring dev/ncpu/ncpu{,.so} dev/poll/poll dev/tcploop/tcploop
$(Q)rm -f dev/hpack/decode dev/hpack/gen-enc dev/hpack/gen-rht
$(Q)rm -f dev/qpack/decode dev/gdb/pm-from-core dev/gdb/libs-from-core
$(Q)rm -f dev/qpack/decode dev/gdb/pm-from-core
tags:
$(Q)find src include \( -name '*.c' -o -name '*.h' \) -print0 | \
@ -1335,8 +1332,7 @@ range:
echo "[ $$index/$$count ] $$commit #############################"; \
git checkout -q $$commit || die 1; \
$(MAKE) all || die 1; \
set -- $(TEST_CMD); \
[ "$$#" -eq 0 ] || "$$@" || die 1; \
[ -z "$(TEST_CMD)" ] || $(TEST_CMD) || die 1; \
index=$$((index + 1)); \
done; \
echo;echo "Done! $${count} commit(s) built successfully for RANGE $${RANGE}" ; \

View File

@ -1,2 +1,2 @@
$Format:%ci$
2026/03/20
2026/03/05

View File

@ -1 +1 @@
3.4-dev7
3.4-dev6

View File

@ -407,7 +407,6 @@ listed below. Metrics from extra counters are not listed.
+----------------------------------------------------+
| haproxy_sticktable_size |
| haproxy_sticktable_used |
| haproxy_sticktable_local_updates |
+----------------------------------------------------+
* Resolvers metrics

View File

@ -149,7 +149,7 @@ usage() {
echo "Options:"
echo " -S, --master-socket <path> Use the master socket at <path> (default: ${SOCKET})"
echo " -s, --socket <path> Use the stats socket at <path>"
echo " -p, --path <path> Specify a base path for relative files (default: ${BASEPATH})"
echo " -p, --path <path> Specifiy a base path for relative files (default: ${BASEPATH})"
echo " -n, --dry-run Read certificates on the socket but don't dump them"
echo " -d, --debug Debug mode, set -x"
echo " -v, --verbose Verbose mode"

View File

@ -1,10 +1,11 @@
#!/bin/sh
#!/bin/bash
set -e
export VERBOSE=1
export TIMEOUT=90
export MASTER_SOCKET="${MASTER_SOCKET:-/var/run/haproxy-master.sock}"
export MASTER_SOCKET=${MASTER_SOCKET:-/var/run/haproxy-master.sock}
export RET=
alert() {
if [ "$VERBOSE" -ge "1" ]; then
@ -14,38 +15,32 @@ alert() {
reload() {
if [ -S "$MASTER_SOCKET" ]; then
socat_addr="UNIX-CONNECT:${MASTER_SOCKET}"
else
case "$MASTER_SOCKET" in
*:[0-9]*)
socat_addr="TCP:${MASTER_SOCKET}"
;;
*)
alert "Invalid master socket address '${MASTER_SOCKET}': expected a UNIX socket file or <host>:<port>"
return 1
;;
esac
fi
while read -r line; do
echo "reload" | socat -t"${TIMEOUT}" "$socat_addr" - | {
read -r status || { alert "No status received (connection error or timeout after ${TIMEOUT}s)."; exit 1; }
case "$status" in
"Success=1") ret=0 ;;
"Success=0") ret=1 ;;
*) alert "Unexpected response: '$status'"; exit 1 ;;
esac
read -r _ # consume "--"
if [ "$VERBOSE" -ge 3 ] || { [ "$ret" = 1 ] && [ "$VERBOSE" -ge 2 ]; }; then
cat >&2
if [ "$line" = "Success=0" ]; then
RET=1
elif [ "$line" = "Success=1" ]; then
RET=0
elif [ "$line" = "Another reload is still in progress." ]; then
alert "$line"
elif [ "$line" = "--" ]; then
continue;
else
cat >/dev/null
if [ "$RET" = 1 ] && [ "$VERBOSE" = "2" ]; then
echo "$line" >&2
elif [ "$VERBOSE" = "3" ]; then
echo "$line" >&2
fi
fi
exit "$ret"
}
done < <(echo "reload" | socat -t"${TIMEOUT}" "${MASTER_SOCKET}" -)
if [ -z "$RET" ]; then
alert "Couldn't finish the reload before the timeout (${TIMEOUT})."
return 1
fi
return "$RET"
}
usage() {
@ -57,12 +52,12 @@ usage() {
echo " EXPERIMENTAL script!"
echo ""
echo "Options:"
echo " -S, --master-socket <addr> Unix socket path or <host>:<port> (default: ${MASTER_SOCKET})"
echo " -S, --master-socket <path> Use the master socket at <path> (default: ${MASTER_SOCKET})"
echo " -d, --debug Debug mode, set -x"
echo " -t, --timeout Timeout (socat -t) (default: ${TIMEOUT})"
echo " -s, --silent Silent mode (no output)"
echo " -v, --verbose Verbose output (output from haproxy on failure)"
echo " -vv --verbose=all Very verbose output (output from haproxy on success and failure)"
echo " -vv Even more verbose output (output from haproxy on success and failure)"
echo " -h, --help This help"
echo ""
echo "Examples:"
@ -89,7 +84,7 @@ main() {
VERBOSE=2
shift
;;
-vv|--verbose=all)
-vv|--verbose)
VERBOSE=3
shift
;;

View File

@ -1,162 +0,0 @@
/*
* Extracts the libs archives from a core dump
*
* Copyright (C) 2026 Willy Tarreau <w@1wt.eu>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
/* Note: builds with no option under glibc, and can be built as a minimal
* uploadable static executable using nolibc as well:
gcc -o libs-from-core -nostdinc -nostdlib -s -Os -static -fno-ident \
-fno-exceptions -fno-asynchronous-unwind-tables -fno-unwind-tables \
-Wl,--gc-sections,--orphan-handling=discard,-znoseparate-code \
-I /path/to/nolibc-sysroot/include libs-from-core.c
*/
#define _GNU_SOURCE
#include <sys/mman.h>
#include <sys/stat.h>
#include <elf.h>
#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
void usage(const char *progname)
{
const char *slash = strrchr(progname, '/');
if (slash)
progname = slash + 1;
fprintf(stderr,
"Usage: %s [-q] <core_file>\n"
"Locate a libs archive from an haproxy core dump and dump it to stdout.\n"
"Arguments:\n"
" -q Query mode: only report offset and length, do not dump\n"
" core_file Core dump produced by haproxy\n",
progname);
}
int main(int argc, char **argv)
{
Elf64_Ehdr *ehdr;
Elf64_Phdr *phdr;
struct stat st;
uint8_t *mem;
int i, fd;
const char *fname;
int quiet = 0;
int arg;
for (arg = 1; arg < argc; arg++) {
if (*argv[arg] != '-')
break;
if (strcmp(argv[arg], "-q") == 0)
quiet = 1;
else if (strcmp(argv[arg], "--") == 0) {
arg++;
break;
}
}
if (arg < argc) {
fname = argv[arg];
} else {
usage(argv[0]);
exit(1);
}
fd = open(fname, O_RDONLY);
/* Let's just map the core dump as an ELF header */
fstat(fd, &st);
mem = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
if (mem == MAP_FAILED) {
perror("mmap()");
exit(1);
}
/* get the program headers */
ehdr = (Elf64_Ehdr *)mem;
/* check that it's really a core. Should be "\x7fELF" */
if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG) != 0) {
fprintf(stderr, "ELF magic not found.\n");
exit(1);
}
if (ehdr->e_ident[EI_CLASS] != ELFCLASS64) {
fprintf(stderr, "Only 64-bit ELF supported.\n");
exit(1);
}
if (ehdr->e_type != ET_CORE) {
fprintf(stderr, "ELF type %d, not a core dump.\n", ehdr->e_type);
exit(1);
}
/* OK we can safely go with program headers */
phdr = (Elf64_Phdr *)(mem + ehdr->e_phoff);
for (i = 0; i < ehdr->e_phnum; i++) {
uint64_t size = phdr[i].p_filesz;
uint64_t offset = phdr[i].p_offset;
int ret = 0;
if (phdr[i].p_type != PT_LOAD)
continue;
//fprintf(stderr, "Scanning segment %d...\n", ehdr->e_phnum);
//fprintf(stderr, "\r%-5d: off=%lx va=%lx sz=%lx ", i, (long)offset, (long)phdr[i].p_vaddr, (long)size);
if (!size)
continue;
if (size < 512) // minimum for a tar header
continue;
/* tar magic */
if (memcmp(mem + offset + 257, "ustar\0""00", 8) != 0)
continue;
/* uid, gid */
if (memcmp(mem + offset + 108, "0000000\0""0000000\0", 16) != 0)
continue;
/* link name */
if (memcmp(mem + offset + 157, "haproxy-libs-dump\0", 18) != 0)
continue;
/* OK that's really it */
if (quiet)
printf("offset=%#lx size=%#lx\n", offset, size);
else
ret = (write(1, mem + offset, size) == size) ? 0 : 1;
return ret;
}
//fprintf(stderr, "\r%75s\n", "\r");
fprintf(stderr, "libs archive not found. Was 'set-dumpable' set to 'libs' ?\n");
return 1;
}

View File

@ -86,7 +86,7 @@ maintenance model and what the user wants is passed, then the LLM is invited to
provide its opinion on the need for a backport and an explanation of the reason
for its choice. This often helps the user to find a quick summary about the
patch. All these outputs are then converted to a long HTML page with colors and
radio buttons, where patches are preselected based on this classification,
radio buttons, where patches are pre-selected based on this classification,
that the user can consult and adjust, read the commits if needed, and the
selected patches finally provide some copy-pastable commands in a text-area to
select commit IDs to work on, typically in a form that's suitable for a simple

File diff suppressed because it is too large Load Diff

View File

@ -134,7 +134,7 @@ HATerm:
- /?R=<enable> Enable sending random data if >0.
Note that those arguments may be cumulated on one line separated by a set of
delimiters among [&?,;/] :
delimitors among [&?,;/] :
- GET /?s=20k&c=1&t=700&K=30r HTTP/1.0
- GET /?r=500?s=0?c=0?t=1000 HTTP/1.0

View File

@ -539,22 +539,10 @@ message. These functions are used by HTX analyzers or by multiplexers.
with the first block not removed, or NULL if everything was removed, and
the amount of data drained.
- htx_xfer() transfers HTX blocks from an HTX message to another, stopping
when a specific amount of bytes, including meta-data, was copied. If the
tail block is a DATA block, it may be partially copied. All other block
are transferred at once. By default, copied blocks are removed from the
original HTX message and headers and trailers parts cannot be partially
copied. But flags can be set to change the default behavior:
- HTX_XFER_KEEP_SRC_BLKS: source blocks are not removed
- HTX_XFER_PARTIAL_HDRS_COPY: partial headers and trailers
part can be xferred
- HTX_XFER_HDRS_ONLY: Only the headers part is xferred
- htx_xfer_blks() [DEPRECATED] transfers HTX blocks from an HTX message to
another, stopping after the first block of a specified type is transferred
or when a specific amount of bytes, including meta-data, was moved. If the
tail block is a DATA block, it may be partially moved. All other block are
- htx_xfer_blks() transfers HTX blocks from an HTX message to another,
stopping after the first block of a specified type is transferred or when
a specific amount of bytes, including meta-data, was moved. If the tail
block is a DATA block, it may be partially moved. All other block are
transferred at once or kept. This function returns a mixed value, with the
last block moved, or NULL if nothing was moved, and the amount of data
transferred. When HEADERS or TRAILERS blocks must be transferred, this

View File

@ -114,7 +114,7 @@ SHUT RDY ACT
1 1 1 => shut pending
PB: we can land into final shut if one thread disables the FD while another
one that was waiting on it reports it as shut. Theoretically it should be
one that was waiting on it reports it as shut. Theorically it should be
implicitly ready though, since reported. But if no data is reported, it
will be reportedly shut only. And no event will be reported then. This
might still make sense since it's not active, thus we don't want events.

View File

@ -1,50 +0,0 @@
2026-03-12 - thread execution context
Thread execution context (thread_exec_ctx) is a combination of type and pointer
that are set in the current running thread at th_ctx->exec_ctx when entering
certain processing (tasks, sample fetch functions, actions, CLI keywords etc).
They're refined along execution, so that a task such as process_stream could
temporarily switch to a converter while evaluating an expression and switch
back to process_stream. They are reported in thread dumps and are mixed with
caller locations for memory profiling. As such they are intentionally not too
precise in order to avoid an explosion of the number of buckets. At the moment,
the level of granularity it provides is sufficient to try to narrow a
misbehaving origin down to a list of keywords. The context types can currently
be:
- something registered via an initcall, with the initcall's location
- something registered via an ha_caller, with the caller's location
- an explicit sample fetch / converter / action / CLI keyword list
- an explicit function (mainly used for actions without keywords)
- a task / tasklet (no distinction is made), using the ->process pointer
- a filter (e.g. compression), via flt_conf, reporting name
- a mux (via the mux_ops, reporting the name)
- an applet (e.g. cache, stats, CLI)
A macro EXEC_CTX_MAKE(type, pointer) makes a thread_exec_ctx from such
values.
A macro EXEC_CTX_NO_RET(ctx, statement) calls a void statement under the
specified context.
A macro EXEC_CTX_WITH_RET(ctx, expr) calls an expression under the specified
context.
Most locations were modified to directly use these macros on the fly, by
retrieving the context from where it was set on the element being evaluated
(e.g. an action rule contains the context inherited by the action keyword
that was used to create it).
In tools.c, chunk_append_thread_ctx() tries to decode the given exec_ctx and
appends it into the provided buffer. It's used by ha_thread_dump_one() and
cli_io_handler_show_activity() for memory profiling. In this latter case,
the detected thread_ctx are reported in the output under brackets prefixed
with "[via ...]" to distinguish call paths to the same allocators.
A good way to test if a context is properly reported is to place a bleeding
malloc() call into one of the monitored functions, e.g.:
DISGUISE(malloc(8));
and issue "show profiling memory" after stressing the function. Its context
must appear on the right with the number of calls.

View File

@ -1731,7 +1731,7 @@ add backend <name> from <defproxy> [mode <mode>] [guid <guid>] [ EXPERIMENTAL ]
Only TCP or HTTP proxies can be created. All of the settings are inherited
from <defproxy> default proxy instance. By default, it is mandatory to
specify the backend mode via the argument of the same name, unless <defproxy>
already defines it explicitly. It is also possible to use an optional GUID
already defines it explicitely. It is also possible to use an optional GUID
argument if wanted.
Servers can be added via the command "add server". The backend is initialized
@ -1740,7 +1740,10 @@ add backend <name> from <defproxy> [mode <mode>] [guid <guid>] [ EXPERIMENTAL ]
All named default proxies can be used, given that they validate the same
inheritance rules applied during configuration parsing. There is some
exceptions though, for example when the mode is neither TCP nor HTTP.
exceptions though, for example when the mode is neither TCP nor HTTP. Another
exception is that it is not yet possible to use a default proxies which
reference custom HTTP errors, for example via the errorfiles or http-rules
keywords.
This command is restricted and can only be issued on sockets configured for
level "admin". Moreover, this feature is still considered in development so it
@ -2130,7 +2133,7 @@ del backend <name>
be attached to the backend instance.
There is additional restrictions which prevent backend removal. First, a
backend cannot be removed if it is explicitly referenced by config elements,
backend cannot be removed if it is explicitely referenced by config elements,
for example via a use_backend rule or in sample expressions. Some proxies
options are also incompatible with runtime deletion. Currently, this is the
case when deprecated dispatch or option transparent are used. Also, a backend
@ -2138,7 +2141,7 @@ del backend <name>
impossible for now to remove a backend if QUIC servers were present in it.
It can be useful to use "wait be-removable" prior to this command to check
for the aforementioned requisites. This also provides a method to wait for
for the aformentioned requisites. This also provides a methode to wait for
the final closure of the streams attached to the target backend.
This command is restricted and can only be issued on sockets configured for
@ -3356,7 +3359,7 @@ show pools [byname|bysize|byusage] [detailed] [match <pfx>] [<nb>]
- Pool quic_conn_c (152 bytes) : 1337 allocated (203224 bytes), ...
Total: 15 pools, 109578176 bytes allocated, 109578176 used ...
show profiling [{all | status | tasks | memory}] [byaddr|bytime|byctx|aggr|<max_lines>]*
show profiling [{all | status | tasks | memory}] [byaddr|bytime|aggr|<max_lines>]*
Dumps the current profiling settings, one per line, as well as the command
needed to change them. When tasks profiling is enabled, some per-function
statistics collected by the scheduler will also be emitted, with a summary
@ -3365,15 +3368,14 @@ show profiling [{all | status | tasks | memory}] [byaddr|bytime|byctx|aggr|<max_
allocations/releases and their sizes will be reported. It is possible to
limit the dump to only the profiling status, the tasks, or the memory
profiling by specifying the respective keywords; by default all profiling
information are dumped. It is also possible to limit the number of lines of
information are dumped. It is also possible to limit the number of lines
of output of each category by specifying a numeric limit. If is possible to
request that the output is sorted by address, by total execution time, or by
calling context instead of usage, e.g. to ease comparisons between subsequent
calls or to check what needs to be optimized, and to aggregate task activity
by called function instead of seeing the details. Please note that profiling
is essentially aimed at developers since it gives hints about where CPU
cycles or memory are wasted in the code. There is nothing useful to monitor
there.
request that the output is sorted by address or by total execution time
instead of usage, e.g. to ease comparisons between subsequent calls or to
check what needs to be optimized, and to aggregate task activity by called
function instead of seeing the details. Please note that profiling is
essentially aimed at developers since it gives hints about where CPU cycles
or memory are wasted in the code. There is nothing useful to monitor there.
show resolvers [<resolvers section id>]
Dump statistics for the given resolvers section, or all resolvers sections

View File

@ -1,69 +0,0 @@
# Example: log HTTP traffic and TLS session keys to separate destinations
#
# "option httpslog" sends HTTP access logs to the /dev/log syslog server.
# TLS session keys are written to 2 ring buffers.
#
# Requirements:
# - HAProxy built with OpenSSL support
# - "tune.ssl.keylog on" in the global section
#
# Retrieve TLS session keys from the ring buffer via the CLI:
# For frontend connections:
#
# (echo "show events keylog-fc -w"; read) | socat /tmp/worker.socket -
#
# For backend connections:
#
# (echo "show events keylog-bc -w"; read) | socat /tmp/worker.socket -
#
# The result is in SSLKEYLOGFILE format and can be saved to a file and loaded
# into Wireshark to decrypt captured TLS traffic.
global
stats socket /tmp/worker.socket mode 0660
tune.ssl.keylog on
# Ring buffer for TLS session keys.
# "format raw" stores only the log message text, without any syslog envelope,
# producing output in the SSLKEYLOGFILE format directly.
ring keylog-fc
description "TLS session key frontend log"
format raw
maxlen 2000
size 1M
ring keylog-bc
description "TLS session key backend log"
format raw
maxlen 2000
size 1M
defaults
mode http
timeout client 30s
timeout server 30s
timeout connect 5s
log-profile keylog-fc
on any format "${HAPROXY_KEYLOG_FC_LOG_FMT}"
log-profile keylog-bc
on any format "${HAPROXY_KEYLOG_BC_LOG_FMT}"
frontend https-in
bind :443 ssl crt "common.pem"
option httpslog
# HTTPs access logs sent to the syslog server
log /dev/log format raw local0
# TLS session keys written to the ring buffer
log ring@keylog-fc profile keylog-fc local1
log ring@keylog-bc profile keylog-bc local1
default_backend be1
backend be1
server s1 10.0.0.123:443 ssl verify none

View File

@ -2,27 +2,17 @@
#ifndef _ACME_T_H_
#define _ACME_T_H_
#include <haproxy/acme_resolvers-t.h>
#include <haproxy/istbuf.h>
#include <haproxy/openssl-compat.h>
#if defined(HAVE_ACME)
#define ACME_RETRY 5
/* Readiness requirements for challenge */
#define ACME_RDY_NONE 0x00
#define ACME_RDY_CLI 0x01
#define ACME_RDY_DNS 0x02
/* acme section configuration */
struct acme_cfg {
char *filename; /* config filename */
int linenum; /* config linenum */
char *name; /* section name */
int reuse_key; /* do we need to renew the private key */
int cond_ready; /* ready condition */
unsigned int dns_delay; /* delay in seconds before re-triggering DNS resolution (default: 300) */
char *directory; /* directory URL */
char *map; /* storage for tokens + thumbprint */
struct {
@ -50,9 +40,6 @@ enum acme_st {
ACME_NEWACCOUNT,
ACME_NEWORDER,
ACME_AUTH,
ACME_RSLV_WAIT,
ACME_RSLV_TRIGGER,
ACME_RSLV_READY,
ACME_CHALLENGE,
ACME_CHKCHALLENGE,
ACME_FINALIZE,
@ -71,8 +58,6 @@ struct acme_auth {
struct ist auth; /* auth URI */
struct ist chall; /* challenge URI */
struct ist token; /* token */
int validated; /* already validated */
struct acme_rslv *rslv; /* acme dns-01 resolver */
int ready; /* is the challenge ready ? */
void *next;
};
@ -99,7 +84,6 @@ struct acme_ctx {
X509_REQ *req;
struct ist finalize;
struct ist certificate;
unsigned int dnstasks; /* number of DNS tasks running for this ctx */
struct task *task;
struct ebmb_node node;
char name[VAR_ARRAY];
@ -117,6 +101,4 @@ struct acme_ctx {
#define ACME_VERB_ADVANCED 4
#define ACME_VERB_COMPLETE 5
#endif /* ! HAVE_ACME */
#endif

View File

@ -1,27 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#ifndef _HAPROXY_ACME_RESOLVERS_T_H
#define _HAPROXY_ACME_RESOLVERS_T_H
#include <haproxy/obj_type-t.h>
#include <haproxy/resolvers-t.h>
struct dns_counters;
/* TXT records for dns-01 */
struct acme_rslv {
enum obj_type obj_type; /* OBJ_TYPE_ACME_RSLV */
unsigned int *dnstasks; /* number of running DNS resolution for the same acme_task */
char *hostname_dn;
int hostname_dn_len;
struct resolvers *resolvers;
struct resolv_requester *requester;
int result; /* RSLV_STATUS_* — NONE until done */
int error_code; /* RSLV_RESP_* from the error callback */
struct task *acme_task; /* ACME task to wake on completion, or NULL */
struct ist txt; /* first TXT record found */
int (*success_cb)(struct resolv_requester *, struct dns_counters *);
int (*error_cb)(struct resolv_requester *, int);
};
#endif /* _HAPROXY_ACME_RESOLVERS_T_H */

View File

@ -1,18 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#ifndef _HAPROXY_ACME_RESOLVERS_H
#define _HAPROXY_ACME_RESOLVERS_H
#include <haproxy/openssl-compat.h>
#if defined(HAVE_ACME)
#include <haproxy/acme_resolvers-t.h>
#include <haproxy/acme-t.h>
#include <haproxy/resolvers-t.h>
struct acme_rslv *acme_rslv_start(struct acme_auth *auth, unsigned int *dnstasks, char **errmsg);
void acme_rslv_free(struct acme_rslv *rslv);
#endif
#endif /* _HAPROXY_ACME_RESOLVERS_H */

View File

@ -151,7 +151,6 @@ struct act_rule {
struct ist str; /* string param (reason, header name, ...) */
struct lf_expr fmt; /* log-format compatible expression */
struct my_regex *re; /* used by replace-header/value/uri/path */
struct sample_expr *expr; /* sample expression used by HTTP action */
} http; /* args used by some HTTP rules */
struct http_reply *http_reply; /* HTTP response to be used by return/deny/tarpit rules */
struct redirect_rule *redir; /* redirect rule or "http-request redirect" */
@ -199,11 +198,6 @@ struct act_rule {
struct server *srv; /* target server to attach the connection */
struct sample_expr *name; /* used to differentiate idle connections */
} attach_srv; /* 'attach-srv' rule */
struct {
enum log_orig_id orig;
char *profile_name;
struct log_profile *profile;
} do_log; /* 'do-log' action */
struct {
int value;
struct sample_expr *expr;
@ -212,7 +206,6 @@ struct act_rule {
void *p[4];
} act; /* generic pointers to be used by custom actions */
} arg; /* arguments used by some actions */
struct thread_exec_ctx exec_ctx; /* execution context */
struct {
char *file; /* file name where the rule appears (or NULL) */
int line; /* line number where the rule appears */
@ -224,9 +217,7 @@ struct action_kw {
enum act_parse_ret (*parse)(const char **args, int *cur_arg, struct proxy *px,
struct act_rule *rule, char **err);
int flags;
/* 4 bytes here */
void *private;
struct thread_exec_ctx exec_ctx; /* execution context */
};
struct action_kw_list {

View File

@ -35,7 +35,6 @@ int act_resolution_cb(struct resolv_requester *requester, struct dns_counters *c
int act_resolution_error_cb(struct resolv_requester *requester, int error_code);
const char *action_suggest(const char *word, const struct list *keywords, const char **extra);
void free_act_rule(struct act_rule *rule);
void act_add_list(struct list *head, struct action_kw_list *kw_list);
static inline struct action_kw *action_lookup(struct list *keywords, const char *kw)
{

View File

@ -24,7 +24,6 @@
#include <haproxy/api-t.h>
#include <haproxy/freq_ctr-t.h>
#include <haproxy/tinfo-t.h>
/* bit fields for the "profiling" global variable */
#define HA_PROF_TASKS_OFF 0x00000000 /* per-task CPU profiling forced disabled */
@ -85,7 +84,6 @@ struct memprof_stats {
unsigned long long alloc_tot;
unsigned long long free_tot;
void *info; // for pools, ptr to the pool
struct thread_exec_ctx exec_ctx;
};
#endif

View File

@ -130,7 +130,6 @@ struct appctx {
int (*io_handler)(struct appctx *appctx); /* used within the cli_io_handler when st0 = CLI_ST_CALLBACK */
void (*io_release)(struct appctx *appctx); /* used within the cli_io_handler when st0 = CLI_ST_CALLBACK,
if the command is terminated or the session released */
struct cli_kw *kw; /* the keyword being processed */
} cli_ctx; /* context dedicated to the CLI applet */
struct buffer_wait buffer_wait; /* position in the list of objects waiting for a buffer */

View File

@ -62,13 +62,6 @@ ssize_t applet_append_line(void *ctx, struct ist v1, struct ist v2, size_t ofs,
static forceinline void applet_fl_set(struct appctx *appctx, uint on);
static forceinline void applet_fl_clr(struct appctx *appctx, uint off);
/* macros to switch the calling context to the applet during a call. There's
* one with a return value for most calls, and one without for the few like
* fct(), shut(), or release() with no return.
*/
#define CALL_APPLET_WITH_RET(applet, func) EXEC_CTX_WITH_RET(EXEC_CTX_MAKE(TH_EX_CTX_APPLET, (applet)), (applet)->func)
#define CALL_APPLET_NO_RET(applet, func) EXEC_CTX_NO_RET(EXEC_CTX_MAKE(TH_EX_CTX_APPLET, (applet)), (applet)->func)
static forceinline uint appctx_app_test(const struct appctx *appctx, uint test)
{
@ -133,7 +126,7 @@ static inline int appctx_init(struct appctx *appctx)
task_set_thread(appctx->t, tid);
if (appctx->applet->init)
return CALL_APPLET_WITH_RET(appctx->applet, init(appctx));
return appctx->applet->init(appctx);
return 0;
}

View File

@ -99,11 +99,8 @@ static inline int be_is_eligible(const struct proxy *be)
/* set the time of last session on the backend */
static inline void be_set_sess_last(struct proxy *be)
{
uint now_sec = ns_to_sec(now_ns);
if (be->be_counters.shared.tg)
if (HA_ATOMIC_LOAD(&be->be_counters.shared.tg[tgid - 1]->last_sess) != now_sec)
HA_ATOMIC_STORE(&be->be_counters.shared.tg[tgid - 1]->last_sess, now_sec);
HA_ATOMIC_STORE(&be->be_counters.shared.tg[tgid - 1]->last_sess, ns_to_sec(now_ns));
}
/* This function returns non-zero if the designated server will be

View File

@ -59,7 +59,6 @@ enum chk_result {
#define CHK_ST_FASTINTER 0x0400 /* force fastinter check */
#define CHK_ST_READY 0x0800 /* check ready to migrate or run, see below */
#define CHK_ST_SLEEPING 0x1000 /* check was sleeping, i.e. not currently bound to a thread, see below */
#define CHK_ST_USE_SMALL_BUFF 0x2000 /* Use small buffers if possible for the request */
/* 4 possible states for CHK_ST_SLEEPING and CHK_ST_READY:
* SLP RDY State Description
@ -155,7 +154,7 @@ enum {
};
struct tcpcheck_rule;
struct tcpcheck;
struct tcpcheck_rules;
struct check {
enum obj_type obj_type; /* object type == OBJ_TYPE_CHECK */
@ -174,7 +173,7 @@ struct check {
signed char use_ssl; /* use SSL for health checks (1: on, 0: server mode, -1: off) */
int send_proxy; /* send a PROXY protocol header with checks */
int reuse_pool; /* try to reuse idle connections */
struct tcpcheck *tcpcheck; /* tcp-check to use to perform a health-check */
struct tcpcheck_rules *tcpcheck_rules; /* tcp-check send / expect rules */
struct tcpcheck_rule *current_step; /* current step when using tcpcheck */
int inter, fastinter, downinter; /* checks: time in milliseconds */
enum chk_result result; /* health-check result : CHK_RES_* */
@ -189,7 +188,6 @@ struct check {
char **envp; /* the environment to use if running a process-based check */
struct pid_list *curpid; /* entry in pid_list used for current process-based test, or -1 if not in test */
struct sockaddr_storage addr; /* the address to check */
struct protocol *proto; /* protocol used for check, may be different from the server's one */
char *pool_conn_name; /* conn name used on reuse */
char *sni; /* Server name */
char *alpn_str; /* ALPN to use for checks */

View File

@ -78,11 +78,12 @@ struct task *process_chk(struct task *t, void *context, unsigned int state);
struct task *srv_chk_io_cb(struct task *t, void *ctx, unsigned int state);
int check_buf_available(void *target);
struct buffer *check_get_buf(struct check *check, struct buffer *bptr, unsigned int small_buffer);
struct buffer *check_get_buf(struct check *check, struct buffer *bptr);
void check_release_buf(struct check *check, struct buffer *bptr);
const char *init_check(struct check *check, int type);
void free_check(struct check *check);
void check_purge(struct check *check);
int wake_srv_chk(struct stconn *sc);
int init_srv_check(struct server *srv);
int init_srv_agent_check(struct server *srv);

View File

@ -33,7 +33,6 @@
extern struct pool_head *pool_head_trash;
extern struct pool_head *pool_head_large_trash;
extern struct pool_head *pool_head_small_trash;
/* function prototypes */
@ -49,7 +48,6 @@ int chunk_strcmp(const struct buffer *chk, const char *str);
int chunk_strcasecmp(const struct buffer *chk, const char *str);
struct buffer *get_trash_chunk(void);
struct buffer *get_large_trash_chunk(void);
struct buffer *get_small_trash_chunk(void);
struct buffer *get_trash_chunk_sz(size_t size);
struct buffer *get_larger_trash_chunk(struct buffer *chunk);
int init_trash_buffers(int first);
@ -135,29 +133,6 @@ static forceinline struct buffer *alloc_large_trash_chunk(void)
return chunk;
}
/*
* Allocate a small trash chunk from the reentrant pool. The buffer starts at
* the end of the chunk. This chunk must be freed using free_trash_chunk(). This
* call may fail and the caller is responsible for checking that the returned
* pointer is not NULL.
*/
static forceinline struct buffer *alloc_small_trash_chunk(void)
{
struct buffer *chunk;
if (!pool_head_small_trash)
return NULL;
chunk = pool_alloc(pool_head_small_trash);
if (chunk) {
char *buf = (char *)chunk + sizeof(struct buffer);
*buf = 0;
chunk_init(chunk, buf,
pool_head_small_trash->size - sizeof(struct buffer));
}
return chunk;
}
/*
* Allocate a trash chunk accordingly to the requested size. This chunk must be
* freed using free_trash_chunk(). This call may fail and the caller is
@ -165,9 +140,7 @@ static forceinline struct buffer *alloc_small_trash_chunk(void)
*/
static forceinline struct buffer *alloc_trash_chunk_sz(size_t size)
{
if (pool_head_small_trash && size <= pool_head_small_trash->size)
return alloc_small_trash_chunk();
else if (size <= pool_head_trash->size)
if (likely(size <= pool_head_trash->size))
return alloc_trash_chunk();
else if (pool_head_large_trash && size <= pool_head_large_trash->size)
return alloc_large_trash_chunk();
@ -180,12 +153,10 @@ static forceinline struct buffer *alloc_trash_chunk_sz(size_t size)
*/
static forceinline void free_trash_chunk(struct buffer *chunk)
{
if (pool_head_small_trash && chunk && chunk->size == pool_head_small_trash->size - sizeof(struct buffer))
pool_free(pool_head_small_trash, chunk);
else if (pool_head_large_trash && chunk && chunk->size == pool_head_large_trash->size - sizeof(struct buffer))
pool_free(pool_head_large_trash, chunk);
else
if (likely(chunk && chunk->size == pool_head_trash->size - sizeof(struct buffer)))
pool_free(pool_head_trash, chunk);
else
pool_free(pool_head_large_trash, chunk);
}
/* copies chunk <src> into <chk>. Returns 0 in case of failure. */

View File

@ -23,7 +23,6 @@
#define _HAPROXY_CLI_T_H
#include <haproxy/applet-t.h>
#include <haproxy/tinfo-t.h>
/* Access level for a stats socket (appctx->cli_ctx.level) */
#define ACCESS_LVL_NONE 0x0000
@ -121,8 +120,6 @@ struct cli_kw {
void (*io_release)(struct appctx *appctx);
void *private;
int level; /* this is the level needed to show the keyword usage and to use it */
/* 4-byte hole here */
struct thread_exec_ctx exec_ctx; /* execution context */
};
struct cli_kw_list {

View File

@ -34,7 +34,6 @@
#include <haproxy/listener-t.h>
#include <haproxy/obj_type.h>
#include <haproxy/pool-t.h>
#include <haproxy/protocol.h>
#include <haproxy/server.h>
#include <haproxy/session-t.h>
#include <haproxy/task-t.h>
@ -50,13 +49,6 @@ extern struct mux_stopping_data mux_stopping_data[MAX_THREADS];
#define IS_HTX_CONN(conn) ((conn)->mux && ((conn)->mux->flags & MX_FL_HTX))
/* macros to switch the calling context to the mux during a call. There's one
* with a return value for most calls, and one without for the few like shut(),
* detach() or destroy() with no return.
*/
#define CALL_MUX_WITH_RET(mux, func) EXEC_CTX_WITH_RET(EXEC_CTX_MAKE(TH_EX_CTX_MUX, (mux)), (mux)->func)
#define CALL_MUX_NO_RET(mux, func) EXEC_CTX_NO_RET(EXEC_CTX_MAKE(TH_EX_CTX_MUX, (mux)), (mux)->func)
/* receive a PROXY protocol header over a connection */
int conn_recv_proxy(struct connection *conn, int flag);
int conn_send_proxy(struct connection *conn, unsigned int flag);
@ -488,7 +480,7 @@ static inline int conn_install_mux(struct connection *conn, const struct mux_ops
conn->mux = mux;
conn->ctx = ctx;
ret = mux->init ? CALL_MUX_WITH_RET(mux, init(conn, prx, sess, &BUF_NULL)) : 0;
ret = mux->init ? mux->init(conn, prx, sess, &BUF_NULL) : 0;
if (ret < 0) {
conn->mux = NULL;
conn->ctx = NULL;
@ -610,13 +602,13 @@ void list_mux_proto(FILE *out);
*/
static inline const struct mux_proto_list *conn_get_best_mux_entry(
const struct ist mux_proto,
int proto_side, int proto_is_quic, int proto_mode)
int proto_side, int proto_mode)
{
struct mux_proto_list *item;
struct mux_proto_list *fallback = NULL;
list_for_each_entry(item, &mux_proto_list.list, list) {
if (!(item->side & proto_side) || !(item->mode & proto_mode) || (proto_is_quic && !(item->mux->flags & MX_FL_FRAMED)))
if (!(item->side & proto_side) || !(item->mode & proto_mode))
continue;
if (istlen(mux_proto) && isteq(mux_proto, item->token))
return item;
@ -641,7 +633,7 @@ static inline const struct mux_ops *conn_get_best_mux(struct connection *conn,
{
const struct mux_proto_list *item;
item = conn_get_best_mux_entry(mux_proto, proto_side, proto_is_quic(conn->ctrl), proto_mode);
item = conn_get_best_mux_entry(mux_proto, proto_side, proto_mode);
return item ? item->mux : NULL;
}

View File

@ -536,11 +536,6 @@
#define TIME_STATS_SAMPLES 512
#endif
/* number of samples used to measure the load in the run queue */
#ifndef RQ_LOAD_SAMPLES
#define RQ_LOAD_SAMPLES 512
#endif
/* max ocsp cert id asn1 encoded length */
#ifndef OCSP_MAX_CERTID_ASN1_LENGTH
#define OCSP_MAX_CERTID_ASN1_LENGTH 128
@ -606,7 +601,7 @@
* store stats.
*/
#ifndef MEMPROF_HASH_BITS
# define MEMPROF_HASH_BITS 12
# define MEMPROF_HASH_BITS 10
#endif
#define MEMPROF_HASH_BUCKETS (1U << MEMPROF_HASH_BITS)

View File

@ -37,7 +37,6 @@
extern struct pool_head *pool_head_buffer;
extern struct pool_head *pool_head_large_buffer;
extern struct pool_head *pool_head_small_buffer;
int init_buffer(void);
void buffer_dump(FILE *o, struct buffer *b, int from, int to);
@ -67,12 +66,6 @@ static inline int b_is_large_sz(size_t sz)
return (pool_head_large_buffer && sz == pool_head_large_buffer->size);
}
/* Return 1 if <sz> is the size of a small buffer */
static inline int b_is_small_sz(size_t sz)
{
return (pool_head_small_buffer && sz == pool_head_small_buffer->size);
}
/* Return 1 if <bug> is a default buffer */
static inline int b_is_default(struct buffer *buf)
{
@ -85,12 +78,6 @@ static inline int b_is_large(struct buffer *buf)
return b_is_large_sz(b_size(buf));
}
/* Return 1 if <buf> is a small buffer */
static inline int b_is_small(struct buffer *buf)
{
return b_is_small_sz(b_size(buf));
}
/**************************************************/
/* Functions below are used for buffer allocation */
/**************************************************/
@ -185,8 +172,6 @@ static inline char *__b_get_emergency_buf(void)
* than the default buffers */ \
if (unlikely(b_is_large_sz(sz))) \
pool_free(pool_head_large_buffer, area); \
else if (unlikely(b_is_small_sz(sz))) \
pool_free(pool_head_small_buffer, area); \
else if (th_ctx->emergency_bufs_left < global.tune.reserved_bufs) \
th_ctx->emergency_bufs[th_ctx->emergency_bufs_left++] = area; \
else \
@ -200,35 +185,6 @@ static inline char *__b_get_emergency_buf(void)
__b_free((_buf)); \
} while (0)
static inline struct buffer *b_alloc_small(struct buffer *buf)
{
char *area = NULL;
if (!buf->size) {
area = pool_alloc(pool_head_small_buffer);
if (!area)
return NULL;
buf->area = area;
buf->size = global.tune.bufsize_small;
}
return buf;
}
static inline struct buffer *b_alloc_large(struct buffer *buf)
{
char *area = NULL;
if (!buf->size) {
area = pool_alloc(pool_head_large_buffer);
if (!area)
return NULL;
buf->area = area;
buf->size = global.tune.bufsize_large;
}
return buf;
}
/* Offer one or multiple buffer currently belonging to target <from> to whoever
* needs one. Any pointer is valid for <from>, including NULL. Its purpose is
* to avoid passing a buffer to oneself in case of failed allocations (e.g.

View File

@ -28,9 +28,7 @@
#include <haproxy/stream-t.h>
extern const char *trace_flt_id;
extern const char *http_comp_req_flt_id;
extern const char *http_comp_res_flt_id;
extern const char *http_comp_flt_id;
extern const char *cache_store_flt_id;
extern const char *spoe_filter_id;
extern const char *fcgi_flt_id;

View File

@ -403,25 +403,6 @@ static inline uint swrate_add_scaled_opportunistic(uint *sum, uint n, uint v, ui
return new_sum;
}
/* Like swrate_add() except that if <v> is beyond the current average, the
* average is replaced by the peak. This is essentially used to measure peak
* loads in the scheduler, reason why it is provided as a local variant that
* does not involve atomic operations.
*/
static inline uint swrate_add_peak_local(uint *sum, uint n, uint v)
{
uint old_sum, new_sum;
old_sum = *sum;
if (v * n > old_sum)
new_sum = v * n;
else
new_sum = old_sum - (old_sum + n - 1) / n + v;
*sum = new_sum;
return new_sum;
}
/* Returns the average sample value for the sum <sum> over a sliding window of
* <n> samples. Better if <n> is a power of two. It must be the same <n> as the
* one used above in all additions.

View File

@ -79,7 +79,7 @@
#define GTUNE_DISABLE_H2_WEBSOCKET (1<<21)
#define GTUNE_DISABLE_ACTIVE_CLOSE (1<<22)
#define GTUNE_QUICK_EXIT (1<<23)
#define GTUNE_COLLECT_LIBS (1<<24)
/* (1<<24) unused */
/* (1<<25) unused */
#define GTUNE_USE_FAST_FWD (1<<26)
#define GTUNE_LISTENER_MQ_FAIR (1<<27)

View File

@ -58,10 +58,6 @@ extern int devnullfd;
extern int fileless_mode;
extern struct cfgfile fileless_cfg;
/* storage for collected libs */
extern void *lib_storage;
extern size_t lib_size;
struct proxy;
struct server;
int main(int argc, char **argv);

View File

@ -5,6 +5,7 @@
#include <haproxy/hstream-t.h>
struct task *sc_hstream_io_cb(struct task *t, void *ctx, unsigned int state);
int hstream_wake(struct stconn *sc);
void hstream_shutdown(struct stconn *sc);
void *hstream_new(struct session *sess, struct stconn *sc, struct buffer *input);

View File

@ -290,36 +290,6 @@ static inline int http_status_matches(const long *array, uint status)
return ha_bit_test(status - 100, array);
}
/* This function returns 1 if the header is one of the immutable headers.
* Forbidden headers are the ones that must not be rewritten. Function returns
* 0 if a header can be rewritten
*/
static inline int is_immutable_header(struct ist hdr)
{
switch (hdr.len) {
case 6:
return isteqi(hdr, ist("expect"));
case 7:
return isteqi(hdr, ist("trailer")) ||
isteqi(hdr, ist("upgrade"));
case 10:
return isteqi(hdr, ist("connection")) ||
isteqi(hdr, ist("keep-alive"));
case 14:
return isteqi(hdr, ist("content-length"));
case 16:
return isteqi(hdr, ist("proxy-connection"));
case 17:
return isteqi(hdr, ist("transfer-encoding"));
case 18:
return isteqi(hdr, ist("proxy-authenticate"));
case 19:
return isteqi(hdr, ist("proxy-authorization"));
default:
return 0;
}
}
#endif /* _HAPROXY_HTTP_H */
/*

View File

@ -93,22 +93,4 @@ struct http_errors {
struct list list; /* http-errors list */
};
/* Indicates the keyword origin of an http-error definition. This is used in
* <conf_errors> type to indicate which part of the internal union should be
* manipulated.
*/
enum http_err_directive {
HTTP_ERR_DIRECTIVE_SECTION = 0, /* "errorfiles" keyword referencing a http-errors section */
HTTP_ERR_DIRECTIVE_INLINE, /* "errorfile" keyword with inline error definition */
};
/* Used with "errorfiles" directives. It indicates for each known HTTP error
* status codes if they are defined in the target http-errors section.
*/
enum http_err_import {
HTTP_ERR_IMPORT_NO = 0,
HTTP_ERR_IMPORT_IMPLICIT, /* import every errcode defined in a section */
HTTP_ERR_IMPORT_EXPLICIT, /* import a specific errcode from a section */
};
#endif /* _HAPROXY_HTTP_HTX_T_H */

View File

@ -78,7 +78,6 @@ struct buffer *http_load_errorfile(const char *file, char **errmsg);
struct buffer *http_load_errormsg(const char *key, const struct ist msg, char **errmsg);
struct buffer *http_parse_errorfile(int status, const char *file, char **errmsg);
struct buffer *http_parse_errorloc(int errloc, int status, const char *url, char **errmsg);
int proxy_check_http_errors(struct proxy *px);
int proxy_dup_default_conf_errors(struct proxy *curpx, const struct proxy *defpx, char **errmsg);
void proxy_release_conf_errors(struct proxy *px);

View File

@ -37,7 +37,6 @@ struct htx_blk *htx_add_blk(struct htx *htx, enum htx_blk_type type, uint32_t bl
struct htx_blk *htx_remove_blk(struct htx *htx, struct htx_blk *blk);
struct htx_ret htx_find_offset(struct htx *htx, uint32_t offset);
void htx_truncate(struct htx *htx, uint32_t offset);
void htx_truncate_blk(struct htx *htx, struct htx_blk *blk);
struct htx_ret htx_drain(struct htx *htx, uint32_t max);
struct htx_blk *htx_replace_blk_value(struct htx *htx, struct htx_blk *blk,
@ -57,16 +56,6 @@ size_t htx_add_data(struct htx *htx, const struct ist data);
struct htx_blk *htx_add_last_data(struct htx *htx, struct ist data);
void htx_move_blk_before(struct htx *htx, struct htx_blk **blk, struct htx_blk **ref);
int htx_append_msg(struct htx *dst, const struct htx *src);
struct buffer *htx_move_to_small_buffer(struct buffer *dst, struct buffer *src);
struct buffer *htx_move_to_large_buffer(struct buffer *dst, struct buffer *src);
struct buffer *htx_copy_to_small_buffer(struct buffer *dst, struct buffer *src);
struct buffer *htx_copy_to_large_buffer(struct buffer *dst, struct buffer *src);
#define HTX_XFER_DEFAULT 0x00000000 /* Default XFER: no partial xfer / remove blocks from source */
#define HTX_XFER_KEEP_SRC_BLKS 0x00000001 /* Don't remove xfer blocks from source messages during xfer */
#define HTX_XFER_PARTIAL_HDRS_COPY 0x00000002 /* Allow partial copy of headers and trailers part */
#define HTX_XFER_HDRS_ONLY 0x00000003 /* Only Transfer header blocks (start-line, header and EOH) */
size_t htx_xfer(struct htx *dst, struct htx *src, size_t count, unsigned int flags);
/* Functions and macros to get parts of the start-line or length of these
* parts. Request and response start-lines are both composed of 3 parts.

View File

@ -20,11 +20,6 @@ extern struct list server_deinit_list;
extern struct list per_thread_free_list;
extern struct list per_thread_deinit_list;
/* initcall caller location */
extern const struct initcall *caller_initcall;
extern const char *caller_file;
extern int caller_line;
void hap_register_pre_check(int (*fct)());
void hap_register_post_check(int (*fct)());
void hap_register_post_proxy_check(int (*fct)(struct proxy *));

View File

@ -77,8 +77,6 @@ struct initcall {
void *arg1;
void *arg2;
void *arg3;
const char *loc_file; /* file where the call is declared, or NULL */
int loc_line; /* line where the call is declared, or NULL */
#if defined(USE_OBSOLETE_LINKER)
void *next;
#endif
@ -109,8 +107,6 @@ struct initcall {
.arg1 = (void *)(a1), \
.arg2 = (void *)(a2), \
.arg3 = (void *)(a3), \
.loc_file = __FILE__, \
.loc_line = linenum, \
} : NULL
@ -135,8 +131,6 @@ __attribute__((constructor)) static void __initcb_##linenum() \
.arg1 = (void *)(a1), \
.arg2 = (void *)(a2), \
.arg3 = (void *)(a3), \
.loc_file = __FILE__, \
.loc_line = linenum, \
}; \
if (stg < STG_SIZE) { \
entry.next = __initstg[stg]; \
@ -235,15 +229,8 @@ extern struct initcall *__initstg[STG_SIZE];
const struct initcall **ptr; \
if (stg >= STG_SIZE) \
break; \
FOREACH_INITCALL(ptr, stg) { \
caller_initcall = *ptr; \
caller_file = (*ptr)->loc_file; \
caller_line = (*ptr)->loc_line; \
FOREACH_INITCALL(ptr, stg) \
(*ptr)->fct((*ptr)->arg1, (*ptr)->arg2, (*ptr)->arg3); \
caller_initcall = NULL; \
caller_file = NULL; \
caller_line = 0; \
} \
} while (0)
#else // USE_OBSOLETE_LINKER
@ -256,15 +243,8 @@ extern struct initcall *__initstg[STG_SIZE];
const struct initcall *ptr; \
if (stg >= STG_SIZE) \
break; \
FOREACH_INITCALL(ptr, stg) { \
caller_initcall = ptr; \
caller_file = (ptr)->loc_file; \
caller_line = (ptr)->loc_line; \
FOREACH_INITCALL(ptr, stg) \
(ptr)->fct((ptr)->arg1, (ptr)->arg2, (ptr)->arg3); \
caller_initcall = NULL; \
caller_file = NULL; \
caller_line = 0; \
} \
} while (0)
#endif // USE_OBSOLETE_LINKER

View File

@ -27,7 +27,7 @@
#ifdef USE_OPENSSL
enum jwt_alg jwt_parse_alg(const char *alg_str, unsigned int alg_len);
int jwt_tokenize(const struct buffer *jwt, struct jwt_item *items, unsigned int item_num);
int jwt_tokenize(const struct buffer *jwt, struct jwt_item *items, unsigned int *item_num);
int jwt_tree_load_cert(char *path, int pathlen, int tryload_cert, const char *file, int line, char **err);
enum jwt_vrfy_status jwt_verify(const struct buffer *token, const struct buffer *alg,

View File

@ -42,8 +42,6 @@ extern char clf_tcp_log_format[];
extern char default_http_log_format[];
extern char clf_http_log_format[];
extern char default_https_log_format[];
extern char keylog_format_fc[];
extern char keylog_format_bc[];
extern char default_rfc5424_sd_log_format[];

View File

@ -47,7 +47,6 @@ enum obj_type {
OBJ_TYPE_DGRAM, /* object is a struct quic_dgram */
#endif
OBJ_TYPE_HATERM, /* object is a struct hstream */
OBJ_TYPE_ACME_RSLV, /* object is a struct acme_rslv */
OBJ_TYPE_ENTRIES /* last one : number of entries */
} __attribute__((packed)) ;

View File

@ -22,7 +22,6 @@
#ifndef _HAPROXY_OBJ_TYPE_H
#define _HAPROXY_OBJ_TYPE_H
#include <haproxy/acme_resolvers-t.h>
#include <haproxy/api.h>
#include <haproxy/applet-t.h>
#include <haproxy/check-t.h>
@ -46,18 +45,17 @@ static inline enum obj_type obj_type(const enum obj_type *t)
static inline const char *obj_type_name(const enum obj_type *t)
{
switch (obj_type(t)) {
case OBJ_TYPE_NONE: return "NONE";
case OBJ_TYPE_LISTENER: return "LISTENER";
case OBJ_TYPE_PROXY: return "PROXY";
case OBJ_TYPE_SERVER: return "SERVER";
case OBJ_TYPE_APPLET: return "APPLET";
case OBJ_TYPE_APPCTX: return "APPCTX";
case OBJ_TYPE_CONN: return "CONN";
case OBJ_TYPE_SRVRQ: return "SRVRQ";
case OBJ_TYPE_SC: return "SC";
case OBJ_TYPE_STREAM: return "STREAM";
case OBJ_TYPE_CHECK: return "CHECK";
case OBJ_TYPE_ACME_RSLV: return "ACME_RSLV";
case OBJ_TYPE_NONE: return "NONE";
case OBJ_TYPE_LISTENER: return "LISTENER";
case OBJ_TYPE_PROXY: return "PROXY";
case OBJ_TYPE_SERVER: return "SERVER";
case OBJ_TYPE_APPLET: return "APPLET";
case OBJ_TYPE_APPCTX: return "APPCTX";
case OBJ_TYPE_CONN: return "CONN";
case OBJ_TYPE_SRVRQ: return "SRVRQ";
case OBJ_TYPE_SC: return "SC";
case OBJ_TYPE_STREAM: return "STREAM";
case OBJ_TYPE_CHECK: return "CHECK";
#ifdef USE_QUIC
case OBJ_TYPE_DGRAM: return "DGRAM";
#endif
@ -205,18 +203,6 @@ static inline struct hstream *objt_hstream(enum obj_type *t)
return __objt_hstream(t);
}
static inline struct acme_rslv *__objt_acme_rslv(enum obj_type *t)
{
return container_of(t, struct acme_rslv, obj_type);
}
static inline struct acme_rslv *objt_acme_rslv(enum obj_type *t)
{
if (!t || *t != OBJ_TYPE_ACME_RSLV)
return NULL;
return __objt_acme_rslv(t);
}
#ifdef USE_QUIC
static inline struct quic_dgram *__objt_dgram(enum obj_type *t)
{
@ -234,18 +220,17 @@ static inline struct quic_dgram *objt_dgram(enum obj_type *t)
static inline void *obj_base_ptr(enum obj_type *t)
{
switch (obj_type(t)) {
case OBJ_TYPE_NONE: return NULL;
case OBJ_TYPE_LISTENER: return __objt_listener(t);
case OBJ_TYPE_PROXY: return __objt_proxy(t);
case OBJ_TYPE_SERVER: return __objt_server(t);
case OBJ_TYPE_APPLET: return __objt_applet(t);
case OBJ_TYPE_APPCTX: return __objt_appctx(t);
case OBJ_TYPE_CONN: return __objt_conn(t);
case OBJ_TYPE_SRVRQ: return __objt_resolv_srvrq(t);
case OBJ_TYPE_SC: return __objt_sc(t);
case OBJ_TYPE_STREAM: return __objt_stream(t);
case OBJ_TYPE_CHECK: return __objt_check(t);
case OBJ_TYPE_ACME_RSLV: return __objt_acme_rslv(t);
case OBJ_TYPE_NONE: return NULL;
case OBJ_TYPE_LISTENER: return __objt_listener(t);
case OBJ_TYPE_PROXY: return __objt_proxy(t);
case OBJ_TYPE_SERVER: return __objt_server(t);
case OBJ_TYPE_APPLET: return __objt_applet(t);
case OBJ_TYPE_APPCTX: return __objt_appctx(t);
case OBJ_TYPE_CONN: return __objt_conn(t);
case OBJ_TYPE_SRVRQ: return __objt_resolv_srvrq(t);
case OBJ_TYPE_SC: return __objt_sc(t);
case OBJ_TYPE_STREAM: return __objt_stream(t);
case OBJ_TYPE_CHECK: return __objt_check(t);
#ifdef USE_QUIC
case OBJ_TYPE_DGRAM: return __objt_dgram(t);
#endif

View File

@ -394,12 +394,6 @@ static inline unsigned long ERR_peek_error_func(const char **func)
#define __OPENSSL_110_CONST__
#endif
#if (HA_OPENSSL_VERSION_NUMBER >= 0x40000000L) && (!defined(USE_OPENSSL_WOLFSSL))
#define __X509_NAME_CONST__ const
#else
#define __X509_NAME_CONST__
#endif
/* ERR_remove_state() was deprecated in 1.0.0 in favor of
* ERR_remove_thread_state(), which was in turn deprecated in
* 1.1.0 and does nothing anymore. Let's simply silently kill

View File

@ -124,12 +124,6 @@ static inline int real_family(int ss_family)
return fam ? fam->real_family : AF_UNSPEC;
}
static inline int proto_is_quic(const struct protocol *proto)
{
return (proto->proto_type == PROTO_TYPE_DGRAM &&
proto->xprt_type == PROTO_TYPE_STREAM);
}
#endif /* _HAPROXY_PROTOCOL_H */
/*

View File

@ -117,9 +117,10 @@ enum PR_SRV_STATE_FILE {
#define PR_O_HTTP_DROP_REQ_TRLS 0x04000000 /* Drop the request trailers when forwarding to the server */
#define PR_O_HTTP_DROP_RES_TRLS 0x08000000 /* Drop response trailers when forwarding to the client */
/* unused: 0x10000000 */
#define PR_O_TCPCHK_SSL 0x10000000 /* at least one TCPCHECK connect rule requires SSL */
#define PR_O_CONTSTATS 0x20000000 /* continuous counters */
/* unused: 0x40000000..0x80000000 */
#define PR_O_DISABLE404 0x40000000 /* Disable a server on a 404 response to a health-check */
/* unused: 0x80000000 */
/* bits for proxy->options2 */
#define PR_O2_SPLIC_REQ 0x00000001 /* transfer requests using linux kernel's splice() */
@ -144,7 +145,7 @@ enum PR_SRV_STATE_FILE {
#define PR_O2_NODELAY 0x00020000 /* fully interactive mode, never delay outgoing data */
#define PR_O2_USE_PXHDR 0x00040000 /* use Proxy-Connection for proxy requests */
/* unused: 0x00080000 */
#define PR_O2_CHK_SNDST 0x00080000 /* send the state of each server along with HTTP health checks */
#define PR_O2_SRC_ADDR 0x00100000 /* get the source ip and port for logs */
@ -155,17 +156,14 @@ enum PR_SRV_STATE_FILE {
#define PR_O2_RSTRICT_REQ_HDR_NAMES_NOOP 0x01000000 /* preserve request header names containing chars outside of [0-9a-zA-Z-] charset */
#define PR_O2_RSTRICT_REQ_HDR_NAMES_MASK 0x01c00000 /* mask for restrict-http-header-names option */
/* server health checks */
#define PR_O2_CHK_NONE 0x00000000 /* no L7 health checks configured (TCP by default) */
#define PR_O2_TCPCHK_CHK 0x02000000 /* use TCPCHK check for server health */
#define PR_O2_EXT_CHK 0x04000000 /* use external command for server health */
#define PR_O2_CHK_ANY 0x06000000 /* Mask to cover any check */
/* unused : 0x02000000 ... 0x08000000 */
#define PR_O2_USE_SBUF_QUEUE 0x08000000 /* use small buffer for request when stream are queued*/
#define PR_O2_USE_SBUF_L7_RETRY 0x10000000 /* use small buffer for request when L7 retires are enabled */
#define PR_O2_USE_SBUF_CHECK 0x20000000 /* use small buffer for request's healthchecks */
#define PR_O2_USE_SBUF_ALL 0x38000000 /* all flags for use-large-buffer option */
/* unused : 0x40000000 ... 0x80000000 */
/* server health checks */
#define PR_O2_CHK_NONE 0x00000000 /* no L7 health checks configured (TCP by default) */
#define PR_O2_TCPCHK_CHK 0x90000000 /* use TCPCHK check for server health */
#define PR_O2_EXT_CHK 0xA0000000 /* use external command for server health */
/* unused: 0xB0000000 to 0xF000000, reserved for health checks */
#define PR_O2_CHK_ANY 0xF0000000 /* Mask to cover any check */
/* end of proxy->options2 */
/* bits for proxy->options3 */
@ -243,12 +241,12 @@ enum PR_SRV_STATE_FILE {
/* Proxy flags */
#define PR_FL_DISABLED 0x00000001 /* The proxy was disabled in the configuration (not at runtime) */
#define PR_FL_STOPPED 0x00000002 /* The proxy was stopped */
#define PR_FL_DEF_EXPLICIT_MODE 0x00000004 /* Proxy mode is explicitly defined - only used for defaults instance */
#define PR_FL_DEF_EXPLICIT_MODE 0x00000004 /* Proxy mode is explicitely defined - only used for defaults instance */
#define PR_FL_EXPLICIT_REF 0x00000008 /* The default proxy is explicitly referenced by another proxy */
#define PR_FL_IMPLICIT_REF 0x00000010 /* The default proxy is implicitly referenced by another proxy */
#define PR_FL_PAUSED 0x00000020 /* The proxy was paused at run time (reversible) */
#define PR_FL_CHECKED 0x00000040 /* The proxy configuration was fully checked (including postparsing checks) */
#define PR_FL_BE_UNPUBLISHED 0x00000080 /* The proxy cannot be targeted by content switching rules */
#define PR_FL_BE_UNPUBLISHED 0x00000080 /* The proxy cannot be targetted by content switching rules */
#define PR_FL_DELETED 0x00000100 /* Proxy has been deleted and must be manipulated with care */
#define PR_FL_NON_PURGEABLE 0x00000200 /* Proxy referenced by config elements which prevent its runtime removal. */
@ -444,7 +442,7 @@ struct proxy {
struct stktable *table; /* table for storing sticking streams */
struct task *task; /* the associated task, mandatory to manage rate limiting, stopping and resource shortage, NULL if disabled */
struct tcpcheck tcpcheck; /* tcp-check to use to perform a health-check */
struct tcpcheck_rules tcpcheck_rules; /* tcp-check send / expect rules */
char *check_command; /* Command to use for external agent checks */
char *check_path; /* PATH environment to use for external agent checks */
struct http_reply *replies[HTTP_ERR_SIZE]; /* HTTP replies for known errors */

View File

@ -72,7 +72,6 @@ extern struct pool_head *resolv_requester_pool;
/* dns record types (non exhaustive list) */
#define DNS_RTYPE_A 1 /* IPv4 address */
#define DNS_RTYPE_CNAME 5 /* canonical name */
#define DNS_RTYPE_TXT 16 /* TXT */
#define DNS_RTYPE_AAAA 28 /* IPv6 address */
#define DNS_RTYPE_SRV 33 /* SRV record */
#define DNS_RTYPE_OPT 41 /* OPT */

View File

@ -24,7 +24,6 @@
#define _HAPROXY_SAMPLE_T_H
#include <haproxy/api-t.h>
#include <haproxy/tinfo-t.h>
#include <haproxy/sample_data-t.h>
/* input and output sample types
@ -266,7 +265,6 @@ struct sample_conv {
unsigned int in_type; /* expected input sample type */
unsigned int out_type; /* output sample type */
void *private; /* private values. only used by maps and Lua */
struct thread_exec_ctx exec_ctx; /* execution context */
};
/* sample conversion expression */
@ -290,7 +288,6 @@ struct sample_fetch {
unsigned int use; /* fetch source (SMP_USE_*) */
unsigned int val; /* fetch validity (SMP_VAL_*) */
void *private; /* private values. only used by Lua */
struct thread_exec_ctx exec_ctx; /* execution context */
};
/* sample expression */

View File

@ -36,10 +36,6 @@
void sc_update_rx(struct stconn *sc);
void sc_update_tx(struct stconn *sc);
void sc_abort(struct stconn *sc);
void sc_shutdown(struct stconn *sc);
void sc_chk_rcv(struct stconn *sc);
struct task *sc_conn_io_cb(struct task *t, void *ctx, unsigned int state);
int sc_conn_sync_recv(struct stconn *sc);
int sc_conn_sync_send(struct stconn *sc);
@ -364,6 +360,38 @@ static inline int sc_is_recv_allowed(const struct stconn *sc)
return !(sc->flags & (SC_FL_WONT_READ|SC_FL_NEED_BUFF|SC_FL_NEED_ROOM));
}
/* This is to be used after making some room available in a channel. It will
* return without doing anything if the stream connector's RX path is blocked.
* It will automatically mark the stream connector as busy processing the end
* point in order to avoid useless repeated wakeups.
* It will then call ->chk_rcv() to enable receipt of new data.
*/
static inline void sc_chk_rcv(struct stconn *sc)
{
if (sc_ep_test(sc, SE_FL_APPLET_NEED_CONN) &&
sc_state_in(sc_opposite(sc)->state, SC_SB_RDY|SC_SB_EST|SC_SB_DIS|SC_SB_CLO)) {
sc_ep_clr(sc, SE_FL_APPLET_NEED_CONN);
sc_ep_report_read_activity(sc);
}
if (!sc_is_recv_allowed(sc))
return;
if (!sc_state_in(sc->state, SC_SB_RDY|SC_SB_EST))
return;
sc_ep_set(sc, SE_FL_HAVE_NO_DATA);
if (likely(sc->app_ops->chk_rcv))
sc->app_ops->chk_rcv(sc);
}
/* Calls chk_snd on the endpoint using the data layer */
static inline void sc_chk_snd(struct stconn *sc)
{
if (likely(sc->app_ops->chk_snd))
sc->app_ops->chk_snd(sc);
}
/* Perform a synchronous receive using the right version, depending the endpoing
* is a connection or an applet.
@ -508,10 +536,24 @@ static inline void sc_schedule_abort(struct stconn *sc)
sc->flags |= SC_FL_ABRT_WANTED;
}
/* Abort the SC and notify the endpoint using the data layer */
static inline void sc_abort(struct stconn *sc)
{
if (likely(sc->app_ops->abort))
sc->app_ops->abort(sc);
}
/* Schedule a shutdown for the SC */
static inline void sc_schedule_shutdown(struct stconn *sc)
{
sc->flags |= SC_FL_SHUT_WANTED;
}
/* Shutdown the SC and notify the endpoint using the data layer */
static inline void sc_shutdown(struct stconn *sc)
{
if (likely(sc->app_ops->shutdown))
sc->app_ops->shutdown(sc);
}
#endif /* _HAPROXY_SC_STRM_H */

View File

@ -220,12 +220,8 @@ static inline void srv_inc_sess_ctr(struct server *s)
/* set the time of last session on the designated server */
static inline void srv_set_sess_last(struct server *s)
{
if (s->counters.shared.tg) {
uint now_sec = ns_to_sec(now_ms);
if (HA_ATOMIC_LOAD(&s->counters.shared.tg[tgid - 1]->last_sess) != now_sec)
HA_ATOMIC_STORE(&s->counters.shared.tg[tgid - 1]->last_sess, now_sec);
}
if (s->counters.shared.tg)
HA_ATOMIC_STORE(&s->counters.shared.tg[tgid - 1]->last_sess, ns_to_sec(now_ns));
}
/* returns the current server throttle rate between 0 and 100% */

View File

@ -339,7 +339,7 @@ struct global_ssl {
char **passphrase_cmd;
int passphrase_cmd_args_cnt;
unsigned int certificate_compression:1; /* allow to explicitly disable certificate compression */
unsigned int certificate_compression:1; /* allow to explicitely disable certificate compression */
};
/* The order here matters for picking a default context,

View File

@ -34,10 +34,10 @@ int cert_get_pkey_algo(X509 *crt, struct buffer *out);
int ssl_sock_get_serial(X509 *crt, struct buffer *out);
int ssl_sock_crt2der(X509 *crt, struct buffer *out);
int ssl_sock_get_time(ASN1_TIME *tm, struct buffer *out);
int ssl_sock_get_dn_entry(__X509_NAME_CONST__ X509_NAME *a, const struct buffer *entry, int pos,
int ssl_sock_get_dn_entry(X509_NAME *a, const struct buffer *entry, int pos,
struct buffer *out);
int ssl_sock_get_dn_formatted(__X509_NAME_CONST__ X509_NAME *a, const struct buffer *format, struct buffer *out);
int ssl_sock_get_dn_oneline(__X509_NAME_CONST__ X509_NAME *a, struct buffer *out);
int ssl_sock_get_dn_formatted(X509_NAME *a, const struct buffer *format, struct buffer *out);
int ssl_sock_get_dn_oneline(X509_NAME *a, struct buffer *out);
X509* ssl_sock_get_peer_certificate(SSL *ssl);
X509* ssl_sock_get_verified_chain_root(SSL *ssl);
unsigned int openssl_version_parser(const char *version);

View File

@ -36,7 +36,7 @@ struct shm_stats_file_hdr {
/* 2 bytes hole */
uint global_now_ms; /* global monotonic date (ms) common to all processes using the shm */
ullong global_now_ns; /* global monotonic date (ns) common to all processes using the shm */
ALWAYS_PAD(8); // 8 bytes hole
llong now_offset; /* offset applied to global monotonic date on startup */
/* each process uses one slot and is identified using its pid, max 64 in order
* to be able to use bitmask to refer to a process and then look its pid in the
* "slots.pid" map

View File

@ -37,7 +37,7 @@
#define STAT_F_CHUNKED 0x00000040 /* use chunked encoding (HTTP/1.1) */
#define STAT_F_JSON_SCHM 0x00000080 /* dump the json schema */
#define STAT_F_SHOWVER 0x00000100 /* conf: report the version and reldate */
#define STAT_F_HIDEVER 0x00000100 /* conf: do not report the version and reldate */
#define STAT_F_SHNODE 0x00000200 /* conf: show node name */
#define STAT_F_SHDESC 0x00000400 /* conf: show description */
#define STAT_F_SHLGNDS 0x00000800 /* conf: show legends */

View File

@ -73,9 +73,7 @@ enum se_flags {
SE_FL_DETACHED = 0x00000010, /* The endpoint is detached (no mux/no applet) */
SE_FL_ORPHAN = 0x00000020, /* The endpoint is orphan (no stream connector) */
SE_FL_APP_STARTED= 0x00000040, /* the application layer has really started */
/* unused: 0x00000080 */
/* unused: 0x00000040 .. 0x00000080 */
SE_FL_SHRD = 0x00000100, /* read shut, draining extra data */
SE_FL_SHRR = 0x00000200, /* read shut, resetting extra data */
@ -137,12 +135,12 @@ static forceinline char *se_show_flags(char *buf, size_t len, const char *delim,
_(0);
/* flags */
_(SE_FL_T_MUX, _(SE_FL_T_APPLET, _(SE_FL_DETACHED, _(SE_FL_ORPHAN,
_(SE_FL_APP_STARTED, _(SE_FL_SHRD, _(SE_FL_SHRR, _(SE_FL_SHWN, _(SE_FL_SHWS,
_(SE_FL_SHRD, _(SE_FL_SHRR, _(SE_FL_SHWN, _(SE_FL_SHWS,
_(SE_FL_NOT_FIRST, _(SE_FL_WEBSOCKET, _(SE_FL_EOI, _(SE_FL_EOS,
_(SE_FL_ERROR, _(SE_FL_ERR_PENDING, _(SE_FL_RCV_MORE,
_(SE_FL_WANT_ROOM, _(SE_FL_EXP_NO_DATA, _(SE_FL_MAY_FASTFWD_PROD, _(SE_FL_MAY_FASTFWD_CONS,
_(SE_FL_WAIT_FOR_HS, _(SE_FL_KILL_CONN, _(SE_FL_WAIT_DATA,
_(SE_FL_WONT_CONSUME, _(SE_FL_HAVE_NO_DATA, _(SE_FL_APPLET_NEED_CONN))))))))))))))))))))))))));
_(SE_FL_WONT_CONSUME, _(SE_FL_HAVE_NO_DATA, _(SE_FL_APPLET_NEED_CONN)))))))))))))))))))))))));
/* epilogue */
_(~0U);
return buf;
@ -351,6 +349,19 @@ struct sedesc {
unsigned long long kop; /* Known outgoing payload length (see above) */
};
/* sc_app_ops describes the application layer's operations and notification
* callbacks when I/O activity is reported and to use to perform shutr/shutw.
* There are very few combinations in practice (strm/chk <-> none/mux/applet).
*/
struct sc_app_ops {
void (*chk_rcv)(struct stconn *); /* chk_rcv function, may not be null */
void (*chk_snd)(struct stconn *); /* chk_snd function, may not be null */
void (*abort)(struct stconn *); /* abort function, may not be null */
void (*shutdown)(struct stconn *); /* shutdown function, may not be null */
int (*wake)(struct stconn *); /* data-layer callback to report activity */
char name[8]; /* data layer name, zero-terminated */
};
/*
* This structure describes the elements of a connection relevant to a stream
*/
@ -372,6 +383,7 @@ struct stconn {
struct wait_event wait_event; /* We're in a wait list */
struct sedesc *sedesc; /* points to the stream endpoint descriptor */
enum obj_type *app; /* points to the applicative point (stream or check) */
const struct sc_app_ops *app_ops; /* general operations used at the app layer */
struct sockaddr_storage *src; /* source address (pool), when known, otherwise NULL */
struct sockaddr_storage *dst; /* destination address (pool), when known, otherwise NULL */
};

View File

@ -45,7 +45,8 @@ void se_shutdown(struct sedesc *sedesc, enum se_shut_mode mode);
struct stconn *sc_new_from_endp(struct sedesc *sedesc, struct session *sess, struct buffer *input);
struct stconn *sc_new_from_strm(struct stream *strm, unsigned int flags);
struct stconn *sc_new_from_check(struct check *check);
struct stconn *sc_new_from_check(struct check *check, unsigned int flags);
struct stconn *sc_new_from_haterm(struct sedesc *sd, struct session *sess, struct buffer *input);
void sc_free(struct stconn *sc);
int sc_attach_mux(struct stconn *sc, void *target, void *ctx);
@ -56,8 +57,6 @@ void sc_destroy(struct stconn *sc);
int sc_reset_endp(struct stconn *sc);
struct appctx *sc_applet_create(struct stconn *sc, struct applet *app);
int sc_applet_process(struct stconn *sc);
int sc_conn_process(struct stconn *sc);
void sc_conn_prepare_endp_upgrade(struct stconn *sc);
void sc_conn_abort_endp_upgrade(struct stconn *sc);
@ -350,6 +349,16 @@ static inline struct hstream *sc_hstream(const struct stconn *sc)
return NULL;
}
/* Returns the name of the application layer's name for the stconn,
* or "NONE" when none is attached.
*/
static inline const char *sc_get_data_name(const struct stconn *sc)
{
if (!sc->app_ops)
return "NONE";
return sc->app_ops->name;
}
/* Returns non-zero if the stream connector's Rx path is blocked because of
* lack of room in the input buffer. This usually happens after applets failed
* to deliver data into the channel's buffer and reported it via sc_need_room().
@ -451,7 +460,7 @@ static inline size_t se_nego_ff(struct sedesc *se, struct buffer *input, size_t
goto end;
}
ret = CALL_MUX_WITH_RET(mux, nego_fastfwd(se->sc, input, count, flags));
ret = mux->nego_fastfwd(se->sc, input, count, flags);
if (se->iobuf.flags & IOBUF_FL_FF_BLOCKED) {
sc_ep_report_blocked_send(se->sc, 0);
@ -484,7 +493,7 @@ static inline size_t se_done_ff(struct sedesc *se)
size_t to_send = se_ff_data(se);
BUG_ON(!mux->done_fastfwd);
ret = CALL_MUX_WITH_RET(mux, done_fastfwd(se->sc));
ret = mux->done_fastfwd(se->sc);
if (ret) {
/* Something was forwarded, unblock the zero-copy forwarding.
* If all data was sent, report and send activity.
@ -516,7 +525,7 @@ static inline size_t se_done_ff(struct sedesc *se)
}
}
}
se->sc->bytes_out += ret;
return ret;
}

View File

@ -130,22 +130,20 @@ struct notification {
* on return.
*/
#define TASK_COMMON \
unsigned int state; /* task state : bitfield of TASK_ */ \
int tid; /* tid of task/tasklet. <0 = local for tasklet, unbound for task */ \
struct task *(*process)(struct task *t, void *ctx, unsigned int state); /* the function which processes the task */ \
void *context; /* the task's context */ \
const struct ha_caller *caller; /* call place of last wakeup(); 0 on init, -1 on free */ \
uint32_t wake_date; /* date of the last task wakeup */ \
unsigned int calls; /* number of times process was called */ \
TASK_DEBUG_STORAGE; \
short last_run; /* 16-bit now_ms of last run */
/* a 16- or 48-bit hole remains here and is used by task */
struct { \
unsigned int state; /* task state : bitfield of TASK_ */ \
int tid; /* tid of task/tasklet. <0 = local for tasklet, unbound for task */ \
struct task *(*process)(struct task *t, void *ctx, unsigned int state); /* the function which processes the task */ \
void *context; /* the task's context */ \
const struct ha_caller *caller; /* call place of last wakeup(); 0 on init, -1 on free */ \
uint32_t wake_date; /* date of the last task wakeup */ \
unsigned int calls; /* number of times process was called */ \
TASK_DEBUG_STORAGE; \
}
/* The base for all tasks */
struct task {
TASK_COMMON; /* must be at the beginning! */
short nice; /* task prio from -1024 to +1024 */
int expire; /* next expiration date for this task, in ticks */
struct eb32_node rq; /* ebtree node used to hold the task in the run queue */
/* WARNING: the struct task is often aliased as a struct tasklet when
* it is NOT in the run queue. The tasklet has its struct list here
@ -153,12 +151,14 @@ struct task {
* ever reorder these fields without taking this into account!
*/
struct eb32_node wq; /* ebtree node used to hold the task in the wait queue */
int expire; /* next expiration date for this task, in ticks */
short nice; /* task prio from -1024 to +1024 */
/* 16-bit hole here */
};
/* lightweight tasks, without priority, mainly used for I/Os */
struct tasklet {
TASK_COMMON; /* must be at the beginning! */
/* 48-bit hole here */
struct list list;
/* WARNING: the struct task is often aliased as a struct tasklet when
* it is not in the run queue. The task has its struct rq here where

View File

@ -104,15 +104,10 @@ enum tcpcheck_rule_type {
TCPCHK_ACT_ACTION_KW, /* custom registered action_kw rule. */
};
#define TCPCHK_FL_NONE 0x00000000
#define TCPCHK_FL_UNUSED_TCP_RS 0x00000001 /* An unused tcp-check ruleset exists for the current proxy */
#define TCPCHK_FL_UNUSED_HTTP_RS 0x00000002 /* An unused http-check ruleset exists for the current proxy */
#define TCPCHK_FL_UNUSED_RS 0x00000003 /* Mask for unused ruleset */
#define TCPCHK_FL_USE_SSL 0x00000004 /* tcp-check uses SSL connection */
#define TCPCHK_RULES_NONE 0x00000000
#define TCPCHK_RULES_DISABLE404 0x00000001 /* Disable a server on a 404 response wht HTTP health checks */
#define TCPCHK_RULES_SNDST 0x00000002 /* send the state of each server along with HTTP health checks */
#define TCPCHK_RULES_NONE 0x00000000
#define TCPCHK_RULES_UNUSED_TCP_RS 0x00000001 /* An unused tcp-check ruleset exists */
#define TCPCHK_RULES_UNUSED_HTTP_RS 0x00000002 /* An unused http-check ruleset exists */
#define TCPCHK_RULES_UNUSED_RS 0x00000003 /* Mask for unused ruleset */
#define TCPCHK_RULES_PGSQL_CHK 0x00000010
#define TCPCHK_RULES_REDIS_CHK 0x00000020
@ -126,7 +121,6 @@ enum tcpcheck_rule_type {
/* Unused 0x000000A0..0x00000FF0 (reserved for future proto) */
#define TCPCHK_RULES_TCP_CHK 0x00000FF0
#define TCPCHK_RULES_PROTO_CHK 0x00000FF0 /* Mask to cover protocol check */
#define TCPCHK_RULES_MAY_USE_SBUF 0x00001000 /* checks may try to use small buffers if possible for the request */
struct check;
struct tcpcheck_connect {
@ -233,24 +227,18 @@ struct tcpcheck_var {
struct list list; /* element to chain tcp-check vars */
};
/* a list of tcp-check rules */
struct tcpcheck_rules {
unsigned int flags; /* flags applied to the rules */
struct list *list; /* the list of tcpcheck_rules */
struct list preset_vars; /* The list of variable to preset before executing the ruleset */
};
/* A list of tcp-check rules with a name */
struct tcpcheck_ruleset {
struct list rules; /* the list of tcpcheck_rule */
unsigned int flags; /* flags applied to the rules */
struct ebpt_node node; /* node in the shared tree */
struct {
struct list preset_vars; /* The list of variable to preset for healthcheck sections */
unsigned int flags; /* TCPCHECK_FL_* for healthcheck sections */
const char *file; /* file where the section appears */
int line; /* line where the section appears */
} conf; /* config information */
};
struct tcpcheck {
struct tcpcheck_ruleset *rs; /* The tcp-check ruleset to use */
char *healthcheck; /* name of the healthcheck section (NULL if not used) */
struct list preset_vars; /* The list of variable to preset before executing the ruleset */
unsigned int flags; /* TCPCHECK_FL_* */
};
#endif /* _HAPROXY_CHECKS_T_H */

View File

@ -36,7 +36,7 @@ extern struct action_kw_list tcp_check_keywords;
extern struct pool_head *pool_head_tcpcheck_rule;
int tcpcheck_get_step_id(const struct check *check, const struct tcpcheck_rule *rule);
struct tcpcheck_rule *get_first_tcpcheck_rule(const struct tcpcheck_ruleset *rs);
struct tcpcheck_rule *get_first_tcpcheck_rule(const struct tcpcheck_rules *rules);
struct tcpcheck_ruleset *create_tcpcheck_ruleset(const char *name);
struct tcpcheck_ruleset *find_tcpcheck_ruleset(const char *name);
@ -50,9 +50,9 @@ void free_tcpcheck_var(struct tcpcheck_var *var);
int dup_tcpcheck_vars(struct list *dst, const struct list *src);
void free_tcpcheck_vars(struct list *vars);
int add_tcpcheck_expect_str(struct tcpcheck_ruleset *rs, const char *str);
int add_tcpcheck_send_strs(struct tcpcheck_ruleset *rs, const char * const *strs);
int tcpcheck_add_http_rule(struct tcpcheck_rule *chk, struct tcpcheck_ruleset *rs, char **errmsg);
int add_tcpcheck_expect_str(struct tcpcheck_rules *rules, const char *str);
int add_tcpcheck_send_strs(struct tcpcheck_rules *rules, const char * const *strs);
int tcpcheck_add_http_rule(struct tcpcheck_rule *chk, struct tcpcheck_rules *rules, char **errmsg);
void free_tcpcheck_http_hdr(struct tcpcheck_http_hdr *hdr);
@ -83,6 +83,10 @@ struct tcpcheck_rule *parse_tcpcheck_expect(char **args, int cur_arg, struct pro
struct list *rules, unsigned int proto,
const char *file, int line, char **errmsg);
int proxy_parse_tcpcheck(char **args, int section, struct proxy *curpx,
const struct proxy *defpx, const char *file, int line,
char **errmsg);
int proxy_parse_tcp_check_opt(char **args, int cur_arg, struct proxy *curpx, const struct proxy *defpx,
const char *file, int line);
int proxy_parse_redis_check_opt(char **args, int cur_arg, struct proxy *curpx, const struct proxy *defpx,
@ -102,8 +106,6 @@ int proxy_parse_spop_check_opt(char **args, int cur_arg, struct proxy *curpx, co
int proxy_parse_httpchk_opt(char **args, int cur_arg, struct proxy *curpx, const struct proxy *defpx,
const char *file, int line);
int check_server_tcpcheck(struct server *srv);
void tcp_check_keywords_register(struct action_kw_list *kw_list);
/* Return the struct action_kw associated to a keyword */
@ -131,22 +133,6 @@ static inline int tcpchk_rules_type_to_proto_mode(int tcpchk_rules_type)
return mode;
}
static inline const char *tcpcheck_ruleset_type_to_str(struct tcpcheck_ruleset *rs)
{
switch (rs->flags & TCPCHK_RULES_PROTO_CHK) {
case TCPCHK_RULES_PGSQL_CHK: return "PGSQL"; break;
case TCPCHK_RULES_REDIS_CHK: return "REDIS"; break;
case TCPCHK_RULES_SMTP_CHK: return "SMTP"; break;
case TCPCHK_RULES_HTTP_CHK: return "HTTP"; break;
case TCPCHK_RULES_MYSQL_CHK: return "MYSQL"; break;
case TCPCHK_RULES_LDAP_CHK: return "LDAP"; break;
case TCPCHK_RULES_SSL3_CHK: return "SSL3"; break;
case TCPCHK_RULES_AGENT_CHK: return "AGENT"; break;
case TCPCHK_RULES_SPOP_CHK: return "SPOP"; break;
case TCPCHK_RULES_TCP_CHK: return "TCP"; break;
default: return "???"; break;
}
}
#endif /* _HAPROXY_TCPCHECK_H */
/*

View File

@ -75,41 +75,6 @@ enum {
/* we have 4 buffer-wait queues, in highest to lowest emergency order */
#define DYNBUF_NBQ 4
/* execution context, for tracing resource usage or warning origins */
enum thread_exec_ctx_type {
TH_EX_CTX_NONE = 0, /* context not filled */
TH_EX_CTX_OTHER, /* context only known by a generic pointer */
TH_EX_CTX_INITCALL, /* the pointer is an initcall providing file:line */
TH_EX_CTX_CALLER, /* the pointer is an ha_caller of the caller providing file:line etc */
TH_EX_CTX_SMPF, /* directly registered sample fetch function, using .smpf_kwl */
TH_EX_CTX_CONV, /* directly registered converter function, using .conv_kwl */
TH_EX_CTX_FUNC, /* hopefully recognizable function/callback, using .pointer */
TH_EX_CTX_ACTION, /* directly registered action function, using .action_kwl */
TH_EX_CTX_FLT, /* filter whose config is in .flt_conf */
TH_EX_CTX_MUX, /* mux whose mux_ops is in .mux_ops */
TH_EX_CTX_TASK, /* task or tasklet whose function is in .task */
TH_EX_CTX_APPLET, /* applet whose applet is in .applet */
TH_EX_CTX_CLI_KWL, /* CLI keyword list, using .cli_kwl */
};
struct thread_exec_ctx {
enum thread_exec_ctx_type type;
/* 32-bit hole here on 64-bit platforms */
union {
const void *pointer; /* generic pointer (for other) */
const struct initcall *initcall; /* used with TH_EX_CTX_INITCALL */
const struct ha_caller *ha_caller; /* used with TH_EX_CTX_CALLER */
const struct sample_fetch_kw_list *smpf_kwl; /* used with TH_EX_CTX_SMPF */
const struct sample_conv_kw_list *conv_kwl; /* used with TH_EX_CTX_CONV */
const struct action_kw_list *action_kwl; /* used with TH_EX_CTX_ACTION */
const struct flt_conf *flt_conf; /* used with TH_EX_CTX_FLTCONF */
const struct mux_ops *mux_ops; /* used with TH_EX_CTX_MUX */
const struct task *(*task)(struct task *, void *, unsigned int); /* used with TH_EX_CTX_TASK */
const struct applet *applet; /* used with TH_EX_CTX_APPLET */
const struct cli_kw_list *cli_kwl; /* used with TH_EX_CTX_CLI_KWL */
};
};
/* Thread group information. This defines a base and a count of global thread
* IDs which belong to it, and which can be looked up into thread_info/ctx. It
* is set up during parsing and is stable during operation. Thread groups start
@ -207,7 +172,8 @@ struct thread_ctx {
uint64_t curr_mono_time; /* latest system wide monotonic time (leaving poll) */
ulong lock_history; /* history of used locks, see thread.h for more details */
struct thread_exec_ctx exec_ctx; /* current execution context when known, or NULL */
/* around 56 unused bytes here */
// fourth cache line here on 64 bits: accessed mostly using atomic ops
ALWAYS_ALIGN(64);
@ -233,7 +199,6 @@ struct thread_ctx {
struct buffer *last_dump_buffer; /* Copy of last buffer used for a dump; may be NULL or invalid; for post-mortem only */
unsigned long long total_streams; /* Total number of streams created on this thread */
unsigned int stream_cnt; /* Number of streams attached to this thread */
unsigned int rq_tot_peak; /* total run queue size last call */
// around 68 bytes here for shared variables

View File

@ -117,42 +117,4 @@ static inline void thread_set_pin_grp1(struct thread_set *ts, ulong mask)
ts->rel[i] = 0;
}
/* switches the current execution context to <ctx> and returns the previous one
* so that this may even be used to save and restore. Setting EXEC_CTX_NONE
* resets it. It's efficient because it uses a pair of registers on input and
* output.
*/
static inline struct thread_exec_ctx switch_exec_ctx(const struct thread_exec_ctx ctx)
{
const struct thread_exec_ctx prev = th_ctx->exec_ctx;
th_ctx->exec_ctx = ctx;
return prev;
}
/* used to reset the execution context */
#define EXEC_CTX_NONE ((struct thread_exec_ctx){ .type = 0, .pointer = NULL })
/* make an execution context from a type and a pointer */
#define EXEC_CTX_MAKE(_type, _pointer) ((struct thread_exec_ctx){ .type = (_type), .pointer = (_pointer) })
/* execute expression <expr> under context <new_ctx> then restore the previous
* one, and return the expression's return value.
*/
#define EXEC_CTX_WITH_RET(new_ctx, expr) ({ \
const struct thread_exec_ctx __prev_ctx = switch_exec_ctx(new_ctx); \
typeof(expr) __ret = (expr); \
switch_exec_ctx(__prev_ctx); \
__ret; \
})
/* execute expression <expr> under context <new_ctx> then restore the previous
* one. This one has no return value.
*/
#define EXEC_CTX_NO_RET(new_ctx, expr) do { \
const struct thread_exec_ctx __prev_ctx = switch_exec_ctx(new_ctx); \
do { expr; } while (0); \
switch_exec_ctx(__prev_ctx); \
} while (0)
#endif /* _HAPROXY_TINFO_H */

View File

@ -1147,13 +1147,10 @@ void dump_hex(struct buffer *out, const char *pfx, const void *buf, int len, int
int may_access(const void *ptr);
const void *resolve_sym_name(struct buffer *buf, const char *pfx, const void *addr);
const void *resolve_dso_name(struct buffer *buf, const char *pfx, const void *addr);
void make_tar_header(char *output, const char *pfx, const char *fname, const char *link, size_t size, mode_t mode);
int load_file_into_tar(char **storage, size_t *size, const char *pfx, const char *fname, const char *input, const char *link);
const char *get_exec_path(void);
void *get_sym_curr_addr(const char *name);
void *get_sym_next_addr(const char *name);
int dump_libs(struct buffer *output, int with_addr);
void collect_libs(void);
/* Note that this may result in opening libgcc() on first call, so it may need
* to have been called once before chrooting.
@ -1327,62 +1324,6 @@ static inline uint statistical_prng_range(uint range)
return mul32hi(statistical_prng(), range ? range - 1 : 0);
}
/* The functions below are used to hash one or two pointers together and reduce
* the result to fit into a given number of bits. The first part is made of a
* multiplication (and possibly an addition) by one or two prime numbers giving
* a 64-bit number whose center bits are the most distributed, and the second
* part will reuse this value and return a mix of the most variable bits that
* fits in the requested size. The most convenient approach is to directly
* call ptr_hash() / ptr2_hash(), though for some specific use cases where a
* second value could be useful, one may prefer to call the lower level
* operations instead.
*/
/* reduce a 64-bit pointer hash to <bits> bits */
static forceinline uint _ptr_hash_reduce(unsigned long long x, const int bits)
{
if (!bits)
return 0;
if (sizeof(long) == 4)
x ^= x >> 32;
else
x >>= 31 - (bits + 1) / 2;
return x & (~0U >> (-bits & 31));
}
/* single-pointer version, low-level, use ptr_hash() instead */
static forceinline ullong _ptr_hash(const void *p)
{
unsigned long long x = (unsigned long)p;
x *= 0xacd1be85U;
return x;
}
/* two-pointer version, low-level, use ptr2_hash() instead */
static forceinline ullong _ptr2_hash(const void *p1, const void *p2)
{
unsigned long long x = (unsigned long)p1;
unsigned long long y = (unsigned long)p2;
x *= 0xacd1be85U;
y *= 0x9d28e4e9U;
return x ^ y;
}
/* two-pointer plus arg version, low-level, use ptr2_hash_arg() instead */
static forceinline ullong _ptr2_hash_arg(const void *p1, const void *p2, ulong arg)
{
unsigned long long x = (unsigned long)p1;
unsigned long long y = (unsigned long)p2;
x *= 0xacd1be85U;
x += arg;
y *= 0x9d28e4e9U;
return x ^ y;
}
/* returns a hash on <bits> bits of pointer <p> that is suitable for being used
* to compute statistic buckets, in that it's fast and reasonably distributed
* thanks to mixing the bits via a multiplication by a prime number and using
@ -1396,7 +1337,17 @@ static forceinline ullong _ptr2_hash_arg(const void *p1, const void *p2, ulong a
*/
static forceinline uint ptr_hash(const void *p, const int bits)
{
return _ptr_hash_reduce(_ptr_hash(p), bits);
unsigned long long x = (unsigned long)p;
if (!bits)
return 0;
x *= 0xacd1be85U;
if (sizeof(long) == 4)
x ^= x >> 32;
else
x >>= 31 - (bits + 1) / 2;
return x & (~0U >> (-bits & 31));
}
/* Same as above but works on two pointers. It will return the same values
@ -1404,15 +1355,20 @@ static forceinline uint ptr_hash(const void *p, const int bits)
*/
static forceinline uint ptr2_hash(const void *p1, const void *p2, const int bits)
{
return _ptr_hash_reduce(_ptr2_hash(p1, p2), bits);
}
unsigned long long x = (unsigned long)p1;
unsigned long long y = (unsigned long)p2;
/* Same as above but works on two pointers and a long argument. It will return
* the same values if the second pointer is NULL.
*/
static forceinline uint ptr2_hash_arg(const void *p1, const void *p2, ulong arg, const int bits)
{
return _ptr_hash_reduce(_ptr2_hash_arg(p1, p2, arg), bits);
if (!bits)
return 0;
x *= 0xacd1be85U;
y *= 0x9d28e4e9U;
x ^= y;
if (sizeof(long) == 4)
x ^= x >> 32;
else
x >>= 33 - bits / 2;
return x & (~0U >> (-bits & 31));
}
@ -1543,6 +1499,4 @@ void ha_freearray(char ***array);
void ha_memset_s(void *s, int c, size_t n);
void chunk_append_thread_ctx(struct buffer *output, const struct thread_exec_ctx *ctx, const char *pfx, const char *sfx);
#endif /* _HAPROXY_TOOLS_H */

View File

@ -190,8 +190,7 @@ void trace_no_cb(enum trace_level level, uint64_t mask, const struct trace_sourc
void trace_register_source(struct trace_source *source);
int trace_add_cmd(const char *arg_src, char **errmsg);
void trace_parse_cmds(void);
int trace_parse_cmd(const char *arg_src, char **errmsg);
/* return a single char to describe a trace state */
static inline char trace_state_char(enum trace_state st)

View File

@ -1587,7 +1587,7 @@ struct XXH3_state_s {
/*!
* simple alias to preselected XXH3_128bits variant
* simple alias to pre-selected XXH3_128bits variant
*/
XXH_PUBLIC_API XXH_PUREF XXH128_hash_t XXH128(XXH_NOESCAPE const void* data, size_t len, XXH64_hash_t seed);

View File

@ -1,267 +0,0 @@
varnishtest "Health-checks: tests of healthcheck sections"
feature ignore_unknown_macro
#REQUIRE_OPTION=OPENSSL
#REGTEST_TYPE=slow
server s1 {
rxreq
expect req.method == OPTIONS
expect req.url == /
expect req.proto == HTTP/1.0
expect req.http.host == <undef>
txresp
} -start
server s2 {
rxreq
expect req.method == GET
expect req.url == /status
expect req.proto == HTTP/1.1
expect req.http.host == "www.haproxy.org"
txresp
} -start
server s3 {
rxreq
expect req.method == GET
expect req.url == /health
expect req.proto == HTTP/1.1
txresp
} -start
server s4 {
rxreq
expect req.method == GET
expect req.url == /req1
expect req.proto == HTTP/1.1
expect req.http.x-test == "server=srv"
expect req.http.x-haproxy-server-state ~ "UP.+name=be1/srv4"
expect req.bodylen == 0
txresp
accept
rxreq
expect req.method == GET
expect req.url == /req2
expect req.proto == HTTP/1.1
expect req.http.x-test == "server="
expect req.http.x-haproxy-server-state ~ "UP.+name=be1/srv4"
expect req.http.content-length == 17
expect req.bodylen == 17
expect req.body == "health-check body"
txresp
accept
rxreq
expect req.method == GET
expect req.url == /req3
expect req.proto == HTTP/1.0
expect req.http.x-test == <undef>
expect req.http.x-haproxy-server-state ~ "UP.+name=be1/srv4"
expect req.bodylen == 0
txresp
accept
rxreq
expect req.method == GET
expect req.url == /
expect req.proto == HTTP/1.0
expect req.http.x-test == <undef>
expect req.http.x-haproxy-server-state ~ "UP.+name=be1/srv4"
expect req.bodylen == 24
expect req.body == "health-check on be1-srv4"
txresp
} -start
# REDIS
server s5 {
recv 14
send "+PONG\r\n"
} -start
# TCP-CHECK
server s6 {
rxreq
expect req.method == GET
expect req.url == /
expect req.proto == HTTP/1.0
expect req.http.host == "www.haproxy.org"
txresp
} -start
# PgSQL
server s8 {
recv 23
sendhex "52000000170000000A534352414D2D5348412D3235360000"
} -start
# SMTP
server s9 {
send "220 smtp-check.vtc SMTP Server\r\n"
recv 17
send "250-smtp-check.vtc\r\n"
send "250-KEYWORD\r\n"
send "250 LAST KEYWORD\r\n"
recv 6
send "221 smtp-check.vtc closing\r\n"
} -start
# MySQL
server s10 {
sendhex "4A0000000A382E302E3139000A0000006F3C025E6249410D00FFFFFF0200FFC715000000000000000000007C182159106E2761144322200063616368696E675F736861325F70617373776F726400"
recv 47
sendhex "0700000200000002000000"
} -start
# LDAP
server s11 {
recv 14
sendhex "308400000010020101 61 84000000070A01"
sendhex "00 04000400"
} -start
# SPOP
server s12 {
recv 82
sendhex "00000036 65 00000001 0000 0776657273696F6E 0803322E30 0E6D61782D6672616D652D73697A65 03FCF0 060C6361706162696C6974696573 0800"
} -start
syslog S1 -level notice {
recv
expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be1/srv[1-4] succeeded"
recv
expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be1/srv[1-4] succeeded"
recv
expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be1/srv[1-4] succeeded"
recv
expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be1/srv[1-4] succeeded"
} -start
syslog S2 -level notice {
recv
expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be2/srv[0-9]+ succeeded"
recv
expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be2/srv[0-9]+ succeeded"
recv
expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be2/srv[0-9] succeeded"
recv
expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be2/srv[0-9]+ succeeded"
recv
expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be2/srv[0-9]+ succeeded"
recv
expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be2/srv[0-9]+ succeeded"
recv
expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be2/srv[0-9]+ succeeded"
recv
expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be2/srv[0-9]+ succeeded"
} -start
haproxy h1 -conf {
global
.if feature(THREAD)
thread-groups 1
.endif
.if !ssllib_name_startswith(AWS-LC)
tune.ssl.default-dh-param 2048
.endif
defaults
mode tcp
timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
healthcheck http-status
type httpchk GET /status HTTP/1.1 www.haproxy.org
healthcheck http-health
type httpchk
http-check send meth GET uri /health ver HTTP/1.1
healthcheck http-complex
http-check send-state
http-check connect addr ${s4_addr}:${s4_port}
http-check set-var(check.server) "str(srv)"
http-check set-var(check.path) "str(/req1)"
http-check send meth GET uri-lf "%[var(check.path)]" ver HTTP/1.1 hdr x-test "server=%[var(check.server)]"
http-check expect status 200
http-check connect addr ${s4_addr} port ${s4_port}
http-check unset-var(check.server)
http-check set-var(check.path) "str(/req2)"
http-check send meth GET uri-lf "%[var(check.path)]" ver HTTP/1.1 hdr x-test "server=%[var(check.server)]" body "health-check body"
http-check expect rstatus "^2[0-9]{2}"
http-check connect addr ${s4_addr} port ${s4_port}
http-check set-var(check.path) "str(/req3)"
http-check send meth GET uri-lf "%[var(check.path)]"
http-check expect rstatus "^2[0-9]{2}"
http-check connect addr ${s4_addr} port ${s4_port}
http-check unset-var(check.path)
http-check send meth GET uri-lf "%[var(check.path)]" body-lf "health-check on %[be_name]-%[srv_name]"
## implicit expect rule
type httpchk
healthcheck tcpchk
type tcp-check
tcp-check connect
tcp-check send GET\ /\ HTTP/1.0\r\n
tcp-check send Host:\ www.haproxy.org\r\n
tcp-check send \r\n
tcp-check expect rstring (2..|3..)
tcp-check connect addr ${h1_li6_addr} port ${h1_li6_port} ssl
tcp-check send GET\ /\ HTTP/1.0\r\n
tcp-check send Host:\ www.haproxy.org\r\n
tcp-check send \r\n
tcp-check expect rstring (2..|3..)
healthcheck redis
type redis-check
healthcheck sslchk
type ssl-hello-chk
healthcheck pgchk
type pgsql-check user postgres
healthcheck smtpchk
type smtpchk EHLO domain.tld
healthcheck mysqlchk
type mysql-check user user
healthcheck ldapchk
type ldap-check
healthcheck spopchk
type spop-check
listen li6
mode http
bind "fd@${li6}" ssl crt ${testdir}/certs/common.pem
http-request return status 200
backend be1
log ${S1_addr}:${S1_port} daemon
option log-health-checks
option httpchk
server srv1 ${s1_addr}:${s1_port} check inter 100ms rise 1 fall 1
server srv2 ${s2_addr}:${s2_port} check inter 100ms rise 1 fall 1 healthcheck http-status
server srv3 ${s3_addr}:${s3_port} check inter 100ms rise 1 fall 1 healthcheck http-health
server srv4 ${s4_addr}:${s4_port} check inter 100ms rise 1 fall 1 healthcheck http-complex
backend be2
log ${S2_addr}:${S2_port} daemon
option log-health-checks
server srv5 ${s5_addr}:${s5_port} check inter 100ms rise 1 fall 1 healthcheck redis
server srv6 ${s6_addr}:${s6_port} check inter 100ms rise 1 fall 1 healthcheck tcpchk verify none
server srv7 ${h1_li6_addr}:${h1_li6_port} check inter 100ms rise 1 fall 1 healthcheck sslchk
server srv8 ${s8_addr}:${s8_port} check inter 100ms rise 1 fall 1 healthcheck pgchk
server srv9 ${s9_addr}:${s9_port} check inter 100ms rise 1 fall 1 healthcheck smtpchk
server srv10 ${s10_addr}:${s10_port} check inter 100ms rise 1 fall 1 healthcheck mysqlchk
server srv11 ${s11_addr}:${s11_port} check inter 100ms rise 1 fall 1 healthcheck ldapchk
server srv12 ${s12_addr}:${s12_port} check inter 100ms rise 1 fall 1 healthcheck spopchk
} -start
syslog S1 -wait
syslog S2 -wait

View File

@ -1,13 +0,0 @@
-----BEGIN CERTIFICATE-----
MIICBTCCAaugAwIBAgIUN+Ne3W00v5RwrlIBqhub+WHgq3kwCgYIKoZIzj0EAwIw
VzELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGElu
dGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEQMA4GA1UEAwwHZm9vLmJhcjAgFw0yNjAy
MjYxMDM5MjhaGA8yMDUzMDcxNDEwMzkyOFowVzELMAkGA1UEBhMCQVUxEzARBgNV
BAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0
ZDEQMA4GA1UEAwwHZm9vLmJhcjBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABGwE
ope2KbYUXi5bSLGiQmkaxO17SwkVbTqRrXTztIx99xj9qfSrVKFqN3lnaNDXAclG
GnfmU/j7xsEocZdYmPujUzBRMB0GA1UdDgQWBBQZSL9UUhRofXo5X9BoS0XBug4i
DzAfBgNVHSMEGDAWgBQZSL9UUhRofXo5X9BoS0XBug4iDzAPBgNVHRMBAf8EBTAD
AQH/MAoGCCqGSM49BAMCA0gAMEUCIQDFDrvj5p9R7wmMRoJGUuEJu7I2xYtXDcOP
lLE0quJtvwIgWW7vuM3B+ruCslhIrMMqD+DYeguxAxi+aHRVMnBig/c=
-----END CERTIFICATE-----

View File

@ -1,5 +0,0 @@
-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg6qbbYYII1zqqmlDH
hTwJt+JYBe+ELI02yAecAx+nD4yhRANCAARsBKKXtim2FF4uW0ixokJpGsTte0sJ
FW06ka1087SMffcY/an0q1Shajd5Z2jQ1wHJRhp35lP4+8bBKHGXWJj7
-----END PRIVATE KEY-----

View File

@ -16,7 +16,7 @@ feature cmd "$HAPROXY_PROGRAM -cc 'feature(OPENSSL)'"
feature cmd "command -v socat"
feature ignore_unknown_macro
server s1 -repeat 40 {
server s1 -repeat 27 {
rxreq
txresp
} -start
@ -542,44 +542,3 @@ client c27 -connect ${h1_mainfe_sock} {
expect resp.http.x-jwt-verify-RS256-var2 == "1"
} -run
client c28 -connect ${h1_mainfe_sock} {
# Token content : {"alg":"none"}
# {"iss":"joe", "exp":1300819380, "http://example.com/is_root":true}
txreq -url "/none" -hdr "Authorization: Bearer eyJhbGciOiJub25lIn0.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ."
rxresp
expect resp.status == 200
expect resp.http.x-jwt-alg == "none"
expect resp.http.x-jwt-verify == "1"
} -run
client c29 -connect ${h1_mainfe_sock} {
# Invalid Token : too many subparts
txreq -url "/errors" -hdr "Authorization: Bearer eyJhbGciOiJub25lIn0.aa.aa.aa"
rxresp
expect resp.status == 200
expect resp.http.x-jwt-alg == "none"
expect resp.http.x-jwt-verify == "-3"
# Invalid Token : too many subparts
txreq -url "/errors" -hdr "Authorization: Bearer eyJhbGciOiJub25lIn0.aa.aa."
rxresp
expect resp.status == 200
expect resp.http.x-jwt-alg == "none"
expect resp.http.x-jwt-verify == "-3"
# Invalid Token : too few subparts
txreq -url "/errors" -hdr "Authorization: Bearer eyJhbGciOiJub25lIn0.aa"
rxresp
expect resp.status == 200
expect resp.http.x-jwt-alg == "none"
expect resp.http.x-jwt-verify == "-3"
# Invalid Token : no signature but alg different than "none"
txreq -url "/errors" -hdr "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ."
rxresp
expect resp.status == 200
expect resp.http.x-jwt-alg == "RS256"
expect resp.http.x-jwt-verify == "-3"
} -run

View File

@ -19,7 +19,7 @@ feature cmd "$HAPROXY_PROGRAM -cc 'version_atleast(3.4-dev2)'"
feature cmd "$HAPROXY_PROGRAM -cc 'feature(OPENSSL) && openssl_version_atleast(1.1.1)'"
feature ignore_unknown_macro
server s1 -repeat 30 {
server s1 -repeat 20 {
rxreq
txresp
} -start
@ -53,10 +53,6 @@ haproxy h1 -conf {
# { "kty": "RSA", "e": "AQAB", "n": "wsqJbopx18NQFYLYOq4ZeMSE89yGiEankUpf25yV8QqroKUGrASj_OeqTWUjwPGKTN1vGFFuHYxiJeAUQH2qQPmg9Oqk6-ATBEKn9COKYniQ5459UxCwmZA2RL6ufhrNyq0JF3GfXkjLDBfhU9zJJEOhknsA0L_c-X4AI3d_NbFdMqxNe1V_UWAlLcbKdwO6iC9fAvwUmDQxgy6R0DC1CMouQpenMRcALaSHar1cm4K-syoNobv3HEuqgZ3s6-hOOSqauqAO0GUozPpaIA7OeruyRl5sTWT0r-iz39bchID2bIKtcqLiFcSYPLBcxmsaQCqRlGhmv6stjTCLV1yT9w", "kid": "ff3c5c96-392e-46ef-a839-6ff16027af78", "d": "b9hXfQ8lOtw8mX1dpqPcoElGhbczz_-xq2znCXQpbBPSZBUddZvchRSH5pSSKPEHlgb3CSGIdpLqsBCv0C_XmCM9ViN8uqsYgDO9uCLIDK5plWttbkqA_EufvW03R9UgIKWmOL3W4g4t-C2mBb8aByaGGVNjLnlb6i186uBsPGkvaeLHbQcRQKAvhOUTeNiyiiCbUGJwCm4avMiZrsz1r81Y1Z5izo0ERxdZymxM3FRZ9vjTB-6DtitvTXXnaAm1JTu6TIpj38u2mnNLkGMbflOpgelMNKBZVxSmfobIbFN8CHVc1UqLK2ElsZ9RCQANgkMHlMkOMj-XT0wHa3VBUQ", "p": "8mgriveKJAp1S7SHqirQAfZafxVuAK_A2QBYPsAUhikfBOvN0HtZjgurPXSJSdgR8KbWV7ZjdJM_eOivIb_XiuAaUdIOXbLRet7t9a_NJtmX9iybhoa9VOJFMBq_rbnbbte2kq0-FnXmv3cukbC2LaEw3aEcDgyURLCgWFqt7M0", "q": "zbbTv5421GowOfKVEuVoA35CEWgl8mdasnEZac2LWxMwKExikKU5LLacLQlcOt7A6n1ZGUC2wyH8mstO5tV34Eug3fnNrbnxFUEE_ZB_njs_rtZnwz57AoUXOXVnd194seIZF9PjdzZcuwXwXbrZ2RSVW8if_ZH5OVYEM1EsA9M", "dp": "1BaIYmIKn1X3InGlcSFcNRtSOnaJdFhRpotCqkRssKUx2qBlxs7ln_5dqLtZkx5VM_UE_GE7yzc6BZOwBxtOftdsr8HVh-14ksSR9rAGEsO2zVBiEuW4qZf_aQM-ScWfU--wcczZ0dT-Ou8P87Bk9K9fjcn0PeaLoz3WTPepzNE", "dq": "kYw2u4_UmWvcXVOeV_VKJ5aQZkJ6_sxTpodRBMPyQmkMHKcW4eKU1mcJju_deqWadw5jGPPpm5yTXm5UkAwfOeookoWpGa7CvVf4kPNI6Aphn3GBjunJHNpPuU6w-wvomGsxd-NqQDGNYKHuFFMcyXO_zWXglQdP_1o1tJ1M-BM", "qi": "j94Ens784M8zsfwWoJhYq9prcSZOGgNbtFWQZO8HP8pcNM9ls7YA4snTtAS_B4peWWFAFZ0LSKPCxAvJnrq69ocmEKEk7ss1Jo062f9pLTQ6cnhMjev3IqLocIFt5Vbsg_PWYpFSR7re6FRbF9EYOM7F2-HRv1idxKCWoyQfBqk" }
load crt rsa_oeap.pem key rsa_oeap.key jwt on
# Private key built out of the following JWK:
# {"crv":"P-256","d":"6qbbYYII1zqqmlDHhTwJt-JYBe-ELI02yAecAx-nD4w","kty":"EC","x":"bASil7YpthReLltIsaJCaRrE7XtLCRVtOpGtdPO0jH0","y":"9xj9qfSrVKFqN3lnaNDXAclGGnfmU_j7xsEocZdYmPs"}
load crt ec_decrypt.crt key ec_decrypt.key jwt on
listen main-fe
bind "fd@${mainfe}"
@ -88,11 +84,6 @@ haproxy h1 -conf {
http-request set-var(txn.decrypted) var(txn.jwe),jwt_decrypt_cert(txn.pem)
.if ssllib_name_startswith(AWS-LC)
acl aws_unmanaged var(txn.jwe),jwt_header_query('$.alg') -m end "A128KW" -m end "A192KW"
http-request set-var(txn.decrypted) str("AWS-LC UNMANAGED") if aws_unmanaged
.endif
http-after-response set-header X-Decrypted %[var(txn.decrypted)]
server s1 ${s1_addr}:${s1_port}
@ -104,7 +95,7 @@ haproxy h1 -conf {
http-request set-var(txn.decrypted) var(txn.jwe),jwt_decrypt_jwk(txn.jwk)
.if ssllib_name_startswith(AWS-LC)
acl aws_unmanaged var(txn.jwe),jwt_header_query('$.alg') -m end "A128KW" -m end "A192KW"
acl aws_unmanaged var(txn.jwe),jwt_header_query('$.alg') -m str "A128KW"
http-request set-var(txn.decrypted) str("AWS-LC UNMANAGED") if aws_unmanaged
.endif
@ -271,53 +262,3 @@ client c8 -connect ${h1_mainfe_sock} {
expect resp.http.x-decrypted == ""
} -run
# ECDH-ES
client c9 -connect ${h1_mainfe_sock} {
txreq -url "/jwk" -hdr "Authorization: Bearer eyJhbGciOiAiRUNESC1FUyIsICJlbmMiOiAiQTI1NkdDTSIsICJlcGsiOiB7Imt0eSI6ICJFQyIsICJjcnYiOiAiUC0yNTYiLCAieCI6ICJZVUg1VlJweURCb3FiUjVCUWlSMGV4anJ0bDdLb24yeTZkejFnM3NuNzZJIiwgInkiOiAiZld2RHFHb3pYNjJnMnRTS19oSkctWkVKNkFCcFhYTS1Tc1hPeE5KUXFtUSJ9fQ..0tN70AQ3P_4uEV4t.zkv7KfnUlDTKjJ82zKCMK_z7OEFk_euXGuJemShf8mnOeEUE4UN8wS5cRJzMQWxcY9d3dIvUCYx0HhzeoXnKqnkEU6be659IVtKpqtceLYKcIkpjj0XiaEalVqIKKXTU2NG2ldNsYwnEDN_XxMnIUPFOy3yJqpOfjf8v98ABYuTWfJVwk3tK9vYCj-ScCf2NK7cEIti_09VCsxMg7z0kvco5UaTXvDjEbPhj_EVfHoPlmDE6EuaO5OX5t3reOoJ1vsM2PEpADiYfmvSZxeWAmmtAH7cvrRIUCcy4Q5pNczh1Pmt0y-uJKtme16YWq8PxVtnb7lY9HDTuPeaMVqvMV6PlQ9vnfsirjpz72qx3ArAeXkIGJsPOGKfgCoW6sAWHQxCzvq8ek7zOaqTAo169PSdtxfBL4MJWxoLg38pODy4cjEGR71YYirthejEMgRs7G1A8ksxgs2bkYGInunUD_iAWkQzxYZhFlLRntWP1ikOKmx9gbqR6K9UiqCK1UG4NXF3o4OV34m-jw-cXMDF2JkekVK2-rhxTbXmqP-VhDrkQ2ANdk7fTW9elFYNisVzE1QjdClMKGhO1fdKiSJ9xSPo3W6pMuquYYN-XT1fLiu3GDtO4ELZWVdwmiucsxv9H2jzPwbhvbvlXwXsmyCBtvumcEUbiYCOIYvlddhTGjZHplvDU73O5SkxUYJTYh7H0DcSiZ-6tcWdRCs605xVZMJ_X91_gZ1tb2_df73lYT_tVo39kw78m3GVFBeK2Zy4JeLheo0fHE7n8lg13uwG77SHwrWSV61KKWhBPZR0bWGi8YvVHnqX0GWklIjpqjbIjYAk4baFv4MO4OvEkPxnGm64NNZWrGEA0U8eEHCgjF1ZagQFNb674Crgd-tRA0QPEAOc9NsnlK1Q-47KIgqNbwoc3VpbpHNLVJT4aKWV5q187YNxarbpeDqguh75M9AgbpT5bSDFhjF83f1kiEDgLdNTkAd-CPAzgtzaEAfxD1K4ViZZZ2DqXgw0PFTFZAWrWqv8Ydi61r5MJ.Srleju8Bifrc_6bqFPUF_w" \
-hdr "X-JWK: {\"kty\":\"EC\",\"crv\":\"P-256\",\"x\":\"DxaAKzwruXJh4IkdieycIJER6w8M1TYMCV3qOa-l9CM\",\"y\":\"_kRI1aD7-PMFwhUpXmcRzw6hALF_xdKwADuKOM-xsak\",\"d\":\"SOu5eRc40yn5yVrg069VjWNH4wsoErN8_AxmH4cI88s\"}"
rxresp
expect resp.http.x-decrypted == "Sed ut perspiciatis unde omnis iste natus error sit voluptatem doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. porro quisquam est, qui dolorem ipsum quia dolor sit amet, adipisci velit, sed quia non numquam eius modi tempora incidunt ut dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in voluptate velit esse quam nihil molestiae consequatur, vel illum qui eum fugiat quo voluptas nulla pariatur?"
txreq -url "/jwk" -hdr "Authorization: Bearer eyJhbGciOiJFQ0RILUVTIiwiZW5jIjoiQTI1NkNCQy1IUzUxMiIsImVwayI6eyJjcnYiOiJQLTUyMSIsImt0eSI6IkVDIiwieCI6IkFYelVIT0hFdXU1RzlxSHBQOGdXelBub3FQNUpSVmNrYWZGb1VxV0FUQVd6b3FUN0tmX3V5WW5HSElaNkVXdUx0U0NrUnREUHE4WDJlcV9lSDc0QVRQZGwiLCJ5IjoiQVRxelFNWV9PUE9lWUZYNlpGN0l4ZkgwQ2x6RlRjZjVhaE1UTERmMHJYRkczNmdHN1lDMjR1Q2hrR2ZoZHlBT1RRY09kN1ZyQlM4clNZeC03R0hLbzNWNSJ9fQ..kTaw9v3MWCN78jq5OXTWZA.w4o_19dlHEFEhQ0GXI08x-vJnImL_mtZ_oHXTCvfCj_aCEDL4UuiaAU7-yvtM60G3HjNO6TTvmCdvHOTz6Ynrg.H-EbBpTyi5YXNT5DHSFiNBeBcdjmClR_LDARvak4qng" \
-hdr "X-JWK: {\"alg\":\"ECDH-ES\",\"crv\":\"P-521\",\"d\":\"AVBp1yn67_t0C8WfJnrhZsgy4TDkA9XktZnwAHcCTUMWTBCURXOjCNCIaCyE65xzIQbZUc9rO-B93XKFO81u8myd\",\"key_ops\":[\"wrapKey\",\"unwrapKey\"],\"kty\":\"EC\",\"x\":\"AByuEl5P9ledNRyj4EjTtQwDcsIYpbNzUqjri5o8GPGLzeTWUzjDBVt1ZyxKfK8VMVQbj8sIrBHncYUqM1Re3pSA\",\"y\":\"AW171IiyQSWx95A9uT1m76XPcAss3jeE7lHgw8mU7yIxSi_SItDYFixJ5Xtf2Vu2BLlmpR0on6VV1UUNIyPk6qwb\"}"
rxresp
expect resp.http.x-decrypted == "Random test message for ECDH-ES encrypted tokens"
txreq -url "/pem" -hdr "Authorization: Bearer eyJhbGciOiJFQ0RILUVTIiwiZW5jIjoiQTEyOENCQy1IUzI1NiIsImVwayI6eyJjcnYiOiJQLTI1NiIsImt0eSI6IkVDIiwieCI6InhEcUZveF9oR3Q5VjZWSWZjRUpaU1VVTm1uT0V5Qk1BYzZybHlOV09lcjgiLCJ5IjoiUVZmdkstcVJ0V0J1Uk9XVzRnMmlVampqMFN3U1BzYjB6ZE10R0c2czBFUSJ9fQ..0ykoqdP2WMKra2VugMQMzg.dyCI6QGNIf-x4n0DIaXgVnGtoSCOD3sOX7I01djrFdNRRSmPnITcQiJn1lw1LbiZyqZxOLf_mJHw7BRrcgPxBG6gsP3oFBnLeXllcD6kuLtllVofaPDEKdr66W9dp6Cr.002j4NUlGTYz8d_0mTM38A" \
-hdr "X-PEM: ${testdir}/ec_decrypt.crt"
rxresp
expect resp.http.x-decrypted == "Random test message for ECDH-ES encrypted token (with some extra padding for good measure)"
} -run
# ECDH-ES+A___KW
client c10 -connect ${h1_mainfe_sock} {
# ECDH-ES+A128KW
txreq -url "/jwk" -hdr "Authorization: Bearer eyJhbGciOiJFQ0RILUVTK0ExMjhLVyIsImVuYyI6IkExMjhDQkMtSFMyNTYiLCJlcGsiOnsiY3J2IjoiUC0yNTYiLCJrdHkiOiJFQyIsIngiOiJtc2poQktWNW5oNnBjdjhoRnR0UDlFVXRzaURzWG83T3RCekVZYkVJM1EwIiwieSI6IloxQ3FPQlEya1RNR1lENWdMUWJCaHB0MzRKRkR3dW5TX2ZzSmhsMlc1OWcifX0.5l7YaATvAWFJnWK_HsBPmawJ0RMqrkiwyZ9xAuiYCFSiqWWSr8D82A.0sa1s5V2RcDf0FW6hA1lig.z2DVLxtHeY1fPp6dJHiHEuHLVIQHQ10GfYXeFxwNE7JGyto-D3K1elHQn0Yq4Pitaheja21gnXkJajXhOA0rwQ.YmpToFWmj8XQrXMeXTa9eQ" \
-hdr "X-JWK: {\"crv\":\"P-256\",\"d\":\"6qbbYYII1zqqmlDHhTwJt-JYBe-ELI02yAecAx-nD4w\",\"kty\":\"EC\",\"x\":\"bASil7YpthReLltIsaJCaRrE7XtLCRVtOpGtdPO0jH0\",\"y\":\"9xj9qfSrVKFqN3lnaNDXAclGGnfmU_j7xsEocZdYmPs\"}"
rxresp
expect resp.http.x-decrypted ~ "(Random test message for ECDH-ES encrypted tokens|AWS-LC UNMANAGED)"
txreq -url "/pem" -hdr "Authorization: Bearer eyJhbGciOiJFQ0RILUVTK0ExMjhLVyIsImVuYyI6IkExMjhDQkMtSFMyNTYiLCJlcGsiOnsiY3J2IjoiUC0yNTYiLCJrdHkiOiJFQyIsIngiOiJKeUJzcDZtZjVCMWROYUk0ZGppX2pnMm9NdFRRQUd4akxTekdGbGJ0dXZZIiwieSI6IlFfZnlBUmZiMGpjWXFtSTZUNEdXTXA1U2dGYXZiQ3lGUGF3OHhab1BIYzAifX0.JKrKKRF9QdxUyv0KX-MV11eHpP2Vz8Amdh8j3ipd_QP57jkN-OWRCQ.CjpnSVRVV51C10cUwCTaXA.bliaBk7mGYIOGdvgiMg481iC8GiOarRrjIkUgEBuqiSJENmOi90IXgnoVp4qQdi70bJVBNuCYP7Q9sLzZc4X2g.C_TCuAfAH5020v-NdR91BA" \
-hdr "X-PEM: ${testdir}/ec_decrypt.crt"
rxresp
expect resp.http.x-decrypted ~ "(Random test message for ECDH-ES\\+A128KW encrypted token|AWS-LC UNMANAGED)"
# ECDH-ES+A192KW
txreq -url "/jwk" -hdr "Authorization: Bearer eyJhbGciOiJFQ0RILUVTK0ExOTJLVyIsImVuYyI6IkExOTJDQkMtSFMzODQiLCJlcGsiOnsiY3J2IjoiUC0zODQiLCJrdHkiOiJFQyIsIngiOiJDcTd3Y0MzUm92VFRZSTMzLU9DcXBocjFlN1NzeEZWY0dOQXhEOEpWZHBRQmROaGg3Z2dLNTJKVkJ1RF9uZXVHIiwieSI6IjlaLU1MV09TQ3VZd0JZVTEtcTd2YUREWUZ1WFhqc1EwSmxpWllLVmdOU0dqVHVLY3VXQnJHemV2RzZEeGgyRHQifX0.75lt6Ixq6UhlN8uiaEphy8SiqEVsuD4Rc3QbFcmP7MJUTyt15LcZ3y-M7TJeNBh3Ajy_6K2WooU.cO9tUaQ2eVo0tIuOqb5_Bw.HQ6DqnLhW2Ad0c78WFGgwCStefYdL37xmh2Fa2mCsVNW5q0K3-xeDHYuIP9Q5xBYEY70U6wV5a0iVN87ii_iMA.feLteQh1ickYVJ2ZZ2whoVzNGRHgUpjp" \
-hdr "X-JWK: {\"alg\":\"ECDH-ES+A192KW\",\"crv\":\"P-384\",\"d\":\"pj6xIezfwtUakkkLtbRQ9FmN6uN1YJ-TSBkWn4awuDfWiHgqpQHA7_L95Hjks1cK\",\"key_ops\":[\"wrapKey\",\"unwrapKey\"],\"kty\":\"EC\",\"x\":\"JO3ojbUYOzoSb-7lAy-c7VhDIjhEtg4zrPn_NJKuGhat-cuI1c4LvOj3n8p3j4bn\",\"y\":\"CA3i4pN7t6liWxQXyxdDp9t79B8uWuubGADJuGn_2_yl6pufhnQ30OBA590fOtEm\"}"
rxresp
expect resp.http.x-decrypted ~ "(Random test message for ECDH-ES\\+A192KW encrypted tokens|AWS-LC UNMANAGED)"
# ECDH-ES+A256KW
txreq -url "/jwk" -hdr "Authorization: Bearer eyJhbGciOiJFQ0RILUVTK0EyNTZLVyIsImVuYyI6IkEyNTZDQkMtSFM1MTIiLCJlcGsiOnsiY3J2IjoiUC01MjEiLCJrdHkiOiJFQyIsIngiOiJBTFZuZXN6Tl93WVJSWVYtblp3dy1sSkVDTXB2eE1iSENXX3BjY3EyWlF2eFdsNzVKdm5TM3lKbjgzcTE1MlpnWU4zTTB4SUhzQmw1empWZS02OGR4TThwIiwieSI6IkFUX2pGel94RGt0VFY4WWYzZlo1MnRvbE5QWkwwNXlwa0dVTThPWFRNZTBaaVNfYnIzaS0xNHFlWG1OcjA3TFFjNUZMX1VTQkE5WmlyWGRaZkVLUnFqNmEifX0.MqGFvMzpIlwQHeXgPucBkXmS2BaXr2ByUugzD31XrPtxwlWw96vOmfcjSHvda2FGJ1u6InaMMVZMMp75P6AF0kvk8vuM7QF2.kHYblcqwHgXv0xRQrLHwoA.gwFUyTx3RRHWvmqyUL5N6W8HcwbNc1hPTImQPoCNPv6rkhzV1obikVj7sNuTh3Po0nBu2QCKrt-GjJTlD4Q5kw.Q_YZWSkVVxv1rcpySgENN3ZPp-chIYoCGC070kkqiXc" \
-hdr "X-JWK: {\"alg\":\"ECDH-ES+A256KW\",\"crv\":\"P-521\",\"d\":\"AGGLpIzSL1jE34wGa-owWCVt2rgk8j3jqh33QQFKwYCJ9abp3vROyQ-dNv6j6PjrnF1EFyY9dDzChNpWmzoOZAp3\",\"key_ops\":[\"wrapKey\",\"unwrapKey\"],\"kty\":\"EC\",\"x\":\"AD0EIUE6Bt_TDcyOPM6VchRocp7AFSeVd6XkVALWf8AFebeMgKIvJsCsGeRdPTO3vWWrR5AOvvpiBfurb9M9Tus-\",\"y\":\"AOeI5d0iF463g3DolhmVFn6MWk764ONuXRexLApjN-Q6_RkcnCieRSZzqqSPMYuEn-N3i4aYfiEPZV0jk8oZKQMQ\"}"
rxresp
expect resp.http.x-decrypted == "Random test message for ECDH-ES+A256KW encrypted tokens"
} -run

View File

@ -28,7 +28,7 @@
# show-backports -q -m -r hapee-r2 hapee-r1
USAGE="Usage: ${0##*/} [-q] [-H] [-m] [-u] [-L] [-r reference] [-l logexpr] [-s subject] [-b base] {branch|range} [...] [-- file*]"
USAGE="Usage: ${0##*/} [-q] [-H] [-m] [-u] [-r reference] [-l logexpr] [-s subject] [-b base] {branch|range} [...] [-- file*]"
BASES=( )
BRANCHES=( )
REF=
@ -39,7 +39,6 @@ SUBJECT=
MISSING=
UPSTREAM=
BODYHASH=
SINCELAST=
die() {
[ "$#" -eq 0 ] || echo "$*" >&2
@ -71,7 +70,7 @@ dump_commit_matrix() {
count=0
# now look up commits
while read ref subject; do
if [ -n "$MISSING" -o -n "$SINCELAST" ] && [ "${subject:0:9}" = "[RELEASE]" ]; then
if [ -n "$MISSING" -a "${subject:0:9}" = "[RELEASE]" ]; then
continue
fi
@ -154,7 +153,6 @@ while [ -n "$1" -a -z "${1##-*}" ]; do
-m) MISSING=1 ; shift ;;
-u) UPSTREAM=1 ; shift ;;
-H) BODYHASH=1 ; shift ;;
-L) SINCELAST=1 ; shift ;;
-h|--help) quit "$USAGE" ;;
*) die "$USAGE" ;;
esac
@ -257,7 +255,7 @@ if [ -z "$BASE" -a -n "$MISSING" ]; then
fi
if [ -z "$BASE" ]; then
[ "$QUIET" != "" ] || err "Warning! No base specified, looking for common ancestor."
err "Warning! No base specified, looking for common ancestor."
BASE=$(git merge-base --all "$REF" "${BRANCHES[@]}")
if [ -z "$BASE" ]; then
die "Couldn't find a common ancestor between these branches"
@ -299,23 +297,9 @@ dump_commit_matrix | column -t | \
(
left_commits=( )
right_commits=( )
since_last=( )
last_bkp=$BASE
while read line; do
# append the subject at the end of the line
set -- $line
if [ -n "$SINCELAST" ]; then
if [ "${line::1}" = ":" ]; then
continue
fi
if [ "$2" != "-" ]; then
last_bkp="$1"
since_last=( )
else
since_last[${#since_last[@]}]="$1"
fi
continue
fi
echo -n "$line "
if [ "${line::1}" = ":" ]; then
echo "---- Subject ----"
@ -331,24 +315,7 @@ dump_commit_matrix | column -t | \
right_commits[${#right_commits[@]}]="$comm"
fi
done
if [ -n "$SINCELAST" -a ${#since_last[@]} -eq 0 ]; then
echo "No new commit upstream since last commit $last_bkp."
elif [ -n "$SINCELAST" ]; then
echo "Found ${#since_last[@]} commit(s) added to branch $REF since last backported commit $last_bkp:"
echo
if [ -z "$QUIET" ]; then
for c in "${since_last[@]}"; do
echo "$(git log -1 --pretty=" %h | %s" "$c")"
done
echo
echo "In order to show and/or apply them all to current branch :"
echo
echo " git show --pretty=format:'%C(yellow)commit %H%C(normal)%nAuthor: %an <%ae>%nDate: %aD%n%n%C(green)%C(bold)git cherry-pick -sx %h%n%n%w(0,4,4)%B%N' ${since_last[@]}"
echo
fi
echo " git cherry-pick -sx ${since_last[@]}"
echo
elif [ -n "$MISSING" -a ${#left_commits[@]} -eq 0 ]; then
if [ -n "$MISSING" -a ${#left_commits[@]} -eq 0 ]; then
echo "No missing commit to apply."
elif [ -n "$MISSING" ]; then
echo

View File

@ -4,7 +4,6 @@
* Implements the ACMEv2 RFC 8555 protocol
*/
#include "haproxy/ticks.h"
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
@ -15,9 +14,7 @@
#include <haproxy/acme-t.h>
#include <haproxy/acme_resolvers.h>
#include <haproxy/base64.h>
#include <haproxy/intops.h>
#include <haproxy/cfgparse.h>
#include <haproxy/cli.h>
#include <haproxy/errors.h>
@ -26,7 +23,6 @@
#include <haproxy/list.h>
#include <haproxy/log.h>
#include <haproxy/pattern.h>
#include <haproxy/resolvers.h>
#include <haproxy/sink.h>
#include <haproxy/ssl_ckch.h>
#include <haproxy/ssl_gencert.h>
@ -121,9 +117,6 @@ static void acme_trace(enum trace_level level, uint64_t mask, const struct trace
case ACME_NEWACCOUNT: chunk_appendf(&trace_buf, "ACME_NEWACCOUNT"); break;
case ACME_NEWORDER: chunk_appendf(&trace_buf, "ACME_NEWORDER"); break;
case ACME_AUTH: chunk_appendf(&trace_buf, "ACME_AUTH"); break;
case ACME_RSLV_WAIT: chunk_appendf(&trace_buf, "ACME_RSLV_WAIT"); break;
case ACME_RSLV_TRIGGER: chunk_appendf(&trace_buf, "ACME_RSLV_TRIGGER"); break;
case ACME_RSLV_READY: chunk_appendf(&trace_buf, "ACME_RSLV_READY"); break;
case ACME_CHALLENGE: chunk_appendf(&trace_buf, "ACME_CHALLENGE"); break;
case ACME_CHKCHALLENGE: chunk_appendf(&trace_buf, "ACME_CHKCHALLENGE"); break;
case ACME_FINALIZE: chunk_appendf(&trace_buf, "ACME_FINALIZE"); break;
@ -197,7 +190,6 @@ struct acme_cfg *new_acme_cfg(const char *name)
ret->linenum = 0;
ret->challenge = strdup("http-01"); /* default value */
ret->dns_delay = 300; /* default DNS re-trigger delay in seconds */
/* The default generated keys are EC-384 */
ret->key.type = EVP_PKEY_EC;
@ -274,6 +266,7 @@ static int cfg_parse_acme(const char *file, int linenum, char **args, int kwm)
mark_tainted(TAINTED_CONFIG_EXP_KW_DECLARED);
if (strcmp(args[0], "acme") == 0) {
struct acme_cfg *tmp_acme = acme_cfgs;
if (alertif_too_many_args(1, file, linenum, args, &err_code))
goto out;
@ -299,7 +292,7 @@ static int cfg_parse_acme(const char *file, int linenum, char **args, int kwm)
* name */
err_code |= ERR_ALERT | ERR_FATAL;
ha_alert("parsing [%s:%d]: acme section '%s' already exists (%s:%d).\n",
file, linenum, args[1], cur_acme->filename, cur_acme->linenum);
file, linenum, args[1], tmp_acme->filename, tmp_acme->linenum);
goto out;
}
@ -427,18 +420,6 @@ static int cfg_parse_acme_kws(char **args, int section_type, struct proxy *curpx
ha_alert("parsing [%s:%d]: out of memory.\n", file, linenum);
goto out;
}
/* require the CLI by default */
if ((strcasecmp("dns-01", args[1]) == 0) && (cur_acme->cond_ready == 0)) {
cur_acme->cond_ready = ACME_RDY_CLI;
}
if ((strcasecmp("http-01", args[1]) == 0) && (cur_acme->cond_ready != 0)) {
ha_alert("parsing [%s:%d]: keyword '%s' in '%s' section, \"http-01\" is not compatible with the \"challenge-ready\" option\n", file, linenum, args[0], cursection);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
} else if (strcmp(args[0], "map") == 0) {
/* save the map name for thumbprint + token storage */
if (!*args[1]) {
@ -456,74 +437,6 @@ static int cfg_parse_acme_kws(char **args, int section_type, struct proxy *curpx
ha_alert("parsing [%s:%d]: out of memory.\n", file, linenum);
goto out;
}
} else if (strcmp(args[0], "challenge-ready") == 0) {
char *str = args[1];
char *saveptr;
if (!*args[1]) {
ha_alert("parsing [%s:%d]: keyword '%s' in '%s' section requires an argument\n", file, linenum, args[0], cursection);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
if (alertif_too_many_args(1, file, linenum, args, &err_code))
goto out;
cur_acme->cond_ready = 0;
while ((str = strtok_r(str, ",", &saveptr))) {
if (strcmp(str, "cli") == 0) {
/* wait for the CLI-ready to run the challenge */
cur_acme->cond_ready |= ACME_RDY_CLI;
} else if (strcmp(str, "dns") == 0) {
/* wait for the DNS-check to run the challenge */
cur_acme->cond_ready |= ACME_RDY_DNS;
} else if (strcmp(str, "none") == 0) {
if (cur_acme->cond_ready || (saveptr && *saveptr)) {
err_code |= ERR_ALERT | ERR_FATAL;
ha_alert("parsing [%s:%d]: keyword '%s' in '%s' can't combine 'none' with other keywords.\n", file, linenum, args[0], cursection);
goto out;
}
cur_acme->cond_ready = ACME_RDY_NONE;
} else {
err_code |= ERR_ALERT | ERR_FATAL;
ha_alert("parsing [%s:%d]: keyword '%s' in '%s' section requires parameter separated by commas: 'cli', 'dns' or 'none'\n", file, linenum, args[0], cursection);
goto out;
}
str = NULL;
}
if ((strcasecmp("http-01", cur_acme->challenge) == 0) && (cur_acme->cond_ready != 0)) {
ha_alert("parsing [%s:%d]: keyword '%s' in '%s' section, \"http-01\" is not compatible with the \"challenge-ready\" option\n", file, linenum, args[0], cursection);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
} else if (strcmp(args[0], "dns-delay") == 0) {
const char *res;
if (!*args[1]) {
ha_alert("parsing [%s:%d]: keyword '%s' in '%s' section requires an argument\n", file, linenum, args[0], cursection);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
if (alertif_too_many_args(1, file, linenum, args, &err_code))
goto out;
res = parse_time_err(args[1], &cur_acme->dns_delay, TIME_UNIT_S);
if (res == PARSE_TIME_OVER) {
ha_alert("parsing [%s:%d]: timer overflow in argument <%s> to '%s'\n", file, linenum, args[1], args[0]);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
} else if (res == PARSE_TIME_UNDER) {
ha_alert("parsing [%s:%d]: timer underflow in argument <%s> to '%s'\n", file, linenum, args[1], args[0]);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
} else if (res) {
ha_alert("parsing [%s:%d]: unexpected character '%c' in argument to '%s'\n", file, linenum, *res, args[0]);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
} else if (strcmp(args[0], "reuse-key") == 0) {
if (!*args[1]) {
ha_alert("parsing [%s:%d]: keyword '%s' in '%s' section requires an argument\n", file, linenum, args[0], cursection);
@ -928,8 +841,6 @@ static struct cfg_kw_list cfg_kws_acme = {ILH, {
{ CFG_ACME, "curves", cfg_parse_acme_cfg_key },
{ CFG_ACME, "map", cfg_parse_acme_kws },
{ CFG_ACME, "reuse-key", cfg_parse_acme_kws },
{ CFG_ACME, "challenge-ready", cfg_parse_acme_kws },
{ CFG_ACME, "dns-delay", cfg_parse_acme_kws },
{ CFG_ACME, "acme-vars", cfg_parse_acme_vars_provider },
{ CFG_ACME, "provider-name", cfg_parse_acme_vars_provider },
{ CFG_GLOBAL, "acme.scheduler", cfg_parse_global_acme_sched },
@ -968,7 +879,6 @@ static void acme_ctx_destroy(struct acme_ctx *ctx)
istfree(&auth->chall);
istfree(&auth->token);
istfree(&auth->dns);
acme_rslv_free(auth->rslv);
next = auth->next;
free(auth);
auth = next;
@ -1278,7 +1188,7 @@ int acme_res_certificate(struct task *task, struct acme_ctx *ctx, char **errmsg)
}
/* get the next retry timing */
if (isteqi(hdr->n, ist("Retry-After"))) {
ctx->retryafter = __strl2uic(hdr->v.ptr, hdr->v.len);
ctx->retryafter = atol(hdr->v.ptr);
}
}
@ -1351,7 +1261,7 @@ int acme_res_chkorder(struct task *task, struct acme_ctx *ctx, char **errmsg)
}
/* get the next retry timing */
if (isteqi(hdr->n, ist("Retry-After"))) {
ctx->retryafter = __strl2uic(hdr->v.ptr, hdr->v.len);
ctx->retryafter = atol(hdr->v.ptr);
}
}
@ -1434,6 +1344,7 @@ int acme_req_finalize(struct task *task, struct acme_ctx *ctx, char **errmsg)
csr->data = ret;
chunk_printf(req_in, "{ \"csr\": \"%.*s\" }", (int)csr->data, csr->area);
OPENSSL_free(data);
if (acme_jws_payload(req_in, ctx->nonce, ctx->finalize, ctx->cfg->account.pkey, ctx->kid, req_out, errmsg) != 0)
@ -1447,7 +1358,6 @@ int acme_req_finalize(struct task *task, struct acme_ctx *ctx, char **errmsg)
error:
memprintf(errmsg, "couldn't request the finalize URL");
out:
OPENSSL_free(data);
free_trash_chunk(req_in);
free_trash_chunk(req_out);
free_trash_chunk(csr);
@ -1481,7 +1391,7 @@ int acme_res_finalize(struct task *task, struct acme_ctx *ctx, char **errmsg)
}
/* get the next retry timing */
if (isteqi(hdr->n, ist("Retry-After"))) {
ctx->retryafter = __strl2uic(hdr->v.ptr, hdr->v.len);
ctx->retryafter = atol(hdr->v.ptr);
}
}
@ -1582,7 +1492,7 @@ enum acme_ret acme_res_challenge(struct task *task, struct acme_ctx *ctx, struct
}
/* get the next retry timing */
if (isteqi(hdr->n, ist("Retry-After"))) {
ctx->retryafter = __strl2uic(hdr->v.ptr, hdr->v.len);
ctx->retryafter = atol(hdr->v.ptr);
}
}
@ -1708,7 +1618,7 @@ int acme_res_auth(struct task *task, struct acme_ctx *ctx, struct acme_auth *aut
}
/* get the next retry timing */
if (isteqi(hdr->n, ist("Retry-After"))) {
ctx->retryafter = __strl2uic(hdr->v.ptr, hdr->v.len);
ctx->retryafter = atol(hdr->v.ptr);
}
}
@ -1744,19 +1654,6 @@ int acme_res_auth(struct task *task, struct acme_ctx *ctx, struct acme_auth *aut
auth->dns = istdup(ist2(t2->area, t2->data));
ret = mjson_get_string(hc->res.buf.area, hc->res.buf.data, "$.status", trash.area, trash.size);
if (ret == -1) {
memprintf(errmsg, "couldn't get a \"status\" from Authorization URL \"%s\"", auth->auth.ptr);
goto error;
}
trash.data = ret;
/* if auth is already valid we need to skip solving challenges */
if (strncasecmp("valid", trash.area, trash.data) == 0) {
auth->validated = 1;
goto out;
}
/* get the multiple challenges and select the one from the configuration */
for (i = 0; ; i++) {
int ret;
@ -1820,13 +1717,8 @@ int acme_res_auth(struct task *task, struct acme_ctx *ctx, struct acme_auth *aut
goto error;
}
/* replace the token by the TXT entry */
istfree(&auth->token);
auth->token = istdup(ist2(dns_record->area, dns_record->data));
if (ctx->cfg->cond_ready & ACME_RDY_CLI)
send_log(NULL, LOG_NOTICE,"acme: %s: dns-01 requires to set the \"_acme-challenge.%.*s\" TXT record to \"%.*s\" and use the \"acme challenge_ready %s domain %.*s\" command over the CLI\n",
ctx->store->path, (int)auth->dns.len, auth->dns.ptr, (int)auth->token.len, auth->token.ptr, ctx->store->path, (int)auth->dns.len, auth->dns.ptr);
send_log(NULL, LOG_NOTICE,"acme: %s: dns-01 requires to set the \"_acme-challenge.%.*s\" TXT record to \"%.*s\" and use the \"acme challenge_ready %s domain %.*s\" command over the CLI\n",
ctx->store->path, (int)auth->dns.len, auth->dns.ptr, (int)dns_record->data, dns_record->area, ctx->store->path, (int)auth->dns.len, auth->dns.ptr);
/* dump to the "dpapi" sink */
line[nmsg++] = ist("acme deploy ");
@ -1869,7 +1761,6 @@ int acme_res_auth(struct task *task, struct acme_ctx *ctx, struct acme_auth *aut
break;
}
out:
ret = 0;
error:
@ -1958,7 +1849,7 @@ int acme_res_neworder(struct task *task, struct acme_ctx *ctx, char **errmsg)
}
/* get the next retry timing */
if (isteqi(hdr->n, ist("Retry-After"))) {
ctx->retryafter = __strl2uic(hdr->v.ptr, hdr->v.len);
ctx->retryafter = atol(hdr->v.ptr);
}
/* get the order URL */
if (isteqi(hdr->n, ist("Location"))) {
@ -2010,6 +1901,11 @@ int acme_res_neworder(struct task *task, struct acme_ctx *ctx, char **errmsg)
goto error;
}
/* if the challenge is not dns-01, consider that the challenge
* is ready because computed by HAProxy */
if (strcasecmp(ctx->cfg->challenge, "dns-01") != 0)
auth->ready = 1;
auth->next = ctx->auths;
ctx->auths = auth;
ctx->next_auth = auth;
@ -2113,7 +2009,7 @@ int acme_res_account(struct task *task, struct acme_ctx *ctx, int newaccount, ch
}
/* get the next retry timing */
if (isteqi(hdr->n, ist("Retry-After"))) {
ctx->retryafter = __strl2uic(hdr->v.ptr, hdr->v.len);
ctx->retryafter = atol(hdr->v.ptr);
}
if (isteqi(hdr->n, ist("Replay-Nonce"))) {
istfree(&ctx->nonce);
@ -2358,148 +2254,18 @@ re:
goto retry;
}
if ((ctx->next_auth = ctx->next_auth->next) == NULL) {
if (strcasecmp(ctx->cfg->challenge, "dns-01") == 0 && ctx->cfg->cond_ready)
st = ACME_RSLV_WAIT;
else
st = ACME_CHALLENGE;
st = ACME_CHALLENGE;
ctx->next_auth = ctx->auths;
}
/* call with next auth or do the challenge step */
goto nextreq;
}
break;
case ACME_RSLV_WAIT: {
struct acme_auth *auth;
int all_cond_ready = ctx->cfg->cond_ready;
for (auth = ctx->auths; auth != NULL; auth = auth->next) {
all_cond_ready &= auth->ready;
}
/* if everything is ready, let's do the challenge request */
if ((all_cond_ready & ctx->cfg->cond_ready) == ctx->cfg->cond_ready) {
st = ACME_CHALLENGE;
ctx->http_state = ACME_HTTP_REQ;
ctx->state = st;
goto nextreq;
}
/* if we need to wait for the CLI, let's wait */
if ((ctx->cfg->cond_ready & ACME_RDY_CLI) && !(all_cond_ready & ACME_RDY_CLI))
goto wait;
/* we don't need to wait, we can trigger the resolution
* after the delay */
st = ACME_RSLV_TRIGGER;
ctx->http_state = ACME_HTTP_REQ;
ctx->state = st;
send_log(NULL, LOG_NOTICE, "acme: %s: dns-01: triggering the resolution in %ds\n",
ctx->store->path, ctx->cfg->dns_delay);
task->expire = tick_add(now_ms, ctx->cfg->dns_delay * 1000);
return task;
}
break;
case ACME_RSLV_TRIGGER: {
struct acme_auth *auth;
/* if it was trigger by the CLI, still wait dns_delay if
* not everything is ready, or skip and to to
* ACME_CHALLENGE */
if (!(state & TASK_WOKEN_TIMER)) {
int all_ready = 1;
for (auth = ctx->auths; auth != NULL; auth = auth->next) {
if (auth->ready == ctx->cfg->cond_ready)
continue;
all_ready = 0;
}
if (all_ready) {
st = ACME_CHALLENGE;
ctx->http_state = ACME_HTTP_REQ;
ctx->state = st;
goto nextreq;
} else {
return task;
}
}
/* on timer expiry, re-trigger resolution for non-ready auths */
for (auth = ctx->auths; auth != NULL; auth = auth->next) {
if (auth->ready == ctx->cfg->cond_ready)
continue;
HA_ATOMIC_INC(&ctx->dnstasks);
auth->rslv = acme_rslv_start(auth, &ctx->dnstasks, &errmsg);
if (!auth->rslv)
goto abort;
auth->rslv->acme_task = task;
}
st = ACME_RSLV_READY;
goto wait;
}
break;
case ACME_RSLV_READY: {
struct acme_auth *auth;
int all_ready = 1;
/* if triggered by the CLI, wait for the DNS tasks to
* finish
*/
if (HA_ATOMIC_LOAD(&ctx->dnstasks) != 0)
goto wait;
/* triggered by the latest DNS task */
for (auth = ctx->auths; auth != NULL; auth = auth->next) {
if (auth->ready == ctx->cfg->cond_ready)
continue;
if (auth->rslv->result != RSLV_STATUS_VALID) {
send_log(NULL, LOG_NOTICE, "acme: %s: dns-01: Couldn't get the TXT record for \"_acme-challenge.%.*s\", expected \"%.*s\" (status=%d)\n",
ctx->store->path, (int)auth->dns.len, auth->dns.ptr,
(int)auth->token.len, auth->token.ptr,
auth->rslv->result);
all_ready = 0;
} else {
if (isteq(auth->rslv->txt, auth->token)) {
auth->ready |= ACME_RDY_DNS;
} else {
send_log(NULL, LOG_NOTICE, "acme: %s: dns-01: TXT record mismatch for \"_acme-challenge.%.*s\": expected \"%.*s\", got \"%.*s\"\n",
ctx->store->path, (int)auth->dns.len, auth->dns.ptr,
(int)auth->token.len, auth->token.ptr,
(int)auth->rslv->txt.len, auth->rslv->txt.ptr);
all_ready = 0;
}
}
acme_rslv_free(auth->rslv);
auth->rslv = NULL;
}
if (all_ready) {
st = ACME_CHALLENGE;
ctx->next_auth = ctx->auths;
goto nextreq;
}
/* not all ready yet, retry after dns-delay */
st = ACME_RSLV_WAIT;
ctx->http_state = ACME_HTTP_REQ;
ctx->state = st;
goto nextreq;
}
break;
case ACME_CHALLENGE:
if (http_st == ACME_HTTP_REQ) {
/* if challenge is already validated we skip this stage */
if (ctx->next_auth->validated) {
if ((ctx->next_auth = ctx->next_auth->next) == NULL) {
st = ACME_CHKCHALLENGE;
ctx->next_auth = ctx->auths;
}
goto nextreq;
}
/* if the challenge is not ready, wait to be wakeup */
if (ctx->next_auth->ready != ctx->cfg->cond_ready)
if (!ctx->next_auth->ready)
goto wait;
if (acme_req_challenge(task, ctx, ctx->next_auth, &errmsg) != 0)
@ -2526,14 +2292,6 @@ re:
break;
case ACME_CHKCHALLENGE:
if (http_st == ACME_HTTP_REQ) {
/* if challenge is already validated we skip this stage */
if (ctx->next_auth->validated) {
if ((ctx->next_auth = ctx->next_auth->next) == NULL)
st = ACME_FINALIZE;
goto nextreq;
}
if (acme_post_as_get(task, ctx, ctx->next_auth->chall, &errmsg) != 0)
goto retry;
}
@ -2768,9 +2526,9 @@ X509_REQ *acme_x509_req(EVP_PKEY *pkey, char **san)
{
struct buffer *san_trash = NULL;
X509_REQ *x = NULL;
X509_NAME *nm = NULL;
X509_NAME *nm;
STACK_OF(X509_EXTENSION) *exts = NULL;
X509_EXTENSION *ext_san = NULL;
X509_EXTENSION *ext_san;
char *str_san = NULL;
int i = 0;
@ -2801,36 +2559,26 @@ X509_REQ *acme_x509_req(EVP_PKEY *pkey, char **san)
for (i = 0; san[i]; i++) {
chunk_appendf(san_trash, "%sDNS:%s", i ? "," : "", san[i]);
}
if ((str_san = my_strndup(san_trash->area, san_trash->data)) == NULL)
goto error;
str_san = my_strndup(san_trash->area, san_trash->data);
if ((ext_san = X509V3_EXT_conf_nid(NULL, NULL, NID_subject_alt_name, str_san)) == NULL)
goto error;
if (!sk_X509_EXTENSION_push(exts, ext_san))
goto error;
ext_san = NULL; /* handle double-free upon error */
if (!X509_REQ_add_extensions(x, exts))
goto error;
sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);
if (!X509_REQ_sign(x, pkey, EVP_sha256()))
goto error;
sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);
X509_NAME_free(nm);
free(str_san);
free_trash_chunk(san_trash);
return x;
error:
X509_EXTENSION_free(ext_san);
sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);
X509_REQ_free(x);
X509_NAME_free(nm);
free(str_san);
free_trash_chunk(san_trash);
return NULL;
@ -2879,7 +2627,7 @@ EVP_PKEY *acme_gen_tmp_pkey()
/* start an ACME task */
static int acme_start_task(struct ckch_store *store, char **errmsg)
{
struct task *task = NULL;
struct task *task;
struct acme_ctx *ctx = NULL;
struct acme_cfg *cfg;
struct ckch_store *newstore = NULL;
@ -2964,8 +2712,6 @@ err:
HA_RWLOCK_WRUNLOCK(OTHER_LOCK, &acme_lock);
acme_ctx_destroy(ctx);
}
if (task)
task_destroy(task);
memprintf(errmsg, "%sCan't start the ACME client.", *errmsg ? *errmsg : "");
return 1;
}
@ -2975,10 +2721,7 @@ static int cli_acme_renew_parse(char **args, char *payload, struct appctx *appct
struct ckch_store *store = NULL;
char *errmsg = NULL;
if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
return 1;
if (!*args[2]) {
if (!*args[1]) {
memprintf(&errmsg, ": not enough parameters\n");
goto err;
}
@ -3012,16 +2755,13 @@ static int cli_acme_chall_ready_parse(char **args, char *payload, struct appctx
const char *crt;
const char *dns;
struct acme_ctx *ctx = NULL;
struct acme_auth *auth = NULL;
struct acme_auth *auth;
int found = 0;
int remain = 0;
struct ebmb_node *node = NULL;
if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
return 1;
if (!*args[2] || !*args[3] || !*args[4]) {
memprintf(&msg, "Not enough parameters: \"acme challenge_ready <certfile> domain <domain>\"\n");
if (!*args[2] && !*args[3] && !*args[4]) {
memprintf(&msg, ": not enough parameters\n");
goto err;
}
@ -3032,18 +2772,17 @@ static int cli_acme_chall_ready_parse(char **args, char *payload, struct appctx
node = ebst_lookup(&acme_tasks, crt);
if (node) {
ctx = ebmb_entry(node, struct acme_ctx, node);
if (ctx->cfg->cond_ready & ACME_RDY_CLI)
auth = ctx->auths;
auth = ctx->auths;
while (auth) {
if (strncmp(dns, auth->dns.ptr, auth->dns.len) == 0) {
if (!(auth->ready & ACME_RDY_CLI)) {
auth->ready |= ACME_RDY_CLI;
if (!auth->ready) {
auth->ready = 1;
found++;
} else {
memprintf(&msg, "ACME challenge for crt \"%s\" and dns \"%s\" was already READY !\n", crt, dns);
}
}
if ((auth->ready & ACME_RDY_CLI) == 0)
if (auth->ready == 0)
remain++;
auth = auth->next;
}
@ -3051,7 +2790,7 @@ static int cli_acme_chall_ready_parse(char **args, char *payload, struct appctx
HA_RWLOCK_WRUNLOCK(OTHER_LOCK, &acme_lock);
if (!found) {
if (!msg)
memprintf(&msg, "Couldn't find an ACME task using crt \"%s\" and dns \"%s\" to set as ready!\n", crt, dns);
memprintf(&msg, "Couldn't find the ACME task using crt \"%s\" and dns \"%s\" !\n", crt, dns);
goto err;
} else {
if (!remain) {
@ -3143,12 +2882,8 @@ end:
return 1;
}
static int cli_acme_parse_status(char **args, char *payload, struct appctx *appctx, void *private)
static int cli_acme_ps(char **args, char *payload, struct appctx *appctx, void *private)
{
if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
return 1;
return 0;
}
@ -3156,7 +2891,7 @@ static int cli_acme_parse_status(char **args, char *payload, struct appctx *appc
static struct cli_kw_list cli_kws = {{ },{
{ { "acme", "renew", NULL }, "acme renew <certfile> : renew a certificate using the ACME protocol", cli_acme_renew_parse, NULL, NULL, NULL, 0 },
{ { "acme", "status", NULL }, "acme status : show status of certificates configured with ACME", cli_acme_parse_status, cli_acme_status_io_handler, NULL, NULL, 0 },
{ { "acme", "status", NULL }, "acme status : show status of certificates configured with ACME", cli_acme_ps, cli_acme_status_io_handler, NULL, NULL, 0 },
{ { "acme", "challenge_ready", NULL }, "acme challenge_ready <certfile> domain <domain> : notify HAProxy that the ACME challenge is ready", cli_acme_chall_ready_parse, NULL, NULL, NULL, 0 },
{ { NULL }, NULL, NULL, NULL }
}};

View File

@ -1,166 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Implements the DNS resolution pre-check for dns-01
*/
#include <haproxy/openssl-compat.h>
#if defined(HAVE_ACME)
#include <stdlib.h>
#include <string.h>
#include <haproxy/acme_resolvers.h>
#include <haproxy/applet.h>
#include <haproxy/obj_type.h>
#include <haproxy/resolvers.h>
#include <haproxy/tools.h>
/* success callback, copy the TXT string to rslv->txt */
static int acme_rslv_success_cb(struct resolv_requester *req, struct dns_counters *counters)
{
struct acme_rslv *rslv = objt_acme_rslv(req->owner);
struct resolv_resolution *res;
struct eb32_node *eb32;
struct resolv_answer_item *item;
if (!rslv)
return 1;
rslv->result = RSLV_STATUS_INVALID;
res = req->resolution;
if (!res)
goto done;
/* XXX: must fail on multiple TXT entries for the same dn */
/* copy the data from the response tree */
for (eb32 = eb32_first(&res->response.answer_tree); eb32 != NULL; eb32 = eb32_next(eb32)) {
item = eb32_entry(eb32, typeof(*item), link);
/* only handle 1 entry */
if (item->type == DNS_RTYPE_TXT) {
int len = item->data_len;
if (len > DNS_MAX_NAME_SIZE)
len = DNS_MAX_NAME_SIZE;
rslv->txt = istdup(ist2(item->data.target, len));
break;
}
}
rslv->result = RSLV_STATUS_VALID;
done:
/* if there's no other DNS task for this acme task, wake up acme_task */
if (HA_ATOMIC_SUB_FETCH(rslv->dnstasks, 1) == 0) {
if (rslv->acme_task)
task_wakeup(rslv->acme_task, TASK_WOKEN_MSG);
}
return 1;
}
/* error callback, set the error code to rslv->result */
static int acme_rslv_error_cb(struct resolv_requester *req, int error_code)
{
struct acme_rslv *rslv = objt_acme_rslv(req->owner);
if (!rslv)
return 0;
rslv->result = error_code;
if (HA_ATOMIC_SUB_FETCH(rslv->dnstasks, 1) == 0) {
if (rslv->acme_task)
task_wakeup(rslv->acme_task, TASK_WOKEN_MSG);
}
return 0;
}
/* unlink from the resolver and free the acme_rslv */
void acme_rslv_free(struct acme_rslv *rslv)
{
if (!rslv)
return;
if (rslv->requester)
resolv_unlink_resolution(rslv->requester);
free(rslv->hostname_dn);
istfree(&rslv->txt);
free(rslv);
}
struct acme_rslv *acme_rslv_start(struct acme_auth *auth, unsigned int *dnstasks, char **errmsg)
{
struct acme_rslv *rslv = NULL;
struct resolvers *resolvers;
char hostname[DNS_MAX_NAME_SIZE + 1];
char dn[DNS_MAX_NAME_SIZE + 1];
int hostname_len;
int dn_len;
/* XXX: allow to change the resolvers section to use */
resolvers = find_resolvers_by_id("default");
if (!resolvers) {
memprintf(errmsg, "couldn't find the \"default\" resolvers section!\n");
goto error;
}
/* dns-01 TXT record lives at _acme-challenge.<domain> */
hostname_len = snprintf(hostname, sizeof(hostname), "_acme-challenge.%.*s",
(int)auth->dns.len, auth->dns.ptr);
if (hostname_len < 0 || hostname_len >= (int)sizeof(hostname)) {
memprintf(errmsg, "hostname \"_acme-challenge.%.*s\" too long!\n", (int)auth->dns.len, auth->dns.ptr);
goto error;
}
dn_len = resolv_str_to_dn_label(hostname, hostname_len, dn, sizeof(dn));
if (dn_len <= 0) {
memprintf(errmsg, "couldn't convert hostname \"_acme-challenge.%.*s\" into dn label\n", (int)auth->dns.len, auth->dns.ptr);
goto error;
}
rslv = calloc(1, sizeof(*rslv));
if (!rslv) {
memprintf(errmsg, "Could not allocate memory\n");
goto error;
}
rslv->obj_type = OBJ_TYPE_ACME_RSLV;
rslv->resolvers = resolvers;
rslv->hostname_dn = strdup(dn);
rslv->hostname_dn_len = dn_len;
rslv->result = RSLV_STATUS_NONE;
rslv->success_cb = acme_rslv_success_cb;
rslv->error_cb = acme_rslv_error_cb;
rslv->dnstasks = dnstasks;
if (!rslv->hostname_dn) {
memprintf(errmsg, "Could not allocate memory\n");
goto error;
}
if (resolv_link_resolution(rslv, OBJ_TYPE_ACME_RSLV, 0) < 0) {
memprintf(errmsg, "Could not create resolution task for \"%.*s\"\n", hostname_len, hostname);
goto error;
}
resolv_trigger_resolution(rslv->requester);
return rslv;
error:
if (rslv)
free(rslv->hostname_dn);
free(rslv);
return NULL;
}
#endif /* HAVE_ACME */
/*
* Local variables:
* c-indent-level: 8
* c-basic-offset: 8
* End:
*/

View File

@ -25,8 +25,7 @@
/* Check an action ruleset validity. It returns the number of error encountered
* and err_code is updated if a warning is emitted. It also takes this
* opportunity for filling the execution context based on available info.
* and err_code is updated if a warning is emitted.
*/
int check_action_rules(struct list *rules, struct proxy *px, int *err_code)
{
@ -41,13 +40,6 @@ int check_action_rules(struct list *rules, struct proxy *px, int *err_code)
}
*err_code |= warnif_tcp_http_cond(px, rule->cond);
ha_free(&errmsg);
if (!rule->exec_ctx.type) {
if (rule->kw && rule->kw->exec_ctx.type)
rule->exec_ctx = rule->kw->exec_ctx;
else if (rule->action_ptr)
rule->exec_ctx = EXEC_CTX_MAKE(TH_EX_CTX_FUNC, rule->action_ptr);
}
}
return err;
@ -386,24 +378,3 @@ void dump_act_rules(const struct list *rules, const char *pfx)
(akwn->flags & KWF_MATCH_PREFIX) ? "*" : "");
}
}
/* adds the keyword list kw_list to the head <head> */
void act_add_list(struct list *head, struct action_kw_list *kw_list)
{
int i;
for (i = 0; kw_list->kw[i].kw != NULL; i++) {
/* store declaration file/line if known */
if (kw_list->kw[i].exec_ctx.type)
continue;
if (caller_initcall) {
kw_list->kw[i].exec_ctx.type = TH_EX_CTX_INITCALL;
kw_list->kw[i].exec_ctx.initcall = caller_initcall;
} else {
kw_list->kw[i].exec_ctx.type = TH_EX_CTX_ACTION;
kw_list->kw[i].exec_ctx.action_kwl = kw_list;
}
}
LIST_APPEND(head, &kw_list->list);
}

View File

@ -29,11 +29,8 @@ struct show_prof_ctx {
int dump_step; /* 0,1,2,4,5,6; see cli_iohandler_show_profiling() */
int linenum; /* next line to be dumped (starts at 0) */
int maxcnt; /* max line count per step (0=not set) */
int by_what; /* 0=sort by usage, 1=sort by address, 2=sort by time, 3=sort by ctx */
int by_what; /* 0=sort by usage, 1=sort by address, 2=sort by time */
int aggr; /* 0=dump raw, 1=aggregate on callee */
/* 4-byte hole here */
struct sched_activity *tmp_activity; /* dynamically allocated during dumps */
struct memprof_stats *tmp_memstats; /* dynamically allocated during dumps */
};
/* CLI context for the "show activity" command */
@ -302,18 +299,13 @@ struct memprof_stats *memprof_get_bin(const void *ra, enum memprof_method meth)
int retries = 16; // up to 16 consecutive entries may be tested.
const void *old;
unsigned int bin;
ullong hash;
if (unlikely(!ra)) {
bin = MEMPROF_HASH_BUCKETS;
goto leave;
}
hash = _ptr2_hash_arg(ra, th_ctx->exec_ctx.pointer, th_ctx->exec_ctx.type);
for (bin = _ptr_hash_reduce(hash, MEMPROF_HASH_BITS);
memprof_stats[bin].caller != ra ||
memprof_stats[bin].exec_ctx.type != th_ctx->exec_ctx.type ||
memprof_stats[bin].exec_ctx.pointer != th_ctx->exec_ctx.pointer;
bin = (bin + (hash | 1)) & (MEMPROF_HASH_BUCKETS - 1)) {
bin = ptr_hash(ra, MEMPROF_HASH_BITS);
for (; memprof_stats[bin].caller != ra; bin = (bin + 1) & (MEMPROF_HASH_BUCKETS - 1)) {
if (!--retries) {
bin = MEMPROF_HASH_BUCKETS;
break;
@ -322,7 +314,6 @@ struct memprof_stats *memprof_get_bin(const void *ra, enum memprof_method meth)
old = NULL;
if (!memprof_stats[bin].caller &&
HA_ATOMIC_CAS(&memprof_stats[bin].caller, &old, ra)) {
memprof_stats[bin].exec_ctx = th_ctx->exec_ctx;
memprof_stats[bin].method = meth;
break;
}
@ -927,14 +918,6 @@ static int cmp_memprof_stats(const void *a, const void *b)
return -1;
else if (l->alloc_tot + l->free_tot < r->alloc_tot + r->free_tot)
return 1;
else if (l->exec_ctx.type > r->exec_ctx.type)
return -1;
else if (l->exec_ctx.type < r->exec_ctx.type)
return 1;
else if (l->exec_ctx.pointer > r->exec_ctx.pointer)
return -1;
else if (l->exec_ctx.pointer < r->exec_ctx.pointer)
return 1;
else
return 0;
}
@ -948,47 +931,6 @@ static int cmp_memprof_addr(const void *a, const void *b)
return -1;
else if (l->caller < r->caller)
return 1;
else if (l->exec_ctx.type > r->exec_ctx.type)
return -1;
else if (l->exec_ctx.type < r->exec_ctx.type)
return 1;
else if (l->exec_ctx.pointer > r->exec_ctx.pointer)
return -1;
else if (l->exec_ctx.pointer < r->exec_ctx.pointer)
return 1;
else
return 0;
}
static int cmp_memprof_ctx(const void *a, const void *b)
{
const struct memprof_stats *l = (const struct memprof_stats *)a;
const struct memprof_stats *r = (const struct memprof_stats *)b;
const void *ptrl = l->exec_ctx.pointer;
const void *ptrr = r->exec_ctx.pointer;
/* in case of a mux, we'll use the always-present ->subscribe()
* function as a sorting key so that mux-ops and other mux functions
* appear grouped together.
*/
if (l->exec_ctx.type == TH_EX_CTX_MUX)
ptrl = l->exec_ctx.mux_ops->subscribe;
if (r->exec_ctx.type == TH_EX_CTX_MUX)
ptrr = r->exec_ctx.mux_ops->subscribe;
if (ptrl > ptrr)
return -1;
else if (ptrl < ptrr)
return 1;
else if (l->exec_ctx.type > r->exec_ctx.type)
return -1;
else if (l->exec_ctx.type < r->exec_ctx.type)
return 1;
else if (l->caller > r->caller)
return -1;
else if (l->caller < r->caller)
return 1;
else
return 0;
}
@ -1050,9 +992,9 @@ struct sched_activity *sched_activity_entry(struct sched_activity *array, const
static int cli_io_handler_show_profiling(struct appctx *appctx)
{
struct show_prof_ctx *ctx = appctx->svcctx;
struct sched_activity *tmp_activity = ctx->tmp_activity;
struct sched_activity tmp_activity[SCHED_ACT_HASH_BUCKETS];
#ifdef USE_MEMORY_PROFILING
struct memprof_stats *tmp_memstats = ctx->tmp_memstats;
struct memprof_stats tmp_memstats[MEMPROF_HASH_BUCKETS + 1];
unsigned long long tot_alloc_calls, tot_free_calls;
unsigned long long tot_alloc_bytes, tot_free_bytes;
#endif
@ -1093,20 +1035,7 @@ static int cli_io_handler_show_profiling(struct appctx *appctx)
if ((ctx->dump_step & 3) != 1)
goto skip_tasks;
if (tmp_activity)
goto tasks_resume;
/* first call for show profiling tasks: we have to allocate a tmp
* array for sorting and processing, and possibly perform some
* sorting and aggregation.
*/
tmp_activity = ha_aligned_alloc(__alignof__(*tmp_activity), sizeof(sched_activity));
if (!tmp_activity)
goto end_tasks;
ctx->tmp_activity = tmp_activity;
memcpy(tmp_activity, sched_activity, sizeof(sched_activity));
memcpy(tmp_activity, sched_activity, sizeof(tmp_activity));
/* for addr sort and for callee aggregation we have to first sort by address */
if (ctx->aggr || ctx->by_what == 1) // sort by addr
qsort(tmp_activity, SCHED_ACT_HASH_BUCKETS, sizeof(tmp_activity[0]), cmp_sched_activity_addr);
@ -1131,7 +1060,6 @@ static int cli_io_handler_show_profiling(struct appctx *appctx)
else if (ctx->by_what == 2) // by cpu_tot
qsort(tmp_activity, SCHED_ACT_HASH_BUCKETS, sizeof(tmp_activity[0]), cmp_sched_activity_cpu);
tasks_resume:
if (!ctx->linenum)
chunk_appendf(&trash, "Tasks activity over %.3f sec till %.3f sec ago:\n"
" function calls cpu_tot cpu_avg lkw_avg lkd_avg mem_avg lat_avg\n",
@ -1195,8 +1123,6 @@ static int cli_io_handler_show_profiling(struct appctx *appctx)
return 0;
}
end_tasks:
ha_free(&ctx->tmp_activity);
ctx->linenum = 0; // reset first line to dump
if ((ctx->dump_step & 4) == 0)
ctx->dump_step++; // next step
@ -1207,57 +1133,16 @@ static int cli_io_handler_show_profiling(struct appctx *appctx)
if ((ctx->dump_step & 3) != 2)
goto skip_mem;
if (tmp_memstats)
goto memstats_resume;
/* first call for show profiling memory: we have to allocate a tmp
* array for sorting and processing, and possibly perform some sorting
* and aggregation.
*/
tmp_memstats = ha_aligned_alloc(__alignof__(*tmp_memstats), sizeof(memprof_stats));
if (!tmp_memstats)
goto end_memstats;
ctx->tmp_memstats = tmp_memstats;
memcpy(tmp_memstats, memprof_stats, sizeof(memprof_stats));
if (ctx->by_what == 1)
memcpy(tmp_memstats, memprof_stats, sizeof(tmp_memstats));
if (ctx->by_what)
qsort(tmp_memstats, MEMPROF_HASH_BUCKETS+1, sizeof(tmp_memstats[0]), cmp_memprof_addr);
else if (ctx->by_what == 3)
qsort(tmp_memstats, MEMPROF_HASH_BUCKETS+1, sizeof(tmp_memstats[0]), cmp_memprof_ctx);
else
qsort(tmp_memstats, MEMPROF_HASH_BUCKETS+1, sizeof(tmp_memstats[0]), cmp_memprof_stats);
if (ctx->aggr) {
/* merge entries for the same caller and reset the exec_ctx */
for (i = j = 0; i < MEMPROF_HASH_BUCKETS; i++) {
if ((tmp_memstats[i].alloc_calls | tmp_memstats[i].free_calls) == 0)
continue;
for (j = i + 1; j < MEMPROF_HASH_BUCKETS; j++) {
if ((tmp_memstats[j].alloc_calls | tmp_memstats[j].free_calls) == 0)
continue;
if (tmp_memstats[j].caller != tmp_memstats[i].caller ||
tmp_memstats[j].method != tmp_memstats[i].method ||
tmp_memstats[j].info != tmp_memstats[i].info)
continue;
tmp_memstats[i].locked_calls += tmp_memstats[j].locked_calls;
tmp_memstats[i].alloc_calls += tmp_memstats[j].alloc_calls;
tmp_memstats[i].free_calls += tmp_memstats[j].free_calls;
tmp_memstats[i].alloc_tot += tmp_memstats[j].alloc_tot;
tmp_memstats[i].free_tot += tmp_memstats[j].free_tot;
/* don't dump the ctx */
tmp_memstats[i].exec_ctx.type = 0;
/* don't dump the merged entry */
tmp_memstats[j].alloc_calls = tmp_memstats[j].free_calls = 0;
}
}
}
memstats_resume:
if (!ctx->linenum)
chunk_appendf(&trash,
"Alloc/Free statistics by call place over %.3f sec till %.3f sec ago:\n"
" Calls | Tot Bytes | Caller, method, extra info\n"
" Calls | Tot Bytes | Caller and method\n"
"<- alloc -> <- free ->|<-- alloc ---> <-- free ---->|\n",
(prof_mem_start_ns ? (prof_mem_stop_ns ? prof_mem_stop_ns : now_ns) - prof_mem_start_ns : 0) / 1000000000.0,
(prof_mem_stop_ns ? now_ns - prof_mem_stop_ns : 0) / 1000000000.0);
@ -1315,7 +1200,6 @@ static int cli_io_handler_show_profiling(struct appctx *appctx)
(int)((1000ULL * entry->locked_calls / tot_calls) % 10));
}
chunk_append_thread_ctx(&trash, &entry->exec_ctx, " [via ", "]");
chunk_appendf(&trash, "\n");
if (applet_putchk(appctx, &trash) == -1)
@ -1425,15 +1309,9 @@ static int cli_io_handler_show_profiling(struct appctx *appctx)
tot_alloc_calls - tot_free_calls,
tot_alloc_bytes - tot_free_bytes);
/* release optional buffer name */
for (i = 0; i < max; i++)
ha_free(&tmp_memstats[i].info);
if (applet_putchk(appctx, &trash) == -1)
return 0;
end_memstats:
ha_free(&ctx->tmp_memstats);
ctx->linenum = 0; // reset first line to dump
if ((ctx->dump_step & 4) == 0)
ctx->dump_step++; // next step
@ -1444,15 +1322,6 @@ static int cli_io_handler_show_profiling(struct appctx *appctx)
return 1;
}
/* release structs allocated by "show profiling" */
static void cli_release_show_profiling(struct appctx *appctx)
{
struct show_prof_ctx *ctx = appctx->svcctx;
ha_free(&ctx->tmp_activity);
ha_free(&ctx->tmp_memstats);
}
/* parse a "show profiling" command. It returns 1 on failure, 0 if it starts to dump.
* - cli.i0 is set to the first state (0=all, 4=status, 5=tasks, 6=memory)
* - cli.o1 is set to 1 if the output must be sorted by addr instead of usage
@ -1485,9 +1354,6 @@ static int cli_parse_show_profiling(char **args, char *payload, struct appctx *a
else if (strcmp(args[arg], "bytime") == 0) {
ctx->by_what = 2; // sort output by total time instead of usage
}
else if (strcmp(args[arg], "byctx") == 0) {
ctx->by_what = 3; // sort output by caller context instead of usage
}
else if (strcmp(args[arg], "aggr") == 0) {
ctx->aggr = 1; // aggregate output by callee
}
@ -1495,7 +1361,7 @@ static int cli_parse_show_profiling(char **args, char *payload, struct appctx *a
ctx->maxcnt = atoi(args[arg]); // number of entries to dump
}
else
return cli_err(appctx, "Expects either 'all', 'status', 'tasks', 'memory', 'byaddr', 'bytime', 'byctx', 'aggr' or a max number of output lines.\n");
return cli_err(appctx, "Expects either 'all', 'status', 'tasks', 'memory', 'byaddr', 'bytime', 'aggr' or a max number of output lines.\n");
}
return 0;
}
@ -1839,7 +1705,7 @@ INITCALL1(STG_REGISTER, cfg_register_keywords, &cfg_kws);
static struct cli_kw_list cli_kws = {{ },{
{ { "set", "profiling", NULL }, "set profiling <what> {auto|on|off} : enable/disable resource profiling (tasks,memory)", cli_parse_set_profiling, NULL },
{ { "show", "activity", NULL }, "show activity [-1|0|thread_num] : show per-thread activity stats (for support/developers)", cli_parse_show_activity, cli_io_handler_show_activity, NULL },
{ { "show", "profiling", NULL }, "show profiling [<what>|<#lines>|<opts>]*: show profiling state (all,status,tasks,memory)", cli_parse_show_profiling, cli_io_handler_show_profiling, cli_release_show_profiling },
{ { "show", "profiling", NULL }, "show profiling [<what>|<#lines>|<opts>]*: show profiling state (all,status,tasks,memory)", cli_parse_show_profiling, cli_io_handler_show_profiling, NULL },
{ { "show", "tasks", NULL }, "show tasks : show running tasks", NULL, cli_io_handler_show_tasks, NULL },
{{},}
}};

View File

@ -31,6 +31,7 @@ unsigned int nb_applets = 0;
DECLARE_TYPED_POOL(pool_head_appctx, "appctx", struct appctx);
/* trace source and events */
static void applet_trace(enum trace_level level, uint64_t mask,
const struct trace_source *src,
@ -416,7 +417,7 @@ void appctx_shut(struct appctx *appctx)
TRACE_ENTER(APPLET_EV_RELEASE, appctx);
if (appctx->applet->release)
CALL_APPLET_NO_RET(appctx->applet, release(appctx));
appctx->applet->release(appctx);
applet_fl_set(appctx, APPCTX_FL_SHUTDOWN);
b_dequeue(&appctx->buffer_wait);
@ -511,7 +512,7 @@ size_t appctx_htx_rcv_buf(struct appctx *appctx, struct buffer *buf, size_t coun
goto out;
}
htx_xfer(buf_htx, appctx_htx, count, HTX_XFER_DEFAULT);
htx_xfer_blks(buf_htx, appctx_htx, count, HTX_BLK_UNUSED);
buf_htx->flags |= (appctx_htx->flags & (HTX_FL_PARSING_ERROR|HTX_FL_PROCESSING_ERROR));
if (htx_is_empty(appctx_htx)) {
buf_htx->flags |= (appctx_htx->flags & HTX_FL_EOM);
@ -550,7 +551,7 @@ size_t appctx_rcv_buf(struct stconn *sc, struct buffer *buf, size_t count, unsig
if (flags & CO_RFL_BUF_FLUSH)
applet_fl_set(appctx, APPCTX_FL_FASTFWD);
ret = CALL_APPLET_WITH_RET(appctx->applet, rcv_buf(appctx, buf, count, flags));
ret = appctx->applet->rcv_buf(appctx, buf, count, flags);
if (ret)
applet_fl_clr(appctx, APPCTX_FL_OUTBLK_FULL);
@ -608,7 +609,7 @@ size_t appctx_htx_snd_buf(struct appctx *appctx, struct buffer *buf, size_t coun
goto end;
}
htx_xfer(appctx_htx, buf_htx, count, HTX_XFER_DEFAULT);
htx_xfer_blks(appctx_htx, buf_htx, count, HTX_BLK_UNUSED);
if (htx_is_empty(buf_htx)) {
appctx_htx->flags |= (buf_htx->flags & HTX_FL_EOM);
}
@ -658,7 +659,7 @@ size_t appctx_snd_buf(struct stconn *sc, struct buffer *buf, size_t count, unsig
goto end;
}
ret = CALL_APPLET_WITH_RET(appctx->applet, snd_buf(appctx, buf, count, flags));
ret = appctx->applet->snd_buf(appctx, buf, count, flags);
if (applet_fl_test(appctx, (APPCTX_FL_ERROR|APPCTX_FL_ERR_PENDING)))
se_report_term_evt(appctx->sedesc, se_tevt_type_snd_err);
@ -715,7 +716,7 @@ int appctx_fastfwd(struct stconn *sc, unsigned int count, unsigned int flags)
}
b_add(sdo->iobuf.buf, sdo->iobuf.offset);
ret = CALL_APPLET_WITH_RET(appctx->applet, fastfwd(appctx, sdo->iobuf.buf, len, 0));
ret = appctx->applet->fastfwd(appctx, sdo->iobuf.buf, len, 0);
b_sub(sdo->iobuf.buf, sdo->iobuf.offset);
sdo->iobuf.data += ret;
@ -852,7 +853,7 @@ struct task *task_run_applet(struct task *t, void *context, unsigned int state)
* already called)
*/
if (!se_fl_test(app->sedesc, SE_FL_SHR) || !se_fl_test(app->sedesc, SE_FL_SHW))
CALL_APPLET_NO_RET(app->applet, fct(app));
app->applet->fct(app);
TRACE_POINT(APPLET_EV_PROCESS, app);
@ -899,7 +900,7 @@ struct task *task_run_applet(struct task *t, void *context, unsigned int state)
stream_dump_and_crash(&app->obj_type, read_freq_ctr(&app->call_rate));
}
sc_applet_process(sc);
sc->app_ops->wake(sc);
channel_release_buffer(ic, &app->buffer_wait);
TRACE_LEAVE(APPLET_EV_PROCESS, app);
return t;
@ -953,7 +954,7 @@ struct task *task_process_applet(struct task *t, void *context, unsigned int sta
* already called)
*/
if (!applet_fl_test(app, APPCTX_FL_SHUTDOWN))
CALL_APPLET_NO_RET(app->applet, fct(app));
app->applet->fct(app);
TRACE_POINT(APPLET_EV_PROCESS, app);
@ -992,7 +993,7 @@ struct task *task_process_applet(struct task *t, void *context, unsigned int sta
stream_dump_and_crash(&app->obj_type, read_freq_ctr(&app->call_rate));
}
sc_applet_process(sc);
sc->app_ops->wake(sc);
appctx_release_buffers(app);
TRACE_LEAVE(APPLET_EV_PROCESS, app);
return t;

View File

@ -1396,7 +1396,7 @@ check_tgid:
tree = search_tree ? &srv->per_thr[i].safe_conns : &srv->per_thr[i].idle_conns;
conn = srv_lookup_conn(tree, hash);
while (conn) {
if (conn->mux->takeover && CALL_MUX_WITH_RET(conn->mux, takeover(conn, i, 0)) == 0) {
if (conn->mux->takeover && conn->mux->takeover(conn, i, 0) == 0) {
conn_delete_from_tree(conn, i);
_HA_ATOMIC_INC(&activity[tid].fd_takeover);
found = 1;
@ -1498,7 +1498,7 @@ takeover_random_idle_conn(struct ceb_root **root, int curtid)
conn = ceb64_item_first(root, hash_node.node, hash_node.key, struct connection);
while (conn) {
if (conn->mux->takeover && CALL_MUX_WITH_RET(conn->mux, takeover(conn, curtid, 1)) == 0) {
if (conn->mux->takeover && conn->mux->takeover(conn, curtid, 1) == 0) {
conn_delete_from_tree(conn, curtid);
return conn;
}
@ -1555,7 +1555,7 @@ kill_random_idle_conn(struct server *srv)
*/
_HA_ATOMIC_INC(&srv->curr_used_conns);
}
CALL_MUX_NO_RET(conn->mux, destroy(conn->ctx));
conn->mux->destroy(conn->ctx);
return 1;
}
return 0;
@ -1765,7 +1765,7 @@ int be_reuse_connection(int64_t hash, struct session *sess,
}
if (avail >= 1) {
if (CALL_MUX_WITH_RET(srv_conn->mux, attach(srv_conn, sc->sedesc, sess)) == -1) {
if (srv_conn->mux->attach(srv_conn, sc->sedesc, sess) == -1) {
if (sc_reset_endp(sc) < 0)
goto err;
sc_ep_clr(sc, ~SE_FL_DETACHED);
@ -1879,7 +1879,7 @@ int connect_server(struct stream *s)
* It will in turn call srv_release_conn through
* conn_free which also uses it.
*/
CALL_MUX_NO_RET(tokill_conn->mux, destroy(tokill_conn->ctx));
tokill_conn->mux->destroy(tokill_conn->ctx);
}
else {
HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
@ -2067,7 +2067,7 @@ int connect_server(struct stream *s)
* available.
*
* This check must be performed before conn_prepare()
* to ensure consistency across the whole stack, in
* to ensure consistency accross the whole stack, in
* particular for QUIC between quic-conn and mux layer.
*/
if (IS_HTX_STRM(s) && srv->use_ssl &&
@ -2204,7 +2204,7 @@ int connect_server(struct stream *s)
*/
if (may_start_mux_now) {
const struct mux_ops *alt_mux =
likely(!(s->flags & SF_WEBSOCKET) || !srv) ? NULL : srv_get_ws_proto(srv);
likely(!(s->flags & SF_WEBSOCKET)) ? NULL : srv_get_ws_proto(srv);
if (conn_install_mux_be(srv_conn, s->scb, s->sess, alt_mux) < 0) {
conn_full_close(srv_conn);
return SF_ERR_INTERNAL;
@ -3063,7 +3063,7 @@ int be_downtime(struct proxy *px) {
/* Checks if <px> backend supports the addition of servers at runtime. Either a
* backend or a defaults proxy are supported. If proxy is incompatible, <msg>
* will be allocated to contain a textual explanation.
* will be allocated to contain a textual explaination.
*/
int be_supports_dynamic_srv(struct proxy *px, char **msg)
{

View File

@ -626,7 +626,7 @@ cache_store_check(struct proxy *px, struct flt_conf *fconf)
return 1;
}
}
else if (f->id == http_comp_req_flt_id || f->id == http_comp_res_flt_id)
else if (f->id == http_comp_flt_id)
comp = 1;
else if (f->id == fcgi_flt_id)
continue;

View File

@ -71,7 +71,7 @@ static void srv_diag_cookies(int *ret, struct server *srv, struct eb_root *cooki
static void srv_diag_check_reuse(int *ret, struct server *srv, struct proxy *px)
{
if (srv->do_check && srv->check.reuse_pool) {
if (px->tcpcheck.rs && (px->tcpcheck.rs->flags & TCPCHK_RULES_PROTO_CHK) != TCPCHK_RULES_HTTP_CHK) {
if ((px->tcpcheck_rules.flags & TCPCHK_RULES_PROTO_CHK) != TCPCHK_RULES_HTTP_CHK) {
diag_warning(ret, "parsing [%s:%d] : 'server %s': check-reuse-pool is ineffective for non http-check rulesets.\n",
srv->conf.file, srv->conf.line, srv->id);
}

View File

@ -89,23 +89,12 @@ int cfg_parse_global(const char *file, int linenum, char **args, int kwm)
global.tune.options |= GTUNE_BUSY_POLLING;
}
else if (strcmp(args[0], "set-dumpable") == 0) { /* "no set-dumpable" or "set-dumpable" */
if (alertif_too_many_args(1, file, linenum, args, &err_code))
if (alertif_too_many_args(0, file, linenum, args, &err_code))
goto out;
if (kwm == KWM_NO) {
if (kwm == KWM_NO)
global.tune.options &= ~GTUNE_SET_DUMPABLE;
goto out;
}
if (!*args[1] || strcmp(args[1], "on") == 0)
global.tune.options |= GTUNE_SET_DUMPABLE;
else if (strcmp(args[1], "libs") == 0)
global.tune.options |= GTUNE_SET_DUMPABLE | GTUNE_COLLECT_LIBS;
else if (strcmp(args[1], "off") == 0)
global.tune.options &= ~GTUNE_SET_DUMPABLE;
else {
ha_alert("parsing [%s:%d] : '%s' only supports 'on' and 'off' as an argument, found '%s'.\n", file, linenum, args[0], args[1]);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
else
global.tune.options |= GTUNE_SET_DUMPABLE;
}
else if (strcmp(args[0], "h2-workaround-bogus-websocket-clients") == 0) { /* "no h2-workaround-bogus-websocket-clients" or "h2-workaround-bogus-websocket-clients" */
if (alertif_too_many_args(0, file, linenum, args, &err_code))

View File

@ -1358,15 +1358,14 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
goto out;
}
if (warnif_misplaced_http_req(curproxy, file, linenum, args[0], NULL))
err_code |= ERR_WARN;
err_code |= warnif_misplaced_http_req(curproxy, file, linenum, args[0], NULL);
if (curproxy->cap & PR_CAP_FE)
where |= SMP_VAL_FE_HRQ_HDR;
if (curproxy->cap & PR_CAP_BE)
where |= SMP_VAL_BE_HRQ_HDR;
err_code |= warnif_cond_conflicts(rule->cond, where, &errmsg);
if (errmsg && *errmsg)
if (err_code)
ha_warning("parsing [%s:%d] : '%s.\n'", file, linenum, errmsg);
LIST_APPEND(&curproxy->http_req_rules, &rule->list);
@ -1401,7 +1400,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
if (curproxy->cap & PR_CAP_BE)
where |= SMP_VAL_BE_HRS_HDR;
err_code |= warnif_cond_conflicts(rule->cond, where, &errmsg);
if (errmsg && *errmsg)
if (err_code)
ha_warning("parsing [%s:%d] : '%s.\n'", file, linenum, errmsg);
LIST_APPEND(&curproxy->http_res_rules, &rule->list);
@ -1435,7 +1434,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
if (curproxy->cap & PR_CAP_BE)
where |= SMP_VAL_BE_HRS_HDR;
err_code |= warnif_cond_conflicts(rule->cond, where, &errmsg);
if (errmsg && *errmsg)
if (err_code)
ha_warning("parsing [%s:%d] : '%s.\n'", file, linenum, errmsg);
LIST_APPEND(&curproxy->http_after_res_rules, &rule->list);
@ -1492,15 +1491,14 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
}
LIST_APPEND(&curproxy->redirect_rules, &rule->list);
if (warnif_misplaced_redirect(curproxy, file, linenum, args[0], NULL))
err_code |= ERR_WARN;
err_code |= warnif_misplaced_redirect(curproxy, file, linenum, args[0], NULL);
if (curproxy->cap & PR_CAP_FE)
where |= SMP_VAL_FE_HRQ_HDR;
if (curproxy->cap & PR_CAP_BE)
where |= SMP_VAL_BE_HRQ_HDR;
err_code |= warnif_cond_conflicts(rule->cond, where, &errmsg);
if (errmsg && *errmsg)
if (err_code)
ha_warning("parsing [%s:%d] : '%s.\n'", file, linenum, errmsg);
}
else if (strcmp(args[0], "use_backend") == 0) {
@ -1530,7 +1528,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
}
err_code |= warnif_cond_conflicts(cond, SMP_VAL_FE_SET_BCK, &errmsg);
if (errmsg && *errmsg)
if (err_code)
ha_warning("parsing [%s:%d] : '%s.\n'", file, linenum, errmsg);
}
else if (*args[2]) {
@ -1593,7 +1591,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
}
err_code |= warnif_cond_conflicts(cond, SMP_VAL_BE_SET_SRV, &errmsg);
if (errmsg && *errmsg)
if (err_code)
ha_warning("parsing [%s:%d] : '%s.\n'", file, linenum, errmsg);
rule = calloc(1, sizeof(*rule));
@ -1648,7 +1646,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
* where force-persist is applied.
*/
err_code |= warnif_cond_conflicts(cond, SMP_VAL_BE_REQ_CNT, &errmsg);
if (errmsg && *errmsg)
if (err_code)
ha_warning("parsing [%s:%d] : '%s.\n'", file, linenum, errmsg);
rule = calloc(1, sizeof(*rule));
@ -1816,7 +1814,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
err_code |= warnif_cond_conflicts(cond, SMP_VAL_BE_STO_RUL, &errmsg);
else
err_code |= warnif_cond_conflicts(cond, SMP_VAL_BE_SET_SRV, &errmsg);
if (errmsg && *errmsg)
if (err_code)
ha_warning("parsing [%s:%d] : '%s.\n'", file, linenum, errmsg);
rule = calloc(1, sizeof(*rule));
@ -1874,7 +1872,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
if (curproxy->cap & PR_CAP_BE)
where |= SMP_VAL_BE_HRQ_HDR;
err_code |= warnif_cond_conflicts(cond, where, &errmsg);
if (errmsg && *errmsg)
if (err_code)
ha_warning("parsing [%s:%d] : '%s.\n'", file, linenum, errmsg);
rule = calloc(1, sizeof(*rule));
@ -1954,7 +1952,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
if (curproxy->cap & PR_CAP_BE)
where |= SMP_VAL_BE_HRQ_HDR;
err_code |= warnif_cond_conflicts(rule->cond, where, &errmsg);
if (errmsg && *errmsg)
if (err_code)
ha_warning("parsing [%s:%d] : '%s.\n'", file, linenum, errmsg);
LIST_APPEND(&curproxy->uri_auth->http_req_rules, &rule->list);
@ -1976,10 +1974,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
if (!stats_check_init_uri_auth(&curproxy->uri_auth))
goto alloc_error;
} else if (strcmp(args[1], "hide-version") == 0) {
if (curproxy->uri_auth)
curproxy->uri_auth->flags &= ~STAT_F_SHOWVER;
} else if (strcmp(args[1], "show-version") == 0) {
if (!stats_set_flag(&curproxy->uri_auth, STAT_F_SHOWVER))
if (!stats_set_flag(&curproxy->uri_auth, STAT_F_HIDEVER))
goto alloc_error;
} else if (strcmp(args[1], "show-legends") == 0) {
if (!stats_set_flag(&curproxy->uri_auth, STAT_F_SHLGNDS))
@ -2046,7 +2041,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
}
} else {
stats_error_parsing:
ha_alert("parsing [%s:%d]: %s '%s', expects 'admin', 'uri', 'realm', 'auth', 'scope', 'enable', 'hide-version', 'show-node', 'show-desc' , 'show-legends' or 'show-version'.\n",
ha_alert("parsing [%s:%d]: %s '%s', expects 'admin', 'uri', 'realm', 'auth', 'scope', 'enable', 'hide-version', 'show-node', 'show-desc' or 'show-legends'.\n",
file, linenum, *args[1]?"unknown stats parameter":"missing keyword in", args[*args[1]?1:0]);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
@ -2205,42 +2200,6 @@ stats_error_parsing:
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
else if (strcmp(args[1], "use-small-buffers") == 0) {
unsigned int flags = PR_O2_USE_SBUF_ALL;
if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[1], NULL)) {
err_code |= ERR_WARN;
goto out;
}
if (*(args[2])) {
int cur_arg;
flags = 0;
for (cur_arg = 2; *(args[cur_arg]); cur_arg++) {
if (strcmp(args[cur_arg], "queue") == 0)
flags |= PR_O2_USE_SBUF_QUEUE;
else if (strcmp(args[cur_arg], "l7-retries") == 0)
flags |= PR_O2_USE_SBUF_L7_RETRY;
else if (strcmp(args[cur_arg], "check") == 0)
flags |= PR_O2_USE_SBUF_CHECK;
else {
ha_alert("parsing [%s:%d] : invalid parameter '%s'. option '%s' expects 'queue', 'l7-retries' or 'check' value.\n",
file, linenum, args[cur_arg], args[1]);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
}
}
if (kwm == KWM_STD) {
curproxy->options2 &= ~PR_O2_USE_SBUF_ALL;
curproxy->options2 |= flags;
}
else if (kwm == KWM_NO) {
curproxy->options2 &= ~flags;
}
goto out;
}
if (kwm != KWM_STD) {
ha_alert("parsing [%s:%d]: negation/default is not supported for option '%s'.\n",
@ -2598,8 +2557,7 @@ stats_error_parsing:
goto out;
}
if (warnif_misplaced_monitor(curproxy, file, linenum, args[0], args[1]))
err_code |= ERR_WARN;
err_code |= warnif_misplaced_monitor(curproxy, file, linenum, args[0], args[1]);
if ((cond = build_acl_cond(file, linenum, &curproxy->acl, curproxy, (const char **)args + 2, &errmsg)) == NULL) {
ha_alert("parsing [%s:%d] : error detected while parsing a '%s %s' condition : %s.\n",
file, linenum, args[0], args[1], errmsg);

View File

@ -521,7 +521,7 @@ static int ssl_parse_global_keylog(char **args, int section_type, struct proxy *
}
#endif
/* Allow to explicitly disable certificate compression when set to "off" */
/* Allow to explicitely disable certificate compression when set to "off" */
#ifdef SSL_OP_NO_RX_CERTIFICATE_COMPRESSION
static int ssl_parse_certificate_compression(char **args, int section_type, struct proxy *curpx,
const struct proxy *defpx, const char *file, int line,

View File

@ -63,7 +63,6 @@
#include <haproxy/global.h>
#include <haproxy/http_ana.h>
#include <haproxy/http_rules.h>
#include <haproxy/http_htx.h>
#include <haproxy/lb_chash.h>
#include <haproxy/lb_fas.h>
#include <haproxy/lb_fwlc.h>
@ -2319,18 +2318,6 @@ int check_config_validity()
"Please fix either value to remove this warning.\n",
global.tune.bufsize_large, global.tune.bufsize);
global.tune.bufsize_large = 0;
err_code |= ERR_WARN;
}
}
if (global.tune.bufsize_small > 0) {
if (global.tune.bufsize_small == global.tune.bufsize)
global.tune.bufsize_small = 0;
else if (global.tune.bufsize_small > global.tune.bufsize) {
ha_warning("invalid small buffer size %d bytes which is greater to default bufsize %d bytes.\n",
global.tune.bufsize_small, global.tune.bufsize);
global.tune.bufsize_small = 0;
err_code |= ERR_WARN;
}
}
@ -2390,9 +2377,6 @@ int check_config_validity()
cfgerr += check_action_rules(&defpx->http_req_rules, defpx, &err_code);
cfgerr += check_action_rules(&defpx->http_res_rules, defpx, &err_code);
cfgerr += check_action_rules(&defpx->http_after_res_rules, defpx, &err_code);
#ifdef USE_QUIC
cfgerr += check_action_rules(&defpx->quic_init_rules, defpx, &err_code);
#endif
err = NULL;
i = smp_resolve_args(defpx, &err);
@ -2405,8 +2389,6 @@ int check_config_validity()
else {
cfgerr += acl_find_targets(defpx);
}
err_code |= proxy_check_http_errors(defpx);
}
/* starting to initialize the main proxies list */

View File

@ -235,7 +235,19 @@ static void check_trace(enum trace_level level, uint64_t mask,
if (mask & CHK_EV_TCPCHK) {
const char *type;
type = tcpcheck_ruleset_type_to_str(check->tcpcheck->rs);
switch (check->tcpcheck_rules->flags & TCPCHK_RULES_PROTO_CHK) {
case TCPCHK_RULES_PGSQL_CHK: type = "PGSQL"; break;
case TCPCHK_RULES_REDIS_CHK: type = "REDIS"; break;
case TCPCHK_RULES_SMTP_CHK: type = "SMTP"; break;
case TCPCHK_RULES_HTTP_CHK: type = "HTTP"; break;
case TCPCHK_RULES_MYSQL_CHK: type = "MYSQL"; break;
case TCPCHK_RULES_LDAP_CHK: type = "LDAP"; break;
case TCPCHK_RULES_SSL3_CHK: type = "SSL3"; break;
case TCPCHK_RULES_AGENT_CHK: type = "AGENT"; break;
case TCPCHK_RULES_SPOP_CHK: type = "SPOP"; break;
case TCPCHK_RULES_TCP_CHK: type = "TCP"; break;
default: type = "???"; break;
}
if (check->current_step)
chunk_appendf(&trace_buf, " - tcp-check=(%s,%d)", type, tcpcheck_get_step_id(check, NULL));
else
@ -259,7 +271,7 @@ static void check_trace(enum trace_level level, uint64_t mask,
buf = (b_is_null(&check->bo) ? NULL : &check->bo);
if (buf) {
if ((check->tcpcheck->rs->flags & TCPCHK_RULES_PROTO_CHK) == TCPCHK_RULES_HTTP_CHK) {
if ((check->tcpcheck_rules->flags & TCPCHK_RULES_PROTO_CHK) == TCPCHK_RULES_HTTP_CHK) {
int full = (src->verbosity == CHK_VERB_COMPLETE);
chunk_memcat(&trace_buf, "\n\t", 2);
@ -820,7 +832,7 @@ void chk_report_conn_err(struct check *check, int errno_bck, int expired)
chk = get_trash_chunk();
if (check->type == PR_O2_TCPCHK_CHK &&
(check->tcpcheck->rs->flags & TCPCHK_RULES_PROTO_CHK) == TCPCHK_RULES_TCP_CHK) {
(check->tcpcheck_rules->flags & TCPCHK_RULES_PROTO_CHK) == TCPCHK_RULES_TCP_CHK) {
step = tcpcheck_get_step_id(check, NULL);
if (!step) {
TRACE_DEVEL("initial connection failure", CHK_EV_HCHK_END|CHK_EV_HCHK_ERR, check);
@ -1033,12 +1045,13 @@ int httpchk_build_status_header(struct server *s, struct buffer *buf)
/**************************************************************************/
/***************** Health-checks based on connections *********************/
/**************************************************************************/
/* This function handles connection status updates including errors. If
* necessary, it wakes the check task up.
/* This function is used only for server health-checks. It handles connection
* status updates including errors. If necessary, it wakes the check task up.
* It returns 0 on normal cases, <0 if at least one close() has happened on the
* connection (eg: reconnect). It relies on tcpcheck_main().
*/
struct task *srv_chk_io_cb(struct task *t, void *ctx, unsigned int state)
int wake_srv_chk(struct stconn *sc)
{
struct stconn *sc = ctx;
struct connection *conn;
struct check *check = __sc_check(sc);
int ret = 0;
@ -1085,6 +1098,15 @@ struct task *srv_chk_io_cb(struct task *t, void *ctx, unsigned int state)
end:
TRACE_LEAVE(CHK_EV_HCHK_WAKE, check);
return ret;
}
/* This function checks if any I/O is wanted, and if so, attempts to do so */
struct task *srv_chk_io_cb(struct task *t, void *ctx, unsigned int state)
{
struct stconn *sc = ctx;
wake_srv_chk(sc);
return t;
}
@ -1305,7 +1327,7 @@ struct task *process_chk_conn(struct task *t, void *context, unsigned int state)
check->current_step = NULL;
check->sc = sc_new_from_check(check);
check->sc = sc_new_from_check(check, SC_FL_NONE);
if (!check->sc) {
set_server_check_status(check, HCHK_STATUS_SOCKERR, NULL);
goto end;
@ -1503,15 +1525,13 @@ int check_buf_available(void *target)
/*
* Allocate a buffer. If it fails, it adds the check in buffer wait queue.
*/
struct buffer *check_get_buf(struct check *check, struct buffer *bptr, unsigned int small_buffer)
struct buffer *check_get_buf(struct check *check, struct buffer *bptr)
{
struct buffer *buf = NULL;
if (small_buffer == 0 || (buf = b_alloc_small(bptr)) == NULL) {
if (likely(!LIST_INLIST(&check->buf_wait.list)) &&
unlikely((buf = b_alloc(bptr, DB_CHANNEL)) == NULL)) {
b_queue(DB_CHANNEL, &check->buf_wait, check, check_buf_available);
}
if (likely(!LIST_INLIST(&check->buf_wait.list)) &&
unlikely((buf = b_alloc(bptr, DB_CHANNEL)) == NULL)) {
b_queue(DB_CHANNEL, &check->buf_wait, check, check_buf_available);
}
return buf;
}
@ -1523,11 +1543,8 @@ struct buffer *check_get_buf(struct check *check, struct buffer *bptr, unsigned
void check_release_buf(struct check *check, struct buffer *bptr)
{
if (bptr->size) {
int defbuf = b_is_default(bptr);
b_free(bptr);
if (defbuf)
offer_buffers(check->buf_wait.target, 1);
offer_buffers(check->buf_wait.target, 1);
}
}
@ -1552,10 +1569,9 @@ void free_check(struct check *check)
* done for health-check : the proxy is the owner of the rules / vars
* in this case.
*/
if (check->state & CHK_ST_AGENT || check->tcpcheck->healthcheck) {
free_tcpcheck_vars(&check->tcpcheck->preset_vars);
ha_free(&check->tcpcheck->healthcheck);
ha_free(&check->tcpcheck);
if (check->state & CHK_ST_AGENT) {
free_tcpcheck_vars(&check->tcpcheck_rules->preset_vars);
ha_free(&check->tcpcheck_rules);
}
ha_free(&check->pool_conn_name);
@ -1648,6 +1664,7 @@ int start_check_task(struct check *check, int mininter,
*/
static int start_checks()
{
struct proxy *px;
struct server *s;
char *errmsg = NULL;
@ -1674,10 +1691,6 @@ static int start_checks()
*/
for (px = proxies_list; px; px = px->next) {
for (s = px->srv; s; s = s->next) {
if ((px->options2 & PR_O2_USE_SBUF_CHECK) &&
(s->check.tcpcheck->rs->flags & TCPCHK_RULES_MAY_USE_SBUF))
s->check.state |= CHK_ST_USE_SMALL_BUFF;
if (s->check.state & CHK_ST_CONFIGURED) {
nbcheck++;
if ((srv_getinter(&s->check) >= SRV_CHK_INTER_THRES) &&
@ -1792,7 +1805,7 @@ int init_srv_check(struct server *srv)
if (!srv->do_check || !(srv->proxy->cap & PR_CAP_BE))
goto out;
check_type = srv->check.tcpcheck->rs->flags & TCPCHK_RULES_PROTO_CHK;
check_type = srv->check.tcpcheck_rules->flags & TCPCHK_RULES_PROTO_CHK;
if (!(srv->flags & SRV_F_DYNAMIC)) {
/* If neither a port nor an addr was specified and no check
@ -1802,15 +1815,7 @@ int init_srv_check(struct server *srv)
* specified.
*/
if (!srv->check.port && !is_addr(&srv->check.addr)) {
/*
* If any setting is set for the check, then we can't
* assume we'll use the same XPRT as the server, the
* server may be QUIC, but we want a TCP check.
*/
if (!srv->check.use_ssl && srv->use_ssl != -1 &&
!srv->check.via_socks4 && !srv->check.send_proxy &&
(!srv->check.alpn_len || (srv->check.alpn_len == srv->ssl_ctx.alpn_len && !strncmp(srv->check.alpn_str, srv->ssl_ctx.alpn_str, srv->check.alpn_len))) &&
(!srv->check.mux_proto || srv->check.mux_proto != srv->mux_proto))
if (!srv->check.use_ssl && srv->use_ssl != -1)
srv->check.xprt = srv->xprt;
else if (srv->check.use_ssl == 1)
srv->check.xprt = xprt_get(XPRT_SSL);
@ -1886,7 +1891,7 @@ int init_srv_check(struct server *srv)
(!is_inet_addr(&srv->check.addr) && (is_addr(&srv->check.addr) || !is_inet_addr(&srv->addr))))
goto init;
if (LIST_ISEMPTY(&srv->check.tcpcheck->rs->rules)) {
if (!srv->proxy->tcpcheck_rules.list || LIST_ISEMPTY(srv->proxy->tcpcheck_rules.list)) {
ha_alert("config: %s '%s': server '%s' has neither service port nor check port.\n",
proxy_type_str(srv->proxy), srv->proxy->id, srv->id);
ret |= ERR_ALERT | ERR_ABORT;
@ -1894,7 +1899,7 @@ int init_srv_check(struct server *srv)
}
/* search the first action (connect / send / expect) in the list */
r = get_first_tcpcheck_rule(srv->check.tcpcheck->rs);
r = get_first_tcpcheck_rule(&srv->proxy->tcpcheck_rules);
if (!r || (r->action != TCPCHK_ACT_CONNECT) || (!r->connect.port && !get_host_port(&r->connect.addr))) {
ha_alert("config: %s '%s': server '%s' has neither service port nor check port "
"nor tcp_check rule 'connect' with port information.\n",
@ -1904,7 +1909,7 @@ int init_srv_check(struct server *srv)
}
/* scan the tcp-check ruleset to ensure a port has been configured */
list_for_each_entry(r, &srv->check.tcpcheck->rs->rules, list) {
list_for_each_entry(r, srv->proxy->tcpcheck_rules.list, list) {
if ((r->action == TCPCHK_ACT_CONNECT) && (!r->connect.port && !get_host_port(&r->connect.addr))) {
ha_alert("config: %s '%s': server '%s' has neither service port nor check port, "
"and a tcp_check rule 'connect' with no port information.\n",
@ -1951,7 +1956,7 @@ int init_srv_agent_check(struct server *srv)
/* If there is no connect rule preceding all send / expect rules, an
* implicit one is inserted before all others.
*/
chk = get_first_tcpcheck_rule(srv->agent.tcpcheck->rs);
chk = get_first_tcpcheck_rule(srv->agent.tcpcheck_rules);
if (!chk || chk->action != TCPCHK_ACT_CONNECT) {
chk = calloc(1, sizeof(*chk));
if (!chk) {
@ -1963,14 +1968,14 @@ int init_srv_agent_check(struct server *srv)
}
chk->action = TCPCHK_ACT_CONNECT;
chk->connect.options = (TCPCHK_OPT_DEFAULT_CONNECT|TCPCHK_OPT_IMPLICIT);
LIST_INSERT(&srv->agent.tcpcheck->rs->rules, &chk->list);
LIST_INSERT(srv->agent.tcpcheck_rules->list, &chk->list);
}
/* <chk> is always defined here and it is a CONNECT action. If there is
* a preset variable, it means there is an agent string defined and data
* will be sent after the connect.
*/
if (!LIST_ISEMPTY(&srv->agent.tcpcheck->preset_vars))
if (!LIST_ISEMPTY(&srv->agent.tcpcheck_rules->preset_vars))
chk->connect.options |= TCPCHK_OPT_HAS_DATA;
@ -2061,7 +2066,6 @@ static int srv_parse_addr(char **args, int *cur_arg, struct proxy *curpx, struct
char **errmsg)
{
struct sockaddr_storage *sk;
struct protocol *proto;
int port1, port2, err_code = 0;
@ -2070,7 +2074,7 @@ static int srv_parse_addr(char **args, int *cur_arg, struct proxy *curpx, struct
goto error;
}
sk = str2sa_range(args[*cur_arg+1], NULL, &port1, &port2, NULL, &proto, NULL, errmsg, NULL, NULL, NULL,
sk = str2sa_range(args[*cur_arg+1], NULL, &port1, &port2, NULL, NULL, NULL, errmsg, NULL, NULL, NULL,
PA_O_RESOLVE | PA_O_PORT_OK | PA_O_STREAM | PA_O_CONNECT);
if (!sk) {
memprintf(errmsg, "'%s' : %s", args[*cur_arg], *errmsg);
@ -2078,7 +2082,6 @@ static int srv_parse_addr(char **args, int *cur_arg, struct proxy *curpx, struct
}
srv->check.addr = *sk;
srv->check.proto = proto;
/* if agentaddr was never set, we can use addr */
if (!(srv->flags & SRV_F_AGENTADDR))
srv->agent.addr = *sk;
@ -2108,11 +2111,7 @@ static int srv_parse_agent_addr(char **args, int *cur_arg, struct proxy *curpx,
goto error;
}
set_srv_agent_addr(srv, &sk);
/* Agent currently only uses TCP */
if (sk.ss_family == AF_INET)
srv->agent.proto = &proto_tcpv4;
else
srv->agent.proto = &proto_tcpv6;
out:
return err_code;
@ -2126,7 +2125,7 @@ static int srv_parse_agent_check(char **args, int *cur_arg, struct proxy *curpx,
char **errmsg)
{
struct tcpcheck_ruleset *rs = NULL;
struct tcpcheck *tc = srv->agent.tcpcheck;
struct tcpcheck_rules *rules = srv->agent.tcpcheck_rules;
struct tcpcheck_rule *chk;
int err_code = 0;
@ -2139,15 +2138,17 @@ static int srv_parse_agent_check(char **args, int *cur_arg, struct proxy *curpx,
return ERR_WARN;
}
if (!tc) {
tc = calloc(1, sizeof(*tc));
if (!tc) {
if (!rules) {
rules = calloc(1, sizeof(*rules));
if (!rules) {
memprintf(errmsg, "out of memory.");
goto error;
}
LIST_INIT(&tc->preset_vars);
srv->agent.tcpcheck = tc;
LIST_INIT(&rules->preset_vars);
srv->agent.tcpcheck_rules = rules;
}
rules->list = NULL;
rules->flags = 0;
rs = find_tcpcheck_ruleset("*agent-check");
if (rs)
@ -2180,9 +2181,9 @@ static int srv_parse_agent_check(char **args, int *cur_arg, struct proxy *curpx,
LIST_APPEND(&rs->rules, &chk->list);
ruleset_found:
tc->rs = rs;
tc->flags &= ~TCPCHK_FL_UNUSED_RS;
rs->flags |= TCPCHK_RULES_AGENT_CHK;
rules->list = &rs->rules;
rules->flags &= ~(TCPCHK_RULES_PROTO_CHK|TCPCHK_RULES_UNUSED_RS);
rules->flags |= TCPCHK_RULES_AGENT_CHK;
srv->do_agent = 1;
out:
@ -2275,7 +2276,7 @@ static int srv_parse_agent_port(char **args, int *cur_arg, struct proxy *curpx,
int set_srv_agent_send(struct server *srv, const char *send)
{
struct tcpcheck *tc = srv->agent.tcpcheck;
struct tcpcheck_rules *rules = srv->agent.tcpcheck_rules;
struct tcpcheck_var *var = NULL;
char *str;
@ -2284,13 +2285,13 @@ int set_srv_agent_send(struct server *srv, const char *send)
if (str == NULL || var == NULL)
goto error;
free_tcpcheck_vars(&tc->preset_vars);
free_tcpcheck_vars(&rules->preset_vars);
var->data.type = SMP_T_STR;
var->data.u.str.area = str;
var->data.u.str.data = strlen(str);
LIST_INIT(&var->list);
LIST_APPEND(&tc->preset_vars, &var->list);
LIST_APPEND(&rules->preset_vars, &var->list);
return 1;
@ -2304,7 +2305,7 @@ int set_srv_agent_send(struct server *srv, const char *send)
static int srv_parse_agent_send(char **args, int *cur_arg, struct proxy *curpx, struct server *srv,
char **errmsg)
{
struct tcpcheck *tc = srv->agent.tcpcheck;
struct tcpcheck_rules *rules = srv->agent.tcpcheck_rules;
int err_code = 0;
if (!*(args[*cur_arg+1])) {
@ -2312,14 +2313,14 @@ static int srv_parse_agent_send(char **args, int *cur_arg, struct proxy *curpx,
goto error;
}
if (!tc) {
tc = calloc(1, sizeof(*tc));
if (!tc) {
if (!rules) {
rules = calloc(1, sizeof(*rules));
if (!rules) {
memprintf(errmsg, "out of memory.");
goto error;
}
LIST_INIT(&tc->preset_vars);
srv->agent.tcpcheck = tc;
LIST_INIT(&rules->preset_vars);
srv->agent.tcpcheck_rules = rules;
}
if (!set_srv_agent_send(srv, args[*cur_arg+1])) {

View File

@ -53,22 +53,6 @@ struct pool_head *pool_head_large_trash __read_mostly = NULL;
/* this is used to drain data, and as a temporary large buffer */
THREAD_LOCAL struct buffer trash_large = { };
/* small trash chunks used for various conversions */
static THREAD_LOCAL struct buffer *small_trash_chunk;
static THREAD_LOCAL struct buffer small_trash_chunk1;
static THREAD_LOCAL struct buffer small_trash_chunk2;
/* small trash buffers used for various conversions */
static int small_trash_size __read_mostly = 0;
static THREAD_LOCAL char *small_trash_buf1 = NULL;
static THREAD_LOCAL char *small_trash_buf2 = NULL;
/* the trash pool for reentrant allocations */
struct pool_head *pool_head_small_trash __read_mostly = NULL;
/* this is used to drain data, and as a temporary small buffer */
THREAD_LOCAL struct buffer trash_small = { };
/*
* Returns a pre-allocated and initialized trash chunk that can be used for any
* type of conversion. Two chunks and their respective buffers are alternatively
@ -96,7 +80,7 @@ struct buffer *get_trash_chunk(void)
}
/* Similar to get_trash_chunk() but return a pre-allocated large chunk
* instead. Because large buffers are not enabled by default, this function may
* instead. Becasuse large buffers are not enabled by default, this function may
* return NULL.
*/
struct buffer *get_large_trash_chunk(void)
@ -119,40 +103,14 @@ struct buffer *get_large_trash_chunk(void)
return large_trash_chunk;
}
/* Similar to get_trash_chunk() but return a pre-allocated small chunk
* instead. Because small buffers are not enabled by default, this function may
* return NULL.
*/
struct buffer *get_small_trash_chunk(void)
{
char *small_trash_buf;
if (!small_trash_size)
return NULL;
if (small_trash_chunk == &small_trash_chunk1) {
small_trash_chunk = &small_trash_chunk2;
small_trash_buf = small_trash_buf2;
}
else {
small_trash_chunk = &small_trash_chunk1;
small_trash_buf = small_trash_buf1;
}
*small_trash_buf = 0;
chunk_init(small_trash_chunk, small_trash_buf, small_trash_size);
return small_trash_chunk;
}
/* Returns a trash chunk accordingly to the requested size. This function may
* fail if the requested size is too big or if the large chubks are not
* configured.
*/
struct buffer *get_trash_chunk_sz(size_t size)
{
if (likely(size > small_trash_size && size <= trash_size))
return get_trash_chunk();
else if (small_trash_size && size <= small_trash_size)
return get_small_trash_chunk();
if (likely(size <= trash_size))
return get_trash_chunk();
else if (large_trash_size && size <= large_trash_size)
return get_large_trash_chunk();
else
@ -164,20 +122,17 @@ struct buffer *get_trash_chunk_sz(size_t size)
*/
struct buffer *get_larger_trash_chunk(struct buffer *chk)
{
struct buffer *chunk = NULL;
struct buffer *chunk;
if (!chk || chk->size == small_trash_size) {
/* no chunk or a small one, use a regular buffer */
chunk = get_trash_chunk();
}
else if (large_trash_size && chk->size <= large_trash_size) {
/* a regular byffer, use a large buffer if possible */
chunk = get_large_trash_chunk();
}
if (!chk)
return get_trash_chunk();
if (chk && chunk)
b_xfer(chunk, chk, b_data(chk));
/* No large buffers or current chunk is alread a large trash chunk */
if (!large_trash_size || chk->size == large_trash_size)
return NULL;
chunk = get_large_trash_chunk();
b_xfer(chunk, chk, b_data(chk));
return chunk;
}
@ -211,29 +166,9 @@ static int alloc_large_trash_buffers(int bufsize)
return trash_large.area && large_trash_buf1 && large_trash_buf2;
}
/* allocates the trash small buffers if necessary. Returns 0 in case of
* failure. Unlike alloc_trash_buffers(), It is unexpected to call this function
* multiple times. Small buffers are not used during configuration parsing.
*/
static int alloc_small_trash_buffers(int bufsize)
{
small_trash_size = bufsize;
if (!small_trash_size)
return 1;
BUG_ON(trash_small.area && small_trash_buf1 && small_trash_buf2);
chunk_init(&trash_small, my_realloc2(trash_small.area, bufsize), bufsize);
small_trash_buf1 = (char *)my_realloc2(small_trash_buf1, bufsize);
small_trash_buf2 = (char *)my_realloc2(small_trash_buf2, bufsize);
return trash_small.area && small_trash_buf1 && small_trash_buf2;
}
static int alloc_trash_buffers_per_thread()
{
return (alloc_trash_buffers(global.tune.bufsize) &&
alloc_large_trash_buffers(global.tune.bufsize_large) &&
alloc_small_trash_buffers(global.tune.bufsize_large));
return alloc_trash_buffers(global.tune.bufsize) && alloc_large_trash_buffers(global.tune.bufsize_large);
}
static void free_trash_buffers_per_thread()
@ -245,10 +180,6 @@ static void free_trash_buffers_per_thread()
chunk_destroy(&trash_large);
ha_free(&large_trash_buf2);
ha_free(&large_trash_buf1);
chunk_destroy(&trash_small);
ha_free(&small_trash_buf2);
ha_free(&small_trash_buf1);
}
/* Initialize the trash buffers. It returns 0 if an error occurred. */
@ -276,14 +207,6 @@ int init_trash_buffers(int first)
if (!pool_head_large_trash)
return 0;
}
if (!first && global.tune.bufsize_small) {
pool_head_small_trash = create_pool("small_trash",
sizeof(struct buffer) + global.tune.bufsize_small,
MEM_F_EXACT);
if (!pool_head_small_trash)
return 0;
}
return 1;
}

View File

@ -400,21 +400,6 @@ struct cli_kw* cli_find_kw_exact(char **args)
void cli_register_kw(struct cli_kw_list *kw_list)
{
struct cli_kw *kw;
for (kw = &kw_list->kw[0]; kw->str_kw[0]; kw++) {
/* store declaration file/line if known */
if (kw->exec_ctx.type)
continue;
if (caller_initcall) {
kw->exec_ctx.type = TH_EX_CTX_INITCALL;
kw->exec_ctx.initcall = caller_initcall;
} else {
kw->exec_ctx.type = TH_EX_CTX_CLI_KWL;
kw->exec_ctx.cli_kwl = kw_list;
}
}
LIST_APPEND(&cli_keywords.list, &kw_list->list);
}
@ -864,7 +849,6 @@ static int cli_process_cmdline(struct appctx *appctx)
else if (kw->level == ACCESS_EXPERIMENTAL)
mark_tainted(TAINTED_CLI_EXPERIMENTAL_MODE);
appctx->cli_ctx.kw = kw;
appctx->cli_ctx.io_handler = kw->io_handler;
appctx->cli_ctx.io_release = kw->io_release;
@ -884,7 +868,6 @@ static int cli_process_cmdline(struct appctx *appctx)
goto end;
fail:
appctx->cli_ctx.kw = NULL;
appctx->cli_ctx.io_handler = NULL;
appctx->cli_ctx.io_release = NULL;
@ -1226,19 +1209,17 @@ void cli_io_handler(struct appctx *appctx)
case CLI_ST_CALLBACK: /* use custom pointer */
if (appctx->cli_ctx.io_handler)
if (EXEC_CTX_WITH_RET(appctx->cli_ctx.kw->exec_ctx, appctx->cli_ctx.io_handler(appctx))) {
if (appctx->cli_ctx.io_handler(appctx)) {
appctx->t->expire = TICK_ETERNITY;
appctx->st0 = CLI_ST_PROMPT;
if (appctx->cli_ctx.io_release) {
EXEC_CTX_NO_RET(appctx->cli_ctx.kw->exec_ctx, appctx->cli_ctx.io_release(appctx));
appctx->cli_ctx.io_release(appctx);
appctx->cli_ctx.io_release = NULL;
appctx->cli_ctx.kw = NULL;
/* some release handlers might have
* pending output to print.
*/
continue;
}
appctx->cli_ctx.kw = NULL;
}
break;
default: /* abnormal state */
@ -1344,9 +1325,8 @@ static void cli_release_handler(struct appctx *appctx)
free_trash_chunk(appctx->cli_ctx.cmdline);
if (appctx->cli_ctx.io_release) {
EXEC_CTX_NO_RET(appctx->cli_ctx.kw->exec_ctx, appctx->cli_ctx.io_release(appctx));
appctx->cli_ctx.io_release(appctx);
appctx->cli_ctx.io_release = NULL;
appctx->cli_ctx.kw = NULL;
}
else if (appctx->st0 == CLI_ST_PRINT_DYN || appctx->st0 == CLI_ST_PRINT_DYNERR) {
struct cli_print_ctx *ctx = applet_reserve_svcctx(appctx, sizeof(*ctx));
@ -2634,9 +2614,8 @@ static int cli_parse_echo(char **args, char *payload, struct appctx *appctx, voi
static int _send_status(char **args, char *payload, struct appctx *appctx, void *private)
{
struct listener *mproxy_li;
struct mworker_proc *proc;
struct stconn *sc = appctx_sc(appctx);
struct listener *mproxy_li = strm_li(__sc_strm(sc));
char *msg = "READY\n";
int pid;
@ -2646,18 +2625,12 @@ static int _send_status(char **args, char *payload, struct appctx *appctx, void
pid = atoi(args[2]);
list_for_each_entry(proc, &proc_list, list) {
/* update status of the new worker */
if (proc->pid == pid) {
proc->options &= ~PROC_O_INIT;
/* the proxy used to receive the _send_status must be
* the one corresponding to the PID we received in
* argument */
BUG_ON(proc->ipc_fd[0] < 0);
BUG_ON(mproxy_li != fdtab[proc->ipc_fd[0]].owner);
mproxy_li = fdtab[proc->ipc_fd[0]].owner;
stop_listener(mproxy_li, 0, 0, 0);
}
/* send TERM to workers, which have exceeded max_reloads counter */
if (max_reloads != -1) {
if ((proc->options & PROC_O_TYPE_WORKER) &&
@ -2669,15 +2642,6 @@ static int _send_status(char **args, char *payload, struct appctx *appctx, void
}
}
/* the sockpair between the master and the worker is
* used temporarily as a listener to receive
* _send_status. Once it is received we don't want to
* use this FD as a listener anymore, but only as a
* server, to allow only connections from the master to
* the worker for the master CLI */
BUG_ON(mproxy_li == NULL);
stop_listener(mproxy_li, 0, 0, 0);
/* At this point we are sure, that newly forked worker is started,
* so we can write our PID in a pidfile, if provided. Master doesn't
* perform chroot.
@ -2876,7 +2840,7 @@ static int pcli_prefix_to_pid(const char *prefix)
if (*errtol != '\0')
return -1;
list_for_each_entry(child, &proc_list, list) {
if (!(child->options & PROC_O_TYPE_WORKER) || (child->options & PROC_O_INIT))
if (!(child->options & PROC_O_TYPE_WORKER))
continue;
if (child->pid == proc_pid){
return child->pid;
@ -2899,7 +2863,7 @@ static int pcli_prefix_to_pid(const char *prefix)
/* chose the right process, the current one is the one with the
least number of reloads */
list_for_each_entry(child, &proc_list, list) {
if (!(child->options & PROC_O_TYPE_WORKER) || (child->options & PROC_O_INIT))
if (!(child->options & PROC_O_TYPE_WORKER))
continue;
if (child->reloads == 0)
return child->pid;

View File

@ -266,7 +266,6 @@ void clock_update_global_date()
{
ullong old_now_ns;
uint old_now_ms;
int now_ns_changed = 0;
/* now that we have bounded the local time, let's check if it's
* realistic regarding the global date, which only moves forward,
@ -276,10 +275,8 @@ void clock_update_global_date()
old_now_ms = _HA_ATOMIC_LOAD(global_now_ms);
do {
if (now_ns < old_now_ns) {
now_ns_changed = 1;
if (now_ns < old_now_ns)
now_ns = old_now_ns;
}
/* now <now_ns> is expected to be the most accurate date,
* equal to <global_now_ns> or newer. Updating the global
@ -298,11 +295,8 @@ void clock_update_global_date()
if (unlikely(now_ms == TICK_ETERNITY))
now_ms++;
if (!((now_ns ^ old_now_ns) & ~0x7FFFULL)) {
if (now_ns_changed)
goto end;
if (!((now_ns ^ old_now_ns) & ~0x7FFFULL))
return;
}
/* let's try to update the global_now_ns (both in nanoseconds
* and ms forms) or loop again.
@ -311,7 +305,6 @@ void clock_update_global_date()
(now_ms != old_now_ms && !_HA_ATOMIC_CAS(global_now_ms, &old_now_ms, now_ms))) &&
__ha_cpu_relax());
end:
if (!th_ctx->curr_mono_time) {
/* Only update the offset when monotonic time is not available.
* <now_ns> and <now_ms> are now updated to the last value of
@ -321,16 +314,6 @@ void clock_update_global_date()
*/
HA_ATOMIC_STORE(&now_offset, now_ns - tv_to_ns(&date));
}
else if (global_now_ns != &_global_now_ns) {
/*
* or global_now_ns is shared with other processes: this results
* in the now_offset requiring to self-adjust so that it is consistent
* with now_offset used by other processes, as we may have learned from
* a new global_now_ns that was used in pair with a different offset from
* ours
*/
HA_ATOMIC_STORE(&now_offset, now_ns - th_ctx->curr_mono_time);
}
}
/* must be called once at boot to initialize some global variables */

View File

@ -141,7 +141,7 @@ int conn_create_mux(struct connection *conn, int *closed_connection)
fail:
/* let the upper layer know the connection failed */
if (sc) {
sc_conn_process(sc);
sc->app_ops->wake(sc);
}
else if (conn_reverse_in_preconnect(conn)) {
struct listener *l = conn_active_reverse_listener(conn);
@ -232,14 +232,14 @@ int conn_notify_mux(struct connection *conn, int old_flags, int forced_wake)
HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
}
ret = CALL_MUX_WITH_RET(conn->mux, wake(conn));
ret = conn->mux->wake(conn);
if (ret < 0)
goto done;
if (conn_in_list) {
if (srv && (srv->cur_admin & SRV_ADMF_MAINT)) {
/* Do not store an idle conn if server in maintenance. */
CALL_MUX_NO_RET(conn->mux, destroy(conn->ctx));
conn->mux->destroy(conn->ctx);
ret = -1;
goto done;
}
@ -247,7 +247,7 @@ int conn_notify_mux(struct connection *conn, int old_flags, int forced_wake)
if (conn->flags & CO_FL_SESS_IDLE) {
if (!session_reinsert_idle_conn(conn->owner, conn)) {
/* session add conn failure */
CALL_MUX_NO_RET(conn->mux, destroy(conn->ctx));
conn->mux->destroy(conn->ctx);
ret = -1;
}
}
@ -291,7 +291,7 @@ int conn_upgrade_mux_fe(struct connection *conn, void *ctx, struct buffer *buf,
old_mux_ctx = conn->ctx;
conn->mux = new_mux;
conn->ctx = ctx;
if (CALL_MUX_WITH_RET(new_mux, init(conn, bind_conf->frontend, conn->owner, buf)) == -1) {
if (new_mux->init(conn, bind_conf->frontend, conn->owner, buf) == -1) {
/* The mux upgrade failed, so restore the old mux */
conn->ctx = old_mux_ctx;
conn->mux = old_mux;
@ -300,7 +300,7 @@ int conn_upgrade_mux_fe(struct connection *conn, void *ctx, struct buffer *buf,
/* The mux was upgraded, destroy the old one */
*buf = BUF_NULL;
CALL_MUX_NO_RET(old_mux, destroy(old_mux_ctx));
old_mux->destroy(old_mux_ctx);
return 0;
}
@ -412,7 +412,7 @@ int conn_install_mux_chk(struct connection *conn, void *ctx, struct session *ses
struct ist mux_proto;
const char *alpn_str = NULL;
int alpn_len = 0;
int mode = tcpchk_rules_type_to_proto_mode(check->tcpcheck->flags);
int mode = tcpchk_rules_type_to_proto_mode(check->tcpcheck_rules->flags);
conn_get_alpn(conn, &alpn_str, &alpn_len);
mux_proto = ist2(alpn_str, alpn_len);
@ -658,7 +658,7 @@ void conn_free(struct connection *conn)
void conn_release(struct connection *conn)
{
if (conn->mux) {
CALL_MUX_NO_RET(conn->mux, destroy(conn->ctx));
conn->mux->destroy(conn->ctx);
}
else {
conn_stop_tracking(conn);
@ -3034,7 +3034,7 @@ static struct task *mux_stopping_process(struct task *t, void *ctx, unsigned int
list_for_each_entry_safe(conn, back, &mux_stopping_data[tid].list, stopping_list) {
if (conn->mux && conn->mux->wake)
CALL_MUX_NO_RET(conn->mux, wake(conn));
conn->mux->wake(conn);
}
return t;

View File

@ -367,9 +367,6 @@ void ha_thread_dump_one(struct buffer *buf, int is_caller)
(now - th_ctx->sched_call_date));
}
/* report the execution context when known */
chunk_append_thread_ctx(buf, &th_ctx->exec_ctx, " exec_ctx: ", "\n");
/* this is the end of what we can dump from outside the current thread */
chunk_appendf(buf, " curr_task=");

View File

@ -24,7 +24,6 @@
struct pool_head *pool_head_buffer __read_mostly;
struct pool_head *pool_head_large_buffer __read_mostly = NULL;
struct pool_head *pool_head_small_buffer __read_mostly;
/* perform minimal initializations, report 0 in case of error, 1 if OK. */
int init_buffer()
@ -44,12 +43,6 @@ int init_buffer()
return 0;
}
if (global.tune.bufsize_small) {
pool_head_small_buffer = create_aligned_pool("small_buffer", global.tune.bufsize_small, 64, MEM_F_SHARED|MEM_F_EXACT);
if (!pool_head_small_buffer)
return 0;
}
/* make sure any change to the queues assignment isn't overlooked */
BUG_ON(DB_PERMANENT - DB_UNLIKELY - 1 != DYNBUF_NBQ);
BUG_ON(DB_MUX_RX_Q < DB_SE_RX_Q || DB_MUX_RX_Q >= DYNBUF_NBQ);

View File

@ -136,10 +136,6 @@ static int cli_parse_show_ech(char **args, char *payload,
{
struct show_ech_ctx *ctx = applet_reserve_svcctx(appctx, sizeof(*ctx));
if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
return 1;
/* no parameter, shows only file list */
if (*args[3]) {
SSL_CTX *sctx = NULL;
@ -301,9 +297,6 @@ static int cli_parse_add_ech(char **args, char *payload, struct appctx *appctx,
OSSL_ECHSTORE *es = NULL;
BIO *es_in = NULL;
if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
return 1;
if (!*args[3] || !payload)
return cli_err(appctx, "syntax: add ssl ech <name> <PEM file content>");
if (cli_find_ech_specific_ctx(args[3], &sctx) != 1)
@ -331,9 +324,6 @@ static int cli_parse_set_ech(char **args, char *payload, struct appctx *appctx,
OSSL_ECHSTORE *es = NULL;
BIO *es_in = NULL;
if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
return 1;
if (!*args[3] || !payload)
return cli_err(appctx, "syntax: set ssl ech <name> <PEM file content>");
if (cli_find_ech_specific_ctx(args[3], &sctx) != 1)
@ -361,9 +351,6 @@ static int cli_parse_del_ech(char **args, char *payload, struct appctx *appctx,
char success_message[ECH_SUCCESS_MSG_MAX];
OSSL_ECHSTORE *es = NULL;
if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
return 1;
if (!*args[3])
return cli_err(appctx, "syntax: del ssl ech <name>");
if (*args[4])

View File

@ -221,8 +221,7 @@ static int fcgi_flt_check(struct proxy *px, struct flt_conf *fconf)
}
list_for_each_entry(f, &px->filter_configs, list) {
if (f->id == http_comp_req_flt_id || f->id == http_comp_res_flt_id ||
f->id == cache_store_flt_id)
if (f->id == http_comp_flt_id || f->id == cache_store_flt_id)
continue;
else if ((f->id == fconf->id) && f->conf != fcgi_conf) {
ha_alert("proxy '%s' : only one fcgi-app supported per backend.\n",

View File

@ -450,8 +450,7 @@ flt_stream_add_filter(struct stream *s, struct flt_conf *fconf, unsigned int fla
f->flags |= flags;
if (FLT_OPS(f)->attach) {
struct thread_exec_ctx exec_ctx = EXEC_CTX_MAKE(TH_EX_CTX_FLT, f->config);
int ret = EXEC_CTX_WITH_RET(exec_ctx, FLT_OPS(f)->attach(s, f));
int ret = FLT_OPS(f)->attach(s, f);
if (ret <= 0) {
pool_free(pool_head_filter, f);
return ret;
@ -507,10 +506,8 @@ flt_stream_release(struct stream *s, int only_backend)
list_for_each_entry_safe(filter, back, &strm_flt(s)->filters, list) {
if (!only_backend || (filter->flags & FLT_FL_IS_BACKEND_FILTER)) {
filter->calls++;
if (FLT_OPS(filter)->detach) {
struct thread_exec_ctx exec_ctx = EXEC_CTX_MAKE(TH_EX_CTX_FLT, filter->config);
EXEC_CTX_NO_RET(exec_ctx, FLT_OPS(filter)->detach(s, filter));
}
if (FLT_OPS(filter)->detach)
FLT_OPS(filter)->detach(s, filter);
LIST_DELETE(&filter->list);
LIST_DELETE(&filter->req_list);
LIST_DELETE(&filter->res_list);
@ -533,10 +530,8 @@ flt_stream_start(struct stream *s)
list_for_each_entry(filter, &strm_flt(s)->filters, list) {
if (FLT_OPS(filter)->stream_start) {
struct thread_exec_ctx exec_ctx = EXEC_CTX_MAKE(TH_EX_CTX_FLT, filter->config);
filter->calls++;
if (EXEC_CTX_WITH_RET(exec_ctx, FLT_OPS(filter)->stream_start(s, filter) < 0)) {
if (FLT_OPS(filter)->stream_start(s, filter) < 0) {
s->last_entity.type = STRM_ENTITY_FILTER;
s->last_entity.ptr = filter;
return -1;
@ -561,10 +556,8 @@ flt_stream_stop(struct stream *s)
list_for_each_entry(filter, &strm_flt(s)->filters, list) {
if (FLT_OPS(filter)->stream_stop) {
struct thread_exec_ctx exec_ctx = EXEC_CTX_MAKE(TH_EX_CTX_FLT, filter->config);
filter->calls++;
EXEC_CTX_NO_RET(exec_ctx, FLT_OPS(filter)->stream_stop(s, filter));
FLT_OPS(filter)->stream_stop(s, filter);
}
}
}
@ -580,10 +573,8 @@ flt_stream_check_timeouts(struct stream *s)
list_for_each_entry(filter, &strm_flt(s)->filters, list) {
if (FLT_OPS(filter)->check_timeouts) {
struct thread_exec_ctx exec_ctx = EXEC_CTX_MAKE(TH_EX_CTX_FLT, filter->config);
filter->calls++;
EXEC_CTX_NO_RET(exec_ctx, FLT_OPS(filter)->check_timeouts(s, filter));
FLT_OPS(filter)->check_timeouts(s, filter);
}
}
}
@ -610,10 +601,8 @@ flt_set_stream_backend(struct stream *s, struct proxy *be)
end:
list_for_each_entry(filter, &strm_flt(s)->filters, list) {
if (FLT_OPS(filter)->stream_set_backend) {
struct thread_exec_ctx exec_ctx = EXEC_CTX_MAKE(TH_EX_CTX_FLT, filter->config);
filter->calls++;
if (EXEC_CTX_WITH_RET(exec_ctx, FLT_OPS(filter)->stream_set_backend(s, filter, be) < 0)) {
if (FLT_OPS(filter)->stream_set_backend(s, filter, be) < 0) {
s->last_entity.type = STRM_ENTITY_FILTER;
s->last_entity.ptr = filter;
return -1;
@ -661,11 +650,9 @@ flt_http_end(struct stream *s, struct http_msg *msg)
continue;
if (FLT_OPS(filter)->http_end) {
struct thread_exec_ctx exec_ctx = EXEC_CTX_MAKE(TH_EX_CTX_FLT, filter->config);
DBG_TRACE_DEVEL(FLT_ID(filter), STRM_EV_HTTP_ANA|STRM_EV_FLT_ANA, s);
filter->calls++;
ret = EXEC_CTX_WITH_RET(exec_ctx, FLT_OPS(filter)->http_end(s, filter, msg));
ret = FLT_OPS(filter)->http_end(s, filter, msg);
if (ret <= 0) {
resume_filter_list_break(s, msg->chn, filter, ret);
goto end;
@ -694,11 +681,9 @@ flt_http_reset(struct stream *s, struct http_msg *msg)
for (filter = flt_list_start(s, msg->chn); filter;
filter = flt_list_next(s, msg->chn, filter)) {
if (FLT_OPS(filter)->http_reset) {
struct thread_exec_ctx exec_ctx = EXEC_CTX_MAKE(TH_EX_CTX_FLT, filter->config);
DBG_TRACE_DEVEL(FLT_ID(filter), STRM_EV_HTTP_ANA|STRM_EV_FLT_ANA, s);
filter->calls++;
EXEC_CTX_NO_RET(exec_ctx, FLT_OPS(filter)->http_reset(s, filter, msg));
FLT_OPS(filter)->http_reset(s, filter, msg);
}
}
DBG_TRACE_LEAVE(STRM_EV_STRM_ANA|STRM_EV_HTTP_ANA|STRM_EV_FLT_ANA, s);
@ -716,11 +701,9 @@ flt_http_reply(struct stream *s, short status, const struct buffer *msg)
DBG_TRACE_ENTER(STRM_EV_STRM_ANA|STRM_EV_HTTP_ANA|STRM_EV_FLT_ANA, s, s->txn, msg);
list_for_each_entry(filter, &strm_flt(s)->filters, list) {
if (FLT_OPS(filter)->http_reply) {
struct thread_exec_ctx exec_ctx = EXEC_CTX_MAKE(TH_EX_CTX_FLT, filter->config);
DBG_TRACE_DEVEL(FLT_ID(filter), STRM_EV_HTTP_ANA|STRM_EV_FLT_ANA, s);
filter->calls++;
EXEC_CTX_NO_RET(exec_ctx, FLT_OPS(filter)->http_reply(s, filter, status, msg));
FLT_OPS(filter)->http_reply(s, filter, status, msg);
}
}
DBG_TRACE_LEAVE(STRM_EV_STRM_ANA|STRM_EV_HTTP_ANA|STRM_EV_FLT_ANA, s);
@ -749,7 +732,6 @@ flt_http_payload(struct stream *s, struct http_msg *msg, unsigned int len)
DBG_TRACE_ENTER(STRM_EV_STRM_ANA|STRM_EV_HTTP_ANA|STRM_EV_FLT_ANA, s, s->txn, msg);
for (filter = flt_list_start(s, msg->chn); filter;
filter = flt_list_next(s, msg->chn, filter)) {
struct thread_exec_ctx exec_ctx = EXEC_CTX_MAKE(TH_EX_CTX_FLT, filter->config);
unsigned long long *flt_off = &FLT_OFF(filter, msg->chn);
unsigned int offset = *flt_off - *strm_off;
@ -763,7 +745,7 @@ flt_http_payload(struct stream *s, struct http_msg *msg, unsigned int len)
DBG_TRACE_DEVEL(FLT_ID(filter), STRM_EV_HTTP_ANA|STRM_EV_FLT_ANA, s);
filter->calls++;
ret = EXEC_CTX_WITH_RET(exec_ctx, FLT_OPS(filter)->http_payload(s, filter, msg, out + offset, data - offset));
ret = FLT_OPS(filter)->http_payload(s, filter, msg, out + offset, data - offset);
if (ret < 0) {
resume_filter_list_break(s, msg->chn, filter, ret);
goto end;
@ -833,11 +815,9 @@ flt_start_analyze(struct stream *s, struct channel *chn, unsigned int an_bit)
FLT_OFF(filter, chn) = 0;
if (FLT_OPS(filter)->channel_start_analyze) {
struct thread_exec_ctx exec_ctx = EXEC_CTX_MAKE(TH_EX_CTX_FLT, filter->config);
DBG_TRACE_DEVEL(FLT_ID(filter), STRM_EV_FLT_ANA, s);
filter->calls++;
ret = EXEC_CTX_WITH_RET(exec_ctx, FLT_OPS(filter)->channel_start_analyze(s, filter, chn));
ret = FLT_OPS(filter)->channel_start_analyze(s, filter, chn);
if (ret <= 0) {
resume_filter_list_break(s, chn, filter, ret);
goto end;
@ -872,11 +852,9 @@ flt_pre_analyze(struct stream *s, struct channel *chn, unsigned int an_bit)
for (filter = resume_filter_list_start(s, chn); filter;
filter = resume_filter_list_next(s, chn, filter)) {
if (FLT_OPS(filter)->channel_pre_analyze && (filter->pre_analyzers & an_bit)) {
struct thread_exec_ctx exec_ctx = EXEC_CTX_MAKE(TH_EX_CTX_FLT, filter->config);
DBG_TRACE_DEVEL(FLT_ID(filter), STRM_EV_FLT_ANA, s);
filter->calls++;
ret = EXEC_CTX_WITH_RET(exec_ctx, FLT_OPS(filter)->channel_pre_analyze(s, filter, chn, an_bit));
ret = FLT_OPS(filter)->channel_pre_analyze(s, filter, chn, an_bit);
if (ret <= 0) {
resume_filter_list_break(s, chn, filter, ret);
goto check_result;
@ -911,11 +889,9 @@ flt_post_analyze(struct stream *s, struct channel *chn, unsigned int an_bit)
for (filter = flt_list_start(s, chn); filter;
filter = flt_list_next(s, chn, filter)) {
if (FLT_OPS(filter)->channel_post_analyze && (filter->post_analyzers & an_bit)) {
struct thread_exec_ctx exec_ctx = EXEC_CTX_MAKE(TH_EX_CTX_FLT, filter->config);
DBG_TRACE_DEVEL(FLT_ID(filter), STRM_EV_FLT_ANA, s);
filter->calls++;
ret = EXEC_CTX_WITH_RET(exec_ctx, FLT_OPS(filter)->channel_post_analyze(s, filter, chn, an_bit));
ret = FLT_OPS(filter)->channel_post_analyze(s, filter, chn, an_bit);
if (ret < 0) {
resume_filter_list_break(s, chn, filter, ret);
break;
@ -946,11 +922,9 @@ flt_analyze_http_headers(struct stream *s, struct channel *chn, unsigned int an_
for (filter = resume_filter_list_start(s, chn); filter;
filter = resume_filter_list_next(s, chn, filter)) {
if (FLT_OPS(filter)->http_headers) {
struct thread_exec_ctx exec_ctx = EXEC_CTX_MAKE(TH_EX_CTX_FLT, filter->config);
DBG_TRACE_DEVEL(FLT_ID(filter), STRM_EV_HTTP_ANA|STRM_EV_FLT_ANA, s);
filter->calls++;
ret = EXEC_CTX_WITH_RET(exec_ctx, FLT_OPS(filter)->http_headers(s, filter, msg));
ret = FLT_OPS(filter)->http_headers(s, filter, msg);
if (ret <= 0) {
resume_filter_list_break(s, chn, filter, ret);
goto check_result;
@ -999,11 +973,9 @@ flt_end_analyze(struct stream *s, struct channel *chn, unsigned int an_bit)
unregister_data_filter(s, chn, filter);
if (FLT_OPS(filter)->channel_end_analyze) {
struct thread_exec_ctx exec_ctx = EXEC_CTX_MAKE(TH_EX_CTX_FLT, filter->config);
DBG_TRACE_DEVEL(FLT_ID(filter), STRM_EV_FLT_ANA, s);
filter->calls++;
ret = EXEC_CTX_WITH_RET(exec_ctx, FLT_OPS(filter)->channel_end_analyze(s, filter, chn));
ret = FLT_OPS(filter)->channel_end_analyze(s, filter, chn);
if (ret <= 0) {
resume_filter_list_break(s, chn, filter, ret);
goto end;
@ -1070,7 +1042,6 @@ flt_tcp_payload(struct stream *s, struct channel *chn, unsigned int len)
DBG_TRACE_ENTER(STRM_EV_TCP_ANA|STRM_EV_FLT_ANA, s);
for (filter = flt_list_start(s, chn); filter;
filter = flt_list_next(s, chn, filter)) {
struct thread_exec_ctx exec_ctx = EXEC_CTX_MAKE(TH_EX_CTX_FLT, filter->config);
unsigned long long *flt_off = &FLT_OFF(filter, chn);
unsigned int offset = *flt_off - *strm_off;
@ -1084,7 +1055,7 @@ flt_tcp_payload(struct stream *s, struct channel *chn, unsigned int len)
DBG_TRACE_DEVEL(FLT_ID(filter), STRM_EV_TCP_ANA|STRM_EV_FLT_ANA, s);
filter->calls++;
ret = EXEC_CTX_WITH_RET(exec_ctx, FLT_OPS(filter)->tcp_payload(s, filter, chn, out + offset, data - offset));
ret = FLT_OPS(filter)->tcp_payload(s, filter, chn, out + offset, data - offset);
if (ret < 0) {
resume_filter_list_break(s, chn, filter, ret);
goto end;

View File

@ -27,15 +27,17 @@
#define COMP_STATE_PROCESSING 0x01
const char *http_comp_req_flt_id = "comp-req filter";
const char *http_comp_res_flt_id = "comp-res filter";
const char *http_comp_flt_id = "compression filter";
struct flt_ops comp_req_ops;
struct flt_ops comp_res_ops;
struct flt_ops comp_ops;
struct comp_state {
struct comp_ctx *comp_ctx; /* compression context */
struct comp_algo *comp_algo; /* compression algorithm if not NULL */
/*
* For both comp_ctx and comp_algo, COMP_DIR_REQ is the index
* for requests, and COMP_DIR_RES for responses
*/
struct comp_ctx *comp_ctx[2]; /* compression context */
struct comp_algo *comp_algo[2]; /* compression algorithm if not NULL */
unsigned int flags; /* COMP_STATE_* */
};
@ -74,8 +76,10 @@ comp_strm_init(struct stream *s, struct filter *filter)
if (st == NULL)
return -1;
st->comp_algo = NULL;
st->comp_ctx = NULL;
st->comp_algo[COMP_DIR_REQ] = NULL;
st->comp_algo[COMP_DIR_RES] = NULL;
st->comp_ctx[COMP_DIR_REQ] = NULL;
st->comp_ctx[COMP_DIR_RES] = NULL;
st->flags = 0;
filter->ctx = st;
@ -96,8 +100,10 @@ comp_strm_deinit(struct stream *s, struct filter *filter)
return;
/* release any possible compression context */
if (st->comp_algo)
st->comp_algo->end(&st->comp_ctx);
if (st->comp_algo[COMP_DIR_REQ])
st->comp_algo[COMP_DIR_REQ]->end(&st->comp_ctx[COMP_DIR_REQ]);
if (st->comp_algo[COMP_DIR_RES])
st->comp_algo[COMP_DIR_RES]->end(&st->comp_ctx[COMP_DIR_RES]);
pool_free(pool_head_comp_state, st);
filter->ctx = NULL;
}
@ -166,9 +172,9 @@ comp_prepare_compress_request(struct comp_state *st, struct stream *s, struct ht
if (txn->meth == HTTP_METH_HEAD)
return;
if (s->be->comp && s->be->comp->algo_req != NULL)
st->comp_algo = s->be->comp->algo_req;
st->comp_algo[COMP_DIR_REQ] = s->be->comp->algo_req;
else if (strm_fe(s)->comp && strm_fe(s)->comp->algo_req != NULL)
st->comp_algo = strm_fe(s)->comp->algo_req;
st->comp_algo[COMP_DIR_REQ] = strm_fe(s)->comp->algo_req;
else
goto fail; /* no algo selected: nothing to do */
@ -183,69 +189,43 @@ comp_prepare_compress_request(struct comp_state *st, struct stream *s, struct ht
goto fail;
/* initialize compression */
if (st->comp_algo->init(&st->comp_ctx, global.tune.comp_maxlevel) < 0)
if (st->comp_algo[COMP_DIR_REQ]->init(&st->comp_ctx[COMP_DIR_REQ], global.tune.comp_maxlevel) < 0)
goto fail;
return;
fail:
st->comp_algo = NULL;
st->comp_algo[COMP_DIR_REQ] = NULL;
}
static int
comp_req_http_headers(struct stream *s, struct filter *filter, struct http_msg *msg)
comp_http_headers(struct stream *s, struct filter *filter, struct http_msg *msg)
{
struct comp_state *st = filter->ctx;
int comp_flags = 0;
if (!strm_fe(s)->comp && !s->be->comp)
goto end;
if (strm_fe(s)->comp)
comp_flags |= strm_fe(s)->comp->flags;
if (s->be->comp)
comp_flags |= s->be->comp->flags;
if (!(comp_flags & COMP_FL_DIR_REQ))
goto end;
if (!(msg->chn->flags & CF_ISRESP)) {
comp_prepare_compress_request(st, s, msg);
if (st->comp_algo) {
if (!set_compression_header(st, s, msg))
goto end;
register_data_filter(s, msg->chn, filter);
st->flags |= COMP_STATE_PROCESSING;
if (comp_flags & COMP_FL_DIR_REQ) {
comp_prepare_compress_request(st, s, msg);
if (st->comp_algo[COMP_DIR_REQ]) {
if (!set_compression_header(st, s, msg))
goto end;
register_data_filter(s, msg->chn, filter);
st->flags |= COMP_STATE_PROCESSING;
}
}
}
end:
return 1;
}
static int
comp_res_http_headers(struct stream *s, struct filter *filter, struct http_msg *msg)
{
struct comp_state *st = filter->ctx;
int comp_flags = 0;
if (!strm_fe(s)->comp && !s->be->comp)
goto end;
if (strm_fe(s)->comp)
comp_flags |= strm_fe(s)->comp->flags;
if (s->be->comp)
comp_flags |= s->be->comp->flags;
if (!(comp_flags & COMP_FL_DIR_RES))
goto end;
if (!(msg->chn->flags & CF_ISRESP))
select_compression_request_header(st, s, msg);
else {
if (comp_flags & COMP_FL_DIR_RES)
select_compression_request_header(st, s, msg);
} else if (comp_flags & COMP_FL_DIR_RES) {
/* Response headers have already been checked in
* comp_res_http_post_analyze callback. */
if (st->comp_algo) {
* comp_http_post_analyze callback. */
if (st->comp_algo[COMP_DIR_RES]) {
if (!set_compression_header(st, s, msg))
goto end;
register_data_filter(s, msg->chn, filter);
@ -258,8 +238,8 @@ comp_res_http_headers(struct stream *s, struct filter *filter, struct http_msg *
}
static int
comp_res_http_post_analyze(struct stream *s, struct filter *filter,
struct channel *chn, unsigned an_bit)
comp_http_post_analyze(struct stream *s, struct filter *filter,
struct channel *chn, unsigned an_bit)
{
struct http_txn *txn = s->txn;
struct http_msg *msg = &txn->rsp;
@ -279,13 +259,19 @@ comp_res_http_post_analyze(struct stream *s, struct filter *filter,
static int
comp_http_payload(struct stream *s, struct filter *filter, struct http_msg *msg,
unsigned int offset, unsigned int len, int dir)
unsigned int offset, unsigned int len)
{
struct comp_state *st = filter->ctx;
struct htx *htx = htxbuf(&msg->chn->buf);
struct htx_ret htxret = htx_find_offset(htx, offset);
struct htx_blk *blk, *next;
int ret, consumed = 0, to_forward = 0, last = 0;
int dir;
if (msg->chn->flags & CF_ISRESP)
dir = COMP_DIR_RES;
else
dir = COMP_DIR_REQ;
blk = htxret.blk;
offset = htxret.ret;
@ -375,7 +361,7 @@ comp_http_payload(struct stream *s, struct filter *filter, struct http_msg *msg,
if (to_forward != consumed)
flt_update_offsets(filter, msg->chn, to_forward - consumed);
if (st->comp_ctx && st->comp_ctx->cur_lvl > 0) {
if (st->comp_ctx[dir] && st->comp_ctx[dir]->cur_lvl > 0) {
update_freq_ctr(&global.comp_bps_in, consumed);
if (s->sess->fe_tgcounters) {
_HA_ATOMIC_ADD(&s->sess->fe_tgcounters->comp_in[dir], consumed);
@ -398,33 +384,14 @@ comp_http_payload(struct stream *s, struct filter *filter, struct http_msg *msg,
return -1;
}
static int
comp_req_http_payload(struct stream *s, struct filter *filter, struct http_msg *msg,
unsigned int offset, unsigned int len)
{
if (msg->chn->flags & CF_ISRESP)
return 0;
return comp_http_payload(s, filter, msg, offset, len, COMP_DIR_REQ);
}
static int
comp_res_http_payload(struct stream *s, struct filter *filter, struct http_msg *msg,
unsigned int offset, unsigned int len)
{
if (!(msg->chn->flags & CF_ISRESP))
return 0;
return comp_http_payload(s, filter, msg, offset, len, COMP_DIR_RES);
}
static int
comp_res_http_end(struct stream *s, struct filter *filter,
struct http_msg *msg)
comp_http_end(struct stream *s, struct filter *filter,
struct http_msg *msg)
{
struct comp_state *st = filter->ctx;
if (!(msg->chn->flags & CF_ISRESP) || !st || !st->comp_algo)
if (!(msg->chn->flags & CF_ISRESP) || !st || !st->comp_algo[COMP_DIR_RES])
goto end;
if (strm_fe(s)->mode == PR_MODE_HTTP && s->sess->fe_tgcounters)
@ -444,12 +411,18 @@ set_compression_header(struct comp_state *st, struct stream *s, struct http_msg
struct htx_sl *sl;
struct http_hdr_ctx ctx, last_vary;
struct comp_algo *comp_algo;
int comp_index;
if (msg->chn->flags & CF_ISRESP)
comp_index = COMP_DIR_RES;
else
comp_index = COMP_DIR_REQ;
sl = http_get_stline(htx);
if (!sl)
goto error;
comp_algo = st->comp_algo;
comp_algo = st->comp_algo[comp_index];
/* add "Transfer-Encoding: chunked" header */
if (!(msg->flags & HTTP_MSGF_TE_CHNK)) {
@ -523,8 +496,8 @@ set_compression_header(struct comp_state *st, struct stream *s, struct http_msg
return 1;
error:
st->comp_algo->end(&st->comp_ctx);
st->comp_algo = NULL;
st->comp_algo[comp_index]->end(&st->comp_ctx[comp_index]);
st->comp_algo[comp_index] = NULL;
return 0;
}
@ -552,7 +525,7 @@ select_compression_request_header(struct comp_state *st, struct stream *s, struc
*(ctx.value.ptr + 30) < '6' ||
(*(ctx.value.ptr + 30) == '6' &&
(ctx.value.len < 54 || memcmp(ctx.value.ptr + 51, "SV1", 3) != 0)))) {
st->comp_algo = NULL;
st->comp_algo[COMP_DIR_RES] = NULL;
return 0;
}
@ -606,7 +579,7 @@ select_compression_request_header(struct comp_state *st, struct stream *s, struc
for (comp_algo = comp_algo_back; comp_algo; comp_algo = comp_algo->next) {
if (*(ctx.value.ptr) == '*' ||
word_match(ctx.value.ptr, toklen, comp_algo->ua_name, comp_algo->ua_name_len)) {
st->comp_algo = comp_algo;
st->comp_algo[COMP_DIR_RES] = comp_algo;
best_q = q;
break;
}
@ -615,7 +588,7 @@ select_compression_request_header(struct comp_state *st, struct stream *s, struc
}
/* remove all occurrences of the header when "compression offload" is set */
if (st->comp_algo) {
if (st->comp_algo[COMP_DIR_RES]) {
if ((s->be->comp && (s->be->comp->flags & COMP_FL_OFFLOAD)) ||
(strm_fe(s)->comp && (strm_fe(s)->comp->flags & COMP_FL_OFFLOAD))) {
http_remove_header(htx, &ctx);
@ -631,13 +604,13 @@ select_compression_request_header(struct comp_state *st, struct stream *s, struc
(strm_fe(s)->comp && (comp_algo_back = strm_fe(s)->comp->algos_res))) {
for (comp_algo = comp_algo_back; comp_algo; comp_algo = comp_algo->next) {
if (comp_algo->cfg_name_len == 8 && memcmp(comp_algo->cfg_name, "identity", 8) == 0) {
st->comp_algo = comp_algo;
st->comp_algo[COMP_DIR_RES] = comp_algo;
return 1;
}
}
}
st->comp_algo = NULL;
st->comp_algo[COMP_DIR_RES] = NULL;
return 0;
}
@ -654,7 +627,7 @@ select_compression_response_header(struct comp_state *st, struct stream *s, stru
unsigned int comp_minsize = 0;
/* no common compression algorithm was found in request header */
if (st->comp_algo == NULL)
if (st->comp_algo[COMP_DIR_RES] == NULL)
goto fail;
/* compression already in progress */
@ -752,13 +725,13 @@ select_compression_response_header(struct comp_state *st, struct stream *s, stru
goto fail;
/* initialize compression */
if (st->comp_algo->init(&st->comp_ctx, global.tune.comp_maxlevel) < 0)
if (st->comp_algo[COMP_DIR_RES]->init(&st->comp_ctx[COMP_DIR_RES], global.tune.comp_maxlevel) < 0)
goto fail;
msg->flags |= HTTP_MSGF_COMPRESSING;
return 1;
fail:
st->comp_algo = NULL;
st->comp_algo[COMP_DIR_RES] = NULL;
return 0;
}
@ -781,7 +754,7 @@ htx_compression_buffer_add_data(struct comp_state *st, const char *data, size_t
struct buffer *out, int dir)
{
return st->comp_algo->add_data(st->comp_ctx, data, len, out);
return st->comp_algo[dir]->add_data(st->comp_ctx[dir], data, len, out);
}
static int
@ -789,58 +762,26 @@ htx_compression_buffer_end(struct comp_state *st, struct buffer *out, int end, i
{
if (end)
return st->comp_algo->finish(st->comp_ctx, out);
return st->comp_algo[dir]->finish(st->comp_ctx[dir], out);
else
return st->comp_algo->flush(st->comp_ctx, out);
return st->comp_algo[dir]->flush(st->comp_ctx[dir], out);
}
/***********************************************************************/
struct flt_ops comp_req_ops = {
struct flt_ops comp_ops = {
.init = comp_flt_init,
.attach = comp_strm_init,
.detach = comp_strm_deinit,
.http_headers = comp_req_http_headers,
.http_payload = comp_req_http_payload,
.channel_post_analyze = comp_http_post_analyze,
.http_headers = comp_http_headers,
.http_payload = comp_http_payload,
.http_end = comp_http_end,
};
struct flt_ops comp_res_ops = {
.init = comp_flt_init,
.attach = comp_strm_init,
.detach = comp_strm_deinit,
.channel_post_analyze = comp_res_http_post_analyze,
.http_headers = comp_res_http_headers,
.http_payload = comp_res_http_payload,
.http_end = comp_res_http_end,
};
/* returns compression options from <proxy> proxy or allocates them if
* needed
*
* When compression options are created, flags will be set to <defaults>
*
* Returns NULL in case of memory error
*/
static inline struct comp *proxy_get_comp(struct proxy *proxy, int defaults)
{
struct comp *comp;
if (proxy->comp == NULL) {
comp = calloc(1, sizeof(*comp));
if (unlikely(!comp))
return NULL;
comp->flags = defaults;
proxy->comp = comp;
}
return proxy->comp;
}
static int
parse_compression_options(char **args, int section, struct proxy *proxy,
const struct proxy *defpx, const char *file, int line,
@ -850,13 +791,19 @@ parse_compression_options(char **args, int section, struct proxy *proxy,
int ret = 0;
const char *res;
/* always default to compress responses */
comp = proxy_get_comp(proxy, COMP_FL_DIR_RES);
if (comp == NULL) {
memprintf(err, "'%s': out of memory.", args[0]);
ret = -1;
goto end;
if (proxy->comp == NULL) {
comp = calloc(1, sizeof(*comp));
if (unlikely(!comp)) {
memprintf(err, "'%s': out of memory.", args[0]);
ret = -1;
goto end;
}
/* Always default to compress responses */
comp->flags = COMP_FL_DIR_RES;
proxy->comp = comp;
}
else
comp = proxy->comp;
if (strcmp(args[1], "algo") == 0 || strcmp(args[1], "algo-res") == 0) {
struct comp_ctx *ctx;
@ -1023,109 +970,27 @@ parse_http_comp_flt(char **args, int *cur_arg, struct proxy *px,
struct flt_conf *fconf, char **err, void *private)
{
struct flt_conf *fc, *back;
struct flt_conf *fconf_res;
list_for_each_entry_safe(fc, back, &px->filter_configs, list) {
if (fc->id == http_comp_req_flt_id || fc->id == http_comp_res_flt_id) {
if (fc->id == http_comp_flt_id) {
memprintf(err, "%s: Proxy supports only one compression filter\n", px->id);
return -1;
}
}
fconf->id = http_comp_req_flt_id;
fconf->id = http_comp_flt_id;
fconf->conf = NULL;
fconf->ops = &comp_req_ops;
/* FILTER API prepared a single filter_conf struct as it is meant to
* initialize exactly one fconf per keyword, but with the "compression"
* filter, for retro-compatibility we want to emulate the historical
* behavior which is to compress both requests and responses, so to
* emulate that we manually initialize the comp-res filter as well
*/
fconf_res = calloc(1, sizeof(*fconf_res));
if (!fconf_res) {
memprintf(err, "'%s' : out of memory", args[0]);
return -1;
}
fconf_res->id = http_comp_res_flt_id;
fconf_res->conf = NULL;
fconf_res->ops = &comp_res_ops;
/* manually add the fconf_res to the list because filter API doesn't
* know about it
*/
LIST_APPEND(&px->filter_configs, &fconf_res->list);
fconf->ops = &comp_ops;
(*cur_arg)++;
return 0;
}
static int
parse_http_comp_req_flt(char **args, int *cur_arg, struct proxy *px,
struct flt_conf *fconf, char **err, void *private)
{
struct flt_conf *fc, *back;
struct comp *comp;
list_for_each_entry_safe(fc, back, &px->filter_configs, list) {
if (fc->id == http_comp_req_flt_id) {
memprintf(err, "%s: Proxy supports only one comp-req filter\n", px->id);
return -1;
}
}
comp = proxy_get_comp(px, 0);
if (comp == NULL) {
memprintf(err, "memory failure\n");
return -1;
}
comp->flags |= COMP_FL_DIR_REQ;
fconf->id = http_comp_req_flt_id;
fconf->conf = NULL;
fconf->ops = &comp_req_ops;
(*cur_arg)++;
return 0;
}
static int
parse_http_comp_res_flt(char **args, int *cur_arg, struct proxy *px,
struct flt_conf *fconf, char **err, void *private)
{
struct flt_conf *fc, *back;
struct comp *comp;
list_for_each_entry_safe(fc, back, &px->filter_configs, list) {
if (fc->id == http_comp_res_flt_id) {
memprintf(err, "%s: Proxy supports only one comp-res filter\n", px->id);
return -1;
}
}
comp = proxy_get_comp(px, 0);
if (comp == NULL) {
memprintf(err, "memory failure\n");
return -1;
}
comp->flags |= COMP_FL_DIR_RES;
fconf->id = http_comp_res_flt_id;
fconf->conf = NULL;
fconf->ops = &comp_res_ops;
(*cur_arg)++;
return 0;
}
int
check_implicit_http_comp_flt(struct proxy *proxy)
{
struct flt_conf *fconf;
struct flt_conf *fconf_req = NULL;
struct flt_conf *fconf_res = NULL;
int explicit = 0;
int comp = 0;
int err = 0;
@ -1134,7 +999,7 @@ check_implicit_http_comp_flt(struct proxy *proxy)
goto end;
if (!LIST_ISEMPTY(&proxy->filter_configs)) {
list_for_each_entry(fconf, &proxy->filter_configs, list) {
if (fconf->id == http_comp_req_flt_id || fconf->id == http_comp_res_flt_id)
if (fconf->id == http_comp_flt_id)
comp = 1;
else if (fconf->id == cache_store_flt_id) {
if (comp) {
@ -1162,25 +1027,17 @@ check_implicit_http_comp_flt(struct proxy *proxy)
/* Implicit declaration of the compression filter is always the last
* one */
fconf_req = calloc(1, sizeof(*fconf));
fconf_res = calloc(1, sizeof(*fconf));
if (!fconf_req || !fconf_res) {
fconf = calloc(1, sizeof(*fconf));
if (!fconf) {
ha_alert("config: %s '%s': out of memory\n",
proxy_type_str(proxy), proxy->id);
ha_free(&fconf_req);
ha_free(&fconf_res);
err++;
goto end;
}
fconf_req->id = http_comp_req_flt_id;
fconf_req->conf = NULL;
fconf_req->ops = &comp_req_ops;
LIST_APPEND(&proxy->filter_configs, &fconf_req->list);
fconf_res->id = http_comp_res_flt_id;
fconf_res->conf = NULL;
fconf_res->ops = &comp_res_ops;
LIST_APPEND(&proxy->filter_configs, &fconf_res->list);
fconf->id = http_comp_flt_id;
fconf->conf = NULL;
fconf->ops = &comp_ops;
LIST_APPEND(&proxy->filter_configs, &fconf->list);
end:
return err;
}
@ -1215,7 +1072,7 @@ smp_fetch_res_comp_algo(const struct arg *args, struct sample *smp,
return 0;
list_for_each_entry(filter, &strm_flt(smp->strm)->filters, list) {
if (FLT_ID(filter) != http_comp_res_flt_id)
if (FLT_ID(filter) != http_comp_flt_id)
continue;
if (!(st = filter->ctx))
@ -1223,8 +1080,8 @@ smp_fetch_res_comp_algo(const struct arg *args, struct sample *smp,
smp->data.type = SMP_T_STR;
smp->flags = SMP_F_CONST;
smp->data.u.str.area = st->comp_algo->cfg_name;
smp->data.u.str.data = st->comp_algo->cfg_name_len;
smp->data.u.str.area = st->comp_algo[COMP_DIR_RES]->cfg_name;
smp->data.u.str.data = st->comp_algo[COMP_DIR_RES]->cfg_name_len;
return 1;
}
return 0;
@ -1242,8 +1099,6 @@ INITCALL1(STG_REGISTER, cfg_register_keywords, &cfg_kws);
/* Declare the filter parser for "compression" keyword */
static struct flt_kw_list filter_kws = { "COMP", { }, {
{ "compression", parse_http_comp_flt, NULL },
{ "comp-req", parse_http_comp_req_flt, NULL },
{ "comp-res", parse_http_comp_res_flt, NULL },
{ NULL, NULL, NULL },
}
};

View File

@ -516,11 +516,8 @@ static void spoe_handle_appctx(struct appctx *appctx)
appctx->st0 = SPOE_APPCTX_ST_END;
applet_set_error(appctx);
}
else {
SPOE_APPCTX(appctx)->spoe_ctx->state = SPOE_CTX_ST_WAITING_ACK;
if (!spoe_handle_receiving_frame_appctx(appctx))
break;
}
else if (!spoe_handle_receiving_frame_appctx(appctx))
break;
goto switchstate;
case SPOE_APPCTX_ST_EXIT:
@ -1112,16 +1109,6 @@ static int spoe_process_event(struct stream *s, struct spoe_context *ctx,
agent->id, spoe_event_str[ev], s->uniq_id, ctx->status_code, ctx->stats.t_process,
agent->counters.nb_errors, agent->counters.nb_processed);
}
else if (ret == 0) {
if ((s->scf->flags & SC_FL_ERROR) ||
((s->scf->flags & SC_FL_EOS) && proxy_abrt_close_def(s->be, 1))) {
ctx->status_code = SPOE_CTX_ERR_INTERRUPT;
spoe_stop_processing(agent, ctx);
spoe_handle_processing_error(s, agent, ctx, dir);
ret = 1;
}
}
return ret;
}

View File

@ -319,7 +319,6 @@ static struct htx_sl *h2_prepare_htx_reqline(uint32_t fields, struct ist *phdr,
*/
int h2_make_htx_request(struct http_hdr *list, struct htx *htx, unsigned int *msgf, unsigned long long *body_len, int relaxed)
{
struct htx_blk *tailblk = htx_get_tail_blk(htx);
struct ist phdr_val[H2_PHDR_NUM_ENTRIES];
uint32_t fields; /* bit mask of H2_PHDR_FND_* */
uint32_t idx;
@ -534,7 +533,6 @@ int h2_make_htx_request(struct http_hdr *list, struct htx *htx, unsigned int *ms
return ret;
fail:
htx_truncate_blk(htx, tailblk);
return -1;
}
@ -639,7 +637,6 @@ static struct htx_sl *h2_prepare_htx_stsline(uint32_t fields, struct ist *phdr,
*/
int h2_make_htx_response(struct http_hdr *list, struct htx *htx, unsigned int *msgf, unsigned long long *body_len, char *upgrade_protocol)
{
struct htx_blk *tailblk = htx_get_tail_blk(htx);
struct ist phdr_val[H2_PHDR_NUM_ENTRIES];
uint32_t fields; /* bit mask of H2_PHDR_FND_* */
uint32_t idx;
@ -796,7 +793,6 @@ int h2_make_htx_response(struct http_hdr *list, struct htx *htx, unsigned int *m
return ret;
fail:
htx_truncate_blk(htx, tailblk);
return -1;
}
@ -816,7 +812,6 @@ int h2_make_htx_response(struct http_hdr *list, struct htx *htx, unsigned int *m
*/
int h2_make_htx_trailers(struct http_hdr *list, struct htx *htx)
{
struct htx_blk *tailblk = htx_get_tail_blk(htx);
const char *ctl;
struct ist v;
uint32_t idx;
@ -866,8 +861,8 @@ int h2_make_htx_trailers(struct http_hdr *list, struct htx *htx)
goto fail;
}
/* Check the number of trailers against "tune.http.maxhdr" value before adding EOT block */
if (idx > global.tune.max_http_hdr)
/* Check the number of blocks against "tune.http.maxhdr" value before adding EOT block */
if (htx_nbblks(htx) > global.tune.max_http_hdr)
goto fail;
if (!htx_add_endof(htx, HTX_BLK_EOT))
@ -876,6 +871,5 @@ int h2_make_htx_trailers(struct http_hdr *list, struct htx *htx)
return 1;
fail:
htx_truncate_blk(htx, tailblk);
return -1;
}

Some files were not shown because too many files have changed in this diff Show More