aboutsummaryrefslogtreecommitdiffstats
path: root/library
diff options
context:
space:
mode:
authorAlexey Efimov <xeno@prnwatch.com>2022-05-18 19:23:33 +0300
committerAlexey Efimov <xeno@prnwatch.com>2022-05-18 19:23:33 +0300
commit90e99413865b0990ff8a5e35251074288bde15d9 (patch)
treeb5c17609b32840b95a50f755cdfbe0ab25fc55cb /library
parente1b4a8a09912622730eea7b2d3ca1267ef9dc135 (diff)
downloadydb-90e99413865b0990ff8a5e35251074288bde15d9.tar.gz
add support for mixed and ipv4-only environment KIKIMR-14869
ref:ec57c92c9ef01b8aad21861c915e620ec8823586
Diffstat (limited to 'library')
-rw-r--r--library/cpp/actors/http/http.h5
-rw-r--r--library/cpp/actors/http/http_config.h6
-rw-r--r--library/cpp/actors/http/http_proxy.cpp57
-rw-r--r--library/cpp/actors/http/http_proxy.h16
-rw-r--r--library/cpp/actors/http/http_proxy_acceptor.cpp27
-rw-r--r--library/cpp/actors/http/http_proxy_outgoing.cpp65
-rw-r--r--library/cpp/actors/http/http_proxy_sock64.h79
-rw-r--r--library/cpp/actors/http/http_proxy_sock_impl.h12
-rw-r--r--library/cpp/actors/http/http_ut.cpp36
9 files changed, 250 insertions, 53 deletions
diff --git a/library/cpp/actors/http/http.h b/library/cpp/actors/http/http.h
index 38e616cafa..2f11bfe04d 100644
--- a/library/cpp/actors/http/http.h
+++ b/library/cpp/actors/http/http.h
@@ -15,13 +15,14 @@ struct THash<TIntrusivePtr<Type>> {
};
template<>
-inline void Out<TSockAddrInet6>(IOutputStream& o, const TSockAddrInet6& x) {
- o << x.ToString();
+inline void Out<NHttp::THttpConfig::SocketAddressType>(IOutputStream& o, const NHttp::THttpConfig::SocketAddressType& x) {
+ o << x->ToString();
}
namespace NHttp {
bool IsIPv6(const TString& host);
+bool IsIPv4(const TString& host);
bool CrackURL(TStringBuf url, TStringBuf& scheme, TStringBuf& host, TStringBuf& uri);
void CrackAddress(const TString& address, TString& hostname, TIpPort& port);
void TrimBegin(TStringBuf& target, char delim);
diff --git a/library/cpp/actors/http/http_config.h b/library/cpp/actors/http/http_config.h
index faeff79449..1a2f8646a3 100644
--- a/library/cpp/actors/http/http_config.h
+++ b/library/cpp/actors/http/http_config.h
@@ -3,6 +3,8 @@
#include <library/cpp/actors/core/log.h>
#include <library/cpp/actors/protos/services_common.pb.h>
+class TInet64StreamSocket;
+
namespace NHttp {
struct THttpConfig {
@@ -12,8 +14,8 @@ struct THttpConfig {
static constexpr int LISTEN_QUEUE = 10;
static constexpr TDuration SOCKET_TIMEOUT = TDuration::MilliSeconds(60000);
static constexpr TDuration CONNECTION_TIMEOUT = TDuration::MilliSeconds(60000);
- using SocketType = TInet6StreamSocket;
- using SocketAddressType = TSockAddrInet6;
+ using SocketType = TInet64StreamSocket;
+ using SocketAddressType = std::shared_ptr<ISockAddr>;
};
}
diff --git a/library/cpp/actors/http/http_proxy.cpp b/library/cpp/actors/http/http_proxy.cpp
index e347a3e1c2..394cb17bd3 100644
--- a/library/cpp/actors/http/http_proxy.cpp
+++ b/library/cpp/actors/http/http_proxy.cpp
@@ -119,7 +119,7 @@ protected:
}
void Handle(TEvHttpProxy::TEvRegisterHandler::TPtr event, const NActors::TActorContext& ctx) {
- LOG_DEBUG_S(ctx, HttpLog, "Register handler " << event->Get()->Path << " to " << event->Get()->Handler);
+ LOG_TRACE_S(ctx, HttpLog, "Register handler " << event->Get()->Path << " to " << event->Get()->Handler);
Handlers[event->Get()->Path] = event->Get()->Handler;
}
@@ -131,11 +131,16 @@ protected:
TIpPort portPart = 0;
CrackAddress(host, addressPart, portPart);
if (IsIPv6(addressPart)) {
- TSockAddrInet6 address(addressPart.c_str(), portPart);
if (it == Hosts.end()) {
it = Hosts.emplace(host, THostEntry()).first;
}
- it->second.Address = address;
+ it->second.Address = std::make_shared<TSockAddrInet6>(addressPart.data(), portPart);
+ it->second.DeadlineTime = ctx.Now() + HostsTimeToLive;
+ } else if (IsIPv4(addressPart)) {
+ if (it == Hosts.end()) {
+ it = Hosts.emplace(host, THostEntry()).first;
+ }
+ it->second.Address = std::make_shared<TSockAddrInet>(addressPart.data(), portPart);
it->second.DeadlineTime = ctx.Now() + HostsTimeToLive;
} else {
// TODO(xenoxeno): move to another, possible blocking actor
@@ -143,21 +148,31 @@ protected:
const NDns::TResolvedHost* result = NDns::CachedResolve(NDns::TResolveInfo(addressPart, portPart));
if (result != nullptr) {
auto pAddr = result->Addr.Begin();
- while (pAddr != result->Addr.End() && pAddr->ai_family != AF_INET6) {
+ while (pAddr != result->Addr.End() && pAddr->ai_family != AF_INET && pAddr->ai_family != AF_INET6) {
++pAddr;
}
if (pAddr == result->Addr.End()) {
ctx.Send(event->Sender, new TEvHttpProxy::TEvResolveHostResponse("Invalid address family resolved"));
return;
}
- TSockAddrInet6 address = {};
- static_cast<sockaddr_in6&>(address) = *reinterpret_cast<sockaddr_in6*>(pAddr->ai_addr);
- LOG_DEBUG_S(ctx, HttpLog, "Host " << host << " resolved to " << address.ToString());
- if (it == Hosts.end()) {
- it = Hosts.emplace(host, THostEntry()).first;
+ THttpConfig::SocketAddressType address;
+ switch (pAddr->ai_family) {
+ case AF_INET:
+ address = std::make_shared<TSockAddrInet>();
+ break;
+ case AF_INET6:
+ address = std::make_shared<TSockAddrInet6>();
+ break;
+ }
+ if (address) {
+ memcpy(address->SockAddr(), pAddr->ai_addr, pAddr->ai_addrlen);
+ LOG_DEBUG_S(ctx, HttpLog, "Host " << host << " resolved to " << address->ToString());
+ if (it == Hosts.end()) {
+ it = Hosts.emplace(host, THostEntry()).first;
+ }
+ it->second.Address = address;
+ it->second.DeadlineTime = ctx.Now() + HostsTimeToLive;
}
- it->second.Address = address;
- it->second.DeadlineTime = ctx.Now() + HostsTimeToLive;
} else {
ctx.Send(event->Sender, new TEvHttpProxy::TEvResolveHostResponse("Error resolving host"));
return;
@@ -222,7 +237,7 @@ protected:
TVector<TActorId> Acceptors;
struct THostEntry {
- TSockAddrInet6 Address;
+ THttpConfig::SocketAddressType Address;
TInstant DeadlineTime;
};
@@ -259,7 +274,23 @@ NActors::IActor* CreateHttpProxy(std::weak_ptr<NMonitoring::TMetricRegistry> reg
}
bool IsIPv6(const TString& host) {
- return host.find_first_not_of(":0123456789abcdef") == TString::npos;
+ if (host.find_first_not_of(":0123456789abcdef") != TString::npos) {
+ return false;
+ }
+ if (std::count(host.begin(), host.end(), ':') < 2) {
+ return false;
+ }
+ return true;
+}
+
+bool IsIPv4(const TString& host) {
+ if (host.find_first_not_of(".0123456789") != TString::npos) {
+ return false;
+ }
+ if (std::count(host.begin(), host.end(), '.') != 3) {
+ return false;
+ }
+ return true;
}
bool CrackURL(TStringBuf url, TStringBuf& scheme, TStringBuf& host, TStringBuf& uri) {
diff --git a/library/cpp/actors/http/http_proxy.h b/library/cpp/actors/http/http_proxy.h
index bd907c13a7..b95954e561 100644
--- a/library/cpp/actors/http/http_proxy.h
+++ b/library/cpp/actors/http/http_proxy.h
@@ -11,6 +11,7 @@
#include <library/cpp/monlib/metrics/metric_registry.h>
#include <util/generic/variant.h>
#include "http.h"
+#include "http_proxy_sock64.h"
#include "http_proxy_ssl.h"
namespace NHttp {
@@ -18,6 +19,17 @@ namespace NHttp {
struct TSocketDescriptor : NActors::TSharedDescriptor, THttpConfig {
SocketType Socket;
+ TSocketDescriptor() = default;
+
+ TSocketDescriptor(int af)
+ : Socket(af)
+ {
+ }
+
+ TSocketDescriptor(SocketType&& s)
+ : Socket(std::move(s))
+ {}
+
int GetDescriptor() override {
return static_cast<SOCKET>(Socket);
}
@@ -188,10 +200,10 @@ struct TEvHttpProxy {
struct TEvResolveHostResponse : NActors::TEventLocal<TEvResolveHostResponse, EvResolveHostResponse> {
TString Host;
- TSockAddrInet6 Address;
+ THttpConfig::SocketAddressType Address;
TString Error;
- TEvResolveHostResponse(const TString& host, const TSockAddrInet6& address)
+ TEvResolveHostResponse(const TString& host, THttpConfig::SocketAddressType address)
: Host(host)
, Address(address)
{}
diff --git a/library/cpp/actors/http/http_proxy_acceptor.cpp b/library/cpp/actors/http/http_proxy_acceptor.cpp
index d74ef0abac..f73c239780 100644
--- a/library/cpp/actors/http/http_proxy_acceptor.cpp
+++ b/library/cpp/actors/http/http_proxy_acceptor.cpp
@@ -22,9 +22,9 @@ public:
, Socket(new TSocketDescriptor())
{
// for unit tests :(
- CheckedSetSockOpt(Socket->Socket, SOL_SOCKET, SO_REUSEADDR, (int)true, "reuse address");
+ SetSockOpt(Socket->Socket, SOL_SOCKET, SO_REUSEADDR, (int)true);
#ifdef SO_REUSEPORT
- CheckedSetSockOpt(Socket->Socket, SOL_SOCKET, SO_REUSEPORT, (int)true, "reuse port");
+ SetSockOpt(Socket->Socket, SOL_SOCKET, SO_REUSEPORT, (int)true);
#endif
}
@@ -45,7 +45,7 @@ protected:
}
void HandleInit(TEvHttpProxy::TEvAddListeningPort::TPtr event, const NActors::TActorContext& ctx) {
- SocketAddressType bindAddress(event->Get()->Address ? event->Get()->Address.data() : "::", event->Get()->Port);
+ SocketAddressType bindAddress(Socket->Socket.MakeAddress(event->Get()->Address,event->Get()->Port));
Endpoint = std::make_shared<TPrivateEndpointInfo>(event->Get()->CompressContentTypes);
Endpoint->Owner = ctx.SelfID;
Endpoint->Proxy = Owner;
@@ -64,12 +64,12 @@ protected:
}
}
if (err == 0) {
- err = Socket->Socket.Bind(&bindAddress);
+ err = Socket->Socket.Bind(bindAddress.get());
}
if (err == 0) {
err = Socket->Socket.Listen(LISTEN_QUEUE);
if (err == 0) {
- LOG_INFO_S(ctx, HttpLog, "Listening on " << bindAddress.ToString());
+ LOG_INFO_S(ctx, HttpLog, "Listening on " << bindAddress->ToString());
SetNonBlock(Socket->Socket);
ctx.Send(Poller, new NActors::TEvPollerRegister(Socket, SelfId(), SelfId()));
TBase::Become(&TAcceptorActor::StateListening);
@@ -77,7 +77,7 @@ protected:
return;
}
}
- LOG_WARN_S(ctx, HttpLog, "Failed to listen on " << bindAddress.ToString() << " - retrying...");
+ LOG_WARN_S(ctx, HttpLog, "Failed to listen on " << bindAddress->ToString() << " - retrying...");
ctx.ExecutorThread.Schedule(TDuration::Seconds(1), event.Release());
}
@@ -94,10 +94,13 @@ protected:
}
void Handle(NActors::TEvPollerReady::TPtr, const NActors::TActorContext& ctx) {
- TIntrusivePtr<TSocketDescriptor> socket = new TSocketDescriptor();
- SocketAddressType addr;
- int err;
- while ((err = Socket->Socket.Accept(&socket->Socket, &addr)) == 0) {
+ for (;;) {
+ SocketAddressType addr;
+ std::optional<SocketType> s = Socket->Socket.Accept(addr);
+ if (!s) {
+ break;
+ }
+ TIntrusivePtr<TSocketDescriptor> socket = new TSocketDescriptor(std::move(s).value());
NActors::IActor* connectionSocket = nullptr;
if (RecycledRequests.empty()) {
connectionSocket = CreateIncomingConnectionActor(Endpoint, socket, addr);
@@ -108,9 +111,9 @@ protected:
NActors::TActorId connectionId = ctx.Register(connectionSocket);
ctx.Send(Poller, new NActors::TEvPollerRegister(socket, connectionId, connectionId));
Connections.emplace(connectionId);
- socket = new TSocketDescriptor();
}
- if (err == -EAGAIN || err == -EWOULDBLOCK) { // request poller for further connection polling
+ int err = errno;
+ if (err == EAGAIN || err == EWOULDBLOCK) { // request poller for further connection polling
Y_VERIFY(PollerToken);
PollerToken->Request(true, false);
}
diff --git a/library/cpp/actors/http/http_proxy_outgoing.cpp b/library/cpp/actors/http/http_proxy_outgoing.cpp
index d9189dba8a..8866773016 100644
--- a/library/cpp/actors/http/http_proxy_outgoing.cpp
+++ b/library/cpp/actors/http/http_proxy_outgoing.cpp
@@ -25,8 +25,6 @@ public:
, Poller(poller)
, Host(host)
{
- TSocketImpl::SetNonBlock();
- TSocketImpl::SetTimeout(SOCKET_TIMEOUT);
}
void Die(const NActors::TActorContext& ctx) override {
@@ -35,18 +33,30 @@ public:
TBase::Die(ctx);
}
+ TString GetSocketName() {
+ TStringBuilder builder;
+ if (TSocketImpl::Socket) {
+ builder << "(#" << TSocketImpl::GetRawSocket();
+ if (Address && Address->SockAddr()->sa_family) {
+ builder << "," << Address;
+ }
+ builder << ") ";
+ }
+ return builder;
+ }
+
void ReplyAndDie(const NActors::TActorContext& ctx) {
- LOG_DEBUG_S(ctx, HttpLog, "(#" << TSocketImpl::GetRawSocket() << "," << Address << ") -> (" << Response->Status << " " << Response->Message << ")");
+ LOG_DEBUG_S(ctx, HttpLog, GetSocketName() << "-> (" << Response->Status << " " << Response->Message << ")");
ctx.Send(RequestOwner, new TEvHttpProxy::TEvHttpIncomingResponse(Request, Response));
RequestOwner = TActorId();
THolder<TEvHttpProxy::TEvReportSensors> sensors(BuildOutgoingRequestSensors(Request, Response));
ctx.Send(Owner, sensors.Release());
- LOG_DEBUG_S(ctx, HttpLog, "(#" << TSocketImpl::GetRawSocket() << "," << Address << ") connection closed");
+ LOG_DEBUG_S(ctx, HttpLog, GetSocketName() << "connection closed");
Die(ctx);
}
void ReplyErrorAndDie(const NActors::TActorContext& ctx, const TString& error) {
- LOG_ERROR_S(ctx, HttpLog, "(#" << TSocketImpl::GetRawSocket() << "," << Address << ") connection closed with error: " << error);
+ LOG_ERROR_S(ctx, HttpLog, GetSocketName() << "connection closed with error: " << error);
if (RequestOwner) {
ctx.Send(RequestOwner, new TEvHttpProxy::TEvHttpIncomingResponse(Request, Response, error));
RequestOwner = TActorId();
@@ -65,7 +75,10 @@ protected:
}
void Connect(const NActors::TActorContext& ctx) {
- LOG_DEBUG_S(ctx, HttpLog, "(#" << TSocketImpl::GetRawSocket() << "," << Address << ") connecting");
+ LOG_DEBUG_S(ctx, HttpLog, GetSocketName() << "connecting");
+ TSocketImpl::Create(Address->SockAddr()->sa_family);
+ TSocketImpl::SetNonBlock();
+ TSocketImpl::SetTimeout(ConnectionTimeout);
int res = TSocketImpl::Connect(Address);
RegisterPoller(ctx);
switch (-res) {
@@ -162,20 +175,41 @@ protected:
return ReplyErrorAndDie(ctx, strerror(-res));
}
}
- LOG_DEBUG_S(ctx, HttpLog, "(#" << TSocketImpl::GetRawSocket() << "," << Address << ") outgoing connection opened");
+ LOG_DEBUG_S(ctx, HttpLog, GetSocketName() << "outgoing connection opened");
TBase::Become(&TOutgoingConnectionActor::StateConnected);
- LOG_DEBUG_S(ctx, HttpLog, "(#" << TSocketImpl::GetRawSocket() << "," << Address << ") <- (" << Request->Method << " " << Request->URL << ")");
+ LOG_DEBUG_S(ctx, HttpLog, GetSocketName() << "<- (" << Request->Method << " " << Request->URL << ")");
ctx.Send(ctx.SelfID, new NActors::TEvPollerReady(nullptr, true, true));
}
+ static int GetPort(SocketAddressType address) {
+ switch (address->SockAddr()->sa_family) {
+ case AF_INET:
+ return ntohs(reinterpret_cast<sockaddr_in*>(address->SockAddr())->sin_port);
+ case AF_INET6:
+ return ntohs(reinterpret_cast<sockaddr_in6*>(address->SockAddr())->sin6_port);
+ }
+ return {};
+ }
+
+ static void SetPort(SocketAddressType address, int port) {
+ switch (address->SockAddr()->sa_family) {
+ case AF_INET:
+ reinterpret_cast<sockaddr_in*>(address->SockAddr())->sin_port = htons(port);
+ break;
+ case AF_INET6:
+ reinterpret_cast<sockaddr_in6*>(address->SockAddr())->sin6_port = htons(port);
+ break;
+ }
+ }
+
void HandleResolving(TEvHttpProxy::TEvResolveHostResponse::TPtr event, const NActors::TActorContext& ctx) {
LastActivity = ctx.Now();
if (!event->Get()->Error.empty()) {
return FailConnection(ctx, event->Get()->Error);
}
Address = event->Get()->Address;
- if (Address.GetPort() == 0) {
- Address.SetPort(Request->Secure ? 443 : 80);
+ if (GetPort(Address) == 0) {
+ SetPort(Address, Request->Secure ? 443 : 80);
}
Connect(ctx);
}
@@ -205,13 +239,12 @@ protected:
LastActivity = ctx.Now();
Request = std::move(event->Get()->Request);
Host = Request->Host;
- LOG_DEBUG_S(ctx, HttpLog, "(#" << TSocketImpl::GetRawSocket() << ") resolving " << Host);
+ LOG_DEBUG_S(ctx, HttpLog, GetSocketName() << "resolving " << Host);
Request->Timer.Reset();
RequestOwner = event->Sender;
ctx.Send(Owner, new TEvHttpProxy::TEvResolveHostRequest(Host));
if (event->Get()->Timeout) {
ConnectionTimeout = event->Get()->Timeout;
- TSocketImpl::SetTimeout(ConnectionTimeout);
}
ctx.Schedule(ConnectionTimeout, new NActors::TEvents::TEvWakeup());
LastActivity = ctx.Now();
@@ -220,12 +253,12 @@ protected:
void HandleConnected(NActors::TEvPollerReady::TPtr event, const NActors::TActorContext& ctx) {
LastActivity = ctx.Now();
- if (event->Get()->Read) {
- PullInput(ctx);
- }
- if (event->Get()->Write) {
+ if (event->Get()->Write && RequestOwner) {
FlushOutput(ctx);
}
+ if (event->Get()->Read && RequestOwner) {
+ PullInput(ctx);
+ }
}
void HandleConnected(NActors::TEvPollerRegisterResult::TPtr ev, const NActors::TActorContext& ctx) {
diff --git a/library/cpp/actors/http/http_proxy_sock64.h b/library/cpp/actors/http/http_proxy_sock64.h
new file mode 100644
index 0000000000..7f64a0f353
--- /dev/null
+++ b/library/cpp/actors/http/http_proxy_sock64.h
@@ -0,0 +1,79 @@
+#pragma once
+#include <util/network/sock.h>
+#include "http.h"
+
+class TInet64StreamSocket: public TStreamSocket {
+protected:
+ TInet64StreamSocket(const TInet64StreamSocket& parent, SOCKET fd)
+ : TStreamSocket(fd)
+ , AF(parent.AF)
+ {
+ }
+
+public:
+ TInet64StreamSocket(int af = {}) {
+ CreateSocket(af);
+ }
+
+ std::shared_ptr<ISockAddr> MakeAddress(const TString& address, int port) {
+ if (!address) {
+ if (AF == AF_INET6) {
+ return std::make_shared<TSockAddrInet6>("::", port);
+ } else {
+ return std::make_shared<TSockAddrInet>(INADDR_ANY, port);
+ }
+ }
+ if (NHttp::IsIPv6(address)) {
+ return std::make_shared<TSockAddrInet6>(address.data(), port);
+ } else {
+ return std::make_shared<TSockAddrInet>(address.data(), port);
+ }
+ }
+
+ static std::shared_ptr<ISockAddr> MakeAddress(const sockaddr_storage& storage) {
+ std::shared_ptr<ISockAddr> addr;
+ switch (storage.ss_family) {
+ case AF_INET:
+ addr = std::make_shared<TSockAddrInet>();
+ break;
+ case AF_INET6:
+ addr = std::make_shared<TSockAddrInet6>();
+ break;
+ }
+ if (addr) {
+ memcpy(addr->SockAddr(), &storage, addr->Size());
+ }
+ return addr;
+ }
+
+ std::optional<TInet64StreamSocket> Accept(std::shared_ptr<ISockAddr>& acceptedAddr) {
+ sockaddr_storage addrStorage = {};
+ socklen_t addrLen = sizeof(addrStorage);
+ SOCKET s = accept((SOCKET)*this, reinterpret_cast<sockaddr*>(&addrStorage), &addrLen);
+ if (s == INVALID_SOCKET) {
+ return {};
+ }
+ acceptedAddr = MakeAddress(addrStorage);
+ return TInet64StreamSocket(*this, s);
+ }
+
+protected:
+ int AF = 0;
+
+ void CreateSocket(int af) {
+ SOCKET s;
+ if (af == 0) {
+ s = socket(AF = AF_INET6, SOCK_STREAM, 0);
+ if (s < 0) {
+ s = socket(AF = AF_INET, SOCK_STREAM, 0);
+ }
+ } else {
+ s = socket(AF = af, SOCK_STREAM, 0);
+ }
+ if (AF == AF_INET6) {
+ SetSockOpt(s, SOL_SOCKET, IPV6_V6ONLY, (int)false);
+ }
+ TSocketHolder sock(s);
+ sock.Swap(*this);
+ }
+};
diff --git a/library/cpp/actors/http/http_proxy_sock_impl.h b/library/cpp/actors/http/http_proxy_sock_impl.h
index bd0a079dae..b5fd429462 100644
--- a/library/cpp/actors/http/http_proxy_sock_impl.h
+++ b/library/cpp/actors/http/http_proxy_sock_impl.h
@@ -8,9 +8,11 @@ namespace NHttp {
struct TPlainSocketImpl : virtual public THttpConfig {
TIntrusivePtr<TSocketDescriptor> Socket;
- TPlainSocketImpl()
- : Socket(new TSocketDescriptor())
- {}
+ TPlainSocketImpl() = default;
+
+ void Create(int af) {
+ Socket = new TSocketDescriptor(af);
+ }
TPlainSocketImpl(TIntrusivePtr<TSocketDescriptor> socket)
: Socket(std::move(socket))
@@ -41,8 +43,8 @@ struct TPlainSocketImpl : virtual public THttpConfig {
::shutdown(Socket->Socket, SHUT_RDWR);
}
- int Connect(const SocketAddressType& address) {
- return Socket->Socket.Connect(&address);
+ int Connect(SocketAddressType address) {
+ return Socket->Socket.Connect(address.get());
}
static constexpr int OnConnect(bool&, bool&) {
diff --git a/library/cpp/actors/http/http_ut.cpp b/library/cpp/actors/http/http_ut.cpp
index e87de6b6e1..ad3b49e869 100644
--- a/library/cpp/actors/http/http_ut.cpp
+++ b/library/cpp/actors/http/http_ut.cpp
@@ -186,12 +186,46 @@ Y_UNIT_TEST_SUITE(HttpProxy) {
UNIT_ASSERT_VALUES_EQUAL(requestData, "GET /data/url HTTP/1.1\r\nHost: www.yandex.ru\r\nAccept: */*\r\nCookie: cookie1=123456; cookie2=45678;\r\n");
}
- Y_UNIT_TEST(BasicRunning) {
+ Y_UNIT_TEST(BasicRunning4) {
NActors::TTestActorRuntimeBase actorSystem;
TPortManager portManager;
TIpPort port = portManager.GetTcpPort();
TAutoPtr<NActors::IEventHandle> handle;
actorSystem.Initialize();
+ actorSystem.SetLogPriority(NActorsServices::HTTP, NActors::NLog::PRI_DEBUG);
+
+ NActors::IActor* proxy = NHttp::CreateHttpProxy();
+ NActors::TActorId proxyId = actorSystem.Register(proxy);
+ actorSystem.Send(new NActors::IEventHandle(proxyId, TActorId(), new NHttp::TEvHttpProxy::TEvAddListeningPort(port)), 0, true);
+ actorSystem.DispatchEvents();
+
+ 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://127.0.0.1:" + ToString(port) + "/test");
+ actorSystem.Send(new NActors::IEventHandle(proxyId, clientId, new NHttp::TEvHttpProxy::TEvHttpOutgoingRequest(httpRequest)), 0, true);
+
+ NHttp::TEvHttpProxy::TEvHttpIncomingRequest* request = actorSystem.GrabEdgeEvent<NHttp::TEvHttpProxy::TEvHttpIncomingRequest>(handle);
+
+ UNIT_ASSERT_EQUAL(request->Request->URL, "/test");
+
+ NHttp::THttpOutgoingResponsePtr httpResponse = request->Request->CreateResponseString("HTTP/1.1 200 Found\r\nConnection: Close\r\nTransfer-Encoding: chunked\r\n\r\n6\r\npassed\r\n0\r\n\r\n");
+ actorSystem.Send(new NActors::IEventHandle(handle->Sender, serverId, new NHttp::TEvHttpProxy::TEvHttpOutgoingResponse(httpResponse)), 0, true);
+
+ NHttp::TEvHttpProxy::TEvHttpIncomingResponse* response = actorSystem.GrabEdgeEvent<NHttp::TEvHttpProxy::TEvHttpIncomingResponse>(handle);
+
+ UNIT_ASSERT_EQUAL(response->Response->Status, "200");
+ UNIT_ASSERT_EQUAL(response->Response->Body, "passed");
+ }
+
+ Y_UNIT_TEST(BasicRunning6) {
+ NActors::TTestActorRuntimeBase actorSystem;
+ TPortManager portManager;
+ TIpPort port = portManager.GetTcpPort();
+ TAutoPtr<NActors::IEventHandle> handle;
+ actorSystem.Initialize();
+ actorSystem.SetLogPriority(NActorsServices::HTTP, NActors::NLog::PRI_DEBUG);
NActors::IActor* proxy = NHttp::CreateHttpProxy();
NActors::TActorId proxyId = actorSystem.Register(proxy);