include $(TOPDIR)/rules.mk
PKG_NAME:=haproxy
-PKG_VERSION:=1.8.20
-PKG_RELEASE:=1
+PKG_VERSION:=2.0.0
+PKG_RELEASE:=2
PKG_SOURCE:=haproxy-$(PKG_VERSION).tar.gz
-PKG_SOURCE_URL:=https://www.haproxy.org/download/1.8/src/
-PKG_HASH:=3228f78d5fe1dfbaccf41bf387e36b08eeef6e16330053cafde5fa303e262b16
+PKG_SOURCE_URL:=https://www.haproxy.org/download/2.0/src/
+PKG_HASH:=fe0a0d69e1091066a91b8d39199c19af8748e0e872961c6fc43c91ec7a28ff20
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(BUILD_VARIANT)/$(PKG_NAME)-$(PKG_VERSION)
PKG_LICENSE:=GPL-2.0
ENABLE_REGPARM:=n
ifeq ($(CONFIG_TARGET_x86),y)
- ENABLE_REGPARM:=y
+ ENABLE_REGPARM:=y
endif
-LINUX_TARGET:=linux2628
+ifeq ($(CONFIG_USE_UCLIBC),y)
+ LINUX_TARGET:=linux-uclibc
+else
+ LINUX_TARGET:=linux-glibc
+endif
ifeq ($(BUILD_VARIANT),ssl)
ADDON+=USE_OPENSSL=1
CC="$(TARGET_CC)" \
PCREDIR="$(STAGING_DIR)/usr/" \
SMALL_OPTS="-DBUFSIZE=16384 -DMAXREWRITE=1030 -DSYSTEM_MAXCONN=165530" \
- USE_LINUX_TPROXY=1 USE_LINUX_SPLICE=1 USE_TFO=1 \
- USE_ZLIB=yes USE_PCRE=1 USE_PCRE_JIT=1 USE_GETADDRINFO=1 \
+ USE_LINUX_TPROXY=1 USE_LINUX_SPLICE=1 USE_TFO=1 USE_NS=1 \
+ USE_ZLIB=1 USE_PCRE=1 USE_PCRE_JIT=1 USE_GETADDRINFO=1 \
+ USE_THREAD=1 USE_PTHREAD_PSHARED=1 \
VERSION="$(PKG_VERSION)" SUBVERS="-$(PKG_RELEASE)" \
VERDATE="$(shell date -d @$(SOURCE_DATE_EPOCH) '+%Y/%m/%d')" IGNOREGIT=1 \
$(ADDON) \
- CFLAGS="$(TARGET_CFLAGS)" \
+ CFLAGS="$(TARGET_CFLAGS) -fno-strict-aliasing -Wdeclaration-after-statement -fwrapv -Wno-format-truncation -Wno-unused-label -Wno-sign-compare -Wno-unused-parameter -Wno-old-style-declaration -Wno-ignored-qualifiers -Wno-clobbered -Wno-missing-field-initializers -Wno-implicit-fallthrough -Wno-stringop-overflow -Wno-cast-function-type -Wtype-limits -Wshift-negative-value -Wshift-overflow=2 -Wduplicated-cond -Wnull-dereference" \
LD="$(TARGET_CC)" \
- LDFLAGS="$(TARGET_LDFLAGS) -latomic"
+ LDFLAGS="$(TARGET_LDFLAGS) -latomic" \
+ EXTRA_OBJS="contrib/prometheus-exporter/service-prometheus.o"
$(MAKE_VARS) $(MAKE) -C $(PKG_BUILD_DIR) \
DESTDIR="$(PKG_INSTALL_DIR)" \
$(MAKE_VARS) $(MAKE) -C $(PKG_BUILD_DIR)/contrib/halog \
DESTDIR="$(PKG_INSTALL_DIR)" \
$(MAKE_FLAGS) \
+ OPTIMIZE="$(TARGET_CFLAGS)" \
ADDLIB="-lcrypto" \
halog
endef
-# Example configuration file for HAProxy 1.3, refer to the url below for
+# Example configuration file for HAProxy 2.0, refer to the url below for
# a full documentation and examples for configuration:
-# http://haproxy.1wt.eu/download/1.3/doc/configuration.txt
+# https://cbonte.github.io/haproxy-dconv/2.0/configuration.html
# Global parameters
# limits like number of open file descriptors. Default is 1.
#nbproc 2
+# Default parameters
+defaults
+ # Default timeouts
+ timeout connect 5000ms
+ timeout client 50000ms
+ timeout server 50000ms
+
# Example HTTP proxy listener
listen my_http_proxy
# Round robin load balancing over two servers on port 123 forcing
# the address 192.168.1.1 and port 25 as source.
balance roundrobin
- #use next line for transparent proxy, so the servers can see the
- #original ip-address and remove source keyword in server definition
- #source 0.0.0.0 usesrc clientip
+ #use next line for transparent proxy, so the servers can see the
+ #original ip-address and remove source keyword in server definition
+ #source 0.0.0.0 usesrc clientip
server server01 192.168.1.10:123 source 192.168.1.1:25
server server02 192.168.1.20:123 source 192.168.1.1:25
#!/bin/sh
if [ "$ACTION" = add ]; then
-
/etc/init.d/haproxy enabled && \
/etc/init.d/haproxy start
fi
STOP=80
SERVICE_USE_PID=1
+EXTRA_COMMANDS="check"
HAPROXY_BIN="/usr/sbin/haproxy"
HAPROXY_CONFIG="/etc/haproxy.cfg"
}
reload() {
- $HAPROXY_BIN -D -q -f $HAPROXY_CONFIG -p $HAPROXY_PID -sf $(cat $HAPROXY_PID | tr "\n" " ")
- #$HAPROXY_BIN -D -q -f $HAPROXY_CONFIG -p $HAPROXY_PID -sf $(cat $HAPROXY_PID)
+ $HAPROXY_BIN -D -q -f $HAPROXY_CONFIG -p $HAPROXY_PID -sf $(cat $HAPROXY_PID)
+}
+
+check() {
+ $HAPROXY_BIN -c -q -V -f $HAPROXY_CONFIG
}
#!/bin/bash
-CLONEURL=http://git.haproxy.org/git/haproxy-1.8.git
-BASE_TAG=v1.8.20
+CLONEURL=http://git.haproxy.org/git/haproxy-2.0.git
+BASE_TAG=v2.0.0
TMP_REPODIR=tmprepo
PATCHESDIR=patches
--- /dev/null
+commit 032cff38c24d8359dc575423a94d19b6ad8bf848
+Author: Christopher Faulet <cfaulet@haproxy.com>
+Date: Mon Jun 17 11:44:47 2019 +0200
+
+ BUG/MEDIUM: h2/htx: Update data length of the HTX when the cookie list is built
+
+ When an H2 request is converted into an HTX message, All cookie headers are
+ grouped into one, each value separated by a semicolon (;). To do so, we add the
+ header "cookie" with the first value and then we update the value by appending
+ other cookies. But during this operation, only the size of the HTX block is
+ updated. And not the data length of the whole HTX message.
+
+ It is an old bug and it seems to work by chance till now. But it may lead to
+ undefined behaviour by time to time.
+
+ This patch must be backported to 2.0 and 1.9
+
+ (cherry picked from commit 0c6de00d7c842a682bba7586ef34fb10f69ec63c)
+ Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
+
+diff --git a/src/h2.c b/src/h2.c
+index 9681aca5..32c1ef16 100644
+--- a/src/h2.c
++++ b/src/h2.c
+@@ -737,6 +737,7 @@ int h2_make_htx_request(struct http_hdr *list, struct htx *htx, unsigned int *ms
+ goto fail;
+
+ htx_set_blk_value_len(blk, tl);
++ htx->data += vl+2;
+ *(char *)(htx_get_blk_ptr(htx, blk) + bs + 0) = ';';
+ *(char *)(htx_get_blk_ptr(htx, blk) + bs + 1) = ' ';
+ memcpy(htx_get_blk_ptr(htx, blk) + bs + 2, list[ck].v.ptr, vl);
+++ /dev/null
-commit cf2f1243373be97249567ffd259e975cc87068b8
-Author: Christopher Faulet <cfaulet@haproxy.com>
-Date: Mon Apr 29 13:12:02 2019 +0200
-
- BUG/MINOR: http: Call stream_inc_be_http_req_ctr() only one time per request
-
- The function stream_inc_be_http_req_ctr() is called at the beginning of the
- analysers AN_REQ_HTTP_PROCESS_FE/BE. It as an effect only on the backend. But we
- must be careful to call it only once. If the processing of HTTP rules is
- interrupted in the middle, when the analyser is resumed, we must not call it
- again. Otherwise, the tracked counters of the backend are incremented several
- times.
-
- This bug was reported in github. See issue #74.
-
- This fix should be backported as far as 1.6.
-
- (cherry picked from commit 1907ccc2f75b78ace1ee4acdfc60d48a76e3decd)
- Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
- (cherry picked from commit 319921866ea9ecc46215fea5679abc8efdfcbea5)
- [cf: HTX part was removed]
- Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
-
-diff --git a/src/proto_http.c b/src/proto_http.c
-index ccacd6a4..556cabad 100644
---- a/src/proto_http.c
-+++ b/src/proto_http.c
-@@ -3420,8 +3420,10 @@ int http_process_req_common(struct stream *s, struct channel *req, int an_bit, s
- req->buf->i,
- req->analysers);
-
-- /* just in case we have some per-backend tracking */
-- stream_inc_be_http_req_ctr(s);
-+ /* just in case we have some per-backend tracking. Only called the first
-+ * execution of the analyser. */
-+ if (!s->current_rule || s->current_rule_list != &px->http_req_rules)
-+ stream_inc_be_http_req_ctr(s);
-
- /* evaluate http-request rules */
- if (!LIST_ISEMPTY(&px->http_req_rules)) {
+++ /dev/null
-commit c1620a52a3def02b4837376385c416c03ca874c4
-Author: Kevin Zhu <ipandtcp@gmail.com>
-Date: Fri Apr 26 14:00:01 2019 +0800
-
- BUG/MEDIUM: spoe: arg len encoded in previous frag frame but len changed
-
- Fragmented arg will do fetch at every encode time, each fetch may get
- different result if SMP_F_MAY_CHANGE, for example res.payload, but
- the length already encoded in first fragment of the frame, that will
- cause SPOA decode failed and waste resources.
-
- This patch must be backported to 1.9 and 1.8.
-
- (cherry picked from commit f7f54280c8106e92a55243f5d60f8587e79602d1)
- Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
- (cherry picked from commit 3a838e526cdbc00ded5362e66f1ef3a441abc3c1)
- Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
-
-diff --git a/include/proto/spoe.h b/include/proto/spoe.h
-index 002cf7d7..2cdca10b 100644
---- a/include/proto/spoe.h
-+++ b/include/proto/spoe.h
-@@ -121,7 +121,7 @@ spoe_decode_buffer(char **buf, char *end, char **str, uint64_t *len)
- * many bytes has been encoded. If <*off> is zero at the end, it means that all
- * data has been encoded. */
- static inline int
--spoe_encode_data(struct sample *smp, unsigned int *off, char **buf, char *end)
-+spoe_encode_data(unsigned int *len, struct sample *smp, unsigned int *off, char **buf, char *end)
- {
- char *p = *buf;
- int ret;
-@@ -183,15 +183,16 @@ spoe_encode_data(struct sample *smp, unsigned int *off, char **buf, char *end)
- ret = spoe_encode_frag_buffer(chk->str, chk->len, &p, end);
- if (ret == -1)
- return -1;
-+ *len = chk->len;
- }
- else {
- /* The sample has been fragmented, encode remaining data */
-- ret = MIN(chk->len - *off, end - p);
-+ ret = MIN(*len - *off, end - p);
- memcpy(p, chk->str + *off, ret);
- p += ret;
- }
- /* Now update <*off> */
-- if (ret + *off != chk->len)
-+ if (ret + *off != *len)
- *off += ret;
- else
- *off = 0;
-diff --git a/include/types/spoe.h b/include/types/spoe.h
-index 53e7200c..cfaa42f8 100644
---- a/include/types/spoe.h
-+++ b/include/types/spoe.h
-@@ -304,6 +304,7 @@ struct spoe_context {
- struct spoe_message *curmsg; /* SPOE message from which to resume encoding */
- struct spoe_arg *curarg; /* SPOE arg in <curmsg> from which to resume encoding */
- unsigned int curoff; /* offset in <curarg> from which to resume encoding */
-+ unsigned int curlen; /* length of <curarg> need to be encode, for SMP_F_MAY_CHANGE data */
- unsigned int flags; /* SPOE_FRM_FL_* */
- } frag_ctx; /* Info about fragmented frames, valid on if SPOE_CTX_FL_FRAGMENTED is set */
- };
-diff --git a/src/flt_spoe.c b/src/flt_spoe.c
-index f6109778..0c0b3794 100644
---- a/src/flt_spoe.c
-+++ b/src/flt_spoe.c
-@@ -2172,6 +2172,7 @@ spoe_encode_message(struct stream *s, struct spoe_context *ctx,
- list_for_each_entry(arg, &msg->args, list) {
- ctx->frag_ctx.curarg = arg;
- ctx->frag_ctx.curoff = UINT_MAX;
-+ ctx->frag_ctx.curlen = 0;
-
- encode_argument:
- if (ctx->frag_ctx.curoff != UINT_MAX)
-@@ -2186,7 +2187,7 @@ spoe_encode_message(struct stream *s, struct spoe_context *ctx,
-
- /* Fetch the arguement value */
- smp = sample_process(s->be, s->sess, s, dir|SMP_OPT_FINAL, arg->expr, NULL);
-- ret = spoe_encode_data(smp, &ctx->frag_ctx.curoff, buf, end);
-+ ret = spoe_encode_data(&ctx->frag_ctx.curlen, smp, &ctx->frag_ctx.curoff, buf, end);
- if (ret == -1 || ctx->frag_ctx.curoff)
- goto too_big;
- }
--- /dev/null
+commit 5a8549e68225070d0b79cbbb9c5f791e103685e7
+Author: Christopher Faulet <cfaulet@haproxy.com>
+Date: Mon Jun 17 13:36:06 2019 +0200
+
+ BUG/MINOR: lua/htx: Make txn.req_req_* and txn.res_rep_* HTX aware
+
+ These bindings were not updated to support HTX streams.
+
+ This patch must be backported to 2.0 and 1.9. It fixes the issue #124.
+
+ (cherry picked from commit ea418748dd22331e9798cfd8f5e25b436cd577e3)
+ Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
+
+diff --git a/src/hlua.c b/src/hlua.c
+index 28abd083..32f0e8db 100644
+--- a/src/hlua.c
++++ b/src/hlua.c
+@@ -5375,7 +5375,13 @@ __LJMP static inline int hlua_http_rep_hdr(lua_State *L, struct hlua_txn *htxn,
+ if (!(re = regex_comp(reg, 1, 1, NULL)))
+ WILL_LJMP(luaL_argerror(L, 3, "invalid regex"));
+
+- http_transform_header_str(htxn->s, msg, name, name_len, value, re, action);
++ if (IS_HTX_STRM(htxn->s)) {
++ struct htx *htx = htxbuf(&msg->chn->buf);
++
++ htx_transform_header_str(htxn->s, msg->chn, htx, ist2(name, name_len), value, re, action);
++ }
++ else
++ http_transform_header_str(htxn->s, msg, name, name_len, value, re, action);
+ regex_free(re);
+ return 0;
+ }
--- /dev/null
+commit 661bfc3d0e1b7756db59d00d86e316f694cae3c6
+Author: Christopher Faulet <cfaulet@haproxy.com>
+Date: Mon Jun 17 14:07:46 2019 +0200
+
+ BUG/MINOR: mux-h1: Add the header connection in lower case in outgoing messages
+
+ When necessary, this header is directly added in outgoing messages by the H1
+ multiplexer. Because there is no HTX conversion first, the header name is not
+ converserted to its lower case version. So, it must be added in lower case by
+ the multiplexer.
+
+ This patch must be backported to 2.0 and 1.9.
+
+ (cherry picked from commit a110ecbd843e156dd01c6ac581c735be5e240d5b)
+ Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
+
+diff --git a/src/mux_h1.c b/src/mux_h1.c
+index 317f1a55..21deb354 100644
+--- a/src/mux_h1.c
++++ b/src/mux_h1.c
+@@ -1642,7 +1642,7 @@ static size_t h1_process_output(struct h1c *h1c, struct buffer *buf, size_t coun
+ /* There is no "Connection:" header and
+ * it the conn_mode must be
+ * processed. So do it */
+- n = ist("Connection");
++ n = ist("connection");
+ v = ist("");
+ h1_process_output_conn_mode(h1s, h1m, &v);
+ if (v.len) {
+++ /dev/null
-commit 72fdff1fdb5b82685dc3d2db23ece042195a0cbd
-Author: Christopher Faulet <cfaulet@haproxy.com>
-Date: Fri Apr 26 14:30:15 2019 +0200
-
- MINOR: spoe: Use the sample context to pass frag_ctx info during encoding
-
- This simplifies the API and hide the details in the sample. This way, only
- string and binary are aware of these info, because other types cannot be
- partially encoded.
-
- This patch may be backported to 1.9 and 1.8.
-
- (cherry picked from commit 85db3212b87b33f1a39a688546f4f53a5c4ba4da)
- Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
- (cherry picked from commit b93366e3ee44f5de93f01569fcdcd602f6d0703f)
- Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
-
-diff --git a/include/proto/spoe.h b/include/proto/spoe.h
-index 2cdca10b..cce13e50 100644
---- a/include/proto/spoe.h
-+++ b/include/proto/spoe.h
-@@ -117,11 +117,9 @@ spoe_decode_buffer(char **buf, char *end, char **str, uint64_t *len)
- *
- * If the value is too big to be encoded, depending on its type, then encoding
- * failed or the value is partially encoded. Only strings and binaries can be
-- * partially encoded. In this case, the offset <*off> is updated to known how
-- * many bytes has been encoded. If <*off> is zero at the end, it means that all
-- * data has been encoded. */
-+ * partially encoded. */
- static inline int
--spoe_encode_data(unsigned int *len, struct sample *smp, unsigned int *off, char **buf, char *end)
-+spoe_encode_data(struct sample *smp, char **buf, char *end)
- {
- char *p = *buf;
- int ret;
-@@ -164,12 +162,16 @@ spoe_encode_data(unsigned int *len, struct sample *smp, unsigned int *off, char
-
- case SMP_T_STR:
- case SMP_T_BIN: {
-+ /* If defined, get length and offset of the sample by reading the sample
-+ * context. ctx.a[0] is the pointer to the length and ctx.a[1] is the
-+ * pointer to the offset. If the offset is greater than 0, it means the
-+ * sample is partially encoded. In this case, we only need to encode the
-+ * reamining. When all the sample is encoded, the offset is reset to 0.
-+ * So the caller know it can try to encode the next sample. */
- struct chunk *chk = &smp->data.u.str;
-+ unsigned int *len = (smp->ctx.a[0] ? smp->ctx.a[0] : 0);
-+ unsigned int *off = (smp->ctx.a[1] ? smp->ctx.a[1] : 0);
-
-- /* Here, we need to know if the sample has already been
-- * partially encoded. If yes, we only need to encode the
-- * remaining, <*off> reprensenting the number of bytes
-- * already encoded. */
- if (!*off) {
- /* First evaluation of the sample : encode the
- * type (string or binary), the buffer length
-diff --git a/src/flt_spoe.c b/src/flt_spoe.c
-index 0c0b3794..66d8b045 100644
---- a/src/flt_spoe.c
-+++ b/src/flt_spoe.c
-@@ -2187,7 +2187,9 @@ spoe_encode_message(struct stream *s, struct spoe_context *ctx,
-
- /* Fetch the arguement value */
- smp = sample_process(s->be, s->sess, s, dir|SMP_OPT_FINAL, arg->expr, NULL);
-- ret = spoe_encode_data(&ctx->frag_ctx.curlen, smp, &ctx->frag_ctx.curoff, buf, end);
-+ smp->ctx.a[0] = &ctx->frag_ctx.curlen;
-+ smp->ctx.a[1] = &ctx->frag_ctx.curoff;
-+ ret = spoe_encode_data(smp, buf, end);
- if (ret == -1 || ctx->frag_ctx.curoff)
- goto too_big;
- }
--- /dev/null
+commit eaf650083924a697cde3379703984c5e7a5ebd41
+Author: Tim Duesterhus <tim@bastelstu.be>
+Date: Mon Jun 17 16:10:07 2019 +0200
+
+ BUG/MEDIUM: compression: Set Vary: Accept-Encoding for compressed responses
+
+ Make HAProxy set the `Vary: Accept-Encoding` response header if it compressed
+ the server response.
+
+ Technically the `Vary` header SHOULD also be set for responses that would
+ normally be compressed based off the current configuration, but are not due
+ to a missing or invalid `Accept-Encoding` request header or due to the
+ maximum compression rate being exceeded.
+
+ Not setting the header in these cases does no real harm, though: An
+ uncompressed response might be returned by a Cache, even if a compressed
+ one could be retrieved from HAProxy. This increases the traffic to the end
+ user if the cache is unable to compress itself, but it saves another
+ roundtrip to HAProxy.
+
+ see the discussion on the mailing list: https://www.mail-archive.com/haproxy@formilux.org/msg34221.html
+ Message-ID: 20190617121708.GA2964@1wt.eu
+
+ A small issue remains: The User-Agent is not added to the `Vary` header,
+ despite being relevant to the response. Adding the User-Agent header would
+ make responses effectively uncacheable and it's unlikely to see a Mozilla/4
+ in the wild in 2019.
+
+ Add a reg-test to ensure the behaviour as described in this commit message.
+
+ see issue #121
+ Should be backported to all branches with compression (i.e. 1.6+).
+
+ (cherry picked from commit 721d686bd10dc6993859f9026ad907753d1d2064)
+ Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
+
+diff --git a/reg-tests/compression/vary.vtc b/reg-tests/compression/vary.vtc
+new file mode 100644
+index 00000000..0a060e4b
+--- /dev/null
++++ b/reg-tests/compression/vary.vtc
+@@ -0,0 +1,187 @@
++varnishtest "Compression sets Vary header"
++
++#REQUIRE_VERSION=1.9
++#REQUIRE_OPTION=ZLIB|SLZ
++
++feature ignore_unknown_macro
++
++server s1 {
++ rxreq
++ expect req.url == "/plain/accept-encoding-gzip"
++ expect req.http.accept-encoding == "gzip"
++ txresp \
++ -hdr "Content-Type: text/plain" \
++ -bodylen 100
++
++ rxreq
++ expect req.url == "/plain/accept-encoding-invalid"
++ expect req.http.accept-encoding == "invalid"
++ txresp \
++ -hdr "Content-Type: text/plain" \
++ -bodylen 100
++
++ rxreq
++ expect req.url == "/plain/accept-encoding-null"
++ expect req.http.accept-encoding == "<undef>"
++ txresp \
++ -hdr "Content-Type: text/plain" \
++ -bodylen 100
++
++ rxreq
++ expect req.url == "/html/accept-encoding-gzip"
++ expect req.http.accept-encoding == "gzip"
++ txresp \
++ -hdr "Content-Type: text/html" \
++ -bodylen 100
++
++ rxreq
++ expect req.url == "/html/accept-encoding-invalid"
++ expect req.http.accept-encoding == "invalid"
++ txresp \
++ -hdr "Content-Type: text/html" \
++ -bodylen 100
++
++
++ rxreq
++ expect req.url == "/html/accept-encoding-null"
++ expect req.http.accept-encoding == "<undef>"
++ txresp \
++ -hdr "Content-Type: text/html" \
++ -bodylen 100
++
++ rxreq
++ expect req.url == "/dup-etag/accept-encoding-gzip"
++ expect req.http.accept-encoding == "gzip"
++ txresp \
++ -hdr "Content-Type: text/plain" \
++ -hdr "ETag: \"123\"" \
++ -hdr "ETag: \"123\"" \
++ -bodylen 100
++} -repeat 2 -start
++
++
++haproxy h1 -conf {
++ defaults
++ mode http
++ ${no-htx} option http-use-htx
++ timeout connect 1s
++ timeout client 1s
++ timeout server 1s
++
++ frontend fe-gzip
++ bind "fd@${fe_gzip}"
++ default_backend be-gzip
++
++ backend be-gzip
++ compression algo gzip
++ compression type text/plain
++ server www ${s1_addr}:${s1_port}
++
++ frontend fe-nothing
++ bind "fd@${fe_nothing}"
++ default_backend be-nothing
++
++ backend be-nothing
++ server www ${s1_addr}:${s1_port}
++} -start
++
++client c1 -connect ${h1_fe_gzip_sock} {
++ txreq -url "/plain/accept-encoding-gzip" \
++ -hdr "Accept-Encoding: gzip"
++ rxresp
++ expect resp.status == 200
++ expect resp.http.content-encoding == "gzip"
++ expect resp.http.vary == "Accept-Encoding"
++ gunzip
++ expect resp.bodylen == 100
++
++ txreq -url "/plain/accept-encoding-invalid" \
++ -hdr "Accept-Encoding: invalid"
++ rxresp
++ expect resp.status == 200
++ expect resp.http.vary == "<undef>"
++ expect resp.bodylen == 100
++
++ txreq -url "/plain/accept-encoding-null"
++ rxresp
++ expect resp.status == 200
++ expect resp.http.vary == "<undef>"
++ expect resp.bodylen == 100
++
++ txreq -url "/html/accept-encoding-gzip" \
++ -hdr "Accept-Encoding: gzip"
++ rxresp
++ expect resp.status == 200
++ expect resp.http.vary == "<undef>"
++ expect resp.bodylen == 100
++
++ txreq -url "/html/accept-encoding-invalid" \
++ -hdr "Accept-Encoding: invalid"
++ rxresp
++ expect resp.status == 200
++ expect resp.http.vary == "<undef>"
++ expect resp.bodylen == 100
++
++ txreq -url "/html/accept-encoding-null"
++ rxresp
++ expect resp.status == 200
++ expect resp.http.vary == "<undef>"
++ expect resp.bodylen == 100
++
++ txreq -url "/dup-etag/accept-encoding-gzip" \
++ -hdr "Accept-Encoding: gzip"
++ rxresp
++ expect resp.status == 200
++ expect resp.http.vary == "<undef>"
++ expect resp.bodylen == 100
++} -run
++
++# This Client duplicates c1, against the "nothing" frontend, ensuring no Vary header is ever set.
++client c2 -connect ${h1_fe_nothing_sock} {
++ txreq -url "/plain/accept-encoding-gzip" \
++ -hdr "Accept-Encoding: gzip"
++ rxresp
++ expect resp.status == 200
++ expect resp.http.vary == "<undef>"
++ expect resp.bodylen == 100
++
++ txreq -url "/plain/accept-encoding-invalid" \
++ -hdr "Accept-Encoding: invalid"
++ rxresp
++ expect resp.status == 200
++ expect resp.http.vary == "<undef>"
++ expect resp.bodylen == 100
++
++ txreq -url "/plain/accept-encoding-null"
++ rxresp
++ expect resp.status == 200
++ expect resp.http.vary == "<undef>"
++ expect resp.bodylen == 100
++
++ txreq -url "/html/accept-encoding-gzip" \
++ -hdr "Accept-Encoding: gzip"
++ rxresp
++ expect resp.status == 200
++ expect resp.http.vary == "<undef>"
++ expect resp.bodylen == 100
++
++ txreq -url "/html/accept-encoding-invalid" \
++ -hdr "Accept-Encoding: invalid"
++ rxresp
++ expect resp.status == 200
++ expect resp.http.vary == "<undef>"
++ expect resp.bodylen == 100
++
++ txreq -url "/html/accept-encoding-null"
++ rxresp
++ expect resp.status == 200
++ expect resp.http.vary == "<undef>"
++ expect resp.bodylen == 100
++
++ txreq -url "/dup-etag/accept-encoding-gzip" \
++ -hdr "Accept-Encoding: gzip"
++ rxresp
++ expect resp.status == 200
++ expect resp.http.vary == "<undef>"
++ expect resp.bodylen == 100
++} -run
+diff --git a/src/flt_http_comp.c b/src/flt_http_comp.c
+index b04dcd14..37f237fe 100644
+--- a/src/flt_http_comp.c
++++ b/src/flt_http_comp.c
+@@ -523,6 +523,9 @@ http_set_comp_reshdr(struct comp_state *st, struct stream *s, struct http_msg *m
+ }
+ }
+
++ if (http_header_add_tail2(msg, &txn->hdr_idx, "Vary: Accept-Encoding", 21) < 0)
++ goto error;
++
+ return 1;
+
+ error:
+@@ -577,6 +580,9 @@ htx_set_comp_reshdr(struct comp_state *st, struct stream *s, struct http_msg *ms
+ }
+ }
+
++ if (!http_add_header(htx, ist("Vary"), ist("Accept-Encoding")))
++ goto error;
++
+ return 1;
+
+ error:
+++ /dev/null
-commit dfc3718f0a302ea3deb5f1a325d35fce0e4cfa48
-Author: Yann Cézard <ycezard@viareport.com>
-Date: Thu Apr 25 14:48:38 2019 +0200
-
- DOC: contrib/modsecurity: Typos and fix the reject example
-
- Thanks to https://www.mail-archive.com/haproxy@formilux.org/msg30056.html
-
- This patch may be backported to 1.9 and 1.8.
-
- (cherry picked from commit 494ddbff478d880e48de490f2689607addac70bc)
- Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
- (cherry picked from commit 850896603086877641272d6e4075e66bd91f2e50)
- Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
-
-diff --git a/contrib/modsecurity/README b/contrib/modsecurity/README
-index e6cb305e..8031389d 100644
---- a/contrib/modsecurity/README
-+++ b/contrib/modsecurity/README
-@@ -88,15 +88,15 @@ HAProxy configuration. For example:
- balance roundrobin
- timeout connect 5s
- timeout server 3m
-- server iprep1 127.0.0.1:12345
-+ server modsec1 127.0.0.1:12345
-
- The modsecurity action is returned in a variable called txn.modsec.code. It
- contains the HTTP returned code. If the variable contains 0, the request is
- clean.
-
-- tcp-request content reject if { var(txn.modsec.code) -m int gt 0 }
-+ http-request deny if { var(txn.modsec.code) -m int gt 0 }
-
--With this rule, all the request not clean are reected.
-+With this rule, all the request not clean are rejected.
-
-
- Known bugs, limitations and TODO list
+++ /dev/null
-commit 95cf225d099dcb49eefcf4f5b648be604414ae0c
-Author: Yann Cézard <ycezard@viareport.com>
-Date: Thu Apr 25 14:30:23 2019 +0200
-
- BUG/MEDIUM: contrib/modsecurity: If host header is NULL, don't try to strdup it
-
- I discovered this bug when running OWASP regression tests against HAProxy +
- modsecurity-spoa (it's a POC to evaluate how it is working). I found out that
- modsecurity spoa will crash when the request doesn't have any Host header.
-
- See the pull request #86 on github for details.
-
- This patch must be backported to 1.9 and 1.8.
-
- (cherry picked from commit bf60f6b8033deddc86de5357d6099c7593fe44cc)
- Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
- (cherry picked from commit d988e3dddcbe1f48f3b24d1bb529fc9ecefde180)
- Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
-
-diff --git a/contrib/modsecurity/modsec_wrapper.c b/contrib/modsecurity/modsec_wrapper.c
-index 271ec15d..2f3987b4 100644
---- a/contrib/modsecurity/modsec_wrapper.c
-+++ b/contrib/modsecurity/modsec_wrapper.c
-@@ -325,7 +325,11 @@ int modsecurity_process(struct worker *worker, struct modsecurity_parameters *pa
- req->content_type = apr_table_get(req->headers_in, "Content-Type");
- req->content_encoding = apr_table_get(req->headers_in, "Content-Encoding");
- req->hostname = apr_table_get(req->headers_in, "Host");
-- req->parsed_uri.hostname = chunk_strdup(req, req->hostname, strlen(req->hostname));
-+ if (req->hostname != NULL) {
-+ req->parsed_uri.hostname = chunk_strdup(req, req->hostname, strlen(req->hostname));
-+ } else {
-+ req->parsed_uri.hostname = NULL;
-+ }
-
- lang = apr_table_get(req->headers_in, "Content-Languages");
- if (lang != NULL) {
--- /dev/null
+commit 8d09dc21dc913d1540d07d1019a51c430317eae1
+Author: Christopher Faulet <cfaulet@haproxy.com>
+Date: Tue Jun 18 09:37:00 2019 +0200
+
+ MINOR: htx: Add the function htx_change_blk_value_len()
+
+ As its name suggest, this function change the value length of a block. But it
+ also update the HTX message accordingly. It simplifies the HTX API. The function
+ htx_set_blk_value_len() is still available and must be used with caution because
+ this one does not update the HTX message. It just updates the HTX block. It
+ should be considered as an internal function. When possible,
+ htx_change_blk_value_len() should be used instead.
+
+ This function is used to fix a bug affecting the 2.0. So, this patch must be
+ backported to 2.0.
+
+ (cherry picked from commit bb0efcdd293de33607a6eba075971b49857375e2)
+ Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
+
+diff --git a/include/common/htx.h b/include/common/htx.h
+index 9631c618..7d15365a 100644
+--- a/include/common/htx.h
++++ b/include/common/htx.h
+@@ -470,7 +470,41 @@ static inline struct htx_blk *htx_get_next_blk(const struct htx *htx,
+ }
+
+ /* Changes the size of the value. It is the caller responsibility to change the
+- * value itself, make sure there is enough space and update allocated value.
++ * value itself, make sure there is enough space and update allocated
++ * value. This function updates the HTX message accordingly.
++ */
++static inline void htx_change_blk_value_len(struct htx *htx, struct htx_blk *blk, uint32_t newlen)
++{
++ enum htx_blk_type type = htx_get_blk_type(blk);
++ uint32_t oldlen, sz;
++ int32_t delta;
++
++ sz = htx_get_blksz(blk);
++ switch (type) {
++ case HTX_BLK_HDR:
++ case HTX_BLK_TLR:
++ oldlen = (blk->info >> 8) & 0xfffff;
++ blk->info = (type << 28) + (newlen << 8) + (blk->info & 0xff);
++ break;
++ default:
++ oldlen = blk->info & 0xfffffff;
++ blk->info = (type << 28) + newlen;
++ break;
++ }
++
++ /* Update HTTP message */
++ delta = (newlen - oldlen);
++ htx->data += delta;
++ if (blk->addr+sz == htx->tail_addr)
++ htx->tail_addr += delta;
++ else if (blk->addr+sz == htx->head_addr)
++ htx->head_addr += delta;
++}
++
++/* Changes the size of the value. It is the caller responsibility to change the
++ * value itself, make sure there is enough space and update allocated
++ * value. Unlike the function htx_change_blk_value_len(), this one does not
++ * update the HTX message. So it should be used with caution.
+ */
+ static inline void htx_set_blk_value_len(struct htx_blk *blk, uint32_t vlen)
+ {
--- /dev/null
+commit 41dc8432f87622145390dc1b1467a5ee14ba184c
+Author: Christopher Faulet <cfaulet@haproxy.com>
+Date: Tue Jun 18 09:49:16 2019 +0200
+
+ BUG/MEDIUM: htx: Fully update HTX message when the block value is changed
+
+ Everywhere the value length of a block is changed, calling the function
+ htx_set_blk_value_len(), the HTX message must be updated. But at many places,
+ because of the recent changes in the HTX structure, this update was only
+ partially done. tail_addr and head_addr values were not systematically updated.
+
+ In fact, the function htx_set_blk_value_len() was designed as an internal
+ function to the HTX API. And we used it from outside by convenience. But it is
+ really painfull and error prone to let the caller update the HTX message. So
+ now, we use the function htx_change_blk_value_len() wherever is possible. It
+ changes the value length of a block and updates the HTX message accordingly.
+
+ This patch must be backported to 2.0.
+
+ (cherry picked from commit 3e2638ee04407a1d9e9376f0c518f67fca7deaa4)
+ Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
+
+diff --git a/src/h2.c b/src/h2.c
+index 32c1ef16..990d602b 100644
+--- a/src/h2.c
++++ b/src/h2.c
+@@ -736,8 +736,7 @@ int h2_make_htx_request(struct http_hdr *list, struct htx *htx, unsigned int *ms
+ if (tl > fs)
+ goto fail;
+
+- htx_set_blk_value_len(blk, tl);
+- htx->data += vl+2;
++ htx_change_blk_value_len(htx, blk, tl);
+ *(char *)(htx_get_blk_ptr(htx, blk) + bs + 0) = ';';
+ *(char *)(htx_get_blk_ptr(htx, blk) + bs + 1) = ' ';
+ memcpy(htx_get_blk_ptr(htx, blk) + bs + 2, list[ck].v.ptr, vl);
+diff --git a/src/http_htx.c b/src/http_htx.c
+index 7322b337..bc26e5ba 100644
+--- a/src/http_htx.c
++++ b/src/http_htx.c
+@@ -461,10 +461,7 @@ int http_remove_header(struct htx *htx, struct http_hdr_ctx *ctx)
+ }
+ /* Update the block content and its len */
+ memmove(start, start+len, v.len-len);
+- htx_set_blk_value_len(blk, v.len-len);
+-
+- /* Update HTX msg */
+- htx->data -= len;
++ htx_change_blk_value_len(htx, blk, v.len-len);
+
+ /* Finally update the ctx */
+ ctx->value.ptr = start;
+diff --git a/src/htx.c b/src/htx.c
+index bfd136f4..81492598 100644
+--- a/src/htx.c
++++ b/src/htx.c
+@@ -406,15 +406,8 @@ void htx_truncate(struct htx *htx, uint32_t offset)
+ offset -= sz;
+ continue;
+ }
+- if (type == HTX_BLK_DATA) {
+- htx_set_blk_value_len(blk, offset);
+- htx->data -= (sz - offset);
+-
+- if (blk->addr+sz == htx->tail_addr)
+- htx->tail_addr -= offset;
+- else if (blk->addr+sz == htx->head_addr)
+- htx->head_addr -= offset;
+- }
++ if (type == HTX_BLK_DATA)
++ htx_change_blk_value_len(htx, blk, offset);
+ offset = 0;
+ }
+ while (blk)
+@@ -522,14 +515,7 @@ struct htx_blk *htx_add_data_atonce(struct htx *htx, struct ist data)
+ /* Append data and update the block itself */
+ ptr = htx_get_blk_ptr(htx, tailblk);
+ memcpy(ptr+sz, data.ptr, len);
+- htx_set_blk_value_len(tailblk, sz+len);
+-
+- /* Update HTTP message */
+- htx->data += len;
+- if (tailblk->addr+sz == htx->tail_addr)
+- htx->tail_addr += len;
+- else if (tailblk->addr+sz == htx->head_addr)
+- htx->head_addr += len;
++ htx_change_blk_value_len(htx, tailblk, sz+len);
+
+ if (data.len == len) {
+ blk = tailblk;
+@@ -988,14 +974,7 @@ size_t htx_add_data(struct htx *htx, const struct ist data)
+ /* Append data and update the block itself */
+ ptr = htx_get_blk_ptr(htx, tailblk);
+ memcpy(ptr + sz, data.ptr, len);
+- htx_set_blk_value_len(tailblk, sz + len);
+-
+- /* Update HTTP message */
+- htx->data += len;
+- if (tailblk->addr+sz == htx->tail_addr)
+- htx->tail_addr += len;
+- else if (tailblk->addr+sz == htx->head_addr)
+- htx->head_addr += len;
++ htx_change_blk_value_len(htx, tailblk, sz+len);
+
+ BUG_ON((int32_t)htx->tail_addr < 0);
+ BUG_ON((int32_t)htx->head_addr < 0);
+diff --git a/src/proto_htx.c b/src/proto_htx.c
+index 7f501366..d821e38c 100644
+--- a/src/proto_htx.c
++++ b/src/proto_htx.c
+@@ -4314,10 +4314,8 @@ static void htx_manage_client_side_cookies(struct stream *s, struct channel *req
+ hdr_end = (preserve_hdr ? del_from : hdr_beg);
+ }
+ if ((hdr_end - hdr_beg) != ctx.value.len) {
+- if (hdr_beg != hdr_end) {
+- htx_set_blk_value_len(ctx.blk, hdr_end - hdr_beg);
+- htx->data -= ctx.value.len - (hdr_end - hdr_beg);
+- }
++ if (hdr_beg != hdr_end)
++ htx_change_blk_value_len(htx, ctx.blk, hdr_end - hdr_beg);
+ else
+ http_remove_header(htx, &ctx);
+ }
+@@ -4495,8 +4493,7 @@ static void htx_manage_server_side_cookies(struct stream *s, struct channel *res
+ next += stripped_before;
+ hdr_end += stripped_before;
+
+- htx_set_blk_value_len(ctx.blk, hdr_end - hdr_beg);
+- htx->data -= ctx.value.len - (hdr_end - hdr_beg);
++ htx_change_blk_value_len(htx, ctx.blk, hdr_end - hdr_beg);
+ ctx.value.len = hdr_end - hdr_beg;
+ }
+
+++ /dev/null
-commit 86860896dc1841eb59cb95832d76a8093e8dc8c5
-Author: Christopher Faulet <cfaulet@haproxy.com>
-Date: Tue Apr 30 10:55:38 2019 +0200
-
- MINOR: examples: Use right locale for the last changelog date in haproxy.spec
-
- The last changelog entry was stamped with the wrong locale.
-
- No need to backport, it is specific to 1.8
-
-diff --git a/examples/haproxy.spec b/examples/haproxy.spec
-index f3e0c7e0..fe5215d7 100644
---- a/examples/haproxy.spec
-+++ b/examples/haproxy.spec
-@@ -74,7 +74,7 @@ fi
- %attr(0755,root,root) %config %{_sysconfdir}/rc.d/init.d/%{name}
-
- %changelog
--* jeu. avril 25 2019 Christopher Faulet <cfaulet@haproxy.com>
-+* Thu Apr 25 2019 Christopher Faulet <cfaulet@haproxy.com>
- - updated to 1.8.20
-
- * Mon Feb 11 2019 Willy Tarreau <w@1wt.eu>
+++ /dev/null
-commit 83af1f6b65806982640679823228976deebf5202
-Author: Willy Tarreau <w@1wt.eu>
-Date: Tue Apr 30 11:43:43 2019 +0200
-
- BUG/MAJOR: map/acl: real fix segfault during show map/acl on CLI
-
- A previous commit 8d85aa44d ("BUG/MAJOR: map: fix segfault during
- 'show map/acl' on cli.") was provided to address a concurrency issue
- between "show acl" and "clear acl" on the CLI. Sadly the code placed
- there was copy-pasted without changing the element type (which was
- struct stream in the original code) and not tested since the crash
- is still present.
-
- The reproducer is simple : load a large ACL file (e.g. geolocation
- addresses), issue "show acl #0" in loops in one window and issue a
- "clear acl #0" in the other one, haproxy crashes.
-
- This fix was also tested with threads enabled and looks good since
- the locking seems to work correctly in these areas though. It will
- have to be backported as far as 1.6 since the commit above went
- that far as well...
-
- (cherry picked from commit 49ee3b2f9a9e5d0b8d394938df527aa645ce72b4)
- Signed-off-by: Willy Tarreau <w@1wt.eu>
- (cherry picked from commit ac4be10f62ef72962d9cf0e6f2619e1e1c370d62)
- Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
-
-diff --git a/src/pattern.c b/src/pattern.c
-index 7eea9d96..21639569 100644
---- a/src/pattern.c
-+++ b/src/pattern.c
-@@ -1651,7 +1651,7 @@ int pat_ref_delete_by_id(struct pat_ref *ref, struct pat_ref_elt *refelt)
- LIST_DEL(&bref->users);
- LIST_INIT(&bref->users);
- if (elt->list.n != &ref->head)
-- LIST_ADDQ(&LIST_ELEM(elt->list.n, struct stream *, list)->back_refs, &bref->users);
-+ LIST_ADDQ(&LIST_ELEM(elt->list.n, typeof(elt), list)->back_refs, &bref->users);
- bref->ref = elt->list.n;
- }
- list_for_each_entry(expr, &ref->pat, list)
-@@ -1691,7 +1691,7 @@ int pat_ref_delete(struct pat_ref *ref, const char *key)
- LIST_DEL(&bref->users);
- LIST_INIT(&bref->users);
- if (elt->list.n != &ref->head)
-- LIST_ADDQ(&LIST_ELEM(elt->list.n, struct stream *, list)->back_refs, &bref->users);
-+ LIST_ADDQ(&LIST_ELEM(elt->list.n, typeof(elt), list)->back_refs, &bref->users);
- bref->ref = elt->list.n;
- }
- list_for_each_entry(expr, &ref->pat, list)
-@@ -2086,7 +2086,7 @@ void pat_ref_reload(struct pat_ref *ref, struct pat_ref *replace)
- LIST_DEL(&bref->users);
- LIST_INIT(&bref->users);
- if (elt->list.n != &ref->head)
-- LIST_ADDQ(&LIST_ELEM(elt->list.n, struct stream *, list)->back_refs, &bref->users);
-+ LIST_ADDQ(&LIST_ELEM(elt->list.n, typeof(elt), list)->back_refs, &bref->users);
- bref->ref = elt->list.n;
- }
- LIST_DEL(&elt->list);
-@@ -2175,7 +2175,7 @@ void pat_ref_prune(struct pat_ref *ref)
- LIST_DEL(&bref->users);
- LIST_INIT(&bref->users);
- if (elt->list.n != &ref->head)
-- LIST_ADDQ(&LIST_ELEM(elt->list.n, struct stream *, list)->back_refs, &bref->users);
-+ LIST_ADDQ(&LIST_ELEM(elt->list.n, typeof(elt), list)->back_refs, &bref->users);
- bref->ref = elt->list.n;
- }
- LIST_DEL(&elt->list);
--- /dev/null
+commit 3d574a587dc3704e93bcd29b16d54d96069667b4
+Author: Christopher Faulet <cfaulet@haproxy.com>
+Date: Tue Jun 18 12:22:38 2019 +0200
+
+ BUG/MEDIUM: mux-h2: Reset padlen when several frames are demux
+
+ In the function h2_process_demux(), if several frames are parsed, the padding
+ length must be reset between each frame. Otherwise we may wrongly think a frame
+ has a padding block because the previous one was padded.
+
+ This patch must be backported to 2.0 and 1.9.
+
+ (cherry picked from commit dd2a5620d594523cd515a629e105a9a2b64345bb)
+ Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
+
+diff --git a/src/mux_h2.c b/src/mux_h2.c
+index d02168df..c06d5d68 100644
+--- a/src/mux_h2.c
++++ b/src/mux_h2.c
+@@ -2316,6 +2316,7 @@ static void h2_process_demux(struct h2c *h2c)
+ break;
+ }
+
++ padlen = 0;
+ if (h2_ft_bit(hdr.ft) & H2_FT_PADDED_MASK && hdr.ff & H2_F_PADDED) {
+ /* If the frame is padded (HEADERS, PUSH_PROMISE or DATA),
+ * we read the pad length and drop it from the remaining
+++ /dev/null
-commit 7bd7a8d2b8889f604b807c21190d2e70328d6674
-Author: Christopher Faulet <cfaulet@haproxy.com>
-Date: Tue Apr 30 12:17:13 2019 +0200
-
- BUG/MEDIUM: listener: Fix how unlimited number of consecutive accepts is handled
-
- There is a bug when global.tune.maxaccept is set to -1 (no limit). It is pretty
- visible with one process (nbproc sets to 1). The functions listener_accept() and
- accept_queue_process() don't expect to handle negative maxaccept values. So
- instead of accepting incoming connections without any limit, none are never
- accepted and HAProxy loop infinitly in the scheduler.
-
- When there are 2 or more processes, the bug is a bit more subtile. The limit for
- a listener is set to 1. So only one connection is accepted at a time by a given
- listener. This happens because the listener's maxaccept value is an unsigned
- integer. In check_config_validity(), it is first set to UINT_MAX (-1 casted in
- an unsigned integer), and then some calculations on it leads to an integer
- overflow.
-
- To fix the bug, the listener's maxaccept value is now a signed integer. So, if a
- negative value is set for global.tune.maxaccept, we keep it untouched for the
- listener and no calculation is made on it. Then, in the listener code, this
- signed value is casted to a unsigned one. It simplifies all tests instead of
- dealing with negative values. So, it limits the number of connections accepted
- at a time to UINT_MAX at most. But, honestly, it not an issue.
-
- This patch must be backported to 1.9 and 1.8.
-
- (cherry picked from commit 102854cbbaa4d22466dddec9035d411db244082f)
- Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
- (cherry picked from commit bca4fb2d9d7f2966d9f8270fa1796fdc0dfc866d)
- Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
-
-diff --git a/include/types/listener.h b/include/types/listener.h
-index ea2eadb5..16ef6d7a 100644
---- a/include/types/listener.h
-+++ b/include/types/listener.h
-@@ -196,7 +196,7 @@ struct listener {
- int nbconn; /* current number of connections on this listener */
- int maxconn; /* maximum connections allowed on this listener */
- unsigned int backlog; /* if set, listen backlog */
-- unsigned int maxaccept; /* if set, max number of connections accepted at once */
-+ int maxaccept; /* if set, max number of connections accepted at once (-1 when disabled) */
- struct list proto_list; /* list in the protocol header */
- int (*accept)(struct listener *l, int fd, struct sockaddr_storage *addr); /* upper layer's accept() */
- enum obj_type *default_target; /* default target to use for accepted sessions or NULL */
-diff --git a/src/listener.c b/src/listener.c
-index 821c931a..74990c45 100644
---- a/src/listener.c
-+++ b/src/listener.c
-@@ -406,7 +406,7 @@ void listener_accept(int fd)
- {
- struct listener *l = fdtab[fd].owner;
- struct proxy *p;
-- int max_accept;
-+ unsigned int max_accept;
- int next_conn = 0;
- int next_feconn = 0;
- int next_actconn = 0;
-@@ -420,6 +420,10 @@ void listener_accept(int fd)
- if (!l)
- return;
- p = l->bind_conf->frontend;
-+
-+ /* if l->maxaccept is -1, then max_accept is UINT_MAX. It is not really
-+ * illimited, but it is probably enough.
-+ */
- max_accept = l->maxaccept ? l->maxaccept : 1;
-
- if (!(l->options & LI_O_UNLIMITED) && global.sps_lim) {
-@@ -480,7 +484,7 @@ void listener_accept(int fd)
- * worst case. If we fail due to system limits or temporary resource
- * shortage, we try again 100ms later in the worst case.
- */
-- for (; max_accept-- > 0; next_conn = next_feconn = next_actconn = 0) {
-+ for (; max_accept; next_conn = next_feconn = next_actconn = 0, max_accept--) {
- struct sockaddr_storage addr;
- socklen_t laddr = sizeof(addr);
- unsigned int count;
--- /dev/null
+commit 4fb65f421b4d650711e5d8b9dbcbf4bf589d26cc
+Author: Christopher Faulet <cfaulet@haproxy.com>
+Date: Wed Jun 19 09:25:58 2019 +0200
+
+ BUG/MEDIUM: mux-h2: Remove the padding length when a DATA frame size is checked
+
+ When a DATA frame is processed for a message with a content-length, we first
+ take care to not have a frame size that exceeds the remaining to
+ read. Otherwise, an error is triggered. But we must remove the padding length
+ from the frame size because the padding is not included in the announced
+ content-length.
+
+ This patch must be backported to 2.0 and 1.9.
+
+ (cherry picked from commit 4f09ec812adbd9336cddc054660a7fb5cd54b459)
+ Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
+
+diff --git a/src/mux_h2.c b/src/mux_h2.c
+index c06d5d68..5bb85181 100644
+--- a/src/mux_h2.c
++++ b/src/mux_h2.c
+@@ -2177,7 +2177,7 @@ static int h2c_frt_handle_data(struct h2c *h2c, struct h2s *h2s)
+ goto strm_err;
+ }
+
+- if ((h2s->flags & H2_SF_DATA_CLEN) && h2c->dfl > h2s->body_len) {
++ if ((h2s->flags & H2_SF_DATA_CLEN) && (h2c->dfl - h2c->dpl) > h2s->body_len) {
+ /* RFC7540#8.1.2 */
+ error = H2_ERR_PROTOCOL_ERROR;
+ goto strm_err;
--- /dev/null
+commit 3f0b1de623d09f8668db34c1be696f7245de7d50
+Author: Christopher Faulet <cfaulet@haproxy.com>
+Date: Wed Jun 19 10:50:38 2019 +0200
+
+ BUG/MEDIUM: lb_fwlc: Don't test the server's lb_tree from outside the lock
+
+ In the function fwlc_srv_reposition(), the server's lb_tree is tested from
+ outside the lock. So it is possible to remove it after the test and then call
+ eb32_insert() in fwlc_queue_srv() with a NULL root pointer, which is
+ invalid. Moving the test in the scope of the lock fixes the bug.
+
+ This issue was reported on Github, issue #126.
+
+ This patch must be backported to 2.0, 1.9 and 1.8.
+
+ (cherry picked from commit 1ae2a8878170ded922f2c4d32b6704af7689bbfd)
+ Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
+
+diff --git a/src/lb_fwlc.c b/src/lb_fwlc.c
+index 174dc67e..5fa81739 100644
+--- a/src/lb_fwlc.c
++++ b/src/lb_fwlc.c
+@@ -66,12 +66,11 @@ static inline void fwlc_queue_srv(struct server *s)
+ */
+ static void fwlc_srv_reposition(struct server *s)
+ {
+- if (!s->lb_tree)
+- return;
+-
+ HA_SPIN_LOCK(LBPRM_LOCK, &s->proxy->lbprm.lock);
+- fwlc_dequeue_srv(s);
+- fwlc_queue_srv(s);
++ if (s->lb_tree) {
++ fwlc_dequeue_srv(s);
++ fwlc_queue_srv(s);
++ }
+ HA_SPIN_UNLOCK(LBPRM_LOCK, &s->proxy->lbprm.lock);
+ }
+
+++ /dev/null
-commit 6e580b6e744011e87c337ebe2c082acfd5ca835a
-Author: Christopher Faulet <cfaulet@haproxy.com>
-Date: Tue Apr 30 14:03:56 2019 +0200
-
- MINOR: config: Test validity of tune.maxaccept during the config parsing
-
- Only -1 and positive integers from 0 to INT_MAX are accepted. An error is
- triggered during the config parsing for any other values.
-
- This patch may be backported to all supported versions.
-
- (cherry picked from commit 6b02ab87348090efec73b1dd24f414239669f279)
- Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
- (cherry picked from commit 2bbc40f8bc9a52ba0d03b25270ac0129cca29bba)
- Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
-
-diff --git a/src/cfgparse.c b/src/cfgparse.c
-index c178538b..8e325416 100644
---- a/src/cfgparse.c
-+++ b/src/cfgparse.c
-@@ -789,6 +789,8 @@ int cfg_parse_global(const char *file, int linenum, char **args, int kwm)
- global.tune.maxpollevents = atol(args[1]);
- }
- else if (!strcmp(args[0], "tune.maxaccept")) {
-+ long max;
-+
- if (alertif_too_many_args(1, file, linenum, args, &err_code))
- goto out;
- if (global.tune.maxaccept != 0) {
-@@ -801,7 +803,13 @@ int cfg_parse_global(const char *file, int linenum, char **args, int kwm)
- err_code |= ERR_ALERT | ERR_FATAL;
- goto out;
- }
-- global.tune.maxaccept = atol(args[1]);
-+ max = atol(args[1]);
-+ if (/*max < -1 || */max > INT_MAX) {
-+ ha_alert("parsing [%s:%d] : '%s' expects -1 or an integer from 0 to INT_MAX.\n", file, linenum, args[0]);
-+ err_code |= ERR_ALERT | ERR_FATAL;
-+ goto out;
-+ }
-+ global.tune.maxaccept = max;
- }
- else if (!strcmp(args[0], "tune.chksize")) {
- if (alertif_too_many_args(1, file, linenum, args, &err_code))
--- /dev/null
+commit 9eae8935663bc0b27c23018e8cc24ae9a3e31732
+Author: Frédéric Lécaille <flecaille@haproxy.com>
+Date: Thu Jun 20 09:31:04 2019 +0200
+
+ BUG/MAJOR: sample: Wrong stick-table name parsing in "if/unless" ACL condition.
+
+ This bug was introduced by 1b8e68e commit which supposed the stick-table was always
+ stored in struct arg at parsing time. This is never the case with the usage of
+ "if/unless" conditions in stick-table declared as backends. In this case, this is
+ the name of the proxy which must be considered as the stick-table name.
+
+ This must be backported to 2.0.
+
+ (cherry picked from commit 9417f4534ad742eda35c4cc3d1ccb390f75ea4b1)
+ Signed-off-by: Willy Tarreau <w@1wt.eu>
+
+diff --git a/src/sample.c b/src/sample.c
+index 67f59e84..77ec9b1e 100644
+--- a/src/sample.c
++++ b/src/sample.c
+@@ -1245,15 +1245,11 @@ int smp_resolve_args(struct proxy *p)
+ break;
+
+ case ARGT_TAB:
+- if (!arg->data.str.data) {
+- ha_alert("parsing [%s:%d] : missing table name in arg %d of %s%s%s%s '%s' %s proxy '%s'.\n",
+- cur->file, cur->line,
+- cur->arg_pos + 1, conv_pre, conv_ctx, conv_pos, ctx, cur->kw, where, p->id);
+- cfgerr++;
+- continue;
+- }
++ if (arg->data.str.data)
++ stktname = arg->data.str.area;
++ else
++ stktname = px->id;
+
+- stktname = arg->data.str.area;
+ t = stktable_find_by_name(stktname);
+ if (!t) {
+ ha_alert("parsing [%s:%d] : unable to find table '%s' referenced in arg %d of %s%s%s%s '%s' %s proxy '%s'.\n",
+++ /dev/null
-commit c6e03c1495fa51f9a98ed0bbe3230313c7c7201c
-Author: Christopher Faulet <cfaulet@haproxy.com>
-Date: Tue Apr 30 14:08:41 2019 +0200
-
- CLEANUP: config: Don't alter listener->maxaccept when nbproc is set to 1
-
- This patch only removes a useless calculation on listener->maxaccept when nbproc
- is set to 1. Indeed, the following formula has no effet in such case:
-
- listener->maxaccept = (listener->maxaccept + nbproc - 1) / nbproc;
-
- This patch may be backported as far as 1.5.
-
- (cherry picked from commit 02f3cf19ed803d20aff9294ce7cb732489951ff5)
- Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
- (cherry picked from commit 14203e3cf9404e57de5e274b453f0fe4f2174924)
- Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
-
-diff --git a/src/cfgparse.c b/src/cfgparse.c
-index 8e325416..3f6ea352 100644
---- a/src/cfgparse.c
-+++ b/src/cfgparse.c
-@@ -9018,9 +9018,8 @@ out_uri_auth_compat:
- * is bound to. Rememeber that maxaccept = -1 must be kept as it is
- * used to disable the limit.
- */
-- if (listener->maxaccept > 0) {
-- if (nbproc > 1)
-- listener->maxaccept = (listener->maxaccept + 1) / 2;
-+ if (listener->maxaccept > 0 && nbproc > 1) {
-+ listener->maxaccept = (listener->maxaccept + 1) / 2;
- listener->maxaccept = (listener->maxaccept + nbproc - 1) / nbproc;
- }
-
+++ /dev/null
-commit f95cf6ad70565ee2322cf23bc519b7bb0b3831b2
-Author: Olivier Houchard <ohouchard@haproxy.com>
-Date: Tue Apr 30 13:38:02 2019 +0200
-
- MINOR: threads: Implement HA_ATOMIC_LOAD().
-
- The same way we have HA_ATOMIC_STORE(), implement HA_ATOMIC_LOAD().
-
- This should be backported to 1.8 and 1.9, as we need it for a bug fix
- in port ranges.
-
- (cherry picked from commit 9ce62b5498b27fbf4217d9c25779d5b2ceca23f2)
- Signed-off-by: Olivier Houchard <cognet@ci0.org>
- (cherry picked from commit 358c979611370fa2bc3b8e47ed50a325cf9126cf)
- Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
-
-diff --git a/include/common/hathreads.h b/include/common/hathreads.h
-index 8134839a..11d7cab6 100644
---- a/include/common/hathreads.h
-+++ b/include/common/hathreads.h
-@@ -62,6 +62,7 @@ enum { tid = 0 };
- *(val) = new; \
- __old_xchg; \
- })
-+#define HA_ATOMIC_LOAD(val) *(val)
- #define HA_ATOMIC_STORE(val, new) ({*(val) = new;})
- #define HA_ATOMIC_UPDATE_MAX(val, new) \
- ({ \
-@@ -203,6 +204,16 @@ static inline unsigned long thread_isolated()
- } while (!__sync_bool_compare_and_swap(__val_xchg, __old_xchg, __new_xchg)); \
- __old_xchg; \
- })
-+
-+#define HA_ATOMIC_LOAD(val) \
-+ ({ \
-+ typeof(*(val)) ret; \
-+ __sync_synchronize(); \
-+ ret = *(volatile typeof(val))val; \
-+ __sync_synchronize(); \
-+ ret; \
-+ })
-+
- #define HA_ATOMIC_STORE(val, new) \
- ({ \
- typeof((val)) __val_store = (val); \
-@@ -221,6 +232,8 @@ static inline unsigned long thread_isolated()
- #define HA_ATOMIC_OR(val, flags) __atomic_or_fetch(val, flags, __ATOMIC_SEQ_CST)
- #define HA_ATOMIC_XCHG(val, new) __atomic_exchange_n(val, new, __ATOMIC_SEQ_CST)
- #define HA_ATOMIC_STORE(val, new) __atomic_store_n(val, new, __ATOMIC_SEQ_CST)
-+#define HA_ATOMIC_LOAD(val) __atomic_load_n(val, __ATOMIC_SEQ_CST)
-+
- #endif
-
- #define HA_ATOMIC_UPDATE_MAX(val, new) \
--- /dev/null
+--- a/Makefile
++++ b/Makefile
+@@ -327,6 +327,15 @@ ifeq ($(TARGET),linux-glibc)
+ USE_GETADDRINFO)
+ endif
+
++# For linux >= 2.6.28 and uclibc
++ifeq ($(TARGET),linux-uclibc)
++ set_target_defaults = $(call default_opts, \
++ USE_POLL USE_TPROXY USE_DL USE_RT USE_NETFILTER \
++ USE_CPU_AFFINITY USE_THREAD USE_EPOLL USE_FUTEX USE_LINUX_TPROXY \
++ USE_ACCEPT4 USE_LINUX_SPLICE USE_PRCTL USE_THREAD_DUMP USE_NS USE_TFO \
++ USE_GETADDRINFO)
++endif
++
+ # Solaris 8 and above
+ ifeq ($(TARGET),solaris)
+ # We also enable getaddrinfo() which works since solaris 8.
+++ /dev/null
-commit 31470e2ba2aabb4c6340fbc15cb5486ceb8c69c8
-Author: Olivier Houchard <ohouchard@haproxy.com>
-Date: Mon Apr 29 18:52:06 2019 +0200
-
- BUG/MEDIUM: port_range: Make the ring buffer lock-free.
-
- Port range uses a ring buffer, and unfortunately, when making haproxy
- multithreaded, it's been overlooked, and the ring buffer is not thread-safe.
- When specifying a source range, 2 or more threads could pick the same
- port, and of course only one of them could use the port, the others would
- always fail the connection.
- To fix this, make it a lock-free ring buffer. This is easier than usual
- because we know the ring buffer can never be full.
-
- This should be backported to 1.8 and 1.9.
-
- (cherry picked from commit 07425de71777b688e77a9c70a7088c13e66e41e9)
- Signed-off-by: Olivier Houchard <cognet@ci0.org>
- (cherry picked from commit bffb51147a4a5939e344b3c838628f9a944febef)
- Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
-
-diff --git a/include/proto/port_range.h b/include/proto/port_range.h
-index 8c63faca..f7e3f1d5 100644
---- a/include/proto/port_range.h
-+++ b/include/proto/port_range.h
-@@ -24,18 +24,22 @@
-
- #include <types/port_range.h>
-
-+#define GET_NEXT_OFF(range, off) ((off) == (range)->size - 1 ? 0 : (off) + 1)
-+
- /* return an available port from range <range>, or zero if none is left */
- static inline int port_range_alloc_port(struct port_range *range)
- {
- int ret;
-+ int get;
-+ int put;
-
-- if (!range->avail)
-- return 0;
-- ret = range->ports[range->get];
-- range->get++;
-- if (range->get >= range->size)
-- range->get = 0;
-- range->avail--;
-+ get = HA_ATOMIC_LOAD(&range->get);
-+ do {
-+ put = HA_ATOMIC_LOAD(&range->put_t);
-+ if (unlikely(put == get))
-+ return 0;
-+ ret = range->ports[get];
-+ } while (!(HA_ATOMIC_CAS(&range->get, &get, GET_NEXT_OFF(range, get))));
- return ret;
- }
-
-@@ -45,14 +49,28 @@ static inline int port_range_alloc_port(struct port_range *range)
- */
- static inline void port_range_release_port(struct port_range *range, int port)
- {
-+ int put;
-+
- if (!port || !range)
- return;
-
-- range->ports[range->put] = port;
-- range->avail++;
-- range->put++;
-- if (range->put >= range->size)
-- range->put = 0;
-+ put = range->put_h;
-+ /* put_h is reserved for producers, so that they can each get a
-+ * free slot, put_t is what is used by consumers to know if there's
-+ * elements available or not
-+ */
-+ /* First reserve or slot, we know the ring buffer can't be full,
-+ * as we will only ever release port we allocated before
-+ */
-+ while (!(HA_ATOMIC_CAS(&range->put_h, &put, GET_NEXT_OFF(range, put))));
-+ HA_ATOMIC_STORE(&range->ports[put], port);
-+ /* Wait until all the threads that got a slot before us are done */
-+ while ((volatile int)range->put_t != put)
-+ __ha_compiler_barrier();
-+ /* Let the world know we're done, and any potential consumer they
-+ * can use that port.
-+ */
-+ HA_ATOMIC_STORE(&range->put_t, GET_NEXT_OFF(range, put));
- }
-
- /* return a new initialized port range of N ports. The ports are not
-@@ -62,8 +80,10 @@ static inline struct port_range *port_range_alloc_range(int n)
- {
- struct port_range *ret;
- ret = calloc(1, sizeof(struct port_range) +
-- n * sizeof(((struct port_range *)0)->ports[0]));
-- ret->size = ret->avail = n;
-+ (n + 1) * sizeof(((struct port_range *)0)->ports[0]));
-+ ret->size = n + 1;
-+ /* Start at the first free element */
-+ ret->put_h = ret->put_t = n;
- return ret;
- }
-
-diff --git a/include/types/port_range.h b/include/types/port_range.h
-index 1d010f77..33455d2d 100644
---- a/include/types/port_range.h
-+++ b/include/types/port_range.h
-@@ -25,8 +25,7 @@
- #include <netinet/in.h>
-
- struct port_range {
-- int size, get, put; /* range size, and get/put positions */
-- int avail; /* number of available ports left */
-+ int size, get, put_h, put_t; /* range size, and get/put positions */
- uint16_t ports[0]; /* array of <size> ports, in host byte order */
- };
-
+++ /dev/null
---- a/src/ssl_sock.c
-+++ b/src/ssl_sock.c
-@@ -39,6 +39,7 @@
- #include <netdb.h>
- #include <netinet/tcp.h>
-
-+#include <openssl/bn.h>
- #include <openssl/crypto.h>
- #include <openssl/ssl.h>
- #include <openssl/x509.h>
-@@ -60,6 +61,17 @@
- #include <openssl/async.h>
- #endif
-
-+#ifndef OPENSSL_VERSION
-+#define OPENSSL_VERSION SSLEAY_VERSION
-+#define OpenSSL_version(x) SSLeay_version(x)
-+#define OpenSSL_version_num SSLeay
-+#endif
-+
-+#if OPENSSL_VERSION_NUMBER < 0x10100000L
-+#define X509_getm_notBefore X509_get_notBefore
-+#define X509_getm_notAfter X509_get_notAfter
-+#endif
-+
- #include <import/lru.h>
- #include <import/xxhash.h>
-
-@@ -217,7 +229,7 @@ static struct {
- .capture_cipherlist = 0,
- };
-
--#ifdef USE_THREAD
-+#if defined(USE_THREAD) && (OPENSSL_VERSION_NUMBER < 0x10100000L)
-
- static HA_RWLOCK_T *ssl_rwlocks;
-
-@@ -1716,8 +1728,8 @@ ssl_sock_do_create_cert(const char *servername, struct bind_conf *bind_conf, SSL
- ASN1_INTEGER_set(X509_get_serialNumber(newcrt), HA_ATOMIC_ADD(&ssl_ctx_serial, 1));
-
- /* Set duration for the certificate */
-- if (!X509_gmtime_adj(X509_get_notBefore(newcrt), (long)-60*60*24) ||
-- !X509_gmtime_adj(X509_get_notAfter(newcrt),(long)60*60*24*365))
-+ if (!X509_gmtime_adj(X509_getm_notBefore(newcrt), (long)-60*60*24) ||
-+ !X509_gmtime_adj(X509_getm_notAfter(newcrt),(long)60*60*24*365))
- goto mkcert_error;
-
- /* set public key in the certificate */
-@@ -6299,7 +6311,7 @@ smp_fetch_ssl_x_notafter(const struct arg *args, struct sample *smp, const char
- goto out;
-
- smp_trash = get_trash_chunk();
-- if (ssl_sock_get_time(X509_get_notAfter(crt), smp_trash) <= 0)
-+ if (ssl_sock_get_time(X509_getm_notAfter(crt), smp_trash) <= 0)
- goto out;
-
- smp->data.u.str = *smp_trash;
-@@ -6399,7 +6411,7 @@ smp_fetch_ssl_x_notbefore(const struct arg *args, struct sample *smp, const char
- goto out;
-
- smp_trash = get_trash_chunk();
-- if (ssl_sock_get_time(X509_get_notBefore(crt), smp_trash) <= 0)
-+ if (ssl_sock_get_time(X509_getm_notBefore(crt), smp_trash) <= 0)
- goto out;
-
- smp->data.u.str = *smp_trash;
-@@ -8976,10 +8988,12 @@ static void __ssl_sock_init(void)
- #endif
-
- xprt_register(XPRT_SSL, &ssl_sock);
-+#if OPENSSL_VERSION_NUMBER < 0x10100000L
- SSL_library_init();
-+#endif
- cm = SSL_COMP_get_compression_methods();
- sk_SSL_COMP_zero(cm);
--#ifdef USE_THREAD
-+#if defined(USE_THREAD) && (OPENSSL_VERSION_NUMBER < 0x10100000L)
- ssl_locking_init();
- #endif
- #if (OPENSSL_VERSION_NUMBER >= 0x1000200fL && !defined OPENSSL_NO_TLSEXT && !defined OPENSSL_IS_BORINGSSL && !defined LIBRESSL_VERSION_NUMBER)
-@@ -9008,8 +9022,8 @@ static void __ssl_sock_init(void)
- #else /* OPENSSL_IS_BORINGSSL */
- OPENSSL_VERSION_TEXT
- "\nRunning on OpenSSL version : %s%s",
-- SSLeay_version(SSLEAY_VERSION),
-- ((OPENSSL_VERSION_NUMBER ^ SSLeay()) >> 8) ? " (VERSIONS DIFFER!)" : "");
-+ OpenSSL_version(OPENSSL_VERSION),
-+ ((OPENSSL_VERSION_NUMBER ^ OpenSSL_version_num()) >> 8) ? " (VERSIONS DIFFER!)" : "");
- #endif
- memprintf(&ptr, "%s\nOpenSSL library supports TLS extensions : "
- #if OPENSSL_VERSION_NUMBER < 0x00907000L
-@@ -9100,12 +9114,14 @@ static void __ssl_sock_deinit(void)
- }
- #endif
-
-+#if OPENSSL_VERSION_NUMBER < 0x10100000L
- ERR_remove_state(0);
- ERR_free_strings();
-
- EVP_cleanup();
-+#endif
-
--#if OPENSSL_VERSION_NUMBER >= 0x00907000L
-+#if OPENSSL_VERSION_NUMBER >= 0x00907000L && OPENSSL_VERSION_NUMBER < 0x10100000L
- CRYPTO_cleanup_all_ex_data();
- #endif
- }