Skip to content

Commit 94be89e

Browse files
ttaymkrizhanovsky
andauthored
Recreate upgrade headers for websocket request (#1592)
Co-authored-by: Alexander Krizhanovsky <[email protected]> Signed-off-by: Aleksey Mikhaylov <[email protected]>
1 parent ff0c1d6 commit 94be89e

File tree

3 files changed

+120
-14
lines changed

3 files changed

+120
-14
lines changed

fw/http.c

+86-9
Original file line numberDiff line numberDiff line change
@@ -2572,6 +2572,44 @@ tfw_http_set_hdr_date(TfwHttpMsg *hm)
25722572
return r;
25732573
}
25742574

2575+
/*
2576+
* Add 'Upgrade:' header for websocket upgrade messages
2577+
*/
2578+
static int
2579+
tfw_http_set_hdr_upgrade(TfwHttpMsg *hm, bool is_resp)
2580+
{
2581+
int r = 0;
2582+
2583+
if (test_bit(TFW_HTTP_B_UPGRADE_WEBSOCKET, hm->flags)) {
2584+
/*
2585+
* RFC7230#section-6.7:
2586+
* A server that sends a 101 (Switching Protocols) response
2587+
* MUST send an Upgrade header field to indicate the new
2588+
* protocol(s) to which the connection is being switched; if
2589+
* multiple protocol layers are being switched, the sender MUST
2590+
* list the protocols in layer-ascending order.
2591+
*
2592+
* We do expect neither upgrades besides 'websocket' nor
2593+
* multilayer upgrades. So we consider extra options as error.
2594+
*/
2595+
if (is_resp && ((TfwHttpResp *)hm)->status == 101
2596+
&& test_bit(TFW_HTTP_B_UPGRADE_EXTRA, hm->flags))
2597+
{
2598+
T_ERR("Unable to add uncompliant 'Upgrade:' header "
2599+
"to msg [%p]\n", hm);
2600+
return -EINVAL;
2601+
}
2602+
r = tfw_http_msg_hdr_xfrm(hm, "upgrade", SLEN("upgrade"),
2603+
"websocket", SLEN("websocket"),
2604+
TFW_HTTP_HDR_UPGRADE, 0);
2605+
if (r)
2606+
T_ERR("Unable to add Upgrade: header to msg [%p]\n", hm);
2607+
else
2608+
T_DBG2("Added Upgrade: header to msg [%p]\n", hm);
2609+
}
2610+
return r;
2611+
}
2612+
25752613
/*
25762614
* Expand HTTP response with 'Date:' header field.
25772615
*/
@@ -2677,23 +2715,54 @@ tfw_http_expand_hbh(TfwHttpResp *resp, unsigned short status)
26772715
static int
26782716
tfw_http_set_hdr_connection(TfwHttpMsg *hm, unsigned long conn_flg)
26792717
{
2718+
int r;
26802719
BUILD_BUG_ON(BIT_WORD(__TFW_HTTP_MSG_M_CONN) != 0);
26812720
if (((hm->flags[0] & __TFW_HTTP_MSG_M_CONN) == conn_flg)
26822721
&& (!TFW_STR_EMPTY(&hm->h_tbl->tbl[TFW_HTTP_HDR_CONNECTION]))
2683-
&& !test_bit(TFW_HTTP_B_CONN_EXTRA, hm->flags))
2722+
&& !test_bit(TFW_HTTP_B_CONN_EXTRA, hm->flags)
2723+
&& !test_bit(TFW_HTTP_B_CONN_UPGRADE, hm->flags))
2724+
{
26842725
return 0;
2726+
}
26852727

