- Add new patches (see https://www.haproxy.org/bugs/bugs-1.8.8.html) - Raise patch-level to 02 Signed-off-by: Christian Lachner <gladiac@gmail.com>lilik-openwrt-22.03
@ -0,0 +1,26 @@ | |||
commit 6c9efc8219e35f4eb17e94b364f4c371cfb56cca | |||
Author: Aurélien Nephtali <aurelien.nephtali@corp.ovh.com> | |||
Date: Thu Apr 19 16:56:07 2018 +0200 | |||
BUG/MINOR: pattern: Add a missing HA_SPIN_INIT() in pat_ref_newid() | |||
pat_ref_newid() is lacking a spinlock init. It was probably forgotten | |||
in b5997f740b ("MAJOR: threads/map: Make acls/maps thread safe"). | |||
Signed-off-by: Aurélien Nephtali <aurelien.nephtali@corp.ovh.com> | |||
(cherry picked from commit 564d15a71ecb3ae3372767866335cfbc068c4b48) | |||
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com> | |||
diff --git a/src/pattern.c b/src/pattern.c | |||
index fe672f12..2eb82650 100644 | |||
--- a/src/pattern.c | |||
+++ b/src/pattern.c | |||
@@ -1906,7 +1906,7 @@ struct pat_ref *pat_ref_newid(int unique_id, const char *display, unsigned int f | |||
ref->unique_id = unique_id; | |||
LIST_INIT(&ref->head); | |||
LIST_INIT(&ref->pat); | |||
- | |||
+ HA_SPIN_INIT(&ref->lock); | |||
LIST_ADDQ(&pattern_reference, &ref->list); | |||
return ref; |
@ -0,0 +1,87 @@ | |||
commit e0f6d4a4e8696140d1fcff812fb287d534d702e9 | |||
Author: Tim Duesterhus <tim@bastelstu.be> | |||
Date: Tue Apr 24 19:20:43 2018 +0200 | |||
BUG/MAJOR: channel: Fix crash when trying to read from a closed socket | |||
When haproxy is compiled using GCC <= 3.x or >= 5.x the `unlikely` | |||
macro performs a comparison with zero: `(x) != 0`, thus returning | |||
either 0 or 1. | |||
In `int co_getline_nc()` this macro was accidentally applied to | |||
the variable `retcode` itself, instead of the result of the | |||
comparison `retcode <= 0`. As a result any negative `retcode` | |||
is converted to `1` for purposes of the comparison. | |||
Thus never taking the branch (and exiting the function) for | |||
negative values. | |||
This in turn leads to reads of uninitialized memory in the for-loop | |||
below: | |||
==12141== Conditional jump or move depends on uninitialised value(s) | |||
==12141== at 0x4EB6B4: co_getline_nc (channel.c:346) | |||
==12141== by 0x421CA4: hlua_socket_receive_yield (hlua.c:1713) | |||
==12141== by 0x421F6F: hlua_socket_receive (hlua.c:1896) | |||
==12141== by 0x529B08F: ??? (in /usr/lib/x86_64-linux-gnu/liblua5.3.so.0.0.0) | |||
==12141== by 0x52A7EFC: ??? (in /usr/lib/x86_64-linux-gnu/liblua5.3.so.0.0.0) | |||
==12141== by 0x529B497: ??? (in /usr/lib/x86_64-linux-gnu/liblua5.3.so.0.0.0) | |||
==12141== by 0x529711A: lua_pcallk (in /usr/lib/x86_64-linux-gnu/liblua5.3.so.0.0.0) | |||
==12141== by 0x52ABDF0: ??? (in /usr/lib/x86_64-linux-gnu/liblua5.3.so.0.0.0) | |||
==12141== by 0x529B08F: ??? (in /usr/lib/x86_64-linux-gnu/liblua5.3.so.0.0.0) | |||
==12141== by 0x52A7EFC: ??? (in /usr/lib/x86_64-linux-gnu/liblua5.3.so.0.0.0) | |||
==12141== by 0x529A9F1: ??? (in /usr/lib/x86_64-linux-gnu/liblua5.3.so.0.0.0) | |||
==12141== by 0x529B523: lua_resume (in /usr/lib/x86_64-linux-gnu/liblua5.3.so.0.0.0) | |||
==12141== | |||
==12141== Use of uninitialised value of size 8 | |||
==12141== at 0x4EB6B9: co_getline_nc (channel.c:346) | |||
==12141== by 0x421CA4: hlua_socket_receive_yield (hlua.c:1713) | |||
==12141== by 0x421F6F: hlua_socket_receive (hlua.c:1896) | |||
==12141== by 0x529B08F: ??? (in /usr/lib/x86_64-linux-gnu/liblua5.3.so.0.0.0) | |||
==12141== by 0x52A7EFC: ??? (in /usr/lib/x86_64-linux-gnu/liblua5.3.so.0.0.0) | |||
==12141== by 0x529B497: ??? (in /usr/lib/x86_64-linux-gnu/liblua5.3.so.0.0.0) | |||
==12141== by 0x529711A: lua_pcallk (in /usr/lib/x86_64-linux-gnu/liblua5.3.so.0.0.0) | |||
==12141== by 0x52ABDF0: ??? (in /usr/lib/x86_64-linux-gnu/liblua5.3.so.0.0.0) | |||
==12141== by 0x529B08F: ??? (in /usr/lib/x86_64-linux-gnu/liblua5.3.so.0.0.0) | |||
==12141== by 0x52A7EFC: ??? (in /usr/lib/x86_64-linux-gnu/liblua5.3.so.0.0.0) | |||
==12141== by 0x529A9F1: ??? (in /usr/lib/x86_64-linux-gnu/liblua5.3.so.0.0.0) | |||
==12141== by 0x529B523: lua_resume (in /usr/lib/x86_64-linux-gnu/liblua5.3.so.0.0.0) | |||
==12141== | |||
==12141== Invalid read of size 1 | |||
==12141== at 0x4EB6B9: co_getline_nc (channel.c:346) | |||
==12141== by 0x421CA4: hlua_socket_receive_yield (hlua.c:1713) | |||
==12141== by 0x421F6F: hlua_socket_receive (hlua.c:1896) | |||
==12141== by 0x529B08F: ??? (in /usr/lib/x86_64-linux-gnu/liblua5.3.so.0.0.0) | |||
==12141== by 0x52A7EFC: ??? (in /usr/lib/x86_64-linux-gnu/liblua5.3.so.0.0.0) | |||
==12141== by 0x529B497: ??? (in /usr/lib/x86_64-linux-gnu/liblua5.3.so.0.0.0) | |||
==12141== by 0x529711A: lua_pcallk (in /usr/lib/x86_64-linux-gnu/liblua5.3.so.0.0.0) | |||
==12141== by 0x52ABDF0: ??? (in /usr/lib/x86_64-linux-gnu/liblua5.3.so.0.0.0) | |||
==12141== by 0x529B08F: ??? (in /usr/lib/x86_64-linux-gnu/liblua5.3.so.0.0.0) | |||
==12141== by 0x52A7EFC: ??? (in /usr/lib/x86_64-linux-gnu/liblua5.3.so.0.0.0) | |||
==12141== by 0x529A9F1: ??? (in /usr/lib/x86_64-linux-gnu/liblua5.3.so.0.0.0) | |||
==12141== by 0x529B523: lua_resume (in /usr/lib/x86_64-linux-gnu/liblua5.3.so.0.0.0) | |||
==12141== Address 0x8637171e928bb500 is not stack'd, malloc'd or (recently) free'd | |||
Fix this bug by correctly applying the `unlikely` macro to the result of the comparison. | |||
This bug exists as of commit ca16b038132444dea06e6d83953034128a812bce | |||
which is the first commit adding this function. | |||
v1.6-dev1 is the first tag containing this commit, the fix should | |||
be backported to haproxy 1.6 and newer. | |||
(cherry picked from commit 45be38c9c7ba2b20806f2b887876db4fb5b9457c) | |||
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com> | |||
diff --git a/src/channel.c b/src/channel.c | |||
index bd5c4de0..3770502c 100644 | |||
--- a/src/channel.c | |||
+++ b/src/channel.c | |||
@@ -340,7 +340,7 @@ int co_getline_nc(const struct channel *chn, | |||
int l; | |||
retcode = co_getblk_nc(chn, blk1, len1, blk2, len2); | |||
- if (unlikely(retcode) <= 0) | |||
+ if (unlikely(retcode <= 0)) | |||
return retcode; | |||
for (l = 0; l < *len1 && (*blk1)[l] != '\n'; l++); |
@ -0,0 +1,50 @@ | |||
commit 0e645ba57ddff9163a3d9b5626f189e974e671bd | |||
Author: Rian McGuire <rian.mcguire@stileeducation.com> | |||
Date: Tue Apr 24 11:19:21 2018 -0300 | |||
BUG/MINOR: log: t_idle (%Ti) is not set for some requests | |||
If TCP content inspection is used, msg_state can be >= HTTP_MSG_ERROR | |||
the first time http_wait_for_request is called. t_idle was being left | |||
unset in that case. | |||
In the example below : | |||
stick-table type string len 64 size 100k expire 60s | |||
tcp-request inspect-delay 1s | |||
tcp-request content track-sc1 hdr(X-Session) | |||
%Ti will always be -1, because the msg_state is already at HTTP_MSG_BODY | |||
when http_wait_for_request is called for the first time. | |||
This patch should backported to 1.8 and 1.7. | |||
(cherry picked from commit 89fcb7d929283e904cabad58de495d62fc753da2) | |||
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com> | |||
diff --git a/src/proto_http.c b/src/proto_http.c | |||
index b38dd84f..4c18a27c 100644 | |||
--- a/src/proto_http.c | |||
+++ b/src/proto_http.c | |||
@@ -1618,18 +1618,16 @@ int http_wait_for_request(struct stream *s, struct channel *req, int an_bit) | |||
/* we're speaking HTTP here, so let's speak HTTP to the client */ | |||
s->srv_error = http_return_srv_error; | |||
+ /* If there is data available for analysis, log the end of the idle time. */ | |||
+ if (buffer_not_empty(req->buf) && s->logs.t_idle == -1) | |||
+ s->logs.t_idle = tv_ms_elapsed(&s->logs.tv_accept, &now) - s->logs.t_handshake; | |||
+ | |||
/* There's a protected area at the end of the buffer for rewriting | |||
* purposes. We don't want to start to parse the request if the | |||
* protected area is affected, because we may have to move processed | |||
* data later, which is much more complicated. | |||
*/ | |||
if (buffer_not_empty(req->buf) && msg->msg_state < HTTP_MSG_ERROR) { | |||
- | |||
- /* This point is executed when some data is avalaible for analysis, | |||
- * so we log the end of the idle time. */ | |||
- if (s->logs.t_idle == -1) | |||
- s->logs.t_idle = tv_ms_elapsed(&s->logs.tv_accept, &now) - s->logs.t_handshake; | |||
- | |||
if (txn->flags & TX_NOT_FIRST) { | |||
if (unlikely(!channel_is_rewritable(req))) { | |||
if (req->flags & (CF_SHUTW|CF_SHUTW_NOW|CF_WRITE_ERROR|CF_WRITE_TIMEOUT)) |
@ -0,0 +1,48 @@ | |||
commit 17f3e16826e5b1a3f79b7421d69bb85be09a4ad9 | |||
Author: Tim Duesterhus <tim@bastelstu.be> | |||
Date: Tue Apr 24 13:56:01 2018 +0200 | |||
BUG/MEDIUM: lua: Fix segmentation fault if a Lua task exits | |||
PiBa-NL reported that haproxy crashes with a segmentation fault | |||
if a function registered using `core.register_task` returns. | |||
An example Lua script that reproduces the bug is: | |||
mytask = function() | |||
core.Info("Stopping task") | |||
end | |||
core.register_task(mytask) | |||
The Valgrind output is as follows: | |||
==6759== Process terminating with default action of signal 11 (SIGSEGV) | |||
==6759== Access not within mapped region at address 0x20 | |||
==6759== at 0x5B60AA9: lua_sethook (in /usr/lib/x86_64-linux-gnu/liblua5.3.so.0.0.0) | |||
==6759== by 0x430264: hlua_ctx_resume (hlua.c:1009) | |||
==6759== by 0x43BB68: hlua_process_task (hlua.c:5525) | |||
==6759== by 0x4FED0A: process_runnable_tasks (task.c:231) | |||
==6759== by 0x4B2256: run_poll_loop (haproxy.c:2397) | |||
==6759== by 0x4B2256: run_thread_poll_loop (haproxy.c:2459) | |||
==6759== by 0x41A7E4: main (haproxy.c:3049) | |||
Add the missing `task = NULL` for the `HLUA_E_OK` case. The error cases | |||
have been fixed as of 253e53e661c49fb9723535319cf511152bf09bc7 which | |||
first was included in haproxy v1.8-dev3. This bugfix should be backported | |||
to haproxy 1.8. | |||
(cherry picked from commit cd235c60425dbe66c9015a357369afacc4880211) | |||
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com> | |||
diff --git a/src/hlua.c b/src/hlua.c | |||
index 4e759c7c..d4b7ce91 100644 | |||
--- a/src/hlua.c | |||
+++ b/src/hlua.c | |||
@@ -5528,6 +5528,7 @@ static struct task *hlua_process_task(struct task *task) | |||
hlua_ctx_destroy(hlua); | |||
task_delete(task); | |||
task_free(task); | |||
+ task = NULL; | |||
break; | |||
case HLUA_E_AGAIN: /* co process or timeout wake me later. */ |
@ -0,0 +1,147 @@ | |||
commit a8bcc7dd3fe5aa615f21e795375ff9225f004498 | |||
Author: Willy Tarreau <w@1wt.eu> | |||
Date: Wed Apr 25 18:13:58 2018 +0200 | |||
MINOR: h2: detect presence of CONNECT and/or content-length | |||
We'll need this in order to support uploading chunks. The h2 to h1 | |||
converter checks for the presence of the content-length header field | |||
as well as the CONNECT method and returns these information to the | |||
caller. The caller indicates whether or not a body is detected for | |||
the message (presence of END_STREAM or not). No transfer-encoding | |||
header is emitted yet. | |||
(cherry picked from commit 174b06a572ef141f15d8b7ea64eb6b34ec4c9af1) | |||
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com> | |||
diff --git a/include/common/h2.h b/include/common/h2.h | |||
index 65c5ab1c..576ed105 100644 | |||
--- a/include/common/h2.h | |||
+++ b/include/common/h2.h | |||
@@ -145,9 +145,15 @@ enum h2_err { | |||
"\x0d\x0a\x53\x4d\x0d\x0a\x0d\x0a" | |||
+/* some flags related to protocol parsing */ | |||
+#define H2_MSGF_BODY 0x0001 // a body is present | |||
+#define H2_MSGF_BODY_CL 0x0002 // content-length is present | |||
+#define H2_MSGF_BODY_TUNNEL 0x0004 // a tunnel is in use (CONNECT) | |||
+ | |||
+ | |||
/* various protocol processing functions */ | |||
-int h2_make_h1_request(struct http_hdr *list, char *out, int osize); | |||
+int h2_make_h1_request(struct http_hdr *list, char *out, int osize, unsigned int *msgf); | |||
/* | |||
* Some helpful debugging functions. | |||
diff --git a/src/h2.c b/src/h2.c | |||
index 43ed7f3c..7d9ddd50 100644 | |||
--- a/src/h2.c | |||
+++ b/src/h2.c | |||
@@ -36,9 +36,10 @@ | |||
* stored in <phdr[]>. <fields> indicates what was found so far. This should be | |||
* called once at the detection of the first general header field or at the end | |||
* of the request if no general header field was found yet. Returns 0 on success | |||
- * or a negative error code on failure. | |||
+ * or a negative error code on failure. Upon success, <msgf> is updated with a | |||
+ * few H2_MSGF_* flags indicating what was found while parsing. | |||
*/ | |||
-static int h2_prepare_h1_reqline(uint32_t fields, struct ist *phdr, char **ptr, char *end) | |||
+static int h2_prepare_h1_reqline(uint32_t fields, struct ist *phdr, char **ptr, char *end, unsigned int *msgf) | |||
{ | |||
char *out = *ptr; | |||
int uri_idx = H2_PHDR_IDX_PATH; | |||
@@ -62,6 +63,7 @@ static int h2_prepare_h1_reqline(uint32_t fields, struct ist *phdr, char **ptr, | |||
} | |||
// otherwise OK ; let's use the authority instead of the URI | |||
uri_idx = H2_PHDR_IDX_AUTH; | |||
+ *msgf |= H2_MSGF_BODY_TUNNEL; | |||
} | |||
else if ((fields & (H2_PHDR_FND_METH|H2_PHDR_FND_SCHM|H2_PHDR_FND_PATH)) != | |||
(H2_PHDR_FND_METH|H2_PHDR_FND_SCHM|H2_PHDR_FND_PATH)) { | |||
@@ -113,6 +115,10 @@ static int h2_prepare_h1_reqline(uint32_t fields, struct ist *phdr, char **ptr, | |||
* for a max of <osize> bytes, and the amount of bytes emitted is returned. In | |||
* case of error, a negative error code is returned. | |||
* | |||
+ * Upon success, <msgf> is filled with a few H2_MSGF_* flags indicating what | |||
+ * was found while parsing. The caller must set it to zero in or H2_MSGF_BODY | |||
+ * if a body is detected (!ES). | |||
+ * | |||
* The headers list <list> must be composed of : | |||
* - n.name != NULL, n.len > 0 : literal header name | |||
* - n.name == NULL, n.len > 0 : indexed pseudo header name number <n.len> | |||
@@ -124,7 +130,7 @@ static int h2_prepare_h1_reqline(uint32_t fields, struct ist *phdr, char **ptr, | |||
* The Cookie header will be reassembled at the end, and for this, the <list> | |||
* will be used to create a linked list, so its contents may be destroyed. | |||
*/ | |||
-int h2_make_h1_request(struct http_hdr *list, char *out, int osize) | |||
+int h2_make_h1_request(struct http_hdr *list, char *out, int osize, unsigned int *msgf) | |||
{ | |||
struct ist phdr_val[H2_PHDR_NUM_ENTRIES]; | |||
char *out_end = out + osize; | |||
@@ -176,7 +182,7 @@ int h2_make_h1_request(struct http_hdr *list, char *out, int osize) | |||
/* regular header field in (name,value) */ | |||
if (!(fields & H2_PHDR_FND_NONE)) { | |||
/* no more pseudo-headers, time to build the request line */ | |||
- ret = h2_prepare_h1_reqline(fields, phdr_val, &out, out_end); | |||
+ ret = h2_prepare_h1_reqline(fields, phdr_val, &out, out_end, msgf); | |||
if (ret != 0) | |||
goto leave; | |||
fields |= H2_PHDR_FND_NONE; | |||
@@ -185,6 +191,10 @@ int h2_make_h1_request(struct http_hdr *list, char *out, int osize) | |||
if (isteq(list[idx].n, ist("host"))) | |||
fields |= H2_PHDR_FND_HOST; | |||
+ if ((*msgf & (H2_MSGF_BODY|H2_MSGF_BODY_TUNNEL|H2_MSGF_BODY_CL)) == H2_MSGF_BODY && | |||
+ isteq(list[idx].n, ist("content-length"))) | |||
+ *msgf |= H2_MSGF_BODY_CL; | |||
+ | |||
/* these ones are forbidden in requests (RFC7540#8.1.2.2) */ | |||
if (isteq(list[idx].n, ist("connection")) || | |||
isteq(list[idx].n, ist("proxy-connection")) || | |||
@@ -232,7 +242,7 @@ int h2_make_h1_request(struct http_hdr *list, char *out, int osize) | |||
/* Let's dump the request now if not yet emitted. */ | |||
if (!(fields & H2_PHDR_FND_NONE)) { | |||
- ret = h2_prepare_h1_reqline(fields, phdr_val, &out, out_end); | |||
+ ret = h2_prepare_h1_reqline(fields, phdr_val, &out, out_end, msgf); | |||
if (ret != 0) | |||
goto leave; | |||
} | |||
diff --git a/src/mux_h2.c b/src/mux_h2.c | |||
index 4fde7fcc..82dd414a 100644 | |||
--- a/src/mux_h2.c | |||
+++ b/src/mux_h2.c | |||
@@ -2626,6 +2626,7 @@ static int h2_frt_decode_headers(struct h2s *h2s, struct buffer *buf, int count) | |||
struct chunk *tmp = get_trash_chunk(); | |||
struct http_hdr list[MAX_HTTP_HDR * 2]; | |||
struct chunk *copy = NULL; | |||
+ unsigned int msgf; | |||
int flen = h2c->dfl; | |||
int outlen = 0; | |||
int wrap; | |||
@@ -2727,13 +2728,22 @@ static int h2_frt_decode_headers(struct h2s *h2s, struct buffer *buf, int count) | |||
} | |||
/* OK now we have our header list in <list> */ | |||
- outlen = h2_make_h1_request(list, bi_end(buf), try); | |||
+ msgf = (h2c->dff & H2_F_DATA_END_STREAM) ? 0 : H2_MSGF_BODY; | |||
+ outlen = h2_make_h1_request(list, bi_end(buf), try, &msgf); | |||
if (outlen < 0) { | |||
h2c_error(h2c, H2_ERR_COMPRESSION_ERROR); | |||
goto fail; | |||
} | |||
+ if (msgf & H2_MSGF_BODY) { | |||
+ /* a payload is present */ | |||
+ if (msgf & H2_MSGF_BODY_CL) | |||
+ h2s->flags |= H2_SF_DATA_CLEN; | |||
+ else if (!(msgf & H2_MSGF_BODY_TUNNEL)) | |||
+ h2s->flags |= H2_SF_DATA_CHNK; | |||
+ } | |||
+ | |||
/* now consume the input data */ | |||
bi_del(h2c->dbuf, h2c->dfl); | |||
h2c->st0 = H2_CS_FRAME_H; |
@ -0,0 +1,164 @@ | |||
commit 05657bd24ebaf20e5c508a435be9a0830591f033 | |||
Author: Willy Tarreau <w@1wt.eu> | |||
Date: Wed Apr 25 20:44:22 2018 +0200 | |||
BUG/MEDIUM: h2: implement missing support for chunked encoded uploads | |||
Upload requests not carrying a content-length nor tunnelling data must | |||
be sent chunked-encoded over HTTP/1. The code was planned but for some | |||
reason forgotten during the implementation, leading to such payloads to | |||
be sent as tunnelled data. | |||
Browsers always emit a content length in uploads so this problem doesn't | |||
happen for most sites. However some applications may send data frames | |||
after a request without indicating it earlier. | |||
The only way to detect that a client will need to send data is that the | |||
HEADERS frame doesn't hold the ES bit. In this case it's wise to look | |||
for the content-length header. If it's not there, either we're in tunnel | |||
(CONNECT method) or chunked-encoding (other methods). | |||
This patch implements this. | |||
The following request is sent using content-length : | |||
curl --http2 -sk https://127.0.0.1:4443/s2 -XPOST -T /large/file | |||
and these ones using chunked-encoding : | |||
curl --http2 -sk https://127.0.0.1:4443/s2 -XPUT -T /large/file | |||
curl --http2 -sk https://127.0.0.1:4443/s2 -XPUT -T - < /dev/urandom | |||
Thanks to Robert Samuel Newson for raising this issue with details. | |||
This fix must be backported to 1.8. | |||
(cherry picked from commit eba10f24b7da27cde60d2db24aeb1147e1657579) | |||
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com> | |||
diff --git a/src/h2.c b/src/h2.c | |||
index 7d9ddd50..5c83d6b6 100644 | |||
--- a/src/h2.c | |||
+++ b/src/h2.c | |||
@@ -262,6 +262,14 @@ int h2_make_h1_request(struct http_hdr *list, char *out, int osize, unsigned int | |||
*(out++) = '\n'; | |||
} | |||
+ if ((*msgf & (H2_MSGF_BODY|H2_MSGF_BODY_TUNNEL|H2_MSGF_BODY_CL)) == H2_MSGF_BODY) { | |||
+ /* add chunked encoding */ | |||
+ if (out + 28 > out_end) | |||
+ goto fail; | |||
+ memcpy(out, "transfer-encoding: chunked\r\n", 28); | |||
+ out += 28; | |||
+ } | |||
+ | |||
/* now we may have to build a cookie list. We'll dump the values of all | |||
* visited headers. | |||
*/ | |||
diff --git a/src/mux_h2.c b/src/mux_h2.c | |||
index 82dd414a..5f1da0df 100644 | |||
--- a/src/mux_h2.c | |||
+++ b/src/mux_h2.c | |||
@@ -2785,6 +2785,7 @@ static int h2_frt_transfer_data(struct h2s *h2s, struct buffer *buf, int count) | |||
struct h2c *h2c = h2s->h2c; | |||
int block1, block2; | |||
unsigned int flen = h2c->dfl; | |||
+ unsigned int chklen = 0; | |||
h2s->cs->flags &= ~CS_FL_RCV_MORE; | |||
h2c->flags &= ~H2_CF_DEM_SFULL; | |||
@@ -2820,14 +2821,35 @@ static int h2_frt_transfer_data(struct h2s *h2s, struct buffer *buf, int count) | |||
return 0; | |||
} | |||
+ /* chunked-encoding requires more room */ | |||
+ if (h2s->flags & H2_SF_DATA_CHNK) { | |||
+ chklen = MIN(flen, count); | |||
+ chklen = (chklen < 16) ? 1 : (chklen < 256) ? 2 : | |||
+ (chklen < 4096) ? 3 : (chklen < 65536) ? 4 : | |||
+ (chklen < 1048576) ? 4 : 8; | |||
+ chklen += 4; // CRLF, CRLF | |||
+ } | |||
+ | |||
/* does it fit in output buffer or should we wait ? */ | |||
- if (flen > count) { | |||
- flen = count; | |||
- if (!flen) { | |||
- h2c->flags |= H2_CF_DEM_SFULL; | |||
- h2s->cs->flags |= CS_FL_RCV_MORE; | |||
- return 0; | |||
- } | |||
+ if (flen + chklen > count) { | |||
+ if (chklen >= count) | |||
+ goto full; | |||
+ flen = count - chklen; | |||
+ } | |||
+ | |||
+ if (h2s->flags & H2_SF_DATA_CHNK) { | |||
+ /* emit the chunk size */ | |||
+ unsigned int chksz = flen; | |||
+ char str[10]; | |||
+ char *beg; | |||
+ | |||
+ beg = str + sizeof(str); | |||
+ *--beg = '\n'; | |||
+ *--beg = '\r'; | |||
+ do { | |||
+ *--beg = hextab[chksz & 0xF]; | |||
+ } while (chksz >>= 4); | |||
+ bi_putblk(buf, beg, str + sizeof(str) - beg); | |||
} | |||
/* Block1 is the length of the first block before the buffer wraps, | |||
@@ -2844,6 +2866,11 @@ static int h2_frt_transfer_data(struct h2s *h2s, struct buffer *buf, int count) | |||
if (block2) | |||
bi_putblk(buf, b_ptr(h2c->dbuf, block1), block2); | |||
+ if (h2s->flags & H2_SF_DATA_CHNK) { | |||
+ /* emit the CRLF */ | |||
+ bi_putblk(buf, "\r\n", 2); | |||
+ } | |||
+ | |||
/* now mark the input data as consumed (will be deleted from the buffer | |||
* by the caller when seeing FRAME_A after sending the window update). | |||
*/ | |||
@@ -2854,15 +2881,22 @@ static int h2_frt_transfer_data(struct h2s *h2s, struct buffer *buf, int count) | |||
if (h2c->dfl > h2c->dpl) { | |||
/* more data available, transfer stalled on stream full */ | |||
- h2c->flags |= H2_CF_DEM_SFULL; | |||
- h2s->cs->flags |= CS_FL_RCV_MORE; | |||
- return flen; | |||
+ goto more; | |||
} | |||
end_transfer: | |||
/* here we're done with the frame, all the payload (except padding) was | |||
* transferred. | |||
*/ | |||
+ | |||
+ if (h2c->dff & H2_F_DATA_END_STREAM && h2s->flags & H2_SF_DATA_CHNK) { | |||
+ /* emit the trailing 0 CRLF CRLF */ | |||
+ if (count < 5) | |||
+ goto more; | |||
+ chklen += 5; | |||
+ bi_putblk(buf, "0\r\n\r\n", 5); | |||
+ } | |||
+ | |||
h2c->rcvd_c += h2c->dpl; | |||
h2c->rcvd_s += h2c->dpl; | |||
h2c->dpl = 0; | |||
@@ -2877,7 +2911,13 @@ static int h2_frt_transfer_data(struct h2s *h2s, struct buffer *buf, int count) | |||
h2s->flags |= H2_SF_ES_RCVD; | |||
} | |||
- return flen; | |||
+ return flen + chklen; | |||
+ full: | |||
+ flen = chklen = 0; | |||
+ more: | |||
+ h2c->flags |= H2_CF_DEM_SFULL; | |||
+ h2s->cs->flags |= CS_FL_RCV_MORE; | |||
+ return flen + chklen; | |||
} | |||
/* |
@ -0,0 +1,36 @@ | |||
commit 8b8d55be7e94ee3d758d41a21fa86a036e91a264 | |||
Author: Christopher Faulet <cfaulet@haproxy.com> | |||
Date: Wed Apr 25 10:34:45 2018 +0200 | |||
BUG/MINOR: lua/threads: Make lua's tasks sticky to the current thread | |||
PiBa-NL reported a bug with tasks registered in lua when HAProxy is started with | |||
serveral threads. These tasks have not specific affinity with threads so they | |||
can be woken up on any threads. So, it is impossbile for these tasks to handled | |||
cosockets or applets, because cosockets and applets are sticky on the thread | |||
which created them. It is forbbiden to manipulate a cosocket from another | |||
thread. | |||
So to fix the bug, tasks registered in lua are now sticky to the current | |||
thread. Because these tasks can be registered before threads creation, the | |||
affinity is set the first time a lua's task is processed. | |||
This patch must be backported in HAProxy 1.8. | |||
(cherry picked from commit 5bc9972ed836517924eea91954d255d317a53418) | |||
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com> | |||
diff --git a/src/hlua.c b/src/hlua.c | |||
index d4b7ce91..bd0b87e3 100644 | |||
--- a/src/hlua.c | |||
+++ b/src/hlua.c | |||
@@ -5513,6 +5513,9 @@ static struct task *hlua_process_task(struct task *task) | |||
struct hlua *hlua = task->context; | |||
enum hlua_exec status; | |||
+ if (task->thread_mask == MAX_THREADS_MASK) | |||
+ task_set_affinity(task, tid_bit); | |||
+ | |||
/* If it is the first call to the task, we must initialize the | |||
* execution timeouts. | |||
*/ |