-
Notifications
You must be signed in to change notification settings - Fork 103
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Recreate upgrade headers for websocket request #1592
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2572,6 +2572,44 @@ tfw_http_set_hdr_date(TfwHttpMsg *hm) | |
return r; | ||
} | ||
|
||
/* | ||
* Add 'Upgrade:' header for websocket upgrade messages | ||
*/ | ||
static int | ||
tfw_http_set_hdr_upgrade(TfwHttpMsg *hm, bool is_resp) | ||
{ | ||
int r = 0; | ||
|
||
if (test_bit(TFW_HTTP_B_UPGRADE_WEBSOCKET, hm->flags)) { | ||
/* | ||
* RFC7230#section-6.7: | ||
* A server that sends a 101 (Switching Protocols) response | ||
* MUST send an Upgrade header field to indicate the new | ||
* protocol(s) to which the connection is being switched; if | ||
* multiple protocol layers are being switched, the sender MUST | ||
* list the protocols in layer-ascending order. | ||
* | ||
* We do expect neither upgrades besides 'websocket' nor | ||
* multilayer upgrades. So we consider extra options as error. | ||
*/ | ||
if (is_resp && ((TfwHttpResp *)hm)->status == 101 | ||
&& test_bit(TFW_HTTP_B_UPGRADE_EXTRA, hm->flags)) | ||
{ | ||
T_ERR("Unable to add uncompliant 'Upgrade:' header " | ||
"to msg [%p]\n", hm); | ||
return -EINVAL; | ||
} | ||
r = tfw_http_msg_hdr_xfrm(hm, "upgrade", SLEN("upgrade"), | ||
"websocket", SLEN("websocket"), | ||
TFW_HTTP_HDR_UPGRADE, 0); | ||
if (r) | ||
T_ERR("Unable to add Upgrade: header to msg [%p]\n", hm); | ||
else | ||
T_DBG2("Added Upgrade: header to msg [%p]\n", hm); | ||
krizhanovsky marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
return r; | ||
} | ||
|
||
/* | ||
* Expand HTTP response with 'Date:' header field. | ||
*/ | ||
|
@@ -2677,23 +2715,54 @@ tfw_http_expand_hbh(TfwHttpResp *resp, unsigned short status) | |
static int | ||
tfw_http_set_hdr_connection(TfwHttpMsg *hm, unsigned long conn_flg) | ||
{ | ||
int r; | ||
BUILD_BUG_ON(BIT_WORD(__TFW_HTTP_MSG_M_CONN) != 0); | ||
if (((hm->flags[0] & __TFW_HTTP_MSG_M_CONN) == conn_flg) | ||
&& (!TFW_STR_EMPTY(&hm->h_tbl->tbl[TFW_HTTP_HDR_CONNECTION])) | ||
&& !test_bit(TFW_HTTP_B_CONN_EXTRA, hm->flags)) | ||
&& !test_bit(TFW_HTTP_B_CONN_EXTRA, hm->flags) | ||
&& !test_bit(TFW_HTTP_B_CONN_UPGRADE, hm->flags)) | ||
{ | ||
return 0; | ||
} | ||
|
||
switch (conn_flg) { | ||
case BIT(TFW_HTTP_B_CONN_CLOSE): | ||
/* | ||
* We can see `TFW_HTTP_B_CONN_CLOSE` here only in case of 4XX | ||
* response with 'Connection: close' option. | ||
* | ||
* For requests conn_flg by default is TFW_HTTP_B_CONN_KA. | ||
*/ | ||
if (unlikely(conn_flg == BIT(TFW_HTTP_B_CONN_CLOSE))) | ||
return TFW_HTTP_MSG_HDR_XFRM(hm, "Connection", "close", | ||
TFW_HTTP_HDR_CONNECTION, 0); | ||
case BIT(TFW_HTTP_B_CONN_KA): | ||
return TFW_HTTP_MSG_HDR_XFRM(hm, "Connection", "keep-alive", | ||
TFW_HTTP_HDR_CONNECTION, 0); | ||
default: | ||
return TFW_HTTP_MSG_HDR_DEL(hm, "Connection", | ||
TFW_HTTP_HDR_CONNECTION); | ||
|
||
if (conn_flg == BIT(TFW_HTTP_B_CONN_KA)) { | ||
if (test_bit(TFW_HTTP_B_UPGRADE_WEBSOCKET, hm->flags) | ||
&& test_bit(TFW_HTTP_B_CONN_UPGRADE, hm->flags)) | ||
{ | ||
r = TFW_HTTP_MSG_HDR_XFRM(hm, "Connection", | ||
"keep-alive, upgrade", | ||
TFW_HTTP_HDR_CONNECTION, 0); | ||
} | ||
else { | ||
r = TFW_HTTP_MSG_HDR_XFRM(hm, "Connection", | ||
"keep-alive", | ||
TFW_HTTP_HDR_CONNECTION, 0); | ||
} | ||
} else { | ||
if (test_bit(TFW_HTTP_B_UPGRADE_WEBSOCKET, hm->flags) | ||
&& test_bit(TFW_HTTP_B_CONN_UPGRADE, hm->flags)) | ||
{ | ||
r = TFW_HTTP_MSG_HDR_XFRM(hm, "Connection", | ||
"upgrade", | ||
TFW_HTTP_HDR_CONNECTION, 0); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If we have There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. By default passed 0 in the function for responses, But for requests by default passed And semantically connection is keep-alive by default for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If we have May be that is right enough. |
||
} | ||
else { | ||
r = TFW_HTTP_MSG_HDR_DEL(hm, "Connection", | ||
TFW_HTTP_HDR_CONNECTION); | ||
} | ||
} | ||
|
||
return r; | ||
} | ||
|
||
/** | ||
|
@@ -3072,6 +3141,10 @@ tfw_h1_adjust_req(TfwHttpReq *req) | |
if (r < 0) | ||
return r; | ||
|
||
r = tfw_http_set_hdr_upgrade(hm, false); | ||
if (r < 0) | ||
return r; | ||
|
||
r = tfw_h1_set_loc_hdrs(hm, false, false); | ||
if (r < 0) | ||
return r; | ||
|
@@ -3642,6 +3715,10 @@ tfw_http_adjust_resp(TfwHttpResp *resp) | |
if (r < 0) | ||
return r; | ||
|
||
r = tfw_http_set_hdr_upgrade(hm, true); | ||
if (r < 0) | ||
return r; | ||
|
||
r = tfw_http_set_hdr_keep_alive(hm, conn_flg); | ||
if (r < 0) | ||
return r; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure if I understand this. It seems this is about https://datatracker.ietf.org/doc/html/rfc7230#section-6.7
This piece of code is for response with something extra plus to
websocket
inUpgrader
header. Since we can only generateUpgrade: websocket
in adjusted client request and server MUST NOT add anything non-requested, then what could be in the response for the extra? Can't we just always sendUpgrade: websocket
from the server to the client?If I'm wrong, then a good comment with the RFC cite is required in the place.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My intention was as follows:
We always strip upgrade header from response and re-add it when needed. So we do not just pass it through tempesta as is. But when we recreate headers would be beneficially to do simple sane check because we essentially hide backend and act on behalf on it.
Imaging erroneous backend that we on our discretion silently transform into compliant backend. That would be destructive if you ask me.
But this intention is, i understand, subtle and subjective. It is up to you if we need just alway send
Upgrade: websocket
.