/* * This file is part of the Flowee project * Copyright (C) 2025 Tom Zander * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef SIMPLEHTTPCLIENT_H #define SIMPLEHTTPCLIENT_H #include #include #include #include #include #include #include #include #include class SimpleHttpClient : public QObject, public std::enable_shared_from_this { Q_OBJECT public: /** * Example: * @code * // for a HEAD * * boost::beast::http::request> request; * request.version(11); // http 1.1 * request.method(boost::beast::http::verb::head); * request.target("/index.html"); * request.set(boost::beast::http::field::host, "flowee.org"); * * // or for a POST; * * boost::beast::http::request> request; * request.version(11); * request.method(boost::beast::http::verb::post); * request.target("/upload"); * request.set(boost::beast::http::field::host, "flowee.org"); * request.set(boost::beast::http::field::content_type, "application/octet-stream"); * request.body() = std::vector(data.begin(), data.end()); * * // or for a GET * * boost::beast::http::request> request; * request.version(11); * request.method(boost::beast::http::verb::get); * request.target("/image.png"); * request.set(boost::beast::http::field::host, "flowee.org"); * @endcode */ static std::shared_ptr create(boost::asio::io_context &context, boost::asio::ssl::context &sslContext, const boost::beast::http::request> &request); /** * Create a client that does not wait for the entire download to finish before emitting a signal. * This is very similar in usage to the basic create() method, but the client will emit * "dataAvailable()" signals that HAVE to be handled because they hold the data payload. * The responseBody will always return an empty field in this version. */ static std::shared_ptr createIncremental(boost::asio::io_context &context, boost::asio::ssl::context &sslContext, const boost::beast::http::request> &request); enum ErrorType { NoError, DnsIssues, SslIssues, SendIssues, ReceiveIssues, PeerIssues, // remote server gave error }; Streaming::ConstBuffer responseBody() const; ErrorType error() const; int httpErrorCode() const; /// Response headers access. std::string_view headerValue(const char *name) const; /// Response headers access. std::string_view headerValue(boost::beast::http::field field) const; QDateTime headerDate(boost::beast::http::field field) const; boost::beast::http::request> request() const; signals: void finished(); void errored(ErrorType type); void dataAvailable(const Streaming::ConstBuffer &data); private: SimpleHttpClient(boost::asio::io_context &context, boost::asio::ssl::context &sslContext); void resolve(); void connect(boost::beast::error_code ec, boost::asio::ip::tcp::resolver::results_type results); void sslHandshake(boost::beast::error_code ec); void sendRequest(boost::beast::error_code ec); void requestSent(boost::beast::error_code ec, std::size_t bytesTransferred); void readHeaderReply(boost::beast::error_code ec, std::size_t bytesTransferred); void readReply(boost::beast::error_code ec, std::size_t bytesTransferred); void readPartialReply(boost::beast::error_code ec, std::size_t bytesTransferred); void connectionShutdown(boost::beast::error_code ec); void setError(ErrorType newError); boost::asio::ip::tcp::resolver m_resolver; boost::beast::ssl_stream m_stream; boost::beast::http::request> m_request; boost::beast::flat_buffer m_readBuffer; // for the response std::unique_ptr> m_response; // for HEAD requests boost::beast::http::response m_headResponse; std::unique_ptr> m_parser; // for partial requests std::unique_ptr> m_partialParser; Streaming::ConstBuffer m_responseBody; ErrorType m_error = NoError; bool m_incremental = false; }; #endif