diff options
author | komels <komels@yandex-team.ru> | 2022-04-15 16:53:39 +0300 |
---|---|---|
committer | komels <komels@yandex-team.ru> | 2022-04-15 16:53:39 +0300 |
commit | 703a2fb6e100d202d1c7fcd052d73bd5affef408 (patch) | |
tree | 22b7320c06bb04d86dbf7b9af9ae44281331cd15 /library/cpp/http/simple/http_client.cpp | |
parent | 3375bbfda1e2afb03aa2072bf5f2f2c3a26026e8 (diff) | |
download | ydb-703a2fb6e100d202d1c7fcd052d73bd5affef408.tar.gz |
Move 'kikimr/yndx'-depending tests out of ydb/core
ref:0a380e13308d579e0545a76924330d1ca5129c43
Diffstat (limited to 'library/cpp/http/simple/http_client.cpp')
-rw-r--r-- | library/cpp/http/simple/http_client.cpp | 356 |
1 files changed, 0 insertions, 356 deletions
diff --git a/library/cpp/http/simple/http_client.cpp b/library/cpp/http/simple/http_client.cpp deleted file mode 100644 index 818dc048ad..0000000000 --- a/library/cpp/http/simple/http_client.cpp +++ /dev/null @@ -1,356 +0,0 @@ -#include "http_client.h" - -#include <library/cpp/string_utils/url/url.h> -#include <library/cpp/uri/http_url.h> - -#include <util/stream/output.h> -#include <util/string/cast.h> -#include <util/string/join.h> -#include <util/string/split.h> - -TKeepAliveHttpClient::TKeepAliveHttpClient(const TString& host, - ui32 port, - TDuration socketTimeout, - TDuration connectTimeout) - : Host(CutHttpPrefix(host)) - , Port(port) - , SocketTimeout(socketTimeout) - , ConnectTimeout(connectTimeout) - , IsHttps(host.StartsWith("https")) - , IsClosingRequired(false) - , HttpsVerification(TVerifyCert{Host}) - , IfResponseRequired([](const THttpInput&) { return true; }) -{ -} - -TKeepAliveHttpClient::THttpCode TKeepAliveHttpClient::DoGet(const TStringBuf relativeUrl, - IOutputStream* output, - const THeaders& headers, - THttpHeaders* outHeaders) { - return DoRequest(TStringBuf("GET"), - relativeUrl, - {}, - output, - headers, - outHeaders); -} - -TKeepAliveHttpClient::THttpCode TKeepAliveHttpClient::DoPost(const TStringBuf relativeUrl, - const TStringBuf body, - IOutputStream* output, - const THeaders& headers, - THttpHeaders* outHeaders) { - return DoRequest(TStringBuf("POST"), - relativeUrl, - body, - output, - headers, - outHeaders); -} - -TKeepAliveHttpClient::THttpCode TKeepAliveHttpClient::DoRequest(const TStringBuf method, - const TStringBuf relativeUrl, - const TStringBuf body, - IOutputStream* output, - const THeaders& inHeaders, - THttpHeaders* outHeaders) { - const TString contentLength = IntToString<10, size_t>(body.size()); - return DoRequestReliable(FormRequest(method, relativeUrl, body, inHeaders, contentLength), output, outHeaders); -} - -TKeepAliveHttpClient::THttpCode TKeepAliveHttpClient::DoRequestRaw(const TStringBuf raw, - IOutputStream* output, - THttpHeaders* outHeaders) { - return DoRequestReliable(raw, output, outHeaders); -} - -void TKeepAliveHttpClient::DisableVerificationForHttps() { - HttpsVerification.Clear(); - Connection.Reset(); -} - -void TKeepAliveHttpClient::SetClientCertificate(const TOpenSslClientIO::TOptions::TClientCert& options) { - ClientCertificate = options; -} - -void TKeepAliveHttpClient::ResetConnection() { - Connection.Reset(); -} - -TVector<IOutputStream::TPart> TKeepAliveHttpClient::FormRequest(TStringBuf method, - const TStringBuf relativeUrl, - TStringBuf body, - const TKeepAliveHttpClient::THeaders& headers, - TStringBuf contentLength) const { - TVector<IOutputStream::TPart> parts; - - parts.reserve(16 + 4 * headers.size()); - parts.push_back(method); - parts.push_back(TStringBuf(" ")); - parts.push_back(relativeUrl); - parts.push_back(TStringBuf(" HTTP/1.1")); - parts.push_back(IOutputStream::TPart::CrLf()); - parts.push_back(TStringBuf("Host: ")); - parts.push_back(TStringBuf(Host)); - parts.push_back(IOutputStream::TPart::CrLf()); - parts.push_back(TStringBuf("Content-Length: ")); - parts.push_back(contentLength); - parts.push_back(IOutputStream::TPart::CrLf()); - - for (const auto& entry : headers) { - parts.push_back(IOutputStream::TPart(entry.first)); - parts.push_back(IOutputStream::TPart(TStringBuf(": "))); - parts.push_back(IOutputStream::TPart(entry.second)); - parts.push_back(IOutputStream::TPart::CrLf()); - } - - parts.push_back(IOutputStream::TPart::CrLf()); - if (body) { - parts.push_back(IOutputStream::TPart(body)); - } - - return parts; -} - -TKeepAliveHttpClient::THttpCode TKeepAliveHttpClient::ReadAndTransferHttp(THttpInput& input, - IOutputStream* output, - THttpHeaders* outHeaders) const { - TKeepAliveHttpClient::THttpCode statusCode; - try { - statusCode = ParseHttpRetCode(input.FirstLine()); - } catch (TFromStringException& e) { - TString rest = input.ReadAll(); - ythrow THttpRequestException() << "Failed parse status code in response of " << Host << ": " << e.what() << " (" << input.FirstLine() << ")" - << "\nFull http response:\n" - << rest; - } - - auto canContainBody = [](auto statusCode) { - return statusCode != HTTP_NOT_MODIFIED && statusCode != HTTP_NO_CONTENT; - }; - - if (output && canContainBody(statusCode) && IfResponseRequired(input)) { - TransferData(&input, output); - } - if (outHeaders) { - *outHeaders = input.Headers(); - } - - return statusCode; -} - -THttpInput* TKeepAliveHttpClient::GetHttpInput() { - return Connection ? Connection->GetHttpInput() : nullptr; -} - -bool TKeepAliveHttpClient::CreateNewConnectionIfNeeded() { - if (IsClosingRequired || (Connection && !Connection->IsOk())) { - Connection.Reset(); - } - if (!Connection) { - Connection = MakeHolder<NPrivate::THttpConnection>(Host, - Port, - SocketTimeout, - ConnectTimeout, - IsHttps, - ClientCertificate, - HttpsVerification); - IsClosingRequired = false; - return true; - } - return false; -} - -THttpRequestException::THttpRequestException(int statusCode) - : StatusCode(statusCode) -{ -} - -int THttpRequestException::GetStatusCode() const { - return StatusCode; -} - -TSimpleHttpClient::TSimpleHttpClient(const TOptions& options) - : Host(options.Host()) - , Port(options.Port()) - , SocketTimeout(options.SocketTimeout()) - , ConnectTimeout(options.ConnectTimeout()) -{ -} - -TSimpleHttpClient::TSimpleHttpClient(const TString& host, ui32 port, TDuration socketTimeout, TDuration connectTimeout) - : Host(host) - , Port(port) - , SocketTimeout(socketTimeout) - , ConnectTimeout(connectTimeout) -{ -} - -void TSimpleHttpClient::EnableVerificationForHttps() { - HttpsVerification = true; -} - -void TSimpleHttpClient::DoGet(const TStringBuf relativeUrl, IOutputStream* output, const THeaders& headers) const { - TKeepAliveHttpClient cl = CreateClient(); - - TKeepAliveHttpClient::THttpCode code = cl.DoGet(relativeUrl, output, headers); - - Y_ENSURE(cl.GetHttpInput()); - ProcessResponse(relativeUrl, *cl.GetHttpInput(), output, code); -} - -void TSimpleHttpClient::DoPost(const TStringBuf relativeUrl, TStringBuf body, IOutputStream* output, const THashMap<TString, TString>& headers) const { - TKeepAliveHttpClient cl = CreateClient(); - - TKeepAliveHttpClient::THttpCode code = cl.DoPost(relativeUrl, body, output, headers); - - Y_ENSURE(cl.GetHttpInput()); - ProcessResponse(relativeUrl, *cl.GetHttpInput(), output, code); -} - -void TSimpleHttpClient::DoPostRaw(const TStringBuf relativeUrl, const TStringBuf rawRequest, IOutputStream* output) const { - TKeepAliveHttpClient cl = CreateClient(); - - TKeepAliveHttpClient::THttpCode code = cl.DoRequestRaw(rawRequest, output); - - Y_ENSURE(cl.GetHttpInput()); - ProcessResponse(relativeUrl, *cl.GetHttpInput(), output, code); -} - -namespace NPrivate { - THttpConnection::THttpConnection(const TString& host, - ui32 port, - TDuration sockTimeout, - TDuration connTimeout, - bool isHttps, - const TMaybe<TOpenSslClientIO::TOptions::TClientCert>& clientCert, - const TMaybe<TOpenSslClientIO::TOptions::TVerifyCert>& verifyCert) - : Addr(Resolve(host, port)) - , Socket(Connect(Addr, sockTimeout, connTimeout, host, port)) - , SocketIn(Socket) - , SocketOut(Socket) - { - if (isHttps) { - TOpenSslClientIO::TOptions opts; - if (clientCert) { - opts.ClientCert_ = clientCert; - } - if (verifyCert) { - opts.VerifyCert_ = verifyCert; - } - - Ssl = MakeHolder<TOpenSslClientIO>(&SocketIn, &SocketOut, opts); - HttpOut = MakeHolder<THttpOutput>(Ssl.Get()); - } else { - HttpOut = MakeHolder<THttpOutput>(&SocketOut); - } - - HttpOut->EnableKeepAlive(true); - } - - TNetworkAddress THttpConnection::Resolve(const TString& host, ui32 port) { - try { - return TNetworkAddress(host, port); - } catch (const yexception& e) { - ythrow THttpRequestException() << "Resolve of " << host << ": " << e.what(); - } - } - - TSocket THttpConnection::Connect(TNetworkAddress& addr, - TDuration sockTimeout, - TDuration connTimeout, - const TString& host, - ui32 port) { - try { - TSocket socket(addr, connTimeout); - TDuration socketTimeout = Max(sockTimeout, TDuration::MilliSeconds(1)); // timeout less than 1ms will be interpreted as 0 in SetSocketTimeout() call below and will result in infinite wait - - ui32 seconds = socketTimeout.Seconds(); - ui32 milliSeconds = (socketTimeout - TDuration::Seconds(seconds)).MilliSeconds(); - socket.SetSocketTimeout(seconds, milliSeconds); - return socket; - } catch (const yexception& e) { - ythrow THttpRequestException() << "Connect to " << host << ':' << port << " failed: " << e.what(); - } - } -} - -void TSimpleHttpClient::ProcessResponse(const TStringBuf relativeUrl, THttpInput& input, IOutputStream*, const unsigned statusCode) const { - if (!(statusCode >= 200 && statusCode < 300)) { - TString rest = input.ReadAll(); - ythrow THttpRequestException(statusCode) << "Got " << statusCode << " at " << Host << relativeUrl << "\nFull http response:\n" - << rest; - } -} - -TSimpleHttpClient::~TSimpleHttpClient() { -} - -TKeepAliveHttpClient TSimpleHttpClient::CreateClient() const { - TKeepAliveHttpClient cl(Host, Port, SocketTimeout, ConnectTimeout); - - if (!HttpsVerification) { - cl.DisableVerificationForHttps(); - } - - PrepareClient(cl); - - return cl; -} - -void TSimpleHttpClient::PrepareClient(TKeepAliveHttpClient&) const { -} - -TRedirectableHttpClient::TRedirectableHttpClient(const TString& host, ui32 port, TDuration socketTimeout, TDuration connectTimeout) - : TSimpleHttpClient(host, port, socketTimeout, connectTimeout) -{ -} - -void TRedirectableHttpClient::PrepareClient(TKeepAliveHttpClient& cl) const { - cl.IfResponseRequired = [](const THttpInput& input) { - return !input.Headers().HasHeader("Location"); - }; -} - -void TRedirectableHttpClient::ProcessResponse(const TStringBuf relativeUrl, THttpInput& input, IOutputStream* output, const unsigned statusCode) const { - for (auto i = input.Headers().Begin(), e = input.Headers().End(); i != e; ++i) { - if (0 == TString::compare(i->Name(), TStringBuf("Location"))) { - TVector<TString> request_url_parts, request_body_parts; - - size_t splitted_index = 0; - for (auto& iter : StringSplitter(i->Value()).Split('/')) { - if (splitted_index < 3) { - request_url_parts.push_back(TString(iter.Token())); - } else { - request_body_parts.push_back(TString(iter.Token())); - } - ++splitted_index; - } - - TString url = JoinSeq("/", request_url_parts); - ui16 port = 443; - - THttpURL u; - if (THttpURL::ParsedOK == u.Parse(url)) { - const char* p = u.Get(THttpURL::FieldPort); - if (p) { - port = FromString<ui16>(p); - url = u.PrintS(THttpURL::FlagScheme | THttpURL::FlagHost); - } - } - - TRedirectableHttpClient cl(url, port, TDuration::Seconds(60), TDuration::Seconds(60)); - if (HttpsVerification) { - cl.EnableVerificationForHttps(); - } - cl.DoGet(TString("/") + JoinSeq("/", request_body_parts), output); - return; - } - } - if (!(statusCode >= 200 && statusCode < 300)) { - TString rest = input.ReadAll(); - ythrow THttpRequestException(statusCode) << "Got " << statusCode << " at " << Host << relativeUrl << "\nFull http response:\n" - << rest; - } - TransferData(&input, output); -} |