2686-
switch (conn_flg) {
2687-
case BIT(TFW_HTTP_B_CONN_CLOSE):
2728+
/*
2729+
* We can see `TFW_HTTP_B_CONN_CLOSE` here only in case of 4XX
2730+
* response with 'Connection: close' option.
2731+
*
2732+
* For requests conn_flg by default is TFW_HTTP_B_CONN_KA.
2733+
*/
2734+
if (unlikely(conn_flg == BIT(TFW_HTTP_B_CONN_CLOSE)))
26882735
return TFW_HTTP_MSG_HDR_XFRM(hm, "Connection", "close",
26892736
TFW_HTTP_HDR_CONNECTION, 0);
2690-
case BIT(TFW_HTTP_B_CONN_KA):
2691-
return TFW_HTTP_MSG_HDR_XFRM(hm, "Connection", "keep-alive",
2692-
TFW_HTTP_HDR_CONNECTION, 0);
2693-
default:
2694-
return TFW_HTTP_MSG_HDR_DEL(hm, "Connection",
2695-
TFW_HTTP_HDR_CONNECTION);
2737+
2738+
if (conn_flg == BIT(TFW_HTTP_B_CONN_KA)) {
2739+
if (test_bit(TFW_HTTP_B_UPGRADE_WEBSOCKET, hm->flags)
2740+
&& test_bit(TFW_HTTP_B_CONN_UPGRADE, hm->flags))
2741+
{
2742+
r = TFW_HTTP_MSG_HDR_XFRM(hm, "Connection",
2743+
"keep-alive, upgrade",
2744+
TFW_HTTP_HDR_CONNECTION, 0);
2745+
}
2746+
else {
2747+
r = TFW_HTTP_MSG_HDR_XFRM(hm, "Connection",
2748+
"keep-alive",
2749+
TFW_HTTP_HDR_CONNECTION, 0);
2750+
}
2751+
} else {
2752+
if (test_bit(TFW_HTTP_B_UPGRADE_WEBSOCKET, hm->flags)
2753+
&& test_bit(TFW_HTTP_B_CONN_UPGRADE, hm->flags))
2754+
{
2755+
r = TFW_HTTP_MSG_HDR_XFRM(hm, "Connection",
2756+
"upgrade",
2757+
TFW_HTTP_HDR_CONNECTION, 0);
2758+
}
2759+
else {
2760+
r = TFW_HTTP_MSG_HDR_DEL(hm, "Connection",
2761+
TFW_HTTP_HDR_CONNECTION);
2762+
}
26962763
}
2764+
2765+
return r;
26972766
}
26982767

26992768
/**
@@ -3072,6 +3141,10 @@ tfw_h1_adjust_req(TfwHttpReq *req)
30723141
if (r < 0)
30733142
return r;
30743143

3144+
r = tfw_http_set_hdr_upgrade(hm, false);
3145+
if (r < 0)
3146+
return r;
3147+
30753148
r = tfw_h1_set_loc_hdrs(hm, false, false);
30763149
if (r < 0)
30773150
return r;
@@ -3642,6 +3715,10 @@ tfw_http_adjust_resp(TfwHttpResp *resp)
36423715
if (r < 0)
36433716
return r;
36443717

3718+
r = tfw_http_set_hdr_upgrade(hm, true);
3719+
if (r < 0)
3720+
return r;
3721+
36453722
r = tfw_http_set_hdr_keep_alive(hm, conn_flg);
36463723
if (r < 0)
36473724
return r;

fw/http.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -242,8 +242,10 @@ enum {
242242
TFW_HTTP_B_CONN_KA,
243243
TFW_HTTP_B_CONN_UPGRADE,
244244
TFW_HTTP_B_CONN_EXTRA,
245-
/* Request is a websocket upgrade request */
245+
/* Message is a websocket upgrade request */
246246
TFW_HTTP_B_UPGRADE_WEBSOCKET,
247+
/* Message upgrade header contains extra fields */
248+
TFW_HTTP_B_UPGRADE_EXTRA,
247249
/* Chunked is last transfer encoding. */
248250
TFW_HTTP_B_CHUNKED,
249251
/* Chunked in the middle of applied transfer encodings. */

fw/http_parser.c

+31-4
Original file line numberDiff line numberDiff line change
@@ -3348,7 +3348,7 @@ STACK_FRAME_NON_STANDARD(__parse_pragma);
33483348
* __FSM_I_MOVE_fixup()/__FSM_I_MATCH_fixup()/TRY_STR_fixup() everywhere.
33493349
*/
33503350
static int
3351-
__req_parse_upgrade(TfwHttpMsg *hm, unsigned char *data, size_t len)
3351+
__parse_upgrade(TfwHttpMsg *hm, unsigned char *data, size_t len)
33523352
{
33533353
int r = CSTR_NEQ;
33543354
__FSM_DECLARE_VARS(hm);
@@ -3382,6 +3382,8 @@ __req_parse_upgrade(TfwHttpMsg *hm, unsigned char *data, size_t len)
33823382
*/
33833383
return CSTR_NEQ;
33843384
}
3385+
3386+
__set_bit(TFW_HTTP_B_UPGRADE_EXTRA, msg->flags);
33853387
__FSM_I_JMP(I_UpgradeProtocolEnd);
33863388
}
33873389

@@ -3398,6 +3400,8 @@ __req_parse_upgrade(TfwHttpMsg *hm, unsigned char *data, size_t len)
33983400
__set_bit(TFW_HTTP_B_UPGRADE_WEBSOCKET,
33993401
msg->flags);
34003402
}
3403+
} else {
3404+
__set_bit(TFW_HTTP_B_UPGRADE_EXTRA, msg->flags);
34013405
}
34023406

