nghttpd: Issue RST_STREAM if content-length does not match uploaded bytes
This commit is contained in:
parent
22e41bab3f
commit
d142830109
|
@ -246,7 +246,8 @@ private:
|
|||
};
|
||||
|
||||
Stream::Stream(Http2Handler *handler, int32_t stream_id)
|
||||
: handler(handler), body_left(0), stream_id(stream_id), file(-1) {
|
||||
: handler(handler), body_left(0), upload_left(-1), stream_id(stream_id),
|
||||
file(-1) {
|
||||
auto config = handler->get_config();
|
||||
ev_timer_init(&rtimer, stream_timeout_cb, 0., config->stream_read_timeout);
|
||||
ev_timer_init(&wtimer, stream_timeout_cb, 0., config->stream_write_timeout);
|
||||
|
@ -1048,6 +1049,13 @@ int on_header_callback(nghttp2_session *session, const nghttp2_frame *frame,
|
|||
return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
|
||||
}
|
||||
|
||||
if (token == http2::HD_CONTENT_LENGTH) {
|
||||
auto upload_left = util::parse_uint(value, valuelen);
|
||||
if (upload_left != -1) {
|
||||
stream->upload_left = upload_left;
|
||||
}
|
||||
}
|
||||
|
||||
http2::index_header(stream->hdidx, token, stream->headers.size());
|
||||
http2::add_header(stream->headers, name, namelen, value, valuelen,
|
||||
flags & NGHTTP2_NV_FLAG_NO_INDEX);
|
||||
|
@ -1093,6 +1101,10 @@ int hd_on_frame_recv_callback(nghttp2_session *session,
|
|||
|
||||
if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
|
||||
remove_stream_read_timeout(stream);
|
||||
if (stream->upload_left > 0) {
|
||||
hd->submit_rst_stream(stream, NGHTTP2_PROTOCOL_ERROR);
|
||||
return 0;
|
||||
}
|
||||
if (!hd->get_config()->early_response) {
|
||||
prepare_response(stream, hd);
|
||||
}
|
||||
|
@ -1129,6 +1141,10 @@ int hd_on_frame_recv_callback(nghttp2_session *session,
|
|||
|
||||
if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
|
||||
remove_stream_read_timeout(stream);
|
||||
if (stream->upload_left > 0) {
|
||||
hd->submit_rst_stream(stream, NGHTTP2_PROTOCOL_ERROR);
|
||||
return 0;
|
||||
}
|
||||
if (!hd->get_config()->early_response) {
|
||||
prepare_response(stream, hd);
|
||||
}
|
||||
|
@ -1230,6 +1246,15 @@ int on_data_chunk_recv_callback(nghttp2_session *session, uint8_t flags,
|
|||
|
||||
// TODO Handle POST
|
||||
|
||||
if (stream->upload_left != -1) {
|
||||
if (stream->upload_left < len) {
|
||||
stream->upload_left = -1;
|
||||
hd->submit_rst_stream(stream, NGHTTP2_PROTOCOL_ERROR);
|
||||
return 0;
|
||||
}
|
||||
stream->upload_left -= len;
|
||||
}
|
||||
|
||||
add_stream_read_timeout(stream);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -81,6 +81,7 @@ struct Stream {
|
|||
ev_timer rtimer;
|
||||
ev_timer wtimer;
|
||||
int64_t body_left;
|
||||
int64_t upload_left;
|
||||
int32_t stream_id;
|
||||
int file;
|
||||
int hdidx[http2::HD_MAXIDX];
|
||||
|
|
|
@ -133,6 +133,7 @@ int main(int argc, char *argv[]) {
|
|||
shrpx::test_util_utos_with_unit) ||
|
||||
!CU_add_test(pSuite, "util_parse_uint_with_unit",
|
||||
shrpx::test_util_parse_uint_with_unit) ||
|
||||
!CU_add_test(pSuite, "util_parse_uint", shrpx::test_util_parse_uint) ||
|
||||
!CU_add_test(pSuite, "gzip_inflate", test_nghttp2_gzip_inflate) ||
|
||||
!CU_add_test(pSuite, "ringbuf_write", nghttp2::test_ringbuf_write) ||
|
||||
!CU_add_test(pSuite, "ringbuf_iovec", nghttp2::test_ringbuf_iovec) ||
|
||||
|
|
27
src/util.cc
27
src/util.cc
|
@ -950,6 +950,33 @@ int64_t parse_uint_with_unit(const char *s) {
|
|||
return n * mul;
|
||||
}
|
||||
|
||||
int64_t parse_uint(const char *s) {
|
||||
return parse_uint(reinterpret_cast<const uint8_t *>(s), strlen(s));
|
||||
}
|
||||
|
||||
int64_t parse_uint(const uint8_t *s, size_t len) {
|
||||
if (len == 0) {
|
||||
return -1;
|
||||
}
|
||||
constexpr int64_t max = std::numeric_limits<int64_t>::max();
|
||||
int64_t n = 0;
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
if ('0' <= s[i] && s[i] <= '9') {
|
||||
if (n > max / 10) {
|
||||
return -1;
|
||||
}
|
||||
n *= 10;
|
||||
if (n > max - (s[i] - '0')) {
|
||||
return -1;
|
||||
}
|
||||
n += s[i] - '0';
|
||||
continue;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
} // namespace util
|
||||
|
||||
} // namespace nghttp2
|
||||
|
|
|
@ -502,6 +502,11 @@ bool ipv6_numeric_addr(const char *host);
|
|||
// -1.
|
||||
int64_t parse_uint_with_unit(const char *s);
|
||||
|
||||
// Parses NULL terminated string |s| as unsigned integer and returns
|
||||
// the parsed integer. If there is an error, returns -1.
|
||||
int64_t parse_uint(const char *s);
|
||||
int64_t parse_uint(const uint8_t *s, size_t len);
|
||||
|
||||
} // namespace util
|
||||
|
||||
} // namespace nghttp2
|
||||
|
|
|
@ -207,4 +207,20 @@ void test_util_parse_uint_with_unit(void) {
|
|||
CU_ASSERT(-1 == util::parse_uint_with_unit(""));
|
||||
}
|
||||
|
||||
void test_util_parse_uint(void) {
|
||||
CU_ASSERT(0 == util::parse_uint("0"));
|
||||
CU_ASSERT(1023 == util::parse_uint("1023"));
|
||||
CU_ASSERT(-1 == util::parse_uint("1k"));
|
||||
CU_ASSERT(9223372036854775807LL == util::parse_uint("9223372036854775807"));
|
||||
// check overflow case
|
||||
CU_ASSERT(-1 == util::parse_uint("9223372036854775808"));
|
||||
CU_ASSERT(-1 == util::parse_uint("10000000000000000000"));
|
||||
// bad characters
|
||||
CU_ASSERT(-1 == util::parse_uint("1.1"));
|
||||
CU_ASSERT(-1 == util::parse_uint("1a"));
|
||||
CU_ASSERT(-1 == util::parse_uint("a1"));
|
||||
CU_ASSERT(-1 == util::parse_uint("1T"));
|
||||
CU_ASSERT(-1 == util::parse_uint(""));
|
||||
}
|
||||
|
||||
} // namespace shrpx
|
||||
|
|
|
@ -39,6 +39,7 @@ void test_util_select_h2(void);
|
|||
void test_util_ipv6_numeric_addr(void);
|
||||
void test_util_utos_with_unit(void);
|
||||
void test_util_parse_uint_with_unit(void);
|
||||
void test_util_parse_uint(void);
|
||||
|
||||
} // namespace shrpx
|
||||
|
||||
|
|
Loading…
Reference in New Issue