idfxx 1.0.0
Modern C++23 components for ESP-IDF
Loading...
Searching...
No Matches
client.hpp
Go to the documentation of this file.
1// SPDX-License-Identifier: Apache-2.0
2// Copyright 2026 Chris Leishman
3
4#pragma once
5
21#include <idfxx/error>
22#include <idfxx/http/types>
23
24#include <chrono>
25#include <cstdint>
26#include <functional>
27#include <optional>
28#include <span>
29#include <string>
30#include <string_view>
31#include <system_error>
32
33typedef struct esp_http_client* esp_http_client_handle_t;
34struct esp_http_client_event;
35typedef int esp_err_t;
36
37namespace idfxx::http {
38
43enum class event_id : int {
44 // clang-format off
45 error = 0,
46 on_connected = 1,
47 headers_sent = 2,
48 on_header = 3,
49 on_data = 4,
50 on_finish = 5,
51 disconnected = 6,
52 redirect = 7,
53 // clang-format on
54};
55
60struct event_data {
61 enum event_id id;
62 std::span<const uint8_t> data;
63 std::string_view header_key;
64 std::string_view header_value;
65};
66
77class client {
78public:
82 enum class errc : esp_err_t {
83 // clang-format off
84 max_redirect = 0x7001,
85 connect = 0x7002,
86 write_data = 0x7003,
87 fetch_header = 0x7004,
88 invalid_transport = 0x7005,
89 connecting = 0x7006,
90 eagain = 0x7007,
91 connection_closed = 0x7008,
92 // clang-format on
93 };
94
98 class error_category : public std::error_category {
99 public:
102
104 [[nodiscard]] std::string message(int ec) const override final;
105 };
106
111 // Connection
112 std::string url = {};
113 std::string host = {};
114 int port = 0;
115 std::string path = {};
116 std::string query = {};
118 enum transport transport_type = transport::unknown;
119 std::chrono::milliseconds timeout{5000};
120
121 // Authentication
122 std::string username = {};
123 std::string password = {};
125
126 // TLS (client stores owned copies to keep data alive for the handle)
127 std::string cert_pem = {};
128 std::string client_cert_pem = {};
129 std::string client_key_pem = {};
130
131 // Headers
132 std::string user_agent = {};
133
134 // Redirect
135 bool disable_auto_redirect = false;
136 int max_redirection_count = 0;
137 int max_authorization_retries = 0;
138
139 // Buffers
140 int buffer_size = 0;
141 int buffer_size_tx = 0;
142
143 // Keep-alive
144 bool keep_alive_enable = false;
145 std::chrono::seconds keep_alive_idle{5};
146 std::chrono::seconds keep_alive_interval{5};
147 int keep_alive_count = 3;
148
149 // TLS options
150 bool use_global_ca_store = false;
151 bool skip_cert_common_name_check = false;
152 std::string common_name = {};
164 std::move_only_function<int(void*) const> crt_bundle_attach = {};
165
166 // Event handling
167 std::move_only_function<void(const event_data&) const> on_event = {};
168 };
169
170#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
178 [[nodiscard]] explicit client(config cfg);
179#endif
180
188
193
194 client(const client&) = delete;
195 client& operator=(const client&) = delete;
196
199
202
203 // =========================================================================
204 // Request Configuration
205 // =========================================================================
206
207#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
215 void set_url(std::string_view url) { unwrap(try_set_url(url)); }
216
217#endif
218
225 [[nodiscard]] result<void> try_set_url(std::string_view url);
226
232 void set_method(enum method m);
233
242 void set_header(std::string_view key, std::string_view value);
243
249 void delete_header(std::string_view key);
250
260 void set_post_field(std::string_view data);
261
267 void set_username(std::string_view username);
268
274 void set_password(std::string_view password);
275
281 void set_auth_type(enum auth_type type);
282
290 template<typename Rep, typename Period>
291 void set_timeout(const std::chrono::duration<Rep, Period>& timeout) {
292 _set_timeout(std::chrono::ceil<std::chrono::milliseconds>(timeout));
293 }
294
295 // =========================================================================
296 // Simple Request (blocking)
297 // =========================================================================
298
299#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
316#endif
317
327
328 // =========================================================================
329 // Streaming API
330 // =========================================================================
331
332#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
344 void open(size_t write_len = 0) { unwrap(try_open(write_len)); }
345
347 void open(int write_len) { open(static_cast<size_t>(write_len)); }
348
357 [[nodiscard]] size_t write(std::span<const uint8_t> data) { return unwrap(try_write(data)); }
358
367 [[nodiscard]] size_t write(std::string_view data) { return unwrap(try_write(data)); }
368
380
389 [[nodiscard]] size_t read(std::span<uint8_t> buf) { return unwrap(try_read(buf)); }
390
399 [[nodiscard]] size_t read(std::span<char> buf) { return unwrap(try_read(buf)); }
400
408
415 void close() { unwrap(try_close()); }
416#endif
417
430
432 [[nodiscard]] result<void> try_open(int write_len) { return try_open(static_cast<size_t>(write_len)); }
433
440 [[nodiscard]] result<size_t> try_write(std::span<const uint8_t> data);
441
448 [[nodiscard]] result<size_t> try_write(std::string_view data);
449
458 // [[nodiscard]] intentionally omitted: callers may fetch headers for their
459 // side effects without needing the returned content-length value.
461
468 [[nodiscard]] result<size_t> try_read(std::span<uint8_t> buf);
469
476 [[nodiscard]] result<size_t> try_read(std::span<char> buf);
477
484
491
492 // =========================================================================
493 // Response Accessors
494 // =========================================================================
495
500 [[nodiscard]] int status_code() const;
501
507
513
520 [[nodiscard]] std::optional<std::string> get_header(std::string_view key) const;
521
529 [[nodiscard]] std::string get_url() const;
530
531 // =========================================================================
532 // Redirect Control
533 // =========================================================================
534
535#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
547#endif
548
559
566
572
573private:
574 client(
576 std::move_only_function<void(const event_data&) const> on_event,
577 std::move_only_function<int(void*) const> crt_bundle_attach,
578 std::string post_data,
579 std::string cert_pem,
580 std::string client_cert_pem,
581 std::string client_key_pem
582 );
583
584 void _set_timeout(std::chrono::milliseconds timeout);
585
586 static result<esp_http_client_handle_t> _init_client(
587 config& cfg,
588 const std::string& cert_pem,
589 const std::string& client_cert_pem,
590 const std::string& client_key_pem
591 );
592 static esp_err_t _http_event_handler(esp_http_client_event* evt);
593 static esp_err_t _crt_bundle_trampoline(void* conf);
594
596 std::move_only_function<void(const event_data&) const> _on_event;
597 std::move_only_function<int(void*) const> _crt_bundle_attach;
598 std::string _post_data;
599 std::string _cert_pem;
600 std::string _client_cert_pem;
601 std::string _client_key_pem;
602};
603
611
617 return {std::to_underlying(e), http_client_category()};
618}
619
631[[nodiscard]] std::unexpected<std::error_code> http_client_error(esp_err_t e);
632
633} // namespace idfxx::http
634
635namespace idfxx {
636
645
646} // namespace idfxx
647
649namespace std {
650template<>
651struct is_error_code_enum<idfxx::http::client::errc> : true_type {};
652} // namespace std
655#include "sdkconfig.h"
656#ifdef CONFIG_IDFXX_STD_FORMAT
658#include <algorithm>
659#include <format>
660namespace std {
661
662template<>
663struct formatter<idfxx::http::event_id> {
664 constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
665
666 template<typename FormatContext>
667 auto format(idfxx::http::event_id id, FormatContext& ctx) const {
668 auto s = idfxx::to_string(id);
669 return std::copy(s.begin(), s.end(), ctx.out());
670 }
671};
672
673} // namespace std
675#endif // CONFIG_IDFXX_STD_FORMAT
676
// end of idfxx_http_client
Error category for HTTP client errors.
Definition client.hpp:98
std::string message(int ec) const override final
Returns a human-readable message for the given error code.
const char * name() const noexcept override final
Returns the name of the error category.
HTTP client with blocking and streaming request support.
Definition client.hpp:77
void delete_header(std::string_view key)
Deletes a request header.
result< void > try_set_url(std::string_view url)
Sets the request URL.
client(client &&) noexcept
Move constructor.
result< size_t > try_read(std::span< char > buf)
Reads response body data into a character buffer.
void perform()
Performs a blocking HTTP request.
Definition client.hpp:315
void set_url(std::string_view url)
Sets the request URL.
Definition client.hpp:215
result< size_t > try_write(std::span< const uint8_t > data)
Writes data to the open connection.
void open(size_t write_len=0)
Opens a connection for streaming.
Definition client.hpp:344
int64_t content_length() const
Returns the response content length.
client(config cfg)
Creates an HTTP client from configuration.
void set_password(std::string_view password)
Sets the password for authentication.
void set_auth_type(enum auth_type type)
Sets the authentication type.
void set_username(std::string_view username)
Sets the username for authentication.
size_t write(std::span< const uint8_t > data)
Writes data to the open connection.
Definition client.hpp:357
void close()
Closes the connection.
Definition client.hpp:415
void reset_redirect_counter()
Resets the redirect counter to zero.
result< void > try_perform()
Performs a blocking HTTP request.
result< void > try_set_redirection()
Applies the current redirect URL.
result< void > try_close()
Closes the connection.
size_t read(std::span< char > buf)
Reads response body data into a character buffer.
Definition client.hpp:399
result< size_t > try_write(std::string_view data)
Writes string data to the open connection.
std::optional< std::string > get_header(std::string_view key) const
Retrieves a response header value.
result< int64_t > try_fetch_headers()
Reads and processes response headers.
static result< client > make(config cfg)
Creates an HTTP client from configuration.
result< void > try_flush_response()
Discards any remaining response data.
void set_method(enum method m)
Sets the HTTP method.
void open(int write_len)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition client.hpp:347
void set_header(std::string_view key, std::string_view value)
Sets a request header.
client & operator=(const client &)=delete
void set_redirection()
Applies the current redirect URL.
Definition client.hpp:546
client(const client &)=delete
~client()
Destroys the client and releases all resources.
void set_timeout(const std::chrono::duration< Rep, Period > &timeout)
Sets the request timeout.
Definition client.hpp:291
bool is_chunked_response() const
Checks whether the response uses chunked transfer encoding.
int status_code() const
Returns the HTTP response status code.
void flush_response()
Discards any remaining response data.
Definition client.hpp:407
void set_post_field(std::string_view data)
Sets the POST request body.
result< void > try_open(int write_len)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition client.hpp:432
result< size_t > try_read(std::span< uint8_t > buf)
Reads response body data.
int64_t fetch_headers()
Reads and processes response headers.
Definition client.hpp:379
errc
Error codes for HTTP client operations.
Definition client.hpp:82
@ max_redirect
Maximum number of redirects exceeded.
@ fetch_header
Error reading response headers.
@ connection_closed
Connection closed by remote.
@ write_data
Error writing request data.
@ connecting
Connection in progress (async mode)
@ eagain
Resource temporarily unavailable, try again.
@ connect
Connection to server failed.
@ invalid_transport
Invalid transport type specified.
result< void > try_open(size_t write_len=0)
Opens a connection for streaming.
size_t read(std::span< uint8_t > buf)
Reads response body data.
Definition client.hpp:389
std::string get_url() const
Retrieves the current effective URL.
size_t write(std::string_view data)
Writes string data to the open connection.
Definition client.hpp:367
esp_http_client_handle_t idf_handle() const noexcept
Returns the underlying ESP-IDF HTTP client handle.
Definition client.hpp:571
Concept for types that can be both received and posted as event data.
Definition event.hpp:164
int esp_err_t
Definition error.hpp:35
std::string to_string(core_id c)
Returns a string representation of a CPU core identifier.
Definition cpu.hpp:52
struct esp_http_client * esp_http_client_handle_t
Definition client.hpp:33
int esp_err_t
Definition client.hpp:35
method
HTTP request methods.
Definition types.hpp:29
auth_type
HTTP authentication types.
Definition types.hpp:56
@ none
No authentication.
event_id
HTTP client event identifiers.
Definition client.hpp:43
@ on_data
Received response body data.
@ on_header
Received a response header.
@ disconnected
Disconnected from the server.
@ on_connected
Connected to the server.
@ headers_sent
All request headers have been sent.
@ on_finish
Finished a complete HTTP session.
@ error
An error occurred during the HTTP operation.
@ redirect
Intercepting a redirect.
std::unexpected< std::error_code > http_client_error(esp_err_t e)
Creates an unexpected error from an ESP-IDF error code, mapping to HTTP client error codes where poss...
std::error_code make_error_code(client::errc e) noexcept
Creates an error code from an idfxx::http::client::errc value.
Definition client.hpp:616
const client::error_category & http_client_category() noexcept
Returns a reference to the HTTP client error category singleton.
transport
HTTP transport types.
Definition types.hpp:68
@ unknown
Unknown transport.
T unwrap(result< T > result)
Throws a std::system_error if the result is an error.
Definition error.hpp:307
errc
IDFXX error codes.
Definition error.hpp:46
@ timeout
Operation timed out.
std::expected< T, std::error_code > result
result type wrapping a value or error code.
Definition error.hpp:120
HTTP client configuration.
Definition client.hpp:110
std::string_view header_key
Header name for on_header events.
Definition client.hpp:63
std::string_view header_value
Header value for on_header events.
Definition client.hpp:64
std::span< const uint8_t > data
Payload for on_data events.
Definition client.hpp:62
enum event_id id
Event type.
Definition client.hpp:61