-
Notifications
You must be signed in to change notification settings - Fork 105
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
Fix request h2 -> http1.1 conversion #1374
Fix request h2 -> http1.1 conversion #1374
Conversation
470ae9f
to
ffc49a6
Compare
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.
Looks good to me, with minor cleanups.
tempesta_fw/http.c
Outdated
if (host) { | ||
h1_hdrs_sz -= ht->tbl[TFW_HTTP_HDR_HOST].len; | ||
h1_hdrs_sz -= SLEN(S_H2_AUTH); | ||
h1_hdrs_sz += SLEN(S_F_HOST); |
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.
Looks like excessive SLEN(S_DLM)
counted here for Host
header; it seems, that this size has already counted above, in the following code:
h1_hdrs_sz = pit->hdrs_len
+ (pit->hdrs_cnt - pseudo_num) * (SLEN(S_DLM) + SLEN(S_CRLF))
- req->mark.len;
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.
Fixed, please check once more time.
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 mean - from the previous code:
if (host) {
h1_hdrs_sz -= ht->tbl[TFW_HTTP_HDR_HOST].len;
h1_hdrs_sz -= SLEN(S_H2_AUTH);
h1_hdrs_sz += SLEN(S_F_HOST);
}
else {
h1_hdrs_sz -= SLEN(S_H2_AUTH);
h1_hdrs_sz += SLEN(S_F_HOST) + SLEN(S_CRLF);
}
just to make
if (host) {
h1_hdrs_sz -= ht->tbl[TFW_HTTP_HDR_HOST].len;
h1_hdrs_sz -= SLEN(S_H2_AUTH);
h1_hdrs_sz += SLEN(S_F_HOST) - SLEN(S_DLM);
}
else {
h1_hdrs_sz -= SLEN(S_H2_AUTH);
h1_hdrs_sz += SLEN(S_F_HOST) + SLEN(S_CRLF);
}
to evict SLEN(S_DLM)
length from SLEN(S_F_HOST)
, since SLEN(S_DLM)
for Host
header (as well as SLEN(S_CRLF)
) is already contained in h1_hdrs_sz
in case of Host
header existence in source HTTP/2-request.
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.
Let me clear up the calculations:
:authority
psedo-header is counted inh1_hdrs_sz
,- if
host
header is present it is counted inh1_hdrs_sz
andSLEN(S_DLM) + SLEN(S_CRLF)
was added.
So here we need to make some alterations (assuming that the :authority
pseudo header exists):
If the host
header exists, we replace its value with the :authority
ones. So we need to:
- subtract original length of
host
header and length ofS_DLM
andS_CRLF
added to it; - we need subtract difference between
:authority
andhost
length:
h1_hdrs_sz -= SLEN(S_H2_AUTH);
/* S_F_HOST already contains S_DLM, but we already calculated `S_DLM` for authority header. */
h1_hdrs_sz += SLEN(S_F_HOST) - SLEN(S_DLM);
If host header doesn't exist, the we only need to rename :authority
into host
.
That's why che calculations are done in current way.
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.
:authority psedo-header is counted in h1_hdrs_sz
Yes, but in previous version of code the :authority
pseudo-header had not been counted in pit->hdrs_cnt
(i.e. subtracted from it), so the SLEN(S_DLM) + SLEN(S_CRLF)
was not added for it and - that's why my previous comment appeared. But with last correction in 'fix header calculations' commit - it seems the problem is gone.
By the way: the pseudo_num
local variable is constant now and used only once, thus maybe it should be better to move its definition to the beginning of the function, or just evict it (and replace with 3
in the place of usage with adding appropriate comment there).
Main changes: 1. Keep h_tbl always valid since we need to read the table during response caching. 2. Optimize header alteration for h2, use compatibility mode for http1.1 3. Use tfw_msg_write functions to take care of all possible caveats at message creation stage. (E.g. headers may be longer than one page) Known issues: 1. Body and trailer conversion is not tested due to parsing issues: body is not appended to the request and WARN_ON is triggered.
ffc49a6
to
4f0356d
Compare
When tfw_http_msg_grow_hdr_tbl() is called it relocates the hm->ht, but all code around the call still uses the previous pointer. Thus changes are written to previous table, not current.
4f0356d
to
9a4c20c
Compare
- Don't switch fsm state on processing DATA frame header, update the fsm state only after the full DATA frame is processed. Otherwise the fsm is triggered twice and fsm closes the connection when a new portion of DATA frame is expected. - The HTTP2_STREAM_REM_HALF_CLOSED flag is set when the h2 frames are processed, this flag may be evalueted by http parser only when all the data from current h2 frame is parsed
Body it skb list by itself, so a new function is required.
h2 recipient will reject frame if it's too big for it. Honor remote peer settings when send messages, or fail fast otherwise, since the connection will be closed anyway.
553aa19
to
2ad4c3f
Compare
…renct additions of CRLF
Don't switch fsm state on processing frame header, update the fsm state only after the full frame is processed. Otherwise the fsm is triggered twice and fsm closes the connection when a new fragment of frame is expected.
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.
Looks good to me, with minor comments.
* by a CONTINUATION frame for the same stream. A receiver MUST treat | ||
* the receipt of any other type of frame or a frame on a different | ||
* stream as a connection error (Section 5.4.1) of type PROTOCOL_ERROR. | ||
*/ |
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.
The verification of HEADERS
/CONTINUATION
frame sequence is done in tfw_h2_stream_fsm()
. The different streams intersection can be verified here (in tfw_h2_frame_type_process()
) - e.g. via implementing the active_stream
number in TfwH2Ctx
structure, and setting/zeroing it for appropriate stream states in tfw_h2_stream_fsm()
.
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.
The verification of HEADERS/CONTINUATION frame sequence is done in tfw_h2_stream_fsm()
Yes, no problem there.
The different streams intersection
Yes, that is what I meant. If peer has sent a HEADER
frame without HEADERS_END
flag, then he can't sent messages on other streams until the headers are closed with CONTINUATION
frames followed by HEADERS_END
flag.
e.g. via implementing the active_stream number in TfwH2Ctx structure, and setting/zeroing it for appropriate stream states in tfw_h2_stream_fsm().
Seems like it's enough to set some ON_CONTINUATION
flag for the whole connection and check that the current stream ID is the same as the lstream_id
. Many variants are possible here. I didn't implemented it, but the tfw_h2_frame_type_process()
looks like a good candidate to place a TODO note, since all required information is available on this state.
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.
The problem with lstream_id
- is that it will not allow to handle this case for requests (i.e. streams) with HEADERS/CONTINUATION frames after DATA frames.
Main changes:
response caching. Keep the unsent skbs within request to avoid huge
updates of h_tbl
message creation stage. (E.g. headers may be longer than one page)
Known issues:
body is not appended to the request and WARN_ON is triggered.