1#include <xrpl/basics/Log.h>
2#include <xrpl/net/HTTPClient.h>
4#include <boost/algorithm/string/predicate.hpp>
5#include <boost/asio/ip/tcp.hpp>
6#include <boost/beast/core.hpp>
7#include <boost/beast/http.hpp>
8#include <boost/beast/version.hpp>
10#include <doctest/doctest.h>
24 boost::asio::io_context ioc_;
25 boost::asio::ip::tcp::acceptor acceptor_;
26 boost::asio::ip::tcp::endpoint endpoint_;
33 unsigned int status_code_{200};
36 TestHTTPServer() : acceptor_(ioc_), port_(0)
39 endpoint_ = {boost::asio::ip::tcp::v4(), 0};
40 acceptor_.open(endpoint_.protocol());
41 acceptor_.set_option(boost::asio::socket_base::reuse_address(
true));
42 acceptor_.bind(endpoint_);
46 port_ = acceptor_.local_endpoint().port();
56 boost::asio::io_context&
71 custom_headers_[name] = value;
77 response_body_ = body;
81 setStatusCode(
unsigned int code)
100 acceptor_.async_accept(
103 [&](boost::system::error_code
const& error,
104 boost::asio::ip::tcp::socket peer) {
110 handleConnection(std::move(peer));
116 handleConnection(boost::asio::ip::tcp::socket socket)
121 boost::beast::flat_buffer buffer;
122 boost::beast::http::request<boost::beast::http::string_body> req;
123 boost::beast::http::read(socket, buffer, req);
126 boost::beast::http::response<boost::beast::http::string_body> res;
127 res.version(req.version());
128 res.result(status_code_);
129 res.set(boost::beast::http::field::server,
"TestServer");
132 for (
auto const& [name, value] : custom_headers_)
134 res.set(name, value);
138 res.body() = response_body_;
139 res.prepare_payload();
143 for (
auto const& [name, value] : custom_headers_)
145 if (boost::iequals(name,
"Content-Length"))
147 res.
erase(boost::beast::http::field::content_length);
148 res.set(name, value);
153 boost::beast::http::write(socket, res);
156 boost::system::error_code ec;
157 socket.shutdown(boost::asio::ip::tcp::socket::shutdown_send, ec);
172 TestHTTPServer& server,
177 boost::system::error_code& result_error)
193 [&](boost::system::error_code
const& ec,
197 result_status = status;
209 if (server.ioc().run_one() == 0)
220TEST_CASE(
"HTTPClient case insensitive Content-Length")
231 for (
auto const& header_name : header_cases)
233 TestHTTPServer server;
235 server.setResponseBody(test_body);
241 boost::system::error_code result_error;
243 bool test_completed = runHTTPTest(
252 CHECK(test_completed);
253 CHECK(!result_error);
254 CHECK(result_status == 200);
255 CHECK(result_data == test_body);
259TEST_CASE(
"HTTPClient basic HTTP request")
261 TestHTTPServer server;
263 server.setResponseBody(test_body);
264 server.setHeader(
"Content-Type",
"text/plain");
269 boost::system::error_code result_error;
271 bool test_completed = runHTTPTest(
272 server,
"/basic", completed, result_status, result_data, result_error);
274 CHECK(test_completed);
275 CHECK(!result_error);
276 CHECK(result_status == 200);
277 CHECK(result_data == test_body);
282 TestHTTPServer server;
283 server.setResponseBody(
"");
284 server.setHeader(
"Content-Length",
"0");
289 boost::system::error_code result_error;
291 bool test_completed = runHTTPTest(
292 server,
"/empty", completed, result_status, result_data, result_error);
294 CHECK(test_completed);
295 CHECK(!result_error);
296 CHECK(result_status == 200);
300TEST_CASE(
"HTTPClient different status codes")
304 for (
auto status : status_codes)
306 TestHTTPServer server;
307 server.setStatusCode(status);
313 boost::system::error_code result_error;
315 bool test_completed = runHTTPTest(
323 CHECK(test_completed);
324 CHECK(!result_error);
325 CHECK(result_status ==
static_cast<int>(status));
A generic endpoint for log messages.
static Sink & getNullSink()
Returns a Sink which does nothing.
static void initializeSSLContext(std::string const &sslVerifyDir, std::string const &sslVerifyFile, bool sslVerify, beast::Journal j)
static void get(bool bSSL, boost::asio::io_context &io_context, std::deque< std::string > deqSites, unsigned short const port, std::string const &strPath, std::size_t responseMax, std::chrono::seconds timeout, std::function< bool(boost::system::error_code const &ecResult, int iStatus, std::string const &strData)> complete, beast::Journal &j)
Json::Value accept(jtx::Account const &subject, jtx::Account const &issuer, std::string_view credType)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
TEST_CASE("construct and compare Json::StaticString")