#pragma once #include // for size_t #include // for uint8_t, int32_t #include // for make_unique, unique_ptr #include // for string #include // for string_view #include // for pair #include // for vector #include "SocketStream.h" // for SocketStream #include "URLParser.h" // for URLParser #ifndef BELL_DISABLE_FMT #include "fmt/core.h" // for format #endif #include "picohttpparser.h" // for phr_header namespace bell { class HTTPClient { public: // most basic header type, represents by a key-val typedef std::pair ValueHeader; typedef std::vector Headers; // Helper over ValueHeader, formatting a HTTP bytes range struct RangeHeader { static ValueHeader range(int32_t from, int32_t to) { #ifndef BELL_DISABLE_FMT return ValueHeader{"Range", fmt::format("bytes={}-{}", from, to)}; #else return ValueHeader{ "Range", "bytes=" + std::to_string(from) + "-" + std::to_string(to)}; #endif } static ValueHeader last(int32_t nbytes) { #ifndef BELL_DISABLE_FMT return ValueHeader{"Range", fmt::format("bytes=-{}", nbytes)}; #else return ValueHeader{"Range", "bytes=-" + std::to_string(nbytes)}; #endif } }; class Response { public: Response(){}; ~Response(); /** * Initializes a connection with a given url. */ void connect(const std::string& url); void rawRequest(const std::string& method, const std::string& url, const std::vector& content, Headers& headers); void get(const std::string& url, Headers headers = {}); void post(const std::string& url, Headers headers = {}, const std::vector& body = {}); std::string_view body(); std::vector bytes(); std::string_view header(const std::string& headerName); bell::SocketStream& stream() { return this->socketStream; } size_t contentLength(); size_t totalLength(); private: bell::URLParser urlParser; bell::SocketStream socketStream; struct phr_header phResponseHeaders[32]; const size_t HTTP_BUF_SIZE = 1024; std::vector httpBuffer = std::vector(HTTP_BUF_SIZE); std::vector rawBody = std::vector(); size_t httpBufferAvailable; size_t contentSize = 0; bool hasContentSize = false; Headers responseHeaders; void readResponseHeaders(); void readRawBody(); }; enum class Method : uint8_t { GET = 0, POST = 1 }; struct Request { std::string url; Method method; Headers headers; }; static std::unique_ptr get(const std::string& url, Headers headers = {}) { auto response = std::make_unique(); response->connect(url); response->get(url, headers); return response; } static std::unique_ptr post(const std::string& url, Headers headers = {}, const std::vector& body = {}) { auto response = std::make_unique(); response->connect(url); response->post(url, headers, body); return response; } }; } // namespace bell