http.cpp 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823
  1. #include "http.h"
  2. #include <library/cpp/string_utils/quote/quote.h>
  3. inline TStringBuf operator +(TStringBuf l, TStringBuf r) {
  4. if (l.empty()) {
  5. return r;
  6. }
  7. if (r.empty()) {
  8. return l;
  9. }
  10. if (l.end() == r.begin()) {
  11. return TStringBuf(l.data(), l.size() + r.size());
  12. }
  13. if (r.end() == l.begin()) {
  14. return TStringBuf(r.data(), l.size() + r.size());
  15. }
  16. Y_FAIL("oops");
  17. return TStringBuf();
  18. }
  19. inline TStringBuf operator +=(TStringBuf& l, TStringBuf r) {
  20. return l = l + r;
  21. }
  22. static bool is_not_number(TStringBuf v) {
  23. return v.empty() || std::find_if_not(v.begin(), v.end(), [](unsigned char c) { return std::isdigit(c); }) != v.end();
  24. }
  25. namespace NHttp {
  26. template <> TStringBuf THttpRequest::GetName<&THttpRequest::Host>() { return "Host"; }
  27. template <> TStringBuf THttpRequest::GetName<&THttpRequest::Accept>() { return "Accept"; }
  28. template <> TStringBuf THttpRequest::GetName<&THttpRequest::Connection>() { return "Connection"; }
  29. template <> TStringBuf THttpRequest::GetName<&THttpRequest::ContentType>() { return "Content-Type"; }
  30. template <> TStringBuf THttpRequest::GetName<&THttpRequest::ContentLength>() { return "Content-Length"; }
  31. template <> TStringBuf THttpRequest::GetName<&THttpRequest::TransferEncoding>() { return "Transfer-Encoding"; }
  32. template <> TStringBuf THttpRequest::GetName<&THttpRequest::AcceptEncoding>() { return "Accept-Encoding"; }
  33. const TMap<TStringBuf, TStringBuf THttpRequest::*, TLessNoCase> THttpRequest::HeadersLocation = {
  34. { THttpRequest::GetName<&THttpRequest::Host>(), &THttpRequest::Host },
  35. { THttpRequest::GetName<&THttpRequest::Accept>(), &THttpRequest::Accept },
  36. { THttpRequest::GetName<&THttpRequest::Connection>(), &THttpRequest::Connection },
  37. { THttpRequest::GetName<&THttpRequest::ContentType>(), &THttpRequest::ContentType },
  38. { THttpRequest::GetName<&THttpRequest::ContentLength>(), &THttpRequest::ContentLength },
  39. { THttpRequest::GetName<&THttpRequest::TransferEncoding>(), &THttpRequest::TransferEncoding },
  40. { THttpRequest::GetName<&THttpRequest::AcceptEncoding>(), &THttpRequest::AcceptEncoding },
  41. };
  42. template <> TStringBuf THttpResponse::GetName<&THttpResponse::Connection>() { return "Connection"; }
  43. template <> TStringBuf THttpResponse::GetName<&THttpResponse::ContentType>() { return "Content-Type"; }
  44. template <> TStringBuf THttpResponse::GetName<&THttpResponse::ContentLength>() { return "Content-Length"; }
  45. template <> TStringBuf THttpResponse::GetName<&THttpResponse::TransferEncoding>() { return "Transfer-Encoding"; }
  46. template <> TStringBuf THttpResponse::GetName<&THttpResponse::LastModified>() { return "Last-Modified"; }
  47. template <> TStringBuf THttpResponse::GetName<&THttpResponse::ContentEncoding>() { return "Content-Encoding"; }
  48. const TMap<TStringBuf, TStringBuf THttpResponse::*, TLessNoCase> THttpResponse::HeadersLocation = {
  49. { THttpResponse::GetName<&THttpResponse::Connection>(), &THttpResponse::Connection },
  50. { THttpResponse::GetName<&THttpResponse::ContentType>(), &THttpResponse::ContentType },
  51. { THttpResponse::GetName<&THttpResponse::ContentLength>(), &THttpResponse::ContentLength },
  52. { THttpResponse::GetName<&THttpResponse::TransferEncoding>(), &THttpResponse::TransferEncoding },
  53. { THttpResponse::GetName<&THttpResponse::LastModified>(), &THttpResponse::LastModified },
  54. { THttpResponse::GetName<&THttpResponse::ContentEncoding>(), &THttpResponse::ContentEncoding }
  55. };
  56. void THttpRequest::Clear() {
  57. // a dirty little trick
  58. this->~THttpRequest(); // basically, do nothing
  59. new (this) THttpRequest(); // reset all fields
  60. }
  61. template <>
  62. bool THttpParser<THttpRequest, TSocketBuffer>::HaveBody() const {
  63. if (!Body.empty()) {
  64. return true;
  65. }
  66. return !ContentLength.empty() || !TransferEncoding.empty();
  67. }
  68. template <>
  69. void THttpParser<THttpRequest, TSocketBuffer>::Advance(size_t len) {
  70. TStringBuf data(Pos(), len);
  71. while (!data.empty()) {
  72. if (Stage != EParseStage::Error) {
  73. LastSuccessStage = Stage;
  74. }
  75. switch (Stage) {
  76. case EParseStage::Method: {
  77. if (ProcessData(Method, data, ' ', MaxMethodSize)) {
  78. Stage = EParseStage::URL;
  79. }
  80. break;
  81. }
  82. case EParseStage::URL: {
  83. if (ProcessData(URL, data, ' ', MaxURLSize)) {
  84. Stage = EParseStage::Protocol;
  85. }
  86. break;
  87. }
  88. case EParseStage::Protocol: {
  89. if (ProcessData(Protocol, data, '/', MaxProtocolSize)) {
  90. Stage = EParseStage::Version;
  91. }
  92. break;
  93. }
  94. case EParseStage::Version: {
  95. if (ProcessData(Version, data, "\r\n", MaxVersionSize)) {
  96. Stage = EParseStage::Header;
  97. Headers = data;
  98. }
  99. break;
  100. }
  101. case EParseStage::Header: {
  102. if (ProcessData(Header, data, "\r\n", MaxHeaderSize)) {
  103. if (Header.empty()) {
  104. if (HaveBody() && (ContentLength.empty() || ContentLength != "0")) {
  105. Stage = EParseStage::Body;
  106. } else if (TotalSize.has_value() && !data.empty()) {
  107. Stage = EParseStage::Body;
  108. } else {
  109. Stage = EParseStage::Done;
  110. }
  111. } else {
  112. ProcessHeader(Header);
  113. }
  114. Headers = TStringBuf(Headers.data(), data.data() - Headers.data());
  115. }
  116. if (Stage != EParseStage::Body) {
  117. break;
  118. }
  119. [[fallthrough]];
  120. }
  121. case EParseStage::Body: {
  122. if (TEqNoCase()(TransferEncoding, "chunked")) {
  123. Stage = EParseStage::ChunkLength;
  124. } else if (!ContentLength.empty()) {
  125. if (is_not_number(ContentLength)) {
  126. // Invalid content length
  127. Stage = EParseStage::Error;
  128. } else if (ProcessData(Content, data, FromStringWithDefault(ContentLength, 0))) {
  129. Body = Content;
  130. Stage = EParseStage::Done;
  131. }
  132. } else if (TotalSize.has_value()) {
  133. if (ProcessData(Content, data, GetBodySizeFromTotalSize())) {
  134. Body = Content;
  135. Stage = EParseStage::Done;
  136. }
  137. } else {
  138. // Invalid body encoding
  139. Stage = EParseStage::Error;
  140. }
  141. break;
  142. }
  143. case EParseStage::ChunkLength: {
  144. if (ProcessData(Line, data, "\r\n", MaxChunkLengthSize)) {
  145. if (!Line.empty()) {
  146. ChunkLength = ParseHex(Line);
  147. if (ChunkLength <= MaxChunkSize) {
  148. ContentSize = Content.size() + ChunkLength;
  149. if (ContentSize <= MaxChunkContentSize) {
  150. Stage = EParseStage::ChunkData;
  151. Line.Clear();
  152. } else {
  153. // Invalid chunk content length
  154. Stage = EParseStage::Error;
  155. }
  156. } else {
  157. // Invalid chunk length
  158. Stage = EParseStage::Error;
  159. }
  160. } else {
  161. // Invalid body encoding
  162. Stage = EParseStage::Error;
  163. }
  164. }
  165. break;
  166. }
  167. case EParseStage::ChunkData: {
  168. if (!IsError()) {
  169. if (ProcessData(Content, data, ContentSize)) {
  170. if (ProcessData(Line, data, 2)) {
  171. if (Line == "\r\n") {
  172. if (ChunkLength == 0) {
  173. Body = Content;
  174. Stage = EParseStage::Done;
  175. } else {
  176. Stage = EParseStage::ChunkLength;
  177. }
  178. Line.Clear();
  179. } else {
  180. // Invalid body encoding
  181. Stage = EParseStage::Error;
  182. }
  183. }
  184. }
  185. }
  186. break;
  187. }
  188. case EParseStage::Done:
  189. case EParseStage::Error: {
  190. data.Clear();
  191. break;
  192. }
  193. default:
  194. Y_FAIL("Invalid processing sequence");
  195. break;
  196. }
  197. }
  198. TSocketBuffer::Advance(len);
  199. }
  200. template <>
  201. THttpParser<THttpRequest, TSocketBuffer>::EParseStage THttpParser<THttpRequest, TSocketBuffer>::GetInitialStage() {
  202. return EParseStage::Method;
  203. }
  204. template <>
  205. bool THttpParser<THttpResponse, TSocketBuffer>::HaveBody() const {
  206. if (!Body.empty()) {
  207. return true;
  208. }
  209. return (!Status.starts_with("1") && Status != "204" && Status != "304")
  210. && (!ContentType.empty() || !ContentLength.empty() || !TransferEncoding.empty());
  211. }
  212. template <>
  213. THttpParser<THttpResponse, TSocketBuffer>::EParseStage THttpParser<THttpResponse, TSocketBuffer>::GetInitialStage() {
  214. return EParseStage::Protocol;
  215. }
  216. void THttpResponse::Clear() {
  217. // a dirty little trick
  218. this->~THttpResponse(); // basically, do nothing
  219. new (this) THttpResponse(); // reset all fields
  220. }
  221. template <>
  222. void THttpParser<THttpResponse, TSocketBuffer>::Advance(size_t len) {
  223. TStringBuf data(Pos(), len);
  224. while (!data.empty()) {
  225. if (Stage != EParseStage::Error) {
  226. LastSuccessStage = Stage;
  227. }
  228. switch (Stage) {
  229. case EParseStage::Protocol: {
  230. if (ProcessData(Protocol, data, '/', MaxProtocolSize)) {
  231. Stage = EParseStage::Version;
  232. }
  233. break;
  234. }
  235. case EParseStage::Version: {
  236. if (ProcessData(Version, data, ' ', MaxVersionSize)) {
  237. Stage = EParseStage::Status;
  238. }
  239. break;
  240. }
  241. case EParseStage::Status: {
  242. if (ProcessData(Status, data, ' ', MaxStatusSize)) {
  243. Stage = EParseStage::Message;
  244. }
  245. break;
  246. }
  247. case EParseStage::Message: {
  248. if (ProcessData(Message, data, "\r\n", MaxMessageSize)) {
  249. Stage = EParseStage::Header;
  250. Headers = TStringBuf(data.data(), size_t(0));
  251. }
  252. break;
  253. }
  254. case EParseStage::Header: {
  255. if (ProcessData(Header, data, "\r\n", MaxHeaderSize)) {
  256. if (Header.empty()) {
  257. if (HaveBody() && (ContentLength.empty() || ContentLength != "0")) {
  258. Stage = EParseStage::Body;
  259. } else if (TotalSize.has_value() && !data.empty()) {
  260. Stage = EParseStage::Body;
  261. } else {
  262. Stage = EParseStage::Done;
  263. }
  264. } else {
  265. ProcessHeader(Header);
  266. }
  267. Headers = TStringBuf(Headers.data(), data.data() - Headers.data());
  268. }
  269. if (Stage != EParseStage::Body) {
  270. break;
  271. }
  272. [[fallthrough]];
  273. }
  274. case EParseStage::Body: {
  275. if (TEqNoCase()(TransferEncoding, "chunked")) {
  276. Stage = EParseStage::ChunkLength;
  277. } else if (!ContentLength.empty()) {
  278. if (is_not_number(ContentLength)) {
  279. // Invalid content length
  280. Stage = EParseStage::Error;
  281. } else if (ProcessData(Body, data, FromStringWithDefault(ContentLength, 0))) {
  282. Stage = EParseStage::Done;
  283. if (Body && ContentEncoding == "deflate") {
  284. Content = DecompressDeflate(Body);
  285. Body = Content;
  286. }
  287. }
  288. } else if (TotalSize.has_value()) {
  289. if (ProcessData(Content, data, GetBodySizeFromTotalSize())) {
  290. Body = Content;
  291. Stage = EParseStage::Done;
  292. if (Body && ContentEncoding == "deflate") {
  293. Content = DecompressDeflate(Body);
  294. Body = Content;
  295. }
  296. }
  297. } else {
  298. // Invalid body encoding
  299. Stage = EParseStage::Error;
  300. }
  301. break;
  302. }
  303. case EParseStage::ChunkLength: {
  304. if (ProcessData(Line, data, "\r\n", MaxChunkLengthSize)) {
  305. if (!Line.empty()) {
  306. ChunkLength = ParseHex(Line);
  307. if (ChunkLength <= MaxChunkSize) {
  308. ContentSize = Content.size() + ChunkLength;
  309. if (ContentSize <= MaxChunkContentSize) {
  310. Stage = EParseStage::ChunkData;
  311. Line.Clear();
  312. } else {
  313. // Invalid chunk content length
  314. Stage = EParseStage::Error;
  315. }
  316. } else {
  317. // Invalid chunk length
  318. Stage = EParseStage::Error;
  319. }
  320. } else {
  321. // Invalid body encoding
  322. Stage = EParseStage::Error;
  323. }
  324. }
  325. break;
  326. }
  327. case EParseStage::ChunkData: {
  328. if (!IsError()) {
  329. if (ProcessData(Content, data, ContentSize)) {
  330. if (ProcessData(Line, data, 2)) {
  331. if (Line == "\r\n") {
  332. if (ChunkLength == 0) {
  333. Body = Content;
  334. Stage = EParseStage::Done;
  335. if (Body && ContentEncoding == "deflate") {
  336. Content = DecompressDeflate(Body);
  337. Body = Content;
  338. }
  339. } else {
  340. Stage = EParseStage::ChunkLength;
  341. }
  342. Line.Clear();
  343. } else {
  344. // Invalid body encoding
  345. Stage = EParseStage::Error;
  346. }
  347. }
  348. }
  349. }
  350. break;
  351. }
  352. case EParseStage::Done:
  353. case EParseStage::Error:
  354. data.Clear();
  355. break;
  356. default:
  357. // Invalid processing sequence
  358. Stage = EParseStage::Error;
  359. break;
  360. }
  361. }
  362. TSocketBuffer::Advance(len);
  363. }
  364. template <>
  365. void THttpParser<THttpResponse, TSocketBuffer>::ConnectionClosed() {
  366. if (Stage == EParseStage::Done) {
  367. return;
  368. }
  369. if (Stage == EParseStage::Body) {
  370. // ?
  371. Stage = EParseStage::Done;
  372. } else {
  373. LastSuccessStage = Stage;
  374. Stage = EParseStage::Error;
  375. }
  376. }
  377. THttpOutgoingResponsePtr THttpIncomingRequest::CreateResponseString(TStringBuf data) {
  378. THttpParser<THttpResponse, TSocketBuffer> parser(data);
  379. THeadersBuilder headers(parser.Headers);
  380. if (!Endpoint->WorkerName.empty()) {
  381. headers.Set("X-Worker-Name", Endpoint->WorkerName);
  382. }
  383. THttpOutgoingResponsePtr response = new THttpOutgoingResponse(this);
  384. response->InitResponse(parser.Protocol, parser.Version, parser.Status, parser.Message);
  385. if (parser.HaveBody()) {
  386. if (parser.ContentType && !Endpoint->CompressContentTypes.empty()) {
  387. TStringBuf contentType = parser.ContentType.Before(';');
  388. Trim(contentType, ' ');
  389. if (Count(Endpoint->CompressContentTypes, contentType) != 0) {
  390. if (response->EnableCompression()) {
  391. headers.Erase("Content-Length"); // we will need new length after compression
  392. }
  393. }
  394. }
  395. headers.Erase("Transfer-Encoding"); // we erase transfer-encoding because we convert body to content-length
  396. response->Set(headers);
  397. response->SetBody(parser.Body);
  398. } else {
  399. headers.Erase("Transfer-Encoding"); // we erase transfer-encoding because we convert body to content-length
  400. response->Set(headers);
  401. if (!response->ContentLength) {
  402. response->Set<&THttpResponse::ContentLength>("0");
  403. }
  404. }
  405. return response;
  406. }
  407. THttpOutgoingResponsePtr THttpIncomingRequest::CreateResponseOK(TStringBuf body, TStringBuf contentType, TInstant lastModified) {
  408. return CreateResponse("200", "OK", contentType, body, lastModified);
  409. }
  410. THttpOutgoingResponsePtr THttpIncomingRequest::CreateResponseBadRequest(TStringBuf html, TStringBuf contentType) {
  411. if (html.empty() && IsError()) {
  412. contentType = "text/plain";
  413. html = GetErrorText();
  414. }
  415. return CreateResponse("400", "Bad Request", contentType, html);
  416. }
  417. THttpOutgoingResponsePtr THttpIncomingRequest::CreateResponseNotFound(TStringBuf html, TStringBuf contentType) {
  418. return CreateResponse("404", "Not Found", contentType, html);
  419. }
  420. THttpOutgoingResponsePtr THttpIncomingRequest::CreateResponseServiceUnavailable(TStringBuf html, TStringBuf contentType) {
  421. return CreateResponse("503", "Service Unavailable", contentType, html);
  422. }
  423. THttpOutgoingResponsePtr THttpIncomingRequest::CreateResponseGatewayTimeout(TStringBuf html, TStringBuf contentType) {
  424. return CreateResponse("504", "Gateway Timeout", contentType, html);
  425. }
  426. THttpIncomingResponse::THttpIncomingResponse(THttpOutgoingRequestPtr request)
  427. : Request(request)
  428. {}
  429. THttpOutgoingResponsePtr THttpIncomingRequest::ConstructResponse(TStringBuf status, TStringBuf message) {
  430. TStringBuf version = Version;
  431. if (version != "1.0" && version != "1.1") {
  432. version = "1.1";
  433. }
  434. THttpOutgoingResponsePtr response = new THttpOutgoingResponse(this, "HTTP", version, status, message);
  435. return response;
  436. }
  437. THttpOutgoingResponsePtr THttpIncomingRequest::CreateIncompleteResponse(TStringBuf status, TStringBuf message, const THeaders& headers) {
  438. THttpOutgoingResponsePtr response = ConstructResponse(status, message);
  439. if (!headers.Has("Connection")) {
  440. response->Set<&THttpResponse::Connection>(GetConnection());
  441. }
  442. if (!headers.Has("X-Worker-Name")) {
  443. if (!Endpoint->WorkerName.empty()) {
  444. response->Set("X-Worker-Name", Endpoint->WorkerName);
  445. }
  446. }
  447. response->Set(headers);
  448. return response;
  449. }
  450. THttpOutgoingResponsePtr THttpIncomingRequest::CreateIncompleteResponse(TStringBuf status, TStringBuf message, const THeaders& headers, TStringBuf body) {
  451. THttpOutgoingResponsePtr response = CreateIncompleteResponse(status, message, headers);
  452. if (!response->ContentType.empty() && !body.empty()) {
  453. if (!Endpoint->CompressContentTypes.empty()) {
  454. TStringBuf contentType = response->ContentType.Before(';');
  455. Trim(contentType, ' ');
  456. if (Count(Endpoint->CompressContentTypes, contentType) != 0) {
  457. response->EnableCompression();
  458. }
  459. }
  460. }
  461. return response;
  462. }
  463. void THttpIncomingRequest::FinishResponse(THttpOutgoingResponsePtr& response, TStringBuf body) {
  464. if (response->IsNeedBody() || !body.empty()) {
  465. if (Method == "HEAD") {
  466. response->Set<&THttpResponse::ContentLength>(ToString(body.size()));
  467. } else {
  468. response->SetBody(body);
  469. }
  470. }
  471. }
  472. THttpOutgoingResponsePtr THttpIncomingRequest::CreateResponse(TStringBuf status, TStringBuf message) {
  473. THttpOutgoingResponsePtr response = CreateIncompleteResponse(status, message);
  474. FinishResponse(response);
  475. return response;
  476. }
  477. THttpOutgoingResponsePtr THttpIncomingRequest::CreateResponse(TStringBuf status, TStringBuf message, const THeaders& headers) {
  478. THttpOutgoingResponsePtr response = CreateIncompleteResponse(status, message, headers);
  479. FinishResponse(response);
  480. return response;
  481. }
  482. THttpOutgoingResponsePtr THttpIncomingRequest::CreateResponse(TStringBuf status, TStringBuf message, const THeaders& headers, TStringBuf body) {
  483. THttpOutgoingResponsePtr response = CreateIncompleteResponse(status, message, headers, body);
  484. FinishResponse(response, body);
  485. return response;
  486. }
  487. THttpOutgoingResponsePtr THttpIncomingRequest::CreateResponse(TStringBuf status, TStringBuf message, TStringBuf contentType, TStringBuf body, TInstant lastModified) {
  488. NHttp::THeadersBuilder headers;
  489. if (!contentType.empty() && !body.empty()) {
  490. headers.Set("Content-Type", contentType);
  491. }
  492. if (lastModified) {
  493. headers.Set("Last-Modified", lastModified.FormatGmTime("%a, %d %b %Y %H:%M:%S GMT"));
  494. }
  495. return CreateResponse(status, message, headers, body);
  496. }
  497. THttpIncomingRequestPtr THttpIncomingRequest::Duplicate() {
  498. THttpIncomingRequestPtr request = new THttpIncomingRequest(*this);
  499. request->Reparse();
  500. request->Timer.Reset();
  501. return request;
  502. }
  503. THttpIncomingResponsePtr THttpIncomingResponse::Duplicate(THttpOutgoingRequestPtr request) {
  504. THttpIncomingResponsePtr response = new THttpIncomingResponse(*this);
  505. response->Reparse();
  506. response->Request = request;
  507. return response;
  508. }
  509. THttpOutgoingResponsePtr THttpOutgoingResponse::Duplicate(THttpIncomingRequestPtr request) {
  510. THeadersBuilder headers(Headers);
  511. if (!request->Endpoint->WorkerName.empty()) {
  512. headers.Set("X-Worker-Name", request->Endpoint->WorkerName);
  513. }
  514. THttpOutgoingResponsePtr response = new THttpOutgoingResponse(request);
  515. response->InitResponse(Protocol, Version, Status, Message);
  516. if (Body) {
  517. if (ContentType && !request->Endpoint->CompressContentTypes.empty()) {
  518. TStringBuf contentType = ContentType.Before(';');
  519. Trim(contentType, ' ');
  520. if (Count(request->Endpoint->CompressContentTypes, contentType) != 0) {
  521. if (response->EnableCompression()) {
  522. headers.Erase("Content-Length"); // we will need new length after compression
  523. }
  524. }
  525. }
  526. response->Set(headers);
  527. response->SetBody(Body);
  528. } else {
  529. response->Set(headers);
  530. if (!response->ContentLength) {
  531. response->Set<&THttpResponse::ContentLength>("0");
  532. }
  533. }
  534. return response;
  535. }
  536. THttpOutgoingResponsePtr THttpIncomingResponse::Reverse(THttpIncomingRequestPtr request) {
  537. THttpOutgoingResponsePtr response = new THttpOutgoingResponse(request);
  538. response->Assign(Data(), Size());
  539. response->Reparse();
  540. return response;
  541. }
  542. THttpOutgoingRequest::THttpOutgoingRequest(TStringBuf method, TStringBuf scheme, TStringBuf host, TStringBuf uri, TStringBuf protocol, TStringBuf version) {
  543. Secure = (scheme == "https");
  544. TString urie = UrlEscapeRet(uri);
  545. InitRequest(method, urie, protocol, version);
  546. if (host) {
  547. Set<&THttpRequest::Host>(host);
  548. }
  549. }
  550. THttpOutgoingRequest::THttpOutgoingRequest(TStringBuf method, TStringBuf url, TStringBuf protocol, TStringBuf version) {
  551. TStringBuf scheme, host, uri;
  552. if (!CrackURL(url, scheme, host, uri)) {
  553. Y_FAIL("Invalid URL specified");
  554. }
  555. if (!scheme.empty() && scheme != "http" && scheme != "https") {
  556. Y_FAIL("Invalid URL specified");
  557. }
  558. Secure = (scheme == "https");
  559. TString urie = UrlEscapeRet(uri);
  560. InitRequest(method, urie, protocol, version);
  561. if (host) {
  562. Set<&THttpRequest::Host>(host);
  563. }
  564. }
  565. THttpOutgoingRequestPtr THttpOutgoingRequest::CreateRequestString(const TString& data) {
  566. THttpOutgoingRequestPtr request = new THttpOutgoingRequest();
  567. request->Assign(data.data(), data.size());
  568. request->Reparse();
  569. return request;
  570. }
  571. THttpOutgoingRequestPtr THttpOutgoingRequest::CreateRequestGet(TStringBuf url) {
  572. return CreateRequest("GET", url);
  573. }
  574. THttpOutgoingRequestPtr THttpOutgoingRequest::CreateRequestGet(TStringBuf host, TStringBuf uri) {
  575. return CreateHttpRequest("GET", host, uri);
  576. }
  577. THttpOutgoingRequestPtr THttpOutgoingRequest::CreateRequestPost(TStringBuf url, TStringBuf contentType, TStringBuf body) {
  578. return CreateRequest("POST", url, contentType, body);
  579. }
  580. THttpOutgoingRequestPtr THttpOutgoingRequest::CreateRequestPost(TStringBuf host, TStringBuf uri, TStringBuf contentType, TStringBuf body) {
  581. return CreateHttpRequest("POST", host, uri, contentType, body);
  582. }
  583. THttpOutgoingRequestPtr THttpOutgoingRequest::CreateRequest(TStringBuf method, TStringBuf url, TStringBuf contentType, TStringBuf body) {
  584. THttpOutgoingRequestPtr request = new THttpOutgoingRequest(method, url, "HTTP", "1.1");
  585. request->Set<&THttpRequest::Accept>("*/*");
  586. if (!contentType.empty()) {
  587. request->Set<&THttpRequest::ContentType>(contentType);
  588. request->Set<&THttpRequest::Body>(body);
  589. }
  590. return request;
  591. }
  592. THttpOutgoingRequestPtr THttpOutgoingRequest::CreateHttpRequest(TStringBuf method, TStringBuf host, TStringBuf uri, TStringBuf contentType, TStringBuf body) {
  593. THttpOutgoingRequestPtr request = new THttpOutgoingRequest(method, "http", host, uri, "HTTP", "1.1");
  594. request->Set<&THttpRequest::Accept>("*/*");
  595. if (!contentType.empty()) {
  596. request->Set<&THttpRequest::ContentType>(contentType);
  597. request->Set<&THttpRequest::Body>(body);
  598. }
  599. return request;
  600. }
  601. THttpOutgoingRequestPtr THttpOutgoingRequest::Duplicate() {
  602. THttpOutgoingRequestPtr request = new THttpOutgoingRequest(*this);
  603. request->Reparse();
  604. return request;
  605. }
  606. THttpOutgoingResponse::THttpOutgoingResponse(THttpIncomingRequestPtr request)
  607. : Request(request)
  608. {}
  609. THttpOutgoingResponse::THttpOutgoingResponse(THttpIncomingRequestPtr request, TStringBuf protocol, TStringBuf version, TStringBuf status, TStringBuf message)
  610. : Request(request)
  611. {
  612. InitResponse(protocol, version, status, message);
  613. }
  614. const size_t THttpConfig::BUFFER_MIN_STEP;
  615. const TDuration THttpConfig::CONNECTION_TIMEOUT;
  616. TUrlParameters::TUrlParameters(TStringBuf url) {
  617. TStringBuf base;
  618. TStringBuf params;
  619. if (url.TrySplit('?', base, params)) {
  620. for (TStringBuf param = params.NextTok('&'); !param.empty(); param = params.NextTok('&')) {
  621. TStringBuf name = param.NextTok('=');
  622. Parameters[name] = param;
  623. }
  624. }
  625. }
  626. TString TUrlParameters::operator [](TStringBuf name) const {
  627. TString value(Get(name));
  628. CGIUnescape(value);
  629. return value;
  630. }
  631. bool TUrlParameters::Has(TStringBuf name) const {
  632. return Parameters.count(name) != 0;
  633. }
  634. TStringBuf TUrlParameters::Get(TStringBuf name) const {
  635. auto it = Parameters.find(name);
  636. if (it != Parameters.end()) {
  637. return it->second;
  638. }
  639. return TStringBuf();
  640. }
  641. TString TUrlParameters::Render() const {
  642. TStringBuilder parameters;
  643. for (const std::pair<TStringBuf, TStringBuf> parameter : Parameters) {
  644. if (parameters.empty()) {
  645. parameters << '?';
  646. } else {
  647. parameters << '&';
  648. }
  649. parameters << parameter.first;
  650. parameters << '=';
  651. parameters << parameter.second;
  652. }
  653. return parameters;
  654. }
  655. TCookies::TCookies(TStringBuf cookie) {
  656. for (TStringBuf param = cookie.NextTok(';'); !param.empty(); param = cookie.NextTok(';')) {
  657. param.SkipPrefix(" ");
  658. TStringBuf name = param.NextTok('=');
  659. Cookies[name] = param;
  660. }
  661. }
  662. TStringBuf TCookies::operator [](TStringBuf name) const {
  663. return Get(name);
  664. }
  665. bool TCookies::Has(TStringBuf name) const {
  666. return Cookies.count(name) != 0;
  667. }
  668. TStringBuf TCookies::Get(TStringBuf name) const {
  669. auto it = Cookies.find(name);
  670. if (it != Cookies.end()) {
  671. return it->second;
  672. }
  673. return TStringBuf();
  674. }
  675. TString TCookies::Render() const {
  676. TStringBuilder cookies;
  677. for (const std::pair<TStringBuf, TStringBuf> cookie : Cookies) {
  678. if (!cookies.empty()) {
  679. cookies << ' ';
  680. }
  681. cookies << cookie.first;
  682. cookies << '=';
  683. cookies << cookie.second;
  684. cookies << ';';
  685. }
  686. return cookies;
  687. }
  688. TCookiesBuilder::TCookiesBuilder()
  689. :TCookies(TStringBuf())
  690. {}
  691. void TCookiesBuilder::Set(TStringBuf name, TStringBuf data) {
  692. Data.emplace_back(name, data);
  693. Cookies[Data.back().first] = Data.back().second;
  694. }
  695. THeaders::THeaders(TStringBuf headers) {
  696. Parse(headers);
  697. }
  698. size_t THeaders::Parse(TStringBuf headers) {
  699. auto start = headers.begin();
  700. for (TStringBuf param = headers.NextTok("\r\n"); !param.empty(); param = headers.NextTok("\r\n")) {
  701. TStringBuf name = param.NextTok(":");
  702. param.SkipPrefix(" ");
  703. Headers[name] = param;
  704. }
  705. return headers.begin() - start;
  706. }
  707. const TStringBuf THeaders::operator [](TStringBuf name) const {
  708. return Get(name);
  709. }
  710. bool THeaders::Has(TStringBuf name) const {
  711. return Headers.count(name) != 0;
  712. }
  713. TStringBuf THeaders::Get(TStringBuf name) const {
  714. auto it = Headers.find(name);
  715. if (it != Headers.end()) {
  716. return it->second;
  717. }
  718. return TStringBuf();
  719. }
  720. TString THeaders::Render() const {
  721. TStringBuilder headers;
  722. for (const std::pair<TStringBuf, TStringBuf> header : Headers) {
  723. headers << header.first;
  724. headers << ": ";
  725. headers << header.second;
  726. headers << "\r\n";
  727. }
  728. return headers;
  729. }
  730. THeadersBuilder::THeadersBuilder()
  731. : THeaders(TStringBuf())
  732. {}
  733. THeadersBuilder::THeadersBuilder(TStringBuf headers)
  734. : THeaders(headers)
  735. {}
  736. THeadersBuilder::THeadersBuilder(const THeadersBuilder& builder) {
  737. for (const auto& pr : builder.Headers) {
  738. Set(pr.first, pr.second);
  739. }
  740. }
  741. void THeadersBuilder::Set(TStringBuf name, TStringBuf data) {
  742. Data.emplace_back(name, data);
  743. Headers[Data.back().first] = Data.back().second;
  744. }
  745. void THeadersBuilder::Erase(TStringBuf name) {
  746. Headers.erase(name);
  747. }
  748. }