http_common.h 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. #pragma once
  2. #include <util/generic/array_ref.h>
  3. #include <util/generic/flags.h>
  4. #include <util/generic/ptr.h>
  5. #include <util/generic/vector.h>
  6. #include <util/stream/mem.h>
  7. #include <util/stream/output.h>
  8. #include <library/cpp/deprecated/atomic/atomic.h>
  9. #include "location.h"
  10. #include "neh.h"
  11. #include "rpc.h"
  12. #include <atomic>
  13. //common primitives for http/http2
  14. namespace NNeh {
  15. struct THttpErrorDetails {
  16. TString Details = {};
  17. TString Headers = {};
  18. };
  19. class IHttpRequest: public IRequest {
  20. public:
  21. using IRequest::SendReply;
  22. virtual void SendReply(TData& data, const TString& headers, int httpCode = 200) = 0;
  23. virtual const THttpHeaders& Headers() const = 0;
  24. virtual TStringBuf Method() const = 0;
  25. virtual TStringBuf Body() const = 0;
  26. virtual TStringBuf Cgi() const = 0;
  27. void SendError(TResponseError err, const TString& details = TString()) override final {
  28. SendError(err, THttpErrorDetails{.Details = details});
  29. }
  30. virtual void SendError(TResponseError err, const THttpErrorDetails& details) = 0;
  31. };
  32. namespace NHttp {
  33. enum class EResolverType {
  34. ETCP = 0,
  35. EUNIXSOCKET = 1
  36. };
  37. struct TFdLimits {
  38. public:
  39. TFdLimits()
  40. : Soft_(10000)
  41. , Hard_(15000)
  42. {
  43. }
  44. TFdLimits(const TFdLimits& other) {
  45. Soft_.store(other.Soft(), std::memory_order_release);
  46. Hard_.store(other.Hard(), std::memory_order_release);
  47. }
  48. inline size_t Delta() const noexcept {
  49. return ExceedLimit(Hard_.load(std::memory_order_acquire), Soft_.load(std::memory_order_acquire));
  50. }
  51. inline static size_t ExceedLimit(size_t val, size_t limit) noexcept {
  52. return val > limit ? val - limit : 0;
  53. }
  54. void SetSoft(size_t value) noexcept {
  55. Soft_.store(value, std::memory_order_release);
  56. }
  57. void SetHard(size_t value) noexcept {
  58. Hard_.store(value, std::memory_order_release);
  59. }
  60. size_t Soft() const noexcept {
  61. return Soft_.load(std::memory_order_acquire);
  62. }
  63. size_t Hard() const noexcept {
  64. return Hard_.load(std::memory_order_acquire);
  65. }
  66. private:
  67. std::atomic<size_t> Soft_;
  68. std::atomic<size_t> Hard_;
  69. };
  70. template <class T>
  71. class TLockFreeSequence {
  72. public:
  73. inline TLockFreeSequence() {
  74. memset((void*)T_, 0, sizeof(T_));
  75. }
  76. inline ~TLockFreeSequence() {
  77. for (size_t i = 0; i < Y_ARRAY_SIZE(T_); ++i) {
  78. delete[] T_[i];
  79. }
  80. }
  81. inline T& Get(size_t n) {
  82. const size_t i = GetValueBitCount(n + 1) - 1;
  83. return GetList(i)[n + 1 - (((size_t)1) << i)];
  84. }
  85. private:
  86. inline T* GetList(size_t n) {
  87. T* volatile* t = T_ + n;
  88. T* result;
  89. while (!(result = AtomicGet(*t))) {
  90. TArrayHolder<T> nt(new T[((size_t)1) << n]);
  91. if (AtomicCas(t, nt.Get(), nullptr)) {
  92. return nt.Release();
  93. }
  94. }
  95. return result;
  96. }
  97. private:
  98. T* volatile T_[sizeof(size_t) * 8];
  99. };
  100. class TRequestData: public TNonCopyable {
  101. public:
  102. using TPtr = TAutoPtr<TRequestData>;
  103. using TParts = TVector<IOutputStream::TPart>;
  104. inline TRequestData(size_t memSize)
  105. : Mem(memSize)
  106. {
  107. }
  108. inline void SendTo(IOutputStream& io) const {
  109. io.Write(Parts_.data(), Parts_.size());
  110. }
  111. inline void AddPart(const void* buf, size_t len) noexcept {
  112. Parts_.push_back(IOutputStream::TPart(buf, len));
  113. }
  114. const TParts& Parts() const noexcept {
  115. return Parts_;
  116. }
  117. TVector<char> Mem;
  118. TString Data;
  119. private:
  120. TParts Parts_;
  121. };
  122. struct TRequestSettings {
  123. bool NoDelay = true;
  124. EResolverType ResolverType = EResolverType::ETCP;
  125. TRequestSettings& SetNoDelay(bool noDelay) {
  126. NoDelay = noDelay;
  127. return *this;
  128. }
  129. TRequestSettings& SetResolverType(EResolverType resolverType) {
  130. ResolverType = resolverType;
  131. return *this;
  132. }
  133. };
  134. struct TRequestGet {
  135. static TRequestData::TPtr Build(const TMessage& msg, const TParsedLocation& loc) {
  136. TRequestData::TPtr req(new TRequestData(50 + loc.Service.size() + msg.Data.size() + loc.Host.size()));
  137. TMemoryOutput out(req->Mem.data(), req->Mem.size());
  138. out << TStringBuf("GET /") << loc.Service;
  139. if (!!msg.Data) {
  140. out << '?' << msg.Data;
  141. }
  142. out << TStringBuf(" HTTP/1.1\r\nHost: ") << loc.Host;
  143. if (!!loc.Port) {
  144. out << TStringBuf(":") << loc.Port;
  145. }
  146. out << TStringBuf("\r\n\r\n");
  147. req->AddPart(req->Mem.data(), out.Buf() - req->Mem.data());
  148. return req;
  149. }
  150. static inline TStringBuf Name() noexcept {
  151. return TStringBuf("http");
  152. }
  153. static TRequestSettings RequestSettings() {
  154. return TRequestSettings();
  155. }
  156. };
  157. struct TRequestPost {
  158. static TRequestData::TPtr Build(const TMessage& msg, const TParsedLocation& loc) {
  159. TRequestData::TPtr req(new TRequestData(100 + loc.Service.size() + loc.Host.size()));
  160. TMemoryOutput out(req->Mem.data(), req->Mem.size());
  161. out << TStringBuf("POST /") << loc.Service
  162. << TStringBuf(" HTTP/1.1\r\nHost: ") << loc.Host;
  163. if (!!loc.Port) {
  164. out << TStringBuf(":") << loc.Port;
  165. }
  166. out << TStringBuf("\r\nContent-Length: ") << msg.Data.size() << TStringBuf("\r\n\r\n");
  167. req->AddPart(req->Mem.data(), out.Buf() - req->Mem.data());
  168. req->AddPart(msg.Data.data(), msg.Data.size());
  169. req->Data = msg.Data;
  170. return req;
  171. }
  172. static inline TStringBuf Name() noexcept {
  173. return TStringBuf("post");
  174. }
  175. static TRequestSettings RequestSettings() {
  176. return TRequestSettings();
  177. }
  178. };
  179. struct TRequestFull {
  180. static TRequestData::TPtr Build(const TMessage& msg, const TParsedLocation&) {
  181. TRequestData::TPtr req(new TRequestData(0));
  182. req->AddPart(msg.Data.data(), msg.Data.size());
  183. req->Data = msg.Data;
  184. return req;
  185. }
  186. static inline TStringBuf Name() noexcept {
  187. return TStringBuf("full");
  188. }
  189. static TRequestSettings RequestSettings() {
  190. return TRequestSettings();
  191. }
  192. };
  193. enum class ERequestType {
  194. Any = 0 /* "ANY" */,
  195. Post /* "POST" */,
  196. Get /* "GET" */,
  197. Put /* "PUT" */,
  198. Delete /* "DELETE" */,
  199. Patch /* "PATCH" */,
  200. };
  201. enum class ERequestFlag {
  202. None = 0,
  203. /** use absoulte uri for proxy requests in the first request line
  204. * POST http://ya.ru HTTP/1.1
  205. * @see https://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5.1.2
  206. */
  207. AbsoluteUri = 1,
  208. };
  209. Y_DECLARE_FLAGS(ERequestFlags, ERequestFlag);
  210. Y_DECLARE_OPERATORS_FOR_FLAGS(ERequestFlags);
  211. static constexpr ERequestType DefaultRequestType = ERequestType::Any;
  212. extern const TStringBuf DefaultContentType;
  213. /// @brief `MakeFullRequest` transmutes http/post/http2/post2 message to full/full2 with
  214. /// additional HTTP headers and/or content data.
  215. ///
  216. /// If reqType is `Any`, then request type is POST, unless content is empty and schema
  217. /// prefix is http/https/http2, in that case request type is GET.
  218. ///
  219. /// @msg[in] Will get URL from `msg.Data`.
  220. bool MakeFullRequest(TMessage& msg, TStringBuf headers, TStringBuf content, TStringBuf contentType = DefaultContentType, ERequestType reqType = DefaultRequestType, ERequestFlags flags = ERequestFlag::None);
  221. /// @see `MakeFullrequest`.
  222. ///
  223. /// @urlParts[in] Will construct url from `urlParts`, `msg.Data` is not used.
  224. bool MakeFullRequest(TMessage& msg, TConstArrayRef<TString> urlParts, TStringBuf headers, TStringBuf content, TStringBuf contentType = DefaultContentType, ERequestType reqType = DefaultRequestType, ERequestFlags flags = ERequestFlag::None);
  225. /// Same as `MakeFullRequest` but it will add ERequestFlag::AbsoluteUri to the @a flags
  226. /// and replace msg.Addr with @a proxyAddr
  227. ///
  228. /// @see `MakeFullrequest`.
  229. bool MakeFullProxyRequest(TMessage& msg, TStringBuf proxyAddr, TStringBuf headers, TStringBuf content, TStringBuf contentType = DefaultContentType, ERequestType reqType = DefaultRequestType, ERequestFlags flags = ERequestFlag::None);
  230. size_t GetUrlPartsLength(TConstArrayRef<TString> urlParts);
  231. //part1&part2&...
  232. void JoinUrlParts(TConstArrayRef<TString> urlParts, IOutputStream& out);
  233. //'?' + JoinUrlParts
  234. void WriteUrlParts(TConstArrayRef<TString> urlParts, IOutputStream& out);
  235. bool IsHttpScheme(TStringBuf scheme);
  236. }
  237. }