summaryrefslogtreecommitdiff
path: root/src/h2.c
diff options
context:
space:
mode:
authorGlenn Strauss <gstrauss@gluelogic.com>2023-04-08 21:01:31 -0400
committerGlenn Strauss <gstrauss@gluelogic.com>2023-04-24 21:17:29 -0400
commit723176fa3f4e499554dc9c98563dd4eb1a8a9150 (patch)
tree6be5af17e086fa1f949220284c65ddc29330c1a1 /src/h2.c
parentfdb7ffed88b9dfe09a51e7fb58e5ddfe938c1ec9 (diff)
downloadlighttpd-git-723176fa3f4e499554dc9c98563dd4eb1a8a9150.tar.gz
[core] connection_check_upgrade() h2_upgrade_h2c()
separate generic HTTP handling of Upgrade request header from handling of Upgrade: h2c
Diffstat (limited to 'src/h2.c')
-rw-r--r--src/h2.c99
1 files changed, 35 insertions, 64 deletions
diff --git a/src/h2.c b/src/h2.c
index 86d47a4e..809b14ce 100644
--- a/src/h2.c
+++ b/src/h2.c
@@ -1929,7 +1929,7 @@ h2_read_client_connection_preface (struct connection * const con, chunkqueue * c
void
-h2_init_con (request_st * const restrict h2r, connection * const restrict con, const buffer * const restrict http2_settings)
+h2_init_con (request_st * const restrict h2r, connection * const restrict con)
{
h2con * const h2c = con->h2 = ck_calloc(1, sizeof(h2con));
con->read_idle_ts = log_monotonic_secs;
@@ -1951,9 +1951,6 @@ h2_init_con (request_st * const restrict h2r, connection * const restrict con, c
lshpack_enc_init(&h2c->encoder);
lshpack_enc_use_hist(&h2c->encoder, 1);
- if (http2_settings) /*(if Upgrade: h2c)*/
- h2_parse_frame_settings(con, (uint8_t *)BUF_PTR_LEN(http2_settings));
-
static const uint8_t h2settings[] = { /*(big-endian numbers)*/
/* SETTINGS */
0x00, 0x00, 0x1e /* frame length */ /* 5 * (6 bytes per setting) */
@@ -2897,7 +2894,7 @@ h2_retire_con (request_st * const h2r, connection * const con)
static void
-h2_con_upgrade_h2c (request_st * const h2r, const buffer * const http2_settings)
+h2_con_upgrade_h2c (request_st * const h2r, connection * const con)
{
/* HTTP/1.1 101 Switching Protocols
* Connection: Upgrade
@@ -2919,8 +2916,7 @@ h2_con_upgrade_h2c (request_st * const h2r, const buffer * const http2_settings)
h2r->http_status = 0;
#endif
- connection * const con = h2r->con;
- h2_init_con(h2r, con, http2_settings);
+ h2_init_con(h2r, con);
if (con->h2->sent_goaway) return;
con->h2->h2_cid = 1; /* stream id 1 is assigned to h2c upgrade */
@@ -2932,7 +2928,7 @@ h2_con_upgrade_h2c (request_st * const h2r, const buffer * const http2_settings)
request_st * const r = h2_init_stream(h2r, con);
/*(undo double-count; already incremented in CON_STATE_REQUEST_START)*/
--con->request_count;
- r->state = CON_STATE_REQUEST_END;
+ r->state = CON_STATE_WRITE; /* require 0 == r->reqbody_length */
r->http_status = 0;
r->http_method = h2r->http_method;
r->h2state = H2_STATE_HALF_CLOSED_REMOTE;
@@ -3000,62 +2996,37 @@ h2_con_upgrade_h2c (request_st * const h2r, const buffer * const http2_settings)
}
-int
-h2_check_con_upgrade_h2c (request_st * const r)
+__attribute_cold__
+__attribute_nonnull__()
+static void
+h2_upgrade_h2c (request_st * const r, connection * const con)
{
- /* RFC7540 3.2 Starting HTTP/2 for "http" URIs */
-
- buffer *http_connection, *http2_settings;
- buffer *upgrade = http_header_request_get(r, HTTP_HEADER_UPGRADE,
- CONST_STR_LEN("Upgrade"));
- if (NULL == upgrade) return 0;
- http_connection = http_header_request_get(r, HTTP_HEADER_CONNECTION,
- CONST_STR_LEN("Connection"));
- if (NULL == http_connection) {
- http_header_request_unset(r, HTTP_HEADER_UPGRADE,
- CONST_STR_LEN("Upgrade"));
- return 0;
- }
- if (r->http_version != HTTP_VERSION_1_1) {
- http_header_request_unset(r, HTTP_HEADER_UPGRADE,
- CONST_STR_LEN("Upgrade"));
- http_header_remove_token(http_connection, CONST_STR_LEN("Upgrade"));
- return 0;
+ /* Upgrade: h2c
+ * RFC7540 3.2 Starting HTTP/2 for "http" URIs */
+
+ buffer * const http2_settings =
+ http_header_request_get(r, HTTP_HEADER_HTTP2_SETTINGS,
+ CONST_STR_LEN("HTTP2-Settings"));
+
+ /* ignore Upgrade: h2c if request body present since we do not
+ * (currently) handle request body before transition to h2c */
+ /* RFC7540 3.2 Requests that contain a payload body MUST be sent
+ * in their entirety before the client can send HTTP/2 frames. */
+
+ if (NULL != http2_settings
+ && 0 == r->reqbody_length
+ && r->conf.h2proto > 1/*(must be enabled with server.h2c feature)*/
+ && !con->is_ssl_sock) { /*(disallow h2c over TLS socket)*/
+
+ r->http_version = HTTP_VERSION_2;
+ h2_con_upgrade_h2c(r, con);
+
+ buffer * const b = r->tmp_buf;
+ buffer_clear(b);
+ if (buffer_append_base64_decode(b, BUF_PTR_LEN(http2_settings),
+ BASE64_URL))
+ h2_parse_frame_settings(con, (uint8_t *)BUF_PTR_LEN(b));
+ else
+ h2_send_goaway_e(con, H2_E_PROTOCOL_ERROR);
}
-
- if (!http_header_str_contains_token(BUF_PTR_LEN(upgrade),
- CONST_STR_LEN("h2c")))
- return 0;
-
- http2_settings = http_header_request_get(r, HTTP_HEADER_HTTP2_SETTINGS,
- CONST_STR_LEN("HTTP2-Settings"));
- if (NULL != http2_settings) {
- if (0 == r->reqbody_length) {
- buffer * const b = r->tmp_buf;
- buffer_clear(b);
- if (r->conf.h2proto > 1/*(must be enabled with server.h2c feature)*/
- && !r->con->is_ssl_sock /*(disallow h2c over TLS socket)*/
- &&
- http_header_str_contains_token(BUF_PTR_LEN(http_connection),
- CONST_STR_LEN("HTTP2-Settings"))
- && buffer_append_base64_decode(b, BUF_PTR_LEN(http2_settings),
- BASE64_URL)) {
- h2_con_upgrade_h2c(r, b);
- r->http_version = HTTP_VERSION_2;
- } /* else ignore if invalid base64 */
- }
- else {
- /* ignore Upgrade: h2c if request body present since we do not
- * (currently) handle request body before transition to h2c */
- /* RFC7540 3.2 Requests that contain a payload body MUST be sent
- * in their entirety before the client can send HTTP/2 frames. */
- }
- http_header_request_unset(r, HTTP_HEADER_HTTP2_SETTINGS,
- CONST_STR_LEN("HTTP2-Settings"));
- http_header_remove_token(http_connection, CONST_STR_LEN("HTTP2-Settings"));
- } /* else ignore Upgrade: h2c; HTTP2-Settings required for Upgrade: h2c */
- http_header_request_unset(r, HTTP_HEADER_UPGRADE,
- CONST_STR_LEN("Upgrade"));
- http_header_remove_token(http_connection, CONST_STR_LEN("Upgrade"));
- return (r->http_version == HTTP_VERSION_2);
}