34033407
__FSM_I_JMP(I_UpgradeProtocolEnd);
@@ -3437,7 +3441,6 @@ __req_parse_upgrade(TfwHttpMsg *hm, unsigned char *data, size_t len)
34373441
* At this state we know that we saw at least one character in
34383442
* protocol version and now we can pass zero length token.
34393443
*/
3440-
34413444
__FSM_STATE(I_UpgradeVersion) {
34423445
__FSM_I_MATCH_MOVE_fixup(token, I_UpgradeVersion,
34433446
TFW_STR_VALUE);
@@ -3477,7 +3480,7 @@ __req_parse_upgrade(TfwHttpMsg *hm, unsigned char *data, size_t len)
34773480
done:
34783481
return r;
34793482
}
3480-
STACK_FRAME_NON_STANDARD(__req_parse_upgrade);
3483+
STACK_FRAME_NON_STANDARD(__parse_upgrade);
34813484

34823485
static int
34833486
__req_parse_user_agent(TfwHttpMsg *hm, unsigned char *data, size_t len)
@@ -4479,7 +4482,7 @@ tfw_http_parse_req(void *req_data, unsigned char *data, size_t len,
44794482
TFW_HTTP_HDR_USER_AGENT);
44804483

44814484
/* 'Upgrade:*OWS' is read, process field-value. */
4482-
__TFW_HTTP_PARSE_SPECHDR_VAL(Req_HdrUpgradeV, msg,__req_parse_upgrade,
4485+
__TFW_HTTP_PARSE_SPECHDR_VAL(Req_HdrUpgradeV, msg, __parse_upgrade,
44834486
TFW_HTTP_HDR_UPGRADE, 0);
44844487

44854488
/* 'Cookie:*OWS' is read, process field-value. */
@@ -10057,6 +10060,17 @@ tfw_http_parse_resp(void *resp_data, unsigned char *data, size_t len,
1005710060
__FSM_MOVE_hdr_fixup(RGen_LWS, 1);
1005810061
}
1005910062
__FSM_MOVE(Resp_HdrT);
10063+
case 'u':
10064+
if (likely(__data_available(p, 8)
10065+
&& C4_INT_LCM(p, 'u', 'p', 'g', 'r')
10066+
&& C4_INT3_LCM(p + 4, 'a', 'd', 'e', ':')))
10067+
{
10068+
__msg_hdr_chunk_fixup(data, __data_off(p + 7));
10069+
parser->_i_st = &&Resp_HdrUpgradeV;
10070+
p += 7;
10071+
__FSM_MOVE_hdr_fixup(RGen_LWS, 1);
10072+
}
10073+
__FSM_MOVE(Resp_HdrU);
1006010074
case 'v':
1006110075
if (likely(__data_available(p, 5)
1006210076
&& C4_INT3_LCM(p + 1, 'a', 'r', 'y', ':')))
@@ -10229,6 +10243,10 @@ tfw_http_parse_resp(void *resp_data, unsigned char *data, size_t len,
1022910243
/* 'Pragma:*OWS' is read, process field-value. */
1023010244
__TFW_HTTP_PARSE_RAWHDR_VAL(Resp_HdrPragmaV, msg, __parse_pragma, 0);
1023110245

10246+
/* 'Upgrade:*OWS' is read, process field-value. */
10247+
__TFW_HTTP_PARSE_SPECHDR_VAL(Resp_HdrUpgradeV, msg, __parse_upgrade,
10248+
TFW_HTTP_HDR_UPGRADE, 0);
10249+
1023210250
/* 'Server:*OWS' is read, process field-value. */
1023310251
TFW_HTTP_PARSE_SPECHDR_VAL(Resp_HdrServerV, resp, __resp_parse_server,
1023410252
TFW_HTTP_HDR_SERVER);
@@ -10744,6 +10762,15 @@ tfw_http_parse_resp(void *resp_data, unsigned char *data, size_t len,
1074410762
__FSM_TX_AF(Resp_HdrWWW_Authenticat, 'e', Resp_HdrWWW_Authenticate);
1074510763
__FSM_TX_AF_OWS_HP(Resp_HdrWWW_Authenticate, RGen_HdrOtherV, 61);
1074610764

10765+
/* Upgrade header processing. */
10766+
__FSM_TX_AF(Resp_HdrU, 'p', Resp_HdrUp);
10767+
__FSM_TX_AF(Resp_HdrUp, 'g', Resp_HdrUpg);
10768+
__FSM_TX_AF(Resp_HdrUpg, 'r', Resp_HdrUpgr);
10769+
__FSM_TX_AF(Resp_HdrUpgr, 'a', Resp_HdrUpgra);
10770+
__FSM_TX_AF(Resp_HdrUpgra, 'd', Resp_HdrUpgrad);
10771+
__FSM_TX_AF(Resp_HdrUpgrad, 'e', Resp_HdrUpgrade);
10772+
__FSM_TX_AF_OWS(Resp_HdrUpgrade, Resp_HdrUpgradeV);
10773+
1074710774
__FSM_FINISH(resp);
1074810775

1074910776
return r;

0 commit comments

Comments
 (0)