aboutsummaryrefslogtreecommitdiffstats
path: root/library
diff options
context:
space:
mode:
authorAlexey Efimov <xeno@prnwatch.com>2022-02-10 16:49:41 +0300
committerDaniil Cherednik <dcherednik@yandex-team.ru>2022-02-10 16:49:41 +0300
commit26e0e4fb5e5cd6b4d7f4c21f9fcd7978891bf946 (patch)
treed34555f21d4d9f94f84d460e55b77d7eb41a953c /library
parentca3252a147a429eac4ba8221857493c58dcd09b5 (diff)
downloadydb-26e0e4fb5e5cd6b4d7f4c21f9fcd7978891bf946.tar.gz
Restoring authorship annotation for Alexey Efimov <xeno@prnwatch.com>. Commit 1 of 2.
Diffstat (limited to 'library')
-rw-r--r--library/cpp/actors/core/actor.h2
-rw-r--r--library/cpp/actors/core/actorsystem.h8
-rw-r--r--library/cpp/actors/core/event_local.h2
-rw-r--r--library/cpp/actors/core/event_pb.h104
-rw-r--r--library/cpp/actors/core/executor_pool_base.cpp8
-rw-r--r--library/cpp/actors/core/executor_pool_base.h2
-rw-r--r--library/cpp/actors/core/interconnect.h24
-rw-r--r--library/cpp/actors/core/log.cpp10
-rw-r--r--library/cpp/actors/core/mon.h40
-rw-r--r--library/cpp/actors/core/process_stats.cpp68
-rw-r--r--library/cpp/actors/core/process_stats.h102
-rw-r--r--library/cpp/actors/helpers/future_callback.h62
-rw-r--r--library/cpp/actors/helpers/ya.make2
-rw-r--r--library/cpp/actors/http/http.cpp1188
-rw-r--r--library/cpp/actors/http/http.h1394
-rw-r--r--library/cpp/actors/http/http_cache.cpp1178
-rw-r--r--library/cpp/actors/http/http_cache.h50
-rw-r--r--library/cpp/actors/http/http_config.h34
-rw-r--r--library/cpp/actors/http/http_proxy.cpp564
-rw-r--r--library/cpp/actors/http/http_proxy.h424
-rw-r--r--library/cpp/actors/http/http_proxy_acceptor.cpp210
-rw-r--r--library/cpp/actors/http/http_proxy_incoming.cpp376
-rw-r--r--library/cpp/actors/http/http_proxy_outgoing.cpp450
-rw-r--r--library/cpp/actors/http/http_proxy_sock_impl.h472
-rw-r--r--library/cpp/actors/http/http_proxy_ssl.h148
-rw-r--r--library/cpp/actors/http/http_static.cpp176
-rw-r--r--library/cpp/actors/http/http_static.h16
-rw-r--r--library/cpp/actors/http/http_ut.cpp632
-rw-r--r--library/cpp/actors/http/ut/ya.make26
-rw-r--r--library/cpp/actors/http/ya.make56
-rw-r--r--library/cpp/actors/interconnect/interconnect_common.h6
-rw-r--r--library/cpp/actors/interconnect/interconnect_tcp_server.cpp6
-rw-r--r--library/cpp/actors/protos/interconnect.proto4
-rw-r--r--library/cpp/actors/testlib/test_runtime.cpp272
-rw-r--r--library/cpp/actors/testlib/test_runtime.h120
-rw-r--r--library/cpp/grpc/client/grpc_client_low.h190
-rw-r--r--library/cpp/http/fetch/httpagent.h630
-rw-r--r--library/cpp/http/fetch/sockhandler.h260
-rw-r--r--library/cpp/http/io/stream.cpp18
-rw-r--r--library/cpp/http/ya.make2
-rw-r--r--library/cpp/messagebus/message.h4
-rw-r--r--library/cpp/monlib/service/mon_service_http_request.cpp74
-rw-r--r--library/cpp/monlib/service/mon_service_http_request.h6
-rw-r--r--library/cpp/monlib/service/monservice.cpp16
-rw-r--r--library/cpp/monlib/service/monservice.h20
-rw-r--r--library/cpp/monlib/service/pages/index_mon_page.cpp22
-rw-r--r--library/cpp/monlib/service/pages/index_mon_page.h2
-rw-r--r--library/cpp/monlib/service/pages/templates.h28
-rw-r--r--library/cpp/monlib/service/service.cpp70
-rw-r--r--library/cpp/monlib/service/service.h6
-rw-r--r--library/cpp/threading/future/core/future-inl.h22
-rw-r--r--library/cpp/threading/future/future_ut.cpp14
52 files changed, 4810 insertions, 4810 deletions
diff --git a/library/cpp/actors/core/actor.h b/library/cpp/actors/core/actor.h
index ed29bd14b9..dcdaf07e93 100644
--- a/library/cpp/actors/core/actor.h
+++ b/library/cpp/actors/core/actor.h
@@ -239,7 +239,7 @@ namespace NActors {
INTERCONNECT_POLLER = 285,
INTERCONNECT_SESSION_KILLER = 286,
ACTOR_SYSTEM_SCHEDULER_ACTOR = 312,
- ACTOR_FUTURE_CALLBACK = 337,
+ ACTOR_FUTURE_CALLBACK = 337,
INTERCONNECT_MONACTOR = 362,
INTERCONNECT_LOAD_ACTOR = 376,
INTERCONNECT_LOAD_RESPONDER = 377,
diff --git a/library/cpp/actors/core/actorsystem.h b/library/cpp/actors/core/actorsystem.h
index 40499d7586..48482dc66b 100644
--- a/library/cpp/actors/core/actorsystem.h
+++ b/library/cpp/actors/core/actorsystem.h
@@ -120,10 +120,10 @@ namespace NActors {
return TString();
}
- virtual ui32 GetThreads() const {
- return 1;
- }
-
+ virtual ui32 GetThreads() const {
+ return 1;
+ }
+
// generic
virtual TAffinity* Affinity() const = 0;
diff --git a/library/cpp/actors/core/event_local.h b/library/cpp/actors/core/event_local.h
index 2845aa94dd..a7870e10af 100644
--- a/library/cpp/actors/core/event_local.h
+++ b/library/cpp/actors/core/event_local.h
@@ -66,7 +66,7 @@ namespace NActors {
static IEventBase* Load(NActors::TEventSerializedData*) {
return new TEv();
}
-
+
static IEventBase* Load(const TString&) {
return new TEv();
}
diff --git a/library/cpp/actors/core/event_pb.h b/library/cpp/actors/core/event_pb.h
index d7546b901a..d104517e5d 100644
--- a/library/cpp/actors/core/event_pb.h
+++ b/library/cpp/actors/core/event_pb.h
@@ -157,7 +157,7 @@ namespace NActors {
TString ToString() const override {
return Record.ShortDebugString();
}
-
+
bool IsSerializable() const override {
return true;
}
@@ -422,72 +422,72 @@ namespace NActors {
return TypeName<TEv>() + " { " + TBase::Record.ShortDebugString() + " }";
}
};
-
- template <typename TEv, typename TRecord, ui32 TEventType>
+
+ template <typename TEv, typename TRecord, ui32 TEventType>
class TEventPreSerializedPB: public TEventPB<TEv, TRecord, TEventType> {
- protected:
- using TBase = TEventPB<TEv, TRecord, TEventType>;
- using TSelf = TEventPreSerializedPB<TEv, TRecord, TEventType>;
- using TBase::Record;
-
- public:
- TString PreSerializedData; // already serialized PB data (using message::SerializeToString)
-
- TEventPreSerializedPB() = default;
-
- explicit TEventPreSerializedPB(const TRecord& rec)
- : TBase(rec)
+ protected:
+ using TBase = TEventPB<TEv, TRecord, TEventType>;
+ using TSelf = TEventPreSerializedPB<TEv, TRecord, TEventType>;
+ using TBase::Record;
+
+ public:
+ TString PreSerializedData; // already serialized PB data (using message::SerializeToString)
+
+ TEventPreSerializedPB() = default;
+
+ explicit TEventPreSerializedPB(const TRecord& rec)
+ : TBase(rec)
{
}
-
- explicit TEventPreSerializedPB(TRecord&& rec)
- : TBase(std::move(rec))
+
+ explicit TEventPreSerializedPB(TRecord&& rec)
+ : TBase(std::move(rec))
{
}
-
- // when remote event received locally this method will merge preserialized data
- const TRecord& GetRecord() {
- TRecord& base(TBase::Record);
- if (!PreSerializedData.empty()) {
- TRecord copy;
+
+ // when remote event received locally this method will merge preserialized data
+ const TRecord& GetRecord() {
+ TRecord& base(TBase::Record);
+ if (!PreSerializedData.empty()) {
+ TRecord copy;
Y_PROTOBUF_SUPPRESS_NODISCARD copy.ParseFromString(PreSerializedData);
- copy.MergeFrom(base);
- base.Swap(&copy);
- PreSerializedData.clear();
- }
+ copy.MergeFrom(base);
+ base.Swap(&copy);
+ PreSerializedData.clear();
+ }
return TBase::Record;
- }
-
- const TRecord& GetRecord() const {
- return const_cast<TSelf*>(this)->GetRecord();
- }
-
- TRecord* MutableRecord() {
+ }
+
+ const TRecord& GetRecord() const {
+ return const_cast<TSelf*>(this)->GetRecord();
+ }
+
+ TRecord* MutableRecord() {
GetRecord(); // Make sure PreSerializedData is parsed
- return &(TBase::Record);
- }
-
- TString ToString() const override {
+ return &(TBase::Record);
+ }
+
+ TString ToString() const override {
return GetRecord().ShortDebugString();
- }
-
+ }
+
bool SerializeToArcadiaStream(TChunkSerializer* chunker) const override {
return chunker->WriteString(&PreSerializedData) && TBase::SerializeToArcadiaStream(chunker);
- }
-
- ui32 CalculateSerializedSize() const override {
- return PreSerializedData.size() + TBase::CalculateSerializedSize();
- }
-
- size_t GetCachedByteSize() const {
- return PreSerializedData.size() + TBase::GetCachedByteSize();
- }
+ }
+
+ ui32 CalculateSerializedSize() const override {
+ return PreSerializedData.size() + TBase::CalculateSerializedSize();
+ }
+
+ size_t GetCachedByteSize() const {
+ return PreSerializedData.size() + TBase::GetCachedByteSize();
+ }
ui32 CalculateSerializedSizeCached() const override {
return GetCachedByteSize();
}
- };
-
+ };
+
inline TActorId ActorIdFromProto(const NActorsProto::TActorId& actorId) {
return TActorId(actorId.GetRawX1(), actorId.GetRawX2());
}
diff --git a/library/cpp/actors/core/executor_pool_base.cpp b/library/cpp/actors/core/executor_pool_base.cpp
index c3b9999168..9d50d702e6 100644
--- a/library/cpp/actors/core/executor_pool_base.cpp
+++ b/library/cpp/actors/core/executor_pool_base.cpp
@@ -161,8 +161,8 @@ namespace NActors {
bool TExecutorPoolBaseMailboxed::Cleanup() {
return MailboxTable->Cleanup();
}
-
- ui32 TExecutorPoolBase::GetThreads() const {
- return PoolThreads;
- }
+
+ ui32 TExecutorPoolBase::GetThreads() const {
+ return PoolThreads;
+ }
}
diff --git a/library/cpp/actors/core/executor_pool_base.h b/library/cpp/actors/core/executor_pool_base.h
index c84ce1af77..7f19188ae1 100644
--- a/library/cpp/actors/core/executor_pool_base.h
+++ b/library/cpp/actors/core/executor_pool_base.h
@@ -42,7 +42,7 @@ namespace NActors {
~TExecutorPoolBase();
void ScheduleActivation(ui32 activation) override;
TAffinity* Affinity() const override;
- ui32 GetThreads() const override;
+ ui32 GetThreads() const override;
};
void DoActorInit(TActorSystem*, IActor*, const TActorId&, const TActorId&);
diff --git a/library/cpp/actors/core/interconnect.h b/library/cpp/actors/core/interconnect.h
index 679a4b8cc6..d71fe02c48 100644
--- a/library/cpp/actors/core/interconnect.h
+++ b/library/cpp/actors/core/interconnect.h
@@ -60,7 +60,7 @@ namespace NActors {
// protobuf-parser ctor
explicit TNodeLocation(const NActorsInterconnect::TNodeLocation& location);
-
+
// serialized protobuf ctor
static constexpr struct TFromSerialized {} FromSerialized {};
TNodeLocation(TFromSerialized, const TString& s);
@@ -114,7 +114,7 @@ namespace NActors {
friend bool operator > (const TNodeLocation& x, const TNodeLocation& y) { return x.Compare(y) > 0; }
friend bool operator >=(const TNodeLocation& x, const TNodeLocation& y) { return x.Compare(y) >= 0; }
};
-
+
struct TEvInterconnect {
enum EEv {
EvForward = EventSpaceBegin(TEvents::ES_INTERCONNECT),
@@ -177,7 +177,7 @@ namespace NActors {
struct TEvListNodes: public TEventLocal<TEvListNodes, EvListNodes> {
};
-
+
struct TNodeInfo {
ui32 NodeId;
TString Address;
@@ -185,10 +185,10 @@ namespace NActors {
TString ResolveHost;
ui16 Port;
TNodeLocation Location;
-
- TNodeInfo() = default;
- TNodeInfo(const TNodeInfo&) = default;
- TNodeInfo& operator =(const TNodeInfo&) = default;
+
+ TNodeInfo() = default;
+ TNodeInfo(const TNodeInfo&) = default;
+ TNodeInfo& operator =(const TNodeInfo&) = default;
TNodeInfo(ui32 nodeId,
const TString& address,
const TString& host,
@@ -203,12 +203,12 @@ namespace NActors {
, Location(location)
{
}
-
+
operator ui32() const {
return NodeId;
}
};
-
+
struct TEvNodesInfo: public TEventLocal<TEvNodesInfo, EvNodesInfo> {
TVector<TNodeInfo> Nodes;
@@ -218,8 +218,8 @@ namespace NActors {
return &x;
}
return nullptr;
- }
- };
+ }
+ };
struct TEvDisconnect;
@@ -251,5 +251,5 @@ namespace NActors {
struct TEvPoisonSession : TEventLocal<TEvPoisonSession, EvPoisonSession> {};
struct TEvTerminate : TEventLocal<TEvTerminate, EvTerminate> {};
- };
+ };
}
diff --git a/library/cpp/actors/core/log.cpp b/library/cpp/actors/core/log.cpp
index 5f63b5af58..312baa767a 100644
--- a/library/cpp/actors/core/log.cpp
+++ b/library/cpp/actors/core/log.cpp
@@ -11,7 +11,7 @@ static_assert(int(NActors::NLog::PRI_WARN) == int(::TLOG_WARNING), "expect int(N
static_assert(int(NActors::NLog::PRI_NOTICE) == int(::TLOG_NOTICE), "expect int(NActors::NLog::PRI_NOTICE) == int(::TLOG_NOTICE)");
static_assert(int(NActors::NLog::PRI_INFO) == int(::TLOG_INFO), "expect int(NActors::NLog::PRI_INFO) == int(::TLOG_INFO)");
static_assert(int(NActors::NLog::PRI_DEBUG) == int(::TLOG_DEBUG), "expect int(NActors::NLog::PRI_DEBUG) == int(::TLOG_DEBUG)");
-static_assert(int(NActors::NLog::PRI_TRACE) == int(::TLOG_RESOURCES), "expect int(NActors::NLog::PRI_TRACE) == int(::TLOG_RESOURCES)");
+static_assert(int(NActors::NLog::PRI_TRACE) == int(::TLOG_RESOURCES), "expect int(NActors::NLog::PRI_TRACE) == int(::TLOG_RESOURCES)");
namespace {
struct TRecordWithNewline {
@@ -441,7 +441,7 @@ namespace NActors {
str << "Change priority" << Endl;
}
UL() {
- for (int p = NLog::PRI_EMERG; p <= NLog::PRI_TRACE; ++p) {
+ for (int p = NLog::PRI_EMERG; p <= NLog::PRI_TRACE; ++p) {
LI() {
str << "<a href='logger?c=" << component << "&p=" << p << "'>"
<< NLog::PriorityToString(NLog::EPrio(p)) << "</a>";
@@ -452,7 +452,7 @@ namespace NActors {
str << "Change sampling priority" << Endl;
}
UL() {
- for (int p = NLog::PRI_EMERG; p <= NLog::PRI_TRACE; ++p) {
+ for (int p = NLog::PRI_EMERG; p <= NLog::PRI_TRACE; ++p) {
LI() {
str << "<a href='logger?c=" << component << "&sp=" << p << "'>"
<< NLog::PriorityToString(NLog::EPrio(p)) << "</a>";
@@ -515,7 +515,7 @@ namespace NActors {
}
}
TABLEBODY() {
- for (int p = NLog::PRI_EMERG; p <= NLog::PRI_TRACE; ++p) {
+ for (int p = NLog::PRI_EMERG; p <= NLog::PRI_TRACE; ++p) {
TABLER() {
TABLED() {
str << "<a href = 'logger?c=-1&p=" << p << "'>"
@@ -537,7 +537,7 @@ namespace NActors {
}
}
TABLEBODY() {
- for (int p = NLog::PRI_EMERG; p <= NLog::PRI_TRACE; ++p) {
+ for (int p = NLog::PRI_EMERG; p <= NLog::PRI_TRACE; ++p) {
TABLER() {
TABLED() {
str << "<a href = 'logger?c=-1&sp=" << p << "'>"
diff --git a/library/cpp/actors/core/mon.h b/library/cpp/actors/core/mon.h
index c450f2338e..d17b231107 100644
--- a/library/cpp/actors/core/mon.h
+++ b/library/cpp/actors/core/mon.h
@@ -12,7 +12,7 @@ namespace NActors {
HttpInfoRes,
RemoteHttpInfo,
RemoteHttpInfoRes,
- RemoteJsonInfoRes,
+ RemoteJsonInfoRes,
RemoteBinaryInfoRes,
End
};
@@ -28,14 +28,14 @@ namespace NActors {
}
TEvHttpInfo(const NMonitoring::IMonHttpRequest& request, const TString& userToken)
- : Request(request)
- , UserToken(userToken)
- , SubRequestId(0)
- {
- }
-
+ : Request(request)
+ , UserToken(userToken)
+ , SubRequestId(0)
+ {
+ }
+
const NMonitoring::IMonHttpRequest& Request;
- TString UserToken; // built and serialized
+ TString UserToken; // built and serialized
// SubRequestId != 0 means that we assemble reply from multiple parts and SubRequestId contains this part id
int SubRequestId;
};
@@ -168,22 +168,22 @@ namespace NActors {
struct TEvRemoteJsonInfoRes: public NActors::TEventBase<TEvRemoteJsonInfoRes, RemoteJsonInfoRes> {
TEvRemoteJsonInfoRes() {
}
-
+
TEvRemoteJsonInfoRes(const TString& json)
- : Json(json)
+ : Json(json)
{
}
-
+
TString Json;
-
+
TString ToStringHeader() const override {
- return "TEvRemoteJsonInfoRes";
- }
-
+ return "TEvRemoteJsonInfoRes";
+ }
+
bool SerializeToArcadiaStream(TChunkSerializer *serializer) const override {
return serializer->WriteString(&Json);
- }
-
+ }
+
ui32 CalculateSerializedSize() const override {
return Json.size();
}
@@ -194,9 +194,9 @@ namespace NActors {
static IEventBase* Load(TEventSerializedData* bufs) {
return new TEvRemoteJsonInfoRes(bufs->GetString());
- }
- };
-
+ }
+ };
+
struct TEvRemoteBinaryInfoRes: public NActors::TEventBase<TEvRemoteBinaryInfoRes, RemoteBinaryInfoRes> {
TEvRemoteBinaryInfoRes() {
}
diff --git a/library/cpp/actors/core/process_stats.cpp b/library/cpp/actors/core/process_stats.cpp
index 0e1dbd0031..688a9de6b3 100644
--- a/library/cpp/actors/core/process_stats.cpp
+++ b/library/cpp/actors/core/process_stats.cpp
@@ -1,7 +1,7 @@
#include "actorsystem.h"
#include "actor_bootstrapped.h"
#include "hfunc.h"
-#include "process_stats.h"
+#include "process_stats.h"
#include <library/cpp/monlib/dynamic_counters/counters.h>
#include <library/cpp/monlib/metrics/metric_registry.h>
@@ -44,8 +44,8 @@ namespace NActors {
bool TProcStat::Fill(pid_t pid) {
try {
- TString strPid(ToString(pid));
- TFileInput proc("/proc/" + strPid + "/status");
+ TString strPid(ToString(pid));
+ TFileInput proc("/proc/" + strPid + "/status");
TString str;
while (proc.ReadLine(str)) {
if (ExtractVal(str, "VmRSS:", Rss))
@@ -60,7 +60,7 @@ namespace NActors {
float tickPerMillisec = TicksPerMillisec();
- TFileInput procStat("/proc/" + strPid + "/stat");
+ TFileInput procStat("/proc/" + strPid + "/stat");
procStat.ReadLine(str);
if (!str.empty()) {
sscanf(str.data(),
@@ -78,7 +78,7 @@ namespace NActors {
Uptime = SystemUptime - TDuration::MilliSeconds(StartTime / TicksPerMillisec());
}
- TFileInput statm("/proc/" + strPid + "/statm");
+ TFileInput statm("/proc/" + strPid + "/statm");
statm.ReadLine(str);
TVector<TString> fields;
StringSplitter(str).Split(' ').SkipEmpty().Collect(&fields);
@@ -91,27 +91,27 @@ namespace NActors {
FileRss = shared * PageSize;
AnonRss = (resident - shared) * PageSize;
}
-
- TFileInput cgroup("/proc/" + strPid + "/cgroup");
- TString line;
- TString memoryCGroup;
- while (cgroup.ReadLine(line) > 0) {
- StringSplitter(line).Split(':').Collect(&fields);
- if (fields.size() > 2 && fields[1] == "memory") {
- memoryCGroup = fields[2];
- break;
- }
- }
- if (!memoryCGroup.empty()) {
- TFileInput limit("/sys/fs/cgroup/memory" + memoryCGroup + "/memory.limit_in_bytes");
- if (limit.ReadLine(line) > 0) {
- CGroupMemLim = FromString<ui64>(line);
- if (CGroupMemLim > (1ULL << 40)) {
- CGroupMemLim = 0;
- }
- }
- }
-
+
+ TFileInput cgroup("/proc/" + strPid + "/cgroup");
+ TString line;
+ TString memoryCGroup;
+ while (cgroup.ReadLine(line) > 0) {
+ StringSplitter(line).Split(':').Collect(&fields);
+ if (fields.size() > 2 && fields[1] == "memory") {
+ memoryCGroup = fields[2];
+ break;
+ }
+ }
+ if (!memoryCGroup.empty()) {
+ TFileInput limit("/sys/fs/cgroup/memory" + memoryCGroup + "/memory.limit_in_bytes");
+ if (limit.ReadLine(line) > 0) {
+ CGroupMemLim = FromString<ui64>(line);
+ if (CGroupMemLim > (1ULL << 40)) {
+ CGroupMemLim = 0;
+ }
+ }
+ }
+
} catch (...) {
return false;
}
@@ -191,7 +191,7 @@ namespace {
VmSize = ProcStatGroup->GetCounter("Process/VmSize", false);
AnonRssSize = ProcStatGroup->GetCounter("Process/AnonRssSize", false);
FileRssSize = ProcStatGroup->GetCounter("Process/FileRssSize", false);
- CGroupMemLimit = ProcStatGroup->GetCounter("Process/CGroupMemLimit", false);
+ CGroupMemLimit = ProcStatGroup->GetCounter("Process/CGroupMemLimit", false);
UserTime = ProcStatGroup->GetCounter("Process/UserTime", true);
SysTime = ProcStatGroup->GetCounter("Process/SystemTime", true);
MinorPageFaults = ProcStatGroup->GetCounter("Process/MinorPageFaults", true);
@@ -205,9 +205,9 @@ namespace {
*VmSize = procStat.Vsize;
*AnonRssSize = procStat.AnonRss;
*FileRssSize = procStat.FileRss;
- if (procStat.CGroupMemLim) {
- *CGroupMemLimit = procStat.CGroupMemLim;
- }
+ if (procStat.CGroupMemLim) {
+ *CGroupMemLimit = procStat.CGroupMemLim;
+ }
*UserTime = procStat.Utime;
*SysTime = procStat.Stime;
*MinorPageFaults = procStat.MinFlt;
@@ -222,7 +222,7 @@ namespace {
NMonitoring::TDynamicCounters::TCounterPtr VmSize;
NMonitoring::TDynamicCounters::TCounterPtr AnonRssSize;
NMonitoring::TDynamicCounters::TCounterPtr FileRssSize;
- NMonitoring::TDynamicCounters::TCounterPtr CGroupMemLimit;
+ NMonitoring::TDynamicCounters::TCounterPtr CGroupMemLimit;
NMonitoring::TDynamicCounters::TCounterPtr UserTime;
NMonitoring::TDynamicCounters::TCounterPtr SysTime;
NMonitoring::TDynamicCounters::TCounterPtr MinorPageFaults;
@@ -242,7 +242,7 @@ namespace {
VmSize = registry.IntGauge({{"sensor", "process.VmSize"}});
AnonRssSize = registry.IntGauge({{"sensor", "process.AnonRssSize"}});
FileRssSize = registry.IntGauge({{"sensor", "process.FileRssSize"}});
- CGroupMemLimit = registry.IntGauge({{"sensor", "process.CGroupMemLimit"}});
+ CGroupMemLimit = registry.IntGauge({{"sensor", "process.CGroupMemLimit"}});
UptimeSeconds = registry.IntGauge({{"sensor", "process.UptimeSeconds"}});
NumThreads = registry.IntGauge({{"sensor", "process.NumThreads"}});
SystemUptimeSeconds = registry.IntGauge({{"sensor", "system.UptimeSeconds"}});
@@ -257,7 +257,7 @@ namespace {
VmSize->Set(procStat.Vsize);
AnonRssSize->Set(procStat.AnonRss);
FileRssSize->Set(procStat.FileRss);
- CGroupMemLimit->Set(procStat.CGroupMemLim);
+ CGroupMemLimit->Set(procStat.CGroupMemLim);
UptimeSeconds->Set(procStat.Uptime.Seconds());
NumThreads->Set(procStat.NumThreads);
SystemUptimeSeconds->Set(procStat.SystemUptime.Seconds());
@@ -282,7 +282,7 @@ namespace {
NMonitoring::TIntGauge* VmSize;
NMonitoring::TIntGauge* AnonRssSize;
NMonitoring::TIntGauge* FileRssSize;
- NMonitoring::TIntGauge* CGroupMemLimit;
+ NMonitoring::TIntGauge* CGroupMemLimit;
NMonitoring::TRate* UserTime;
NMonitoring::TRate* SysTime;
NMonitoring::TRate* MinorPageFaults;
diff --git a/library/cpp/actors/core/process_stats.h b/library/cpp/actors/core/process_stats.h
index 66346d0b5a..7b329d6bb4 100644
--- a/library/cpp/actors/core/process_stats.h
+++ b/library/cpp/actors/core/process_stats.h
@@ -10,57 +10,57 @@ namespace NMonitoring {
}
namespace NActors {
- struct TProcStat {
- ui64 Rss;
- ui64 VolCtxSwtch;
- ui64 NonvolCtxSwtch;
-
- int Pid;
- char State;
- int Ppid;
- int Pgrp;
- int Session;
- int TtyNr;
- int TPgid;
- unsigned Flags;
- unsigned long MinFlt;
- unsigned long CMinFlt;
- unsigned long MajFlt;
- unsigned long CMajFlt;
- unsigned long Utime;
- unsigned long Stime;
- long CUtime;
- long CStime;
- long Priority;
- long Nice;
- long NumThreads;
- long ItRealValue;
- // StartTime is measured from system boot
- unsigned long long StartTime;
- unsigned long Vsize;
- long RssPages;
- unsigned long RssLim;
- ui64 FileRss;
- ui64 AnonRss;
- ui64 CGroupMemLim = 0;
-
- TDuration Uptime;
- TDuration SystemUptime;
- // ...
-
- TProcStat() {
- Zero(*this);
- Y_UNUSED(PageSize);
- }
-
- bool Fill(pid_t pid);
-
- private:
- long PageSize = 0;
-
- long ObtainPageSize();
- };
-
+ struct TProcStat {
+ ui64 Rss;
+ ui64 VolCtxSwtch;
+ ui64 NonvolCtxSwtch;
+
+ int Pid;
+ char State;
+ int Ppid;
+ int Pgrp;
+ int Session;
+ int TtyNr;
+ int TPgid;
+ unsigned Flags;
+ unsigned long MinFlt;
+ unsigned long CMinFlt;
+ unsigned long MajFlt;
+ unsigned long CMajFlt;
+ unsigned long Utime;
+ unsigned long Stime;
+ long CUtime;
+ long CStime;
+ long Priority;
+ long Nice;
+ long NumThreads;
+ long ItRealValue;
+ // StartTime is measured from system boot
+ unsigned long long StartTime;
+ unsigned long Vsize;
+ long RssPages;
+ unsigned long RssLim;
+ ui64 FileRss;
+ ui64 AnonRss;
+ ui64 CGroupMemLim = 0;
+
+ TDuration Uptime;
+ TDuration SystemUptime;
+ // ...
+
+ TProcStat() {
+ Zero(*this);
+ Y_UNUSED(PageSize);
+ }
+
+ bool Fill(pid_t pid);
+
+ private:
+ long PageSize = 0;
+
+ long ObtainPageSize();
+ };
+
IActor* CreateProcStatCollector(ui32 intervalSec, NMonitoring::TDynamicCounterPtr counters);
IActor* CreateProcStatCollector(TDuration interval, NMonitoring::TMetricRegistry& registry);
}
diff --git a/library/cpp/actors/helpers/future_callback.h b/library/cpp/actors/helpers/future_callback.h
index 8ca0d99fda..ecaf25d144 100644
--- a/library/cpp/actors/helpers/future_callback.h
+++ b/library/cpp/actors/helpers/future_callback.h
@@ -1,33 +1,33 @@
-#pragma once
-
+#pragma once
+
#include <library/cpp/actors/core/actor.h>
#include <library/cpp/actors/core/hfunc.h>
-
-namespace NActors {
-
-template <typename EventType>
-struct TActorFutureCallback : TActor<TActorFutureCallback<EventType>> {
- using TCallback = std::function<void(TAutoPtr<TEventHandle<EventType>>&)>;
- using TBase = TActor<TActorFutureCallback<EventType>>;
- TCallback Callback;
-
- static constexpr IActor::EActivityType ActorActivityType() {
- return IActor::ACTOR_FUTURE_CALLBACK;
- }
-
- TActorFutureCallback(TCallback&& callback)
- : TBase(&TActorFutureCallback::StateWaitForEvent)
- , Callback(std::move(callback))
- {}
-
- STRICT_STFUNC(StateWaitForEvent,
- HFunc(EventType, Handle)
- )
-
- void Handle(typename EventType::TPtr ev, const TActorContext& ctx) {
- Callback(ev);
- TBase::Die(ctx);
- }
-};
-
-} // NActors
+
+namespace NActors {
+
+template <typename EventType>
+struct TActorFutureCallback : TActor<TActorFutureCallback<EventType>> {
+ using TCallback = std::function<void(TAutoPtr<TEventHandle<EventType>>&)>;
+ using TBase = TActor<TActorFutureCallback<EventType>>;
+ TCallback Callback;
+
+ static constexpr IActor::EActivityType ActorActivityType() {
+ return IActor::ACTOR_FUTURE_CALLBACK;
+ }
+
+ TActorFutureCallback(TCallback&& callback)
+ : TBase(&TActorFutureCallback::StateWaitForEvent)
+ , Callback(std::move(callback))
+ {}
+
+ STRICT_STFUNC(StateWaitForEvent,
+ HFunc(EventType, Handle)
+ )
+
+ void Handle(typename EventType::TPtr ev, const TActorContext& ctx) {
+ Callback(ev);
+ TBase::Die(ctx);
+ }
+};
+
+} // NActors
diff --git a/library/cpp/actors/helpers/ya.make b/library/cpp/actors/helpers/ya.make
index d8771179de..e7302cea09 100644
--- a/library/cpp/actors/helpers/ya.make
+++ b/library/cpp/actors/helpers/ya.make
@@ -7,7 +7,7 @@ SRCS(
activeactors.h
flow_controlled_queue.cpp
flow_controlled_queue.h
- future_callback.h
+ future_callback.h
mon_histogram_helper.h
selfping_actor.cpp
)
diff --git a/library/cpp/actors/http/http.cpp b/library/cpp/actors/http/http.cpp
index 7125f9d8b0..90fdd161ed 100644
--- a/library/cpp/actors/http/http.cpp
+++ b/library/cpp/actors/http/http.cpp
@@ -1,116 +1,116 @@
-#include "http.h"
+#include "http.h"
#include <library/cpp/string_utils/quote/quote.h>
-
-inline TStringBuf operator +(TStringBuf l, TStringBuf r) {
- if (l.empty()) {
- return r;
- }
- if (r.empty()) {
- return l;
- }
- if (l.end() == r.begin()) {
- return TStringBuf(l.data(), l.size() + r.size());
- }
- if (r.end() == l.begin()) {
- return TStringBuf(r.data(), l.size() + r.size());
- }
- Y_FAIL("oops");
- return TStringBuf();
-}
-
-inline TStringBuf operator +=(TStringBuf& l, TStringBuf r) {
- return l = l + r;
-}
-
-namespace NHttp {
-
-template <> TStringBuf THttpRequest::GetName<&THttpRequest::Host>() { return "Host"; }
-template <> TStringBuf THttpRequest::GetName<&THttpRequest::Accept>() { return "Accept"; }
-template <> TStringBuf THttpRequest::GetName<&THttpRequest::Connection>() { return "Connection"; }
-template <> TStringBuf THttpRequest::GetName<&THttpRequest::ContentType>() { return "Content-Type"; }
-template <> TStringBuf THttpRequest::GetName<&THttpRequest::ContentLength>() { return "Content-Length"; }
-template <> TStringBuf THttpRequest::GetName<&THttpRequest::TransferEncoding>() { return "Transfer-Encoding"; }
-
-const TMap<TStringBuf, TStringBuf THttpRequest::*, TLessNoCase> THttpRequest::HeadersLocation = {
- { THttpRequest::GetName<&THttpRequest::Host>(), &THttpRequest::Host },
- { THttpRequest::GetName<&THttpRequest::Accept>(), &THttpRequest::Accept },
- { THttpRequest::GetName<&THttpRequest::Connection>(), &THttpRequest::Connection },
- { THttpRequest::GetName<&THttpRequest::ContentType>(), &THttpRequest::ContentType },
- { THttpRequest::GetName<&THttpRequest::ContentLength>(), &THttpRequest::ContentLength },
- { THttpRequest::GetName<&THttpRequest::TransferEncoding>(), &THttpRequest::TransferEncoding },
-};
-
-template <> TStringBuf THttpResponse::GetName<&THttpResponse::Connection>() { return "Connection"; }
-template <> TStringBuf THttpResponse::GetName<&THttpResponse::ContentType>() { return "Content-Type"; }
-template <> TStringBuf THttpResponse::GetName<&THttpResponse::ContentLength>() { return "Content-Length"; }
-template <> TStringBuf THttpResponse::GetName<&THttpResponse::TransferEncoding>() { return "Transfer-Encoding"; }
-template <> TStringBuf THttpResponse::GetName<&THttpResponse::LastModified>() { return "Last-Modified"; }
+
+inline TStringBuf operator +(TStringBuf l, TStringBuf r) {
+ if (l.empty()) {
+ return r;
+ }
+ if (r.empty()) {
+ return l;
+ }
+ if (l.end() == r.begin()) {
+ return TStringBuf(l.data(), l.size() + r.size());
+ }
+ if (r.end() == l.begin()) {
+ return TStringBuf(r.data(), l.size() + r.size());
+ }
+ Y_FAIL("oops");
+ return TStringBuf();
+}
+
+inline TStringBuf operator +=(TStringBuf& l, TStringBuf r) {
+ return l = l + r;
+}
+
+namespace NHttp {
+
+template <> TStringBuf THttpRequest::GetName<&THttpRequest::Host>() { return "Host"; }
+template <> TStringBuf THttpRequest::GetName<&THttpRequest::Accept>() { return "Accept"; }
+template <> TStringBuf THttpRequest::GetName<&THttpRequest::Connection>() { return "Connection"; }
+template <> TStringBuf THttpRequest::GetName<&THttpRequest::ContentType>() { return "Content-Type"; }
+template <> TStringBuf THttpRequest::GetName<&THttpRequest::ContentLength>() { return "Content-Length"; }
+template <> TStringBuf THttpRequest::GetName<&THttpRequest::TransferEncoding>() { return "Transfer-Encoding"; }
+
+const TMap<TStringBuf, TStringBuf THttpRequest::*, TLessNoCase> THttpRequest::HeadersLocation = {
+ { THttpRequest::GetName<&THttpRequest::Host>(), &THttpRequest::Host },
+ { THttpRequest::GetName<&THttpRequest::Accept>(), &THttpRequest::Accept },
+ { THttpRequest::GetName<&THttpRequest::Connection>(), &THttpRequest::Connection },
+ { THttpRequest::GetName<&THttpRequest::ContentType>(), &THttpRequest::ContentType },
+ { THttpRequest::GetName<&THttpRequest::ContentLength>(), &THttpRequest::ContentLength },
+ { THttpRequest::GetName<&THttpRequest::TransferEncoding>(), &THttpRequest::TransferEncoding },
+};
+
+template <> TStringBuf THttpResponse::GetName<&THttpResponse::Connection>() { return "Connection"; }
+template <> TStringBuf THttpResponse::GetName<&THttpResponse::ContentType>() { return "Content-Type"; }
+template <> TStringBuf THttpResponse::GetName<&THttpResponse::ContentLength>() { return "Content-Length"; }
+template <> TStringBuf THttpResponse::GetName<&THttpResponse::TransferEncoding>() { return "Transfer-Encoding"; }
+template <> TStringBuf THttpResponse::GetName<&THttpResponse::LastModified>() { return "Last-Modified"; }
template <> TStringBuf THttpResponse::GetName<&THttpResponse::ContentEncoding>() { return "Content-Encoding"; }
-
-const TMap<TStringBuf, TStringBuf THttpResponse::*, TLessNoCase> THttpResponse::HeadersLocation = {
- { THttpResponse::GetName<&THttpResponse::Connection>(), &THttpResponse::Connection },
- { THttpResponse::GetName<&THttpResponse::ContentType>(), &THttpResponse::ContentType },
- { THttpResponse::GetName<&THttpResponse::ContentLength>(), &THttpResponse::ContentLength },
- { THttpResponse::GetName<&THttpResponse::TransferEncoding>(), &THttpResponse::TransferEncoding },
- { THttpResponse::GetName<&THttpResponse::LastModified>(), &THttpResponse::LastModified },
+
+const TMap<TStringBuf, TStringBuf THttpResponse::*, TLessNoCase> THttpResponse::HeadersLocation = {
+ { THttpResponse::GetName<&THttpResponse::Connection>(), &THttpResponse::Connection },
+ { THttpResponse::GetName<&THttpResponse::ContentType>(), &THttpResponse::ContentType },
+ { THttpResponse::GetName<&THttpResponse::ContentLength>(), &THttpResponse::ContentLength },
+ { THttpResponse::GetName<&THttpResponse::TransferEncoding>(), &THttpResponse::TransferEncoding },
+ { THttpResponse::GetName<&THttpResponse::LastModified>(), &THttpResponse::LastModified },
{ THttpResponse::GetName<&THttpResponse::ContentEncoding>(), &THttpResponse::ContentEncoding }
-};
-
-void THttpRequest::Clear() {
- // a dirty little trick
- this->~THttpRequest(); // basically, do nothing
- new (this) THttpRequest(); // reset all fields
-}
-
-template <>
-void THttpParser<THttpRequest, TSocketBuffer>::Advance(size_t len) {
- TStringBuf data(Pos(), len);
- while (!data.empty()) {
- if (Stage != EParseStage::Error) {
- LastSuccessStage = Stage;
- }
- switch (Stage) {
- case EParseStage::Method: {
- if (ProcessData(Method, data, ' ', MaxMethodSize)) {
- Stage = EParseStage::URL;
- }
- break;
- }
- case EParseStage::URL: {
- if (ProcessData(URL, data, ' ', MaxURLSize)) {
- Stage = EParseStage::Protocol;
- }
- break;
- }
- case EParseStage::Protocol: {
- if (ProcessData(Protocol, data, '/', MaxProtocolSize)) {
- Stage = EParseStage::Version;
- }
- break;
- }
- case EParseStage::Version: {
- if (ProcessData(Version, data, "\r\n", MaxVersionSize)) {
- Stage = EParseStage::Header;
- Headers = data;
- }
- break;
- }
- case EParseStage::Header: {
- if (ProcessData(Header, data, "\r\n", MaxHeaderSize)) {
- if (Header.empty()) {
- Headers = TStringBuf(Headers.data(), data.begin() - Headers.begin());
- if (HaveBody()) {
- Stage = EParseStage::Body;
- } else {
- Stage = EParseStage::Done;
- }
- } else {
- ProcessHeader(Header);
- }
- }
- break;
- }
- case EParseStage::Body: {
+};
+
+void THttpRequest::Clear() {
+ // a dirty little trick
+ this->~THttpRequest(); // basically, do nothing
+ new (this) THttpRequest(); // reset all fields
+}
+
+template <>
+void THttpParser<THttpRequest, TSocketBuffer>::Advance(size_t len) {
+ TStringBuf data(Pos(), len);
+ while (!data.empty()) {
+ if (Stage != EParseStage::Error) {
+ LastSuccessStage = Stage;
+ }
+ switch (Stage) {
+ case EParseStage::Method: {
+ if (ProcessData(Method, data, ' ', MaxMethodSize)) {
+ Stage = EParseStage::URL;
+ }
+ break;
+ }
+ case EParseStage::URL: {
+ if (ProcessData(URL, data, ' ', MaxURLSize)) {
+ Stage = EParseStage::Protocol;
+ }
+ break;
+ }
+ case EParseStage::Protocol: {
+ if (ProcessData(Protocol, data, '/', MaxProtocolSize)) {
+ Stage = EParseStage::Version;
+ }
+ break;
+ }
+ case EParseStage::Version: {
+ if (ProcessData(Version, data, "\r\n", MaxVersionSize)) {
+ Stage = EParseStage::Header;
+ Headers = data;
+ }
+ break;
+ }
+ case EParseStage::Header: {
+ if (ProcessData(Header, data, "\r\n", MaxHeaderSize)) {
+ if (Header.empty()) {
+ Headers = TStringBuf(Headers.data(), data.begin() - Headers.begin());
+ if (HaveBody()) {
+ Stage = EParseStage::Body;
+ } else {
+ Stage = EParseStage::Done;
+ }
+ } else {
+ ProcessHeader(Header);
+ }
+ }
+ break;
+ }
+ case EParseStage::Body: {
if (!ContentLength.empty()) {
if (ProcessData(Content, data, FromString(ContentLength))) {
Body = Content;
@@ -121,9 +121,9 @@ void THttpParser<THttpRequest, TSocketBuffer>::Advance(size_t len) {
} else {
// Invalid body encoding
Stage = EParseStage::Error;
- }
- break;
- }
+ }
+ break;
+ }
case EParseStage::ChunkLength: {
if (ProcessData(Line, data, "\r\n", MaxChunkLengthSize)) {
if (!Line.empty()) {
@@ -170,484 +170,484 @@ void THttpParser<THttpRequest, TSocketBuffer>::Advance(size_t len) {
break;
}
- case EParseStage::Done:
- case EParseStage::Error: {
- data.Clear();
- break;
- }
- default:
- Y_FAIL("Invalid processing sequence");
- break;
- }
- }
- TSocketBuffer::Advance(len);
-}
-
-template <>
-THttpParser<THttpRequest, TSocketBuffer>::EParseStage THttpParser<THttpRequest, TSocketBuffer>::GetInitialStage() {
- return EParseStage::Method;
-}
-
-template <>
-THttpParser<THttpResponse, TSocketBuffer>::EParseStage THttpParser<THttpResponse, TSocketBuffer>::GetInitialStage() {
- return EParseStage::Protocol;
-}
-
-void THttpResponse::Clear() {
- // a dirty little trick
- this->~THttpResponse(); // basically, do nothing
- new (this) THttpResponse(); // reset all fields
-}
-
-template <>
-void THttpParser<THttpResponse, TSocketBuffer>::Advance(size_t len) {
- TStringBuf data(Pos(), len);
- while (!data.empty()) {
- if (Stage != EParseStage::Error) {
- LastSuccessStage = Stage;
- }
- switch (Stage) {
- case EParseStage::Protocol: {
- if (ProcessData(Protocol, data, '/', MaxProtocolSize)) {
- Stage = EParseStage::Version;
- }
- break;
- }
- case EParseStage::Version: {
- if (ProcessData(Version, data, ' ', MaxVersionSize)) {
- Stage = EParseStage::Status;
- }
- break;
- }
- case EParseStage::Status: {
- if (ProcessData(Status, data, ' ', MaxStatusSize)) {
- Stage = EParseStage::Message;
- }
- break;
- }
- case EParseStage::Message: {
- if (ProcessData(Message, data, "\r\n", MaxMessageSize)) {
- Stage = EParseStage::Header;
- Headers = TStringBuf(data.data(), size_t(0));
- }
- break;
- }
- case EParseStage::Header: {
- if (ProcessData(Header, data, "\r\n", MaxHeaderSize)) {
- if (Header.empty()) {
- if (HaveBody() && (ContentLength.empty() || ContentLength != "0")) {
- Stage = EParseStage::Body;
- } else {
- Stage = EParseStage::Done;
- }
- } else {
- ProcessHeader(Header);
- }
- Headers = TStringBuf(Headers.data(), data.data() - Headers.data());
- }
- break;
- }
- case EParseStage::Body: {
- if (!ContentLength.empty()) {
- if (ProcessData(Body, data, FromString(ContentLength))) {
- Stage = EParseStage::Done;
- }
- } else if (TransferEncoding == "chunked") {
- Stage = EParseStage::ChunkLength;
- } else {
- // Invalid body encoding
- Stage = EParseStage::Error;
- }
- break;
- }
- case EParseStage::ChunkLength: {
- if (ProcessData(Line, data, "\r\n", MaxChunkLengthSize)) {
- if (!Line.empty()) {
- ChunkLength = ParseHex(Line);
- if (ChunkLength <= MaxChunkSize) {
- ContentSize = Content.size() + ChunkLength;
- if (ContentSize <= MaxChunkContentSize) {
- Stage = EParseStage::ChunkData;
- Line.Clear();
- } else {
- // Invalid chunk content length
- Stage = EParseStage::Error;
- }
- } else {
- // Invalid chunk length
- Stage = EParseStage::Error;
- }
- } else {
- // Invalid body encoding
- Stage = EParseStage::Error;
- }
- }
- break;
- }
- case EParseStage::ChunkData: {
- if (!IsError()) {
- if (ProcessData(Content, data, ContentSize)) {
- if (ProcessData(Line, data, 2)) {
- if (Line == "\r\n") {
- if (ChunkLength == 0) {
- Body = Content;
- Stage = EParseStage::Done;
- } else {
- Stage = EParseStage::ChunkLength;
- }
- Line.Clear();
- } else {
- // Invalid body encoding
- Stage = EParseStage::Error;
- }
- }
- }
- }
- break;
- }
- case EParseStage::Done:
- case EParseStage::Error:
- data.Clear();
- break;
- default:
- // Invalid processing sequence
- Stage = EParseStage::Error;
- break;
- }
- }
- TSocketBuffer::Advance(len);
-}
-
-template <>
-void THttpParser<THttpResponse, TSocketBuffer>::ConnectionClosed() {
- if (Stage == EParseStage::Done) {
- return;
- }
- if (Stage == EParseStage::Body) {
- // ?
- Stage = EParseStage::Done;
- } else {
- LastSuccessStage = Stage;
- Stage = EParseStage::Error;
- }
-}
-
-THttpOutgoingResponsePtr THttpIncomingRequest::CreateResponseString(TStringBuf data) {
- THttpOutgoingResponsePtr response = new THttpOutgoingResponse(this);
- response->Append(data);
- response->Reparse();
- return response;
-}
-
-THttpOutgoingResponsePtr THttpIncomingRequest::CreateResponseOK(TStringBuf body, TStringBuf contentType, TInstant lastModified) {
- return CreateResponse("200", "OK", contentType, body, lastModified);
-}
-
-THttpOutgoingResponsePtr THttpIncomingRequest::CreateResponseBadRequest(TStringBuf html, TStringBuf contentType) {
- if (html.empty() && IsError()) {
- contentType = "text/plain";
- html = GetErrorText();
- }
- return CreateResponse("400", "Bad Request", contentType, html);
-}
-
-THttpOutgoingResponsePtr THttpIncomingRequest::CreateResponseNotFound(TStringBuf html, TStringBuf contentType) {
- return CreateResponse("404", "Not Found", contentType, html);
-}
-
-THttpOutgoingResponsePtr THttpIncomingRequest::CreateResponseServiceUnavailable(TStringBuf html, TStringBuf contentType) {
- return CreateResponse("503", "Service Unavailable", contentType, html);
-}
-
-THttpOutgoingResponsePtr THttpIncomingRequest::CreateResponseGatewayTimeout(TStringBuf html, TStringBuf contentType) {
- return CreateResponse("504", "Gateway Timeout", contentType, html);
-}
-
-THttpIncomingResponse::THttpIncomingResponse(THttpOutgoingRequestPtr request)
- : Request(request)
-{}
-
-THttpOutgoingResponsePtr THttpIncomingRequest::CreateResponse(TStringBuf status, TStringBuf message, TStringBuf contentType, TStringBuf body, TInstant lastModified) {
- TStringBuf version = Version;
- if (version != "1.0" && version != "1.1") {
- version = "1.1";
- }
- THttpOutgoingResponsePtr response = new THttpOutgoingResponse(this, "HTTP", version, status, message);
- response->Set<&THttpResponse::Connection>(GetConnection());
- if (!WorkerName.empty()) {
- response->Set("X-Worker-Name", WorkerName);
- }
- if (!contentType.empty() && !body.empty()) {
- response->Set<&THttpResponse::ContentType>(contentType);
- }
- if (lastModified) {
- response->Set<&THttpResponse::LastModified>(lastModified.FormatGmTime("%a, %d %b %Y %H:%M:%S GMT"));
- }
- if (response->IsNeedBody() || !body.empty()) {
- if (Method == "HEAD") {
- response->Set<&THttpResponse::ContentLength>(ToString(body.size()));
- } else {
- response->Set<&THttpResponse::Body>(body);
- }
- }
- return response;
-}
-
-THttpIncomingRequestPtr THttpIncomingRequest::Duplicate() {
- THttpIncomingRequestPtr request = new THttpIncomingRequest(*this);
- request->Reparse();
- request->Timer.Reset();
- return request;
-}
-
-THttpIncomingResponsePtr THttpIncomingResponse::Duplicate(THttpOutgoingRequestPtr request) {
- THttpIncomingResponsePtr response = new THttpIncomingResponse(*this);
- response->Reparse();
- response->Request = request;
- return response;
-}
-
-THttpOutgoingResponsePtr THttpOutgoingResponse::Duplicate(THttpIncomingRequestPtr request) {
- THttpOutgoingResponsePtr response = new THttpOutgoingResponse(*this);
- response->Reparse();
- response->Request = request;
- return response;
-}
-
-
-THttpOutgoingResponsePtr THttpIncomingResponse::Reverse(THttpIncomingRequestPtr request) {
- THttpOutgoingResponsePtr response = new THttpOutgoingResponse(request);
- response->Assign(Data(), Size());
- response->Reparse();
- return response;
-}
-
-THttpOutgoingRequest::THttpOutgoingRequest(TStringBuf method, TStringBuf scheme, TStringBuf host, TStringBuf uri, TStringBuf protocol, TStringBuf version) {
- Secure = (scheme == "https");
- TString urie = UrlEscapeRet(uri);
- InitRequest(method, urie, protocol, version);
- if (host) {
- Set<&THttpRequest::Host>(host);
- }
-}
-
-THttpOutgoingRequest::THttpOutgoingRequest(TStringBuf method, TStringBuf url, TStringBuf protocol, TStringBuf version) {
- TStringBuf scheme, host, uri;
- if (!CrackURL(url, scheme, host, uri)) {
- Y_FAIL("Invalid URL specified");
- }
- if (!scheme.empty() && scheme != "http" && scheme != "https") {
- Y_FAIL("Invalid URL specified");
- }
- Secure = (scheme == "https");
- TString urie = UrlEscapeRet(uri);
- InitRequest(method, urie, protocol, version);
- if (host) {
- Set<&THttpRequest::Host>(host);
- }
-}
-
-THttpOutgoingRequestPtr THttpOutgoingRequest::CreateRequestString(const TString& data) {
- THttpOutgoingRequestPtr request = new THttpOutgoingRequest();
- request->Assign(data.data(), data.size());
- request->Reparse();
- return request;
-}
-
-THttpOutgoingRequestPtr THttpOutgoingRequest::CreateRequestGet(TStringBuf url) {
- return CreateRequest("GET", url);
-}
-
-THttpOutgoingRequestPtr THttpOutgoingRequest::CreateRequestGet(TStringBuf host, TStringBuf uri) {
- return CreateHttpRequest("GET", host, uri);
-}
-
-THttpOutgoingRequestPtr THttpOutgoingRequest::CreateRequestPost(TStringBuf url, TStringBuf contentType, TStringBuf body) {
- return CreateRequest("POST", url, contentType, body);
-}
-
-THttpOutgoingRequestPtr THttpOutgoingRequest::CreateRequestPost(TStringBuf host, TStringBuf uri, TStringBuf contentType, TStringBuf body) {
- return CreateHttpRequest("POST", host, uri, contentType, body);
-}
-
-THttpOutgoingRequestPtr THttpOutgoingRequest::CreateRequest(TStringBuf method, TStringBuf url, TStringBuf contentType, TStringBuf body) {
- THttpOutgoingRequestPtr request = new THttpOutgoingRequest(method, url, "HTTP", "1.1");
- request->Set<&THttpRequest::Accept>("*/*");
- if (!contentType.empty()) {
- request->Set<&THttpRequest::ContentType>(contentType);
- request->Set<&THttpRequest::Body>(body);
- }
- return request;
-}
-
-THttpOutgoingRequestPtr THttpOutgoingRequest::CreateHttpRequest(TStringBuf method, TStringBuf host, TStringBuf uri, TStringBuf contentType, TStringBuf body) {
- THttpOutgoingRequestPtr request = new THttpOutgoingRequest(method, "http", host, uri, "HTTP", "1.1");
- request->Set<&THttpRequest::Accept>("*/*");
- if (!contentType.empty()) {
- request->Set<&THttpRequest::ContentType>(contentType);
- request->Set<&THttpRequest::Body>(body);
- }
- return request;
-}
-
-THttpOutgoingRequestPtr THttpOutgoingRequest::Duplicate() {
- THttpOutgoingRequestPtr request = new THttpOutgoingRequest(*this);
- request->Reparse();
- return request;
-}
-
-THttpOutgoingResponse::THttpOutgoingResponse(THttpIncomingRequestPtr request)
- : Request(request)
-{}
-
-THttpOutgoingResponse::THttpOutgoingResponse(THttpIncomingRequestPtr request, TStringBuf protocol, TStringBuf version, TStringBuf status, TStringBuf message)
- : Request(request)
-{
- InitResponse(protocol, version, status, message);
-}
-
-const size_t THttpConfig::BUFFER_MIN_STEP;
-const TDuration THttpConfig::CONNECTION_TIMEOUT;
-
-TUrlParameters::TUrlParameters(TStringBuf url) {
- TStringBuf base;
- TStringBuf params;
- if (url.TrySplit('?', base, params)) {
- for (TStringBuf param = params.NextTok('&'); !param.empty(); param = params.NextTok('&')) {
- TStringBuf name = param.NextTok('=');
- Parameters[name] = param;
- }
- }
-}
-
-TString TUrlParameters::operator [](TStringBuf name) const {
- TString value(Get(name));
- CGIUnescape(value);
- return value;
-}
-
-bool TUrlParameters::Has(TStringBuf name) const {
- return Parameters.count(name) != 0;
-}
-
-TStringBuf TUrlParameters::Get(TStringBuf name) const {
- auto it = Parameters.find(name);
- if (it != Parameters.end()) {
- return it->second;
- }
- return TStringBuf();
-}
-
-TString TUrlParameters::Render() const {
- TStringBuilder parameters;
- for (const std::pair<TStringBuf, TStringBuf> parameter : Parameters) {
- if (parameters.empty()) {
- parameters << '?';
- } else {
- parameters << '&';
- }
- parameters << parameter.first;
- parameters << '=';
- parameters << parameter.second;
- }
- return parameters;
-}
-
-TCookies::TCookies(TStringBuf cookie) {
- for (TStringBuf param = cookie.NextTok(';'); !param.empty(); param = cookie.NextTok(';')) {
- param.SkipPrefix(" ");
- TStringBuf name = param.NextTok('=');
- Cookies[name] = param;
- }
-}
-
-TStringBuf TCookies::operator [](TStringBuf name) const {
- return Get(name);
-}
-
-bool TCookies::Has(TStringBuf name) const {
- return Cookies.count(name) != 0;
-}
-
-TStringBuf TCookies::Get(TStringBuf name) const {
- auto it = Cookies.find(name);
- if (it != Cookies.end()) {
- return it->second;
- }
- return TStringBuf();
-}
-
-TString TCookies::Render() const {
- TStringBuilder cookies;
- for (const std::pair<TStringBuf, TStringBuf> cookie : Cookies) {
- if (!cookies.empty()) {
- cookies << ' ';
- }
- cookies << cookie.first;
- cookies << '=';
- cookies << cookie.second;
- cookies << ';';
- }
- return cookies;
-}
-
-TCookiesBuilder::TCookiesBuilder()
- :TCookies(TStringBuf())
-{}
-
-void TCookiesBuilder::Set(TStringBuf name, TStringBuf data) {
- Data.emplace_back(name, data);
- Cookies[Data.back().first] = Data.back().second;
-}
-
-THeaders::THeaders(TStringBuf headers) {
- for (TStringBuf param = headers.NextTok("\r\n"); !param.empty(); param = headers.NextTok("\r\n")) {
- TStringBuf name = param.NextTok(":");
- param.SkipPrefix(" ");
- Headers[name] = param;
- }
-}
-
-TStringBuf THeaders::operator [](TStringBuf name) const {
- return Get(name);
-}
-
-bool THeaders::Has(TStringBuf name) const {
- return Headers.count(name) != 0;
-}
-
-TStringBuf THeaders::Get(TStringBuf name) const {
- auto it = Headers.find(name);
- if (it != Headers.end()) {
- return it->second;
- }
- return TStringBuf();
-}
-
-TString THeaders::Render() const {
- TStringBuilder headers;
- for (const std::pair<TStringBuf, TStringBuf> header : Headers) {
- headers << header.first;
- headers << ": ";
- headers << header.second;
- headers << "\r\n";
- }
- return headers;
-}
-
-THeadersBuilder::THeadersBuilder()
- :THeaders(TStringBuf())
-{}
-
-THeadersBuilder::THeadersBuilder(const THeadersBuilder& builder) {
- for (const auto& pr : builder.Headers) {
- Set(pr.first, pr.second);
- }
-}
-
-void THeadersBuilder::Set(TStringBuf name, TStringBuf data) {
- Data.emplace_back(name, data);
- Headers[Data.back().first] = Data.back().second;
-}
-
-}
+ case EParseStage::Done:
+ case EParseStage::Error: {
+ data.Clear();
+ break;
+ }
+ default:
+ Y_FAIL("Invalid processing sequence");
+ break;
+ }
+ }
+ TSocketBuffer::Advance(len);
+}
+
+template <>
+THttpParser<THttpRequest, TSocketBuffer>::EParseStage THttpParser<THttpRequest, TSocketBuffer>::GetInitialStage() {
+ return EParseStage::Method;
+}
+
+template <>
+THttpParser<THttpResponse, TSocketBuffer>::EParseStage THttpParser<THttpResponse, TSocketBuffer>::GetInitialStage() {
+ return EParseStage::Protocol;
+}
+
+void THttpResponse::Clear() {
+ // a dirty little trick
+ this->~THttpResponse(); // basically, do nothing
+ new (this) THttpResponse(); // reset all fields
+}
+
+template <>
+void THttpParser<THttpResponse, TSocketBuffer>::Advance(size_t len) {
+ TStringBuf data(Pos(), len);
+ while (!data.empty()) {
+ if (Stage != EParseStage::Error) {
+ LastSuccessStage = Stage;
+ }
+ switch (Stage) {
+ case EParseStage::Protocol: {
+ if (ProcessData(Protocol, data, '/', MaxProtocolSize)) {
+ Stage = EParseStage::Version;
+ }
+ break;
+ }
+ case EParseStage::Version: {
+ if (ProcessData(Version, data, ' ', MaxVersionSize)) {
+ Stage = EParseStage::Status;
+ }
+ break;
+ }
+ case EParseStage::Status: {
+ if (ProcessData(Status, data, ' ', MaxStatusSize)) {
+ Stage = EParseStage::Message;
+ }
+ break;
+ }
+ case EParseStage::Message: {
+ if (ProcessData(Message, data, "\r\n", MaxMessageSize)) {
+ Stage = EParseStage::Header;
+ Headers = TStringBuf(data.data(), size_t(0));
+ }
+ break;
+ }
+ case EParseStage::Header: {
+ if (ProcessData(Header, data, "\r\n", MaxHeaderSize)) {
+ if (Header.empty()) {
+ if (HaveBody() && (ContentLength.empty() || ContentLength != "0")) {
+ Stage = EParseStage::Body;
+ } else {
+ Stage = EParseStage::Done;
+ }
+ } else {
+ ProcessHeader(Header);
+ }
+ Headers = TStringBuf(Headers.data(), data.data() - Headers.data());
+ }
+ break;
+ }
+ case EParseStage::Body: {
+ if (!ContentLength.empty()) {
+ if (ProcessData(Body, data, FromString(ContentLength))) {
+ Stage = EParseStage::Done;
+ }
+ } else if (TransferEncoding == "chunked") {
+ Stage = EParseStage::ChunkLength;
+ } else {
+ // Invalid body encoding
+ Stage = EParseStage::Error;
+ }
+ break;
+ }
+ case EParseStage::ChunkLength: {
+ if (ProcessData(Line, data, "\r\n", MaxChunkLengthSize)) {
+ if (!Line.empty()) {
+ ChunkLength = ParseHex(Line);
+ if (ChunkLength <= MaxChunkSize) {
+ ContentSize = Content.size() + ChunkLength;
+ if (ContentSize <= MaxChunkContentSize) {
+ Stage = EParseStage::ChunkData;
+ Line.Clear();
+ } else {
+ // Invalid chunk content length
+ Stage = EParseStage::Error;
+ }
+ } else {
+ // Invalid chunk length
+ Stage = EParseStage::Error;
+ }
+ } else {
+ // Invalid body encoding
+ Stage = EParseStage::Error;
+ }
+ }
+ break;
+ }
+ case EParseStage::ChunkData: {
+ if (!IsError()) {
+ if (ProcessData(Content, data, ContentSize)) {
+ if (ProcessData(Line, data, 2)) {
+ if (Line == "\r\n") {
+ if (ChunkLength == 0) {
+ Body = Content;
+ Stage = EParseStage::Done;
+ } else {
+ Stage = EParseStage::ChunkLength;
+ }
+ Line.Clear();
+ } else {
+ // Invalid body encoding
+ Stage = EParseStage::Error;
+ }
+ }
+ }
+ }
+ break;
+ }
+ case EParseStage::Done:
+ case EParseStage::Error:
+ data.Clear();
+ break;
+ default:
+ // Invalid processing sequence
+ Stage = EParseStage::Error;
+ break;
+ }
+ }
+ TSocketBuffer::Advance(len);
+}
+
+template <>
+void THttpParser<THttpResponse, TSocketBuffer>::ConnectionClosed() {
+ if (Stage == EParseStage::Done) {
+ return;
+ }
+ if (Stage == EParseStage::Body) {
+ // ?
+ Stage = EParseStage::Done;
+ } else {
+ LastSuccessStage = Stage;
+ Stage = EParseStage::Error;
+ }
+}
+
+THttpOutgoingResponsePtr THttpIncomingRequest::CreateResponseString(TStringBuf data) {
+ THttpOutgoingResponsePtr response = new THttpOutgoingResponse(this);
+ response->Append(data);
+ response->Reparse();
+ return response;
+}
+
+THttpOutgoingResponsePtr THttpIncomingRequest::CreateResponseOK(TStringBuf body, TStringBuf contentType, TInstant lastModified) {
+ return CreateResponse("200", "OK", contentType, body, lastModified);
+}
+
+THttpOutgoingResponsePtr THttpIncomingRequest::CreateResponseBadRequest(TStringBuf html, TStringBuf contentType) {
+ if (html.empty() && IsError()) {
+ contentType = "text/plain";
+ html = GetErrorText();
+ }
+ return CreateResponse("400", "Bad Request", contentType, html);
+}
+
+THttpOutgoingResponsePtr THttpIncomingRequest::CreateResponseNotFound(TStringBuf html, TStringBuf contentType) {
+ return CreateResponse("404", "Not Found", contentType, html);
+}
+
+THttpOutgoingResponsePtr THttpIncomingRequest::CreateResponseServiceUnavailable(TStringBuf html, TStringBuf contentType) {
+ return CreateResponse("503", "Service Unavailable", contentType, html);
+}
+
+THttpOutgoingResponsePtr THttpIncomingRequest::CreateResponseGatewayTimeout(TStringBuf html, TStringBuf contentType) {
+ return CreateResponse("504", "Gateway Timeout", contentType, html);
+}
+
+THttpIncomingResponse::THttpIncomingResponse(THttpOutgoingRequestPtr request)
+ : Request(request)
+{}
+
+THttpOutgoingResponsePtr THttpIncomingRequest::CreateResponse(TStringBuf status, TStringBuf message, TStringBuf contentType, TStringBuf body, TInstant lastModified) {
+ TStringBuf version = Version;
+ if (version != "1.0" && version != "1.1") {
+ version = "1.1";
+ }
+ THttpOutgoingResponsePtr response = new THttpOutgoingResponse(this, "HTTP", version, status, message);
+ response->Set<&THttpResponse::Connection>(GetConnection());
+ if (!WorkerName.empty()) {
+ response->Set("X-Worker-Name", WorkerName);
+ }
+ if (!contentType.empty() && !body.empty()) {
+ response->Set<&THttpResponse::ContentType>(contentType);
+ }
+ if (lastModified) {
+ response->Set<&THttpResponse::LastModified>(lastModified.FormatGmTime("%a, %d %b %Y %H:%M:%S GMT"));
+ }
+ if (response->IsNeedBody() || !body.empty()) {
+ if (Method == "HEAD") {
+ response->Set<&THttpResponse::ContentLength>(ToString(body.size()));
+ } else {
+ response->Set<&THttpResponse::Body>(body);
+ }
+ }
+ return response;
+}
+
+THttpIncomingRequestPtr THttpIncomingRequest::Duplicate() {
+ THttpIncomingRequestPtr request = new THttpIncomingRequest(*this);
+ request->Reparse();
+ request->Timer.Reset();
+ return request;
+}
+
+THttpIncomingResponsePtr THttpIncomingResponse::Duplicate(THttpOutgoingRequestPtr request) {
+ THttpIncomingResponsePtr response = new THttpIncomingResponse(*this);
+ response->Reparse();
+ response->Request = request;
+ return response;
+}
+
+THttpOutgoingResponsePtr THttpOutgoingResponse::Duplicate(THttpIncomingRequestPtr request) {
+ THttpOutgoingResponsePtr response = new THttpOutgoingResponse(*this);
+ response->Reparse();
+ response->Request = request;
+ return response;
+}
+
+
+THttpOutgoingResponsePtr THttpIncomingResponse::Reverse(THttpIncomingRequestPtr request) {
+ THttpOutgoingResponsePtr response = new THttpOutgoingResponse(request);
+ response->Assign(Data(), Size());
+ response->Reparse();
+ return response;
+}
+
+THttpOutgoingRequest::THttpOutgoingRequest(TStringBuf method, TStringBuf scheme, TStringBuf host, TStringBuf uri, TStringBuf protocol, TStringBuf version) {
+ Secure = (scheme == "https");
+ TString urie = UrlEscapeRet(uri);
+ InitRequest(method, urie, protocol, version);
+ if (host) {
+ Set<&THttpRequest::Host>(host);
+ }
+}
+
+THttpOutgoingRequest::THttpOutgoingRequest(TStringBuf method, TStringBuf url, TStringBuf protocol, TStringBuf version) {
+ TStringBuf scheme, host, uri;
+ if (!CrackURL(url, scheme, host, uri)) {
+ Y_FAIL("Invalid URL specified");
+ }
+ if (!scheme.empty() && scheme != "http" && scheme != "https") {
+ Y_FAIL("Invalid URL specified");
+ }
+ Secure = (scheme == "https");
+ TString urie = UrlEscapeRet(uri);
+ InitRequest(method, urie, protocol, version);
+ if (host) {
+ Set<&THttpRequest::Host>(host);
+ }
+}
+
+THttpOutgoingRequestPtr THttpOutgoingRequest::CreateRequestString(const TString& data) {
+ THttpOutgoingRequestPtr request = new THttpOutgoingRequest();
+ request->Assign(data.data(), data.size());
+ request->Reparse();
+ return request;
+}
+
+THttpOutgoingRequestPtr THttpOutgoingRequest::CreateRequestGet(TStringBuf url) {
+ return CreateRequest("GET", url);
+}
+
+THttpOutgoingRequestPtr THttpOutgoingRequest::CreateRequestGet(TStringBuf host, TStringBuf uri) {
+ return CreateHttpRequest("GET", host, uri);
+}
+
+THttpOutgoingRequestPtr THttpOutgoingRequest::CreateRequestPost(TStringBuf url, TStringBuf contentType, TStringBuf body) {
+ return CreateRequest("POST", url, contentType, body);
+}
+
+THttpOutgoingRequestPtr THttpOutgoingRequest::CreateRequestPost(TStringBuf host, TStringBuf uri, TStringBuf contentType, TStringBuf body) {
+ return CreateHttpRequest("POST", host, uri, contentType, body);
+}
+
+THttpOutgoingRequestPtr THttpOutgoingRequest::CreateRequest(TStringBuf method, TStringBuf url, TStringBuf contentType, TStringBuf body) {
+ THttpOutgoingRequestPtr request = new THttpOutgoingRequest(method, url, "HTTP", "1.1");
+ request->Set<&THttpRequest::Accept>("*/*");
+ if (!contentType.empty()) {
+ request->Set<&THttpRequest::ContentType>(contentType);
+ request->Set<&THttpRequest::Body>(body);
+ }
+ return request;
+}
+
+THttpOutgoingRequestPtr THttpOutgoingRequest::CreateHttpRequest(TStringBuf method, TStringBuf host, TStringBuf uri, TStringBuf contentType, TStringBuf body) {
+ THttpOutgoingRequestPtr request = new THttpOutgoingRequest(method, "http", host, uri, "HTTP", "1.1");
+ request->Set<&THttpRequest::Accept>("*/*");
+ if (!contentType.empty()) {
+ request->Set<&THttpRequest::ContentType>(contentType);
+ request->Set<&THttpRequest::Body>(body);
+ }
+ return request;
+}
+
+THttpOutgoingRequestPtr THttpOutgoingRequest::Duplicate() {
+ THttpOutgoingRequestPtr request = new THttpOutgoingRequest(*this);
+ request->Reparse();
+ return request;
+}
+
+THttpOutgoingResponse::THttpOutgoingResponse(THttpIncomingRequestPtr request)
+ : Request(request)
+{}
+
+THttpOutgoingResponse::THttpOutgoingResponse(THttpIncomingRequestPtr request, TStringBuf protocol, TStringBuf version, TStringBuf status, TStringBuf message)
+ : Request(request)
+{
+ InitResponse(protocol, version, status, message);
+}
+
+const size_t THttpConfig::BUFFER_MIN_STEP;
+const TDuration THttpConfig::CONNECTION_TIMEOUT;
+
+TUrlParameters::TUrlParameters(TStringBuf url) {
+ TStringBuf base;
+ TStringBuf params;
+ if (url.TrySplit('?', base, params)) {
+ for (TStringBuf param = params.NextTok('&'); !param.empty(); param = params.NextTok('&')) {
+ TStringBuf name = param.NextTok('=');
+ Parameters[name] = param;
+ }
+ }
+}
+
+TString TUrlParameters::operator [](TStringBuf name) const {
+ TString value(Get(name));
+ CGIUnescape(value);
+ return value;
+}
+
+bool TUrlParameters::Has(TStringBuf name) const {
+ return Parameters.count(name) != 0;
+}
+
+TStringBuf TUrlParameters::Get(TStringBuf name) const {
+ auto it = Parameters.find(name);
+ if (it != Parameters.end()) {
+ return it->second;
+ }
+ return TStringBuf();
+}
+
+TString TUrlParameters::Render() const {
+ TStringBuilder parameters;
+ for (const std::pair<TStringBuf, TStringBuf> parameter : Parameters) {
+ if (parameters.empty()) {
+ parameters << '?';
+ } else {
+ parameters << '&';
+ }
+ parameters << parameter.first;
+ parameters << '=';
+ parameters << parameter.second;
+ }
+ return parameters;
+}
+
+TCookies::TCookies(TStringBuf cookie) {
+ for (TStringBuf param = cookie.NextTok(';'); !param.empty(); param = cookie.NextTok(';')) {
+ param.SkipPrefix(" ");
+ TStringBuf name = param.NextTok('=');
+ Cookies[name] = param;
+ }
+}
+
+TStringBuf TCookies::operator [](TStringBuf name) const {
+ return Get(name);
+}
+
+bool TCookies::Has(TStringBuf name) const {
+ return Cookies.count(name) != 0;
+}
+
+TStringBuf TCookies::Get(TStringBuf name) const {
+ auto it = Cookies.find(name);
+ if (it != Cookies.end()) {
+ return it->second;
+ }
+ return TStringBuf();
+}
+
+TString TCookies::Render() const {
+ TStringBuilder cookies;
+ for (const std::pair<TStringBuf, TStringBuf> cookie : Cookies) {
+ if (!cookies.empty()) {
+ cookies << ' ';
+ }
+ cookies << cookie.first;
+ cookies << '=';
+ cookies << cookie.second;
+ cookies << ';';
+ }
+ return cookies;
+}
+
+TCookiesBuilder::TCookiesBuilder()
+ :TCookies(TStringBuf())
+{}
+
+void TCookiesBuilder::Set(TStringBuf name, TStringBuf data) {
+ Data.emplace_back(name, data);
+ Cookies[Data.back().first] = Data.back().second;
+}
+
+THeaders::THeaders(TStringBuf headers) {
+ for (TStringBuf param = headers.NextTok("\r\n"); !param.empty(); param = headers.NextTok("\r\n")) {
+ TStringBuf name = param.NextTok(":");
+ param.SkipPrefix(" ");
+ Headers[name] = param;
+ }
+}
+
+TStringBuf THeaders::operator [](TStringBuf name) const {
+ return Get(name);
+}
+
+bool THeaders::Has(TStringBuf name) const {
+ return Headers.count(name) != 0;
+}
+
+TStringBuf THeaders::Get(TStringBuf name) const {
+ auto it = Headers.find(name);
+ if (it != Headers.end()) {
+ return it->second;
+ }
+ return TStringBuf();
+}
+
+TString THeaders::Render() const {
+ TStringBuilder headers;
+ for (const std::pair<TStringBuf, TStringBuf> header : Headers) {
+ headers << header.first;
+ headers << ": ";
+ headers << header.second;
+ headers << "\r\n";
+ }
+ return headers;
+}
+
+THeadersBuilder::THeadersBuilder()
+ :THeaders(TStringBuf())
+{}
+
+THeadersBuilder::THeadersBuilder(const THeadersBuilder& builder) {
+ for (const auto& pr : builder.Headers) {
+ Set(pr.first, pr.second);
+ }
+}
+
+void THeadersBuilder::Set(TStringBuf name, TStringBuf data) {
+ Data.emplace_back(name, data);
+ Headers[Data.back().first] = Data.back().second;
+}
+
+}
diff --git a/library/cpp/actors/http/http.h b/library/cpp/actors/http/http.h
index 96c5c1ec48..a11d6158ee 100644
--- a/library/cpp/actors/http/http.h
+++ b/library/cpp/actors/http/http.h
@@ -1,703 +1,703 @@
-#pragma once
-#include <util/datetime/base.h>
-#include <util/string/builder.h>
-#include <util/system/thread.h>
-#include <util/system/hp_timer.h>
-#include <util/generic/hash_set.h>
-#include <util/generic/buffer.h>
-#include <util/generic/intrlist.h>
-#include "http_config.h"
-
-// TODO(xenoxeno): hide in implementation
-template <typename Type>
-struct THash<TIntrusivePtr<Type>> {
- size_t operator ()(const TIntrusivePtr<Type>& ptr) const { return reinterpret_cast<size_t>(ptr.Get()); }
-};
-
-template<>
-inline void Out<TSockAddrInet6>(IOutputStream& o, const TSockAddrInet6& x) {
- o << x.ToString();
-}
-
-namespace NHttp {
-
-bool IsIPv6(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);
-void TrimEnd(TStringBuf& target, char delim);
-void Trim(TStringBuf& target, char delim);
-void TrimEnd(TString& target, char delim);
-
-struct TLessNoCase {
- bool operator()(TStringBuf l, TStringBuf r) const {
- auto ll = l.length();
- auto rl = r.length();
- if (ll != rl) {
- return ll < rl;
- }
- return strnicmp(l.data(), r.data(), ll) < 0;
- }
-};
-
-struct TUrlParameters {
- THashMap<TStringBuf, TStringBuf> Parameters;
-
- TUrlParameters(TStringBuf url);
- TString operator [](TStringBuf name) const;
- bool Has(TStringBuf name) const;
- TStringBuf Get(TStringBuf name) const; // raw
- TString Render() const;
-};
-
-struct TCookies {
- THashMap<TStringBuf, TStringBuf> Cookies;
-
- TCookies(TStringBuf cookie);
- TCookies(const TCookies&) = delete;
- TStringBuf operator [](TStringBuf name) const;
- bool Has(TStringBuf name) const;
- TStringBuf Get(TStringBuf name) const; // raw
- TString Render() const;
-};
-
-struct TCookiesBuilder : TCookies {
+#pragma once
+#include <util/datetime/base.h>
+#include <util/string/builder.h>
+#include <util/system/thread.h>
+#include <util/system/hp_timer.h>
+#include <util/generic/hash_set.h>
+#include <util/generic/buffer.h>
+#include <util/generic/intrlist.h>
+#include "http_config.h"
+
+// TODO(xenoxeno): hide in implementation
+template <typename Type>
+struct THash<TIntrusivePtr<Type>> {
+ size_t operator ()(const TIntrusivePtr<Type>& ptr) const { return reinterpret_cast<size_t>(ptr.Get()); }
+};
+
+template<>
+inline void Out<TSockAddrInet6>(IOutputStream& o, const TSockAddrInet6& x) {
+ o << x.ToString();
+}
+
+namespace NHttp {
+
+bool IsIPv6(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);
+void TrimEnd(TStringBuf& target, char delim);
+void Trim(TStringBuf& target, char delim);
+void TrimEnd(TString& target, char delim);
+
+struct TLessNoCase {
+ bool operator()(TStringBuf l, TStringBuf r) const {
+ auto ll = l.length();
+ auto rl = r.length();
+ if (ll != rl) {
+ return ll < rl;
+ }
+ return strnicmp(l.data(), r.data(), ll) < 0;
+ }
+};
+
+struct TUrlParameters {
+ THashMap<TStringBuf, TStringBuf> Parameters;
+
+ TUrlParameters(TStringBuf url);
+ TString operator [](TStringBuf name) const;
+ bool Has(TStringBuf name) const;
+ TStringBuf Get(TStringBuf name) const; // raw
+ TString Render() const;
+};
+
+struct TCookies {
+ THashMap<TStringBuf, TStringBuf> Cookies;
+
+ TCookies(TStringBuf cookie);
+ TCookies(const TCookies&) = delete;
+ TStringBuf operator [](TStringBuf name) const;
+ bool Has(TStringBuf name) const;
+ TStringBuf Get(TStringBuf name) const; // raw
+ TString Render() const;
+};
+
+struct TCookiesBuilder : TCookies {
TDeque<std::pair<TString, TString>> Data;
-
- TCookiesBuilder();
- void Set(TStringBuf name, TStringBuf data);
-};
-
-struct THeaders {
- TMap<TStringBuf, TStringBuf, TLessNoCase> Headers;
-
- THeaders() = default;
- THeaders(TStringBuf headers);
- THeaders(const THeaders&) = delete;
- TStringBuf operator [](TStringBuf name) const;
- bool Has(TStringBuf name) const;
- TStringBuf Get(TStringBuf name) const; // raw
- TString Render() const;
-};
-
-struct THeadersBuilder : THeaders {
- TDeque<std::pair<TString, TString>> Data;
-
- THeadersBuilder();
- THeadersBuilder(const THeadersBuilder& builder);
- void Set(TStringBuf name, TStringBuf data);
-};
-
-class TSocketBuffer : public TBuffer, public THttpConfig {
-public:
- TSocketBuffer()
- : TBuffer(BUFFER_SIZE)
- {}
-
- bool EnsureEnoughSpaceAvailable(size_t need) {
- size_t avail = Avail();
- if (avail < need) {
- Reserve(Capacity() + std::max(need, BUFFER_MIN_STEP));
- return false;
- }
- return true;
- }
-};
-
-class THttpRequest {
-public:
- TStringBuf Method;
- TStringBuf URL;
- TStringBuf Protocol;
- TStringBuf Version;
- TStringBuf Headers;
-
- TStringBuf Host;
- TStringBuf Accept;
- TStringBuf Connection;
- TStringBuf ContentType;
- TStringBuf ContentLength;
- TStringBuf TransferEncoding;
-
- TStringBuf Body;
-
- static const TMap<TStringBuf, TStringBuf THttpRequest::*, TLessNoCase> HeadersLocation;
-
- template <TStringBuf THttpRequest::* Header>
- static TStringBuf GetName();
- void Clear();
-};
-
-class THttpResponse {
-public:
- TStringBuf Protocol;
- TStringBuf Version;
- TStringBuf Status;
- TStringBuf Message;
- TStringBuf Headers;
-
- TStringBuf Connection;
- TStringBuf ContentType;
- TStringBuf ContentLength;
- TStringBuf TransferEncoding;
- TStringBuf LastModified;
+
+ TCookiesBuilder();
+ void Set(TStringBuf name, TStringBuf data);
+};
+
+struct THeaders {
+ TMap<TStringBuf, TStringBuf, TLessNoCase> Headers;
+
+ THeaders() = default;
+ THeaders(TStringBuf headers);
+ THeaders(const THeaders&) = delete;
+ TStringBuf operator [](TStringBuf name) const;
+ bool Has(TStringBuf name) const;
+ TStringBuf Get(TStringBuf name) const; // raw
+ TString Render() const;
+};
+
+struct THeadersBuilder : THeaders {
+ TDeque<std::pair<TString, TString>> Data;
+
+ THeadersBuilder();
+ THeadersBuilder(const THeadersBuilder& builder);
+ void Set(TStringBuf name, TStringBuf data);
+};
+
+class TSocketBuffer : public TBuffer, public THttpConfig {
+public:
+ TSocketBuffer()
+ : TBuffer(BUFFER_SIZE)
+ {}
+
+ bool EnsureEnoughSpaceAvailable(size_t need) {
+ size_t avail = Avail();
+ if (avail < need) {
+ Reserve(Capacity() + std::max(need, BUFFER_MIN_STEP));
+ return false;
+ }
+ return true;
+ }
+};
+
+class THttpRequest {
+public:
+ TStringBuf Method;
+ TStringBuf URL;
+ TStringBuf Protocol;
+ TStringBuf Version;
+ TStringBuf Headers;
+
+ TStringBuf Host;
+ TStringBuf Accept;
+ TStringBuf Connection;
+ TStringBuf ContentType;
+ TStringBuf ContentLength;
+ TStringBuf TransferEncoding;
+
+ TStringBuf Body;
+
+ static const TMap<TStringBuf, TStringBuf THttpRequest::*, TLessNoCase> HeadersLocation;
+
+ template <TStringBuf THttpRequest::* Header>
+ static TStringBuf GetName();
+ void Clear();
+};
+
+class THttpResponse {
+public:
+ TStringBuf Protocol;
+ TStringBuf Version;
+ TStringBuf Status;
+ TStringBuf Message;
+ TStringBuf Headers;
+
+ TStringBuf Connection;
+ TStringBuf ContentType;
+ TStringBuf ContentLength;
+ TStringBuf TransferEncoding;
+ TStringBuf LastModified;
TStringBuf ContentEncoding;
-
- TStringBuf Body;
-
- static const TMap<TStringBuf, TStringBuf THttpResponse::*, TLessNoCase> HeadersLocation;
-
- template <TStringBuf THttpResponse::* Header>
- static TStringBuf GetName();
- void Clear();
-};
-
-template <typename HeaderType, typename BufferType>
-class THttpParser : public HeaderType, public BufferType {
-public:
- enum class EParseStage : ui8 {
- Method,
- URL,
- Protocol,
- Version,
- Status,
- Message,
- Header,
- Body,
- ChunkLength,
- ChunkData,
- Done,
- Error,
- };
-
- static constexpr size_t MaxMethodSize = 6;
- static constexpr size_t MaxURLSize = 1024;
- static constexpr size_t MaxProtocolSize = 4;
- static constexpr size_t MaxVersionSize = 4;
- static constexpr size_t MaxStatusSize = 3;
- static constexpr size_t MaxMessageSize = 1024;
+
+ TStringBuf Body;
+
+ static const TMap<TStringBuf, TStringBuf THttpResponse::*, TLessNoCase> HeadersLocation;
+
+ template <TStringBuf THttpResponse::* Header>
+ static TStringBuf GetName();
+ void Clear();
+};
+
+template <typename HeaderType, typename BufferType>
+class THttpParser : public HeaderType, public BufferType {
+public:
+ enum class EParseStage : ui8 {
+ Method,
+ URL,
+ Protocol,
+ Version,
+ Status,
+ Message,
+ Header,
+ Body,
+ ChunkLength,
+ ChunkData,
+ Done,
+ Error,
+ };
+
+ static constexpr size_t MaxMethodSize = 6;
+ static constexpr size_t MaxURLSize = 1024;
+ static constexpr size_t MaxProtocolSize = 4;
+ static constexpr size_t MaxVersionSize = 4;
+ static constexpr size_t MaxStatusSize = 3;
+ static constexpr size_t MaxMessageSize = 1024;
static constexpr size_t MaxHeaderSize = 8192;
- static constexpr size_t MaxChunkLengthSize = 8;
- static constexpr size_t MaxChunkSize = 256 * 1024 * 1024;
- static constexpr size_t MaxChunkContentSize = 1 * 1024 * 1024 * 1024;
-
- EParseStage Stage;
- EParseStage LastSuccessStage;
- TStringBuf Line;
- TStringBuf& Header = Line;
- size_t ChunkLength = 0;
- size_t ContentSize = 0;
- TString Content;
-
- THttpParser(const THttpParser& src)
- : HeaderType(src)
- , BufferType(src)
- , Stage(src.Stage)
- , LastSuccessStage(src.LastSuccessStage)
- , Line()
- , Header(Line)
- , ChunkLength(src.ChunkLength)
- , ContentSize(src.ContentSize)
- , Content(src.Content)
- {}
-
- template <typename StringType>
- bool ProcessData(StringType& target, TStringBuf& source, char delim, size_t maxLen) {
- TStringBuf maxSource(source.substr(0, maxLen + 1 - target.size()));
- size_t pos = maxSource.find(delim);
- target += maxSource.substr(0, pos);
- source.Skip(pos);
- if (target.size() > maxLen) {
- Stage = EParseStage::Error;
- return false;
- }
- if (!source.empty() && *source.begin() == delim) {
- source.Skip(1);
- }
- return pos != TStringBuf::npos;
- }
-
- template <typename StringType>
- bool ProcessData(StringType& target, TStringBuf& source, TStringBuf delim, size_t maxLen) {
- if (delim.empty()) {
- return false;
- }
- if (delim.size() == 1) {
- return ProcessData(target, source, delim[0], maxLen);
- }
+ static constexpr size_t MaxChunkLengthSize = 8;
+ static constexpr size_t MaxChunkSize = 256 * 1024 * 1024;
+ static constexpr size_t MaxChunkContentSize = 1 * 1024 * 1024 * 1024;
+
+ EParseStage Stage;
+ EParseStage LastSuccessStage;
+ TStringBuf Line;
+ TStringBuf& Header = Line;
+ size_t ChunkLength = 0;
+ size_t ContentSize = 0;
+ TString Content;
+
+ THttpParser(const THttpParser& src)
+ : HeaderType(src)
+ , BufferType(src)
+ , Stage(src.Stage)
+ , LastSuccessStage(src.LastSuccessStage)
+ , Line()
+ , Header(Line)
+ , ChunkLength(src.ChunkLength)
+ , ContentSize(src.ContentSize)
+ , Content(src.Content)
+ {}
+
+ template <typename StringType>
+ bool ProcessData(StringType& target, TStringBuf& source, char delim, size_t maxLen) {
+ TStringBuf maxSource(source.substr(0, maxLen + 1 - target.size()));
+ size_t pos = maxSource.find(delim);
+ target += maxSource.substr(0, pos);
+ source.Skip(pos);
+ if (target.size() > maxLen) {
+ Stage = EParseStage::Error;
+ return false;
+ }
+ if (!source.empty() && *source.begin() == delim) {
+ source.Skip(1);
+ }
+ return pos != TStringBuf::npos;
+ }
+
+ template <typename StringType>
+ bool ProcessData(StringType& target, TStringBuf& source, TStringBuf delim, size_t maxLen) {
+ if (delim.empty()) {
+ return false;
+ }
+ if (delim.size() == 1) {
+ return ProcessData(target, source, delim[0], maxLen);
+ }
if (ProcessData(target, source, delim.back(), maxLen + 1)) {
- for (signed i = delim.size() - 2; i >= 0; --i) {
- TrimEnd(target, delim[i]);
- }
- return true;
- }
- return false;
- }
-
- template <typename StringType>
- bool ProcessData(StringType& target, TStringBuf& source, size_t size) {
- TStringBuf maxSource(source.substr(0, size - target.size()));
- target += maxSource;
- source.Skip(maxSource.size());
- if (target.size() > size && !source.empty()) {
- Stage = EParseStage::Error;
- return false;
- }
- return target.size() == size;
- }
-
- void ProcessHeader(TStringBuf& header) {
- TStringBuf name = header.NextTok(':');
- TrimBegin(name, ' ');
- TStringBuf value = header;
- Trim(value, ' ');
- auto cit = HeaderType::HeadersLocation.find(name);
- if (cit != HeaderType::HeadersLocation.end()) {
- this->*cit->second = value;
- }
- header.Clear();
- }
-
- size_t ParseHex(TStringBuf value) {
- size_t result = 0;
- for (char ch : value) {
- if (ch >= '0' && ch <= '9') {
- result *= 16;
- result += ch - '0';
- } else if (ch >= 'a' && ch <= 'f') {
- result *= 16;
- result += 10 + ch - 'a';
- } else if (ch >= 'A' && ch <= 'F') {
- result *= 16;
- result += 10 + ch - 'A';
- } else if (ch == ';') {
- break;
- } else if (isspace(ch)) {
- continue;
- } else {
- Stage = EParseStage::Error;
- return 0;
- }
- }
- return result;
- }
-
- void Advance(size_t len);
- void ConnectionClosed();
-
- void Clear() {
- BufferType::Clear();
- HeaderType::Clear();
- Stage = GetInitialStage();
- Line.Clear();
- Content.clear();
- }
-
- bool IsReady() const {
- return Stage == EParseStage::Done;
- }
-
- bool IsError() const {
- return Stage == EParseStage::Error;
- }
-
- TStringBuf GetErrorText() const {
- switch (LastSuccessStage) {
- case EParseStage::Method:
- return "Invalid http method";
- case EParseStage::URL:
- return "Invalid url";
- case EParseStage::Protocol:
- return "Invalid http protocol";
- case EParseStage::Version:
- return "Invalid http version";
- case EParseStage::Status:
- return "Invalid http status";
- case EParseStage::Message:
- return "Invalid http message";
- case EParseStage::Header:
- return "Invalid http header";
- case EParseStage::Body:
- return "Invalid content body";
- case EParseStage::ChunkLength:
- case EParseStage::ChunkData:
- return "Broken chunked data";
- case EParseStage::Done:
- return "Everything is fine";
- case EParseStage::Error:
- return "Error on error"; // wat? ...because we don't want to include default label here
- }
- }
-
- bool IsDone() const {
- return IsReady() || IsError();
- }
-
- bool HaveBody() const {
- return !HeaderType::ContentType.empty() || !HeaderType::ContentLength.empty() || !HeaderType::TransferEncoding.empty();
- }
-
- bool EnsureEnoughSpaceAvailable(size_t need = BufferType::BUFFER_MIN_STEP) {
- bool result = BufferType::EnsureEnoughSpaceAvailable(need);
- if (!result && !BufferType::Empty()) {
- Reparse();
- }
- return true;
- }
-
- void Reparse() {
- size_t size = BufferType::Size();
- Clear();
- Advance(size);
- }
-
- TStringBuf GetRawData() const {
- return TStringBuf(BufferType::Data(), BufferType::Size());
- }
-
- TString GetObfuscatedData() const {
- THeaders headers(HeaderType::Headers);
- TStringBuf authorization(headers["Authorization"]);
- TStringBuf cookie(headers["Cookie"]);
- TStringBuf x_ydb_auth_ticket(headers["x-ydb-auth-ticket"]);
- TStringBuf x_yacloud_subjecttoken(headers["x-yacloud-subjecttoken"]);
- TString data(GetRawData());
- if (!authorization.empty()) {
- auto pos = data.find(authorization);
- if (pos != TString::npos) {
- data.replace(pos, authorization.size(), TString("<obfuscated>"));
- }
- }
- if (!cookie.empty()) {
- auto pos = data.find(cookie);
- if (pos != TString::npos) {
- data.replace(pos, cookie.size(), TString("<obfuscated>"));
- }
- }
- if (!x_ydb_auth_ticket.empty()) {
- auto pos = data.find(x_ydb_auth_ticket);
- if (pos != TString::npos) {
- data.replace(pos, x_ydb_auth_ticket.size(), TString("<obfuscated>"));
- }
- }
- if (!x_yacloud_subjecttoken.empty()) {
- auto pos = data.find(x_yacloud_subjecttoken);
- if (pos != TString::npos) {
- data.replace(pos, x_yacloud_subjecttoken.size(), TString("<obfuscated>"));
- }
- }
- return data;
- }
-
- static EParseStage GetInitialStage();
-
- THttpParser()
- : Stage(GetInitialStage())
- , LastSuccessStage(Stage)
- {}
-};
-
-template <typename HeaderType, typename BufferType>
-class THttpRenderer : public HeaderType, public BufferType {
-public:
- enum class ERenderStage {
- Init,
- Header,
- Body,
- Done,
- Error,
- };
-
- ERenderStage Stage = ERenderStage::Init;
-
- void Append(TStringBuf text) {
- EnsureEnoughSpaceAvailable(text.size());
- BufferType::Append(text.data(), text.size());
- }
-
- void Append(char c) {
- EnsureEnoughSpaceAvailable(sizeof(c));
- BufferType::Append(c);
- }
-
- template <TStringBuf HeaderType::* string>
- void AppendParsedValue(TStringBuf value) {
- Append(value);
- static_cast<HeaderType*>(this)->*string = TStringBuf(BufferType::Pos() - value.size(), value.size());
- }
-
- template <TStringBuf HeaderType::* name>
- void Set(TStringBuf value) {
- Y_VERIFY_DEBUG(Stage == ERenderStage::Header);
- Append(HeaderType::template GetName<name>());
- Append(": ");
- AppendParsedValue<name>(value);
- Append("\r\n");
- HeaderType::Headers = TStringBuf(HeaderType::Headers.Data(), BufferType::Pos() - HeaderType::Headers.Data());
- }
-
- void Set(TStringBuf name, TStringBuf value) {
- Y_VERIFY_DEBUG(Stage == ERenderStage::Header);
- Append(name);
- Append(": ");
- Append(value);
- Append("\r\n");
- HeaderType::Headers = TStringBuf(HeaderType::Headers.Data(), BufferType::Pos() - HeaderType::Headers.Data());
- }
-
- void Set(const THeaders& headers) {
- Y_VERIFY_DEBUG(Stage == ERenderStage::Header);
- Append(headers.Render());
- HeaderType::Headers = TStringBuf(HeaderType::Headers.Data(), BufferType::Pos() - HeaderType::Headers.Data());
- }
-
- //THttpRenderer(TStringBuf method, TStringBuf url, TStringBuf protocol, TStringBuf version); // request
- void InitRequest(TStringBuf method, TStringBuf url, TStringBuf protocol, TStringBuf version) {
- Y_VERIFY_DEBUG(Stage == ERenderStage::Init);
- AppendParsedValue<&THttpRequest::Method>(method);
- Append(' ');
- AppendParsedValue<&THttpRequest::URL>(url);
- Append(' ');
- AppendParsedValue<&THttpRequest::Protocol>(protocol);
- Append('/');
- AppendParsedValue<&THttpRequest::Version>(version);
- Append("\r\n");
- Stage = ERenderStage::Header;
- HeaderType::Headers = TStringBuf(BufferType::Pos(), size_t(0));
- }
-
- //THttpRenderer(TStringBuf protocol, TStringBuf version, TStringBuf status, TStringBuf message); // response
- void InitResponse(TStringBuf protocol, TStringBuf version, TStringBuf status, TStringBuf message) {
- Y_VERIFY_DEBUG(Stage == ERenderStage::Init);
- AppendParsedValue<&THttpResponse::Protocol>(protocol);
- Append('/');
- AppendParsedValue<&THttpResponse::Version>(version);
- Append(' ');
- AppendParsedValue<&THttpResponse::Status>(status);
- Append(' ');
- AppendParsedValue<&THttpResponse::Message>(message);
- Append("\r\n");
- Stage = ERenderStage::Header;
- HeaderType::Headers = TStringBuf(BufferType::Pos(), size_t(0));
- }
-
- void FinishHeader() {
- Append("\r\n");
- HeaderType::Headers = TStringBuf(HeaderType::Headers.Data(), BufferType::Pos() - HeaderType::Headers.Data());
- Stage = ERenderStage::Body;
- }
-
- void SetBody(TStringBuf body) {
- Y_VERIFY_DEBUG(Stage == ERenderStage::Header);
- if (HeaderType::ContentLength.empty()) {
- Set<&HeaderType::ContentLength>(ToString(body.size()));
- }
- FinishHeader();
- AppendParsedValue<&HeaderType::Body>(body);
- Stage = ERenderStage::Done;
- }
-
- bool IsDone() const {
- return Stage == ERenderStage::Done;
- }
-
- void Finish() {
- switch (Stage) {
- case ERenderStage::Header:
- FinishHeader();
- break;
- default:
- break;
- }
- }
-
- bool EnsureEnoughSpaceAvailable(size_t need = BufferType::BUFFER_MIN_STEP) {
- bool result = BufferType::EnsureEnoughSpaceAvailable(need);
- if (!result && !BufferType::Empty()) {
- Reparse();
- }
- return true;
- }
-
- void Clear() {
- BufferType::Clear();
- HeaderType::Clear();
- }
-
- void Reparse() {
- // move-magic
- size_t size = BufferType::Size();
- THttpParser<HeaderType, BufferType> parser;
- // move the buffer to parser
- static_cast<BufferType&>(parser) = std::move(static_cast<BufferType&>(*this));
- // reparse
- parser.Clear();
- parser.Advance(size);
- // move buffer and result back
- static_cast<HeaderType&>(*this) = std::move(static_cast<HeaderType&>(parser));
- static_cast<BufferType&>(*this) = std::move(static_cast<BufferType&>(parser));
- switch (parser.Stage) {
- case THttpParser<HeaderType, BufferType>::EParseStage::Method:
- case THttpParser<HeaderType, BufferType>::EParseStage::URL:
- case THttpParser<HeaderType, BufferType>::EParseStage::Protocol:
- case THttpParser<HeaderType, BufferType>::EParseStage::Version:
- case THttpParser<HeaderType, BufferType>::EParseStage::Status:
- case THttpParser<HeaderType, BufferType>::EParseStage::Message:
- Stage = ERenderStage::Init;
- break;
- case THttpParser<HeaderType, BufferType>::EParseStage::Header:
- Stage = ERenderStage::Header;
+ for (signed i = delim.size() - 2; i >= 0; --i) {
+ TrimEnd(target, delim[i]);
+ }
+ return true;
+ }
+ return false;
+ }
+
+ template <typename StringType>
+ bool ProcessData(StringType& target, TStringBuf& source, size_t size) {
+ TStringBuf maxSource(source.substr(0, size - target.size()));
+ target += maxSource;
+ source.Skip(maxSource.size());
+ if (target.size() > size && !source.empty()) {
+ Stage = EParseStage::Error;
+ return false;
+ }
+ return target.size() == size;
+ }
+
+ void ProcessHeader(TStringBuf& header) {
+ TStringBuf name = header.NextTok(':');
+ TrimBegin(name, ' ');
+ TStringBuf value = header;
+ Trim(value, ' ');
+ auto cit = HeaderType::HeadersLocation.find(name);
+ if (cit != HeaderType::HeadersLocation.end()) {
+ this->*cit->second = value;
+ }
+ header.Clear();
+ }
+
+ size_t ParseHex(TStringBuf value) {
+ size_t result = 0;
+ for (char ch : value) {
+ if (ch >= '0' && ch <= '9') {
+ result *= 16;
+ result += ch - '0';
+ } else if (ch >= 'a' && ch <= 'f') {
+ result *= 16;
+ result += 10 + ch - 'a';
+ } else if (ch >= 'A' && ch <= 'F') {
+ result *= 16;
+ result += 10 + ch - 'A';
+ } else if (ch == ';') {
+ break;
+ } else if (isspace(ch)) {
+ continue;
+ } else {
+ Stage = EParseStage::Error;
+ return 0;
+ }
+ }
+ return result;
+ }
+
+ void Advance(size_t len);
+ void ConnectionClosed();
+
+ void Clear() {
+ BufferType::Clear();
+ HeaderType::Clear();
+ Stage = GetInitialStage();
+ Line.Clear();
+ Content.clear();
+ }
+
+ bool IsReady() const {
+ return Stage == EParseStage::Done;
+ }
+
+ bool IsError() const {
+ return Stage == EParseStage::Error;
+ }
+
+ TStringBuf GetErrorText() const {
+ switch (LastSuccessStage) {
+ case EParseStage::Method:
+ return "Invalid http method";
+ case EParseStage::URL:
+ return "Invalid url";
+ case EParseStage::Protocol:
+ return "Invalid http protocol";
+ case EParseStage::Version:
+ return "Invalid http version";
+ case EParseStage::Status:
+ return "Invalid http status";
+ case EParseStage::Message:
+ return "Invalid http message";
+ case EParseStage::Header:
+ return "Invalid http header";
+ case EParseStage::Body:
+ return "Invalid content body";
+ case EParseStage::ChunkLength:
+ case EParseStage::ChunkData:
+ return "Broken chunked data";
+ case EParseStage::Done:
+ return "Everything is fine";
+ case EParseStage::Error:
+ return "Error on error"; // wat? ...because we don't want to include default label here
+ }
+ }
+
+ bool IsDone() const {
+ return IsReady() || IsError();
+ }
+
+ bool HaveBody() const {
+ return !HeaderType::ContentType.empty() || !HeaderType::ContentLength.empty() || !HeaderType::TransferEncoding.empty();
+ }
+
+ bool EnsureEnoughSpaceAvailable(size_t need = BufferType::BUFFER_MIN_STEP) {
+ bool result = BufferType::EnsureEnoughSpaceAvailable(need);
+ if (!result && !BufferType::Empty()) {
+ Reparse();
+ }
+ return true;
+ }
+
+ void Reparse() {
+ size_t size = BufferType::Size();
+ Clear();
+ Advance(size);
+ }
+
+ TStringBuf GetRawData() const {
+ return TStringBuf(BufferType::Data(), BufferType::Size());
+ }
+
+ TString GetObfuscatedData() const {
+ THeaders headers(HeaderType::Headers);
+ TStringBuf authorization(headers["Authorization"]);
+ TStringBuf cookie(headers["Cookie"]);
+ TStringBuf x_ydb_auth_ticket(headers["x-ydb-auth-ticket"]);
+ TStringBuf x_yacloud_subjecttoken(headers["x-yacloud-subjecttoken"]);
+ TString data(GetRawData());
+ if (!authorization.empty()) {
+ auto pos = data.find(authorization);
+ if (pos != TString::npos) {
+ data.replace(pos, authorization.size(), TString("<obfuscated>"));
+ }
+ }
+ if (!cookie.empty()) {
+ auto pos = data.find(cookie);
+ if (pos != TString::npos) {
+ data.replace(pos, cookie.size(), TString("<obfuscated>"));
+ }
+ }
+ if (!x_ydb_auth_ticket.empty()) {
+ auto pos = data.find(x_ydb_auth_ticket);
+ if (pos != TString::npos) {
+ data.replace(pos, x_ydb_auth_ticket.size(), TString("<obfuscated>"));
+ }
+ }
+ if (!x_yacloud_subjecttoken.empty()) {
+ auto pos = data.find(x_yacloud_subjecttoken);
+ if (pos != TString::npos) {
+ data.replace(pos, x_yacloud_subjecttoken.size(), TString("<obfuscated>"));
+ }
+ }
+ return data;
+ }
+
+ static EParseStage GetInitialStage();
+
+ THttpParser()
+ : Stage(GetInitialStage())
+ , LastSuccessStage(Stage)
+ {}
+};
+
+template <typename HeaderType, typename BufferType>
+class THttpRenderer : public HeaderType, public BufferType {
+public:
+ enum class ERenderStage {
+ Init,
+ Header,
+ Body,
+ Done,
+ Error,
+ };
+
+ ERenderStage Stage = ERenderStage::Init;
+
+ void Append(TStringBuf text) {
+ EnsureEnoughSpaceAvailable(text.size());
+ BufferType::Append(text.data(), text.size());
+ }
+
+ void Append(char c) {
+ EnsureEnoughSpaceAvailable(sizeof(c));
+ BufferType::Append(c);
+ }
+
+ template <TStringBuf HeaderType::* string>
+ void AppendParsedValue(TStringBuf value) {
+ Append(value);
+ static_cast<HeaderType*>(this)->*string = TStringBuf(BufferType::Pos() - value.size(), value.size());
+ }
+
+ template <TStringBuf HeaderType::* name>
+ void Set(TStringBuf value) {
+ Y_VERIFY_DEBUG(Stage == ERenderStage::Header);
+ Append(HeaderType::template GetName<name>());
+ Append(": ");
+ AppendParsedValue<name>(value);
+ Append("\r\n");
+ HeaderType::Headers = TStringBuf(HeaderType::Headers.Data(), BufferType::Pos() - HeaderType::Headers.Data());
+ }
+
+ void Set(TStringBuf name, TStringBuf value) {
+ Y_VERIFY_DEBUG(Stage == ERenderStage::Header);
+ Append(name);
+ Append(": ");
+ Append(value);
+ Append("\r\n");
+ HeaderType::Headers = TStringBuf(HeaderType::Headers.Data(), BufferType::Pos() - HeaderType::Headers.Data());
+ }
+
+ void Set(const THeaders& headers) {
+ Y_VERIFY_DEBUG(Stage == ERenderStage::Header);
+ Append(headers.Render());
+ HeaderType::Headers = TStringBuf(HeaderType::Headers.Data(), BufferType::Pos() - HeaderType::Headers.Data());
+ }
+
+ //THttpRenderer(TStringBuf method, TStringBuf url, TStringBuf protocol, TStringBuf version); // request
+ void InitRequest(TStringBuf method, TStringBuf url, TStringBuf protocol, TStringBuf version) {
+ Y_VERIFY_DEBUG(Stage == ERenderStage::Init);
+ AppendParsedValue<&THttpRequest::Method>(method);
+ Append(' ');
+ AppendParsedValue<&THttpRequest::URL>(url);
+ Append(' ');
+ AppendParsedValue<&THttpRequest::Protocol>(protocol);
+ Append('/');
+ AppendParsedValue<&THttpRequest::Version>(version);
+ Append("\r\n");
+ Stage = ERenderStage::Header;
+ HeaderType::Headers = TStringBuf(BufferType::Pos(), size_t(0));
+ }
+
+ //THttpRenderer(TStringBuf protocol, TStringBuf version, TStringBuf status, TStringBuf message); // response
+ void InitResponse(TStringBuf protocol, TStringBuf version, TStringBuf status, TStringBuf message) {
+ Y_VERIFY_DEBUG(Stage == ERenderStage::Init);
+ AppendParsedValue<&THttpResponse::Protocol>(protocol);
+ Append('/');
+ AppendParsedValue<&THttpResponse::Version>(version);
+ Append(' ');
+ AppendParsedValue<&THttpResponse::Status>(status);
+ Append(' ');
+ AppendParsedValue<&THttpResponse::Message>(message);
+ Append("\r\n");
+ Stage = ERenderStage::Header;
+ HeaderType::Headers = TStringBuf(BufferType::Pos(), size_t(0));
+ }
+
+ void FinishHeader() {
+ Append("\r\n");
+ HeaderType::Headers = TStringBuf(HeaderType::Headers.Data(), BufferType::Pos() - HeaderType::Headers.Data());
+ Stage = ERenderStage::Body;
+ }
+
+ void SetBody(TStringBuf body) {
+ Y_VERIFY_DEBUG(Stage == ERenderStage::Header);
+ if (HeaderType::ContentLength.empty()) {
+ Set<&HeaderType::ContentLength>(ToString(body.size()));
+ }
+ FinishHeader();
+ AppendParsedValue<&HeaderType::Body>(body);
+ Stage = ERenderStage::Done;
+ }
+
+ bool IsDone() const {
+ return Stage == ERenderStage::Done;
+ }
+
+ void Finish() {
+ switch (Stage) {
+ case ERenderStage::Header:
+ FinishHeader();
break;
- case THttpParser<HeaderType, BufferType>::EParseStage::Body:
- case THttpParser<HeaderType, BufferType>::EParseStage::ChunkLength:
- case THttpParser<HeaderType, BufferType>::EParseStage::ChunkData:
- Stage = ERenderStage::Body;
- break;
- case THttpParser<HeaderType, BufferType>::EParseStage::Done:
- Stage = ERenderStage::Done;
- break;
- case THttpParser<HeaderType, BufferType>::EParseStage::Error:
- Stage = ERenderStage::Error;
- break;
- }
- Y_VERIFY(size == BufferType::Size());
- }
-
- TStringBuf GetRawData() const {
- return TStringBuf(BufferType::Data(), BufferType::Size());
- }
-};
-
-template <>
-template <>
-inline void THttpRenderer<THttpResponse, TSocketBuffer>::Set<&THttpResponse::Body>(TStringBuf value) {
- SetBody(value);
-}
-
-template <>
-template <>
-inline void THttpRenderer<THttpRequest, TSocketBuffer>::Set<&THttpRequest::Body>(TStringBuf value) {
- SetBody(value);
-}
-
-class THttpIncomingRequest;
-using THttpIncomingRequestPtr = TIntrusivePtr<THttpIncomingRequest>;
-
-class THttpOutgoingResponse;
-using THttpOutgoingResponsePtr = TIntrusivePtr<THttpOutgoingResponse>;
-
-class THttpIncomingRequest :
- public THttpParser<THttpRequest, TSocketBuffer>,
- public TRefCounted<THttpIncomingRequest, TAtomicCounter> {
-public:
- THttpConfig::SocketAddressType Address;
- TString WorkerName;
- THPTimer Timer;
- bool Secure = false;
-
- bool IsConnectionClose() const {
- if (Connection.empty()) {
- return Version == "1.0";
- } else {
- return Connection == "close";
- }
- }
-
- TStringBuf GetConnection() const {
- if (!Connection.empty()) {
- return Connection;
- }
- return Version == "1.0" ? "close" : "keep-alive";
- }
-
- THttpOutgoingResponsePtr CreateResponseOK(TStringBuf body, TStringBuf contentType = "text/html", TInstant lastModified = TInstant());
- THttpOutgoingResponsePtr CreateResponseString(TStringBuf data);
- THttpOutgoingResponsePtr CreateResponseBadRequest(TStringBuf html = TStringBuf(), TStringBuf contentType = "text/html"); // 400
- THttpOutgoingResponsePtr CreateResponseNotFound(TStringBuf html = TStringBuf(), TStringBuf contentType = "text/html"); // 404
- THttpOutgoingResponsePtr CreateResponseServiceUnavailable(TStringBuf html = TStringBuf(), TStringBuf contentType = "text/html"); // 503
- THttpOutgoingResponsePtr CreateResponseGatewayTimeout(TStringBuf html = TStringBuf(), TStringBuf contentType = "text/html"); // 504
- THttpOutgoingResponsePtr CreateResponse(
- TStringBuf status,
- TStringBuf message,
- TStringBuf contentType = TStringBuf(),
- TStringBuf body = TStringBuf(),
- TInstant lastModified = TInstant());
-
- THttpIncomingRequestPtr Duplicate();
-};
-
-class THttpIncomingResponse;
-using THttpIncomingResponsePtr = TIntrusivePtr<THttpIncomingResponse>;
-
-class THttpOutgoingRequest;
-using THttpOutgoingRequestPtr = TIntrusivePtr<THttpOutgoingRequest>;
-
-class THttpIncomingResponse :
- public THttpParser<THttpResponse, TSocketBuffer>,
- public TRefCounted<THttpIncomingResponse, TAtomicCounter> {
-public:
- THttpIncomingResponse(THttpOutgoingRequestPtr request);
-
- THttpOutgoingRequestPtr GetRequest() const {
- return Request;
- }
-
- THttpIncomingResponsePtr Duplicate(THttpOutgoingRequestPtr request);
- THttpOutgoingResponsePtr Reverse(THttpIncomingRequestPtr request);
-
-protected:
- THttpOutgoingRequestPtr Request;
-};
-
-class THttpOutgoingRequest :
- public THttpRenderer<THttpRequest, TSocketBuffer>,
- public TRefCounted<THttpOutgoingRequest, TAtomicCounter> {
-public:
- THPTimer Timer;
+ default:
+ break;
+ }
+ }
+
+ bool EnsureEnoughSpaceAvailable(size_t need = BufferType::BUFFER_MIN_STEP) {
+ bool result = BufferType::EnsureEnoughSpaceAvailable(need);
+ if (!result && !BufferType::Empty()) {
+ Reparse();
+ }
+ return true;
+ }
+
+ void Clear() {
+ BufferType::Clear();
+ HeaderType::Clear();
+ }
+
+ void Reparse() {
+ // move-magic
+ size_t size = BufferType::Size();
+ THttpParser<HeaderType, BufferType> parser;
+ // move the buffer to parser
+ static_cast<BufferType&>(parser) = std::move(static_cast<BufferType&>(*this));
+ // reparse
+ parser.Clear();
+ parser.Advance(size);
+ // move buffer and result back
+ static_cast<HeaderType&>(*this) = std::move(static_cast<HeaderType&>(parser));
+ static_cast<BufferType&>(*this) = std::move(static_cast<BufferType&>(parser));
+ switch (parser.Stage) {
+ case THttpParser<HeaderType, BufferType>::EParseStage::Method:
+ case THttpParser<HeaderType, BufferType>::EParseStage::URL:
+ case THttpParser<HeaderType, BufferType>::EParseStage::Protocol:
+ case THttpParser<HeaderType, BufferType>::EParseStage::Version:
+ case THttpParser<HeaderType, BufferType>::EParseStage::Status:
+ case THttpParser<HeaderType, BufferType>::EParseStage::Message:
+ Stage = ERenderStage::Init;
+ break;
+ case THttpParser<HeaderType, BufferType>::EParseStage::Header:
+ Stage = ERenderStage::Header;
+ break;
+ case THttpParser<HeaderType, BufferType>::EParseStage::Body:
+ case THttpParser<HeaderType, BufferType>::EParseStage::ChunkLength:
+ case THttpParser<HeaderType, BufferType>::EParseStage::ChunkData:
+ Stage = ERenderStage::Body;
+ break;
+ case THttpParser<HeaderType, BufferType>::EParseStage::Done:
+ Stage = ERenderStage::Done;
+ break;
+ case THttpParser<HeaderType, BufferType>::EParseStage::Error:
+ Stage = ERenderStage::Error;
+ break;
+ }
+ Y_VERIFY(size == BufferType::Size());
+ }
+
+ TStringBuf GetRawData() const {
+ return TStringBuf(BufferType::Data(), BufferType::Size());
+ }
+};
+
+template <>
+template <>
+inline void THttpRenderer<THttpResponse, TSocketBuffer>::Set<&THttpResponse::Body>(TStringBuf value) {
+ SetBody(value);
+}
+
+template <>
+template <>
+inline void THttpRenderer<THttpRequest, TSocketBuffer>::Set<&THttpRequest::Body>(TStringBuf value) {
+ SetBody(value);
+}
+
+class THttpIncomingRequest;
+using THttpIncomingRequestPtr = TIntrusivePtr<THttpIncomingRequest>;
+
+class THttpOutgoingResponse;
+using THttpOutgoingResponsePtr = TIntrusivePtr<THttpOutgoingResponse>;
+
+class THttpIncomingRequest :
+ public THttpParser<THttpRequest, TSocketBuffer>,
+ public TRefCounted<THttpIncomingRequest, TAtomicCounter> {
+public:
+ THttpConfig::SocketAddressType Address;
+ TString WorkerName;
+ THPTimer Timer;
bool Secure = false;
-
- THttpOutgoingRequest() = default;
- THttpOutgoingRequest(TStringBuf method, TStringBuf url, TStringBuf protocol, TStringBuf version);
- THttpOutgoingRequest(TStringBuf method, TStringBuf scheme, TStringBuf host, TStringBuf uri, TStringBuf protocol, TStringBuf version);
- static THttpOutgoingRequestPtr CreateRequestString(TStringBuf data);
- static THttpOutgoingRequestPtr CreateRequestString(const TString& data);
- static THttpOutgoingRequestPtr CreateRequestGet(TStringBuf url);
- static THttpOutgoingRequestPtr CreateRequestGet(TStringBuf host, TStringBuf uri); // http only
- static THttpOutgoingRequestPtr CreateRequestPost(TStringBuf url, TStringBuf contentType = {}, TStringBuf body = {});
- static THttpOutgoingRequestPtr CreateRequestPost(TStringBuf host, TStringBuf uri, TStringBuf contentType, TStringBuf body); // http only
- static THttpOutgoingRequestPtr CreateRequest(TStringBuf method, TStringBuf url, TStringBuf contentType = TStringBuf(), TStringBuf body = TStringBuf());
- static THttpOutgoingRequestPtr CreateHttpRequest(TStringBuf method, TStringBuf host, TStringBuf uri, TStringBuf contentType = TStringBuf(), TStringBuf body = TStringBuf());
- THttpOutgoingRequestPtr Duplicate();
-};
-
-class THttpOutgoingResponse :
- public THttpRenderer<THttpResponse, TSocketBuffer>,
- public TRefCounted<THttpOutgoingResponse, TAtomicCounter> {
-public:
- THttpOutgoingResponse(THttpIncomingRequestPtr request);
- THttpOutgoingResponse(THttpIncomingRequestPtr request, TStringBuf protocol, TStringBuf version, TStringBuf status, TStringBuf message);
-
- bool IsConnectionClose() const {
- if (!Connection.empty()) {
- return Connection == "close";
- } else {
- return Request->IsConnectionClose();
- }
- }
-
- bool IsNeedBody() const {
- return Status != "204";
- }
-
- THttpIncomingRequestPtr GetRequest() const {
- return Request;
- }
-
- THttpOutgoingResponsePtr Duplicate(THttpIncomingRequestPtr request);
-
-// it's temporary accessible for cleanup
-//protected:
- THttpIncomingRequestPtr Request;
-};
-
-}
+
+ bool IsConnectionClose() const {
+ if (Connection.empty()) {
+ return Version == "1.0";
+ } else {
+ return Connection == "close";
+ }
+ }
+
+ TStringBuf GetConnection() const {
+ if (!Connection.empty()) {
+ return Connection;
+ }
+ return Version == "1.0" ? "close" : "keep-alive";
+ }
+
+ THttpOutgoingResponsePtr CreateResponseOK(TStringBuf body, TStringBuf contentType = "text/html", TInstant lastModified = TInstant());
+ THttpOutgoingResponsePtr CreateResponseString(TStringBuf data);
+ THttpOutgoingResponsePtr CreateResponseBadRequest(TStringBuf html = TStringBuf(), TStringBuf contentType = "text/html"); // 400
+ THttpOutgoingResponsePtr CreateResponseNotFound(TStringBuf html = TStringBuf(), TStringBuf contentType = "text/html"); // 404
+ THttpOutgoingResponsePtr CreateResponseServiceUnavailable(TStringBuf html = TStringBuf(), TStringBuf contentType = "text/html"); // 503
+ THttpOutgoingResponsePtr CreateResponseGatewayTimeout(TStringBuf html = TStringBuf(), TStringBuf contentType = "text/html"); // 504
+ THttpOutgoingResponsePtr CreateResponse(
+ TStringBuf status,
+ TStringBuf message,
+ TStringBuf contentType = TStringBuf(),
+ TStringBuf body = TStringBuf(),
+ TInstant lastModified = TInstant());
+
+ THttpIncomingRequestPtr Duplicate();
+};
+
+class THttpIncomingResponse;
+using THttpIncomingResponsePtr = TIntrusivePtr<THttpIncomingResponse>;
+
+class THttpOutgoingRequest;
+using THttpOutgoingRequestPtr = TIntrusivePtr<THttpOutgoingRequest>;
+
+class THttpIncomingResponse :
+ public THttpParser<THttpResponse, TSocketBuffer>,
+ public TRefCounted<THttpIncomingResponse, TAtomicCounter> {
+public:
+ THttpIncomingResponse(THttpOutgoingRequestPtr request);
+
+ THttpOutgoingRequestPtr GetRequest() const {
+ return Request;
+ }
+
+ THttpIncomingResponsePtr Duplicate(THttpOutgoingRequestPtr request);
+ THttpOutgoingResponsePtr Reverse(THttpIncomingRequestPtr request);
+
+protected:
+ THttpOutgoingRequestPtr Request;
+};
+
+class THttpOutgoingRequest :
+ public THttpRenderer<THttpRequest, TSocketBuffer>,
+ public TRefCounted<THttpOutgoingRequest, TAtomicCounter> {
+public:
+ THPTimer Timer;
+ bool Secure = false;
+
+ THttpOutgoingRequest() = default;
+ THttpOutgoingRequest(TStringBuf method, TStringBuf url, TStringBuf protocol, TStringBuf version);
+ THttpOutgoingRequest(TStringBuf method, TStringBuf scheme, TStringBuf host, TStringBuf uri, TStringBuf protocol, TStringBuf version);
+ static THttpOutgoingRequestPtr CreateRequestString(TStringBuf data);
+ static THttpOutgoingRequestPtr CreateRequestString(const TString& data);
+ static THttpOutgoingRequestPtr CreateRequestGet(TStringBuf url);
+ static THttpOutgoingRequestPtr CreateRequestGet(TStringBuf host, TStringBuf uri); // http only
+ static THttpOutgoingRequestPtr CreateRequestPost(TStringBuf url, TStringBuf contentType = {}, TStringBuf body = {});
+ static THttpOutgoingRequestPtr CreateRequestPost(TStringBuf host, TStringBuf uri, TStringBuf contentType, TStringBuf body); // http only
+ static THttpOutgoingRequestPtr CreateRequest(TStringBuf method, TStringBuf url, TStringBuf contentType = TStringBuf(), TStringBuf body = TStringBuf());
+ static THttpOutgoingRequestPtr CreateHttpRequest(TStringBuf method, TStringBuf host, TStringBuf uri, TStringBuf contentType = TStringBuf(), TStringBuf body = TStringBuf());
+ THttpOutgoingRequestPtr Duplicate();
+};
+
+class THttpOutgoingResponse :
+ public THttpRenderer<THttpResponse, TSocketBuffer>,
+ public TRefCounted<THttpOutgoingResponse, TAtomicCounter> {
+public:
+ THttpOutgoingResponse(THttpIncomingRequestPtr request);
+ THttpOutgoingResponse(THttpIncomingRequestPtr request, TStringBuf protocol, TStringBuf version, TStringBuf status, TStringBuf message);
+
+ bool IsConnectionClose() const {
+ if (!Connection.empty()) {
+ return Connection == "close";
+ } else {
+ return Request->IsConnectionClose();
+ }
+ }
+
+ bool IsNeedBody() const {
+ return Status != "204";
+ }
+
+ THttpIncomingRequestPtr GetRequest() const {
+ return Request;
+ }
+
+ THttpOutgoingResponsePtr Duplicate(THttpIncomingRequestPtr request);
+
+// it's temporary accessible for cleanup
+//protected:
+ THttpIncomingRequestPtr Request;
+};
+
+}
diff --git a/library/cpp/actors/http/http_cache.cpp b/library/cpp/actors/http/http_cache.cpp
index 27c4eeb6f3..8fe6783260 100644
--- a/library/cpp/actors/http/http_cache.cpp
+++ b/library/cpp/actors/http/http_cache.cpp
@@ -1,4 +1,4 @@
-#include "http.h"
+#include "http.h"
#include "http_proxy.h"
#include "http_cache.h"
#include <library/cpp/actors/core/actor_bootstrapped.h>
@@ -6,594 +6,594 @@
#include <library/cpp/actors/core/log.h>
#include <library/cpp/actors/core/scheduler_basic.h>
#include <library/cpp/actors/http/http.h>
-#include <library/cpp/digest/md5/md5.h>
-#include <util/digest/multi.h>
-#include <util/generic/queue.h>
+#include <library/cpp/digest/md5/md5.h>
+#include <util/digest/multi.h>
+#include <util/generic/queue.h>
#include <util/string/cast.h>
-
-namespace NHttp {
-
-class THttpOutgoingCacheActor : public NActors::TActorBootstrapped<THttpOutgoingCacheActor>, THttpConfig {
-public:
- using TBase = NActors::TActorBootstrapped<THttpOutgoingCacheActor>;
+
+namespace NHttp {
+
+class THttpOutgoingCacheActor : public NActors::TActorBootstrapped<THttpOutgoingCacheActor>, THttpConfig {
+public:
+ using TBase = NActors::TActorBootstrapped<THttpOutgoingCacheActor>;
NActors::TActorId HttpProxyId;
- TGetCachePolicy GetCachePolicy;
- static constexpr TDuration RefreshTimeout = TDuration::Seconds(1);
-
- struct TCacheKey {
- TString Host;
- TString URL;
- TString Headers;
-
- operator size_t() const {
- return MultiHash(Host, URL, Headers);
- }
-
- TString GetId() const {
- return MD5::Calc(Host + ':' + URL + ':' + Headers);
- }
- };
-
- struct TCacheRecord {
- TInstant RefreshTime;
- TInstant DeathTime;
- TCachePolicy CachePolicy;
- NHttp::THttpOutgoingRequestPtr Request;
- NHttp::THttpOutgoingRequestPtr OutgoingRequest;
- TDuration Timeout;
- NHttp::THttpIncomingResponsePtr Response;
- TString Error;
- TVector<NHttp::TEvHttpProxy::TEvHttpOutgoingRequest::TPtr> Waiters;
-
- TCacheRecord(const TCachePolicy cachePolicy)
- : CachePolicy(cachePolicy)
- {}
-
- bool IsValid() const {
- return Response != nullptr || !Error.empty();
- }
-
- void UpdateResponse(NHttp::THttpIncomingResponsePtr response, const TString& error, TInstant now) {
- if (error.empty() || Response == nullptr || !CachePolicy.KeepOnError) {
- Response = response;
- Error = error;
- }
- RefreshTime = now + CachePolicy.TimeToRefresh;
- if (CachePolicy.PaceToRefresh) {
- RefreshTime += TDuration::MilliSeconds(RandomNumber<ui64>() % CachePolicy.PaceToRefresh.MilliSeconds());
- }
- }
-
- TString GetName() const {
- return TStringBuilder() << (Request->Secure ? "https://" : "http://") << Request->Host << Request->URL;
- }
- };
-
- struct TRefreshRecord {
- TCacheKey Key;
- TInstant RefreshTime;
-
- bool operator <(const TRefreshRecord& b) const {
- return RefreshTime > b.RefreshTime;
- }
- };
-
- THashMap<TCacheKey, TCacheRecord> Cache;
- TPriorityQueue<TRefreshRecord> RefreshQueue;
- THashMap<THttpOutgoingRequest*, TCacheKey> OutgoingRequests;
-
- THttpOutgoingCacheActor(const NActors::TActorId& httpProxyId, TGetCachePolicy getCachePolicy)
- : HttpProxyId(httpProxyId)
- , GetCachePolicy(std::move(getCachePolicy))
- {}
-
- void Bootstrap(const NActors::TActorContext&) {
- //
- Become(&THttpOutgoingCacheActor::StateWork, RefreshTimeout, new NActors::TEvents::TEvWakeup());
- }
-
- static TString GetCacheHeadersKey(const NHttp::THttpOutgoingRequest* request, const TCachePolicy& policy) {
- TStringBuilder key;
- if (!policy.HeadersToCacheKey.empty()) {
- NHttp::THeaders headers(request->Headers);
- for (const TString& header : policy.HeadersToCacheKey) {
- key << headers[header];
- }
- }
- return key;
- }
-
- static TCacheKey GetCacheKey(const NHttp::THttpOutgoingRequest* request, const TCachePolicy& policy) {
- return { ToString(request->Host), ToString(request->URL), GetCacheHeadersKey(request, policy) };
- }
-
- void Handle(NHttp::TEvHttpProxy::TEvHttpOutgoingResponse::TPtr event, const NActors::TActorContext& ctx) {
- ctx.Send(event->Forward(HttpProxyId));
- }
-
- void Handle(NHttp::TEvHttpProxy::TEvHttpIncomingRequest::TPtr event, const NActors::TActorContext& ctx) {
- ctx.Send(event->Forward(HttpProxyId));
- }
-
- void Handle(NHttp::TEvHttpProxy::TEvAddListeningPort::TPtr event, const NActors::TActorContext& ctx) {
- ctx.Send(event->Forward(HttpProxyId));
- }
-
- void Handle(NHttp::TEvHttpProxy::TEvRegisterHandler::TPtr event, const NActors::TActorContext& ctx) {
- ctx.Send(event->Forward(HttpProxyId));
- }
-
- void Handle(NHttp::TEvHttpProxy::TEvHttpIncomingResponse::TPtr event, const NActors::TActorContext& ctx) {
- NHttp::THttpOutgoingRequestPtr request(event->Get()->Request);
- NHttp::THttpIncomingResponsePtr response(event->Get()->Response);
- auto itRequests = OutgoingRequests.find(request.Get());
- if (itRequests == OutgoingRequests.end()) {
- LOG_ERROR_S(ctx, HttpLog, "Cache received response to unknown request " << request->Host << request->URL);
- return;
- }
- auto key = itRequests->second;
- OutgoingRequests.erase(itRequests);
- auto it = Cache.find(key);
- if (it == Cache.end()) {
- LOG_ERROR_S(ctx, HttpLog, "Cache received response to unknown cache key " << request->Host << request->URL);
- return;
- }
- TCacheRecord& cacheRecord = it->second;
- cacheRecord.OutgoingRequest.Reset();
- for (auto& waiter : cacheRecord.Waiters) {
- NHttp::THttpIncomingResponsePtr response2;
- TString error2;
- if (response != nullptr) {
- response2 = response->Duplicate(waiter->Get()->Request);
- }
- if (!event->Get()->Error.empty()) {
- error2 = event->Get()->Error;
- }
- ctx.Send(waiter->Sender, new NHttp::TEvHttpProxy::TEvHttpIncomingResponse(waiter->Get()->Request, response2, error2));
- }
- cacheRecord.Waiters.clear();
- TString error;
- if (event->Get()->Error.empty()) {
- if (event->Get()->Response != nullptr && event->Get()->Response->Status != "200") {
- error = event->Get()->Response->Message;
- }
- } else {
- error = event->Get()->Error;
- }
- if (!error.empty()) {
- LOG_WARN_S(ctx, HttpLog, "Error from " << cacheRecord.GetName() << ": " << error);
- }
- LOG_DEBUG_S(ctx, HttpLog, "OutgoingUpdate " << cacheRecord.GetName());
- cacheRecord.UpdateResponse(response, event->Get()->Error, ctx.Now());
- RefreshQueue.push({it->first, it->second.RefreshTime});
- LOG_DEBUG_S(ctx, HttpLog, "OutgoingSchedule " << cacheRecord.GetName() << " at " << cacheRecord.RefreshTime << " until " << cacheRecord.DeathTime);
- }
-
- void Handle(NHttp::TEvHttpProxy::TEvHttpOutgoingRequest::TPtr event, const NActors::TActorContext& ctx) {
- const NHttp::THttpOutgoingRequest* request = event->Get()->Request.Get();
- auto policy = GetCachePolicy(request);
- if (policy.TimeToExpire == TDuration()) {
- ctx.Send(event->Forward(HttpProxyId));
- return;
- }
- auto key = GetCacheKey(request, policy);
- auto it = Cache.find(key);
- if (it != Cache.end()) {
- if (it->second.IsValid()) {
- LOG_DEBUG_S(ctx, HttpLog, "OutgoingRespond "
- << it->second.GetName()
- << " ("
- << ((it->second.Response != nullptr) ? ToString(it->second.Response->Size()) : TString("error"))
- << ")");
- NHttp::THttpIncomingResponsePtr response = it->second.Response;
- if (response != nullptr) {
- response = response->Duplicate(event->Get()->Request);
- }
- ctx.Send(event->Sender,
- new NHttp::TEvHttpProxy::TEvHttpIncomingResponse(event->Get()->Request,
- response,
- it->second.Error));
- it->second.DeathTime = ctx.Now() + it->second.CachePolicy.TimeToExpire; // prolong active cache items
- return;
- }
- } else {
- it = Cache.emplace(key, policy).first;
- it->second.Request = event->Get()->Request;
- it->second.Timeout = event->Get()->Timeout;
- it->second.OutgoingRequest = it->second.Request->Duplicate();
- OutgoingRequests[it->second.OutgoingRequest.Get()] = key;
- LOG_DEBUG_S(ctx, HttpLog, "OutgoingInitiate " << it->second.GetName());
- ctx.Send(HttpProxyId, new NHttp::TEvHttpProxy::TEvHttpOutgoingRequest(it->second.OutgoingRequest, it->second.Timeout));
- }
- it->second.DeathTime = ctx.Now() + it->second.CachePolicy.TimeToExpire;
- it->second.Waiters.emplace_back(std::move(event));
- }
-
- void HandleRefresh(const NActors::TActorContext& ctx) {
- while (!RefreshQueue.empty() && RefreshQueue.top().RefreshTime <= ctx.Now()) {
- TRefreshRecord rrec = RefreshQueue.top();
- RefreshQueue.pop();
- auto it = Cache.find(rrec.Key);
- if (it != Cache.end()) {
- if (it->second.DeathTime > ctx.Now()) {
- LOG_DEBUG_S(ctx, HttpLog, "OutgoingRefresh " << it->second.GetName());
- it->second.OutgoingRequest = it->second.Request->Duplicate();
- OutgoingRequests[it->second.OutgoingRequest.Get()] = it->first;
- ctx.Send(HttpProxyId, new NHttp::TEvHttpProxy::TEvHttpOutgoingRequest(it->second.OutgoingRequest, it->second.Timeout));
- } else {
- LOG_DEBUG_S(ctx, HttpLog, "OutgoingForget " << it->second.GetName());
- if (it->second.OutgoingRequest) {
- OutgoingRequests.erase(it->second.OutgoingRequest.Get());
- }
- Cache.erase(it);
- }
- }
- }
- ctx.Schedule(RefreshTimeout, new NActors::TEvents::TEvWakeup());
- }
-
- STFUNC(StateWork) {
- switch (ev->GetTypeRewrite()) {
- HFunc(NHttp::TEvHttpProxy::TEvHttpIncomingResponse, Handle);
- HFunc(NHttp::TEvHttpProxy::TEvHttpOutgoingRequest, Handle);
- HFunc(NHttp::TEvHttpProxy::TEvAddListeningPort, Handle);
- HFunc(NHttp::TEvHttpProxy::TEvRegisterHandler, Handle);
- HFunc(NHttp::TEvHttpProxy::TEvHttpIncomingRequest, Handle);
- HFunc(NHttp::TEvHttpProxy::TEvHttpOutgoingResponse, Handle);
- CFunc(NActors::TEvents::TSystem::Wakeup, HandleRefresh);
- }
- }
-};
-
-const TDuration THttpOutgoingCacheActor::RefreshTimeout;
-
-class THttpIncomingCacheActor : public NActors::TActorBootstrapped<THttpIncomingCacheActor>, THttpConfig {
-public:
- using TBase = NActors::TActorBootstrapped<THttpIncomingCacheActor>;
- NActors::TActorId HttpProxyId;
- TGetCachePolicy GetCachePolicy;
- static constexpr TDuration RefreshTimeout = TDuration::Seconds(1);
- THashMap<TString, TActorId> Handlers;
-
- struct TCacheKey {
- TString Host;
- TString URL;
- TString Headers;
-
- operator size_t() const {
- return MultiHash(Host, URL, Headers);
- }
-
- TString GetId() const {
- return MD5::Calc(Host + ':' + URL + ':' + Headers);
- }
- };
-
- struct TCacheRecord {
- TInstant RefreshTime;
- TInstant DeathTime;
- TCachePolicy CachePolicy;
- TString CacheId;
- NHttp::THttpIncomingRequestPtr Request;
- TDuration Timeout;
- NHttp::THttpOutgoingResponsePtr Response;
- TVector<NHttp::TEvHttpProxy::TEvHttpIncomingRequest::TPtr> Waiters;
- ui32 Retries = 0;
- bool Enqueued = false;
-
- TCacheRecord(const TCachePolicy cachePolicy)
- : CachePolicy(cachePolicy)
- {}
-
- bool IsValid() const {
- return Response != nullptr;
- }
-
- void InitRequest(NHttp::THttpIncomingRequestPtr request) {
- Request = request;
- if (CachePolicy.TimeToExpire) {
- DeathTime = NActors::TlsActivationContext->Now() + CachePolicy.TimeToExpire;
- }
- }
-
- void UpdateResponse(NHttp::THttpOutgoingResponsePtr response, const TString& error, TInstant now) {
- if (error.empty() || !CachePolicy.KeepOnError) {
- Response = response;
- }
- Retries = 0;
- if (CachePolicy.TimeToRefresh) {
- RefreshTime = now + CachePolicy.TimeToRefresh;
- if (CachePolicy.PaceToRefresh) {
- RefreshTime += TDuration::MilliSeconds(RandomNumber<ui64>() % CachePolicy.PaceToRefresh.MilliSeconds());
- }
- }
- }
-
- void UpdateExpireTime() {
- if (CachePolicy.TimeToExpire) {
- DeathTime = NActors::TlsActivationContext->Now() + CachePolicy.TimeToExpire;
- }
- }
-
- TString GetName() const {
- return TStringBuilder() << (Request->Secure ? "https://" : "http://") << Request->Host << Request->URL
- << " (" << CacheId << ")";
- }
- };
-
- struct TRefreshRecord {
- TCacheKey Key;
- TInstant RefreshTime;
-
- bool operator <(const TRefreshRecord& b) const {
- return RefreshTime > b.RefreshTime;
- }
- };
-
- THashMap<TCacheKey, TCacheRecord> Cache;
- TPriorityQueue<TRefreshRecord> RefreshQueue;
- THashMap<THttpIncomingRequest*, TCacheKey> IncomingRequests;
-
- THttpIncomingCacheActor(const NActors::TActorId& httpProxyId, TGetCachePolicy getCachePolicy)
- : HttpProxyId(httpProxyId)
- , GetCachePolicy(std::move(getCachePolicy))
- {}
-
- void Bootstrap(const NActors::TActorContext&) {
- //
- Become(&THttpIncomingCacheActor::StateWork, RefreshTimeout, new NActors::TEvents::TEvWakeup());
- }
-
- static TString GetCacheHeadersKey(const NHttp::THttpIncomingRequest* request, const TCachePolicy& policy) {
- TStringBuilder key;
- if (!policy.HeadersToCacheKey.empty()) {
- NHttp::THeaders headers(request->Headers);
- for (const TString& header : policy.HeadersToCacheKey) {
- key << headers[header];
- }
- }
- return key;
- }
-
- static TCacheKey GetCacheKey(const NHttp::THttpIncomingRequest* request, const TCachePolicy& policy) {
- return { ToString(request->Host), ToString(request->URL), GetCacheHeadersKey(request, policy) };
- }
-
- TActorId GetRequestHandler(NHttp::THttpIncomingRequestPtr request) {
- TStringBuf url = request->URL.Before('?');
- THashMap<TString, TActorId>::iterator it;
- while (!url.empty()) {
- it = Handlers.find(url);
- if (it != Handlers.end()) {
- return it->second;
- } else {
- if (url.EndsWith('/')) {
- url.Trunc(url.size() - 1);
- }
- size_t pos = url.rfind('/');
- if (pos == TStringBuf::npos) {
- break;
- } else {
- url = url.substr(0, pos + 1);
- }
- }
- }
- return {};
- }
-
- void SendCacheRequest(const TCacheKey& cacheKey, TCacheRecord& cacheRecord, const NActors::TActorContext& ctx) {
- cacheRecord.Request = cacheRecord.Request->Duplicate();
- IncomingRequests[cacheRecord.Request.Get()] = cacheKey;
- TActorId handler = GetRequestHandler(cacheRecord.Request);
- if (handler) {
- Send(handler, new NHttp::TEvHttpProxy::TEvHttpIncomingRequest(cacheRecord.Request));
- } else {
- LOG_ERROR_S(ctx, HttpLog, "Can't find cache handler for " << cacheRecord.GetName());
- }
- }
-
- void DropCacheRecord(THashMap<TCacheKey, TCacheRecord>::iterator it) {
- if (it->second.Request) {
- IncomingRequests.erase(it->second.Request.Get());
- }
- for (auto& waiter : it->second.Waiters) {
- NHttp::THttpOutgoingResponsePtr response;
- response = waiter->Get()->Request->CreateResponseGatewayTimeout("Timeout", "text/plain");
- Send(waiter->Sender, new NHttp::TEvHttpProxy::TEvHttpOutgoingResponse(response));
- }
- Cache.erase(it);
- }
-
- void Handle(NHttp::TEvHttpProxy::TEvHttpIncomingResponse::TPtr event, const NActors::TActorContext& ctx) {
- ctx.Send(event->Forward(HttpProxyId));
- }
-
- void Handle(NHttp::TEvHttpProxy::TEvHttpOutgoingRequest::TPtr event, const NActors::TActorContext& ctx) {
- ctx.Send(event->Forward(HttpProxyId));
- }
-
- void Handle(NHttp::TEvHttpProxy::TEvAddListeningPort::TPtr event, const NActors::TActorContext& ctx) {
- ctx.Send(event->Forward(HttpProxyId));
- }
-
- void Handle(NHttp::TEvHttpProxy::TEvRegisterHandler::TPtr event, const NActors::TActorContext& ctx) {
- Handlers[event->Get()->Path] = event->Get()->Handler;
- ctx.Send(HttpProxyId, new NHttp::TEvHttpProxy::TEvRegisterHandler(event->Get()->Path, ctx.SelfID));
- }
-
- void Handle(NHttp::TEvHttpProxy::TEvHttpOutgoingResponse::TPtr event, const NActors::TActorContext& ctx) {
- NHttp::THttpIncomingRequestPtr request(event->Get()->Response->GetRequest());
- NHttp::THttpOutgoingResponsePtr response(event->Get()->Response);
- auto itRequests = IncomingRequests.find(request.Get());
- if (itRequests == IncomingRequests.end()) {
- LOG_ERROR_S(ctx, HttpLog, "Cache received response to unknown request " << request->Host << request->URL);
- return;
- }
-
- TCacheKey key = itRequests->second;
- auto it = Cache.find(key);
- if (it == Cache.end()) {
- LOG_ERROR_S(ctx, HttpLog, "Cache received response to unknown cache key " << request->Host << request->URL);
- return;
- }
-
- IncomingRequests.erase(itRequests);
- TCacheRecord& cacheRecord = it->second;
- TStringBuf status;
- TString error;
-
- if (event->Get()->Response != nullptr) {
- status = event->Get()->Response->Status;
- if (!status.StartsWith("2")) {
- error = event->Get()->Response->Message;
- }
- }
- if (cacheRecord.CachePolicy.RetriesCount > 0) {
- auto itStatusToRetry = std::find(cacheRecord.CachePolicy.StatusesToRetry.begin(), cacheRecord.CachePolicy.StatusesToRetry.end(), status);
- if (itStatusToRetry != cacheRecord.CachePolicy.StatusesToRetry.end()) {
- if (cacheRecord.Retries < cacheRecord.CachePolicy.RetriesCount) {
- ++cacheRecord.Retries;
- LOG_WARN_S(ctx, HttpLog, "IncomingRetry " << cacheRecord.GetName() << ": " << status << " " << error);
- SendCacheRequest(key, cacheRecord, ctx);
- return;
- }
- }
- }
- for (auto& waiter : cacheRecord.Waiters) {
- NHttp::THttpOutgoingResponsePtr response2;
- response2 = response->Duplicate(waiter->Get()->Request);
- ctx.Send(waiter->Sender, new NHttp::TEvHttpProxy::TEvHttpOutgoingResponse(response2));
- }
- cacheRecord.Waiters.clear();
- if (!error.empty()) {
- LOG_WARN_S(ctx, HttpLog, "Error from " << cacheRecord.GetName() << ": " << error);
- if (!cacheRecord.Response) {
- LOG_DEBUG_S(ctx, HttpLog, "IncomingDiscard " << cacheRecord.GetName());
- DropCacheRecord(it);
- return;
- }
- }
- if (cacheRecord.CachePolicy.TimeToRefresh) {
- LOG_DEBUG_S(ctx, HttpLog, "IncomingUpdate " << cacheRecord.GetName());
- cacheRecord.UpdateResponse(response, error, ctx.Now());
- if (!cacheRecord.Enqueued) {
- RefreshQueue.push({it->first, it->second.RefreshTime});
- cacheRecord.Enqueued = true;
- }
- LOG_DEBUG_S(ctx, HttpLog, "IncomingSchedule " << cacheRecord.GetName() << " at " << cacheRecord.RefreshTime << " until " << cacheRecord.DeathTime);
- } else {
- LOG_DEBUG_S(ctx, HttpLog, "IncomingDrop " << cacheRecord.GetName());
- DropCacheRecord(it);
- }
- }
-
- void Handle(NHttp::TEvHttpProxy::TEvHttpIncomingRequest::TPtr event, const NActors::TActorContext& ctx) {
- const NHttp::THttpIncomingRequest* request = event->Get()->Request.Get();
- TCachePolicy policy = GetCachePolicy(request);
- if (policy.TimeToExpire == TDuration() && policy.RetriesCount == 0) {
- TActorId handler = GetRequestHandler(event->Get()->Request);
- if (handler) {
- ctx.Send(event->Forward(handler));
- }
- return;
- }
- auto key = GetCacheKey(request, policy);
- auto it = Cache.find(key);
- if (it != Cache.end() && !policy.DiscardCache) {
- it->second.UpdateExpireTime();
- if (it->second.IsValid()) {
- LOG_DEBUG_S(ctx, HttpLog, "IncomingRespond "
- << it->second.GetName()
- << " ("
- << ((it->second.Response != nullptr) ? ToString(it->second.Response->Size()) : TString("error"))
- << ")");
- NHttp::THttpOutgoingResponsePtr response = it->second.Response;
- if (response != nullptr) {
- response = response->Duplicate(event->Get()->Request);
- }
- ctx.Send(event->Sender, new NHttp::TEvHttpProxy::TEvHttpOutgoingResponse(response));
- return;
- }
- } else {
- it = Cache.emplace(key, policy).first;
- it->second.CacheId = key.GetId(); // for debugging
- it->second.InitRequest(event->Get()->Request);
- if (policy.DiscardCache) {
- LOG_DEBUG_S(ctx, HttpLog, "IncomingDiscardCache " << it->second.GetName());
- }
- LOG_DEBUG_S(ctx, HttpLog, "IncomingInitiate " << it->second.GetName());
- SendCacheRequest(key, it->second, ctx);
- }
- it->second.Waiters.emplace_back(std::move(event));
- }
-
- void HandleRefresh(const NActors::TActorContext& ctx) {
- while (!RefreshQueue.empty() && RefreshQueue.top().RefreshTime <= ctx.Now()) {
- TRefreshRecord rrec = RefreshQueue.top();
- RefreshQueue.pop();
- auto it = Cache.find(rrec.Key);
- if (it != Cache.end()) {
- it->second.Enqueued = false;
- if (it->second.DeathTime > ctx.Now()) {
- LOG_DEBUG_S(ctx, HttpLog, "IncomingRefresh " << it->second.GetName());
- SendCacheRequest(it->first, it->second, ctx);
- } else {
- LOG_DEBUG_S(ctx, HttpLog, "IncomingForget " << it->second.GetName());
- DropCacheRecord(it);
- }
- }
- }
- ctx.Schedule(RefreshTimeout, new NActors::TEvents::TEvWakeup());
- }
-
- STFUNC(StateWork) {
- switch (ev->GetTypeRewrite()) {
- HFunc(NHttp::TEvHttpProxy::TEvHttpIncomingResponse, Handle);
- HFunc(NHttp::TEvHttpProxy::TEvHttpOutgoingRequest, Handle);
- HFunc(NHttp::TEvHttpProxy::TEvAddListeningPort, Handle);
- HFunc(NHttp::TEvHttpProxy::TEvRegisterHandler, Handle);
- HFunc(NHttp::TEvHttpProxy::TEvHttpIncomingRequest, Handle);
- HFunc(NHttp::TEvHttpProxy::TEvHttpOutgoingResponse, Handle);
- CFunc(NActors::TEvents::TSystem::Wakeup, HandleRefresh);
- }
- }
-};
-
-TCachePolicy GetDefaultCachePolicy(const THttpRequest* request, const TCachePolicy& defaultPolicy) {
- TCachePolicy policy = defaultPolicy;
- THeaders headers(request->Headers);
- TStringBuf cacheControl(headers["Cache-Control"]);
- while (TStringBuf cacheItem = cacheControl.NextTok(',')) {
- Trim(cacheItem, ' ');
- if (cacheItem == "no-store" || cacheItem == "no-cache") {
- policy.DiscardCache = true;
- }
- TStringBuf itemName = cacheItem.NextTok('=');
- TrimEnd(itemName, ' ');
- TrimBegin(cacheItem, ' ');
- if (itemName == "max-age") {
- policy.TimeToRefresh = policy.TimeToExpire = TDuration::Seconds(FromString(cacheItem));
- }
- if (itemName == "min-fresh") {
- policy.TimeToRefresh = policy.TimeToExpire = TDuration::Seconds(FromString(cacheItem));
- }
- if (itemName == "stale-if-error") {
- policy.KeepOnError = true;
- }
- }
- return policy;
-}
-
+ TGetCachePolicy GetCachePolicy;
+ static constexpr TDuration RefreshTimeout = TDuration::Seconds(1);
+
+ struct TCacheKey {
+ TString Host;
+ TString URL;
+ TString Headers;
+
+ operator size_t() const {
+ return MultiHash(Host, URL, Headers);
+ }
+
+ TString GetId() const {
+ return MD5::Calc(Host + ':' + URL + ':' + Headers);
+ }
+ };
+
+ struct TCacheRecord {
+ TInstant RefreshTime;
+ TInstant DeathTime;
+ TCachePolicy CachePolicy;
+ NHttp::THttpOutgoingRequestPtr Request;
+ NHttp::THttpOutgoingRequestPtr OutgoingRequest;
+ TDuration Timeout;
+ NHttp::THttpIncomingResponsePtr Response;
+ TString Error;
+ TVector<NHttp::TEvHttpProxy::TEvHttpOutgoingRequest::TPtr> Waiters;
+
+ TCacheRecord(const TCachePolicy cachePolicy)
+ : CachePolicy(cachePolicy)
+ {}
+
+ bool IsValid() const {
+ return Response != nullptr || !Error.empty();
+ }
+
+ void UpdateResponse(NHttp::THttpIncomingResponsePtr response, const TString& error, TInstant now) {
+ if (error.empty() || Response == nullptr || !CachePolicy.KeepOnError) {
+ Response = response;
+ Error = error;
+ }
+ RefreshTime = now + CachePolicy.TimeToRefresh;
+ if (CachePolicy.PaceToRefresh) {
+ RefreshTime += TDuration::MilliSeconds(RandomNumber<ui64>() % CachePolicy.PaceToRefresh.MilliSeconds());
+ }
+ }
+
+ TString GetName() const {
+ return TStringBuilder() << (Request->Secure ? "https://" : "http://") << Request->Host << Request->URL;
+ }
+ };
+
+ struct TRefreshRecord {
+ TCacheKey Key;
+ TInstant RefreshTime;
+
+ bool operator <(const TRefreshRecord& b) const {
+ return RefreshTime > b.RefreshTime;
+ }
+ };
+
+ THashMap<TCacheKey, TCacheRecord> Cache;
+ TPriorityQueue<TRefreshRecord> RefreshQueue;
+ THashMap<THttpOutgoingRequest*, TCacheKey> OutgoingRequests;
+
+ THttpOutgoingCacheActor(const NActors::TActorId& httpProxyId, TGetCachePolicy getCachePolicy)
+ : HttpProxyId(httpProxyId)
+ , GetCachePolicy(std::move(getCachePolicy))
+ {}
+
+ void Bootstrap(const NActors::TActorContext&) {
+ //
+ Become(&THttpOutgoingCacheActor::StateWork, RefreshTimeout, new NActors::TEvents::TEvWakeup());
+ }
+
+ static TString GetCacheHeadersKey(const NHttp::THttpOutgoingRequest* request, const TCachePolicy& policy) {
+ TStringBuilder key;
+ if (!policy.HeadersToCacheKey.empty()) {
+ NHttp::THeaders headers(request->Headers);
+ for (const TString& header : policy.HeadersToCacheKey) {
+ key << headers[header];
+ }
+ }
+ return key;
+ }
+
+ static TCacheKey GetCacheKey(const NHttp::THttpOutgoingRequest* request, const TCachePolicy& policy) {
+ return { ToString(request->Host), ToString(request->URL), GetCacheHeadersKey(request, policy) };
+ }
+
+ void Handle(NHttp::TEvHttpProxy::TEvHttpOutgoingResponse::TPtr event, const NActors::TActorContext& ctx) {
+ ctx.Send(event->Forward(HttpProxyId));
+ }
+
+ void Handle(NHttp::TEvHttpProxy::TEvHttpIncomingRequest::TPtr event, const NActors::TActorContext& ctx) {
+ ctx.Send(event->Forward(HttpProxyId));
+ }
+
+ void Handle(NHttp::TEvHttpProxy::TEvAddListeningPort::TPtr event, const NActors::TActorContext& ctx) {
+ ctx.Send(event->Forward(HttpProxyId));
+ }
+
+ void Handle(NHttp::TEvHttpProxy::TEvRegisterHandler::TPtr event, const NActors::TActorContext& ctx) {
+ ctx.Send(event->Forward(HttpProxyId));
+ }
+
+ void Handle(NHttp::TEvHttpProxy::TEvHttpIncomingResponse::TPtr event, const NActors::TActorContext& ctx) {
+ NHttp::THttpOutgoingRequestPtr request(event->Get()->Request);
+ NHttp::THttpIncomingResponsePtr response(event->Get()->Response);
+ auto itRequests = OutgoingRequests.find(request.Get());
+ if (itRequests == OutgoingRequests.end()) {
+ LOG_ERROR_S(ctx, HttpLog, "Cache received response to unknown request " << request->Host << request->URL);
+ return;
+ }
+ auto key = itRequests->second;
+ OutgoingRequests.erase(itRequests);
+ auto it = Cache.find(key);
+ if (it == Cache.end()) {
+ LOG_ERROR_S(ctx, HttpLog, "Cache received response to unknown cache key " << request->Host << request->URL);
+ return;
+ }
+ TCacheRecord& cacheRecord = it->second;
+ cacheRecord.OutgoingRequest.Reset();
+ for (auto& waiter : cacheRecord.Waiters) {
+ NHttp::THttpIncomingResponsePtr response2;
+ TString error2;
+ if (response != nullptr) {
+ response2 = response->Duplicate(waiter->Get()->Request);
+ }
+ if (!event->Get()->Error.empty()) {
+ error2 = event->Get()->Error;
+ }
+ ctx.Send(waiter->Sender, new NHttp::TEvHttpProxy::TEvHttpIncomingResponse(waiter->Get()->Request, response2, error2));
+ }
+ cacheRecord.Waiters.clear();
+ TString error;
+ if (event->Get()->Error.empty()) {
+ if (event->Get()->Response != nullptr && event->Get()->Response->Status != "200") {
+ error = event->Get()->Response->Message;
+ }
+ } else {
+ error = event->Get()->Error;
+ }
+ if (!error.empty()) {
+ LOG_WARN_S(ctx, HttpLog, "Error from " << cacheRecord.GetName() << ": " << error);
+ }
+ LOG_DEBUG_S(ctx, HttpLog, "OutgoingUpdate " << cacheRecord.GetName());
+ cacheRecord.UpdateResponse(response, event->Get()->Error, ctx.Now());
+ RefreshQueue.push({it->first, it->second.RefreshTime});
+ LOG_DEBUG_S(ctx, HttpLog, "OutgoingSchedule " << cacheRecord.GetName() << " at " << cacheRecord.RefreshTime << " until " << cacheRecord.DeathTime);
+ }
+
+ void Handle(NHttp::TEvHttpProxy::TEvHttpOutgoingRequest::TPtr event, const NActors::TActorContext& ctx) {
+ const NHttp::THttpOutgoingRequest* request = event->Get()->Request.Get();
+ auto policy = GetCachePolicy(request);
+ if (policy.TimeToExpire == TDuration()) {
+ ctx.Send(event->Forward(HttpProxyId));
+ return;
+ }
+ auto key = GetCacheKey(request, policy);
+ auto it = Cache.find(key);
+ if (it != Cache.end()) {
+ if (it->second.IsValid()) {
+ LOG_DEBUG_S(ctx, HttpLog, "OutgoingRespond "
+ << it->second.GetName()
+ << " ("
+ << ((it->second.Response != nullptr) ? ToString(it->second.Response->Size()) : TString("error"))
+ << ")");
+ NHttp::THttpIncomingResponsePtr response = it->second.Response;
+ if (response != nullptr) {
+ response = response->Duplicate(event->Get()->Request);
+ }
+ ctx.Send(event->Sender,
+ new NHttp::TEvHttpProxy::TEvHttpIncomingResponse(event->Get()->Request,
+ response,
+ it->second.Error));
+ it->second.DeathTime = ctx.Now() + it->second.CachePolicy.TimeToExpire; // prolong active cache items
+ return;
+ }
+ } else {
+ it = Cache.emplace(key, policy).first;
+ it->second.Request = event->Get()->Request;
+ it->second.Timeout = event->Get()->Timeout;
+ it->second.OutgoingRequest = it->second.Request->Duplicate();
+ OutgoingRequests[it->second.OutgoingRequest.Get()] = key;
+ LOG_DEBUG_S(ctx, HttpLog, "OutgoingInitiate " << it->second.GetName());
+ ctx.Send(HttpProxyId, new NHttp::TEvHttpProxy::TEvHttpOutgoingRequest(it->second.OutgoingRequest, it->second.Timeout));
+ }
+ it->second.DeathTime = ctx.Now() + it->second.CachePolicy.TimeToExpire;
+ it->second.Waiters.emplace_back(std::move(event));
+ }
+
+ void HandleRefresh(const NActors::TActorContext& ctx) {
+ while (!RefreshQueue.empty() && RefreshQueue.top().RefreshTime <= ctx.Now()) {
+ TRefreshRecord rrec = RefreshQueue.top();
+ RefreshQueue.pop();
+ auto it = Cache.find(rrec.Key);
+ if (it != Cache.end()) {
+ if (it->second.DeathTime > ctx.Now()) {
+ LOG_DEBUG_S(ctx, HttpLog, "OutgoingRefresh " << it->second.GetName());
+ it->second.OutgoingRequest = it->second.Request->Duplicate();
+ OutgoingRequests[it->second.OutgoingRequest.Get()] = it->first;
+ ctx.Send(HttpProxyId, new NHttp::TEvHttpProxy::TEvHttpOutgoingRequest(it->second.OutgoingRequest, it->second.Timeout));
+ } else {
+ LOG_DEBUG_S(ctx, HttpLog, "OutgoingForget " << it->second.GetName());
+ if (it->second.OutgoingRequest) {
+ OutgoingRequests.erase(it->second.OutgoingRequest.Get());
+ }
+ Cache.erase(it);
+ }
+ }
+ }
+ ctx.Schedule(RefreshTimeout, new NActors::TEvents::TEvWakeup());
+ }
+
+ STFUNC(StateWork) {
+ switch (ev->GetTypeRewrite()) {
+ HFunc(NHttp::TEvHttpProxy::TEvHttpIncomingResponse, Handle);
+ HFunc(NHttp::TEvHttpProxy::TEvHttpOutgoingRequest, Handle);
+ HFunc(NHttp::TEvHttpProxy::TEvAddListeningPort, Handle);
+ HFunc(NHttp::TEvHttpProxy::TEvRegisterHandler, Handle);
+ HFunc(NHttp::TEvHttpProxy::TEvHttpIncomingRequest, Handle);
+ HFunc(NHttp::TEvHttpProxy::TEvHttpOutgoingResponse, Handle);
+ CFunc(NActors::TEvents::TSystem::Wakeup, HandleRefresh);
+ }
+ }
+};
+
+const TDuration THttpOutgoingCacheActor::RefreshTimeout;
+
+class THttpIncomingCacheActor : public NActors::TActorBootstrapped<THttpIncomingCacheActor>, THttpConfig {
+public:
+ using TBase = NActors::TActorBootstrapped<THttpIncomingCacheActor>;
+ NActors::TActorId HttpProxyId;
+ TGetCachePolicy GetCachePolicy;
+ static constexpr TDuration RefreshTimeout = TDuration::Seconds(1);
+ THashMap<TString, TActorId> Handlers;
+
+ struct TCacheKey {
+ TString Host;
+ TString URL;
+ TString Headers;
+
+ operator size_t() const {
+ return MultiHash(Host, URL, Headers);
+ }
+
+ TString GetId() const {
+ return MD5::Calc(Host + ':' + URL + ':' + Headers);
+ }
+ };
+
+ struct TCacheRecord {
+ TInstant RefreshTime;
+ TInstant DeathTime;
+ TCachePolicy CachePolicy;
+ TString CacheId;
+ NHttp::THttpIncomingRequestPtr Request;
+ TDuration Timeout;
+ NHttp::THttpOutgoingResponsePtr Response;
+ TVector<NHttp::TEvHttpProxy::TEvHttpIncomingRequest::TPtr> Waiters;
+ ui32 Retries = 0;
+ bool Enqueued = false;
+
+ TCacheRecord(const TCachePolicy cachePolicy)
+ : CachePolicy(cachePolicy)
+ {}
+
+ bool IsValid() const {
+ return Response != nullptr;
+ }
+
+ void InitRequest(NHttp::THttpIncomingRequestPtr request) {
+ Request = request;
+ if (CachePolicy.TimeToExpire) {
+ DeathTime = NActors::TlsActivationContext->Now() + CachePolicy.TimeToExpire;
+ }
+ }
+
+ void UpdateResponse(NHttp::THttpOutgoingResponsePtr response, const TString& error, TInstant now) {
+ if (error.empty() || !CachePolicy.KeepOnError) {
+ Response = response;
+ }
+ Retries = 0;
+ if (CachePolicy.TimeToRefresh) {
+ RefreshTime = now + CachePolicy.TimeToRefresh;
+ if (CachePolicy.PaceToRefresh) {
+ RefreshTime += TDuration::MilliSeconds(RandomNumber<ui64>() % CachePolicy.PaceToRefresh.MilliSeconds());
+ }
+ }
+ }
+
+ void UpdateExpireTime() {
+ if (CachePolicy.TimeToExpire) {
+ DeathTime = NActors::TlsActivationContext->Now() + CachePolicy.TimeToExpire;
+ }
+ }
+
+ TString GetName() const {
+ return TStringBuilder() << (Request->Secure ? "https://" : "http://") << Request->Host << Request->URL
+ << " (" << CacheId << ")";
+ }
+ };
+
+ struct TRefreshRecord {
+ TCacheKey Key;
+ TInstant RefreshTime;
+
+ bool operator <(const TRefreshRecord& b) const {
+ return RefreshTime > b.RefreshTime;
+ }
+ };
+
+ THashMap<TCacheKey, TCacheRecord> Cache;
+ TPriorityQueue<TRefreshRecord> RefreshQueue;
+ THashMap<THttpIncomingRequest*, TCacheKey> IncomingRequests;
+
+ THttpIncomingCacheActor(const NActors::TActorId& httpProxyId, TGetCachePolicy getCachePolicy)
+ : HttpProxyId(httpProxyId)
+ , GetCachePolicy(std::move(getCachePolicy))
+ {}
+
+ void Bootstrap(const NActors::TActorContext&) {
+ //
+ Become(&THttpIncomingCacheActor::StateWork, RefreshTimeout, new NActors::TEvents::TEvWakeup());
+ }
+
+ static TString GetCacheHeadersKey(const NHttp::THttpIncomingRequest* request, const TCachePolicy& policy) {
+ TStringBuilder key;
+ if (!policy.HeadersToCacheKey.empty()) {
+ NHttp::THeaders headers(request->Headers);
+ for (const TString& header : policy.HeadersToCacheKey) {
+ key << headers[header];
+ }
+ }
+ return key;
+ }
+
+ static TCacheKey GetCacheKey(const NHttp::THttpIncomingRequest* request, const TCachePolicy& policy) {
+ return { ToString(request->Host), ToString(request->URL), GetCacheHeadersKey(request, policy) };
+ }
+
+ TActorId GetRequestHandler(NHttp::THttpIncomingRequestPtr request) {
+ TStringBuf url = request->URL.Before('?');
+ THashMap<TString, TActorId>::iterator it;
+ while (!url.empty()) {
+ it = Handlers.find(url);
+ if (it != Handlers.end()) {
+ return it->second;
+ } else {
+ if (url.EndsWith('/')) {
+ url.Trunc(url.size() - 1);
+ }
+ size_t pos = url.rfind('/');
+ if (pos == TStringBuf::npos) {
+ break;
+ } else {
+ url = url.substr(0, pos + 1);
+ }
+ }
+ }
+ return {};
+ }
+
+ void SendCacheRequest(const TCacheKey& cacheKey, TCacheRecord& cacheRecord, const NActors::TActorContext& ctx) {
+ cacheRecord.Request = cacheRecord.Request->Duplicate();
+ IncomingRequests[cacheRecord.Request.Get()] = cacheKey;
+ TActorId handler = GetRequestHandler(cacheRecord.Request);
+ if (handler) {
+ Send(handler, new NHttp::TEvHttpProxy::TEvHttpIncomingRequest(cacheRecord.Request));
+ } else {
+ LOG_ERROR_S(ctx, HttpLog, "Can't find cache handler for " << cacheRecord.GetName());
+ }
+ }
+
+ void DropCacheRecord(THashMap<TCacheKey, TCacheRecord>::iterator it) {
+ if (it->second.Request) {
+ IncomingRequests.erase(it->second.Request.Get());
+ }
+ for (auto& waiter : it->second.Waiters) {
+ NHttp::THttpOutgoingResponsePtr response;
+ response = waiter->Get()->Request->CreateResponseGatewayTimeout("Timeout", "text/plain");
+ Send(waiter->Sender, new NHttp::TEvHttpProxy::TEvHttpOutgoingResponse(response));
+ }
+ Cache.erase(it);
+ }
+
+ void Handle(NHttp::TEvHttpProxy::TEvHttpIncomingResponse::TPtr event, const NActors::TActorContext& ctx) {
+ ctx.Send(event->Forward(HttpProxyId));
+ }
+
+ void Handle(NHttp::TEvHttpProxy::TEvHttpOutgoingRequest::TPtr event, const NActors::TActorContext& ctx) {
+ ctx.Send(event->Forward(HttpProxyId));
+ }
+
+ void Handle(NHttp::TEvHttpProxy::TEvAddListeningPort::TPtr event, const NActors::TActorContext& ctx) {
+ ctx.Send(event->Forward(HttpProxyId));
+ }
+
+ void Handle(NHttp::TEvHttpProxy::TEvRegisterHandler::TPtr event, const NActors::TActorContext& ctx) {
+ Handlers[event->Get()->Path] = event->Get()->Handler;
+ ctx.Send(HttpProxyId, new NHttp::TEvHttpProxy::TEvRegisterHandler(event->Get()->Path, ctx.SelfID));
+ }
+
+ void Handle(NHttp::TEvHttpProxy::TEvHttpOutgoingResponse::TPtr event, const NActors::TActorContext& ctx) {
+ NHttp::THttpIncomingRequestPtr request(event->Get()->Response->GetRequest());
+ NHttp::THttpOutgoingResponsePtr response(event->Get()->Response);
+ auto itRequests = IncomingRequests.find(request.Get());
+ if (itRequests == IncomingRequests.end()) {
+ LOG_ERROR_S(ctx, HttpLog, "Cache received response to unknown request " << request->Host << request->URL);
+ return;
+ }
+
+ TCacheKey key = itRequests->second;
+ auto it = Cache.find(key);
+ if (it == Cache.end()) {
+ LOG_ERROR_S(ctx, HttpLog, "Cache received response to unknown cache key " << request->Host << request->URL);
+ return;
+ }
+
+ IncomingRequests.erase(itRequests);
+ TCacheRecord& cacheRecord = it->second;
+ TStringBuf status;
+ TString error;
+
+ if (event->Get()->Response != nullptr) {
+ status = event->Get()->Response->Status;
+ if (!status.StartsWith("2")) {
+ error = event->Get()->Response->Message;
+ }
+ }
+ if (cacheRecord.CachePolicy.RetriesCount > 0) {
+ auto itStatusToRetry = std::find(cacheRecord.CachePolicy.StatusesToRetry.begin(), cacheRecord.CachePolicy.StatusesToRetry.end(), status);
+ if (itStatusToRetry != cacheRecord.CachePolicy.StatusesToRetry.end()) {
+ if (cacheRecord.Retries < cacheRecord.CachePolicy.RetriesCount) {
+ ++cacheRecord.Retries;
+ LOG_WARN_S(ctx, HttpLog, "IncomingRetry " << cacheRecord.GetName() << ": " << status << " " << error);
+ SendCacheRequest(key, cacheRecord, ctx);
+ return;
+ }
+ }
+ }
+ for (auto& waiter : cacheRecord.Waiters) {
+ NHttp::THttpOutgoingResponsePtr response2;
+ response2 = response->Duplicate(waiter->Get()->Request);
+ ctx.Send(waiter->Sender, new NHttp::TEvHttpProxy::TEvHttpOutgoingResponse(response2));
+ }
+ cacheRecord.Waiters.clear();
+ if (!error.empty()) {
+ LOG_WARN_S(ctx, HttpLog, "Error from " << cacheRecord.GetName() << ": " << error);
+ if (!cacheRecord.Response) {
+ LOG_DEBUG_S(ctx, HttpLog, "IncomingDiscard " << cacheRecord.GetName());
+ DropCacheRecord(it);
+ return;
+ }
+ }
+ if (cacheRecord.CachePolicy.TimeToRefresh) {
+ LOG_DEBUG_S(ctx, HttpLog, "IncomingUpdate " << cacheRecord.GetName());
+ cacheRecord.UpdateResponse(response, error, ctx.Now());
+ if (!cacheRecord.Enqueued) {
+ RefreshQueue.push({it->first, it->second.RefreshTime});
+ cacheRecord.Enqueued = true;
+ }
+ LOG_DEBUG_S(ctx, HttpLog, "IncomingSchedule " << cacheRecord.GetName() << " at " << cacheRecord.RefreshTime << " until " << cacheRecord.DeathTime);
+ } else {
+ LOG_DEBUG_S(ctx, HttpLog, "IncomingDrop " << cacheRecord.GetName());
+ DropCacheRecord(it);
+ }
+ }
+
+ void Handle(NHttp::TEvHttpProxy::TEvHttpIncomingRequest::TPtr event, const NActors::TActorContext& ctx) {
+ const NHttp::THttpIncomingRequest* request = event->Get()->Request.Get();
+ TCachePolicy policy = GetCachePolicy(request);
+ if (policy.TimeToExpire == TDuration() && policy.RetriesCount == 0) {
+ TActorId handler = GetRequestHandler(event->Get()->Request);
+ if (handler) {
+ ctx.Send(event->Forward(handler));
+ }
+ return;
+ }
+ auto key = GetCacheKey(request, policy);
+ auto it = Cache.find(key);
+ if (it != Cache.end() && !policy.DiscardCache) {
+ it->second.UpdateExpireTime();
+ if (it->second.IsValid()) {
+ LOG_DEBUG_S(ctx, HttpLog, "IncomingRespond "
+ << it->second.GetName()
+ << " ("
+ << ((it->second.Response != nullptr) ? ToString(it->second.Response->Size()) : TString("error"))
+ << ")");
+ NHttp::THttpOutgoingResponsePtr response = it->second.Response;
+ if (response != nullptr) {
+ response = response->Duplicate(event->Get()->Request);
+ }
+ ctx.Send(event->Sender, new NHttp::TEvHttpProxy::TEvHttpOutgoingResponse(response));
+ return;
+ }
+ } else {
+ it = Cache.emplace(key, policy).first;
+ it->second.CacheId = key.GetId(); // for debugging
+ it->second.InitRequest(event->Get()->Request);
+ if (policy.DiscardCache) {
+ LOG_DEBUG_S(ctx, HttpLog, "IncomingDiscardCache " << it->second.GetName());
+ }
+ LOG_DEBUG_S(ctx, HttpLog, "IncomingInitiate " << it->second.GetName());
+ SendCacheRequest(key, it->second, ctx);
+ }
+ it->second.Waiters.emplace_back(std::move(event));
+ }
+
+ void HandleRefresh(const NActors::TActorContext& ctx) {
+ while (!RefreshQueue.empty() && RefreshQueue.top().RefreshTime <= ctx.Now()) {
+ TRefreshRecord rrec = RefreshQueue.top();
+ RefreshQueue.pop();
+ auto it = Cache.find(rrec.Key);
+ if (it != Cache.end()) {
+ it->second.Enqueued = false;
+ if (it->second.DeathTime > ctx.Now()) {
+ LOG_DEBUG_S(ctx, HttpLog, "IncomingRefresh " << it->second.GetName());
+ SendCacheRequest(it->first, it->second, ctx);
+ } else {
+ LOG_DEBUG_S(ctx, HttpLog, "IncomingForget " << it->second.GetName());
+ DropCacheRecord(it);
+ }
+ }
+ }
+ ctx.Schedule(RefreshTimeout, new NActors::TEvents::TEvWakeup());
+ }
+
+ STFUNC(StateWork) {
+ switch (ev->GetTypeRewrite()) {
+ HFunc(NHttp::TEvHttpProxy::TEvHttpIncomingResponse, Handle);
+ HFunc(NHttp::TEvHttpProxy::TEvHttpOutgoingRequest, Handle);
+ HFunc(NHttp::TEvHttpProxy::TEvAddListeningPort, Handle);
+ HFunc(NHttp::TEvHttpProxy::TEvRegisterHandler, Handle);
+ HFunc(NHttp::TEvHttpProxy::TEvHttpIncomingRequest, Handle);
+ HFunc(NHttp::TEvHttpProxy::TEvHttpOutgoingResponse, Handle);
+ CFunc(NActors::TEvents::TSystem::Wakeup, HandleRefresh);
+ }
+ }
+};
+
+TCachePolicy GetDefaultCachePolicy(const THttpRequest* request, const TCachePolicy& defaultPolicy) {
+ TCachePolicy policy = defaultPolicy;
+ THeaders headers(request->Headers);
+ TStringBuf cacheControl(headers["Cache-Control"]);
+ while (TStringBuf cacheItem = cacheControl.NextTok(',')) {
+ Trim(cacheItem, ' ');
+ if (cacheItem == "no-store" || cacheItem == "no-cache") {
+ policy.DiscardCache = true;
+ }
+ TStringBuf itemName = cacheItem.NextTok('=');
+ TrimEnd(itemName, ' ');
+ TrimBegin(cacheItem, ' ');
+ if (itemName == "max-age") {
+ policy.TimeToRefresh = policy.TimeToExpire = TDuration::Seconds(FromString(cacheItem));
+ }
+ if (itemName == "min-fresh") {
+ policy.TimeToRefresh = policy.TimeToExpire = TDuration::Seconds(FromString(cacheItem));
+ }
+ if (itemName == "stale-if-error") {
+ policy.KeepOnError = true;
+ }
+ }
+ return policy;
+}
+
NActors::IActor* CreateHttpCache(const NActors::TActorId& httpProxyId, TGetCachePolicy cachePolicy) {
- return new THttpOutgoingCacheActor(httpProxyId, std::move(cachePolicy));
-}
-
-NActors::IActor* CreateOutgoingHttpCache(const NActors::TActorId& httpProxyId, TGetCachePolicy cachePolicy) {
- return new THttpOutgoingCacheActor(httpProxyId, std::move(cachePolicy));
-}
-
-NActors::IActor* CreateIncomingHttpCache(const NActors::TActorId& httpProxyId, TGetCachePolicy cachePolicy) {
- return new THttpIncomingCacheActor(httpProxyId, std::move(cachePolicy));
-}
-
-}
+ return new THttpOutgoingCacheActor(httpProxyId, std::move(cachePolicy));
+}
+
+NActors::IActor* CreateOutgoingHttpCache(const NActors::TActorId& httpProxyId, TGetCachePolicy cachePolicy) {
+ return new THttpOutgoingCacheActor(httpProxyId, std::move(cachePolicy));
+}
+
+NActors::IActor* CreateIncomingHttpCache(const NActors::TActorId& httpProxyId, TGetCachePolicy cachePolicy) {
+ return new THttpIncomingCacheActor(httpProxyId, std::move(cachePolicy));
+}
+
+}
diff --git a/library/cpp/actors/http/http_cache.h b/library/cpp/actors/http/http_cache.h
index ac38bdcac8..567a8105f0 100644
--- a/library/cpp/actors/http/http_cache.h
+++ b/library/cpp/actors/http/http_cache.h
@@ -1,27 +1,27 @@
-#pragma once
+#pragma once
#include <library/cpp/actors/core/actor.h>
-#include "http.h"
-
-namespace NHttp {
-
-struct TCachePolicy {
- TDuration TimeToExpire;
- TDuration TimeToRefresh;
- TDuration PaceToRefresh;
- bool KeepOnError = false;
- bool DiscardCache = false;
- TArrayRef<TString> HeadersToCacheKey;
- TArrayRef<TString> StatusesToRetry;
- ui32 RetriesCount = 0;
-
- TCachePolicy() = default;
-};
-
-using TGetCachePolicy = std::function<TCachePolicy(const THttpRequest*)>;
-
+#include "http.h"
+
+namespace NHttp {
+
+struct TCachePolicy {
+ TDuration TimeToExpire;
+ TDuration TimeToRefresh;
+ TDuration PaceToRefresh;
+ bool KeepOnError = false;
+ bool DiscardCache = false;
+ TArrayRef<TString> HeadersToCacheKey;
+ TArrayRef<TString> StatusesToRetry;
+ ui32 RetriesCount = 0;
+
+ TCachePolicy() = default;
+};
+
+using TGetCachePolicy = std::function<TCachePolicy(const THttpRequest*)>;
+
NActors::IActor* CreateHttpCache(const NActors::TActorId& httpProxyId, TGetCachePolicy cachePolicy);
-NActors::IActor* CreateOutgoingHttpCache(const NActors::TActorId& httpProxyId, TGetCachePolicy cachePolicy);
-NActors::IActor* CreateIncomingHttpCache(const NActors::TActorId& httpProxyId, TGetCachePolicy cachePolicy);
-TCachePolicy GetDefaultCachePolicy(const THttpRequest* request, const TCachePolicy& policy = TCachePolicy());
-
-}
+NActors::IActor* CreateOutgoingHttpCache(const NActors::TActorId& httpProxyId, TGetCachePolicy cachePolicy);
+NActors::IActor* CreateIncomingHttpCache(const NActors::TActorId& httpProxyId, TGetCachePolicy cachePolicy);
+TCachePolicy GetDefaultCachePolicy(const THttpRequest* request, const TCachePolicy& policy = TCachePolicy());
+
+}
diff --git a/library/cpp/actors/http/http_config.h b/library/cpp/actors/http/http_config.h
index faeff79449..eeafd2a019 100644
--- a/library/cpp/actors/http/http_config.h
+++ b/library/cpp/actors/http/http_config.h
@@ -1,19 +1,19 @@
-#pragma once
-#include <util/network/sock.h>
+#pragma once
+#include <util/network/sock.h>
#include <library/cpp/actors/core/log.h>
#include <library/cpp/actors/protos/services_common.pb.h>
-
-namespace NHttp {
-
-struct THttpConfig {
- static constexpr NActors::NLog::EComponent HttpLog = NActorsServices::EServiceCommon::HTTP;
- static constexpr size_t BUFFER_SIZE = 64 * 1024;
- static constexpr size_t BUFFER_MIN_STEP = 10 * 1024;
- 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;
-};
-
-}
+
+namespace NHttp {
+
+struct THttpConfig {
+ static constexpr NActors::NLog::EComponent HttpLog = NActorsServices::EServiceCommon::HTTP;
+ static constexpr size_t BUFFER_SIZE = 64 * 1024;
+ static constexpr size_t BUFFER_MIN_STEP = 10 * 1024;
+ 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;
+};
+
+}
diff --git a/library/cpp/actors/http/http_proxy.cpp b/library/cpp/actors/http/http_proxy.cpp
index 36c6855d93..2217838624 100644
--- a/library/cpp/actors/http/http_proxy.cpp
+++ b/library/cpp/actors/http/http_proxy.cpp
@@ -1,314 +1,314 @@
#include <library/cpp/actors/core/events.h>
#include <library/cpp/monlib/metrics/metric_registry.h>
-#include "http_proxy.h"
-
-namespace NHttp {
-
-class THttpProxy : public NActors::TActorBootstrapped<THttpProxy>, public THttpConfig {
-public:
- IActor* AddListeningPort(TEvHttpProxy::TEvAddListeningPort::TPtr event, const NActors::TActorContext& ctx) {
- IActor* listeningSocket = CreateHttpAcceptorActor(ctx.SelfID, Poller);
+#include "http_proxy.h"
+
+namespace NHttp {
+
+class THttpProxy : public NActors::TActorBootstrapped<THttpProxy>, public THttpConfig {
+public:
+ IActor* AddListeningPort(TEvHttpProxy::TEvAddListeningPort::TPtr event, const NActors::TActorContext& ctx) {
+ IActor* listeningSocket = CreateHttpAcceptorActor(ctx.SelfID, Poller);
TActorId acceptorId = ctx.Register(listeningSocket);
- ctx.Send(event->Forward(acceptorId));
- Acceptors.emplace_back(acceptorId);
- return listeningSocket;
- }
-
- IActor* AddOutgoingConnection(const TString& address, bool secure, const NActors::TActorContext& ctx) {
- IActor* connectionSocket = CreateOutgoingConnectionActor(ctx.SelfID, address, secure, Poller);
+ ctx.Send(event->Forward(acceptorId));
+ Acceptors.emplace_back(acceptorId);
+ return listeningSocket;
+ }
+
+ IActor* AddOutgoingConnection(const TString& address, bool secure, const NActors::TActorContext& ctx) {
+ IActor* connectionSocket = CreateOutgoingConnectionActor(ctx.SelfID, address, secure, Poller);
TActorId connectionId = ctx.Register(connectionSocket);
- Connections.emplace(connectionId);
- return connectionSocket;
- }
-
- void Bootstrap(const NActors::TActorContext& ctx) {
- Poller = ctx.Register(NActors::CreatePollerActor());
- Become(&THttpProxy::StateWork);
- }
-
+ Connections.emplace(connectionId);
+ return connectionSocket;
+ }
+
+ void Bootstrap(const NActors::TActorContext& ctx) {
+ Poller = ctx.Register(NActors::CreatePollerActor());
+ Become(&THttpProxy::StateWork);
+ }
+
THttpProxy(NMonitoring::TMetricRegistry& sensors)
- : Sensors(sensors)
- {}
-
-protected:
- STFUNC(StateWork) {
- switch (ev->GetTypeRewrite()) {
- HFunc(TEvHttpProxy::TEvAddListeningPort, Handle);
- HFunc(TEvHttpProxy::TEvRegisterHandler, Handle);
- HFunc(TEvHttpProxy::TEvHttpIncomingRequest, Handle);
- HFunc(TEvHttpProxy::TEvHttpOutgoingRequest, Handle);
- HFunc(TEvHttpProxy::TEvHttpIncomingResponse, Handle);
- HFunc(TEvHttpProxy::TEvHttpOutgoingResponse, Handle);
- HFunc(TEvHttpProxy::TEvHttpAcceptorClosed, Handle);
- HFunc(TEvHttpProxy::TEvHttpConnectionClosed, Handle);
- HFunc(TEvHttpProxy::TEvResolveHostRequest, Handle);
- HFunc(TEvHttpProxy::TEvReportSensors, Handle);
+ : Sensors(sensors)
+ {}
+
+protected:
+ STFUNC(StateWork) {
+ switch (ev->GetTypeRewrite()) {
+ HFunc(TEvHttpProxy::TEvAddListeningPort, Handle);
+ HFunc(TEvHttpProxy::TEvRegisterHandler, Handle);
+ HFunc(TEvHttpProxy::TEvHttpIncomingRequest, Handle);
+ HFunc(TEvHttpProxy::TEvHttpOutgoingRequest, Handle);
+ HFunc(TEvHttpProxy::TEvHttpIncomingResponse, Handle);
+ HFunc(TEvHttpProxy::TEvHttpOutgoingResponse, Handle);
+ HFunc(TEvHttpProxy::TEvHttpAcceptorClosed, Handle);
+ HFunc(TEvHttpProxy::TEvHttpConnectionClosed, Handle);
+ HFunc(TEvHttpProxy::TEvResolveHostRequest, Handle);
+ HFunc(TEvHttpProxy::TEvReportSensors, Handle);
HFunc(NActors::TEvents::TEvPoison, Handle);
- }
- }
-
+ }
+ }
+
void PassAway() override {
Send(Poller, new NActors::TEvents::TEvPoisonPill());
for (const NActors::TActorId& connection : Connections) {
Send(connection, new NActors::TEvents::TEvPoisonPill());
- }
+ }
for (const NActors::TActorId& acceptor : Acceptors) {
Send(acceptor, new NActors::TEvents::TEvPoisonPill());
- }
+ }
NActors::TActorBootstrapped<THttpProxy>::PassAway();
- }
-
- void Handle(TEvHttpProxy::TEvHttpIncomingRequest::TPtr event, const NActors::TActorContext& ctx) {
- TStringBuf url = event->Get()->Request->URL.Before('?');
+ }
+
+ void Handle(TEvHttpProxy::TEvHttpIncomingRequest::TPtr event, const NActors::TActorContext& ctx) {
+ TStringBuf url = event->Get()->Request->URL.Before('?');
THashMap<TString, TActorId>::iterator it;
- while (!url.empty()) {
- it = Handlers.find(url);
- if (it != Handlers.end()) {
- ctx.Send(event->Forward(it->second));
- return;
- } else {
- if (url.EndsWith('/')) {
- url.Trunc(url.size() - 1);
- }
- size_t pos = url.rfind('/');
- if (pos == TStringBuf::npos) {
- break;
- } else {
- url = url.substr(0, pos + 1);
- }
- }
- }
- ctx.Send(event->Sender, new TEvHttpProxy::TEvHttpOutgoingResponse(event->Get()->Request->CreateResponseNotFound()));
- }
-
- void Handle(TEvHttpProxy::TEvHttpIncomingResponse::TPtr event, const NActors::TActorContext& ctx) {
- Y_UNUSED(event);
- Y_UNUSED(ctx);
- Y_FAIL("This event shouldn't be there, it should go to the http connection owner directly");
- }
-
- void Handle(TEvHttpProxy::TEvHttpOutgoingResponse::TPtr event, const NActors::TActorContext& ctx) {
- Y_UNUSED(event);
- Y_UNUSED(ctx);
- Y_FAIL("This event shouldn't be there, it should go to the http connection directly");
- }
-
- void Handle(TEvHttpProxy::TEvHttpOutgoingRequest::TPtr event, const NActors::TActorContext& ctx) {
- TStringBuf host(event->Get()->Request->Host);
- bool secure(event->Get()->Request->Secure);
- NActors::IActor* actor = AddOutgoingConnection(TString(host), secure, ctx);
- ctx.Send(event->Forward(actor->SelfId()));
- }
-
- void Handle(TEvHttpProxy::TEvAddListeningPort::TPtr event, const NActors::TActorContext& ctx) {
- AddListeningPort(event, ctx);
- }
-
- void Handle(TEvHttpProxy::TEvHttpAcceptorClosed::TPtr event, const NActors::TActorContext&) {
- for (auto it = Acceptors.begin(); it != Acceptors.end(); ++it) {
- if (*it == event->Get()->ConnectionID) {
- Acceptors.erase(it);
- break;
- }
- }
- }
-
- void Handle(TEvHttpProxy::TEvHttpConnectionClosed::TPtr event, const NActors::TActorContext&) {
- Connections.erase(event->Get()->ConnectionID);
- }
-
- void Handle(TEvHttpProxy::TEvRegisterHandler::TPtr event, const NActors::TActorContext&) {
- Handlers[event->Get()->Path] = event->Get()->Handler;
- }
-
- void Handle(TEvHttpProxy::TEvResolveHostRequest::TPtr event, const NActors::TActorContext& ctx) {
- const TString& host(event->Get()->Host);
- auto it = Hosts.find(host);
- if (it == Hosts.end() || it->second.DeadlineTime > ctx.Now()) {
- TString addressPart;
- 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.DeadlineTime = ctx.Now() + HostsTimeToLive;
- } else {
- // TODO(xenoxeno): move to another, possible blocking actor
- try {
- 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) {
- ++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;
- }
- it->second.Address = address;
- it->second.DeadlineTime = ctx.Now() + HostsTimeToLive;
- } else {
- ctx.Send(event->Sender, new TEvHttpProxy::TEvResolveHostResponse("Error resolving host"));
- return;
- }
- }
- catch (const yexception& e) {
- ctx.Send(event->Sender, new TEvHttpProxy::TEvResolveHostResponse(e.what()));
- return;
- }
- }
- }
- ctx.Send(event->Sender, new TEvHttpProxy::TEvResolveHostResponse(it->first, it->second.Address));
- }
-
- void Handle(TEvHttpProxy::TEvReportSensors::TPtr event, const NActors::TActorContext&) {
- const TEvHttpProxy::TEvReportSensors& sensors(*event->Get());
+ while (!url.empty()) {
+ it = Handlers.find(url);
+ if (it != Handlers.end()) {
+ ctx.Send(event->Forward(it->second));
+ return;
+ } else {
+ if (url.EndsWith('/')) {
+ url.Trunc(url.size() - 1);
+ }
+ size_t pos = url.rfind('/');
+ if (pos == TStringBuf::npos) {
+ break;
+ } else {
+ url = url.substr(0, pos + 1);
+ }
+ }
+ }
+ ctx.Send(event->Sender, new TEvHttpProxy::TEvHttpOutgoingResponse(event->Get()->Request->CreateResponseNotFound()));
+ }
+
+ void Handle(TEvHttpProxy::TEvHttpIncomingResponse::TPtr event, const NActors::TActorContext& ctx) {
+ Y_UNUSED(event);
+ Y_UNUSED(ctx);
+ Y_FAIL("This event shouldn't be there, it should go to the http connection owner directly");
+ }
+
+ void Handle(TEvHttpProxy::TEvHttpOutgoingResponse::TPtr event, const NActors::TActorContext& ctx) {
+ Y_UNUSED(event);
+ Y_UNUSED(ctx);
+ Y_FAIL("This event shouldn't be there, it should go to the http connection directly");
+ }
+
+ void Handle(TEvHttpProxy::TEvHttpOutgoingRequest::TPtr event, const NActors::TActorContext& ctx) {
+ TStringBuf host(event->Get()->Request->Host);
+ bool secure(event->Get()->Request->Secure);
+ NActors::IActor* actor = AddOutgoingConnection(TString(host), secure, ctx);
+ ctx.Send(event->Forward(actor->SelfId()));
+ }
+
+ void Handle(TEvHttpProxy::TEvAddListeningPort::TPtr event, const NActors::TActorContext& ctx) {
+ AddListeningPort(event, ctx);
+ }
+
+ void Handle(TEvHttpProxy::TEvHttpAcceptorClosed::TPtr event, const NActors::TActorContext&) {
+ for (auto it = Acceptors.begin(); it != Acceptors.end(); ++it) {
+ if (*it == event->Get()->ConnectionID) {
+ Acceptors.erase(it);
+ break;
+ }
+ }
+ }
+
+ void Handle(TEvHttpProxy::TEvHttpConnectionClosed::TPtr event, const NActors::TActorContext&) {
+ Connections.erase(event->Get()->ConnectionID);
+ }
+
+ void Handle(TEvHttpProxy::TEvRegisterHandler::TPtr event, const NActors::TActorContext&) {
+ Handlers[event->Get()->Path] = event->Get()->Handler;
+ }
+
+ void Handle(TEvHttpProxy::TEvResolveHostRequest::TPtr event, const NActors::TActorContext& ctx) {
+ const TString& host(event->Get()->Host);
+ auto it = Hosts.find(host);
+ if (it == Hosts.end() || it->second.DeadlineTime > ctx.Now()) {
+ TString addressPart;
+ 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.DeadlineTime = ctx.Now() + HostsTimeToLive;
+ } else {
+ // TODO(xenoxeno): move to another, possible blocking actor
+ try {
+ 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) {
+ ++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;
+ }
+ it->second.Address = address;
+ it->second.DeadlineTime = ctx.Now() + HostsTimeToLive;
+ } else {
+ ctx.Send(event->Sender, new TEvHttpProxy::TEvResolveHostResponse("Error resolving host"));
+ return;
+ }
+ }
+ catch (const yexception& e) {
+ ctx.Send(event->Sender, new TEvHttpProxy::TEvResolveHostResponse(e.what()));
+ return;
+ }
+ }
+ }
+ ctx.Send(event->Sender, new TEvHttpProxy::TEvResolveHostResponse(it->first, it->second.Address));
+ }
+
+ void Handle(TEvHttpProxy::TEvReportSensors::TPtr event, const NActors::TActorContext&) {
+ const TEvHttpProxy::TEvReportSensors& sensors(*event->Get());
const static TString urlNotFound = "not-found";
const TString& url = (sensors.Status == "404" ? urlNotFound : sensors.Url);
- Sensors.Rate({
- {"sensor", "count"},
- {"direction", sensors.Direction},
- {"peer", sensors.Host},
+ Sensors.Rate({
+ {"sensor", "count"},
+ {"direction", sensors.Direction},
+ {"peer", sensors.Host},
{"url", url},
- {"status", sensors.Status}
- })->Inc();
- Sensors.HistogramRate({
- {"sensor", "time_us"},
- {"direction", sensors.Direction},
- {"peer", sensors.Host},
+ {"status", sensors.Status}
+ })->Inc();
+ Sensors.HistogramRate({
+ {"sensor", "time_us"},
+ {"direction", sensors.Direction},
+ {"peer", sensors.Host},
{"url", url},
- {"status", sensors.Status}
- },
- NMonitoring::ExplicitHistogram({1, 5, 10, 50, 100, 500, 1000, 5000, 10000, 30000, 60000}))->Record(sensors.Time.MicroSeconds());
- Sensors.HistogramRate({
- {"sensor", "time_ms"},
- {"direction", sensors.Direction},
- {"peer", sensors.Host},
+ {"status", sensors.Status}
+ },
+ NMonitoring::ExplicitHistogram({1, 5, 10, 50, 100, 500, 1000, 5000, 10000, 30000, 60000}))->Record(sensors.Time.MicroSeconds());
+ Sensors.HistogramRate({
+ {"sensor", "time_ms"},
+ {"direction", sensors.Direction},
+ {"peer", sensors.Host},
{"url", url},
- {"status", sensors.Status}
- },
- NMonitoring::ExplicitHistogram({1, 5, 10, 50, 100, 500, 1000, 5000, 10000, 30000, 60000}))->Record(sensors.Time.MilliSeconds());
- }
-
+ {"status", sensors.Status}
+ },
+ NMonitoring::ExplicitHistogram({1, 5, 10, 50, 100, 500, 1000, 5000, 10000, 30000, 60000}))->Record(sensors.Time.MilliSeconds());
+ }
+
void Handle(NActors::TEvents::TEvPoison::TPtr, const NActors::TActorContext&) {
PassAway();
}
NActors::TActorId Poller;
TVector<TActorId> Acceptors;
-
- struct THostEntry {
- TSockAddrInet6 Address;
- TInstant DeadlineTime;
- };
-
- static constexpr TDuration HostsTimeToLive = TDuration::Seconds(60);
-
- THashMap<TString, THostEntry> Hosts;
+
+ struct THostEntry {
+ TSockAddrInet6 Address;
+ TInstant DeadlineTime;
+ };
+
+ static constexpr TDuration HostsTimeToLive = TDuration::Seconds(60);
+
+ THashMap<TString, THostEntry> Hosts;
THashMap<TString, TActorId> Handlers;
THashSet<TActorId> Connections; // outgoing
NMonitoring::TMetricRegistry& Sensors;
-};
-
-TEvHttpProxy::TEvReportSensors* BuildOutgoingRequestSensors(const THttpOutgoingRequestPtr& request, const THttpIncomingResponsePtr& response) {
- return new TEvHttpProxy::TEvReportSensors(
- "out",
- request->Host,
- request->URL.Before('?'),
- response ? response->Status : "504",
+};
+
+TEvHttpProxy::TEvReportSensors* BuildOutgoingRequestSensors(const THttpOutgoingRequestPtr& request, const THttpIncomingResponsePtr& response) {
+ return new TEvHttpProxy::TEvReportSensors(
+ "out",
+ request->Host,
+ request->URL.Before('?'),
+ response ? response->Status : "504",
TDuration::Seconds(std::abs(request->Timer.Passed()))
- );
-}
-
-TEvHttpProxy::TEvReportSensors* BuildIncomingRequestSensors(const THttpIncomingRequestPtr& request, const THttpOutgoingResponsePtr& response) {
- return new TEvHttpProxy::TEvReportSensors(
- "in",
- request->Host,
- request->URL.Before('?'),
- response->Status,
+ );
+}
+
+TEvHttpProxy::TEvReportSensors* BuildIncomingRequestSensors(const THttpIncomingRequestPtr& request, const THttpOutgoingResponsePtr& response) {
+ return new TEvHttpProxy::TEvReportSensors(
+ "in",
+ request->Host,
+ request->URL.Before('?'),
+ response->Status,
TDuration::Seconds(std::abs(request->Timer.Passed()))
- );
-}
-
+ );
+}
+
NActors::IActor* CreateHttpProxy(NMonitoring::TMetricRegistry& sensors) {
- return new THttpProxy(sensors);
-}
-
-bool IsIPv6(const TString& host) {
- return host.find_first_not_of(":0123456789abcdef") == TString::npos;
-}
-
-bool CrackURL(TStringBuf url, TStringBuf& scheme, TStringBuf& host, TStringBuf& uri) {
- url.TrySplit("://", scheme, url);
- auto pos = url.find('/');
- if (pos == TStringBuf::npos) {
- host = url;
- } else {
- host = url.substr(0, pos);
- uri = url.substr(pos);
- }
- return true;
-}
-
-void CrackAddress(const TString& address, TString& hostname, TIpPort& port) {
- size_t first_colon_pos = address.find(':');
- if (first_colon_pos != TString::npos) {
- size_t last_colon_pos = address.rfind(':');
- if (last_colon_pos == first_colon_pos) {
- // only one colon, simple case
- port = FromStringWithDefault<TIpPort>(address.substr(first_colon_pos + 1), 0);
- hostname = address.substr(0, first_colon_pos);
- } else {
- // ipv6?
- size_t closing_bracket_pos = address.rfind(']');
- if (closing_bracket_pos == TString::npos || closing_bracket_pos > last_colon_pos) {
- // whole address is ipv6 host
- hostname = address;
- } else {
- port = FromStringWithDefault<TIpPort>(address.substr(last_colon_pos + 1), 0);
- hostname = address.substr(0, last_colon_pos);
- }
- if (hostname.StartsWith('[') && hostname.EndsWith(']')) {
- hostname = hostname.substr(1, hostname.size() - 2);
- }
- }
- } else {
- hostname = address;
- }
-}
-
-
-void TrimBegin(TStringBuf& target, char delim) {
- while (!target.empty() && *target.begin() == delim) {
- target.Skip(1);
- }
-}
-
-void TrimEnd(TStringBuf& target, char delim) {
- while (!target.empty() && target.back() == delim) {
- target.Trunc(target.size() - 1);
- }
-}
-
-void Trim(TStringBuf& target, char delim) {
- TrimBegin(target, delim);
- TrimEnd(target, delim);
-}
-
-void TrimEnd(TString& target, char delim) {
- while (!target.empty() && target.back() == delim) {
- target.resize(target.size() - 1);
- }
-}
-
-}
+ return new THttpProxy(sensors);
+}
+
+bool IsIPv6(const TString& host) {
+ return host.find_first_not_of(":0123456789abcdef") == TString::npos;
+}
+
+bool CrackURL(TStringBuf url, TStringBuf& scheme, TStringBuf& host, TStringBuf& uri) {
+ url.TrySplit("://", scheme, url);
+ auto pos = url.find('/');
+ if (pos == TStringBuf::npos) {
+ host = url;
+ } else {
+ host = url.substr(0, pos);
+ uri = url.substr(pos);
+ }
+ return true;
+}
+
+void CrackAddress(const TString& address, TString& hostname, TIpPort& port) {
+ size_t first_colon_pos = address.find(':');
+ if (first_colon_pos != TString::npos) {
+ size_t last_colon_pos = address.rfind(':');
+ if (last_colon_pos == first_colon_pos) {
+ // only one colon, simple case
+ port = FromStringWithDefault<TIpPort>(address.substr(first_colon_pos + 1), 0);
+ hostname = address.substr(0, first_colon_pos);
+ } else {
+ // ipv6?
+ size_t closing_bracket_pos = address.rfind(']');
+ if (closing_bracket_pos == TString::npos || closing_bracket_pos > last_colon_pos) {
+ // whole address is ipv6 host
+ hostname = address;
+ } else {
+ port = FromStringWithDefault<TIpPort>(address.substr(last_colon_pos + 1), 0);
+ hostname = address.substr(0, last_colon_pos);
+ }
+ if (hostname.StartsWith('[') && hostname.EndsWith(']')) {
+ hostname = hostname.substr(1, hostname.size() - 2);
+ }
+ }
+ } else {
+ hostname = address;
+ }
+}
+
+
+void TrimBegin(TStringBuf& target, char delim) {
+ while (!target.empty() && *target.begin() == delim) {
+ target.Skip(1);
+ }
+}
+
+void TrimEnd(TStringBuf& target, char delim) {
+ while (!target.empty() && target.back() == delim) {
+ target.Trunc(target.size() - 1);
+ }
+}
+
+void Trim(TStringBuf& target, char delim) {
+ TrimBegin(target, delim);
+ TrimEnd(target, delim);
+}
+
+void TrimEnd(TString& target, char delim) {
+ while (!target.empty() && target.back() == delim) {
+ target.resize(target.size() - 1);
+ }
+}
+
+}
diff --git a/library/cpp/actors/http/http_proxy.h b/library/cpp/actors/http/http_proxy.h
index afd0170997..ce77bf8d5f 100644
--- a/library/cpp/actors/http/http_proxy.h
+++ b/library/cpp/actors/http/http_proxy.h
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
#include <library/cpp/actors/core/actorsystem.h>
#include <library/cpp/actors/core/actor.h>
#include <library/cpp/actors/core/hfunc.h>
@@ -9,231 +9,231 @@
#include <library/cpp/actors/interconnect/poller_actor.h>
#include <library/cpp/dns/cache.h>
#include <library/cpp/monlib/metrics/metric_registry.h>
-#include <util/generic/variant.h>
-#include "http.h"
-#include "http_proxy_ssl.h"
-
-namespace NHttp {
-
-struct TSocketDescriptor : NActors::TSharedDescriptor, THttpConfig {
- SocketType Socket;
-
- int GetDescriptor() override {
- return static_cast<SOCKET>(Socket);
- }
-};
-
-struct TEvHttpProxy {
- enum EEv {
+#include <util/generic/variant.h>
+#include "http.h"
+#include "http_proxy_ssl.h"
+
+namespace NHttp {
+
+struct TSocketDescriptor : NActors::TSharedDescriptor, THttpConfig {
+ SocketType Socket;
+
+ int GetDescriptor() override {
+ return static_cast<SOCKET>(Socket);
+ }
+};
+
+struct TEvHttpProxy {
+ enum EEv {
EvAddListeningPort = EventSpaceBegin(NActors::TEvents::ES_HTTP),
- EvConfirmListen,
- EvRegisterHandler,
- EvHttpIncomingRequest,
- EvHttpOutgoingRequest,
- EvHttpIncomingResponse,
- EvHttpOutgoingResponse,
- EvHttpConnectionOpened,
- EvHttpConnectionClosed,
- EvHttpAcceptorClosed,
- EvResolveHostRequest,
- EvResolveHostResponse,
- EvReportSensors,
- EvEnd
- };
-
+ EvConfirmListen,
+ EvRegisterHandler,
+ EvHttpIncomingRequest,
+ EvHttpOutgoingRequest,
+ EvHttpIncomingResponse,
+ EvHttpOutgoingResponse,
+ EvHttpConnectionOpened,
+ EvHttpConnectionClosed,
+ EvHttpAcceptorClosed,
+ EvResolveHostRequest,
+ EvResolveHostResponse,
+ EvReportSensors,
+ EvEnd
+ };
+
static_assert(EvEnd < EventSpaceEnd(NActors::TEvents::ES_HTTP), "ES_HTTP event space is too small.");
-
- struct TEvAddListeningPort : NActors::TEventLocal<TEvAddListeningPort, EvAddListeningPort> {
- TIpPort Port;
- TString WorkerName;
- bool Secure = false;
- TString CertificateFile;
- TString PrivateKeyFile;
+
+ struct TEvAddListeningPort : NActors::TEventLocal<TEvAddListeningPort, EvAddListeningPort> {
+ TIpPort Port;
+ TString WorkerName;
+ bool Secure = false;
+ TString CertificateFile;
+ TString PrivateKeyFile;
TString SslCertificatePem;
-
- TEvAddListeningPort(TIpPort port)
- : Port(port)
- {}
-
- TEvAddListeningPort(TIpPort port, const TString& workerName)
- : Port(port)
- , WorkerName(workerName)
- {}
- };
-
- struct TEvConfirmListen : NActors::TEventLocal<TEvConfirmListen, EvConfirmListen> {
- THttpConfig::SocketAddressType Address;
-
- TEvConfirmListen(const THttpConfig::SocketAddressType& address)
- : Address(address)
- {}
- };
-
- struct TEvRegisterHandler : NActors::TEventLocal<TEvRegisterHandler, EvRegisterHandler> {
- TString Path;
+
+ TEvAddListeningPort(TIpPort port)
+ : Port(port)
+ {}
+
+ TEvAddListeningPort(TIpPort port, const TString& workerName)
+ : Port(port)
+ , WorkerName(workerName)
+ {}
+ };
+
+ struct TEvConfirmListen : NActors::TEventLocal<TEvConfirmListen, EvConfirmListen> {
+ THttpConfig::SocketAddressType Address;
+
+ TEvConfirmListen(const THttpConfig::SocketAddressType& address)
+ : Address(address)
+ {}
+ };
+
+ struct TEvRegisterHandler : NActors::TEventLocal<TEvRegisterHandler, EvRegisterHandler> {
+ TString Path;
TActorId Handler;
-
+
TEvRegisterHandler(const TString& path, const TActorId& handler)
- : Path(path)
- , Handler(handler)
- {}
- };
-
- struct TEvHttpIncomingRequest : NActors::TEventLocal<TEvHttpIncomingRequest, EvHttpIncomingRequest> {
- THttpIncomingRequestPtr Request;
-
- TEvHttpIncomingRequest(THttpIncomingRequestPtr request)
- : Request(std::move(request))
- {}
- };
-
- struct TEvHttpOutgoingRequest : NActors::TEventLocal<TEvHttpOutgoingRequest, EvHttpOutgoingRequest> {
- THttpOutgoingRequestPtr Request;
- TDuration Timeout;
-
- TEvHttpOutgoingRequest(THttpOutgoingRequestPtr request)
- : Request(std::move(request))
- {}
-
- TEvHttpOutgoingRequest(THttpOutgoingRequestPtr request, TDuration timeout)
- : Request(std::move(request))
- , Timeout(timeout)
- {}
- };
-
- struct TEvHttpIncomingResponse : NActors::TEventLocal<TEvHttpIncomingResponse, EvHttpIncomingResponse> {
- THttpOutgoingRequestPtr Request;
- THttpIncomingResponsePtr Response;
- TString Error;
-
- TEvHttpIncomingResponse(THttpOutgoingRequestPtr request, THttpIncomingResponsePtr response, const TString& error)
- : Request(std::move(request))
- , Response(std::move(response))
- , Error(error)
- {}
-
- TEvHttpIncomingResponse(THttpOutgoingRequestPtr request, THttpIncomingResponsePtr response)
- : Request(std::move(request))
- , Response(std::move(response))
- {}
-
- TString GetError() const {
- TStringBuilder error;
- if (Response != nullptr && !Response->Status.StartsWith('2')) {
- error << Response->Status << ' ' << Response->Message;
- }
- if (!Error.empty()) {
- if (!error.empty()) {
- error << ';';
- }
- error << Error;
- }
- return error;
- }
- };
-
- struct TEvHttpOutgoingResponse : NActors::TEventLocal<TEvHttpOutgoingResponse, EvHttpOutgoingResponse> {
- THttpOutgoingResponsePtr Response;
-
- TEvHttpOutgoingResponse(THttpOutgoingResponsePtr response)
- : Response(std::move(response))
- {}
- };
-
- struct TEvHttpConnectionOpened : NActors::TEventLocal<TEvHttpConnectionOpened, EvHttpConnectionOpened> {
- TString PeerAddress;
+ : Path(path)
+ , Handler(handler)
+ {}
+ };
+
+ struct TEvHttpIncomingRequest : NActors::TEventLocal<TEvHttpIncomingRequest, EvHttpIncomingRequest> {
+ THttpIncomingRequestPtr Request;
+
+ TEvHttpIncomingRequest(THttpIncomingRequestPtr request)
+ : Request(std::move(request))
+ {}
+ };
+
+ struct TEvHttpOutgoingRequest : NActors::TEventLocal<TEvHttpOutgoingRequest, EvHttpOutgoingRequest> {
+ THttpOutgoingRequestPtr Request;
+ TDuration Timeout;
+
+ TEvHttpOutgoingRequest(THttpOutgoingRequestPtr request)
+ : Request(std::move(request))
+ {}
+
+ TEvHttpOutgoingRequest(THttpOutgoingRequestPtr request, TDuration timeout)
+ : Request(std::move(request))
+ , Timeout(timeout)
+ {}
+ };
+
+ struct TEvHttpIncomingResponse : NActors::TEventLocal<TEvHttpIncomingResponse, EvHttpIncomingResponse> {
+ THttpOutgoingRequestPtr Request;
+ THttpIncomingResponsePtr Response;
+ TString Error;
+
+ TEvHttpIncomingResponse(THttpOutgoingRequestPtr request, THttpIncomingResponsePtr response, const TString& error)
+ : Request(std::move(request))
+ , Response(std::move(response))
+ , Error(error)
+ {}
+
+ TEvHttpIncomingResponse(THttpOutgoingRequestPtr request, THttpIncomingResponsePtr response)
+ : Request(std::move(request))
+ , Response(std::move(response))
+ {}
+
+ TString GetError() const {
+ TStringBuilder error;
+ if (Response != nullptr && !Response->Status.StartsWith('2')) {
+ error << Response->Status << ' ' << Response->Message;
+ }
+ if (!Error.empty()) {
+ if (!error.empty()) {
+ error << ';';
+ }
+ error << Error;
+ }
+ return error;
+ }
+ };
+
+ struct TEvHttpOutgoingResponse : NActors::TEventLocal<TEvHttpOutgoingResponse, EvHttpOutgoingResponse> {
+ THttpOutgoingResponsePtr Response;
+
+ TEvHttpOutgoingResponse(THttpOutgoingResponsePtr response)
+ : Response(std::move(response))
+ {}
+ };
+
+ struct TEvHttpConnectionOpened : NActors::TEventLocal<TEvHttpConnectionOpened, EvHttpConnectionOpened> {
+ TString PeerAddress;
TActorId ConnectionID;
-
+
TEvHttpConnectionOpened(const TString& peerAddress, const TActorId& connectionID)
- : PeerAddress(peerAddress)
- , ConnectionID(connectionID)
- {}
- };
-
- struct TEvHttpConnectionClosed : NActors::TEventLocal<TEvHttpConnectionClosed, EvHttpConnectionClosed> {
+ : PeerAddress(peerAddress)
+ , ConnectionID(connectionID)
+ {}
+ };
+
+ struct TEvHttpConnectionClosed : NActors::TEventLocal<TEvHttpConnectionClosed, EvHttpConnectionClosed> {
TActorId ConnectionID;
- TDeque<THttpIncomingRequestPtr> RecycledRequests;
-
+ TDeque<THttpIncomingRequestPtr> RecycledRequests;
+
TEvHttpConnectionClosed(const TActorId& connectionID)
- : ConnectionID(connectionID)
- {}
-
+ : ConnectionID(connectionID)
+ {}
+
TEvHttpConnectionClosed(const TActorId& connectionID, TDeque<THttpIncomingRequestPtr> recycledRequests)
- : ConnectionID(connectionID)
- , RecycledRequests(std::move(recycledRequests))
- {}
- };
-
- struct TEvHttpAcceptorClosed : NActors::TEventLocal<TEvHttpAcceptorClosed, EvHttpAcceptorClosed> {
+ : ConnectionID(connectionID)
+ , RecycledRequests(std::move(recycledRequests))
+ {}
+ };
+
+ struct TEvHttpAcceptorClosed : NActors::TEventLocal<TEvHttpAcceptorClosed, EvHttpAcceptorClosed> {
TActorId ConnectionID;
-
+
TEvHttpAcceptorClosed(const TActorId& connectionID)
- : ConnectionID(connectionID)
- {}
- };
-
- struct TEvResolveHostRequest : NActors::TEventLocal<TEvResolveHostRequest, EvResolveHostRequest> {
- TString Host;
-
- TEvResolveHostRequest(const TString& host)
- : Host(host)
- {}
- };
-
- struct TEvResolveHostResponse : NActors::TEventLocal<TEvResolveHostResponse, EvResolveHostResponse> {
- TString Host;
- TSockAddrInet6 Address;
- TString Error;
-
- TEvResolveHostResponse(const TString& host, const TSockAddrInet6& address)
- : Host(host)
- , Address(address)
- {}
-
- TEvResolveHostResponse(const TString& error)
- : Error(error)
- {}
- };
-
- struct TEvReportSensors : NActors::TEventLocal<TEvReportSensors, EvReportSensors> {
- TString Direction;
- TString Host;
- TString Url;
- TString Status;
- TDuration Time;
-
- TEvReportSensors(
- TStringBuf direction,
- TStringBuf host,
- TStringBuf url,
- TStringBuf status,
- TDuration time)
- : Direction(direction)
- , Host(host)
- , Url(url)
- , Status(status)
- , Time(time)
- {}
- };
-};
-
-struct TEndpointInfo {
+ : ConnectionID(connectionID)
+ {}
+ };
+
+ struct TEvResolveHostRequest : NActors::TEventLocal<TEvResolveHostRequest, EvResolveHostRequest> {
+ TString Host;
+
+ TEvResolveHostRequest(const TString& host)
+ : Host(host)
+ {}
+ };
+
+ struct TEvResolveHostResponse : NActors::TEventLocal<TEvResolveHostResponse, EvResolveHostResponse> {
+ TString Host;
+ TSockAddrInet6 Address;
+ TString Error;
+
+ TEvResolveHostResponse(const TString& host, const TSockAddrInet6& address)
+ : Host(host)
+ , Address(address)
+ {}
+
+ TEvResolveHostResponse(const TString& error)
+ : Error(error)
+ {}
+ };
+
+ struct TEvReportSensors : NActors::TEventLocal<TEvReportSensors, EvReportSensors> {
+ TString Direction;
+ TString Host;
+ TString Url;
+ TString Status;
+ TDuration Time;
+
+ TEvReportSensors(
+ TStringBuf direction,
+ TStringBuf host,
+ TStringBuf url,
+ TStringBuf status,
+ TDuration time)
+ : Direction(direction)
+ , Host(host)
+ , Url(url)
+ , Status(status)
+ , Time(time)
+ {}
+ };
+};
+
+struct TEndpointInfo {
TActorId Proxy;
TActorId Owner;
- TString WorkerName;
- bool Secure;
- TSslHelpers::TSslHolder<SSL_CTX> SecureContext;
-};
-
+ TString WorkerName;
+ bool Secure;
+ TSslHelpers::TSslHolder<SSL_CTX> SecureContext;
+};
+
NActors::IActor* CreateHttpProxy(NMonitoring::TMetricRegistry& sensors);
NActors::IActor* CreateHttpAcceptorActor(const TActorId& owner, const TActorId& poller);
NActors::IActor* CreateOutgoingConnectionActor(const TActorId& owner, const TString& host, bool secure, const TActorId& poller);
-NActors::IActor* CreateIncomingConnectionActor(
- const TEndpointInfo& endpoint,
- TIntrusivePtr<TSocketDescriptor> socket,
- THttpConfig::SocketAddressType address,
- THttpIncomingRequestPtr recycledRequest = nullptr);
-TEvHttpProxy::TEvReportSensors* BuildOutgoingRequestSensors(const THttpOutgoingRequestPtr& request, const THttpIncomingResponsePtr& response);
-TEvHttpProxy::TEvReportSensors* BuildIncomingRequestSensors(const THttpIncomingRequestPtr& request, const THttpOutgoingResponsePtr& response);
-
-}
+NActors::IActor* CreateIncomingConnectionActor(
+ const TEndpointInfo& endpoint,
+ TIntrusivePtr<TSocketDescriptor> socket,
+ THttpConfig::SocketAddressType address,
+ THttpIncomingRequestPtr recycledRequest = nullptr);
+TEvHttpProxy::TEvReportSensors* BuildOutgoingRequestSensors(const THttpOutgoingRequestPtr& request, const THttpIncomingResponsePtr& response);
+TEvHttpProxy::TEvReportSensors* BuildIncomingRequestSensors(const THttpIncomingRequestPtr& request, const THttpOutgoingResponsePtr& response);
+
+}
diff --git a/library/cpp/actors/http/http_proxy_acceptor.cpp b/library/cpp/actors/http/http_proxy_acceptor.cpp
index 9780541b71..3d2557c6fe 100644
--- a/library/cpp/actors/http/http_proxy_acceptor.cpp
+++ b/library/cpp/actors/http/http_proxy_acceptor.cpp
@@ -1,135 +1,135 @@
-#include <util/network/sock.h>
-#include "http_proxy.h"
-#include "http_proxy_ssl.h"
-
-namespace NHttp {
-
-class TAcceptorActor : public NActors::TActor<TAcceptorActor>, public THttpConfig {
-public:
- using TBase = NActors::TActor<TAcceptorActor>;
+#include <util/network/sock.h>
+#include "http_proxy.h"
+#include "http_proxy_ssl.h"
+
+namespace NHttp {
+
+class TAcceptorActor : public NActors::TActor<TAcceptorActor>, public THttpConfig {
+public:
+ using TBase = NActors::TActor<TAcceptorActor>;
const TActorId Owner;
const TActorId Poller;
- TIntrusivePtr<TSocketDescriptor> Socket;
+ TIntrusivePtr<TSocketDescriptor> Socket;
NActors::TPollerToken::TPtr PollerToken;
THashSet<TActorId> Connections;
- TDeque<THttpIncomingRequestPtr> RecycledRequests;
- TEndpointInfo Endpoint;
-
+ TDeque<THttpIncomingRequestPtr> RecycledRequests;
+ TEndpointInfo Endpoint;
+
TAcceptorActor(const TActorId& owner, const TActorId& poller)
- : NActors::TActor<TAcceptorActor>(&TAcceptorActor::StateInit)
- , Owner(owner)
- , Poller(poller)
- , Socket(new TSocketDescriptor())
- {
- // for unit tests :(
- CheckedSetSockOpt(Socket->Socket, SOL_SOCKET, SO_REUSEADDR, (int)true, "reuse address");
-#ifdef SO_REUSEPORT
- CheckedSetSockOpt(Socket->Socket, SOL_SOCKET, SO_REUSEPORT, (int)true, "reuse port");
-#endif
- }
-
-protected:
- STFUNC(StateListening) {
- switch (ev->GetTypeRewrite()) {
+ : NActors::TActor<TAcceptorActor>(&TAcceptorActor::StateInit)
+ , Owner(owner)
+ , Poller(poller)
+ , Socket(new TSocketDescriptor())
+ {
+ // for unit tests :(
+ CheckedSetSockOpt(Socket->Socket, SOL_SOCKET, SO_REUSEADDR, (int)true, "reuse address");
+#ifdef SO_REUSEPORT
+ CheckedSetSockOpt(Socket->Socket, SOL_SOCKET, SO_REUSEPORT, (int)true, "reuse port");
+#endif
+ }
+
+protected:
+ STFUNC(StateListening) {
+ switch (ev->GetTypeRewrite()) {
HFunc(NActors::TEvPollerRegisterResult, Handle);
HFunc(NActors::TEvPollerReady, Handle);
- HFunc(TEvHttpProxy::TEvHttpConnectionClosed, Handle);
- HFunc(TEvHttpProxy::TEvReportSensors, Handle);
- }
- }
-
- STFUNC(StateInit) {
- switch (ev->GetTypeRewrite()) {
- HFunc(TEvHttpProxy::TEvAddListeningPort, HandleInit);
- }
- }
-
- void HandleInit(TEvHttpProxy::TEvAddListeningPort::TPtr event, const NActors::TActorContext& ctx) {
- SocketAddressType bindAddress("::", event->Get()->Port);
- Endpoint.Owner = ctx.SelfID;
- Endpoint.Proxy = Owner;
- Endpoint.WorkerName = event->Get()->WorkerName;
- Endpoint.Secure = event->Get()->Secure;
- int err = 0;
- if (Endpoint.Secure) {
+ HFunc(TEvHttpProxy::TEvHttpConnectionClosed, Handle);
+ HFunc(TEvHttpProxy::TEvReportSensors, Handle);
+ }
+ }
+
+ STFUNC(StateInit) {
+ switch (ev->GetTypeRewrite()) {
+ HFunc(TEvHttpProxy::TEvAddListeningPort, HandleInit);
+ }
+ }
+
+ void HandleInit(TEvHttpProxy::TEvAddListeningPort::TPtr event, const NActors::TActorContext& ctx) {
+ SocketAddressType bindAddress("::", event->Get()->Port);
+ Endpoint.Owner = ctx.SelfID;
+ Endpoint.Proxy = Owner;
+ Endpoint.WorkerName = event->Get()->WorkerName;
+ Endpoint.Secure = event->Get()->Secure;
+ int err = 0;
+ if (Endpoint.Secure) {
if (!event->Get()->SslCertificatePem.empty()) {
Endpoint.SecureContext = TSslHelpers::CreateServerContext(event->Get()->SslCertificatePem);
} else {
Endpoint.SecureContext = TSslHelpers::CreateServerContext(event->Get()->CertificateFile, event->Get()->PrivateKeyFile);
}
- if (Endpoint.SecureContext == nullptr) {
- err = -1;
- LOG_WARN_S(ctx, HttpLog, "Failed to construct server security context");
- }
- }
- if (err == 0) {
- err = Socket->Socket.Bind(&bindAddress);
- }
- if (err == 0) {
- err = Socket->Socket.Listen(LISTEN_QUEUE);
- if (err == 0) {
- LOG_INFO_S(ctx, HttpLog, "Listening on " << bindAddress.ToString());
- SetNonBlock(Socket->Socket);
+ if (Endpoint.SecureContext == nullptr) {
+ err = -1;
+ LOG_WARN_S(ctx, HttpLog, "Failed to construct server security context");
+ }
+ }
+ if (err == 0) {
+ err = Socket->Socket.Bind(&bindAddress);
+ }
+ if (err == 0) {
+ err = Socket->Socket.Listen(LISTEN_QUEUE);
+ if (err == 0) {
+ 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);
- ctx.Send(event->Sender, new TEvHttpProxy::TEvConfirmListen(bindAddress), 0, event->Cookie);
- return;
- }
- }
- LOG_WARN_S(ctx, HttpLog, "Failed to listen on " << bindAddress.ToString() << " - retrying...");
+ TBase::Become(&TAcceptorActor::StateListening);
+ ctx.Send(event->Sender, new TEvHttpProxy::TEvConfirmListen(bindAddress), 0, event->Cookie);
+ return;
+ }
+ }
+ LOG_WARN_S(ctx, HttpLog, "Failed to listen on " << bindAddress.ToString() << " - retrying...");
ctx.ExecutorThread.Schedule(TDuration::Seconds(1), event.Release());
- }
-
- void Die(const NActors::TActorContext& ctx) override {
- ctx.Send(Owner, new TEvHttpProxy::TEvHttpAcceptorClosed(ctx.SelfID));
+ }
+
+ void Die(const NActors::TActorContext& ctx) override {
+ ctx.Send(Owner, new TEvHttpProxy::TEvHttpAcceptorClosed(ctx.SelfID));
for (const NActors::TActorId& connection : Connections) {
- ctx.Send(connection, new NActors::TEvents::TEvPoisonPill());
- }
- }
-
+ ctx.Send(connection, new NActors::TEvents::TEvPoisonPill());
+ }
+ }
+
void Handle(NActors::TEvPollerRegisterResult::TPtr ev, const NActors::TActorContext& /*ctx*/) {
PollerToken = std::move(ev->Get()->PollerToken);
PollerToken->Request(true, false); // request read polling
}
void Handle(NActors::TEvPollerReady::TPtr, const NActors::TActorContext& ctx) {
- TIntrusivePtr<TSocketDescriptor> socket = new TSocketDescriptor();
- SocketAddressType addr;
+ TIntrusivePtr<TSocketDescriptor> socket = new TSocketDescriptor();
+ SocketAddressType addr;
int err;
while ((err = Socket->Socket.Accept(&socket->Socket, &addr)) == 0) {
- NActors::IActor* connectionSocket = nullptr;
- if (RecycledRequests.empty()) {
- connectionSocket = CreateIncomingConnectionActor(Endpoint, socket, addr);
- } else {
- connectionSocket = CreateIncomingConnectionActor(Endpoint, socket, addr, std::move(RecycledRequests.front()));
- RecycledRequests.pop_front();
- }
+ NActors::IActor* connectionSocket = nullptr;
+ if (RecycledRequests.empty()) {
+ connectionSocket = CreateIncomingConnectionActor(Endpoint, socket, addr);
+ } else {
+ connectionSocket = CreateIncomingConnectionActor(Endpoint, socket, addr, std::move(RecycledRequests.front()));
+ RecycledRequests.pop_front();
+ }
NActors::TActorId connectionId = ctx.Register(connectionSocket);
ctx.Send(Poller, new NActors::TEvPollerRegister(socket, connectionId, connectionId));
- Connections.emplace(connectionId);
- socket = new TSocketDescriptor();
- }
+ Connections.emplace(connectionId);
+ socket = new TSocketDescriptor();
+ }
if (err == -EAGAIN || err == -EWOULDBLOCK) { // request poller for further connection polling
Y_VERIFY(PollerToken);
PollerToken->Request(true, false);
}
- }
-
- void Handle(TEvHttpProxy::TEvHttpConnectionClosed::TPtr event, const NActors::TActorContext&) {
- Connections.erase(event->Get()->ConnectionID);
- for (auto& req : event->Get()->RecycledRequests) {
- req->Clear();
- RecycledRequests.push_back(std::move(req));
- }
- }
-
- void Handle(TEvHttpProxy::TEvReportSensors::TPtr event, const NActors::TActorContext& ctx) {
- ctx.Send(event->Forward(Owner));
- }
-};
-
+ }
+
+ void Handle(TEvHttpProxy::TEvHttpConnectionClosed::TPtr event, const NActors::TActorContext&) {
+ Connections.erase(event->Get()->ConnectionID);
+ for (auto& req : event->Get()->RecycledRequests) {
+ req->Clear();
+ RecycledRequests.push_back(std::move(req));
+ }
+ }
+
+ void Handle(TEvHttpProxy::TEvReportSensors::TPtr event, const NActors::TActorContext& ctx) {
+ ctx.Send(event->Forward(Owner));
+ }
+};
+
NActors::IActor* CreateHttpAcceptorActor(const TActorId& owner, const TActorId& poller) {
- return new TAcceptorActor(owner, poller);
-}
-
-}
+ return new TAcceptorActor(owner, poller);
+}
+
+}
diff --git a/library/cpp/actors/http/http_proxy_incoming.cpp b/library/cpp/actors/http/http_proxy_incoming.cpp
index 80fe2af53d..0608e0e25b 100644
--- a/library/cpp/actors/http/http_proxy_incoming.cpp
+++ b/library/cpp/actors/http/http_proxy_incoming.cpp
@@ -1,80 +1,80 @@
-#include "http_proxy.h"
-#include "http_proxy_sock_impl.h"
-
-namespace NHttp {
-
+#include "http_proxy.h"
+#include "http_proxy_sock_impl.h"
+
+namespace NHttp {
+
using namespace NActors;
-template <typename TSocketImpl>
-class TIncomingConnectionActor : public TActor<TIncomingConnectionActor<TSocketImpl>>, public TSocketImpl, virtual public THttpConfig {
-public:
- using TBase = TActor<TIncomingConnectionActor<TSocketImpl>>;
- static constexpr bool RecycleRequests = true;
-
- const TEndpointInfo& Endpoint;
- SocketAddressType Address;
- TList<THttpIncomingRequestPtr> Requests;
- THashMap<THttpIncomingRequestPtr, THttpOutgoingResponsePtr> Responses;
- THttpIncomingRequestPtr CurrentRequest;
- THttpOutgoingResponsePtr CurrentResponse;
- TDeque<THttpIncomingRequestPtr> RecycledRequests;
-
+template <typename TSocketImpl>
+class TIncomingConnectionActor : public TActor<TIncomingConnectionActor<TSocketImpl>>, public TSocketImpl, virtual public THttpConfig {
+public:
+ using TBase = TActor<TIncomingConnectionActor<TSocketImpl>>;
+ static constexpr bool RecycleRequests = true;
+
+ const TEndpointInfo& Endpoint;
+ SocketAddressType Address;
+ TList<THttpIncomingRequestPtr> Requests;
+ THashMap<THttpIncomingRequestPtr, THttpOutgoingResponsePtr> Responses;
+ THttpIncomingRequestPtr CurrentRequest;
+ THttpOutgoingResponsePtr CurrentResponse;
+ TDeque<THttpIncomingRequestPtr> RecycledRequests;
+
THPTimer InactivityTimer;
static constexpr TDuration InactivityTimeout = TDuration::Minutes(2);
TEvPollerReady* InactivityEvent = nullptr;
TPollerToken::TPtr PollerToken;
- TIncomingConnectionActor(
- const TEndpointInfo& endpoint,
- TIntrusivePtr<TSocketDescriptor> socket,
- SocketAddressType address,
- THttpIncomingRequestPtr recycledRequest = nullptr)
- : TBase(&TIncomingConnectionActor::StateAccepting)
- , TSocketImpl(std::move(socket))
- , Endpoint(endpoint)
- , Address(address)
- {
- if (recycledRequest != nullptr) {
- RecycledRequests.emplace_back(std::move(recycledRequest));
- }
- TSocketImpl::SetNonBlock();
- }
-
- void CleanupRequest(THttpIncomingRequestPtr& request) {
- if (RecycleRequests) {
- request->Clear();
- RecycledRequests.push_back(std::move(request));
- } else {
- request = nullptr;
- }
- }
-
- void CleanupResponse(THttpOutgoingResponsePtr& response) {
- CleanupRequest(response->Request);
- // TODO: maybe recycle too?
- response = nullptr;
- }
-
+ TIncomingConnectionActor(
+ const TEndpointInfo& endpoint,
+ TIntrusivePtr<TSocketDescriptor> socket,
+ SocketAddressType address,
+ THttpIncomingRequestPtr recycledRequest = nullptr)
+ : TBase(&TIncomingConnectionActor::StateAccepting)
+ , TSocketImpl(std::move(socket))
+ , Endpoint(endpoint)
+ , Address(address)
+ {
+ if (recycledRequest != nullptr) {
+ RecycledRequests.emplace_back(std::move(recycledRequest));
+ }
+ TSocketImpl::SetNonBlock();
+ }
+
+ void CleanupRequest(THttpIncomingRequestPtr& request) {
+ if (RecycleRequests) {
+ request->Clear();
+ RecycledRequests.push_back(std::move(request));
+ } else {
+ request = nullptr;
+ }
+ }
+
+ void CleanupResponse(THttpOutgoingResponsePtr& response) {
+ CleanupRequest(response->Request);
+ // TODO: maybe recycle too?
+ response = nullptr;
+ }
+
TAutoPtr<IEventHandle> AfterRegister(const TActorId& self, const TActorId& parent) override {
return new IEventHandle(self, parent, new TEvents::TEvBootstrap());
}
void Die(const TActorContext& ctx) override {
- ctx.Send(Endpoint.Owner, new TEvHttpProxy::TEvHttpConnectionClosed(ctx.SelfID, std::move(RecycledRequests)));
- TSocketImpl::Shutdown();
- TBase::Die(ctx);
- }
-
-protected:
+ ctx.Send(Endpoint.Owner, new TEvHttpProxy::TEvHttpConnectionClosed(ctx.SelfID, std::move(RecycledRequests)));
+ TSocketImpl::Shutdown();
+ TBase::Die(ctx);
+ }
+
+protected:
void Bootstrap(const TActorContext& ctx) {
InactivityTimer.Reset();
ctx.Schedule(InactivityTimeout, InactivityEvent = new TEvPollerReady(nullptr, false, false));
- LOG_DEBUG_S(ctx, HttpLog, "(#" << TSocketImpl::GetRawSocket() << "," << Address << ") incoming connection opened");
- OnAccept(ctx);
+ LOG_DEBUG_S(ctx, HttpLog, "(#" << TSocketImpl::GetRawSocket() << "," << Address << ") incoming connection opened");
+ OnAccept(ctx);
}
- void OnAccept(const NActors::TActorContext& ctx) {
+ void OnAccept(const NActors::TActorContext& ctx) {
int res;
bool read = false, write = false;
if ((res = TSocketImpl::OnAccept(Endpoint, read, write)) != 1) {
@@ -86,21 +86,21 @@ protected:
} else {
LOG_ERROR_S(ctx, HttpLog, "(#" << TSocketImpl::GetRawSocket() << "," << Address << ") connection closed - error in Accept: " << strerror(-res));
return Die(ctx);
- }
- }
- TBase::Become(&TIncomingConnectionActor::StateConnected);
+ }
+ }
+ TBase::Become(&TIncomingConnectionActor::StateConnected);
ctx.Send(ctx.SelfID, new TEvPollerReady(nullptr, true, true));
- }
-
+ }
+
void HandleAccepting(TEvPollerRegisterResult::TPtr ev, const NActors::TActorContext& ctx) {
PollerToken = std::move(ev->Get()->PollerToken);
- OnAccept(ctx);
- }
-
+ OnAccept(ctx);
+ }
+
void HandleAccepting(NActors::TEvPollerReady::TPtr, const NActors::TActorContext& ctx) {
- OnAccept(ctx);
- }
-
+ OnAccept(ctx);
+ }
+
void HandleConnected(TEvPollerReady::TPtr event, const TActorContext& ctx) {
if (event->Get()->Read) {
for (;;) {
@@ -114,7 +114,7 @@ protected:
CurrentRequest->Address = Address;
CurrentRequest->WorkerName = Endpoint.WorkerName;
CurrentRequest->Secure = Endpoint.Secure;
- }
+ }
if (!CurrentRequest->EnsureEnoughSpaceAvailable()) {
LOG_DEBUG_S(ctx, HttpLog, "(#" << TSocketImpl::GetRawSocket() << "," << Address << ") connection closed - not enough space available");
return Die(ctx);
@@ -134,13 +134,13 @@ protected:
CurrentRequest = nullptr;
} else if (CurrentRequest->IsError()) {
LOG_DEBUG_S(ctx, HttpLog, "(#" << TSocketImpl::GetRawSocket() << "," << Address << ") -! (" << CurrentRequest->Method << " " << CurrentRequest->URL << ")");
- bool success = Respond(CurrentRequest->CreateResponseBadRequest(), ctx);
- if (!success) {
- return;
- }
+ bool success = Respond(CurrentRequest->CreateResponseBadRequest(), ctx);
+ if (!success) {
+ return;
+ }
CurrentRequest = nullptr;
}
- }
+ }
} else if (-res == EAGAIN || -res == EWOULDBLOCK) {
if (PollerToken) {
if (!read && !write) {
@@ -148,18 +148,18 @@ protected:
}
PollerToken->Request(read, write);
}
- break;
+ break;
} else if (-res == EINTR) {
continue;
} else if (!res) {
// connection closed
- LOG_DEBUG_S(ctx, HttpLog, "(#" << TSocketImpl::GetRawSocket() << "," << Address << ") connection closed");
- return Die(ctx);
+ LOG_DEBUG_S(ctx, HttpLog, "(#" << TSocketImpl::GetRawSocket() << "," << Address << ") connection closed");
+ return Die(ctx);
} else {
- LOG_ERROR_S(ctx, HttpLog, "(#" << TSocketImpl::GetRawSocket() << "," << Address << ") connection closed - error in Receive: " << strerror(-res));
- return Die(ctx);
- }
- }
+ LOG_ERROR_S(ctx, HttpLog, "(#" << TSocketImpl::GetRawSocket() << "," << Address << ") connection closed - error in Receive: " << strerror(-res));
+ return Die(ctx);
+ }
+ }
if (event->Get() == InactivityEvent) {
const TDuration passed = TDuration::Seconds(std::abs(InactivityTimer.Passed()));
if (passed >= InactivityTimeout) {
@@ -173,83 +173,83 @@ protected:
if (event->Get()->Write) {
FlushOutput(ctx);
}
- }
-
+ }
+
void HandleConnected(TEvPollerRegisterResult::TPtr ev, const TActorContext& /*ctx*/) {
PollerToken = std::move(ev->Get()->PollerToken);
PollerToken->Request(true, true);
- }
-
- void HandleConnected(TEvHttpProxy::TEvHttpOutgoingResponse::TPtr event, const TActorContext& ctx) {
- Respond(event->Get()->Response, ctx);
- }
-
- bool Respond(THttpOutgoingResponsePtr response, const TActorContext& ctx) {
- THttpIncomingRequestPtr request = response->GetRequest();
- response->Finish();
- LOG_DEBUG_S(ctx, HttpLog, "(#" << TSocketImpl::GetRawSocket() << "," << Address << ") <- (" << response->Status << " " << response->Message << ")");
- if (response->Status != "200" && response->Status != "404") {
- static constexpr size_t MAX_LOGGED_SIZE = 1024;
- LOG_DEBUG_S(ctx, HttpLog,
- "(#"
- << TSocketImpl::GetRawSocket()
- << ","
- << Address
- << ") Request: "
- << request->GetObfuscatedData().substr(0, MAX_LOGGED_SIZE));
- LOG_DEBUG_S(ctx, HttpLog,
- "(#"
- << TSocketImpl::GetRawSocket()
- << ","
- << Address
- << ") Response: "
- << TString(response->GetRawData()).substr(0, MAX_LOGGED_SIZE));
- }
+ }
+
+ void HandleConnected(TEvHttpProxy::TEvHttpOutgoingResponse::TPtr event, const TActorContext& ctx) {
+ Respond(event->Get()->Response, ctx);
+ }
+
+ bool Respond(THttpOutgoingResponsePtr response, const TActorContext& ctx) {
+ THttpIncomingRequestPtr request = response->GetRequest();
+ response->Finish();
+ LOG_DEBUG_S(ctx, HttpLog, "(#" << TSocketImpl::GetRawSocket() << "," << Address << ") <- (" << response->Status << " " << response->Message << ")");
+ if (response->Status != "200" && response->Status != "404") {
+ static constexpr size_t MAX_LOGGED_SIZE = 1024;
+ LOG_DEBUG_S(ctx, HttpLog,
+ "(#"
+ << TSocketImpl::GetRawSocket()
+ << ","
+ << Address
+ << ") Request: "
+ << request->GetObfuscatedData().substr(0, MAX_LOGGED_SIZE));
+ LOG_DEBUG_S(ctx, HttpLog,
+ "(#"
+ << TSocketImpl::GetRawSocket()
+ << ","
+ << Address
+ << ") Response: "
+ << TString(response->GetRawData()).substr(0, MAX_LOGGED_SIZE));
+ }
THolder<TEvHttpProxy::TEvReportSensors> sensors(BuildIncomingRequestSensors(request, response));
- ctx.Send(Endpoint.Owner, sensors.Release());
- if (request == Requests.front() && CurrentResponse == nullptr) {
- CurrentResponse = response;
- return FlushOutput(ctx);
- } else {
- // we are ahead of our pipeline
- Responses.emplace(request, response);
- return true;
- }
- }
-
- bool FlushOutput(const TActorContext& ctx) {
- while (CurrentResponse != nullptr) {
- size_t size = CurrentResponse->Size();
- if (size == 0) {
- Y_VERIFY(Requests.front() == CurrentResponse->GetRequest());
- bool close = CurrentResponse->IsConnectionClose();
- Requests.pop_front();
- CleanupResponse(CurrentResponse);
- if (!Requests.empty()) {
- auto it = Responses.find(Requests.front());
- if (it != Responses.end()) {
- CurrentResponse = it->second;
- Responses.erase(it);
- continue;
- } else {
- LOG_ERROR_S(ctx, HttpLog, "(#" << TSocketImpl::GetRawSocket() << "," << Address << ") connection closed - FlushOutput request not found");
- Die(ctx);
- return false;
- }
- } else {
- if (close) {
- LOG_DEBUG_S(ctx, HttpLog, "(#" << TSocketImpl::GetRawSocket() << "," << Address << ") connection closed");
- Die(ctx);
- return false;
- } else {
- continue;
- }
- }
- }
+ ctx.Send(Endpoint.Owner, sensors.Release());
+ if (request == Requests.front() && CurrentResponse == nullptr) {
+ CurrentResponse = response;
+ return FlushOutput(ctx);
+ } else {
+ // we are ahead of our pipeline
+ Responses.emplace(request, response);
+ return true;
+ }
+ }
+
+ bool FlushOutput(const TActorContext& ctx) {
+ while (CurrentResponse != nullptr) {
+ size_t size = CurrentResponse->Size();
+ if (size == 0) {
+ Y_VERIFY(Requests.front() == CurrentResponse->GetRequest());
+ bool close = CurrentResponse->IsConnectionClose();
+ Requests.pop_front();
+ CleanupResponse(CurrentResponse);
+ if (!Requests.empty()) {
+ auto it = Responses.find(Requests.front());
+ if (it != Responses.end()) {
+ CurrentResponse = it->second;
+ Responses.erase(it);
+ continue;
+ } else {
+ LOG_ERROR_S(ctx, HttpLog, "(#" << TSocketImpl::GetRawSocket() << "," << Address << ") connection closed - FlushOutput request not found");
+ Die(ctx);
+ return false;
+ }
+ } else {
+ if (close) {
+ LOG_DEBUG_S(ctx, HttpLog, "(#" << TSocketImpl::GetRawSocket() << "," << Address << ") connection closed");
+ Die(ctx);
+ return false;
+ } else {
+ continue;
+ }
+ }
+ }
bool read = false, write = false;
ssize_t res = TSocketImpl::Send(CurrentResponse->Data(), size, read, write);
- if (res > 0) {
- CurrentResponse->ChopHead(res);
+ if (res > 0) {
+ CurrentResponse->ChopHead(res);
} else if (-res == EINTR) {
continue;
} else if (-res == EAGAIN || -res == EWOULDBLOCK) {
@@ -258,45 +258,45 @@ protected:
write = true;
}
PollerToken->Request(read, write);
- }
- break;
+ }
+ break;
} else {
CleanupResponse(CurrentResponse);
LOG_ERROR_S(ctx, HttpLog, "(#" << TSocketImpl::GetRawSocket() << "," << Address << ") connection closed - error in FlushOutput: " << strerror(-res));
- Die(ctx);
- return false;
- }
- }
- return true;
- }
-
- STFUNC(StateAccepting) {
- switch (ev->GetTypeRewrite()) {
+ Die(ctx);
+ return false;
+ }
+ }
+ return true;
+ }
+
+ STFUNC(StateAccepting) {
+ switch (ev->GetTypeRewrite()) {
CFunc(TEvents::TEvBootstrap::EventType, Bootstrap);
HFunc(TEvPollerReady, HandleAccepting);
HFunc(TEvPollerRegisterResult, HandleAccepting);
- }
- }
-
- STFUNC(StateConnected) {
- switch (ev->GetTypeRewrite()) {
+ }
+ }
+
+ STFUNC(StateConnected) {
+ switch (ev->GetTypeRewrite()) {
HFunc(TEvPollerReady, HandleConnected);
- HFunc(TEvHttpProxy::TEvHttpOutgoingResponse, HandleConnected);
+ HFunc(TEvHttpProxy::TEvHttpOutgoingResponse, HandleConnected);
HFunc(TEvPollerRegisterResult, HandleConnected);
- }
- }
-};
-
-IActor* CreateIncomingConnectionActor(
- const TEndpointInfo& endpoint,
- TIntrusivePtr<TSocketDescriptor> socket,
- THttpConfig::SocketAddressType address,
- THttpIncomingRequestPtr recycledRequest) {
- if (endpoint.Secure) {
- return new TIncomingConnectionActor<TSecureSocketImpl>(endpoint, std::move(socket), address, std::move(recycledRequest));
- } else {
- return new TIncomingConnectionActor<TPlainSocketImpl>(endpoint, std::move(socket), address, std::move(recycledRequest));
- }
-}
-
-}
+ }
+ }
+};
+
+IActor* CreateIncomingConnectionActor(
+ const TEndpointInfo& endpoint,
+ TIntrusivePtr<TSocketDescriptor> socket,
+ THttpConfig::SocketAddressType address,
+ THttpIncomingRequestPtr recycledRequest) {
+ if (endpoint.Secure) {
+ return new TIncomingConnectionActor<TSecureSocketImpl>(endpoint, std::move(socket), address, std::move(recycledRequest));
+ } else {
+ return new TIncomingConnectionActor<TPlainSocketImpl>(endpoint, std::move(socket), address, std::move(recycledRequest));
+ }
+}
+
+}
diff --git a/library/cpp/actors/http/http_proxy_outgoing.cpp b/library/cpp/actors/http/http_proxy_outgoing.cpp
index d9189dba8a..5b3d07c614 100644
--- a/library/cpp/actors/http/http_proxy_outgoing.cpp
+++ b/library/cpp/actors/http/http_proxy_outgoing.cpp
@@ -1,92 +1,92 @@
-#include "http_proxy.h"
-#include "http_proxy_sock_impl.h"
-
-namespace NHttp {
-
-template <typename TSocketImpl>
-class TOutgoingConnectionActor : public NActors::TActor<TOutgoingConnectionActor<TSocketImpl>>, public TSocketImpl, virtual public THttpConfig {
-public:
- using TBase = NActors::TActor<TOutgoingConnectionActor<TSocketImpl>>;
- using TSelf = TOutgoingConnectionActor<TSocketImpl>;
+#include "http_proxy.h"
+#include "http_proxy_sock_impl.h"
+
+namespace NHttp {
+
+template <typename TSocketImpl>
+class TOutgoingConnectionActor : public NActors::TActor<TOutgoingConnectionActor<TSocketImpl>>, public TSocketImpl, virtual public THttpConfig {
+public:
+ using TBase = NActors::TActor<TOutgoingConnectionActor<TSocketImpl>>;
+ using TSelf = TOutgoingConnectionActor<TSocketImpl>;
const TActorId Owner;
const TActorId Poller;
- SocketAddressType Address;
- TString Host;
+ SocketAddressType Address;
+ TString Host;
TActorId RequestOwner;
- THttpOutgoingRequestPtr Request;
- THttpIncomingResponsePtr Response;
- TInstant LastActivity;
- TDuration ConnectionTimeout = CONNECTION_TIMEOUT;
+ THttpOutgoingRequestPtr Request;
+ THttpIncomingResponsePtr Response;
+ TInstant LastActivity;
+ TDuration ConnectionTimeout = CONNECTION_TIMEOUT;
NActors::TPollerToken::TPtr PollerToken;
-
+
TOutgoingConnectionActor(const TActorId& owner, const TString& host, const TActorId& poller)
- : TBase(&TSelf::StateWaiting)
- , Owner(owner)
- , Poller(poller)
- , Host(host)
- {
- TSocketImpl::SetNonBlock();
- TSocketImpl::SetTimeout(SOCKET_TIMEOUT);
- }
-
+ : TBase(&TSelf::StateWaiting)
+ , Owner(owner)
+ , Poller(poller)
+ , Host(host)
+ {
+ TSocketImpl::SetNonBlock();
+ TSocketImpl::SetTimeout(SOCKET_TIMEOUT);
+ }
+
void Die(const NActors::TActorContext& ctx) override {
- ctx.Send(Owner, new TEvHttpProxy::TEvHttpConnectionClosed(ctx.SelfID));
- TSocketImpl::Shutdown(); // to avoid errors when connection already closed
- TBase::Die(ctx);
- }
-
- void ReplyAndDie(const NActors::TActorContext& ctx) {
- LOG_DEBUG_S(ctx, HttpLog, "(#" << TSocketImpl::GetRawSocket() << "," << Address << ") -> (" << Response->Status << " " << Response->Message << ")");
- ctx.Send(RequestOwner, new TEvHttpProxy::TEvHttpIncomingResponse(Request, Response));
+ ctx.Send(Owner, new TEvHttpProxy::TEvHttpConnectionClosed(ctx.SelfID));
+ TSocketImpl::Shutdown(); // to avoid errors when connection already closed
+ TBase::Die(ctx);
+ }
+
+ void ReplyAndDie(const NActors::TActorContext& ctx) {
+ LOG_DEBUG_S(ctx, HttpLog, "(#" << TSocketImpl::GetRawSocket() << "," << Address << ") -> (" << 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");
- Die(ctx);
- }
-
- void ReplyErrorAndDie(const NActors::TActorContext& ctx, const TString& error) {
- LOG_ERROR_S(ctx, HttpLog, "(#" << TSocketImpl::GetRawSocket() << "," << Address << ") connection closed with error: " << error);
- if (RequestOwner) {
- ctx.Send(RequestOwner, new TEvHttpProxy::TEvHttpIncomingResponse(Request, Response, error));
+ ctx.Send(Owner, sensors.Release());
+ LOG_DEBUG_S(ctx, HttpLog, "(#" << TSocketImpl::GetRawSocket() << "," << Address << ") 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);
+ if (RequestOwner) {
+ ctx.Send(RequestOwner, new TEvHttpProxy::TEvHttpIncomingResponse(Request, Response, error));
RequestOwner = TActorId();
THolder<TEvHttpProxy::TEvReportSensors> sensors(BuildOutgoingRequestSensors(Request, Response));
- ctx.Send(Owner, sensors.Release());
- Die(ctx);
- }
- }
-
-protected:
- void FailConnection(const NActors::TActorContext& ctx, const TString& error) {
- if (Request) {
- return ReplyErrorAndDie(ctx, error);
- }
- return TBase::Become(&TOutgoingConnectionActor::StateFailed);
- }
-
- void Connect(const NActors::TActorContext& ctx) {
- LOG_DEBUG_S(ctx, HttpLog, "(#" << TSocketImpl::GetRawSocket() << "," << Address << ") connecting");
- int res = TSocketImpl::Connect(Address);
- RegisterPoller(ctx);
- switch (-res) {
- case 0:
- return OnConnect(ctx);
- case EINPROGRESS:
- case EAGAIN:
- return TBase::Become(&TOutgoingConnectionActor::StateConnecting);
- default:
- return ReplyErrorAndDie(ctx, strerror(-res));
- }
- }
-
- void FlushOutput(const NActors::TActorContext& ctx) {
- if (Request != nullptr) {
- Request->Finish();
+ ctx.Send(Owner, sensors.Release());
+ Die(ctx);
+ }
+ }
+
+protected:
+ void FailConnection(const NActors::TActorContext& ctx, const TString& error) {
+ if (Request) {
+ return ReplyErrorAndDie(ctx, error);
+ }
+ return TBase::Become(&TOutgoingConnectionActor::StateFailed);
+ }
+
+ void Connect(const NActors::TActorContext& ctx) {
+ LOG_DEBUG_S(ctx, HttpLog, "(#" << TSocketImpl::GetRawSocket() << "," << Address << ") connecting");
+ int res = TSocketImpl::Connect(Address);
+ RegisterPoller(ctx);
+ switch (-res) {
+ case 0:
+ return OnConnect(ctx);
+ case EINPROGRESS:
+ case EAGAIN:
+ return TBase::Become(&TOutgoingConnectionActor::StateConnecting);
+ default:
+ return ReplyErrorAndDie(ctx, strerror(-res));
+ }
+ }
+
+ void FlushOutput(const NActors::TActorContext& ctx) {
+ if (Request != nullptr) {
+ Request->Finish();
while (auto size = Request->Size()) {
bool read = false, write = false;
ssize_t res = TSocketImpl::Send(Request->Data(), size, read, write);
- if (res > 0) {
- Request->ChopHead(res);
+ if (res > 0) {
+ Request->ChopHead(res);
} else if (-res == EINTR) {
continue;
} else if (-res == EAGAIN || -res == EWOULDBLOCK) {
@@ -97,30 +97,30 @@ protected:
PollerToken->Request(read, write);
}
break;
- } else {
+ } else {
if (!res) {
- ReplyAndDie(ctx);
+ ReplyAndDie(ctx);
} else {
- ReplyErrorAndDie(ctx, strerror(-res));
- }
+ ReplyErrorAndDie(ctx, strerror(-res));
+ }
break;
- }
- }
- }
- }
-
- void PullInput(const NActors::TActorContext& ctx) {
+ }
+ }
+ }
+ }
+
+ void PullInput(const NActors::TActorContext& ctx) {
for (;;) {
- if (Response == nullptr) {
- Response = new THttpIncomingResponse(Request);
- }
- if (!Response->EnsureEnoughSpaceAvailable()) {
- return ReplyErrorAndDie(ctx, "Not enough space in socket buffer");
- }
+ if (Response == nullptr) {
+ Response = new THttpIncomingResponse(Request);
+ }
+ if (!Response->EnsureEnoughSpaceAvailable()) {
+ return ReplyErrorAndDie(ctx, "Not enough space in socket buffer");
+ }
bool read = false, write = false;
ssize_t res = TSocketImpl::Recv(Response->Pos(), Response->Avail(), read, write);
- if (res > 0) {
- Response->Advance(res);
+ if (res > 0) {
+ Response->Advance(res);
if (Response->IsDone() && Response->IsReady()) {
return ReplyAndDie(ctx);
}
@@ -130,169 +130,169 @@ protected:
if (PollerToken) {
if (!read && !write) {
read = true;
- }
+ }
PollerToken->Request(read, write);
- }
+ }
return;
- } else {
+ } else {
if (!res) {
- Response->ConnectionClosed();
- }
+ Response->ConnectionClosed();
+ }
if (Response->IsDone() && Response->IsReady()) {
return ReplyAndDie(ctx);
}
return ReplyErrorAndDie(ctx, strerror(-res));
- }
+ }
}
- }
-
- void RegisterPoller(const NActors::TActorContext& ctx) {
+ }
+
+ void RegisterPoller(const NActors::TActorContext& ctx) {
ctx.Send(Poller, new NActors::TEvPollerRegister(TSocketImpl::Socket, ctx.SelfID, ctx.SelfID));
- }
-
- void OnConnect(const NActors::TActorContext& ctx) {
+ }
+
+ void OnConnect(const NActors::TActorContext& ctx) {
bool read = false, write = false;
if (int res = TSocketImpl::OnConnect(read, write); res != 1) {
if (-res == EAGAIN) {
if (PollerToken) {
PollerToken->Request(read, write);
}
- return;
+ return;
} else {
return ReplyErrorAndDie(ctx, strerror(-res));
- }
- }
- LOG_DEBUG_S(ctx, HttpLog, "(#" << TSocketImpl::GetRawSocket() << "," << Address << ") outgoing connection opened");
- TBase::Become(&TOutgoingConnectionActor::StateConnected);
- LOG_DEBUG_S(ctx, HttpLog, "(#" << TSocketImpl::GetRawSocket() << "," << Address << ") <- (" << Request->Method << " " << Request->URL << ")");
+ }
+ }
+ LOG_DEBUG_S(ctx, HttpLog, "(#" << TSocketImpl::GetRawSocket() << "," << Address << ") outgoing connection opened");
+ TBase::Become(&TOutgoingConnectionActor::StateConnected);
+ LOG_DEBUG_S(ctx, HttpLog, "(#" << TSocketImpl::GetRawSocket() << "," << Address << ") <- (" << Request->Method << " " << Request->URL << ")");
ctx.Send(ctx.SelfID, new NActors::TEvPollerReady(nullptr, true, true));
- }
-
- 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);
- }
- Connect(ctx);
- }
-
+ }
+
+ 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);
+ }
+ Connect(ctx);
+ }
+
void HandleConnecting(NActors::TEvPollerReady::TPtr, const NActors::TActorContext& ctx) {
- LastActivity = ctx.Now();
- int res = TSocketImpl::GetError();
- if (res == 0) {
- OnConnect(ctx);
- } else {
- FailConnection(ctx, TStringBuilder() << strerror(res));
- }
- }
-
+ LastActivity = ctx.Now();
+ int res = TSocketImpl::GetError();
+ if (res == 0) {
+ OnConnect(ctx);
+ } else {
+ FailConnection(ctx, TStringBuilder() << strerror(res));
+ }
+ }
+
void HandleConnecting(NActors::TEvPollerRegisterResult::TPtr ev, const NActors::TActorContext& ctx) {
PollerToken = std::move(ev->Get()->PollerToken);
- LastActivity = ctx.Now();
- int res = TSocketImpl::GetError();
- if (res == 0) {
- OnConnect(ctx);
- } else {
- FailConnection(ctx, TStringBuilder() << strerror(res));
- }
- }
-
- void HandleWaiting(TEvHttpProxy::TEvHttpOutgoingRequest::TPtr event, const NActors::TActorContext& ctx) {
- LastActivity = ctx.Now();
- Request = std::move(event->Get()->Request);
- Host = Request->Host;
- LOG_DEBUG_S(ctx, HttpLog, "(#" << TSocketImpl::GetRawSocket() << ") 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();
- TBase::Become(&TOutgoingConnectionActor::StateResolving);
- }
-
+ LastActivity = ctx.Now();
+ int res = TSocketImpl::GetError();
+ if (res == 0) {
+ OnConnect(ctx);
+ } else {
+ FailConnection(ctx, TStringBuilder() << strerror(res));
+ }
+ }
+
+ void HandleWaiting(TEvHttpProxy::TEvHttpOutgoingRequest::TPtr event, const NActors::TActorContext& ctx) {
+ LastActivity = ctx.Now();
+ Request = std::move(event->Get()->Request);
+ Host = Request->Host;
+ LOG_DEBUG_S(ctx, HttpLog, "(#" << TSocketImpl::GetRawSocket() << ") 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();
+ TBase::Become(&TOutgoingConnectionActor::StateResolving);
+ }
+
void HandleConnected(NActors::TEvPollerReady::TPtr event, const NActors::TActorContext& ctx) {
- LastActivity = ctx.Now();
+ LastActivity = ctx.Now();
if (event->Get()->Read) {
PullInput(ctx);
- }
+ }
if (event->Get()->Write) {
FlushOutput(ctx);
}
- }
-
+ }
+
void HandleConnected(NActors::TEvPollerRegisterResult::TPtr ev, const NActors::TActorContext& ctx) {
PollerToken = std::move(ev->Get()->PollerToken);
- LastActivity = ctx.Now();
+ LastActivity = ctx.Now();
PullInput(ctx);
- FlushOutput(ctx);
- }
-
- void HandleFailed(TEvHttpProxy::TEvHttpOutgoingRequest::TPtr event, const NActors::TActorContext& ctx) {
- Request = std::move(event->Get()->Request);
- RequestOwner = event->Sender;
- ReplyErrorAndDie(ctx, "Failed");
- }
-
- void HandleTimeout(const NActors::TActorContext& ctx) {
- TDuration inactivityTime = ctx.Now() - LastActivity;
- if (inactivityTime >= ConnectionTimeout) {
- FailConnection(ctx, "Connection timed out");
- } else {
- ctx.Schedule(Min(ConnectionTimeout - inactivityTime, TDuration::MilliSeconds(100)), new NActors::TEvents::TEvWakeup());
- }
- }
-
- STFUNC(StateWaiting) {
- switch (ev->GetTypeRewrite()) {
- HFunc(TEvHttpProxy::TEvHttpOutgoingRequest, HandleWaiting);
- CFunc(NActors::TEvents::TEvWakeup::EventType, HandleTimeout);
- }
- }
-
- STFUNC(StateResolving) {
- switch (ev->GetTypeRewrite()) {
- HFunc(TEvHttpProxy::TEvResolveHostResponse, HandleResolving);
- CFunc(NActors::TEvents::TEvWakeup::EventType, HandleTimeout);
- }
- }
-
- STFUNC(StateConnecting) {
- switch (ev->GetTypeRewrite()) {
+ FlushOutput(ctx);
+ }
+
+ void HandleFailed(TEvHttpProxy::TEvHttpOutgoingRequest::TPtr event, const NActors::TActorContext& ctx) {
+ Request = std::move(event->Get()->Request);
+ RequestOwner = event->Sender;
+ ReplyErrorAndDie(ctx, "Failed");
+ }
+
+ void HandleTimeout(const NActors::TActorContext& ctx) {
+ TDuration inactivityTime = ctx.Now() - LastActivity;
+ if (inactivityTime >= ConnectionTimeout) {
+ FailConnection(ctx, "Connection timed out");
+ } else {
+ ctx.Schedule(Min(ConnectionTimeout - inactivityTime, TDuration::MilliSeconds(100)), new NActors::TEvents::TEvWakeup());
+ }
+ }
+
+ STFUNC(StateWaiting) {
+ switch (ev->GetTypeRewrite()) {
+ HFunc(TEvHttpProxy::TEvHttpOutgoingRequest, HandleWaiting);
+ CFunc(NActors::TEvents::TEvWakeup::EventType, HandleTimeout);
+ }
+ }
+
+ STFUNC(StateResolving) {
+ switch (ev->GetTypeRewrite()) {
+ HFunc(TEvHttpProxy::TEvResolveHostResponse, HandleResolving);
+ CFunc(NActors::TEvents::TEvWakeup::EventType, HandleTimeout);
+ }
+ }
+
+ STFUNC(StateConnecting) {
+ switch (ev->GetTypeRewrite()) {
HFunc(NActors::TEvPollerReady, HandleConnecting);
- CFunc(NActors::TEvents::TEvWakeup::EventType, HandleTimeout);
+ CFunc(NActors::TEvents::TEvWakeup::EventType, HandleTimeout);
HFunc(NActors::TEvPollerRegisterResult, HandleConnecting);
- }
- }
-
- STFUNC(StateConnected) {
- switch (ev->GetTypeRewrite()) {
+ }
+ }
+
+ STFUNC(StateConnected) {
+ switch (ev->GetTypeRewrite()) {
HFunc(NActors::TEvPollerReady, HandleConnected);
- CFunc(NActors::TEvents::TEvWakeup::EventType, HandleTimeout);
+ CFunc(NActors::TEvents::TEvWakeup::EventType, HandleTimeout);
HFunc(NActors::TEvPollerRegisterResult, HandleConnected);
- }
- }
-
- STFUNC(StateFailed) {
- switch (ev->GetTypeRewrite()) {
- HFunc(TEvHttpProxy::TEvHttpOutgoingRequest, HandleFailed);
- }
- }
-};
-
+ }
+ }
+
+ STFUNC(StateFailed) {
+ switch (ev->GetTypeRewrite()) {
+ HFunc(TEvHttpProxy::TEvHttpOutgoingRequest, HandleFailed);
+ }
+ }
+};
+
NActors::IActor* CreateOutgoingConnectionActor(const TActorId& owner, const TString& host, bool secure, const TActorId& poller) {
- if (secure) {
- return new TOutgoingConnectionActor<TSecureSocketImpl>(owner, host, poller);
- } else {
- return new TOutgoingConnectionActor<TPlainSocketImpl>(owner, host, poller);
- }
-}
-
-}
+ if (secure) {
+ return new TOutgoingConnectionActor<TSecureSocketImpl>(owner, host, poller);
+ } else {
+ return new TOutgoingConnectionActor<TPlainSocketImpl>(owner, host, poller);
+ }
+}
+
+}
diff --git a/library/cpp/actors/http/http_proxy_sock_impl.h b/library/cpp/actors/http/http_proxy_sock_impl.h
index bf8c71d05a..e7812cc5e1 100644
--- a/library/cpp/actors/http/http_proxy_sock_impl.h
+++ b/library/cpp/actors/http/http_proxy_sock_impl.h
@@ -1,262 +1,262 @@
-#pragma once
-
-#include "http.h"
-#include "http_proxy.h"
-
-namespace NHttp {
-
-struct TPlainSocketImpl : virtual public THttpConfig {
- TIntrusivePtr<TSocketDescriptor> Socket;
-
- TPlainSocketImpl()
- : Socket(new TSocketDescriptor())
- {}
-
- TPlainSocketImpl(TIntrusivePtr<TSocketDescriptor> socket)
- : Socket(std::move(socket))
- {}
-
- SOCKET GetRawSocket() const {
- return static_cast<SOCKET>(Socket->Socket);
- }
-
- void SetNonBlock(bool nonBlock = true) noexcept {
- try {
- ::SetNonBlock(Socket->Socket, nonBlock);
- }
- catch (const yexception&) {
- }
- }
-
- void SetTimeout(TDuration timeout) noexcept {
- try {
- ::SetSocketTimeout(Socket->Socket, timeout.Seconds(), timeout.MilliSecondsOfSecond());
- }
- catch (const yexception&) {
- }
- }
-
- void Shutdown() {
- //Socket->Socket.ShutDown(SHUT_RDWR); // KIKIMR-3895
- ::shutdown(Socket->Socket, SHUT_RDWR);
- }
-
- int Connect(const SocketAddressType& address) {
- return Socket->Socket.Connect(&address);
- }
-
+#pragma once
+
+#include "http.h"
+#include "http_proxy.h"
+
+namespace NHttp {
+
+struct TPlainSocketImpl : virtual public THttpConfig {
+ TIntrusivePtr<TSocketDescriptor> Socket;
+
+ TPlainSocketImpl()
+ : Socket(new TSocketDescriptor())
+ {}
+
+ TPlainSocketImpl(TIntrusivePtr<TSocketDescriptor> socket)
+ : Socket(std::move(socket))
+ {}
+
+ SOCKET GetRawSocket() const {
+ return static_cast<SOCKET>(Socket->Socket);
+ }
+
+ void SetNonBlock(bool nonBlock = true) noexcept {
+ try {
+ ::SetNonBlock(Socket->Socket, nonBlock);
+ }
+ catch (const yexception&) {
+ }
+ }
+
+ void SetTimeout(TDuration timeout) noexcept {
+ try {
+ ::SetSocketTimeout(Socket->Socket, timeout.Seconds(), timeout.MilliSecondsOfSecond());
+ }
+ catch (const yexception&) {
+ }
+ }
+
+ void Shutdown() {
+ //Socket->Socket.ShutDown(SHUT_RDWR); // KIKIMR-3895
+ ::shutdown(Socket->Socket, SHUT_RDWR);
+ }
+
+ int Connect(const SocketAddressType& address) {
+ return Socket->Socket.Connect(&address);
+ }
+
static constexpr int OnConnect(bool&, bool&) {
return 1;
- }
-
+ }
+
static constexpr int OnAccept(const TEndpointInfo&, bool&, bool&) {
return 1;
- }
-
- bool IsGood() {
- int res;
- GetSockOpt(Socket->Socket, SOL_SOCKET, SO_ERROR, res);
- return res == 0;
- }
-
- int GetError() {
- int res;
- GetSockOpt(Socket->Socket, SOL_SOCKET, SO_ERROR, res);
- return res;
- }
-
+ }
+
+ bool IsGood() {
+ int res;
+ GetSockOpt(Socket->Socket, SOL_SOCKET, SO_ERROR, res);
+ return res == 0;
+ }
+
+ int GetError() {
+ int res;
+ GetSockOpt(Socket->Socket, SOL_SOCKET, SO_ERROR, res);
+ return res;
+ }
+
ssize_t Send(const void* data, size_t size, bool&, bool&) {
- return Socket->Socket.Send(data, size);
- }
-
+ return Socket->Socket.Send(data, size);
+ }
+
ssize_t Recv(void* data, size_t size, bool&, bool&) {
- return Socket->Socket.Recv(data, size);
- }
-};
-
-struct TSecureSocketImpl : TPlainSocketImpl, TSslHelpers {
- static TSecureSocketImpl* IO(BIO* bio) noexcept {
- return static_cast<TSecureSocketImpl*>(BIO_get_data(bio));
- }
-
- static int IoWrite(BIO* bio, const char* data, int dlen) noexcept {
- BIO_clear_retry_flags(bio);
- int res = IO(bio)->Socket->Socket.Send(data, dlen);
- if (-res == EAGAIN) {
- BIO_set_retry_write(bio);
- }
- return res;
- }
-
- static int IoRead(BIO* bio, char* data, int dlen) noexcept {
- BIO_clear_retry_flags(bio);
- int res = IO(bio)->Socket->Socket.Recv(data, dlen);
- if (-res == EAGAIN) {
- BIO_set_retry_read(bio);
- }
- return res;
- }
-
- static int IoPuts(BIO* bio, const char* buf) noexcept {
- Y_UNUSED(bio);
- Y_UNUSED(buf);
- return -2;
- }
-
- static int IoGets(BIO* bio, char* buf, int size) noexcept {
- Y_UNUSED(bio);
- Y_UNUSED(buf);
- Y_UNUSED(size);
- return -2;
- }
-
- static long IoCtrl(BIO* bio, int cmd, long larg, void* parg) noexcept {
- Y_UNUSED(larg);
- Y_UNUSED(parg);
-
- if (cmd == BIO_CTRL_FLUSH) {
- IO(bio)->Flush();
- return 1;
- }
-
- return -2;
- }
-
- static int IoCreate(BIO* bio) noexcept {
- BIO_set_data(bio, nullptr);
- BIO_set_init(bio, 1);
- return 1;
- }
-
- static int IoDestroy(BIO* bio) noexcept {
- BIO_set_data(bio, nullptr);
- BIO_set_init(bio, 0);
- return 1;
- }
-
- static BIO_METHOD* CreateIoMethod() {
- BIO_METHOD* method = BIO_meth_new(BIO_get_new_index() | BIO_TYPE_SOURCE_SINK, "SecureSocketImpl");
- BIO_meth_set_write(method, IoWrite);
- BIO_meth_set_read(method, IoRead);
- BIO_meth_set_puts(method, IoPuts);
- BIO_meth_set_gets(method, IoGets);
- BIO_meth_set_ctrl(method, IoCtrl);
- BIO_meth_set_create(method, IoCreate);
- BIO_meth_set_destroy(method, IoDestroy);
- return method;
- }
-
- static BIO_METHOD* IoMethod() {
- static BIO_METHOD* method = CreateIoMethod();
- return method;
- }
-
- TSslHolder<BIO> Bio;
- TSslHolder<SSL_CTX> Ctx;
- TSslHolder<SSL> Ssl;
-
- TSecureSocketImpl() = default;
-
- TSecureSocketImpl(TIntrusivePtr<TSocketDescriptor> socket)
- : TPlainSocketImpl(std::move(socket))
- {}
-
- void InitClientSsl() {
+ return Socket->Socket.Recv(data, size);
+ }
+};
+
+struct TSecureSocketImpl : TPlainSocketImpl, TSslHelpers {
+ static TSecureSocketImpl* IO(BIO* bio) noexcept {
+ return static_cast<TSecureSocketImpl*>(BIO_get_data(bio));
+ }
+
+ static int IoWrite(BIO* bio, const char* data, int dlen) noexcept {
+ BIO_clear_retry_flags(bio);
+ int res = IO(bio)->Socket->Socket.Send(data, dlen);
+ if (-res == EAGAIN) {
+ BIO_set_retry_write(bio);
+ }
+ return res;
+ }
+
+ static int IoRead(BIO* bio, char* data, int dlen) noexcept {
+ BIO_clear_retry_flags(bio);
+ int res = IO(bio)->Socket->Socket.Recv(data, dlen);
+ if (-res == EAGAIN) {
+ BIO_set_retry_read(bio);
+ }
+ return res;
+ }
+
+ static int IoPuts(BIO* bio, const char* buf) noexcept {
+ Y_UNUSED(bio);
+ Y_UNUSED(buf);
+ return -2;
+ }
+
+ static int IoGets(BIO* bio, char* buf, int size) noexcept {
+ Y_UNUSED(bio);
+ Y_UNUSED(buf);
+ Y_UNUSED(size);
+ return -2;
+ }
+
+ static long IoCtrl(BIO* bio, int cmd, long larg, void* parg) noexcept {
+ Y_UNUSED(larg);
+ Y_UNUSED(parg);
+
+ if (cmd == BIO_CTRL_FLUSH) {
+ IO(bio)->Flush();
+ return 1;
+ }
+
+ return -2;
+ }
+
+ static int IoCreate(BIO* bio) noexcept {
+ BIO_set_data(bio, nullptr);
+ BIO_set_init(bio, 1);
+ return 1;
+ }
+
+ static int IoDestroy(BIO* bio) noexcept {
+ BIO_set_data(bio, nullptr);
+ BIO_set_init(bio, 0);
+ return 1;
+ }
+
+ static BIO_METHOD* CreateIoMethod() {
+ BIO_METHOD* method = BIO_meth_new(BIO_get_new_index() | BIO_TYPE_SOURCE_SINK, "SecureSocketImpl");
+ BIO_meth_set_write(method, IoWrite);
+ BIO_meth_set_read(method, IoRead);
+ BIO_meth_set_puts(method, IoPuts);
+ BIO_meth_set_gets(method, IoGets);
+ BIO_meth_set_ctrl(method, IoCtrl);
+ BIO_meth_set_create(method, IoCreate);
+ BIO_meth_set_destroy(method, IoDestroy);
+ return method;
+ }
+
+ static BIO_METHOD* IoMethod() {
+ static BIO_METHOD* method = CreateIoMethod();
+ return method;
+ }
+
+ TSslHolder<BIO> Bio;
+ TSslHolder<SSL_CTX> Ctx;
+ TSslHolder<SSL> Ssl;
+
+ TSecureSocketImpl() = default;
+
+ TSecureSocketImpl(TIntrusivePtr<TSocketDescriptor> socket)
+ : TPlainSocketImpl(std::move(socket))
+ {}
+
+ void InitClientSsl() {
Bio.Reset(BIO_new(IoMethod()));
- BIO_set_data(Bio.Get(), this);
- BIO_set_nbio(Bio.Get(), 1);
- Ctx = CreateClientContext();
- Ssl = ConstructSsl(Ctx.Get(), Bio.Get());
- SSL_set_connect_state(Ssl.Get());
- }
-
- void InitServerSsl(SSL_CTX* ctx) {
+ BIO_set_data(Bio.Get(), this);
+ BIO_set_nbio(Bio.Get(), 1);
+ Ctx = CreateClientContext();
+ Ssl = ConstructSsl(Ctx.Get(), Bio.Get());
+ SSL_set_connect_state(Ssl.Get());
+ }
+
+ void InitServerSsl(SSL_CTX* ctx) {
Bio.Reset(BIO_new(IoMethod()));
- BIO_set_data(Bio.Get(), this);
- BIO_set_nbio(Bio.Get(), 1);
- Ssl = ConstructSsl(ctx, Bio.Get());
- SSL_set_accept_state(Ssl.Get());
- }
-
- void Flush() {}
-
+ BIO_set_data(Bio.Get(), this);
+ BIO_set_nbio(Bio.Get(), 1);
+ Ssl = ConstructSsl(ctx, Bio.Get());
+ SSL_set_accept_state(Ssl.Get());
+ }
+
+ void Flush() {}
+
ssize_t Send(const void* data, size_t size, bool& read, bool& write) {
- ssize_t res = SSL_write(Ssl.Get(), data, size);
- if (res < 0) {
- res = SSL_get_error(Ssl.Get(), res);
- switch(res) {
- case SSL_ERROR_WANT_READ:
+ ssize_t res = SSL_write(Ssl.Get(), data, size);
+ if (res < 0) {
+ res = SSL_get_error(Ssl.Get(), res);
+ switch(res) {
+ case SSL_ERROR_WANT_READ:
read = true;
return -EAGAIN;
- case SSL_ERROR_WANT_WRITE:
+ case SSL_ERROR_WANT_WRITE:
write = true;
- return -EAGAIN;
- default:
- return -EIO;
- }
- }
- return res;
- }
-
+ return -EAGAIN;
+ default:
+ return -EIO;
+ }
+ }
+ return res;
+ }
+
ssize_t Recv(void* data, size_t size, bool& read, bool& write) {
- ssize_t res = SSL_read(Ssl.Get(), data, size);
- if (res < 0) {
- res = SSL_get_error(Ssl.Get(), res);
- switch(res) {
- case SSL_ERROR_WANT_READ:
+ ssize_t res = SSL_read(Ssl.Get(), data, size);
+ if (res < 0) {
+ res = SSL_get_error(Ssl.Get(), res);
+ switch(res) {
+ case SSL_ERROR_WANT_READ:
read = true;
return -EAGAIN;
- case SSL_ERROR_WANT_WRITE:
+ case SSL_ERROR_WANT_WRITE:
write = true;
- return -EAGAIN;
- default:
- return -EIO;
- }
- }
- return res;
- }
-
+ return -EAGAIN;
+ default:
+ return -EIO;
+ }
+ }
+ return res;
+ }
+
int OnConnect(bool& read, bool& write) {
- if (!Ssl) {
- InitClientSsl();
- }
- int res = SSL_connect(Ssl.Get());
+ if (!Ssl) {
+ InitClientSsl();
+ }
+ int res = SSL_connect(Ssl.Get());
if (res <= 0) {
- res = SSL_get_error(Ssl.Get(), res);
- switch(res) {
- case SSL_ERROR_WANT_READ:
+ res = SSL_get_error(Ssl.Get(), res);
+ switch(res) {
+ case SSL_ERROR_WANT_READ:
read = true;
return -EAGAIN;
- case SSL_ERROR_WANT_WRITE:
+ case SSL_ERROR_WANT_WRITE:
write = true;
- return -EAGAIN;
- default:
- return -EIO;
- }
- }
- return res;
- }
-
+ return -EAGAIN;
+ default:
+ return -EIO;
+ }
+ }
+ return res;
+ }
+
int OnAccept(const TEndpointInfo& endpoint, bool& read, bool& write) {
- if (!Ssl) {
- InitServerSsl(endpoint.SecureContext.Get());
- }
- int res = SSL_accept(Ssl.Get());
+ if (!Ssl) {
+ InitServerSsl(endpoint.SecureContext.Get());
+ }
+ int res = SSL_accept(Ssl.Get());
if (res <= 0) {
- res = SSL_get_error(Ssl.Get(), res);
- switch(res) {
- case SSL_ERROR_WANT_READ:
+ res = SSL_get_error(Ssl.Get(), res);
+ switch(res) {
+ case SSL_ERROR_WANT_READ:
read = true;
return -EAGAIN;
- case SSL_ERROR_WANT_WRITE:
+ case SSL_ERROR_WANT_WRITE:
write = true;
- return -EAGAIN;
- default:
- return -EIO;
- }
- }
- return res;
- }
-};
-
-}
+ return -EAGAIN;
+ default:
+ return -EIO;
+ }
+ }
+ return res;
+ }
+};
+
+}
diff --git a/library/cpp/actors/http/http_proxy_ssl.h b/library/cpp/actors/http/http_proxy_ssl.h
index ffce12997f..12fb372b3c 100644
--- a/library/cpp/actors/http/http_proxy_ssl.h
+++ b/library/cpp/actors/http/http_proxy_ssl.h
@@ -1,22 +1,22 @@
-#pragma once
-
-#include <openssl/bio.h>
-#include <openssl/ssl.h>
-#include <openssl/err.h>
-#include <openssl/tls1.h>
-
-namespace NHttp {
-
-struct TSslHelpers {
- struct TSslDestroy {
- static void Destroy(SSL_CTX* ctx) noexcept {
- SSL_CTX_free(ctx);
- }
-
- static void Destroy(SSL* ssl) noexcept {
- SSL_free(ssl);
- }
-
+#pragma once
+
+#include <openssl/bio.h>
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+#include <openssl/tls1.h>
+
+namespace NHttp {
+
+struct TSslHelpers {
+ struct TSslDestroy {
+ static void Destroy(SSL_CTX* ctx) noexcept {
+ SSL_CTX_free(ctx);
+ }
+
+ static void Destroy(SSL* ssl) noexcept {
+ SSL_free(ssl);
+ }
+
static void Destroy(X509* cert) noexcept {
X509_free(cert);
}
@@ -25,48 +25,48 @@ struct TSslHelpers {
EVP_PKEY_free(pkey);
}
- static void Destroy(BIO* bio) noexcept {
- BIO_free(bio);
- }
- };
-
- template <typename T>
- using TSslHolder = THolder<T, TSslDestroy>;
-
- static TSslHolder<SSL_CTX> CreateSslCtx(const SSL_METHOD* method) {
- TSslHolder<SSL_CTX> ctx(SSL_CTX_new(method));
-
- if (ctx) {
- SSL_CTX_set_options(ctx.Get(), SSL_OP_NO_SSLv2);
- SSL_CTX_set_options(ctx.Get(), SSL_OP_NO_SSLv3);
- SSL_CTX_set_options(ctx.Get(), SSL_OP_MICROSOFT_SESS_ID_BUG);
- SSL_CTX_set_options(ctx.Get(), SSL_OP_NETSCAPE_CHALLENGE_BUG);
- }
-
- return ctx;
- }
-
- static TSslHolder<SSL_CTX> CreateClientContext() {
- return CreateSslCtx(SSLv23_client_method());
- }
-
- static TSslHolder<SSL_CTX> CreateServerContext(const TString& certificate, const TString& key) {
- TSslHolder<SSL_CTX> ctx = CreateSslCtx(SSLv23_server_method());
- SSL_CTX_set_ecdh_auto(ctx.Get(), 1);
- int res;
- res = SSL_CTX_use_certificate_chain_file(ctx.Get(), certificate.c_str());
- if (res < 0) {
- // TODO(xenoxeno): more diagnostics?
- return nullptr;
- }
- res = SSL_CTX_use_PrivateKey_file(ctx.Get(), key.c_str(), SSL_FILETYPE_PEM);
- if (res < 0) {
- // TODO(xenoxeno): more diagnostics?
- return nullptr;
- }
- return ctx;
- }
-
+ static void Destroy(BIO* bio) noexcept {
+ BIO_free(bio);
+ }
+ };
+
+ template <typename T>
+ using TSslHolder = THolder<T, TSslDestroy>;
+
+ static TSslHolder<SSL_CTX> CreateSslCtx(const SSL_METHOD* method) {
+ TSslHolder<SSL_CTX> ctx(SSL_CTX_new(method));
+
+ if (ctx) {
+ SSL_CTX_set_options(ctx.Get(), SSL_OP_NO_SSLv2);
+ SSL_CTX_set_options(ctx.Get(), SSL_OP_NO_SSLv3);
+ SSL_CTX_set_options(ctx.Get(), SSL_OP_MICROSOFT_SESS_ID_BUG);
+ SSL_CTX_set_options(ctx.Get(), SSL_OP_NETSCAPE_CHALLENGE_BUG);
+ }
+
+ return ctx;
+ }
+
+ static TSslHolder<SSL_CTX> CreateClientContext() {
+ return CreateSslCtx(SSLv23_client_method());
+ }
+
+ static TSslHolder<SSL_CTX> CreateServerContext(const TString& certificate, const TString& key) {
+ TSslHolder<SSL_CTX> ctx = CreateSslCtx(SSLv23_server_method());
+ SSL_CTX_set_ecdh_auto(ctx.Get(), 1);
+ int res;
+ res = SSL_CTX_use_certificate_chain_file(ctx.Get(), certificate.c_str());
+ if (res < 0) {
+ // TODO(xenoxeno): more diagnostics?
+ return nullptr;
+ }
+ res = SSL_CTX_use_PrivateKey_file(ctx.Get(), key.c_str(), SSL_FILETYPE_PEM);
+ if (res < 0) {
+ // TODO(xenoxeno): more diagnostics?
+ return nullptr;
+ }
+ return ctx;
+ }
+
static bool LoadX509Chain(TSslHolder<SSL_CTX>& ctx, const TString& pem) {
TSslHolder<BIO> bio(BIO_new_mem_buf(pem.c_str(), pem.size()));
if (bio == nullptr) {
@@ -116,16 +116,16 @@ struct TSslHelpers {
return ctx;
}
- static TSslHolder<SSL> ConstructSsl(SSL_CTX* ctx, BIO* bio) {
- TSslHolder<SSL> ssl(SSL_new(ctx));
-
- if (ssl) {
- BIO_up_ref(bio); // SSL_set_bio consumes only one reference if rbio and wbio are the same
- SSL_set_bio(ssl.Get(), bio, bio);
- }
-
- return ssl;
- }
-};
-
-}
+ static TSslHolder<SSL> ConstructSsl(SSL_CTX* ctx, BIO* bio) {
+ TSslHolder<SSL> ssl(SSL_new(ctx));
+
+ if (ssl) {
+ BIO_up_ref(bio); // SSL_set_bio consumes only one reference if rbio and wbio are the same
+ SSL_set_bio(ssl.Get(), bio, bio);
+ }
+
+ return ssl;
+ }
+};
+
+}
diff --git a/library/cpp/actors/http/http_static.cpp b/library/cpp/actors/http/http_static.cpp
index c075c5f693..452b0a8498 100644
--- a/library/cpp/actors/http/http_static.cpp
+++ b/library/cpp/actors/http/http_static.cpp
@@ -5,91 +5,91 @@
#include <library/cpp/actors/core/scheduler_basic.h>
#include <library/cpp/actors/http/http.h>
#include <library/cpp/resource/resource.h>
-#include <util/folder/path.h>
-#include <util/stream/file.h>
-
-namespace NHttp {
-
-class THttpStaticContentHandler : public NActors::TActor<THttpStaticContentHandler> {
-public:
- using TBase = NActors::TActor<THttpStaticContentHandler>;
- const TFsPath URL;
- const TFsPath FilePath;
- const TFsPath ResourcePath;
- const TFsPath Index;
-
- THttpStaticContentHandler(const TString& url, const TString& filePath, const TString& resourcePath, const TString& index)
- : TBase(&THttpStaticContentHandler::StateWork)
- , URL(url)
- , FilePath(filePath)
- , ResourcePath(resourcePath)
- , Index(index)
- {}
-
- static TInstant GetCompileTime() {
- tm compileTime;
- strptime(__DATE__ " " __TIME__, "%B %d %Y %H:%M:%S", &compileTime);
- return TInstant::Seconds(mktime(&compileTime));
- }
-
- void Handle(NHttp::TEvHttpProxy::TEvHttpIncomingRequest::TPtr event, const NActors::TActorContext& ctx) {
- THttpOutgoingResponsePtr response;
- if (event->Get()->Request->Method != "GET") {
- response = event->Get()->Request->CreateResponseBadRequest("Wrong request");
- ctx.Send(event->Sender, new NHttp::TEvHttpProxy::TEvHttpOutgoingResponse(response));
- return;
- }
- TFsPath url(event->Get()->Request->URL.Before('?'));
- if (!url.IsAbsolute()) {
- response = event->Get()->Request->CreateResponseBadRequest("Completely wrong URL");
- ctx.Send(event->Sender, new NHttp::TEvHttpProxy::TEvHttpOutgoingResponse(response));
- return;
- }
- if (url.GetPath().EndsWith('/') && Index.IsDefined()) {
- url /= Index;
- }
- url = url.RelativeTo(URL);
- try {
- // TODO: caching?
- TString contentType = mimetypeByExt(url.GetExtension().c_str());
- TString data;
- TFileStat filestat;
- TFsPath resourcename(ResourcePath / url);
- if (NResource::FindExact(resourcename.GetPath(), &data)) {
- static TInstant compileTime(GetCompileTime());
- filestat.MTime = compileTime.Seconds();
- } else {
- TFsPath filename(FilePath / url);
- if (!filename.IsSubpathOf(FilePath) && filename != FilePath) {
- response = event->Get()->Request->CreateResponseBadRequest("Wrong URL");
- ctx.Send(event->Sender, new NHttp::TEvHttpProxy::TEvHttpOutgoingResponse(response));
- return;
- }
- if (filename.Stat(filestat) && filestat.IsFile()) {
- data = TUnbufferedFileInput(filename).ReadAll();
- }
- }
- if (!filestat.IsNull()) {
- response = event->Get()->Request->CreateResponseOK(data, contentType, TInstant::Seconds(filestat.MTime));
- } else {
- response = event->Get()->Request->CreateResponseNotFound("File not found");
- }
- }
- catch (const yexception&) {
- response = event->Get()->Request->CreateResponseServiceUnavailable("Not available");
- }
- ctx.Send(event->Sender, new NHttp::TEvHttpProxy::TEvHttpOutgoingResponse(response));
- }
-
- STFUNC(StateWork) {
- switch (ev->GetTypeRewrite()) {
- HFunc(NHttp::TEvHttpProxy::TEvHttpIncomingRequest, Handle);
- }
- }
-};
-
-NActors::IActor* CreateHttpStaticContentHandler(const TString& url, const TString& filePath, const TString& resourcePath, const TString& index) {
- return new THttpStaticContentHandler(url, filePath, resourcePath, index);
-}
-
-}
+#include <util/folder/path.h>
+#include <util/stream/file.h>
+
+namespace NHttp {
+
+class THttpStaticContentHandler : public NActors::TActor<THttpStaticContentHandler> {
+public:
+ using TBase = NActors::TActor<THttpStaticContentHandler>;
+ const TFsPath URL;
+ const TFsPath FilePath;
+ const TFsPath ResourcePath;
+ const TFsPath Index;
+
+ THttpStaticContentHandler(const TString& url, const TString& filePath, const TString& resourcePath, const TString& index)
+ : TBase(&THttpStaticContentHandler::StateWork)
+ , URL(url)
+ , FilePath(filePath)
+ , ResourcePath(resourcePath)
+ , Index(index)
+ {}
+
+ static TInstant GetCompileTime() {
+ tm compileTime;
+ strptime(__DATE__ " " __TIME__, "%B %d %Y %H:%M:%S", &compileTime);
+ return TInstant::Seconds(mktime(&compileTime));
+ }
+
+ void Handle(NHttp::TEvHttpProxy::TEvHttpIncomingRequest::TPtr event, const NActors::TActorContext& ctx) {
+ THttpOutgoingResponsePtr response;
+ if (event->Get()->Request->Method != "GET") {
+ response = event->Get()->Request->CreateResponseBadRequest("Wrong request");
+ ctx.Send(event->Sender, new NHttp::TEvHttpProxy::TEvHttpOutgoingResponse(response));
+ return;
+ }
+ TFsPath url(event->Get()->Request->URL.Before('?'));
+ if (!url.IsAbsolute()) {
+ response = event->Get()->Request->CreateResponseBadRequest("Completely wrong URL");
+ ctx.Send(event->Sender, new NHttp::TEvHttpProxy::TEvHttpOutgoingResponse(response));
+ return;
+ }
+ if (url.GetPath().EndsWith('/') && Index.IsDefined()) {
+ url /= Index;
+ }
+ url = url.RelativeTo(URL);
+ try {
+ // TODO: caching?
+ TString contentType = mimetypeByExt(url.GetExtension().c_str());
+ TString data;
+ TFileStat filestat;
+ TFsPath resourcename(ResourcePath / url);
+ if (NResource::FindExact(resourcename.GetPath(), &data)) {
+ static TInstant compileTime(GetCompileTime());
+ filestat.MTime = compileTime.Seconds();
+ } else {
+ TFsPath filename(FilePath / url);
+ if (!filename.IsSubpathOf(FilePath) && filename != FilePath) {
+ response = event->Get()->Request->CreateResponseBadRequest("Wrong URL");
+ ctx.Send(event->Sender, new NHttp::TEvHttpProxy::TEvHttpOutgoingResponse(response));
+ return;
+ }
+ if (filename.Stat(filestat) && filestat.IsFile()) {
+ data = TUnbufferedFileInput(filename).ReadAll();
+ }
+ }
+ if (!filestat.IsNull()) {
+ response = event->Get()->Request->CreateResponseOK(data, contentType, TInstant::Seconds(filestat.MTime));
+ } else {
+ response = event->Get()->Request->CreateResponseNotFound("File not found");
+ }
+ }
+ catch (const yexception&) {
+ response = event->Get()->Request->CreateResponseServiceUnavailable("Not available");
+ }
+ ctx.Send(event->Sender, new NHttp::TEvHttpProxy::TEvHttpOutgoingResponse(response));
+ }
+
+ STFUNC(StateWork) {
+ switch (ev->GetTypeRewrite()) {
+ HFunc(NHttp::TEvHttpProxy::TEvHttpIncomingRequest, Handle);
+ }
+ }
+};
+
+NActors::IActor* CreateHttpStaticContentHandler(const TString& url, const TString& filePath, const TString& resourcePath, const TString& index) {
+ return new THttpStaticContentHandler(url, filePath, resourcePath, index);
+}
+
+}
diff --git a/library/cpp/actors/http/http_static.h b/library/cpp/actors/http/http_static.h
index f91e15dfb1..f2ee13d003 100644
--- a/library/cpp/actors/http/http_static.h
+++ b/library/cpp/actors/http/http_static.h
@@ -1,9 +1,9 @@
-#pragma once
+#pragma once
#include <library/cpp/actors/core/actor.h>
-#include "http.h"
-
-namespace NHttp {
-
-NActors::IActor* CreateHttpStaticContentHandler(const TString& url, const TString& filePath, const TString& resourcePath, const TString& index = TString());
-
-}
+#include "http.h"
+
+namespace NHttp {
+
+NActors::IActor* CreateHttpStaticContentHandler(const TString& url, const TString& filePath, const TString& resourcePath, const TString& index = TString());
+
+}
diff --git a/library/cpp/actors/http/http_ut.cpp b/library/cpp/actors/http/http_ut.cpp
index 4c922f8d0f..209f61f4de 100644
--- a/library/cpp/actors/http/http_ut.cpp
+++ b/library/cpp/actors/http/http_ut.cpp
@@ -3,86 +3,86 @@
#include <library/cpp/actors/core/executor_pool_basic.h>
#include <library/cpp/actors/core/scheduler_basic.h>
#include <library/cpp/actors/testlib/test_runtime.h>
-#include <util/system/tempfile.h>
-#include "http.h"
-#include "http_proxy.h"
-
-
-
-enum EService : NActors::NLog::EComponent {
- MIN,
- Logger,
- MVP,
- MAX
-};
-
-namespace {
-
-template <typename HttpType>
-void EatWholeString(TIntrusivePtr<HttpType>& request, const TString& data) {
- request->EnsureEnoughSpaceAvailable(data.size());
- auto size = std::min(request->Avail(), data.size());
- memcpy(request->Pos(), data.data(), size);
- request->Advance(size);
-}
-
-template <typename HttpType>
-void EatPartialString(TIntrusivePtr<HttpType>& request, const TString& data) {
- for (char c : data) {
- request->EnsureEnoughSpaceAvailable(1);
- memcpy(request->Pos(), &c, 1);
- request->Advance(1);
- }
-}
-
-}
-
+#include <util/system/tempfile.h>
+#include "http.h"
+#include "http_proxy.h"
+
+
+
+enum EService : NActors::NLog::EComponent {
+ MIN,
+ Logger,
+ MVP,
+ MAX
+};
+
+namespace {
+
+template <typename HttpType>
+void EatWholeString(TIntrusivePtr<HttpType>& request, const TString& data) {
+ request->EnsureEnoughSpaceAvailable(data.size());
+ auto size = std::min(request->Avail(), data.size());
+ memcpy(request->Pos(), data.data(), size);
+ request->Advance(size);
+}
+
+template <typename HttpType>
+void EatPartialString(TIntrusivePtr<HttpType>& request, const TString& data) {
+ for (char c : data) {
+ request->EnsureEnoughSpaceAvailable(1);
+ memcpy(request->Pos(), &c, 1);
+ request->Advance(1);
+ }
+}
+
+}
+
Y_UNIT_TEST_SUITE(HttpProxy) {
Y_UNIT_TEST(BasicParsing) {
- NHttp::THttpIncomingRequestPtr request = new NHttp::THttpIncomingRequest();
- EatWholeString(request, "GET /test HTTP/1.1\r\nHost: test\r\nSome-Header: 32344\r\n\r\n");
- UNIT_ASSERT_EQUAL(request->Stage, NHttp::THttpIncomingRequest::EParseStage::Done);
- UNIT_ASSERT_EQUAL(request->Method, "GET");
- UNIT_ASSERT_EQUAL(request->URL, "/test");
- UNIT_ASSERT_EQUAL(request->Protocol, "HTTP");
- UNIT_ASSERT_EQUAL(request->Version, "1.1");
- UNIT_ASSERT_EQUAL(request->Host, "test");
- UNIT_ASSERT_EQUAL(request->Headers, "Host: test\r\nSome-Header: 32344\r\n\r\n");
- }
-
+ NHttp::THttpIncomingRequestPtr request = new NHttp::THttpIncomingRequest();
+ EatWholeString(request, "GET /test HTTP/1.1\r\nHost: test\r\nSome-Header: 32344\r\n\r\n");
+ UNIT_ASSERT_EQUAL(request->Stage, NHttp::THttpIncomingRequest::EParseStage::Done);
+ UNIT_ASSERT_EQUAL(request->Method, "GET");
+ UNIT_ASSERT_EQUAL(request->URL, "/test");
+ UNIT_ASSERT_EQUAL(request->Protocol, "HTTP");
+ UNIT_ASSERT_EQUAL(request->Version, "1.1");
+ UNIT_ASSERT_EQUAL(request->Host, "test");
+ UNIT_ASSERT_EQUAL(request->Headers, "Host: test\r\nSome-Header: 32344\r\n\r\n");
+ }
+
Y_UNIT_TEST(BasicParsingChunkedBody) {
- NHttp::THttpOutgoingRequestPtr request = nullptr; //new NHttp::THttpOutgoingRequest();
- NHttp::THttpIncomingResponsePtr response = new NHttp::THttpIncomingResponse(request);
- EatWholeString(response, "HTTP/1.1 200 OK\r\nConnection: close\r\nTransfer-Encoding: chunked\r\n\r\n4\r\nthis\r\n4\r\n is \r\n5\r\ntest.\r\n0\r\n\r\n");
- UNIT_ASSERT_EQUAL(response->Stage, NHttp::THttpIncomingResponse::EParseStage::Done);
- UNIT_ASSERT_EQUAL(response->Status, "200");
- UNIT_ASSERT_EQUAL(response->Connection, "close");
- UNIT_ASSERT_EQUAL(response->Protocol, "HTTP");
- UNIT_ASSERT_EQUAL(response->Version, "1.1");
- UNIT_ASSERT_EQUAL(response->TransferEncoding, "chunked");
- UNIT_ASSERT_EQUAL(response->Body, "this is test.");
- }
-
- Y_UNIT_TEST(InvalidParsingChunkedBody) {
- NHttp::THttpOutgoingRequestPtr request = nullptr; //new NHttp::THttpOutgoingRequest();
- NHttp::THttpIncomingResponsePtr response = new NHttp::THttpIncomingResponse(request);
- EatWholeString(response, "HTTP/1.1 200 OK\r\nConnection: close\r\nTransfer-Encoding: chunked\r\n\r\n5\r\nthis\r\n4\r\n is \r\n5\r\ntest.\r\n0\r\n\r\n");
- UNIT_ASSERT(response->IsError());
- }
-
- Y_UNIT_TEST(AdvancedParsingChunkedBody) {
- NHttp::THttpOutgoingRequestPtr request = nullptr; //new NHttp::THttpOutgoingRequest();
- NHttp::THttpIncomingResponsePtr response = new NHttp::THttpIncomingResponse(request);
- EatWholeString(response, "HTTP/1.1 200 OK\r\nConnection: close\r\nTransfer-Encoding: chunked\r\n\r\n6\r\nthis\r\n\r\n4\r\n is \r\n5\r\ntest.\r\n0\r\n\r\n");
- UNIT_ASSERT_EQUAL(response->Stage, NHttp::THttpIncomingResponse::EParseStage::Done);
- UNIT_ASSERT_EQUAL(response->Status, "200");
- UNIT_ASSERT_EQUAL(response->Connection, "close");
- UNIT_ASSERT_EQUAL(response->Protocol, "HTTP");
- UNIT_ASSERT_EQUAL(response->Version, "1.1");
- UNIT_ASSERT_EQUAL(response->TransferEncoding, "chunked");
- UNIT_ASSERT_EQUAL(response->Body, "this\r\n is test.");
- }
-
+ NHttp::THttpOutgoingRequestPtr request = nullptr; //new NHttp::THttpOutgoingRequest();
+ NHttp::THttpIncomingResponsePtr response = new NHttp::THttpIncomingResponse(request);
+ EatWholeString(response, "HTTP/1.1 200 OK\r\nConnection: close\r\nTransfer-Encoding: chunked\r\n\r\n4\r\nthis\r\n4\r\n is \r\n5\r\ntest.\r\n0\r\n\r\n");
+ UNIT_ASSERT_EQUAL(response->Stage, NHttp::THttpIncomingResponse::EParseStage::Done);
+ UNIT_ASSERT_EQUAL(response->Status, "200");
+ UNIT_ASSERT_EQUAL(response->Connection, "close");
+ UNIT_ASSERT_EQUAL(response->Protocol, "HTTP");
+ UNIT_ASSERT_EQUAL(response->Version, "1.1");
+ UNIT_ASSERT_EQUAL(response->TransferEncoding, "chunked");
+ UNIT_ASSERT_EQUAL(response->Body, "this is test.");
+ }
+
+ Y_UNIT_TEST(InvalidParsingChunkedBody) {
+ NHttp::THttpOutgoingRequestPtr request = nullptr; //new NHttp::THttpOutgoingRequest();
+ NHttp::THttpIncomingResponsePtr response = new NHttp::THttpIncomingResponse(request);
+ EatWholeString(response, "HTTP/1.1 200 OK\r\nConnection: close\r\nTransfer-Encoding: chunked\r\n\r\n5\r\nthis\r\n4\r\n is \r\n5\r\ntest.\r\n0\r\n\r\n");
+ UNIT_ASSERT(response->IsError());
+ }
+
+ Y_UNIT_TEST(AdvancedParsingChunkedBody) {
+ NHttp::THttpOutgoingRequestPtr request = nullptr; //new NHttp::THttpOutgoingRequest();
+ NHttp::THttpIncomingResponsePtr response = new NHttp::THttpIncomingResponse(request);
+ EatWholeString(response, "HTTP/1.1 200 OK\r\nConnection: close\r\nTransfer-Encoding: chunked\r\n\r\n6\r\nthis\r\n\r\n4\r\n is \r\n5\r\ntest.\r\n0\r\n\r\n");
+ UNIT_ASSERT_EQUAL(response->Stage, NHttp::THttpIncomingResponse::EParseStage::Done);
+ UNIT_ASSERT_EQUAL(response->Status, "200");
+ UNIT_ASSERT_EQUAL(response->Connection, "close");
+ UNIT_ASSERT_EQUAL(response->Protocol, "HTTP");
+ UNIT_ASSERT_EQUAL(response->Version, "1.1");
+ UNIT_ASSERT_EQUAL(response->TransferEncoding, "chunked");
+ UNIT_ASSERT_EQUAL(response->Body, "this\r\n is test.");
+ }
+
Y_UNIT_TEST(CreateRepsonseWithCompressedBody) {
NHttp::THttpIncomingRequestPtr request = nullptr;
NHttp::THttpOutgoingResponsePtr response = new NHttp::THttpOutgoingResponse(request, "HTTP", "1.1", "200", "OK");
@@ -95,264 +95,264 @@ Y_UNIT_TEST_SUITE(HttpProxy) {
}
Y_UNIT_TEST(BasicPartialParsing) {
- NHttp::THttpIncomingRequestPtr request = new NHttp::THttpIncomingRequest();
- EatPartialString(request, "GET /test HTTP/1.1\r\nHost: test\r\nSome-Header: 32344\r\n\r\n");
- UNIT_ASSERT_EQUAL(request->Stage, NHttp::THttpIncomingRequest::EParseStage::Done);
- UNIT_ASSERT_EQUAL(request->Method, "GET");
- UNIT_ASSERT_EQUAL(request->URL, "/test");
- UNIT_ASSERT_EQUAL(request->Protocol, "HTTP");
- UNIT_ASSERT_EQUAL(request->Version, "1.1");
- UNIT_ASSERT_EQUAL(request->Host, "test");
- UNIT_ASSERT_EQUAL(request->Headers, "Host: test\r\nSome-Header: 32344\r\n\r\n");
- }
-
+ NHttp::THttpIncomingRequestPtr request = new NHttp::THttpIncomingRequest();
+ EatPartialString(request, "GET /test HTTP/1.1\r\nHost: test\r\nSome-Header: 32344\r\n\r\n");
+ UNIT_ASSERT_EQUAL(request->Stage, NHttp::THttpIncomingRequest::EParseStage::Done);
+ UNIT_ASSERT_EQUAL(request->Method, "GET");
+ UNIT_ASSERT_EQUAL(request->URL, "/test");
+ UNIT_ASSERT_EQUAL(request->Protocol, "HTTP");
+ UNIT_ASSERT_EQUAL(request->Version, "1.1");
+ UNIT_ASSERT_EQUAL(request->Host, "test");
+ UNIT_ASSERT_EQUAL(request->Headers, "Host: test\r\nSome-Header: 32344\r\n\r\n");
+ }
+
Y_UNIT_TEST(BasicPartialParsingChunkedBody) {
- NHttp::THttpOutgoingRequestPtr request = nullptr; //new NHttp::THttpOutgoingRequest();
- NHttp::THttpIncomingResponsePtr response = new NHttp::THttpIncomingResponse(request);
- EatPartialString(response, "HTTP/1.1 200 OK\r\nConnection: close\r\nTransfer-Encoding: chunked\r\n\r\n4\r\nthis\r\n4\r\n is \r\n5\r\ntest.\r\n0\r\n\r\n");
- UNIT_ASSERT_EQUAL(response->Stage, NHttp::THttpIncomingResponse::EParseStage::Done);
- UNIT_ASSERT_EQUAL(response->Status, "200");
- UNIT_ASSERT_EQUAL(response->Connection, "close");
- UNIT_ASSERT_EQUAL(response->Protocol, "HTTP");
- UNIT_ASSERT_EQUAL(response->Version, "1.1");
- UNIT_ASSERT_EQUAL(response->TransferEncoding, "chunked");
- UNIT_ASSERT_EQUAL(response->Body, "this is test.");
- }
-
+ NHttp::THttpOutgoingRequestPtr request = nullptr; //new NHttp::THttpOutgoingRequest();
+ NHttp::THttpIncomingResponsePtr response = new NHttp::THttpIncomingResponse(request);
+ EatPartialString(response, "HTTP/1.1 200 OK\r\nConnection: close\r\nTransfer-Encoding: chunked\r\n\r\n4\r\nthis\r\n4\r\n is \r\n5\r\ntest.\r\n0\r\n\r\n");
+ UNIT_ASSERT_EQUAL(response->Stage, NHttp::THttpIncomingResponse::EParseStage::Done);
+ UNIT_ASSERT_EQUAL(response->Status, "200");
+ UNIT_ASSERT_EQUAL(response->Connection, "close");
+ UNIT_ASSERT_EQUAL(response->Protocol, "HTTP");
+ UNIT_ASSERT_EQUAL(response->Version, "1.1");
+ UNIT_ASSERT_EQUAL(response->TransferEncoding, "chunked");
+ UNIT_ASSERT_EQUAL(response->Body, "this is test.");
+ }
+
Y_UNIT_TEST(AdvancedParsing) {
- NHttp::THttpIncomingRequestPtr request = new NHttp::THttpIncomingRequest();
- EatWholeString(request, "GE");
- EatWholeString(request, "T");
- EatWholeString(request, " ");
- EatWholeString(request, "/test");
- EatWholeString(request, " HTTP/1.1\r");
- EatWholeString(request, "\nHo");
- EatWholeString(request, "st: test");
- EatWholeString(request, "\r\n");
- EatWholeString(request, "Some-Header: 32344\r\n\r");
- EatWholeString(request, "\n");
- UNIT_ASSERT_EQUAL(request->Stage, NHttp::THttpIncomingRequest::EParseStage::Done);
- UNIT_ASSERT_EQUAL(request->Method, "GET");
- UNIT_ASSERT_EQUAL(request->URL, "/test");
- UNIT_ASSERT_EQUAL(request->Protocol, "HTTP");
- UNIT_ASSERT_EQUAL(request->Version, "1.1");
- UNIT_ASSERT_EQUAL(request->Host, "test");
- UNIT_ASSERT_EQUAL(request->Headers, "Host: test\r\nSome-Header: 32344\r\n\r\n");
- }
-
+ NHttp::THttpIncomingRequestPtr request = new NHttp::THttpIncomingRequest();
+ EatWholeString(request, "GE");
+ EatWholeString(request, "T");
+ EatWholeString(request, " ");
+ EatWholeString(request, "/test");
+ EatWholeString(request, " HTTP/1.1\r");
+ EatWholeString(request, "\nHo");
+ EatWholeString(request, "st: test");
+ EatWholeString(request, "\r\n");
+ EatWholeString(request, "Some-Header: 32344\r\n\r");
+ EatWholeString(request, "\n");
+ UNIT_ASSERT_EQUAL(request->Stage, NHttp::THttpIncomingRequest::EParseStage::Done);
+ UNIT_ASSERT_EQUAL(request->Method, "GET");
+ UNIT_ASSERT_EQUAL(request->URL, "/test");
+ UNIT_ASSERT_EQUAL(request->Protocol, "HTTP");
+ UNIT_ASSERT_EQUAL(request->Version, "1.1");
+ UNIT_ASSERT_EQUAL(request->Host, "test");
+ UNIT_ASSERT_EQUAL(request->Headers, "Host: test\r\nSome-Header: 32344\r\n\r\n");
+ }
+
Y_UNIT_TEST(AdvancedPartialParsing) {
- NHttp::THttpIncomingRequestPtr request = new NHttp::THttpIncomingRequest();
- EatPartialString(request, "GE");
- EatPartialString(request, "T");
- EatPartialString(request, " ");
- EatPartialString(request, "/test");
- EatPartialString(request, " HTTP/1.1\r");
- EatPartialString(request, "\nHo");
- EatPartialString(request, "st: test");
- EatPartialString(request, "\r\n");
- EatPartialString(request, "Some-Header: 32344\r\n\r");
- EatPartialString(request, "\n");
- UNIT_ASSERT_EQUAL(request->Stage, NHttp::THttpIncomingRequest::EParseStage::Done);
- UNIT_ASSERT_EQUAL(request->Method, "GET");
- UNIT_ASSERT_EQUAL(request->URL, "/test");
- UNIT_ASSERT_EQUAL(request->Protocol, "HTTP");
- UNIT_ASSERT_EQUAL(request->Version, "1.1");
- UNIT_ASSERT_EQUAL(request->Host, "test");
- UNIT_ASSERT_EQUAL(request->Headers, "Host: test\r\nSome-Header: 32344\r\n\r\n");
- }
-
- Y_UNIT_TEST(BasicRenderBodyWithHeadersAndCookies) {
- NHttp::THttpOutgoingRequestPtr request = NHttp::THttpOutgoingRequest::CreateRequestGet("http://www.yandex.ru/data/url");
- NHttp::THeadersBuilder headers;
- NHttp::TCookiesBuilder cookies;
- cookies.Set("cookie1", "123456");
- cookies.Set("cookie2", "45678");
- headers.Set("Cookie", cookies.Render());
- request->Set(headers);
- TString requestData;
- request->AsString(requestData);
- 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");
- }
-
+ NHttp::THttpIncomingRequestPtr request = new NHttp::THttpIncomingRequest();
+ EatPartialString(request, "GE");
+ EatPartialString(request, "T");
+ EatPartialString(request, " ");
+ EatPartialString(request, "/test");
+ EatPartialString(request, " HTTP/1.1\r");
+ EatPartialString(request, "\nHo");
+ EatPartialString(request, "st: test");
+ EatPartialString(request, "\r\n");
+ EatPartialString(request, "Some-Header: 32344\r\n\r");
+ EatPartialString(request, "\n");
+ UNIT_ASSERT_EQUAL(request->Stage, NHttp::THttpIncomingRequest::EParseStage::Done);
+ UNIT_ASSERT_EQUAL(request->Method, "GET");
+ UNIT_ASSERT_EQUAL(request->URL, "/test");
+ UNIT_ASSERT_EQUAL(request->Protocol, "HTTP");
+ UNIT_ASSERT_EQUAL(request->Version, "1.1");
+ UNIT_ASSERT_EQUAL(request->Host, "test");
+ UNIT_ASSERT_EQUAL(request->Headers, "Host: test\r\nSome-Header: 32344\r\n\r\n");
+ }
+
+ Y_UNIT_TEST(BasicRenderBodyWithHeadersAndCookies) {
+ NHttp::THttpOutgoingRequestPtr request = NHttp::THttpOutgoingRequest::CreateRequestGet("http://www.yandex.ru/data/url");
+ NHttp::THeadersBuilder headers;
+ NHttp::TCookiesBuilder cookies;
+ cookies.Set("cookie1", "123456");
+ cookies.Set("cookie2", "45678");
+ headers.Set("Cookie", cookies.Render());
+ request->Set(headers);
+ TString requestData;
+ request->AsString(requestData);
+ 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) {
NActors::TTestActorRuntimeBase actorSystem;
- TPortManager portManager;
- TIpPort port = portManager.GetTcpPort();
- TAutoPtr<NActors::IEventHandle> handle;
+ TPortManager portManager;
+ TIpPort port = portManager.GetTcpPort();
+ TAutoPtr<NActors::IEventHandle> handle;
actorSystem.Initialize();
NMonitoring::TMetricRegistry sensors;
-
- NActors::IActor* proxy = NHttp::CreateHttpProxy(sensors);
+
+ NActors::IActor* proxy = NHttp::CreateHttpProxy(sensors);
NActors::TActorId proxyId = actorSystem.Register(proxy);
actorSystem.Send(new NActors::IEventHandle(proxyId, TActorId(), new NHttp::TEvHttpProxy::TEvAddListeningPort(port)), 0, true);
- actorSystem.DispatchEvents();
-
+ actorSystem.DispatchEvents();
+
NActors::TActorId serverId = actorSystem.AllocateEdgeActor();
- actorSystem.Send(new NActors::IEventHandle(proxyId, serverId, new NHttp::TEvHttpProxy::TEvRegisterHandler("/test", serverId)), 0, true);
-
+ 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");
- 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(TlsRunning) {
- NActors::TTestActorRuntimeBase actorSystem;
- TPortManager portManager;
- TIpPort port = portManager.GetTcpPort();
- TAutoPtr<NActors::IEventHandle> handle;
- actorSystem.Initialize();
+ NHttp::THttpOutgoingRequestPtr httpRequest = NHttp::THttpOutgoingRequest::CreateRequestGet("http://[::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(TlsRunning) {
+ NActors::TTestActorRuntimeBase actorSystem;
+ TPortManager portManager;
+ TIpPort port = portManager.GetTcpPort();
+ TAutoPtr<NActors::IEventHandle> handle;
+ actorSystem.Initialize();
NMonitoring::TMetricRegistry sensors;
-
- TString certificateContent = R"___(-----BEGIN PRIVATE KEY-----
-MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCzRZjodO7Aqe1w
-RyOj6kG6g2nn8ZGAxfao4mLT0jDTbVksrhV/h2s3uldLkFo5WrNQ8WZe+iIbXeFL
-s8tO6hslzreo9sih2IHoRcH5KnS/6YTqVhRTJb1jE2dM8NwYbwTi+T2Pe0FrBPjI
-kgVO50gAtYl9C+fc715uZiSKW+rRlP5OoFTwxrOjiU27RPZjFYyWK9wTI1Es9uRr
-lbZbLl5cY6dK2J1AViRraaYKCWO26VbOPWLsY4OD3e+ZXIc3OMCz6Yb0wmRPeJ60
-bbbkGfI8O27kDdv69MAWHIm0yYMzKEnom1dce7rNQNDEqJfocsYIsg+EvayT1yQ9
-KTBegw7LAgMBAAECggEBAKaOCrotqYQmXArsjRhFFDwMy+BKdzyEr93INrlFl0dX
-WHpCYobRcbOc1G3H94tB0UdqgAnNqtJyLlb+++ydZAuEOu4oGc8EL+10ofq0jzOd
-6Xct8kQt0/6wkFDTlii9PHUDy0X65ZRgUiNGRtg/2I2QG+SpowmI+trm2xwQueFs
-VaWrjc3cVvXx0b8Lu7hqZUv08kgC38stzuRk/n2T5VWSAr7Z4ZWQbO918Dv35HUw
-Wy/0jNUFP9CBCvFJ4l0OoH9nYhWFG+HXWzNdw6/Hca4jciRKo6esCiOZ9uWYv/ec
-/NvX9rgFg8G8/SrTisX10+Bbeq+R1RKwq/IG409TH4ECgYEA14L+3QsgNIUMeYAx
-jSCyk22R/tOHI1BM+GtKPUhnwHlAssrcPcxXMJovl6WL93VauYjym0wpCz9urSpA
-I2CqTsG8GYciA6Dr3mHgD6cK0jj9UPAU6EnZ5S0mjhPqKZqutu9QegzD2uESvuN8
-36xezwQthzAf0nI/P3sJGjVXjikCgYEA1POm5xcV6SmM6HnIdadEebhzZIJ9TXQz
-ry3Jj3a7CKyD5C7fAdkHUTCjgT/2ElxPi9ABkZnC+d/cW9GtJFa0II5qO/agm3KQ
-ZXYiutu9A7xACHYFXRiJEjVUdGG9dKMVOHUEa8IHEgrrcUVM/suy/GgutywIfaXs
-y58IFP24K9MCgYEAk6zjz7wL+XEiNy+sxLQfKf7vB9sSwxQHakK6wHuY/L8Zomp3
-uLEJHfjJm/SIkK0N2g0JkXkCtv5kbKyC/rsCeK0wo52BpVLjzaLr0k34kE0U6B1b
-dkEE2pGx1bG3x4KDLj+Wuct9ecK5Aa0IqIyI+vo16GkFpUM8K9e3SQo8UOECgYEA
-sCZYAkILYtJ293p9giz5rIISGasDAUXE1vxWBXEeJ3+kneTTnZCrx9Im/ewtnWR0
-fF90XL9HFDDD88POqAd8eo2zfKR2l/89SGBfPBg2EtfuU9FkgGyiPciVcqvC7q9U
-B15saMKX3KnhtdGwbfeLt9RqCCTJZT4SUSDcq5hwdvcCgYAxY4Be8mNipj8Cgg22
-mVWSolA0TEzbtUcNk6iGodpi+Z0LKpsPC0YRqPRyh1K+rIltG1BVdmUBHcMlOYxl
-lWWvbJH6PkJWy4n2MF7PO45kjN3pPZg4hgH63JjZeAineBwEArUGb9zHnvzcdRvF
-wuQ2pZHL/HJ0laUSieHDJ5917w==
------END PRIVATE KEY-----
-
-
------BEGIN CERTIFICATE-----
-MIIDjTCCAnWgAwIBAgIURt5IBx0J3xgEaQvmyrFH2A+NkpMwDQYJKoZIhvcNAQEL
-BQAwVjELMAkGA1UEBhMCUlUxDzANBgNVBAgMBk1vc2NvdzEPMA0GA1UEBwwGTW9z
-Y293MQ8wDQYDVQQKDAZZYW5kZXgxFDASBgNVBAMMC3Rlc3Qtc2VydmVyMB4XDTE5
-MDkyMDE3MTQ0MVoXDTQ3MDIwNDE3MTQ0MVowVjELMAkGA1UEBhMCUlUxDzANBgNV
-BAgMBk1vc2NvdzEPMA0GA1UEBwwGTW9zY293MQ8wDQYDVQQKDAZZYW5kZXgxFDAS
-BgNVBAMMC3Rlc3Qtc2VydmVyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
-AQEAs0WY6HTuwKntcEcjo+pBuoNp5/GRgMX2qOJi09Iw021ZLK4Vf4drN7pXS5Ba
-OVqzUPFmXvoiG13hS7PLTuobJc63qPbIodiB6EXB+Sp0v+mE6lYUUyW9YxNnTPDc
-GG8E4vk9j3tBawT4yJIFTudIALWJfQvn3O9ebmYkilvq0ZT+TqBU8Mazo4lNu0T2
-YxWMlivcEyNRLPbka5W2Wy5eXGOnStidQFYka2mmCgljtulWzj1i7GODg93vmVyH
-NzjAs+mG9MJkT3ietG225BnyPDtu5A3b+vTAFhyJtMmDMyhJ6JtXXHu6zUDQxKiX
-6HLGCLIPhL2sk9ckPSkwXoMOywIDAQABo1MwUTAdBgNVHQ4EFgQUDv/xuJ4CvCgG
-fPrZP3hRAt2+/LwwHwYDVR0jBBgwFoAUDv/xuJ4CvCgGfPrZP3hRAt2+/LwwDwYD
-VR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAinKpMYaA2tjLpAnPVbjy
-/ZxSBhhB26RiQp3Re8XOKyhTWqgYE6kldYT0aXgK9x9mPC5obQannDDYxDc7lX+/
-qP/u1X81ZcDRo/f+qQ3iHfT6Ftt/4O3qLnt45MFM6Q7WabRm82x3KjZTqpF3QUdy
-tumWiuAP5DMd1IRDtnKjFHO721OsEsf6NLcqdX89bGeqXDvrkwg3/PNwTyW5E7cj
-feY8L2eWtg6AJUnIBu11wvfzkLiH3QKzHvO/SIZTGf5ihDsJ3aKEE9UNauTL3bVc
-CRA/5XcX13GJwHHj6LCoc3sL7mt8qV9HKY2AOZ88mpObzISZxgPpdKCfjsrdm63V
-6g==
------END CERTIFICATE-----)___";
-
- TTempFileHandle certificateFile;
-
- certificateFile.Write(certificateContent.data(), certificateContent.size());
-
- NActors::IActor* proxy = NHttp::CreateHttpProxy(sensors);
+
+ TString certificateContent = R"___(-----BEGIN PRIVATE KEY-----
+MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCzRZjodO7Aqe1w
+RyOj6kG6g2nn8ZGAxfao4mLT0jDTbVksrhV/h2s3uldLkFo5WrNQ8WZe+iIbXeFL
+s8tO6hslzreo9sih2IHoRcH5KnS/6YTqVhRTJb1jE2dM8NwYbwTi+T2Pe0FrBPjI
+kgVO50gAtYl9C+fc715uZiSKW+rRlP5OoFTwxrOjiU27RPZjFYyWK9wTI1Es9uRr
+lbZbLl5cY6dK2J1AViRraaYKCWO26VbOPWLsY4OD3e+ZXIc3OMCz6Yb0wmRPeJ60
+bbbkGfI8O27kDdv69MAWHIm0yYMzKEnom1dce7rNQNDEqJfocsYIsg+EvayT1yQ9
+KTBegw7LAgMBAAECggEBAKaOCrotqYQmXArsjRhFFDwMy+BKdzyEr93INrlFl0dX
+WHpCYobRcbOc1G3H94tB0UdqgAnNqtJyLlb+++ydZAuEOu4oGc8EL+10ofq0jzOd
+6Xct8kQt0/6wkFDTlii9PHUDy0X65ZRgUiNGRtg/2I2QG+SpowmI+trm2xwQueFs
+VaWrjc3cVvXx0b8Lu7hqZUv08kgC38stzuRk/n2T5VWSAr7Z4ZWQbO918Dv35HUw
+Wy/0jNUFP9CBCvFJ4l0OoH9nYhWFG+HXWzNdw6/Hca4jciRKo6esCiOZ9uWYv/ec
+/NvX9rgFg8G8/SrTisX10+Bbeq+R1RKwq/IG409TH4ECgYEA14L+3QsgNIUMeYAx
+jSCyk22R/tOHI1BM+GtKPUhnwHlAssrcPcxXMJovl6WL93VauYjym0wpCz9urSpA
+I2CqTsG8GYciA6Dr3mHgD6cK0jj9UPAU6EnZ5S0mjhPqKZqutu9QegzD2uESvuN8
+36xezwQthzAf0nI/P3sJGjVXjikCgYEA1POm5xcV6SmM6HnIdadEebhzZIJ9TXQz
+ry3Jj3a7CKyD5C7fAdkHUTCjgT/2ElxPi9ABkZnC+d/cW9GtJFa0II5qO/agm3KQ
+ZXYiutu9A7xACHYFXRiJEjVUdGG9dKMVOHUEa8IHEgrrcUVM/suy/GgutywIfaXs
+y58IFP24K9MCgYEAk6zjz7wL+XEiNy+sxLQfKf7vB9sSwxQHakK6wHuY/L8Zomp3
+uLEJHfjJm/SIkK0N2g0JkXkCtv5kbKyC/rsCeK0wo52BpVLjzaLr0k34kE0U6B1b
+dkEE2pGx1bG3x4KDLj+Wuct9ecK5Aa0IqIyI+vo16GkFpUM8K9e3SQo8UOECgYEA
+sCZYAkILYtJ293p9giz5rIISGasDAUXE1vxWBXEeJ3+kneTTnZCrx9Im/ewtnWR0
+fF90XL9HFDDD88POqAd8eo2zfKR2l/89SGBfPBg2EtfuU9FkgGyiPciVcqvC7q9U
+B15saMKX3KnhtdGwbfeLt9RqCCTJZT4SUSDcq5hwdvcCgYAxY4Be8mNipj8Cgg22
+mVWSolA0TEzbtUcNk6iGodpi+Z0LKpsPC0YRqPRyh1K+rIltG1BVdmUBHcMlOYxl
+lWWvbJH6PkJWy4n2MF7PO45kjN3pPZg4hgH63JjZeAineBwEArUGb9zHnvzcdRvF
+wuQ2pZHL/HJ0laUSieHDJ5917w==
+-----END PRIVATE KEY-----
+
+
+-----BEGIN CERTIFICATE-----
+MIIDjTCCAnWgAwIBAgIURt5IBx0J3xgEaQvmyrFH2A+NkpMwDQYJKoZIhvcNAQEL
+BQAwVjELMAkGA1UEBhMCUlUxDzANBgNVBAgMBk1vc2NvdzEPMA0GA1UEBwwGTW9z
+Y293MQ8wDQYDVQQKDAZZYW5kZXgxFDASBgNVBAMMC3Rlc3Qtc2VydmVyMB4XDTE5
+MDkyMDE3MTQ0MVoXDTQ3MDIwNDE3MTQ0MVowVjELMAkGA1UEBhMCUlUxDzANBgNV
+BAgMBk1vc2NvdzEPMA0GA1UEBwwGTW9zY293MQ8wDQYDVQQKDAZZYW5kZXgxFDAS
+BgNVBAMMC3Rlc3Qtc2VydmVyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
+AQEAs0WY6HTuwKntcEcjo+pBuoNp5/GRgMX2qOJi09Iw021ZLK4Vf4drN7pXS5Ba
+OVqzUPFmXvoiG13hS7PLTuobJc63qPbIodiB6EXB+Sp0v+mE6lYUUyW9YxNnTPDc
+GG8E4vk9j3tBawT4yJIFTudIALWJfQvn3O9ebmYkilvq0ZT+TqBU8Mazo4lNu0T2
+YxWMlivcEyNRLPbka5W2Wy5eXGOnStidQFYka2mmCgljtulWzj1i7GODg93vmVyH
+NzjAs+mG9MJkT3ietG225BnyPDtu5A3b+vTAFhyJtMmDMyhJ6JtXXHu6zUDQxKiX
+6HLGCLIPhL2sk9ckPSkwXoMOywIDAQABo1MwUTAdBgNVHQ4EFgQUDv/xuJ4CvCgG
+fPrZP3hRAt2+/LwwHwYDVR0jBBgwFoAUDv/xuJ4CvCgGfPrZP3hRAt2+/LwwDwYD
+VR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAinKpMYaA2tjLpAnPVbjy
+/ZxSBhhB26RiQp3Re8XOKyhTWqgYE6kldYT0aXgK9x9mPC5obQannDDYxDc7lX+/
+qP/u1X81ZcDRo/f+qQ3iHfT6Ftt/4O3qLnt45MFM6Q7WabRm82x3KjZTqpF3QUdy
+tumWiuAP5DMd1IRDtnKjFHO721OsEsf6NLcqdX89bGeqXDvrkwg3/PNwTyW5E7cj
+feY8L2eWtg6AJUnIBu11wvfzkLiH3QKzHvO/SIZTGf5ihDsJ3aKEE9UNauTL3bVc
+CRA/5XcX13GJwHHj6LCoc3sL7mt8qV9HKY2AOZ88mpObzISZxgPpdKCfjsrdm63V
+6g==
+-----END CERTIFICATE-----)___";
+
+ TTempFileHandle certificateFile;
+
+ certificateFile.Write(certificateContent.data(), certificateContent.size());
+
+ NActors::IActor* proxy = NHttp::CreateHttpProxy(sensors);
NActors::TActorId proxyId = actorSystem.Register(proxy);
-
+
THolder<NHttp::TEvHttpProxy::TEvAddListeningPort> add = MakeHolder<NHttp::TEvHttpProxy::TEvAddListeningPort>(port);
- ///////// https configuration
- add->Secure = true;
- add->CertificateFile = certificateFile.Name();
- add->PrivateKeyFile = certificateFile.Name();
- /////////
+ ///////// https configuration
+ add->Secure = true;
+ add->CertificateFile = certificateFile.Name();
+ add->PrivateKeyFile = certificateFile.Name();
+ /////////
actorSystem.Send(new NActors::IEventHandle(proxyId, TActorId(), add.Release()), 0, true);
- actorSystem.DispatchEvents();
-
+ actorSystem.DispatchEvents();
+
NActors::TActorId serverId = actorSystem.AllocateEdgeActor();
- actorSystem.Send(new NActors::IEventHandle(proxyId, serverId, new NHttp::TEvHttpProxy::TEvRegisterHandler("/test", serverId)), 0, true);
-
+ 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("https://[::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");
- }
-
+ NHttp::THttpOutgoingRequestPtr httpRequest = NHttp::THttpOutgoingRequest::CreateRequestGet("https://[::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(AdvancedRunning) {
THolder<NActors::TActorSystemSetup> setup = MakeHolder<NActors::TActorSystemSetup>();
- setup->NodeId = 1;
- setup->ExecutorsCount = 1;
- setup->Executors = new TAutoPtr<NActors::IExecutorPool>[1];
- setup->Executors[0] = new NActors::TBasicExecutorPool(0, 2, 10);
- setup->Scheduler = new NActors::TBasicSchedulerThread(NActors::TSchedulerConfig(512, 100));
- NActors::TActorSystem actorSystem(setup);
- actorSystem.Start();
- NHttp::THttpProxy* incomingProxy = new NHttp::THttpProxy();
+ setup->NodeId = 1;
+ setup->ExecutorsCount = 1;
+ setup->Executors = new TAutoPtr<NActors::IExecutorPool>[1];
+ setup->Executors[0] = new NActors::TBasicExecutorPool(0, 2, 10);
+ setup->Scheduler = new NActors::TBasicSchedulerThread(NActors::TSchedulerConfig(512, 100));
+ NActors::TActorSystem actorSystem(setup);
+ actorSystem.Start();
+ NHttp::THttpProxy* incomingProxy = new NHttp::THttpProxy();
NActors::TActorId incomingProxyId = actorSystem.Register(incomingProxy);
- actorSystem.Send(incomingProxyId, new NHttp::TEvHttpProxy::TEvAddListeningPort(13337));
-
- NHttp::THttpProxy* outgoingProxy = new NHttp::THttpProxy();
+ actorSystem.Send(incomingProxyId, new NHttp::TEvHttpProxy::TEvAddListeningPort(13337));
+
+ NHttp::THttpProxy* outgoingProxy = new NHttp::THttpProxy();
NActors::TActorId outgoingProxyId = actorSystem.Register(outgoingProxy);
-
+
THolder<NHttp::THttpStaticStringRequest> httpRequest = MakeHolder<NHttp::THttpStaticStringRequest>("GET /test HTTP/1.1\r\n\r\n");
- actorSystem.Send(outgoingProxyId, new NHttp::TEvHttpProxy::TEvHttpOutgoingRequest("[::]:13337", std::move(httpRequest)));
-
- Sleep(TDuration::Minutes(60));
- }*/
-
- Y_UNIT_TEST(TooLongHeader) {
- NActors::TTestActorRuntimeBase actorSystem;
- TPortManager portManager;
- TIpPort port = portManager.GetTcpPort();
- TAutoPtr<NActors::IEventHandle> handle;
- actorSystem.Initialize();
- NMonitoring::TMetricRegistry sensors;
-
- NActors::IActor* proxy = NHttp::CreateHttpProxy(sensors);
- 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://[::1]:" + ToString(port) + "/test");
- httpRequest->Set("Connection", "close");
- TString longHeader;
- longHeader.append(9000, 'X');
- httpRequest->Set(longHeader, "data");
- 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");
- }
-}
+ actorSystem.Send(outgoingProxyId, new NHttp::TEvHttpProxy::TEvHttpOutgoingRequest("[::]:13337", std::move(httpRequest)));
+
+ Sleep(TDuration::Minutes(60));
+ }*/
+
+ Y_UNIT_TEST(TooLongHeader) {
+ NActors::TTestActorRuntimeBase actorSystem;
+ TPortManager portManager;
+ TIpPort port = portManager.GetTcpPort();
+ TAutoPtr<NActors::IEventHandle> handle;
+ actorSystem.Initialize();
+ NMonitoring::TMetricRegistry sensors;
+
+ NActors::IActor* proxy = NHttp::CreateHttpProxy(sensors);
+ 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://[::1]:" + ToString(port) + "/test");
+ httpRequest->Set("Connection", "close");
+ TString longHeader;
+ longHeader.append(9000, 'X');
+ httpRequest->Set(longHeader, "data");
+ 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");
+ }
+}
diff --git a/library/cpp/actors/http/ut/ya.make b/library/cpp/actors/http/ut/ya.make
index 8b4c04c4d3..12d360dabf 100644
--- a/library/cpp/actors/http/ut/ya.make
+++ b/library/cpp/actors/http/ut/ya.make
@@ -1,18 +1,18 @@
UNITTEST_FOR(library/cpp/actors/http)
-
-OWNER(xenoxeno)
-
-SIZE(SMALL)
-
-PEERDIR(
+
+OWNER(xenoxeno)
+
+SIZE(SMALL)
+
+PEERDIR(
library/cpp/actors/testlib
-)
-
+)
+
IF (NOT OS_WINDOWS)
-SRCS(
- http_ut.cpp
-)
+SRCS(
+ http_ut.cpp
+)
ELSE()
ENDIF()
-
-END()
+
+END()
diff --git a/library/cpp/actors/http/ya.make b/library/cpp/actors/http/ya.make
index 7ce68b7a75..60c9c93a09 100644
--- a/library/cpp/actors/http/ya.make
+++ b/library/cpp/actors/http/ya.make
@@ -1,33 +1,33 @@
-RECURSE_FOR_TESTS(ut)
-
-LIBRARY()
-
-OWNER(xenoxeno g:kikimr)
-
-SRCS(
- http_cache.cpp
- http_cache.h
- http_config.h
- http_proxy_acceptor.cpp
- http_proxy_incoming.cpp
- http_proxy_outgoing.cpp
- http_proxy_sock_impl.h
- http_proxy_ssl.h
- http_proxy.cpp
- http_proxy.h
- http_static.cpp
- http_static.h
- http.cpp
- http.h
-)
-
-PEERDIR(
- contrib/libs/openssl
+RECURSE_FOR_TESTS(ut)
+
+LIBRARY()
+
+OWNER(xenoxeno g:kikimr)
+
+SRCS(
+ http_cache.cpp
+ http_cache.h
+ http_config.h
+ http_proxy_acceptor.cpp
+ http_proxy_incoming.cpp
+ http_proxy_outgoing.cpp
+ http_proxy_sock_impl.h
+ http_proxy_ssl.h
+ http_proxy.cpp
+ http_proxy.h
+ http_static.cpp
+ http_static.h
+ http.cpp
+ http.h
+)
+
+PEERDIR(
+ contrib/libs/openssl
library/cpp/actors/core
library/cpp/actors/interconnect
library/cpp/dns
library/cpp/monlib/metrics
library/cpp/string_utils/quote
-)
-
-END()
+)
+
+END()
diff --git a/library/cpp/actors/interconnect/interconnect_common.h b/library/cpp/actors/interconnect/interconnect_common.h
index 285709a00c..30e36c4242 100644
--- a/library/cpp/actors/interconnect/interconnect_common.h
+++ b/library/cpp/actors/interconnect/interconnect_common.h
@@ -65,8 +65,8 @@ namespace NActors {
using TRegisterMonPageCallback = std::function<void(const TString& path, const TString& title,
TActorSystem* actorSystem, const TActorId& actorId)>;
- using TInitWhiteboardCallback = std::function<void(ui16 icPort, TActorSystem* actorSystem)>;
-
+ using TInitWhiteboardCallback = std::function<void(ui16 icPort, TActorSystem* actorSystem)>;
+
using TUpdateWhiteboardCallback = std::function<void(const TString& peer, bool connected, bool green, bool yellow,
bool orange, bool red, TActorSystem* actorSystem)>;
@@ -84,7 +84,7 @@ namespace NActors {
TVector<TString> AcceptUUID;
ui64 StartTime = GetCycleCountFast();
TString TechnicalSelfHostName;
- TInitWhiteboardCallback InitWhiteboard;
+ TInitWhiteboardCallback InitWhiteboard;
TUpdateWhiteboardCallback UpdateWhiteboard;
ui32 HandshakeBallastSize = 0;
TAtomic StartedSessionKiller = 0;
diff --git a/library/cpp/actors/interconnect/interconnect_tcp_server.cpp b/library/cpp/actors/interconnect/interconnect_tcp_server.cpp
index b95c994598..557092a13c 100644
--- a/library/cpp/actors/interconnect/interconnect_tcp_server.cpp
+++ b/library/cpp/actors/interconnect/interconnect_tcp_server.cpp
@@ -79,9 +79,9 @@ namespace NActors {
return;
}
}
- if (const auto& callback = ProxyCommonCtx->InitWhiteboard) {
- callback(Address.GetPort(), TlsActivationContext->ExecutorThread.ActorSystem);
- }
+ if (const auto& callback = ProxyCommonCtx->InitWhiteboard) {
+ callback(Address.GetPort(), TlsActivationContext->ExecutorThread.ActorSystem);
+ }
const bool success = ctx.Send(MakePollerActorId(), new TEvPollerRegister(Listener, SelfId(), {}));
Y_VERIFY(success);
Become(&TThis::Listen);
diff --git a/library/cpp/actors/protos/interconnect.proto b/library/cpp/actors/protos/interconnect.proto
index 2e3b0d0d15..76885ef5bd 100644
--- a/library/cpp/actors/protos/interconnect.proto
+++ b/library/cpp/actors/protos/interconnect.proto
@@ -17,8 +17,8 @@ message TEvNodeInfo {
extend google.protobuf.FieldOptions {
optional string PrintName = 50376;
-}
-
+}
+
message TNodeLocation {
// compatibility section -- will be removed in future versions
optional uint32 DataCenterNum = 1 [deprecated=true];
diff --git a/library/cpp/actors/testlib/test_runtime.cpp b/library/cpp/actors/testlib/test_runtime.cpp
index 6fa25b9965..0010a1a135 100644
--- a/library/cpp/actors/testlib/test_runtime.cpp
+++ b/library/cpp/actors/testlib/test_runtime.cpp
@@ -36,24 +36,24 @@ namespace NActors {
ui64 TScheduledEventQueueItem::NextUniqueId = 0;
void PrintEvent(TAutoPtr<IEventHandle>& ev, const TTestActorRuntimeBase* runtime) {
- Cerr << "mailbox: " << ev->GetRecipientRewrite().Hint() << ", type: " << Sprintf("%08x", ev->GetTypeRewrite())
- << ", from " << ev->Sender.LocalId();
+ Cerr << "mailbox: " << ev->GetRecipientRewrite().Hint() << ", type: " << Sprintf("%08x", ev->GetTypeRewrite())
+ << ", from " << ev->Sender.LocalId();
TString name = runtime->GetActorName(ev->Sender);
- if (!name.empty())
- Cerr << " \"" << name << "\"";
- Cerr << ", to " << ev->GetRecipientRewrite().LocalId();
- name = runtime->GetActorName(ev->GetRecipientRewrite());
- if (!name.empty())
- Cerr << " \"" << name << "\"";
- Cerr << ", ";
+ if (!name.empty())
+ Cerr << " \"" << name << "\"";
+ Cerr << ", to " << ev->GetRecipientRewrite().LocalId();
+ name = runtime->GetActorName(ev->GetRecipientRewrite());
+ if (!name.empty())
+ Cerr << " \"" << name << "\"";
+ Cerr << ", ";
if (ev->HasEvent())
- Cerr << " : " << (PRINT_EVENT_BODY ? ev->GetBase()->ToString() : ev->GetBase()->ToStringHeader());
+ Cerr << " : " << (PRINT_EVENT_BODY ? ev->GetBase()->ToString() : ev->GetBase()->ToStringHeader());
else if (ev->HasBuffer())
- Cerr << " : BUFFER";
+ Cerr << " : BUFFER";
else
- Cerr << " : EMPTY";
+ Cerr << " : EMPTY";
- Cerr << "\n";
+ Cerr << "\n";
}
TTestActorRuntimeBase::TNodeDataBase::TNodeDataBase() {
@@ -103,8 +103,8 @@ namespace NActors {
}
if (verbose) {
- Cerr << "Got event at " << TInstant::MicroSeconds(Runtime->CurrentTimestamp) << ", ";
- PrintEvent(ev, Runtime);
+ Cerr << "Got event at " << TInstant::MicroSeconds(Runtime->CurrentTimestamp) << ", ";
+ PrintEvent(ev, Runtime);
}
if (!Runtime->EventFilterFunc(*Runtime, ev)) {
@@ -114,11 +114,11 @@ namespace NActors {
Runtime->GetMailbox(nodeId, mailboxHint).Send(ev);
Runtime->MailboxesHasEvents.Signal();
if (verbose)
- Cerr << "Event was added to sent queue\n";
+ Cerr << "Event was added to sent queue\n";
}
else {
if (verbose)
- Cerr << "Event was dropped\n";
+ Cerr << "Event was dropped\n";
}
}
@@ -316,8 +316,8 @@ namespace NActors {
}
if (verbose) {
- Cerr << "Got scheduled event at " << TInstant::MicroSeconds(Runtime->CurrentTimestamp) << ", ";
- PrintEvent(ev, Runtime);
+ Cerr << "Got scheduled event at " << TInstant::MicroSeconds(Runtime->CurrentTimestamp) << ", ";
+ PrintEvent(ev, Runtime);
}
auto now = Runtime->GetTimeProvider()->Now();
@@ -331,13 +331,13 @@ namespace NActors {
Runtime->GetMailbox(Runtime->FirstNodeId + NodeIndex, mailboxHint).Schedule(TScheduledEventQueueItem(deadline, ev, cookie));
Runtime->MailboxesHasEvents.Signal();
if (verbose)
- Cerr << "Event was added to scheduled queue\n";
+ Cerr << "Event was added to scheduled queue\n";
} else {
if (cookie) {
cookie->Detach();
}
if (verbose) {
- Cerr << "Scheduled event for " << ev->GetRecipientRewrite().ToString() << " was dropped\n";
+ Cerr << "Scheduled event for " << ev->GetRecipientRewrite().ToString() << " was dropped\n";
}
}
}
@@ -351,8 +351,8 @@ namespace NActors {
}
if (verbose) {
- Cerr << "Got event at " << TInstant::MicroSeconds(Runtime->CurrentTimestamp) << ", ";
- PrintEvent(ev, Runtime);
+ Cerr << "Got event at " << TInstant::MicroSeconds(Runtime->CurrentTimestamp) << ", ";
+ PrintEvent(ev, Runtime);
}
if (!Runtime->EventFilterFunc(*Runtime, ev)) {
@@ -385,10 +385,10 @@ namespace NActors {
Runtime->MailboxesHasEvents.Signal();
}
if (verbose)
- Cerr << "Event was added to sent queue\n";
+ Cerr << "Event was added to sent queue\n";
} else {
if (verbose)
- Cerr << "Event was dropped\n";
+ Cerr << "Event was dropped\n";
}
return true;
}
@@ -462,7 +462,7 @@ namespace NActors {
, ClusterUUID(MakeClusterId())
, FirstNodeId(NextNodeId)
, NodeCount(nodeCount)
- , DataCenterCount(dataCenterCount)
+ , DataCenterCount(dataCenterCount)
, UseRealThreads(useRealThreads)
, LocalId(0)
, DispatchCyclesCount(0)
@@ -529,16 +529,16 @@ namespace NActors {
TTestActorRuntimeBase::TTestActorRuntimeBase(ui32 nodeCount, ui32 dataCenterCount)
: TTestActorRuntimeBase(nodeCount, dataCenterCount, false) {
- }
-
+ }
+
TTestActorRuntimeBase::TTestActorRuntimeBase(ui32 nodeCount, bool useRealThreads)
: TTestActorRuntimeBase(nodeCount, nodeCount, useRealThreads) {
- }
-
+ }
+
TTestActorRuntimeBase::~TTestActorRuntimeBase() {
CleanupNodes();
Cerr.Flush();
- Cerr.Flush();
+ Cerr.Flush();
Clog.Flush();
DisableActorCallstack();
@@ -582,58 +582,58 @@ namespace NActors {
void TTestActorRuntimeBase::DefaultRegistrationObserver(TTestActorRuntimeBase& runtime, const TActorId& parentId, const TActorId& actorId) {
if (runtime.ScheduleWhiteList.find(parentId) != runtime.ScheduleWhiteList.end()) {
runtime.ScheduleWhiteList.insert(actorId);
- runtime.ScheduleWhiteListParent[actorId] = parentId;
+ runtime.ScheduleWhiteListParent[actorId] = parentId;
}
}
- class TScheduledTreeItem {
- public:
+ class TScheduledTreeItem {
+ public:
TString Name;
- ui64 Count;
+ ui64 Count;
TVector<TScheduledTreeItem> Children;
-
+
TScheduledTreeItem(const TString& name)
- : Name(name)
- , Count(0)
- {}
-
+ : Name(name)
+ , Count(0)
+ {}
+
TScheduledTreeItem* GetItem(const TString& name) {
- TScheduledTreeItem* item = nullptr;
- for (TScheduledTreeItem& i : Children) {
- if (i.Name == name) {
- item = &i;
- break;
- }
- }
- if (item != nullptr)
- return item;
- Children.emplace_back(name);
- return &Children.back();
- }
-
- void RecursiveSort() {
- Sort(Children, [](const TScheduledTreeItem& a, const TScheduledTreeItem& b) -> bool { return a.Count > b.Count; });
- for (TScheduledTreeItem& item : Children) {
- item.RecursiveSort();
- }
- }
-
+ TScheduledTreeItem* item = nullptr;
+ for (TScheduledTreeItem& i : Children) {
+ if (i.Name == name) {
+ item = &i;
+ break;
+ }
+ }
+ if (item != nullptr)
+ return item;
+ Children.emplace_back(name);
+ return &Children.back();
+ }
+
+ void RecursiveSort() {
+ Sort(Children, [](const TScheduledTreeItem& a, const TScheduledTreeItem& b) -> bool { return a.Count > b.Count; });
+ for (TScheduledTreeItem& item : Children) {
+ item.RecursiveSort();
+ }
+ }
+
void Print(IOutputStream& stream, const TString& prefix) {
- for (auto it = Children.begin(); it != Children.end(); ++it) {
- bool lastChild = (std::next(it) == Children.end());
+ for (auto it = Children.begin(); it != Children.end(); ++it) {
+ bool lastChild = (std::next(it) == Children.end());
TString connectionPrefix = lastChild ? "└─ " : "├─ ";
TString subChildPrefix = lastChild ? " " : "│ ";
- stream << prefix << connectionPrefix << it->Name << " (" << it->Count << ")\n";
- it->Print(stream, prefix + subChildPrefix);
- }
- }
-
+ stream << prefix << connectionPrefix << it->Name << " (" << it->Count << ")\n";
+ it->Print(stream, prefix + subChildPrefix);
+ }
+ }
+
void Print(IOutputStream& stream) {
- stream << Name << " (" << Count << ")\n";
+ stream << Name << " (" << Count << ")\n";
Print(stream, TString());
- }
- };
-
+ }
+ };
+
void TTestActorRuntimeBase::CollapsedTimeScheduledEventsSelector(TTestActorRuntimeBase& runtime, TScheduledEventsList& scheduledEvents, TEventsList& queue) {
if (scheduledEvents.empty())
return;
@@ -641,30 +641,30 @@ namespace NActors {
TInstant time = scheduledEvents.begin()->Deadline;
while (!scheduledEvents.empty() && scheduledEvents.begin()->Deadline == time) {
static THashMap<std::pair<TActorId, TString>, ui64> eventTypes;
- auto& item = *scheduledEvents.begin();
+ auto& item = *scheduledEvents.begin();
TString name = item.Event->GetBase() ? TypeName(*item.Event->GetBase()) : Sprintf("%08" PRIx32, item.Event->Type);
eventTypes[std::make_pair(item.Event->Recipient, name)]++;
runtime.ScheduledCount++;
if (runtime.ScheduledCount > runtime.ScheduledLimit) {
-// TScheduledTreeItem root("Root");
+// TScheduledTreeItem root("Root");
// TVector<TString> path;
-// for (const auto& pr : eventTypes) {
-// path.clear();
-// path.push_back(runtime.GetActorName(pr.first.first));
-// for (auto it = runtime.ScheduleWhiteListParent.find(pr.first.first); it != runtime.ScheduleWhiteListParent.end(); it = runtime.ScheduleWhiteListParent.find(it->second)) {
-// path.insert(path.begin(), runtime.GetActorName(it->second));
-// }
-// path.push_back("<" + pr.first.second + ">"); // event name;
-// ui64 count = pr.second;
-// TScheduledTreeItem* item = &root;
-// item->Count += count;
+// for (const auto& pr : eventTypes) {
+// path.clear();
+// path.push_back(runtime.GetActorName(pr.first.first));
+// for (auto it = runtime.ScheduleWhiteListParent.find(pr.first.first); it != runtime.ScheduleWhiteListParent.end(); it = runtime.ScheduleWhiteListParent.find(it->second)) {
+// path.insert(path.begin(), runtime.GetActorName(it->second));
+// }
+// path.push_back("<" + pr.first.second + ">"); // event name;
+// ui64 count = pr.second;
+// TScheduledTreeItem* item = &root;
+// item->Count += count;
// for (TString name : path) {
-// item = item->GetItem(name);
-// item->Count += count;
-// }
-// }
-// root.RecursiveSort();
-// root.Print(Cerr);
+// item = item->GetItem(name);
+// item->Count += count;
+// }
+// }
+// root.RecursiveSort();
+// root.Print(Cerr);
ythrow TSchedulingLimitReachedException(runtime.ScheduledLimit);
}
@@ -755,10 +755,10 @@ namespace NActors {
IsInitialized = true;
}
- void SetupCrossDC() {
-
- }
-
+ void SetupCrossDC() {
+
+ }
+
TDuration TTestActorRuntimeBase::SetDispatchTimeout(TDuration timeout) {
TGuard<TMutex> guard(Mutex);
TDuration oldTimeout = DispatchTimeout;
@@ -798,11 +798,11 @@ namespace NActors {
}
void TTestActorRuntimeBase::UpdateCurrentTime(TInstant newTime) {
- static int counter = 0;
- ++counter;
- if (VERBOSE) {
- Cerr << "UpdateCurrentTime(" << counter << "," << newTime << ")\n";
- }
+ static int counter = 0;
+ ++counter;
+ if (VERBOSE) {
+ Cerr << "UpdateCurrentTime(" << counter << "," << newTime << ")\n";
+ }
TGuard<TMutex> guard(Mutex);
Y_VERIFY(!UseRealThreads);
if (newTime.MicroSeconds() > CurrentTimestamp) {
@@ -836,7 +836,7 @@ namespace NActors {
TGuard<TMutex> guard(Mutex);
ui64 nextId = ++LocalId;
if (VERBOSE) {
- Cerr << "Allocated id: " << nextId << "\n";
+ Cerr << "Allocated id: " << nextId << "\n";
}
return nextId;
@@ -1068,7 +1068,7 @@ namespace NActors {
const TDuration scheduledEventsInspectInterval = TDuration::MilliSeconds(10);
TInstant inspectScheduledEventsAt = dispatchTime + scheduledEventsInspectInterval;
if (verbose) {
- Cerr << "Start dispatch at " << TInstant::MicroSeconds(CurrentTimestamp) << ", deadline is " << deadline << "\n";
+ Cerr << "Start dispatch at " << TInstant::MicroSeconds(CurrentTimestamp) << ", deadline is " << deadline << "\n";
}
struct TTempEdgeEventsCaptor {
@@ -1181,14 +1181,14 @@ namespace NActors {
ythrow TWithBackTrace<yexception>() << "Dispatched "
<< DispatchedEventsLimit << " events, limit reached.";
}
-
+
auto ev = mbox.second->Pop();
- if (BlockedOutput.find(ev->Sender) == BlockedOutput.end()) {
- //UpdateCurrentTime(TInstant::MicroSeconds(CurrentTimestamp + 10));
- if (verbose) {
- Cerr << "Process event at " << TInstant::MicroSeconds(CurrentTimestamp) << ", ";
- PrintEvent(ev, this);
- }
+ if (BlockedOutput.find(ev->Sender) == BlockedOutput.end()) {
+ //UpdateCurrentTime(TInstant::MicroSeconds(CurrentTimestamp + 10));
+ if (verbose) {
+ Cerr << "Process event at " << TInstant::MicroSeconds(CurrentTimestamp) << ", ";
+ PrintEvent(ev, this);
+ }
}
hasProgress = true;
@@ -1263,7 +1263,7 @@ namespace NActors {
if (!mbox.second->IsEmpty()) {
if (verbose) {
- Cerr << "Dispatch complete with non-empty queue at " << TInstant::MicroSeconds(CurrentTimestamp) << "\n";
+ Cerr << "Dispatch complete with non-empty queue at " << TInstant::MicroSeconds(CurrentTimestamp) << "\n";
}
return true;
@@ -1277,7 +1277,7 @@ namespace NActors {
if (dispatchTime >= deadline) {
if (verbose) {
- Cerr << "Reach deadline at " << TInstant::MicroSeconds(CurrentTimestamp) << "\n";
+ Cerr << "Reach deadline at " << TInstant::MicroSeconds(CurrentTimestamp) << "\n";
}
ythrow TWithBackTrace<TEmptyEventQueueException>();
@@ -1319,8 +1319,8 @@ namespace NActors {
nextScheduleMbox->PushScheduled(capturedScheduledEvents);
for (auto& event : selectedEvents) {
if (verbose && (BlockedOutput.find(event->Sender) == BlockedOutput.end())) {
- Cerr << "Selected scheduled event at " << TInstant::MicroSeconds(CurrentTimestamp) << ", ";
- PrintEvent(event, this);
+ Cerr << "Selected scheduled event at " << TInstant::MicroSeconds(CurrentTimestamp) << ", ";
+ PrintEvent(event, this);
}
nextScheduleMbox->Send(event);
@@ -1330,7 +1330,7 @@ namespace NActors {
if (!isEmpty) {
if (verbose) {
- Cerr << "Process selected events at " << TInstant::MicroSeconds(CurrentTimestamp) << "\n";
+ Cerr << "Process selected events at " << TInstant::MicroSeconds(CurrentTimestamp) << "\n";
}
deadline = dispatchTime + DispatchTimeout;
@@ -1339,7 +1339,7 @@ namespace NActors {
if (nearestMailboxDeadline.Defined()) {
if (verbose) {
- Cerr << "Forward time to " << *nearestMailboxDeadline.Get() << "\n";
+ Cerr << "Forward time to " << *nearestMailboxDeadline.Get() << "\n";
}
UpdateCurrentTime(*nearestMailboxDeadline.Get());
@@ -1369,8 +1369,8 @@ namespace NActors {
void TTestActorRuntimeBase::UpdateFinalEventsStatsForEachContext(IEventHandle& ev) {
TDispatchContext* context = CurrentDispatchContext;
while (context) {
- for (const auto& finalEvent : context->Options->FinalEvents) {
- if (finalEvent.EventCheck(ev)) {
+ for (const auto& finalEvent : context->Options->FinalEvents) {
+ if (finalEvent.EventCheck(ev)) {
auto& freq = context->FinalEventFrequency[&finalEvent];
if (++freq >= finalEvent.RequiredCount) {
context->FinalEventFound = true;
@@ -1397,7 +1397,7 @@ namespace NActors {
TInstant deadline = TInstant::MicroSeconds(CurrentTimestamp) + duration;
GetMailbox(nodeId, mailboxHint).Schedule(TScheduledEventQueueItem(deadline, ev, nullptr));
if (VERBOSE)
- Cerr << "Event was added to scheduled queue\n";
+ Cerr << "Event was added to scheduled queue\n";
}
void TTestActorRuntimeBase::ClearCounters() {
@@ -1497,14 +1497,14 @@ namespace NActors {
void TTestActorRuntimeBase::EnableScheduleForActor(const TActorId& actorId, bool allow) {
TGuard<TMutex> guard(Mutex);
if (allow) {
- if (VERBOSE) {
- Cerr << "Actor " << actorId << " added to schedule whitelist";
- }
+ if (VERBOSE) {
+ Cerr << "Actor " << actorId << " added to schedule whitelist";
+ }
ScheduleWhiteList.insert(actorId);
} else {
- if (VERBOSE) {
- Cerr << "Actor " << actorId << " removed from schedule whitelist";
- }
+ if (VERBOSE) {
+ Cerr << "Actor " << actorId << " removed from schedule whitelist";
+ }
ScheduleWhiteList.erase(actorId);
}
}
@@ -1560,8 +1560,8 @@ namespace NActors {
ui64 recipientLocalId = ev->GetRecipientRewrite().LocalId();
if ((BlockedOutput.find(ev->Sender) == BlockedOutput.end()) && VERBOSE) {
- Cerr << "Send event, ";
- PrintEvent(evHolder, this);
+ Cerr << "Send event, ";
+ PrintEvent(evHolder, this);
}
EvCounters[ev->GetTypeRewrite()]++;
@@ -1589,7 +1589,7 @@ namespace NActors {
TlsActivationContext = prevTlsActivationContext;
} else {
if (VERBOSE) {
- Cerr << "Failed to find actor with local id: " << recipientLocalId << "\n";
+ Cerr << "Failed to find actor with local id: " << recipientLocalId << "\n";
}
auto forwardedEv = ev->ForwardOnNondelivery(TEvents::TEvUndelivered::ReasonActorUnknown);
@@ -1727,18 +1727,18 @@ namespace NActors {
}
void TTestActorRuntimeBase::ClearMailbox(ui32 nodeId, ui32 hint) {
- TGuard<TMutex> guard(Mutex);
- auto mboxId = TEventMailboxId(nodeId, hint);
- Mailboxes.erase(mboxId);
- }
-
+ TGuard<TMutex> guard(Mutex);
+ auto mboxId = TEventMailboxId(nodeId, hint);
+ Mailboxes.erase(mboxId);
+ }
+
TString TTestActorRuntimeBase::GetActorName(const TActorId& actorId) const {
- auto it = ActorNames.find(actorId);
- if (it != ActorNames.end())
- return it->second;
- return actorId.ToString();
- }
-
+ auto it = ActorNames.find(actorId);
+ if (it != ActorNames.end())
+ return it->second;
+ return actorId.ToString();
+ }
+
struct TStrandingActorDecoratorContext : public TThrRefBase {
TStrandingActorDecoratorContext()
: Queue(new TQueueType)
diff --git a/library/cpp/actors/testlib/test_runtime.h b/library/cpp/actors/testlib/test_runtime.h
index 26e3b45c98..589309afd7 100644
--- a/library/cpp/actors/testlib/test_runtime.h
+++ b/library/cpp/actors/testlib/test_runtime.h
@@ -74,20 +74,20 @@ namespace NActors {
struct TDispatchOptions {
struct TFinalEventCondition {
- std::function<bool(IEventHandle& ev)> EventCheck;
+ std::function<bool(IEventHandle& ev)> EventCheck;
ui32 RequiredCount;
TFinalEventCondition(ui32 eventType, ui32 requiredCount = 1)
- : EventCheck([eventType](IEventHandle& ev) -> bool { return ev.GetTypeRewrite() == eventType; })
- , RequiredCount(requiredCount)
- {
- }
-
- TFinalEventCondition(std::function<bool(IEventHandle& ev)> eventCheck, ui32 requiredCount = 1)
- : EventCheck(eventCheck)
+ : EventCheck([eventType](IEventHandle& ev) -> bool { return ev.GetTypeRewrite() == eventType; })
, RequiredCount(requiredCount)
{
}
+
+ TFinalEventCondition(std::function<bool(IEventHandle& ev)> eventCheck, ui32 requiredCount = 1)
+ : EventCheck(eventCheck)
+ , RequiredCount(requiredCount)
+ {
+ }
};
TVector<TFinalEventCondition> FinalEvents;
@@ -359,14 +359,14 @@ namespace NActors {
return GrabEdgeEventIf(handle, truth, simTimeout);
}
- template <typename TEvent>
- THolder<TEvent> GrabEdgeEvent(TDuration simTimeout = TDuration::Max()) {
- TAutoPtr<IEventHandle> handle;
- std::function<bool(const TEvent&)> truth = [](const TEvent&) { return true; };
- GrabEdgeEventIf(handle, truth, simTimeout);
+ template <typename TEvent>
+ THolder<TEvent> GrabEdgeEvent(TDuration simTimeout = TDuration::Max()) {
+ TAutoPtr<IEventHandle> handle;
+ std::function<bool(const TEvent&)> truth = [](const TEvent&) { return true; };
+ GrabEdgeEventIf(handle, truth, simTimeout);
return THolder(handle ? handle->Release<TEvent>().Release() : nullptr);
- }
-
+ }
+
template<class TEvent>
typename TEvent::TPtr GrabEdgeEvent(const TSet<TActorId>& edgeFilter, TDuration simTimeout = TDuration::Max()) {
return GrabEdgeEventIf<TEvent>(edgeFilter, [](const typename TEvent::TPtr&) { return true; }, simTimeout);
@@ -378,33 +378,33 @@ namespace NActors {
return GrabEdgeEvent<TEvent>(edgeFilter, simTimeout);
}
- // replace with std::variant<>
- template <typename... TEvents>
- std::tuple<TEvents*...> GrabEdgeEvents(TAutoPtr<IEventHandle>& handle, TDuration simTimeout = TDuration::Max()) {
- handle.Destroy();
- auto eventTypes = { TEvents::EventType... };
+ // replace with std::variant<>
+ template <typename... TEvents>
+ std::tuple<TEvents*...> GrabEdgeEvents(TAutoPtr<IEventHandle>& handle, TDuration simTimeout = TDuration::Max()) {
+ handle.Destroy();
+ auto eventTypes = { TEvents::EventType... };
WaitForEdgeEvents([&](TTestActorRuntimeBase&, TAutoPtr<IEventHandle>& event) {
- if (std::find(std::begin(eventTypes), std::end(eventTypes), event->GetTypeRewrite()) == std::end(eventTypes))
- return false;
- handle = event;
- return true;
+ if (std::find(std::begin(eventTypes), std::end(eventTypes), event->GetTypeRewrite()) == std::end(eventTypes))
+ return false;
+ handle = event;
+ return true;
}, {}, simTimeout);
- if (simTimeout == TDuration::Max())
- Y_VERIFY(handle);
- if (handle) {
- return std::make_tuple(handle->Type == TEvents::EventType
- ? reinterpret_cast<TAutoPtr<TEventHandle<TEvents>>&>(handle)->Get()
- : static_cast<TEvents*>(nullptr)...);
- }
- return {};
- }
-
+ if (simTimeout == TDuration::Max())
+ Y_VERIFY(handle);
+ if (handle) {
+ return std::make_tuple(handle->Type == TEvents::EventType
+ ? reinterpret_cast<TAutoPtr<TEventHandle<TEvents>>&>(handle)->Get()
+ : static_cast<TEvents*>(nullptr)...);
+ }
+ return {};
+ }
+
template <typename TEvent>
TEvent* GrabEdgeEventRethrow(TAutoPtr<IEventHandle>& handle, TDuration simTimeout = TDuration::Max()) {
try {
return GrabEdgeEvent<TEvent>(handle, simTimeout);
} catch (...) {
- ythrow TWithBackTrace<yexception>() << "Exception occured while waiting for " << TypeName<TEvent>() << ": " << CurrentExceptionMessage();
+ ythrow TWithBackTrace<yexception>() << "Exception occured while waiting for " << TypeName<TEvent>() << ": " << CurrentExceptionMessage();
}
}
@@ -426,33 +426,33 @@ namespace NActors {
}
}
- template <typename... TEvents>
+ template <typename... TEvents>
static TString TypeNames() {
static TString names[] = { TypeName<TEvents>()... };
TString result;
for (const TString& s : names) {
- if (result.empty()) {
- result += '<';
- } else {
- result += ',';
- }
- result += s;
- }
- if (!result.empty()) {
- result += '>';
- }
- return result;
- }
-
- template <typename... TEvents>
- std::tuple<TEvents*...> GrabEdgeEventsRethrow(TAutoPtr<IEventHandle>& handle, TDuration simTimeout = TDuration::Max()) {
- try {
- return GrabEdgeEvents<TEvents...>(handle, simTimeout);
- } catch (...) {
- ythrow TWithBackTrace<yexception>() << "Exception occured while waiting for " << TypeNames<TEvents...>() << ": " << CurrentExceptionMessage();
- }
- }
-
+ if (result.empty()) {
+ result += '<';
+ } else {
+ result += ',';
+ }
+ result += s;
+ }
+ if (!result.empty()) {
+ result += '>';
+ }
+ return result;
+ }
+
+ template <typename... TEvents>
+ std::tuple<TEvents*...> GrabEdgeEventsRethrow(TAutoPtr<IEventHandle>& handle, TDuration simTimeout = TDuration::Max()) {
+ try {
+ return GrabEdgeEvents<TEvents...>(handle, simTimeout);
+ } catch (...) {
+ ythrow TWithBackTrace<yexception>() << "Exception occured while waiting for " << TypeNames<TEvents...>() << ": " << CurrentExceptionMessage();
+ }
+ }
+
void ResetScheduledCount() {
ScheduledCount = 0;
}
@@ -496,7 +496,7 @@ namespace NActors {
IActor* FindActor(const TActorId& actorId, TNodeDataBase* node) const;
void SendInternal(IEventHandle* ev, ui32 nodeIndex, bool viaActorSystem);
TEventMailBox& GetMailbox(ui32 nodeId, ui32 hint);
- void ClearMailbox(ui32 nodeId, ui32 hint);
+ void ClearMailbox(ui32 nodeId, ui32 hint);
void HandleNonEmptyMailboxesForEachContext(TEventMailboxId mboxId);
void UpdateFinalEventsStatsForEachContext(IEventHandle& ev);
bool DispatchEventsInternal(const TDispatchOptions& options, TInstant simDeadline);
@@ -515,7 +515,7 @@ namespace NActors {
const TString ClusterUUID;
const ui32 FirstNodeId;
const ui32 NodeCount;
- const ui32 DataCenterCount;
+ const ui32 DataCenterCount;
const bool UseRealThreads;
ui64 LocalId;
diff --git a/library/cpp/grpc/client/grpc_client_low.h b/library/cpp/grpc/client/grpc_client_low.h
index ab0a0627be..d5ffe74736 100644
--- a/library/cpp/grpc/client/grpc_client_low.h
+++ b/library/cpp/grpc/client/grpc_client_low.h
@@ -126,7 +126,7 @@ public:
// Represents grpc status and error message string
struct TGrpcStatus {
TString Msg;
- TString Details;
+ TString Details;
int GRpcStatusCode;
bool InternalError;
@@ -141,20 +141,20 @@ struct TGrpcStatus {
, InternalError(internalError)
{ }
- TGrpcStatus(grpc::StatusCode status, TString msg, TString details = {})
+ TGrpcStatus(grpc::StatusCode status, TString msg, TString details = {})
: Msg(std::move(msg))
- , Details(std::move(details))
+ , Details(std::move(details))
, GRpcStatusCode(status)
, InternalError(false)
{ }
TGrpcStatus(const grpc::Status& status)
- : TGrpcStatus(status.error_code(), TString(status.error_message()), TString(status.error_details()))
+ : TGrpcStatus(status.error_code(), TString(status.error_message()), TString(status.error_details()))
{ }
TGrpcStatus& operator=(const grpc::Status& status) {
Msg = TString(status.error_message());
- Details = TString(status.error_details());
+ Details = TString(status.error_details());
GRpcStatusCode = status.error_code();
InternalError = false;
return *this;
@@ -178,9 +178,9 @@ bool inline IsGRpcStatusGood(const TGrpcStatus& status) {
template<typename TResponse>
using TResponseCallback = std::function<void (TGrpcStatus&&, TResponse&&)>;
-template<typename TResponse>
-using TAdvancedResponseCallback = std::function<void (const grpc::ClientContext&, TGrpcStatus&&, TResponse&&)>;
-
+template<typename TResponse>
+using TAdvancedResponseCallback = std::function<void (const grpc::ClientContext&, TGrpcStatus&&, TResponse&&)>;
+
// Call associated metadata
struct TCallMeta {
std::shared_ptr<grpc::CallCredentials> CallCredentials;
@@ -305,86 +305,86 @@ private:
bool Replied_ = false;
};
-template<typename TStub, typename TRequest, typename TResponse>
-class TAdvancedRequestProcessor
- : public TThrRefBase
- , public IQueueClientEvent
- , public TGRpcRequestProcessorCommon {
- using TAsyncReaderPtr = std::unique_ptr<grpc::ClientAsyncResponseReader<TResponse>>;
- template<typename> friend class TServiceConnection;
-public:
- using TPtr = TIntrusivePtr<TAdvancedRequestProcessor>;
- using TAsyncRequest = TAsyncReaderPtr (TStub::*)(grpc::ClientContext*, const TRequest&, grpc::CompletionQueue*);
-
+template<typename TStub, typename TRequest, typename TResponse>
+class TAdvancedRequestProcessor
+ : public TThrRefBase
+ , public IQueueClientEvent
+ , public TGRpcRequestProcessorCommon {
+ using TAsyncReaderPtr = std::unique_ptr<grpc::ClientAsyncResponseReader<TResponse>>;
+ template<typename> friend class TServiceConnection;
+public:
+ using TPtr = TIntrusivePtr<TAdvancedRequestProcessor>;
+ using TAsyncRequest = TAsyncReaderPtr (TStub::*)(grpc::ClientContext*, const TRequest&, grpc::CompletionQueue*);
+
explicit TAdvancedRequestProcessor(TAdvancedResponseCallback<TResponse>&& callback)
: Callback_(std::move(callback))
- { }
-
- ~TAdvancedRequestProcessor() {
- if (!Replied_ && Callback_) {
- Callback_(Context, TGrpcStatus::Internal("request left unhandled"), std::move(Reply_));
- Callback_ = nullptr; // free resources as early as possible
- }
- }
-
- bool Execute(bool ok) override {
+ { }
+
+ ~TAdvancedRequestProcessor() {
+ if (!Replied_ && Callback_) {
+ Callback_(Context, TGrpcStatus::Internal("request left unhandled"), std::move(Reply_));
+ Callback_ = nullptr; // free resources as early as possible
+ }
+ }
+
+ bool Execute(bool ok) override {
{
std::unique_lock<std::mutex> guard(Mutex_);
- LocalContext.reset();
- }
- TGrpcStatus status;
- if (ok) {
- status = Status;
- } else {
- status = TGrpcStatus::Internal("Unexpected error");
- }
- Replied_ = true;
- Callback_(Context, std::move(status), std::move(Reply_));
- Callback_ = nullptr; // free resources as early as possible
- return false;
- }
-
- void Destroy() override {
- UnRef();
- }
-
-private:
- IQueueClientEvent* FinishedEvent() {
- Ref();
- return this;
- }
-
- void Start(TStub& stub, TAsyncRequest asyncRequest, const TRequest& request, IQueueClientContextProvider* provider) {
- auto context = provider->CreateContext();
- if (!context) {
- Replied_ = true;
- Callback_(Context, TGrpcStatus(grpc::StatusCode::CANCELLED, "Client is shutting down"), std::move(Reply_));
- Callback_ = nullptr;
- return;
- }
+ LocalContext.reset();
+ }
+ TGrpcStatus status;
+ if (ok) {
+ status = Status;
+ } else {
+ status = TGrpcStatus::Internal("Unexpected error");
+ }
+ Replied_ = true;
+ Callback_(Context, std::move(status), std::move(Reply_));
+ Callback_ = nullptr; // free resources as early as possible
+ return false;
+ }
+
+ void Destroy() override {
+ UnRef();
+ }
+
+private:
+ IQueueClientEvent* FinishedEvent() {
+ Ref();
+ return this;
+ }
+
+ void Start(TStub& stub, TAsyncRequest asyncRequest, const TRequest& request, IQueueClientContextProvider* provider) {
+ auto context = provider->CreateContext();
+ if (!context) {
+ Replied_ = true;
+ Callback_(Context, TGrpcStatus(grpc::StatusCode::CANCELLED, "Client is shutting down"), std::move(Reply_));
+ Callback_ = nullptr;
+ return;
+ }
{
std::unique_lock<std::mutex> guard(Mutex_);
- LocalContext = context;
- Reader_ = (stub.*asyncRequest)(&Context, request, context->CompletionQueue());
- Reader_->Finish(&Reply_, &Status, FinishedEvent());
- }
- context->SubscribeStop([self = TPtr(this)] {
- self->Stop();
- });
- }
-
- void Stop() {
- Context.TryCancel();
- }
-
- TAdvancedResponseCallback<TResponse> Callback_;
- TResponse Reply_;
+ LocalContext = context;
+ Reader_ = (stub.*asyncRequest)(&Context, request, context->CompletionQueue());
+ Reader_->Finish(&Reply_, &Status, FinishedEvent());
+ }
+ context->SubscribeStop([self = TPtr(this)] {
+ self->Stop();
+ });
+ }
+
+ void Stop() {
+ Context.TryCancel();
+ }
+
+ TAdvancedResponseCallback<TResponse> Callback_;
+ TResponse Reply_;
std::mutex Mutex_;
- TAsyncReaderPtr Reader_;
-
- bool Replied_ = false;
-};
-
+ TAsyncReaderPtr Reader_;
+
+ bool Replied_ = false;
+};
+
template<class TResponse>
class IStreamRequestReadProcessor : public TThrRefBase {
public:
@@ -1255,21 +1255,21 @@ public:
}
/*
- * Start simple request
- */
- template<typename TRequest, typename TResponse>
- void DoAdvancedRequest(const TRequest& request,
+ * Start simple request
+ */
+ template<typename TRequest, typename TResponse>
+ void DoAdvancedRequest(const TRequest& request,
TAdvancedResponseCallback<TResponse> callback,
- typename TAdvancedRequestProcessor<TStub, TRequest, TResponse>::TAsyncRequest asyncRequest,
- const TCallMeta& metas = { },
- IQueueClientContextProvider* provider = nullptr)
- {
- auto processor = MakeIntrusive<TAdvancedRequestProcessor<TStub, TRequest, TResponse>>(std::move(callback));
- processor->ApplyMeta(metas);
- processor->Start(*Stub_, asyncRequest, request, provider ? provider : Provider_);
- }
-
- /*
+ typename TAdvancedRequestProcessor<TStub, TRequest, TResponse>::TAsyncRequest asyncRequest,
+ const TCallMeta& metas = { },
+ IQueueClientContextProvider* provider = nullptr)
+ {
+ auto processor = MakeIntrusive<TAdvancedRequestProcessor<TStub, TRequest, TResponse>>(std::move(callback));
+ processor->ApplyMeta(metas);
+ processor->Start(*Stub_, asyncRequest, request, provider ? provider : Provider_);
+ }
+
+ /*
* Start bidirectional streamming
*/
template<typename TRequest, typename TResponse>
diff --git a/library/cpp/http/fetch/httpagent.h b/library/cpp/http/fetch/httpagent.h
index 96475cc05d..10696b6a3a 100644
--- a/library/cpp/http/fetch/httpagent.h
+++ b/library/cpp/http/fetch/httpagent.h
@@ -1,316 +1,316 @@
-#pragma once
-
-#include <cstdio>
-#include <cstring>
-#include <cstdlib>
-
-#include <library/cpp/uri/http_url.h>
-#include <util/datetime/base.h>
-#include <util/network/hostip.h>
-#include <util/network/ip.h>
-#include <util/network/sock.h>
-#include <util/generic/scope.h>
-#include <util/generic/utility.h>
-#include <util/string/cast.h>
-
-#include "exthttpcodes.h"
-#include "sockhandler.h"
-
-class TIpResolver {
-public:
- TAddrList Resolve(const char* host, TIpPort port) const {
- try {
- TAddrList result;
- TNetworkAddress na(host, port);
- for (auto i = na.Begin(); i != na.End(); ++i) {
- const struct addrinfo& ai = *i;
- switch (ai.ai_family) {
- case AF_INET:
- result.push_back(new NAddr::TIPv4Addr(*(sockaddr_in*)ai.ai_addr));
- break;
- case AF_INET6:
- result.push_back(new NAddr::TIPv6Addr(*(sockaddr_in6*)ai.ai_addr));
- break;
- }
- }
- return result;
- } catch (const TNetworkResolutionError&) {
- }
- return TAddrList();
- }
-};
-
-namespace NResolverHelpers {
- Y_HAS_MEMBER(Resolve);
-
- template <typename TResolver>
- std::enable_if_t<TClassHasResolve<TResolver>::value, TAddrList> Resolve(const TResolver& r, const char* host, TIpPort port) {
- return r.Resolve(host, port);
- }
-
- template <typename TResolver>
- std::enable_if_t<!TClassHasResolve<TResolver>::value, TAddrList> Resolve(const TResolver& r, const char* host, TIpPort port) {
- ui32 ip = 0;
- if (r.GetHostIP(host, &ip)) {
- // error
- return TAddrList();
- }
- if (!ip) {
- return TAddrList();
- }
-
- return TAddrList::MakeV4Addr(ip, port);
- }
-}
-
-template <typename TBase>
-class TIpResolverWrapper {
-private:
- TBase Base;
-
-public:
- TIpResolverWrapper() = default;
-
- template <typename T>
- TIpResolverWrapper(T&& base)
- : Base(std::forward(base))
- {
- }
-
- TAddrList Resolve(const char* host, TIpPort port) const {
- return NResolverHelpers::Resolve(Base, host, port);
- }
-};
-
-template <class TSocketHandler = TSimpleSocketHandler, class TDnsClient = TIpResolver>
-class THttpAgent {
-public:
- THttpAgent()
- : Persistent(0)
- , Timeout(TDuration::MicroSeconds(150))
- , Hostheader(nullptr)
- , Footer(nullptr)
- , AltFooter(nullptr)
- , PostData(nullptr)
- , PostDataLen(0)
- , Method(nullptr)
- , MethodLen(0)
- , HostheaderLen(0)
- {
- SetIdentification("YandexSomething/1.0", "webadmin@yandex.ru");
- }
-
- ~THttpAgent() {
- Disconnect();
- free(Hostheader);
- free(Footer);
- }
-
- void SetIdentification(const char* user_agent, const char* http_from) {
- free(Footer);
- size_t len = user_agent ? strlen(user_agent) + 15 : 0;
- len += http_from ? strlen(http_from) + 9 : 0;
- len += 3;
- Footer = (char*)malloc(len);
- if (user_agent)
- strcat(strcat(strcpy(Footer, "User-Agent: "), user_agent), "\r\n");
- if (http_from)
- strcat(strcat(strcat(Footer, "From: "), http_from), "\r\n");
- }
-
- void SetUserAgentFooter(const char* altFooter) {
- AltFooter = altFooter;
- }
-
- void SetPostData(const char* postData, size_t postDataLen) {
- PostData = postData;
- PostDataLen = postDataLen;
- }
-
- void SetMethod(const char* method, size_t methodLen) {
- Method = method;
- MethodLen = methodLen;
- }
-
- // deprecated
- ui32 GetIp() const {
- return Addrs.GetV4Addr().first;
- }
-
- int GetScheme() const {
- return THttpURL::SchemeHTTP;
- }
- void SetTimeout(TDuration tim) {
- Timeout = tim;
- }
-
- void SetConnectTimeout(TDuration timeout) {
- ConnectTimeout = timeout;
- }
-
- int Disconnected() {
- return !Persistent || !Socket.Good();
- }
-
- int SetHost(const char* hostname, TIpPort port) {
- Disconnect();
- TAddrList addrs = DnsClient.Resolve(hostname, port);
- if (!addrs.size()) {
- return 1;
- }
-
- SetHost(hostname, port, addrs);
- return 0;
- }
-
- int SetHost(const char* hostname, TIpPort port, const TAddrList& addrs) {
- Disconnect();
- Addrs = addrs;
- size_t reqHostheaderLen = strlen(hostname) + 20;
- if (HostheaderLen < reqHostheaderLen) {
- free(Hostheader);
- Hostheader = (char*)malloc((HostheaderLen = reqHostheaderLen));
- }
- if (port == 80)
- sprintf(Hostheader, "Host: %s\r\n", hostname);
- else
- sprintf(Hostheader, "Host: %s:%u\r\n", hostname, port);
- pHostBeg = strchr(Hostheader, ' ') + 1;
- pHostEnd = strchr(pHostBeg, '\r');
- // convert hostname to lower case since some web server don't like
- // uppper case (Task ROBOT-562)
- for (char* p = pHostBeg; p < pHostEnd; p++)
- *p = tolower(*p);
- return 0;
- }
-
- // deprecated v4-only
- int SetHost(const char* hostname, TIpPort port, ui32 ip) {
- return SetHost(hostname, port, TAddrList::MakeV4Addr(ip, port));
- }
-
- void SetHostHeader(const char* host) {
- size_t reqHostheaderLen = strlen(host) + 20;
- if (HostheaderLen < reqHostheaderLen) {
- delete[] Hostheader;
- Hostheader = new char[(HostheaderLen = reqHostheaderLen)];
- }
- sprintf(Hostheader, "Host: %s\r\n", host);
- }
-
- void SetSocket(SOCKET fd) {
- Socket.SetSocket(fd);
- }
-
- SOCKET PickOutSocket() {
- return Socket.PickOutSocket();
- }
-
- void Disconnect() {
- Socket.Disconnect();
- }
-
- ssize_t read(void* buffer, size_t buflen) {
- return Socket.read(buffer, buflen);
- }
-
- int RequestGet(const char* url, const char* const* headers, int persistent = 1, bool head_request = false) {
- if (!Addrs.size())
- return HTTP_DNS_FAILURE;
- char message[MessageMax];
- ssize_t messlen = 0;
- if (Method) {
- strncpy(message, Method, MethodLen);
- message[MethodLen] = ' ';
- messlen = MethodLen + 1;
- } else if (PostData) {
- strcpy(message, "POST ");
- messlen = 5;
- } else if (head_request) {
- strcpy(message, "HEAD ");
- messlen = 5;
- } else {
- strcpy(message, "GET ");
- messlen = 4;
- }
-#define _AppendMessage(mes) messlen += Min(MessageMax - messlen, \
- (ssize_t)strlcpy(message + messlen, (mes), MessageMax - messlen))
- _AppendMessage(url);
- _AppendMessage(" HTTP/1.1\r\n");
- if (*url == '/') //if not then Host is a proxy
- _AppendMessage(Hostheader);
- _AppendMessage("Connection: ");
- _AppendMessage(persistent ? "Keep-Alive\r\n" : "Close\r\n");
- while (headers && *headers)
- _AppendMessage(*headers++);
- if (AltFooter)
- _AppendMessage(AltFooter);
- else
- _AppendMessage(Footer);
- _AppendMessage("\r\n");
-#undef _AppendMessage
- if (messlen >= MessageMax)
- return HTTP_HEADER_TOO_LARGE;
-
- if (!Persistent)
- Disconnect();
- Persistent = persistent;
- int connected = Socket.Good();
- for (int attempt = !connected; attempt < 2; attempt++) {
- const auto connectTimeout = ConnectTimeout ? ConnectTimeout : Timeout;
- if (!Socket.Good() && Socket.Connect(Addrs, connectTimeout))
- return HTTP_CONNECT_FAILED;
-
- int sendOk = Socket.send(message, messlen);
- if (sendOk && PostData && PostDataLen)
- sendOk = Socket.send(PostData, PostDataLen);
- if (!sendOk) {
- int err = errno;
- Disconnect();
- errno = err;
- continue;
- }
-
- if (!Socket.peek()) {
- int err = errno;
- Disconnect();
- if (err == EINTR) {
- errno = err;
- return HTTP_INTERRUPTED;
- }
- } else {
- if (!persistent)
- Socket.shutdown();
- return 0;
- }
- }
- return connected ? HTTP_CONNECTION_LOST : HTTP_CONNECT_FAILED;
- }
-
-protected:
- TSocketHandler Socket;
- TIpResolverWrapper<TDnsClient> DnsClient;
- TAddrList Addrs;
- int Persistent;
- TDuration Timeout;
- TDuration ConnectTimeout;
- char *Hostheader, *Footer, *pHostBeg, *pHostEnd;
- const char* AltFooter; // alternative footer can be set by the caller
- const char* PostData;
- size_t PostDataLen;
- const char* Method;
- size_t MethodLen;
- unsigned short HostheaderLen;
+#pragma once
+
+#include <cstdio>
+#include <cstring>
+#include <cstdlib>
+
+#include <library/cpp/uri/http_url.h>
+#include <util/datetime/base.h>
+#include <util/network/hostip.h>
+#include <util/network/ip.h>
+#include <util/network/sock.h>
+#include <util/generic/scope.h>
+#include <util/generic/utility.h>
+#include <util/string/cast.h>
+
+#include "exthttpcodes.h"
+#include "sockhandler.h"
+
+class TIpResolver {
+public:
+ TAddrList Resolve(const char* host, TIpPort port) const {
+ try {
+ TAddrList result;
+ TNetworkAddress na(host, port);
+ for (auto i = na.Begin(); i != na.End(); ++i) {
+ const struct addrinfo& ai = *i;
+ switch (ai.ai_family) {
+ case AF_INET:
+ result.push_back(new NAddr::TIPv4Addr(*(sockaddr_in*)ai.ai_addr));
+ break;
+ case AF_INET6:
+ result.push_back(new NAddr::TIPv6Addr(*(sockaddr_in6*)ai.ai_addr));
+ break;
+ }
+ }
+ return result;
+ } catch (const TNetworkResolutionError&) {
+ }
+ return TAddrList();
+ }
+};
+
+namespace NResolverHelpers {
+ Y_HAS_MEMBER(Resolve);
+
+ template <typename TResolver>
+ std::enable_if_t<TClassHasResolve<TResolver>::value, TAddrList> Resolve(const TResolver& r, const char* host, TIpPort port) {
+ return r.Resolve(host, port);
+ }
+
+ template <typename TResolver>
+ std::enable_if_t<!TClassHasResolve<TResolver>::value, TAddrList> Resolve(const TResolver& r, const char* host, TIpPort port) {
+ ui32 ip = 0;
+ if (r.GetHostIP(host, &ip)) {
+ // error
+ return TAddrList();
+ }
+ if (!ip) {
+ return TAddrList();
+ }
+
+ return TAddrList::MakeV4Addr(ip, port);
+ }
+}
+
+template <typename TBase>
+class TIpResolverWrapper {
+private:
+ TBase Base;
+
+public:
+ TIpResolverWrapper() = default;
+
+ template <typename T>
+ TIpResolverWrapper(T&& base)
+ : Base(std::forward(base))
+ {
+ }
+
+ TAddrList Resolve(const char* host, TIpPort port) const {
+ return NResolverHelpers::Resolve(Base, host, port);
+ }
+};
+
+template <class TSocketHandler = TSimpleSocketHandler, class TDnsClient = TIpResolver>
+class THttpAgent {
+public:
+ THttpAgent()
+ : Persistent(0)
+ , Timeout(TDuration::MicroSeconds(150))
+ , Hostheader(nullptr)
+ , Footer(nullptr)
+ , AltFooter(nullptr)
+ , PostData(nullptr)
+ , PostDataLen(0)
+ , Method(nullptr)
+ , MethodLen(0)
+ , HostheaderLen(0)
+ {
+ SetIdentification("YandexSomething/1.0", "webadmin@yandex.ru");
+ }
+
+ ~THttpAgent() {
+ Disconnect();
+ free(Hostheader);
+ free(Footer);
+ }
+
+ void SetIdentification(const char* user_agent, const char* http_from) {
+ free(Footer);
+ size_t len = user_agent ? strlen(user_agent) + 15 : 0;
+ len += http_from ? strlen(http_from) + 9 : 0;
+ len += 3;
+ Footer = (char*)malloc(len);
+ if (user_agent)
+ strcat(strcat(strcpy(Footer, "User-Agent: "), user_agent), "\r\n");
+ if (http_from)
+ strcat(strcat(strcat(Footer, "From: "), http_from), "\r\n");
+ }
+
+ void SetUserAgentFooter(const char* altFooter) {
+ AltFooter = altFooter;
+ }
+
+ void SetPostData(const char* postData, size_t postDataLen) {
+ PostData = postData;
+ PostDataLen = postDataLen;
+ }
+
+ void SetMethod(const char* method, size_t methodLen) {
+ Method = method;
+ MethodLen = methodLen;
+ }
+
+ // deprecated
+ ui32 GetIp() const {
+ return Addrs.GetV4Addr().first;
+ }
+
+ int GetScheme() const {
+ return THttpURL::SchemeHTTP;
+ }
+ void SetTimeout(TDuration tim) {
+ Timeout = tim;
+ }
+
+ void SetConnectTimeout(TDuration timeout) {
+ ConnectTimeout = timeout;
+ }
+
+ int Disconnected() {
+ return !Persistent || !Socket.Good();
+ }
+
+ int SetHost(const char* hostname, TIpPort port) {
+ Disconnect();
+ TAddrList addrs = DnsClient.Resolve(hostname, port);
+ if (!addrs.size()) {
+ return 1;
+ }
+
+ SetHost(hostname, port, addrs);
+ return 0;
+ }
+
+ int SetHost(const char* hostname, TIpPort port, const TAddrList& addrs) {
+ Disconnect();
+ Addrs = addrs;
+ size_t reqHostheaderLen = strlen(hostname) + 20;
+ if (HostheaderLen < reqHostheaderLen) {
+ free(Hostheader);
+ Hostheader = (char*)malloc((HostheaderLen = reqHostheaderLen));
+ }
+ if (port == 80)
+ sprintf(Hostheader, "Host: %s\r\n", hostname);
+ else
+ sprintf(Hostheader, "Host: %s:%u\r\n", hostname, port);
+ pHostBeg = strchr(Hostheader, ' ') + 1;
+ pHostEnd = strchr(pHostBeg, '\r');
+ // convert hostname to lower case since some web server don't like
+ // uppper case (Task ROBOT-562)
+ for (char* p = pHostBeg; p < pHostEnd; p++)
+ *p = tolower(*p);
+ return 0;
+ }
+
+ // deprecated v4-only
+ int SetHost(const char* hostname, TIpPort port, ui32 ip) {
+ return SetHost(hostname, port, TAddrList::MakeV4Addr(ip, port));
+ }
+
+ void SetHostHeader(const char* host) {
+ size_t reqHostheaderLen = strlen(host) + 20;
+ if (HostheaderLen < reqHostheaderLen) {
+ delete[] Hostheader;
+ Hostheader = new char[(HostheaderLen = reqHostheaderLen)];
+ }
+ sprintf(Hostheader, "Host: %s\r\n", host);
+ }
+
+ void SetSocket(SOCKET fd) {
+ Socket.SetSocket(fd);
+ }
+
+ SOCKET PickOutSocket() {
+ return Socket.PickOutSocket();
+ }
+
+ void Disconnect() {
+ Socket.Disconnect();
+ }
+
+ ssize_t read(void* buffer, size_t buflen) {
+ return Socket.read(buffer, buflen);
+ }
+
+ int RequestGet(const char* url, const char* const* headers, int persistent = 1, bool head_request = false) {
+ if (!Addrs.size())
+ return HTTP_DNS_FAILURE;
+ char message[MessageMax];
+ ssize_t messlen = 0;
+ if (Method) {
+ strncpy(message, Method, MethodLen);
+ message[MethodLen] = ' ';
+ messlen = MethodLen + 1;
+ } else if (PostData) {
+ strcpy(message, "POST ");
+ messlen = 5;
+ } else if (head_request) {
+ strcpy(message, "HEAD ");
+ messlen = 5;
+ } else {
+ strcpy(message, "GET ");
+ messlen = 4;
+ }
+#define _AppendMessage(mes) messlen += Min(MessageMax - messlen, \
+ (ssize_t)strlcpy(message + messlen, (mes), MessageMax - messlen))
+ _AppendMessage(url);
+ _AppendMessage(" HTTP/1.1\r\n");
+ if (*url == '/') //if not then Host is a proxy
+ _AppendMessage(Hostheader);
+ _AppendMessage("Connection: ");
+ _AppendMessage(persistent ? "Keep-Alive\r\n" : "Close\r\n");
+ while (headers && *headers)
+ _AppendMessage(*headers++);
+ if (AltFooter)
+ _AppendMessage(AltFooter);
+ else
+ _AppendMessage(Footer);
+ _AppendMessage("\r\n");
+#undef _AppendMessage
+ if (messlen >= MessageMax)
+ return HTTP_HEADER_TOO_LARGE;
+
+ if (!Persistent)
+ Disconnect();
+ Persistent = persistent;
+ int connected = Socket.Good();
+ for (int attempt = !connected; attempt < 2; attempt++) {
+ const auto connectTimeout = ConnectTimeout ? ConnectTimeout : Timeout;
+ if (!Socket.Good() && Socket.Connect(Addrs, connectTimeout))
+ return HTTP_CONNECT_FAILED;
+
+ int sendOk = Socket.send(message, messlen);
+ if (sendOk && PostData && PostDataLen)
+ sendOk = Socket.send(PostData, PostDataLen);
+ if (!sendOk) {
+ int err = errno;
+ Disconnect();
+ errno = err;
+ continue;
+ }
+
+ if (!Socket.peek()) {
+ int err = errno;
+ Disconnect();
+ if (err == EINTR) {
+ errno = err;
+ return HTTP_INTERRUPTED;
+ }
+ } else {
+ if (!persistent)
+ Socket.shutdown();
+ return 0;
+ }
+ }
+ return connected ? HTTP_CONNECTION_LOST : HTTP_CONNECT_FAILED;
+ }
+
+protected:
+ TSocketHandler Socket;
+ TIpResolverWrapper<TDnsClient> DnsClient;
+ TAddrList Addrs;
+ int Persistent;
+ TDuration Timeout;
+ TDuration ConnectTimeout;
+ char *Hostheader, *Footer, *pHostBeg, *pHostEnd;
+ const char* AltFooter; // alternative footer can be set by the caller
+ const char* PostData;
+ size_t PostDataLen;
+ const char* Method;
+ size_t MethodLen;
+ unsigned short HostheaderLen;
static const ssize_t MessageMax = 32768;
-};
-
-struct TNoTimer {
- inline void OnBeforeSend() {
- }
- inline void OnAfterSend() {
- }
- inline void OnBeforeRecv() {
- }
- inline void OnAfterRecv() {
- }
-};
+};
+
+struct TNoTimer {
+ inline void OnBeforeSend() {
+ }
+ inline void OnAfterSend() {
+ }
+ inline void OnBeforeRecv() {
+ }
+ inline void OnAfterRecv() {
+ }
+};
diff --git a/library/cpp/http/fetch/sockhandler.h b/library/cpp/http/fetch/sockhandler.h
index e18149f657..776704ba8c 100644
--- a/library/cpp/http/fetch/sockhandler.h
+++ b/library/cpp/http/fetch/sockhandler.h
@@ -1,130 +1,130 @@
-#pragma once
-
-#include <library/cpp/logger/all.h>
-
-#include <util/generic/buffer.h>
-#include <util/generic/map.h>
-#include <util/generic/vector.h>
-#include <util/network/address.h>
-#include <util/network/ip.h>
-#include <util/network/socket.h>
-#include <util/system/mutex.h>
-#include <util/system/yassert.h>
-
-#include <cerrno>
-#include <util/generic/noncopyable.h>
-
-class TAddrList: public TVector<NAddr::IRemoteAddrRef> {
-private:
- using TBase = TVector<NAddr::IRemoteAddrRef>;
-
-public:
- //msvc doesn't support base class constructor inheritance
- TAddrList() = default;
-
- template <typename T>
- TAddrList(T&& arg)
- : TBase(std::forward<T>(arg))
- {
- }
-
- template <typename T1, typename T2>
- TAddrList(T1&& arg1, T2&& arg2)
- : TBase(std::forward<T1>(arg1), std::forward<T2>(arg2))
- {
- }
-
- TAddrList(std::initializer_list<NAddr::IRemoteAddrRef> list)
- : TBase(list)
- {
- }
-
- static TAddrList MakeV4Addr(ui32 ip, TIpPort port) {
- return TAddrList({new NAddr::TIPv4Addr(TIpAddress(htonl(ip), htons(port)))});
- }
-
- std::pair<ui32, TIpPort> GetV4Addr() const {
- for (const auto& addrRef : *this) {
- const sockaddr* sa = addrRef->Addr();
- if (sa->sa_family == AF_INET) {
- const sockaddr_in* sin = reinterpret_cast<const sockaddr_in*>(sa);
- return std::make_pair(ntohl(sin->sin_addr.s_addr), ntohs(sin->sin_port));
- }
- }
- return std::make_pair(0, 0);
- }
-};
-
-class TSimpleSocketHandler {
-public:
- TSimpleSocketHandler() = default;
-
- int Good() const {
- return static_cast<bool>(Socket);
- }
-
- int Connect(const TAddrList& addrs, TDuration timeout) {
- try {
- for (const auto& item : addrs) {
- const sockaddr* sa = item->Addr();
- TSocketHolder s(socket(sa->sa_family, SOCK_STREAM, 0));
- if (s.Closed()) {
- continue;
- }
-
-#ifndef WIN32
- if (fcntl(s, F_SETFD, FD_CLOEXEC)) // no inherit on fork()/exec()
- return errno ? errno : EBADF;
-#endif
- if (connect(s, sa, item->Len())) {
- s.Close();
- continue;
- }
-
- Socket.Reset(new TSocket(s.Release()));
- Socket->SetSocketTimeout(timeout.Seconds(), timeout.MilliSecondsOfSecond());
- Socket->SetZeroLinger();
- Socket->SetKeepAlive(true);
- return 0;
- }
- } catch (...) {
- return EBADF;
- }
- return errno ? errno : EBADF;
- }
-
- void Disconnect() {
- if (!Socket)
- return;
- Socket->ShutDown(SHUT_RDWR);
- Socket.Destroy();
- }
-
- void SetSocket(SOCKET fd) {
- Socket.Reset(new TSocket(fd));
- }
-
- void shutdown() {
- Socket->ShutDown(SHUT_WR);
- }
-
- int send(const void* message, size_t messlen) {
- return ((ssize_t)messlen == Socket->Send(message, messlen));
- }
-
- int peek() {
- char buf[1];
- return (1 == recv(*Socket, buf, 1, MSG_PEEK));
- }
-
- ssize_t read(void* buffer, size_t buflen) {
- return Socket->Recv(buffer, buflen);
- }
-
- THolder<TSocket> PickOutSocket() {
- return std::move(Socket);
- }
-
-protected:
- THolder<TSocket> Socket;
-};
+#pragma once
+
+#include <library/cpp/logger/all.h>
+
+#include <util/generic/buffer.h>
+#include <util/generic/map.h>
+#include <util/generic/vector.h>
+#include <util/network/address.h>
+#include <util/network/ip.h>
+#include <util/network/socket.h>
+#include <util/system/mutex.h>
+#include <util/system/yassert.h>
+
+#include <cerrno>
+#include <util/generic/noncopyable.h>
+
+class TAddrList: public TVector<NAddr::IRemoteAddrRef> {
+private:
+ using TBase = TVector<NAddr::IRemoteAddrRef>;
+
+public:
+ //msvc doesn't support base class constructor inheritance
+ TAddrList() = default;
+
+ template <typename T>
+ TAddrList(T&& arg)
+ : TBase(std::forward<T>(arg))
+ {
+ }
+
+ template <typename T1, typename T2>
+ TAddrList(T1&& arg1, T2&& arg2)
+ : TBase(std::forward<T1>(arg1), std::forward<T2>(arg2))
+ {
+ }
+
+ TAddrList(std::initializer_list<NAddr::IRemoteAddrRef> list)
+ : TBase(list)
+ {
+ }
+
+ static TAddrList MakeV4Addr(ui32 ip, TIpPort port) {
+ return TAddrList({new NAddr::TIPv4Addr(TIpAddress(htonl(ip), htons(port)))});
+ }
+
+ std::pair<ui32, TIpPort> GetV4Addr() const {
+ for (const auto& addrRef : *this) {
+ const sockaddr* sa = addrRef->Addr();
+ if (sa->sa_family == AF_INET) {
+ const sockaddr_in* sin = reinterpret_cast<const sockaddr_in*>(sa);
+ return std::make_pair(ntohl(sin->sin_addr.s_addr), ntohs(sin->sin_port));
+ }
+ }
+ return std::make_pair(0, 0);
+ }
+};
+
+class TSimpleSocketHandler {
+public:
+ TSimpleSocketHandler() = default;
+
+ int Good() const {
+ return static_cast<bool>(Socket);
+ }
+
+ int Connect(const TAddrList& addrs, TDuration timeout) {
+ try {
+ for (const auto& item : addrs) {
+ const sockaddr* sa = item->Addr();
+ TSocketHolder s(socket(sa->sa_family, SOCK_STREAM, 0));
+ if (s.Closed()) {
+ continue;
+ }
+
+#ifndef WIN32
+ if (fcntl(s, F_SETFD, FD_CLOEXEC)) // no inherit on fork()/exec()
+ return errno ? errno : EBADF;
+#endif
+ if (connect(s, sa, item->Len())) {
+ s.Close();
+ continue;
+ }
+
+ Socket.Reset(new TSocket(s.Release()));
+ Socket->SetSocketTimeout(timeout.Seconds(), timeout.MilliSecondsOfSecond());
+ Socket->SetZeroLinger();
+ Socket->SetKeepAlive(true);
+ return 0;
+ }
+ } catch (...) {
+ return EBADF;
+ }
+ return errno ? errno : EBADF;
+ }
+
+ void Disconnect() {
+ if (!Socket)
+ return;
+ Socket->ShutDown(SHUT_RDWR);
+ Socket.Destroy();
+ }
+
+ void SetSocket(SOCKET fd) {
+ Socket.Reset(new TSocket(fd));
+ }
+
+ void shutdown() {
+ Socket->ShutDown(SHUT_WR);
+ }
+
+ int send(const void* message, size_t messlen) {
+ return ((ssize_t)messlen == Socket->Send(message, messlen));
+ }
+
+ int peek() {
+ char buf[1];
+ return (1 == recv(*Socket, buf, 1, MSG_PEEK));
+ }
+
+ ssize_t read(void* buffer, size_t buflen) {
+ return Socket->Recv(buffer, buflen);
+ }
+
+ THolder<TSocket> PickOutSocket() {
+ return std::move(Socket);
+ }
+
+protected:
+ THolder<TSocket> Socket;
+};
diff --git a/library/cpp/http/io/stream.cpp b/library/cpp/http/io/stream.cpp
index 6689be684f..115bc9b066 100644
--- a/library/cpp/http/io/stream.cpp
+++ b/library/cpp/http/io/stream.cpp
@@ -640,15 +640,15 @@ private:
return IsRequest(FirstLine_);
}
- inline bool HasResponseBody() const noexcept {
- if (IsHttpResponse()) {
+ inline bool HasResponseBody() const noexcept {
+ if (IsHttpResponse()) {
if (Request_ && Request_->FirstLine().StartsWith(TStringBuf("HEAD")))
- return false;
+ return false;
if (FirstLine_.size() > 9 && strncmp(FirstLine_.data() + 9, "204", 3) == 0)
- return false;
- return true;
- }
- return false;
+ return false;
+ return true;
+ }
+ return false;
}
inline bool IsHttpResponse() const noexcept {
@@ -772,7 +772,7 @@ private:
}
if (IsHttpResponse()) {
- if (Request_ && IsCompressionEnabled() && HasResponseBody()) {
+ if (Request_ && IsCompressionEnabled() && HasResponseBody()) {
TString scheme = Request_->BestCompressionScheme(ComprSchemas_);
if (scheme != "identity") {
AddOrReplaceHeader(THttpInputHeader("Content-Encoding", scheme));
@@ -826,7 +826,7 @@ private:
}
}
- if (!haveContentLength && !chunked && (IsHttpRequest() || HasResponseBody()) && SupportChunkedTransfer() && (keepAlive || encoder || IsHttpRequest())) {
+ if (!haveContentLength && !chunked && (IsHttpRequest() || HasResponseBody()) && SupportChunkedTransfer() && (keepAlive || encoder || IsHttpRequest())) {
AddHeader(THttpInputHeader("Transfer-Encoding", "chunked"));
chunked = true;
}
diff --git a/library/cpp/http/ya.make b/library/cpp/http/ya.make
index fa2d1edef6..6027c72bc4 100644
--- a/library/cpp/http/ya.make
+++ b/library/cpp/http/ya.make
@@ -5,7 +5,7 @@ RECURSE(
coro
examples
fetch
- fetch_gpl
+ fetch_gpl
io
io/fuzz
io/list_codings
diff --git a/library/cpp/messagebus/message.h b/library/cpp/messagebus/message.h
index 005ca10c65..2d2c08fc09 100644
--- a/library/cpp/messagebus/message.h
+++ b/library/cpp/messagebus/message.h
@@ -56,12 +56,12 @@ namespace NBus {
void BeginWork() {
SetInWork(true);
}
-
+
// for internal use only
void EndWork() {
SetInWork(false);
}
-
+
TBusIdentity();
~TBusIdentity();
diff --git a/library/cpp/monlib/service/mon_service_http_request.cpp b/library/cpp/monlib/service/mon_service_http_request.cpp
index 5d805631d9..b22e53d370 100644
--- a/library/cpp/monlib/service/mon_service_http_request.cpp
+++ b/library/cpp/monlib/service/mon_service_http_request.cpp
@@ -42,44 +42,44 @@ const TCgiParameters& TMonService2HttpRequest::GetPostParams() const {
}
TStringBuf TMonService2HttpRequest::GetHeader(TStringBuf name) const {
- const THttpHeaders& headers = HttpRequest->GetHeaders();
- const THttpInputHeader* header = headers.FindHeader(name);
- if (header != nullptr) {
- return header->Value();
- }
- return TStringBuf();
-}
-
+ const THttpHeaders& headers = HttpRequest->GetHeaders();
+ const THttpInputHeader* header = headers.FindHeader(name);
+ if (header != nullptr) {
+ return header->Value();
+ }
+ return TStringBuf();
+}
+
const THttpHeaders& TMonService2HttpRequest::GetHeaders() const {
return HttpRequest->GetHeaders();
}
-
-TString TMonService2HttpRequest::GetRemoteAddr() const {
- return HttpRequest->GetRemoteAddr();
-}
-
+
+TString TMonService2HttpRequest::GetRemoteAddr() const {
+ return HttpRequest->GetRemoteAddr();
+}
+
TStringBuf TMonService2HttpRequest::GetCookie(TStringBuf name) const {
- TStringBuf cookie = GetHeader("Cookie");
- size_t size = cookie.size();
- size_t start = 0;
- while (start < size) {
- size_t semicolon = cookie.find(';', start);
- auto pair = cookie.substr(start, semicolon - start);
- if (!pair.empty()) {
- size_t equal = pair.find('=');
- if (equal != TStringBuf::npos) {
- auto cookieName = pair.substr(0, equal);
- if (cookieName == name) {
- size_t valueStart = equal + 1;
- auto cookieValue = pair.substr(valueStart, semicolon - valueStart);
- return cookieValue;
- }
- }
- start = semicolon;
- while (start < size && (cookie[start] == ' ' || cookie[start] == ';')) {
- ++start;
- }
- }
- }
- return TStringBuf();
-}
+ TStringBuf cookie = GetHeader("Cookie");
+ size_t size = cookie.size();
+ size_t start = 0;
+ while (start < size) {
+ size_t semicolon = cookie.find(';', start);
+ auto pair = cookie.substr(start, semicolon - start);
+ if (!pair.empty()) {
+ size_t equal = pair.find('=');
+ if (equal != TStringBuf::npos) {
+ auto cookieName = pair.substr(0, equal);
+ if (cookieName == name) {
+ size_t valueStart = equal + 1;
+ auto cookieValue = pair.substr(valueStart, semicolon - valueStart);
+ return cookieValue;
+ }
+ }
+ start = semicolon;
+ while (start < size && (cookie[start] == ' ' || cookie[start] == ';')) {
+ ++start;
+ }
+ }
+ }
+ return TStringBuf();
+}
diff --git a/library/cpp/monlib/service/mon_service_http_request.h b/library/cpp/monlib/service/mon_service_http_request.h
index b4f2f8f0c5..d46e2bcd31 100644
--- a/library/cpp/monlib/service/mon_service_http_request.h
+++ b/library/cpp/monlib/service/mon_service_http_request.h
@@ -24,7 +24,7 @@ namespace NMonitoring {
virtual const THttpHeaders& GetHeaders() const = 0;
virtual TStringBuf GetHeader(TStringBuf name) const = 0;
virtual TStringBuf GetCookie(TStringBuf name) const = 0;
- virtual TString GetRemoteAddr() const = 0;
+ virtual TString GetRemoteAddr() const = 0;
virtual TString GetServiceTitle() const = 0;
@@ -71,8 +71,8 @@ namespace NMonitoring {
TStringBuf GetHeader(TStringBuf name) const override;
TStringBuf GetCookie(TStringBuf name) const override;
const THttpHeaders& GetHeaders() const override;
- TString GetRemoteAddr() const override;
-
+ TString GetRemoteAddr() const override;
+
IMonPage* GetPage() const override {
return MonPage;
}
diff --git a/library/cpp/monlib/service/monservice.cpp b/library/cpp/monlib/service/monservice.cpp
index d1b9cda1d2..b45ba2c19b 100644
--- a/library/cpp/monlib/service/monservice.cpp
+++ b/library/cpp/monlib/service/monservice.cpp
@@ -41,14 +41,14 @@ TMonService2::TMonService2(const THttpServerOptions& options, TSimpleSharedPtr<I
TMonService2::TMonService2(ui16 port, ui32 threads, const TString& title, THolder<IAuthProvider> auth)
: TMonService2(port, TString(), threads, title, std::move(auth))
-{
-}
-
+{
+}
+
TMonService2::TMonService2(ui16 port, const TString& title, THolder<IAuthProvider> auth)
: TMonService2(port, TString(), 0, title, std::move(auth))
{
}
-
+
void TMonService2::OutputIndex(IOutputStream& out) {
IndexMonPage->OutputIndex(out, true);
}
@@ -123,7 +123,7 @@ IMonPage* TMonService2::FindPage(const TString& relativePath) {
TIndexMonPage* TMonService2::FindIndexPage(const TString& relativePath) {
return IndexMonPage->FindIndexPage(relativePath);
}
-
-void TMonService2::SortPages() {
- IndexMonPage->SortPages();
-}
+
+void TMonService2::SortPages() {
+ IndexMonPage->SortPages();
+}
diff --git a/library/cpp/monlib/service/monservice.h b/library/cpp/monlib/service/monservice.h
index 8f5e52fcdb..7a6c0383eb 100644
--- a/library/cpp/monlib/service/monservice.h
+++ b/library/cpp/monlib/service/monservice.h
@@ -20,23 +20,23 @@ namespace NMonitoring {
THolder<IAuthProvider> AuthProvider_;
public:
- static THttpServerOptions HttpServerOptions(ui16 port, const TString& host, ui32 threads) {
+ static THttpServerOptions HttpServerOptions(ui16 port, const TString& host, ui32 threads) {
THttpServerOptions opts(port);
- if (!host.empty()) {
- opts.SetHost(host);
- }
+ if (!host.empty()) {
+ opts.SetHost(host);
+ }
opts.SetClientTimeout(TDuration::Minutes(1));
opts.EnableCompression(true);
opts.SetThreads(threads);
- opts.SetMaxConnections(std::max<ui32>(100, threads));
- opts.EnableRejectExcessConnections(true);
+ opts.SetMaxConnections(std::max<ui32>(100, threads));
+ opts.EnableRejectExcessConnections(true);
return opts;
}
- static THttpServerOptions HttpServerOptions(ui16 port, ui32 threads) {
- return HttpServerOptions(port, TString(), threads);
- }
-
+ static THttpServerOptions HttpServerOptions(ui16 port, ui32 threads) {
+ return HttpServerOptions(port, TString(), threads);
+ }
+
public:
explicit TMonService2(ui16 port, const TString& title = GetProgramName(), THolder<IAuthProvider> auth = nullptr);
explicit TMonService2(ui16 port, ui32 threads, const TString& title = GetProgramName(), THolder<IAuthProvider> auth = nullptr);
diff --git a/library/cpp/monlib/service/pages/index_mon_page.cpp b/library/cpp/monlib/service/pages/index_mon_page.cpp
index 83ff8b529a..461cd30698 100644
--- a/library/cpp/monlib/service/pages/index_mon_page.cpp
+++ b/library/cpp/monlib/service/pages/index_mon_page.cpp
@@ -136,16 +136,16 @@ void TIndexMonPage::OutputBody(IMonHttpRequest& req) {
out << "<div>\n"
<< "</body>\n";
}
-
+
void TIndexMonPage::SortPages() {
- TGuard<TMutex> g(Mtx);
- std::sort(Pages.begin(), Pages.end(), [](const TMonPagePtr& a, const TMonPagePtr& b) {
+ TGuard<TMutex> g(Mtx);
+ std::sort(Pages.begin(), Pages.end(), [](const TMonPagePtr& a, const TMonPagePtr& b) {
return AsciiCompareIgnoreCase(a->GetTitle(), b->GetTitle()) < 0;
- });
-}
-
-void TIndexMonPage::ClearPages() {
- TGuard<TMutex> g(Mtx);
- Pages.clear();
- PagesByPath.clear();
-}
+ });
+}
+
+void TIndexMonPage::ClearPages() {
+ TGuard<TMutex> g(Mtx);
+ Pages.clear();
+ PagesByPath.clear();
+}
diff --git a/library/cpp/monlib/service/pages/index_mon_page.h b/library/cpp/monlib/service/pages/index_mon_page.h
index bf514a3105..ea4df882ad 100644
--- a/library/cpp/monlib/service/pages/index_mon_page.h
+++ b/library/cpp/monlib/service/pages/index_mon_page.h
@@ -32,7 +32,7 @@ namespace NMonitoring {
TIndexMonPage* FindIndexPage(const TString& relativePath);
void SortPages();
- void ClearPages();
+ void ClearPages();
};
}
diff --git a/library/cpp/monlib/service/pages/templates.h b/library/cpp/monlib/service/pages/templates.h
index b4656f059f..6a48a9229e 100644
--- a/library/cpp/monlib/service/pages/templates.h
+++ b/library/cpp/monlib/service/pages/templates.h
@@ -123,32 +123,32 @@ namespace NMonitoring {
{
Str << "<" << tag;
- if (!cls.empty()) {
+ if (!cls.empty()) {
Str << " class=\"" << cls << "\"";
}
- if (!for0.empty()) {
+ if (!for0.empty()) {
Str << " for=\"" << for0 << "\"";
}
- if (!id.empty()) {
+ if (!id.empty()) {
Str << "id=\"" << id << "\"";
}
Str << ">";
}
TTag(IOutputStream& str, std::initializer_list<std::pair<TStringBuf, TStringBuf>> attributes)
- : Str(str)
- {
- Str << "<" << tag;
- for (const std::pair<TStringBuf, TStringBuf>& attr : attributes) {
- if (!attr.second.empty()) {
- Str << ' ' << attr.first << "=\"" << attr.second << "\"";
- }
- }
- Str << ">";
- }
-
+ : Str(str)
+ {
+ Str << "<" << tag;
+ for (const std::pair<TStringBuf, TStringBuf>& attr : attributes) {
+ if (!attr.second.empty()) {
+ Str << ' ' << attr.first << "=\"" << attr.second << "\"";
+ }
+ }
+ Str << ">";
+ }
+
~TTag() {
try {
Str << "</" << tag << ">";
diff --git a/library/cpp/monlib/service/service.cpp b/library/cpp/monlib/service/service.cpp
index 929efbf816..0a87d8dff4 100644
--- a/library/cpp/monlib/service/service.cpp
+++ b/library/cpp/monlib/service/service.cpp
@@ -15,10 +15,10 @@
namespace NMonitoring {
class THttpClient: public IHttpRequest {
public:
- void ServeRequest(THttpInput& in, IOutputStream& out, const NAddr::IRemoteAddr* remoteAddr, const THandler& Handler) {
+ void ServeRequest(THttpInput& in, IOutputStream& out, const NAddr::IRemoteAddr* remoteAddr, const THandler& Handler) {
try {
try {
- RemoteAddr = remoteAddr;
+ RemoteAddr = remoteAddr;
THttpHeaderParser parser;
parser.Init(&Header);
if (parser.Execute(in.FirstLine().data(), in.FirstLine().size()) < 0) {
@@ -34,15 +34,15 @@ namespace NMonitoring {
out << "HTTP/1.1 400 Bad request\r\nConnection: Close\r\n\r\n";
return;
}
- Headers = &in.Headers();
+ Headers = &in.Headers();
CgiParams.Scan(Url.Get(THttpURL::FieldQuery));
} catch (...) {
out << "HTTP/1.1 500 Internal server error\r\nConnection: Close\r\n\r\n";
YSYSLOG(TLOG_ERR, "THttpClient: internal error while serving monitoring request: %s", CurrentExceptionMessage().data());
}
- if (Header.http_method == HTTP_METHOD_POST)
- TransferData(&in, &PostContent);
+ if (Header.http_method == HTTP_METHOD_POST)
+ TransferData(&in, &PostContent);
Handler(out, *this);
out.Finish();
@@ -64,49 +64,49 @@ namespace NMonitoring {
return CgiParams;
}
const TCgiParameters& GetPostParams() const override {
- if (PostParams.empty() && !PostContent.Buffer().Empty())
- const_cast<THttpClient*>(this)->ScanPostParams();
+ if (PostParams.empty() && !PostContent.Buffer().Empty())
+ const_cast<THttpClient*>(this)->ScanPostParams();
return PostParams;
}
- TStringBuf GetPostContent() const override {
- return TStringBuf(PostContent.Buffer().Data(), PostContent.Buffer().Size());
- }
+ TStringBuf GetPostContent() const override {
+ return TStringBuf(PostContent.Buffer().Data(), PostContent.Buffer().Size());
+ }
HTTP_METHOD GetMethod() const override {
return (HTTP_METHOD)Header.http_method;
}
- void ScanPostParams() {
+ void ScanPostParams() {
PostParams.Scan(TStringBuf(PostContent.Buffer().data(), PostContent.Buffer().size()));
- }
-
- const THttpHeaders& GetHeaders() const override {
- if (Headers != nullptr) {
- return *Headers;
- }
- static THttpHeaders defaultHeaders;
- return defaultHeaders;
- }
-
- TString GetRemoteAddr() const override {
- return RemoteAddr ? NAddr::PrintHostAndPort(*RemoteAddr) : TString();
- }
-
+ }
+
+ const THttpHeaders& GetHeaders() const override {
+ if (Headers != nullptr) {
+ return *Headers;
+ }
+ static THttpHeaders defaultHeaders;
+ return defaultHeaders;
+ }
+
+ TString GetRemoteAddr() const override {
+ return RemoteAddr ? NAddr::PrintHostAndPort(*RemoteAddr) : TString();
+ }
+
private:
THttpRequestHeader Header;
- const THttpHeaders* Headers = nullptr;
+ const THttpHeaders* Headers = nullptr;
THttpURL Url;
TCgiParameters CgiParams;
TCgiParameters PostParams;
- TBufferOutput PostContent;
- const NAddr::IRemoteAddr* RemoteAddr = nullptr;
+ TBufferOutput PostContent;
+ const NAddr::IRemoteAddr* RemoteAddr = nullptr;
};
/* TCoHttpServer */
class TCoHttpServer::TConnection: public THttpClient {
public:
- TConnection(const TCoHttpServer::TAcceptFull& acc, const TCoHttpServer& parent)
- : Socket(acc.S->Release())
- , RemoteAddr(acc.Remote)
+ TConnection(const TCoHttpServer::TAcceptFull& acc, const TCoHttpServer& parent)
+ : Socket(acc.S->Release())
+ , RemoteAddr(acc.Remote)
, Parent(parent)
{
}
@@ -119,7 +119,7 @@ namespace NMonitoring {
THttpOutput out(&io, &in);
// buffer reply so there will be ne context switching
TStringStream s;
- ServeRequest(in, s, RemoteAddr, Parent.Handler);
+ ServeRequest(in, s, RemoteAddr, Parent.Handler);
out << s.Str();
out.Finish();
} catch (...) {
@@ -129,7 +129,7 @@ namespace NMonitoring {
private:
TSocketHolder Socket;
- const NAddr::IRemoteAddr* RemoteAddr;
+ const NAddr::IRemoteAddr* RemoteAddr;
const TCoHttpServer& Parent;
};
@@ -156,7 +156,7 @@ namespace NMonitoring {
}
void TCoHttpServer::OnAcceptFull(const TAcceptFull& acc) {
- THolder<TConnection> conn(new TConnection(acc, *this));
+ THolder<TConnection> conn(new TConnection(acc, *this));
Executor.Create(*conn, "client");
Y_UNUSED(conn.Release());
}
@@ -195,7 +195,7 @@ namespace NMonitoring {
}
bool Reply(void*) override {
- ServeRequest(Input(), Output(), NAddr::GetPeerAddr(Socket()).Get(), Parent.Handler);
+ ServeRequest(Input(), Output(), NAddr::GetPeerAddr(Socket()).Get(), Parent.Handler);
return true;
}
diff --git a/library/cpp/monlib/service/service.h b/library/cpp/monlib/service/service.h
index 2f66dddaf8..0a10cf2a3d 100644
--- a/library/cpp/monlib/service/service.h
+++ b/library/cpp/monlib/service/service.h
@@ -21,10 +21,10 @@ namespace NMonitoring {
virtual const char* GetPath() const = 0;
virtual const TCgiParameters& GetParams() const = 0;
virtual const TCgiParameters& GetPostParams() const = 0;
- virtual TStringBuf GetPostContent() const = 0;
+ virtual TStringBuf GetPostContent() const = 0;
virtual HTTP_METHOD GetMethod() const = 0;
- virtual const THttpHeaders& GetHeaders() const = 0;
- virtual TString GetRemoteAddr() const = 0;
+ virtual const THttpHeaders& GetHeaders() const = 0;
+ virtual TString GetRemoteAddr() const = 0;
};
// first param - output stream to write result to
// second param - URL of request
diff --git a/library/cpp/threading/future/core/future-inl.h b/library/cpp/threading/future/core/future-inl.h
index 5fd4296a93..b67d79e301 100644
--- a/library/cpp/threading/future/core/future-inl.h
+++ b/library/cpp/threading/future/core/future-inl.h
@@ -73,22 +73,22 @@ namespace NThreading {
default:
Y_ASSERT(state == ValueSet);
}
- }
-
+ }
+
public:
TFutureState()
: State(NotReady)
, NullValue(0)
{
- }
-
+ }
+
template <typename TT>
TFutureState(TT&& value)
: State(ValueSet)
, Value(std::forward<TT>(value))
{
}
-
+
TFutureState(std::exception_ptr exception, TError)
: State(ExceptionSet)
, Exception(std::move(exception))
@@ -101,11 +101,11 @@ namespace NThreading {
Value.~T();
}
}
-
+
bool HasValue() const {
return AtomicGet(State) >= ValueMoved; // ValueMoved, ValueSet, ValueRead
- }
-
+ }
+
void TryRethrow() const {
int state = AtomicGet(State);
TryRethrowWithState(state);
@@ -148,7 +148,7 @@ namespace NThreading {
readyEvent = ReadyEvent.Get();
callbacks = std::move(Callbacks);
-
+
AtomicSet(State, ValueSet);
}
@@ -635,7 +635,7 @@ namespace NThreading {
});
return promise;
}
-
+
template <typename T>
inline bool TFuture<T>::Initialized() const {
return bool(State);
@@ -790,7 +790,7 @@ namespace NThreading {
EnsureInitialized();
State->SetValue(value);
}
-
+
template <typename T>
inline void TPromise<T>::SetValue(T&& value) {
EnsureInitialized();
diff --git a/library/cpp/threading/future/future_ut.cpp b/library/cpp/threading/future/future_ut.cpp
index 05950a568d..8dc8788086 100644
--- a/library/cpp/threading/future/future_ut.cpp
+++ b/library/cpp/threading/future/future_ut.cpp
@@ -447,15 +447,15 @@ namespace {
explicit TRec(int) {
}
};
-
+
auto promise = NewPromise<TRec>();
promise.SetValue(TRec(1));
-
+
auto future = MakeFuture(TRec(1));
auto rec = future.ExtractValue();
Y_UNUSED(rec);
}
-
+
Y_UNIT_TEST(ShouldNotExtractAfterGet) {
TPromise<int> promise = NewPromise<int>();
promise.SetValue(123);
@@ -463,7 +463,7 @@ namespace {
UNIT_ASSERT_EQUAL(promise.GetValue(), 123);
UNIT_CHECK_GENERATED_EXCEPTION(promise.ExtractValue(), TFutureException);
}
-
+
Y_UNIT_TEST(ShouldNotGetAfterExtract) {
TPromise<int> promise = NewPromise<int>();
promise.SetValue(123);
@@ -471,7 +471,7 @@ namespace {
UNIT_ASSERT_EQUAL(promise.ExtractValue(), 123);
UNIT_CHECK_GENERATED_EXCEPTION(promise.GetValue(), TFutureException);
}
-
+
Y_UNIT_TEST(ShouldNotExtractAfterExtract) {
TPromise<int> promise = NewPromise<int>();
promise.SetValue(123);
@@ -635,6 +635,6 @@ namespace {
TestApplyLvalueCopyImpl<void>();
TestApplyLvalueCopyImpl<int>();
}
- }
-
+ }
+
}