Sane C++ Libraries
C++ Platform Abstraction Libraries
Loading...
Searching...
No Matches
HttpClient.h
1// Copyright (c) Stefano Cristiano
2// SPDX-License-Identifier: MIT
3#pragma once
4
5#include "../Foundation/Compiler.h"
6#ifndef SC_EXPORT_LIBRARY_HTTP_CLIENT
7#define SC_EXPORT_LIBRARY_HTTP_CLIENT 0
8#endif
9#define SC_HTTP_CLIENT_EXPORT SC_COMPILER_LIBRARY_EXPORT(SC_EXPORT_LIBRARY_HTTP_CLIENT)
10
11#include "../Foundation/Result.h"
12#include "../Foundation/Span.h"
13#include "../Foundation/StringSpan.h"
14#include "Internal/HttpClientThreading.h"
15
16namespace SC
17{
20
22struct SC_HTTP_CLIENT_EXPORT HttpClientRequest
23{
24 enum Method : uint8_t
25 {
26 HttpGET,
27 HttpPOST,
28 HttpPUT,
29 HttpHEAD,
30 HttpDELETE,
31 HttpPATCH,
32 HttpOPTIONS,
33 };
34
35 Method method = HttpGET;
36
38
39 Span<const StringSpan> headerNames;
40 Span<const StringSpan> headerValues;
41
43
44 uint64_t streamedBodySize = 0;
45
46 uint32_t timeoutMs = 30000;
47 bool allowRedirects = false;
48};
49
51struct SC_HTTP_CLIENT_EXPORT HttpClientResponse
52{
53 enum class Protocol : uint8_t
54 {
55 Unknown,
56 Http11,
57 Http2,
58 };
59
60 int statusCode = 0;
61
62 Span<const char> headers;
63
64 size_t headersLength = 0;
65 Protocol negotiatedProtocol = Protocol::Unknown;
66
67 [[nodiscard]] bool getHeader(StringSpan name, StringSpan& value) const;
68};
69
71struct SC_HTTP_CLIENT_EXPORT HttpClientRequestBodyProvider
72{
74
80 virtual Result pullRequestBody(Span<char> dest, size_t& bytesWritten, bool& endReached) = 0;
81};
82
84struct SC_HTTP_CLIENT_EXPORT HttpClientOperationListener
85{
87
90 virtual void onResponseHead(HttpClientResponse& response) { SC_COMPILER_UNUSED(response); } // namespace SC
91
95
97 virtual void onResponseComplete() {}
98
101 virtual void onError(Result error) { SC_COMPILER_UNUSED(error); }
102};
103
104struct SC_HTTP_CLIENT_EXPORT HttpClientOperation;
105
107struct SC_HTTP_CLIENT_EXPORT HttpClientOperationNotifier
108{
110
113 virtual void notifyHttpClientOperation(HttpClientOperation& operation) = 0;
114};
115
117struct SC_HTTP_CLIENT_EXPORT HttpClientResponseBuffer
118{
119 Span<char> data;
120
121 private:
122 friend struct HttpClientOperation;
123 bool inUse = false;
124};
125
127struct SC_HTTP_CLIENT_EXPORT HttpClientOperationEvent
128{
129 enum class Type : uint8_t
130 {
131 ResponseHead,
132 ResponseData,
133 ResponseComplete,
134 Error,
135 };
136
137 Type type = Type::ResponseHead;
138 size_t size = 0;
139 size_t bufferIndex = 0;
140 Result error = Result(true);
141};
142
144struct SC_HTTP_CLIENT_EXPORT HttpClientOperationMemory
145{
146 Span<HttpClientResponseBuffer> responseBuffers;
148
150 Span<char> responseHeaders;
151 Span<char> backendScratch;
152};
153
155#if SC_COMPILER_MSVC
156#pragma warning(push)
157#pragma warning(disable : 4324)
158#endif
159struct SC_HTTP_CLIENT_EXPORT HttpClient
160{
161 HttpClient();
162 ~HttpClient();
163
164 HttpClient(const HttpClient&) = delete;
165 HttpClient(HttpClient&&) = delete;
166 HttpClient& operator=(const HttpClient&) = delete;
167 HttpClient& operator=(HttpClient&&) = delete;
168
169 [[nodiscard]] Result init();
170 [[nodiscard]] Result close();
171
172 [[nodiscard]] bool isInitialized() const { return initialized; }
173
181 [[nodiscard]] static Result executeBlocking(const HttpClientRequest& request, HttpClientResponse& response,
182 Span<char> bodyBuffer, size_t& bodyLength,
183 const HttpClientOperationMemory& memory);
184
185 friend struct HttpClientOperation;
186
187 private:
188 friend struct Internal;
189 struct Internal;
190
191 Result platformInit();
192 Result platformClose();
193
194 bool initialized = false;
195
196#if SC_PLATFORM_APPLE
197 alignas(uint64_t) char storage[128];
198#elif SC_PLATFORM_WINDOWS
199 alignas(uint64_t) char storage[128];
200#elif SC_PLATFORM_LINUX
201 alignas(uint64_t) char storage[512];
202#else
203 alignas(uint64_t) char storage[8];
204#endif
205};
206
208struct SC_HTTP_CLIENT_EXPORT HttpClientOperation
209{
212
215 HttpClientOperation& operator=(const HttpClientOperation&) = delete;
216 HttpClientOperation& operator=(HttpClientOperation&&) = delete;
217
218 [[nodiscard]] Result init(HttpClient& client, const HttpClientOperationMemory& memory);
219 [[nodiscard]] Result close();
220 [[nodiscard]] Result cancel();
221
228 [[nodiscard]] Result start(const HttpClientRequest& request, HttpClientResponse& response,
229 HttpClientOperationListener* listener = nullptr,
230 HttpClientRequestBodyProvider* bodyProvider = nullptr);
231
235 [[nodiscard]] Result poll(uint32_t timeoutMilliseconds = 0);
236
239 void setNotifier(HttpClientOperationNotifier* notifierValue) { notifier = notifierValue; }
240
241 [[nodiscard]] bool isInitialized() const { return initialized; }
242 [[nodiscard]] bool isRequestInFlight() const { return requestInFlight; }
243
244 friend struct Internal;
245 struct Internal;
246
247 private:
248 friend struct HttpClientAppleCallbacks;
249 friend struct HttpClientLinuxCallbacks;
250 friend struct HttpClientWindowsCallbacks;
251
252 Result platformInit();
253 Result platformClose();
254 Result platformStart();
255 Result platformCancel();
256
257 Result enqueueEvent(const HttpClientOperationEvent& event);
258 bool dequeueEvent(HttpClientOperationEvent& event);
259
260 Result allocateResponseBuffer(size_t minimumSizeInBytes, size_t& bufferIndex, Span<char>& data);
261 void releaseResponseBuffer(size_t bufferIndex);
262 Result enqueueResponseDataCopy(Span<const char> data);
263
264 void enqueueResponseHead();
265 void enqueueResponseBuffer(size_t bufferIndex, size_t size);
266 void enqueueResponseComplete();
267 void enqueueError(Result error);
268
269 void resetResponseState(HttpClientResponse& response);
270 void resetRequestBodyState();
271
272 size_t readRequestBodyChunk(Span<char> dest, Result& outError, bool& outEnd);
273 bool hasPendingEvents() const;
274 Result processPendingEvents();
275
276 HttpClient* client = nullptr;
277 HttpClientResponse* currentResponse = nullptr;
278 HttpClientOperationListener* currentListener = nullptr;
279 HttpClientRequestBodyProvider* currentBodyProvider = nullptr;
280 HttpClientOperationNotifier* notifier = nullptr;
281 HttpClientRequest currentRequest;
282
283 Span<HttpClientResponseBuffer> responseBuffers;
284 Span<HttpClientOperationEvent> eventQueue;
285
286 Span<char> responseHeaders;
287 Span<char> backendScratch;
288
289 mutable HttpClientLocalMutex eventMutex;
290 HttpClientLocalConditionVariable eventCV;
291 HttpClientOperationEvent dequeuedEvent;
292
293 size_t eventHead = 0;
294 size_t eventTail = 0;
295 size_t eventCount = 0;
296 bool requestBodyFinished = false;
297 Result requestBodyError = Result(true);
298 uint64_t requestBodyBytesRead = 0;
299 bool initialized = false;
300 bool requestInFlight = false;
301
302#if SC_PLATFORM_APPLE
303 alignas(uint64_t) char storage[512];
304#elif SC_PLATFORM_WINDOWS
305 alignas(uint64_t) char storage[256];
306#elif SC_PLATFORM_LINUX
307 alignas(uint64_t) char storage[512];
308#else
309 alignas(uint64_t) char storage[8];
310#endif
311};
312#if SC_COMPILER_MSVC
313#pragma warning(pop)
314#endif
315
317} // namespace SC
#define SC_COMPILER_UNUSED(param)
Silence an unused variable or unused parameter warning.
Definition Compiler.h:148
unsigned char uint8_t
Platform independent (1) byte unsigned int.
Definition PrimitiveTypes.h:27
unsigned long long uint64_t
Platform independent (8) bytes unsigned int.
Definition PrimitiveTypes.h:33
unsigned int uint32_t
Platform independent (4) bytes unsigned int.
Definition PrimitiveTypes.h:29
Event slot storage used by HttpClientOperation to hand off backend notifications.
Definition HttpClient.h:128
Listener receiving response notifications during HttpClientOperation::poll.
Definition HttpClient.h:85
virtual void onError(Result error)
Called when the request fails.
Definition HttpClient.h:101
virtual void onResponseComplete()
Called when the response body completed successfully.
Definition HttpClient.h:97
virtual void onResponseHead(HttpClientResponse &response)
Called once the response status code and headers are available.
Definition HttpClient.h:90
virtual void onResponseBody(Span< const char > data)
Called for each response body chunk delivered by poll()
Definition HttpClient.h:94
Caller-owned memory for one HttpClientOperation.
Definition HttpClient.h:145
Span< char > responseBufferMemory
Optional; split equally into responseBuffers if non-empty.
Definition HttpClient.h:149
Optional notifier used by external adapters to wake up their own event loop.
Definition HttpClient.h:108
virtual void notifyHttpClientOperation(HttpClientOperation &operation)=0
Notifies an external adapter that the operation has queued new events.
One in-flight HTTP request/response operation.
Definition HttpClient.h:209
Result start(const HttpClientRequest &request, HttpClientResponse &response, HttpClientOperationListener *listener=nullptr, HttpClientRequestBodyProvider *bodyProvider=nullptr)
Starts a new request on this operation.
void setNotifier(HttpClientOperationNotifier *notifierValue)
Registers an optional notifier used by adapters such as HttpClientAsyncT.
Definition HttpClient.h:239
Result poll(uint32_t timeoutMilliseconds=0)
Processes queued backend events and optionally waits for more work.
Pull-based provider for streamed request bodies.
Definition HttpClient.h:72
virtual Result pullRequestBody(Span< char > dest, size_t &bytesWritten, bool &endReached)=0
Writes the next request body chunk in dest.
Configuration for an outgoing HTTP request.
Definition HttpClient.h:23
Span< const char > body
Fixed request body.
Definition HttpClient.h:42
StringSpan url
Full URL including scheme (e.g. "https://example.com/path")
Definition HttpClient.h:37
Caller-owned response buffer descriptor for one HttpClientOperation.
Definition HttpClient.h:118
Parsed response metadata filled when headers arrive.
Definition HttpClient.h:52
Reusable HTTP backend/session owner.
Definition HttpClient.h:160
static Result executeBlocking(const HttpClientRequest &request, HttpClientResponse &response, Span< char > bodyBuffer, size_t &bodyLength, const HttpClientOperationMemory &memory)
Convenience helper executing a request synchronously on top of HttpClientOperation::poll.
An ascii string used as boolean result. SC_TRY macro forwards errors to caller.
Definition Result.h:13
View over a contiguous sequence of items (pointer + size in elements).
Definition Span.h:29
An read-only view over a string (to avoid including Strings library when parsing is not needed).
Definition StringSpan.h:37