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)
|
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();
|
auto config = handler->get_config();
|
||||||
ev_timer_init(&rtimer, stream_timeout_cb, 0., config->stream_read_timeout);
|
ev_timer_init(&rtimer, stream_timeout_cb, 0., config->stream_read_timeout);
|
||||||
ev_timer_init(&wtimer, stream_timeout_cb, 0., config->stream_write_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;
|
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::index_header(stream->hdidx, token, stream->headers.size());
|
||||||
http2::add_header(stream->headers, name, namelen, value, valuelen,
|
http2::add_header(stream->headers, name, namelen, value, valuelen,
|
||||||
flags & NGHTTP2_NV_FLAG_NO_INDEX);
|
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) {
|
if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
|
||||||
remove_stream_read_timeout(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) {
|
if (!hd->get_config()->early_response) {
|
||||||
prepare_response(stream, hd);
|
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) {
|
if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
|
||||||
remove_stream_read_timeout(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) {
|
if (!hd->get_config()->early_response) {
|
||||||
prepare_response(stream, hd);
|
prepare_response(stream, hd);
|
||||||
}
|
}
|
||||||
|
@ -1230,6 +1246,15 @@ int on_data_chunk_recv_callback(nghttp2_session *session, uint8_t flags,
|
||||||
|
|
||||||
// TODO Handle POST
|
// 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);
|
add_stream_read_timeout(stream);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -81,6 +81,7 @@ struct Stream {
|
||||||
ev_timer rtimer;
|
ev_timer rtimer;
|
||||||
ev_timer wtimer;
|
ev_timer wtimer;
|
||||||
int64_t body_left;
|
int64_t body_left;
|
||||||
|
int64_t upload_left;
|
||||||
int32_t stream_id;
|
int32_t stream_id;
|
||||||
int file;
|
int file;
|
||||||
int hdidx[http2::HD_MAXIDX];
|
int hdidx[http2::HD_MAXIDX];
|
||||||
|
|
|
@ -133,6 +133,7 @@ int main(int argc, char *argv[]) {
|
||||||
shrpx::test_util_utos_with_unit) ||
|
shrpx::test_util_utos_with_unit) ||
|
||||||
!CU_add_test(pSuite, "util_parse_uint_with_unit",
|
!CU_add_test(pSuite, "util_parse_uint_with_unit",
|
||||||
shrpx::test_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, "gzip_inflate", test_nghttp2_gzip_inflate) ||
|
||||||
!CU_add_test(pSuite, "ringbuf_write", nghttp2::test_ringbuf_write) ||
|
!CU_add_test(pSuite, "ringbuf_write", nghttp2::test_ringbuf_write) ||
|
||||||
!CU_add_test(pSuite, "ringbuf_iovec", nghttp2::test_ringbuf_iovec) ||
|
!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;
|
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 util
|
||||||
|
|
||||||
} // namespace nghttp2
|
} // namespace nghttp2
|
||||||
|
|
|
@ -502,6 +502,11 @@ bool ipv6_numeric_addr(const char *host);
|
||||||
// -1.
|
// -1.
|
||||||
int64_t parse_uint_with_unit(const char *s);
|
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 util
|
||||||
|
|
||||||
} // namespace nghttp2
|
} // namespace nghttp2
|
||||||
|
|
|
@ -207,4 +207,20 @@ void test_util_parse_uint_with_unit(void) {
|
||||||
CU_ASSERT(-1 == util::parse_uint_with_unit(""));
|
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
|
} // namespace shrpx
|
||||||
|
|
|
@ -39,6 +39,7 @@ void test_util_select_h2(void);
|
||||||
void test_util_ipv6_numeric_addr(void);
|
void test_util_ipv6_numeric_addr(void);
|
||||||
void test_util_utos_with_unit(void);
|
void test_util_utos_with_unit(void);
|
||||||
void test_util_parse_uint_with_unit(void);
|
void test_util_parse_uint_with_unit(void);
|
||||||
|
void test_util_parse_uint(void);
|
||||||
|
|
||||||
} // namespace shrpx
|
} // namespace shrpx
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue