summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristopher Faulet <cfaulet@haproxy.com>2021-01-21 17:36:12 +0100
committerChristopher Faulet <cfaulet@haproxy.com>2021-01-26 15:00:18 +0100
commit37269e9a00e1fb5417e2148c7a39e06c3f61d4e7 (patch)
tree66e96f334b05a02737868ee2f871394b99bd6b23
parent20938af387d016cf6ca81dd74ef6613865500626 (diff)
downloadhaproxy-37269e9a00e1fb5417e2148c7a39e06c3f61d4e7.tar.gz
MINOR: stream: Add a function to validate TCP to H1 upgrades
TCP to H1 upgrades are buggy for now. When such upgrade is performed, a crash is experienced. The bug is the result of the recent H1 mux refactoring, and more specifically because of the commit c4bfa59f1 ("MAJOR: mux-h1: Create the client stream as later as possible"). Indeed, now the H1 mux is responsible to create the frontend conn-stream once the request headers are fully received. Thus the TCP to H1 upgrade is a problem because the frontend conn-stream already exists. To fix the bug, we must keep this conn-stream and the associate stream and use it in the H1 mux. To do so, the upgrade will be performed in two steps. First, the mux is upgraded from mux-pt to mux-h1. Then, the mux-h1 performs the stream upgrade, once the request headers are fully received and parsed. To do so, stream_upgrade_from_cs() must be used. This function set the SF_HTX flags to switch the stream to HTX mode, it removes the SF_IGNORE flags and eventually it fills the request channel with some input data. This patch is required to fix the TCP to H1 upgrades and is intimately linked with the next commits.
-rw-r--r--include/haproxy/stream.h1
-rw-r--r--src/stream.c32
2 files changed, 33 insertions, 0 deletions
diff --git a/include/haproxy/stream.h b/include/haproxy/stream.h
index f33026093..edd7cbfbe 100644
--- a/include/haproxy/stream.h
+++ b/include/haproxy/stream.h
@@ -60,6 +60,7 @@ extern struct data_cb sess_conn_cb;
struct stream *stream_new(struct session *sess, enum obj_type *origin, struct buffer *input);
int stream_create_from_cs(struct conn_stream *cs, struct buffer *input);
+int stream_upgrade_from_cs(struct conn_stream *cs, struct buffer *input);
/* kill a stream and set the termination flags to <why> (one of SF_ERR_*) */
void stream_shutdown(struct stream *stream, int why);
diff --git a/src/stream.c b/src/stream.c
index 1a41ea53b..74dfa903c 100644
--- a/src/stream.c
+++ b/src/stream.c
@@ -285,6 +285,38 @@ int stream_create_from_cs(struct conn_stream *cs, struct buffer *input)
return 0;
}
+/* Upgrade an existing TCP stream for connection <conn>. Return < 0 on error.
+ * This is only valid right after a TCP to H1 upgrade. The stream should be
+ * "reativated" by removing SF_IGNORE flag. And the right mode must be set.
+ * On success, <input> buffer is transferred to the stream and thus points to
+ * BUF_NULL. On error, it is unchanged and it is the caller responsibility to
+ * release it (this never happens for now).
+ */
+int stream_upgrade_from_cs(struct conn_stream *cs, struct buffer *input)
+{
+ struct stream_interface *si = cs->data;
+ struct stream *s = si_strm(si);
+
+ if (cs->conn->mux->flags & MX_FL_HTX)
+ s->flags |= SF_HTX;
+
+ if (!b_is_null(input)) {
+ /* Xfer the input buffer to the request channel. <input> will
+ * than point to BUF_NULL. From this point, it is the stream
+ * responsibility to release it.
+ */
+ s->req.buf = *input;
+ *input = BUF_NULL;
+ s->req.total = (IS_HTX_STRM(s) ? htxbuf(&s->req.buf)->data : b_data(&s->req.buf));
+ s->req.flags |= (s->req.total ? CF_READ_PARTIAL : 0);
+ }
+
+ s->flags &= ~SF_IGNORE;
+
+ task_wakeup(s->task, TASK_WOKEN_INIT);
+ return 0;
+}
+
/* Callback used to wake up a stream when an input buffer is available. The
* stream <s>'s stream interfaces are checked for a failed buffer allocation
* as indicated by the presence of the SI_FL_RXBLK_ROOM flag and the lack of a