summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjepett0 <[email protected]>2024-02-05 20:17:52 +0300
committerGitHub <[email protected]>2024-02-05 20:17:52 +0300
commit68211df2bd2640fb87c12ff0beeb959b28e2e8a4 (patch)
treeb514b0089629c32cebeba0579d56b86aad127b9f
parent134c08cf8135433102c751798bee4bddb2020d08 (diff)
Handle bad http headers in requests to YDB (#1542)
Header without a colon no longer crashes YDB
-rw-r--r--ydb/library/actors/http/http.cpp10
-rw-r--r--ydb/library/actors/http/http.h10
-rw-r--r--ydb/library/actors/http/http_ut.cpp42
3 files changed, 55 insertions, 7 deletions
diff --git a/ydb/library/actors/http/http.cpp b/ydb/library/actors/http/http.cpp
index 9da46e412bb..8a8e28fd394 100644
--- a/ydb/library/actors/http/http.cpp
+++ b/ydb/library/actors/http/http.cpp
@@ -119,8 +119,9 @@ void THttpParser<THttpRequest, TSocketBuffer>::Advance(size_t len) {
} else {
Stage = EParseStage::Done;
}
- } else {
- ProcessHeader(Header);
+ } else if (!ProcessHeader(Header)) {
+ Stage = EParseStage::Error;
+ break;
}
Headers = TStringBuf(Headers.data(), data.data() - Headers.data());
}
@@ -278,8 +279,9 @@ void THttpParser<THttpResponse, TSocketBuffer>::Advance(size_t len) {
} else {
Stage = EParseStage::Done;
}
- } else {
- ProcessHeader(Header);
+ } else if (!ProcessHeader(Header)) {
+ Stage = EParseStage::Error;
+ break;
}
Headers = TStringBuf(Headers.data(), data.data() - Headers.data());
}
diff --git a/ydb/library/actors/http/http.h b/ydb/library/actors/http/http.h
index d96ab062e89..47ba11cdcc1 100644
--- a/ydb/library/actors/http/http.h
+++ b/ydb/library/actors/http/http.h
@@ -291,16 +291,20 @@ public:
return target.size() == size;
}
- void ProcessHeader(TStringBuf& header) {
- TStringBuf name = header.NextTok(':');
+ bool ProcessHeader(TStringBuf& header) {
+ TStringBuf name;
+ TStringBuf value;
+ if (!header.TrySplit(':', name, value)) {
+ return false;
+ }
TrimBegin(name, ' ');
- TStringBuf value = header;
Trim(value, ' ');
auto cit = HeaderType::HeadersLocation.find(name);
if (cit != HeaderType::HeadersLocation.end()) {
this->*cit->second = value;
}
header.Clear();
+ return true;
}
size_t ParseHex(TStringBuf value) {
diff --git a/ydb/library/actors/http/http_ut.cpp b/ydb/library/actors/http/http_ut.cpp
index 6c92f3b938f..6a10b9d5192 100644
--- a/ydb/library/actors/http/http_ut.cpp
+++ b/ydb/library/actors/http/http_ut.cpp
@@ -50,6 +50,20 @@ Y_UNIT_TEST_SUITE(HttpProxy) {
UNIT_ASSERT_EQUAL(request->Headers, "Host: test\r\nSome-Header: 32344\r\n\r\n");
}
+ Y_UNIT_TEST(HeaderParsingError_Request) {
+ NHttp::THttpIncomingRequestPtr request = new NHttp::THttpIncomingRequest();
+ EatWholeString(request, "GET /test HTTP/1.1\r\nHost: test\r\nHeader-Without-A-Colon\r\n\r\n");
+ UNIT_ASSERT_C(request->IsError(), static_cast<int>(request->Stage));
+ UNIT_ASSERT_EQUAL_C(request->GetErrorText(), "Invalid http header", static_cast<int>(request->LastSuccessStage));
+ }
+
+ Y_UNIT_TEST(HeaderParsingError_Response) {
+ NHttp::THttpIncomingResponsePtr response = new NHttp::THttpIncomingResponse(nullptr);
+ EatWholeString(response, "HTTP/1.1 200 OK\r\nConnection: close\r\nHeader-Without-A-Colon\r\n\r\n");
+ UNIT_ASSERT_C(response->IsError(), static_cast<int>(response->Stage));
+ UNIT_ASSERT_EQUAL_C(response->GetErrorText(), "Invalid http header", static_cast<int>(response->LastSuccessStage));
+ }
+
Y_UNIT_TEST(GetWithSpecifiedContentType) {
NHttp::THttpIncomingRequestPtr request = new NHttp::THttpIncomingRequest();
EatWholeString(request, "GET /test HTTP/1.1\r\nHost: test\r\nContent-Type: application/json\r\nSome-Header: 32344\r\n\r\n");
@@ -506,4 +520,32 @@ CRA/5XcX13GJwHHj6LCoc3sL7mt8qV9HKY2AOZ88mpObzISZxgPpdKCfjsrdm63V
UNIT_ASSERT_EQUAL(response->Response->Status, "400");
UNIT_ASSERT_EQUAL(response->Response->Body, "Invalid http header");
}
+
+ Y_UNIT_TEST(HeaderWithoutAColon) {
+ NActors::TTestActorRuntimeBase actorSystem;
+ actorSystem.SetUseRealInterconnect();
+ TPortManager portManager;
+ TIpPort port = portManager.GetTcpPort();
+ TAutoPtr<NActors::IEventHandle> handle;
+ actorSystem.Initialize();
+
+ NActors::IActor* proxy = NHttp::CreateHttpProxy();
+ NActors::TActorId proxyId = actorSystem.Register(proxy);
+ actorSystem.Send(new NActors::IEventHandle(proxyId, actorSystem.AllocateEdgeActor(), new NHttp::TEvHttpProxy::TEvAddListeningPort(port)), 0, true);
+ actorSystem.GrabEdgeEvent<NHttp::TEvHttpProxy::TEvConfirmListen>(handle);
+
+ NActors::TActorId serverId = actorSystem.AllocateEdgeActor();
+ actorSystem.Send(new NActors::IEventHandle(proxyId, serverId, new NHttp::TEvHttpProxy::TEvRegisterHandler("/test", serverId)), 0, true);
+
+ NActors::TActorId clientId = actorSystem.AllocateEdgeActor();
+ NHttp::THttpOutgoingRequestPtr httpRequest = NHttp::THttpOutgoingRequest::CreateRequestGet("http://[::1]:" + ToString(port) + "/test");
+ httpRequest->Append("Header-Without-A-Colon\r\n");
+ httpRequest->FinishHeader();
+ actorSystem.Send(new NActors::IEventHandle(proxyId, clientId, new NHttp::TEvHttpProxy::TEvHttpOutgoingRequest(httpRequest)), 0, true);
+
+ NHttp::TEvHttpProxy::TEvHttpIncomingResponse* response = actorSystem.GrabEdgeEvent<NHttp::TEvHttpProxy::TEvHttpIncomingResponse>(handle);
+
+ UNIT_ASSERT_EQUAL(response->Response->Status, "400");
+ UNIT_ASSERT_EQUAL(response->Response->Body, "Invalid http header");
+ }
}