aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorxenoxeno <xeno@ydb.tech>2022-11-17 13:36:18 +0300
committerxenoxeno <xeno@ydb.tech>2022-11-17 13:36:18 +0300
commit5d34ce409febec222f18d3aae7983a3c658967f4 (patch)
tree6cf8f293a0d6de3e2e8e8922955205c945992f60
parent53b9f0e219ca25b30531930fffc826f272fae1e3 (diff)
downloadydb-5d34ce409febec222f18d3aae7983a3c658967f4.tar.gz
fix node crash on bad content length parsing
-rw-r--r--library/cpp/actors/http/http.cpp28
1 files changed, 20 insertions, 8 deletions
diff --git a/library/cpp/actors/http/http.cpp b/library/cpp/actors/http/http.cpp
index 7057689b52..f5d7f5cf5c 100644
--- a/library/cpp/actors/http/http.cpp
+++ b/library/cpp/actors/http/http.cpp
@@ -22,6 +22,10 @@ inline TStringBuf operator +=(TStringBuf& l, TStringBuf r) {
return l = l + r;
}
+static bool is_not_number(TStringBuf v) {
+ return v.empty() || std::find_if_not(v.begin(), v.end(), [](unsigned char c) { return std::isdigit(c); }) != v.end();
+}
+
namespace NHttp {
template <> TStringBuf THttpRequest::GetName<&THttpRequest::Host>() { return "Host"; }
@@ -126,13 +130,16 @@ void THttpParser<THttpRequest, TSocketBuffer>::Advance(size_t len) {
[[fallthrough]];
}
case EParseStage::Body: {
- if (!ContentLength.empty()) {
- if (ProcessData(Content, data, FromString(ContentLength))) {
+ if (TEqNoCase()(TransferEncoding, "chunked")) {
+ Stage = EParseStage::ChunkLength;
+ } else if (!ContentLength.empty()) {
+ if (is_not_number(ContentLength)) {
+ // Invalid content length
+ Stage = EParseStage::Error;
+ } else if (ProcessData(Content, data, FromStringWithDefault(ContentLength, 0))) {
Body = Content;
Stage = EParseStage::Done;
}
- } else if (TEqNoCase()(TransferEncoding, "chunked")) {
- Stage = EParseStage::ChunkLength;
} else if (TotalSize.has_value()) {
if (ProcessData(Content, data, GetBodySizeFromTotalSize())) {
Body = Content;
@@ -282,16 +289,19 @@ void THttpParser<THttpResponse, TSocketBuffer>::Advance(size_t len) {
[[fallthrough]];
}
case EParseStage::Body: {
- if (!ContentLength.empty()) {
- if (ProcessData(Body, data, FromString(ContentLength))) {
+ if (TEqNoCase()(TransferEncoding, "chunked")) {
+ Stage = EParseStage::ChunkLength;
+ } else if (!ContentLength.empty()) {
+ if (is_not_number(ContentLength)) {
+ // Invalid content length
+ Stage = EParseStage::Error;
+ } else if (ProcessData(Body, data, FromStringWithDefault(ContentLength, 0))) {
Stage = EParseStage::Done;
if (Body && ContentEncoding == "deflate") {
Content = DecompressDeflate(Body);
Body = Content;
}
}
- } else if (TEqNoCase()(TransferEncoding, "chunked")) {
- Stage = EParseStage::ChunkLength;
} else if (TotalSize.has_value()) {
if (ProcessData(Content, data, GetBodySizeFromTotalSize())) {
Body = Content;
@@ -401,9 +411,11 @@ THttpOutgoingResponsePtr THttpIncomingRequest::CreateResponseString(TStringBuf d
}
}
}
+ headers.Erase("Transfer-Encoding"); // we erase transfer-encoding because we convert body to content-length
response->Set(headers);
response->SetBody(parser.Body);
} else {
+ headers.Erase("Transfer-Encoding"); // we erase transfer-encoding because we convert body to content-length
response->Set(headers);
if (!response->ContentLength) {
response->Set<&THttpResponse::ContentLength>("0");