Skip to content
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

Handle bad http headers in requests to YDB #1542

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions ydb/library/actors/http/http.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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());
}
Expand Down Expand Up @@ -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());
}
Expand Down
10 changes: 7 additions & 3 deletions ydb/library/actors/http/http.h
Original file line number Diff line number Diff line change
Expand Up @@ -291,16 +291,20 @@ class THttpParser : public HeaderType, public BufferType {
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) {
Expand Down
42 changes: 42 additions & 0 deletions ydb/library/actors/http/http_ut.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down Expand Up @@ -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");
}
}
Loading