5#include "../Common/CompilerMacrosExport.h"
6#include "../Common/CompilerMacrosType.h"
7#ifndef SC_EXPORT_LIBRARY_HTTP_CLIENT
8#define SC_EXPORT_LIBRARY_HTTP_CLIENT 0
10#define SC_HTTP_CLIENT_EXPORT SC_COMPILER_LIBRARY_EXPORT(SC_EXPORT_LIBRARY_HTTP_CLIENT)
12#include "../Common/Result.h"
13#include "../Common/Span.h"
14#include "../Common/StringSpan.h"
15#include "HttpClientError.h"
16#include "Internal/HttpClientThreading.h"
23struct SC_HTTP_CLIENT_EXPORT HttpClientRequestBodyProvider;
24struct SC_HTTP_CLIENT_EXPORT HttpClientRequestOptions;
55 [[nodiscard]]
bool isIdentity()
const {
return type == Identity; }
56 [[nodiscard]]
static Type parseName(StringSpan name);
57 [[nodiscard]]
static const char* getName(Type type);
58 [[nodiscard]]
static Result writeAcceptEncoding(Span<const Type> types, Span<char> destination, StringSpan& value);
65 StringSpan headerValue;
66 size_t valueOffset = 0;
67 bool hasHeaderValue =
false;
85 [[nodiscard]]
bool isChunked()
const {
return type == Chunked; }
86 [[nodiscard]]
static Type parseName(StringSpan name);
87 [[nodiscard]]
static const char* getName(Type type);
94 StringSpan headerValue;
95 size_t valueOffset = 0;
96 bool hasHeaderValue =
false;
102 enum Backend : uint8_t
110 enum Feature : uint8_t
112 MultipleOperationsPerClient,
114 SizedStreamRequestBody,
115 ChunkedStreamRequestBody,
118 ProtocolHttp2Preferred,
119 ProtocolHttp2Required,
120 TlsDisablePeerVerification,
129 Backend backend = Unsupported;
131 bool multipleOperationsPerClient =
false;
132 bool fixedRequestBody =
false;
133 bool sizedStreamRequestBody =
false;
134 bool chunkedStreamRequestBody =
false;
135 bool redirectPolicy =
false;
136 bool protocolHttp11Only =
false;
137 bool protocolHttp2Preferred =
false;
138 bool protocolHttp2Required =
false;
139 bool tlsDisablePeerVerification =
false;
140 bool tlsCustomCaPath =
false;
141 bool proxyNoProxy =
false;
142 bool proxyHttp =
false;
143 bool proxyAuthorization =
false;
144 bool proxyBypassList =
false;
145 bool contentCodingPolicy =
false;
147 [[nodiscard]]
bool hasBackend(Backend requiredBackend)
const;
148 [[nodiscard]]
bool supports(Feature feature)
const;
150 [[nodiscard]]
bool supportsAll(Span<const Feature> features)
const;
151 [[nodiscard]] Result requireBackend(Backend requiredBackend)
const;
152 [[nodiscard]] Result requireFeatures(Span<const Feature> features)
const;
154 [[nodiscard]]
const char* getBackendName()
const;
155 [[nodiscard]]
static const char* getBackendName(Backend backend);
156 [[nodiscard]]
static const char* getFeatureName(Feature feature);
173 Span<const char> bytes;
176 uint64_t sizeInBytes = 0;
177 bool canReplay =
false;
181 [[nodiscard]]
bool isStreamed()
const {
return framing == SizedStream or framing == ChunkedStream; }
182 [[nodiscard]]
bool isChunkedStream()
const {
return framing == ChunkedStream; }
183 [[nodiscard]]
const char* getFramingName()
const {
return getFramingName(framing); }
184 [[nodiscard]]
static const char* getFramingName(Framing framing);
185 [[nodiscard]] uint64_t getDeclaredSizeInBytes()
const
187 if (framing == FixedSize)
189 return static_cast<uint64_t
>(bytes.sizeInBytes());
191 return framing == SizedStream ? sizeInBytes : 0;
205 Mode mode = NoRedirects;
206 uint8_t maxRedirects = 10;
208 [[nodiscard]]
const char* getModeName()
const {
return getModeName(mode); }
209 [[nodiscard]]
static const char* getModeName(Mode mode);
215 uint32_t requestTimeoutMs = 30000;
221 bool verifyPeer =
true;
222 StringSpan caCertificatesPath;
228 enum Preference : uint8_t
236 Preference preference = Default;
238 [[nodiscard]]
const char* getPreferenceName()
const {
return getPreferenceName(preference); }
239 [[nodiscard]]
static const char* getPreferenceName(Preference preference);
257 [[nodiscard]]
const char* getModeName()
const {
return getModeName(mode); }
258 [[nodiscard]]
static const char* getModeName(Mode mode);
277 enum Method : uint8_t
288 Method method = HttpGET;
292 Span<const HttpClientHeader> headers;
296 [[nodiscard]]
const char* getMethodName()
const {
return getMethodName(method); }
297 [[nodiscard]]
static const char* getMethodName(Method method);
298 [[nodiscard]] Result validate()
const;
306 enum class Protocol : uint8_t
315 Span<const char> headers;
317 size_t headersLength = 0;
318 Protocol negotiatedProtocol = Protocol::Unknown;
319 StringSpan effectiveUrl;
320 uint32_t redirectCount = 0;
322 [[nodiscard]]
bool getHeader(StringSpan name, StringSpan& value)
const;
323 [[nodiscard]]
bool hasHeader(StringSpan name)
const;
325 StringSpan& value)
const;
327 [[nodiscard]]
bool getContentLength(uint64_t& value)
const;
328 [[nodiscard]]
bool getContentType(StringSpan& value)
const;
329 [[nodiscard]]
bool getContentEncoding(StringSpan& value)
const;
330 [[nodiscard]]
bool getTransferEncoding(StringSpan& value)
const;
331 [[nodiscard]]
bool getLocation(StringSpan& value)
const;
332 [[nodiscard]]
bool getWwwAuthenticate(StringSpan& value)
const;
333 [[nodiscard]]
bool getProxyAuthenticate(StringSpan& value)
const;
338 [[nodiscard]]
bool hasContentCoding(HttpClientContentCoding::Type type)
const;
339 [[nodiscard]]
bool hasTransferCoding(HttpClientTransferCoding::Type type)
const;
340 [[nodiscard]]
bool isHttp11()
const {
return negotiatedProtocol == Protocol::Http11; }
341 [[nodiscard]]
bool isHttp2()
const {
return negotiatedProtocol == Protocol::Http2; }
342 [[nodiscard]]
bool isInformationalStatus()
const {
return statusCode >= 100 and statusCode < 200; }
343 [[nodiscard]]
bool isSuccessfulStatus()
const {
return statusCode >= 200 and statusCode < 300; }
344 [[nodiscard]]
bool isRedirectStatus()
const {
return statusCode >= 300 and statusCode < 400; }
345 [[nodiscard]]
bool isClientErrorStatus()
const {
return statusCode >= 400 and statusCode < 500; }
346 [[nodiscard]]
bool isServerErrorStatus()
const {
return statusCode >= 500 and statusCode < 600; }
347 [[nodiscard]]
bool isErrorStatus()
const {
return statusCode >= 400; }
348 [[nodiscard]]
const char* getProtocolName()
const {
return getProtocolName(negotiatedProtocol); }
349 [[nodiscard]]
static const char* getProtocolName(Protocol protocol);
362 virtual Result
pullRequestBody(Span<char> dest,
size_t& bytesWritten,
bool& endReached) = 0;
383 virtual void onError(Result error) { (void)(error); }
386struct SC_HTTP_CLIENT_EXPORT HttpClientOperation;
411 enum class Type : uint8_t
419 Type type = Type::ResponseHead;
421 size_t bufferIndex = 0;
422 Result error = Result(
true);
434 Span<HttpClientResponseBuffer> responseBuffers;
435 Span<HttpClientOperationEvent> eventQueue;
438 Span<char> responseHeaders;
439 Span<char> responseMetadata;
440 Span<char> backendScratch;
446#pragma warning(disable : 4324)
458 [[nodiscard]] Result init();
459 [[nodiscard]] Result init(HttpClientCapabilities::Backend requiredBackend);
460 [[nodiscard]] Result init(Span<const HttpClientCapabilities::Feature> requiredFeatures);
461 [[nodiscard]] Result init(HttpClientCapabilities::Backend requiredBackend,
462 Span<const HttpClientCapabilities::Feature> requiredFeatures);
463 [[nodiscard]] Result close();
466 [[nodiscard]]
bool isInitialized()
const {
return initialized; }
476 Span<char> bodyBuffer,
size_t& bodyLength,
482 friend struct Internal;
483 friend struct HttpClientLinuxCallbacks;
486 Result platformInit();
487 Result platformClose();
489 bool initialized =
false;
492 alignas(uint64_t)
char storage[128];
493#elif SC_PLATFORM_WINDOWS
494 alignas(uint64_t)
char storage[128];
495#elif SC_PLATFORM_LINUX
496 alignas(uint64_t)
char storage[512];
498 alignas(uint64_t)
char storage[8];
514 [[nodiscard]] Result close();
515 [[nodiscard]] Result cancel();
528 [[nodiscard]] Result
poll(uint32_t timeoutMilliseconds = 0);
534 [[nodiscard]]
bool isInitialized()
const {
return initialized; }
535 [[nodiscard]]
bool isRequestInFlight()
const {
return requestInFlight; }
537 friend struct Internal;
541 friend struct HttpClientTest;
542 friend struct HttpClientAppleCallbacks;
543 friend struct HttpClientLinuxCallbacks;
544 friend struct HttpClientWindowsCallbacks;
546 Result platformInit();
547 Result platformClose();
548 Result platformStart();
549 Result platformCancel();
551 Result enqueueEvent(
const HttpClientOperationEvent& event);
552 bool dequeueEvent(HttpClientOperationEvent& event);
554 Result allocateResponseBuffer(
size_t minimumSizeInBytes,
size_t& bufferIndex, Span<char>& data);
555 void releaseResponseBuffer(
size_t bufferIndex);
556 Result enqueueResponseDataCopy(Span<const char> data);
558 void enqueueResponseHead();
559 void enqueueResponseBuffer(
size_t bufferIndex,
size_t size);
560 void enqueueResponseComplete();
561 void enqueueError(Result error);
563 void resetResponseState(HttpClientResponse& response);
564 void resetRequestBodyState();
565 bool isAutomaticRedirectEnabled()
const;
566 bool canAutomaticRedirectRequestReplay()
const;
567 Result copyResponseEffectiveUrl(StringSpan url);
569 size_t readRequestBodyChunk(Span<char> dest, Result& outError,
bool& outEnd);
570 bool hasPendingEvents()
const;
571 Result processPendingEvents();
573 HttpClient* client =
nullptr;
574 HttpClientResponse* currentResponse =
nullptr;
575 HttpClientOperationListener* currentListener =
nullptr;
576 HttpClientOperationNotifier* notifier =
nullptr;
577 HttpClientRequest currentRequest;
579 Span<HttpClientResponseBuffer> responseBuffers;
580 Span<HttpClientOperationEvent> eventQueue;
582 Span<char> responseHeaders;
583 Span<char> responseMetadata;
584 Span<char> backendScratch;
586 mutable HttpClientLocalMutex eventMutex;
587 HttpClientLocalConditionVariable eventCV;
588 HttpClientOperationEvent dequeuedEvent;
590 size_t eventHead = 0;
591 size_t eventTail = 0;
592 size_t eventCount = 0;
593 bool requestBodyFinished =
false;
594 Result requestBodyError = Result(
true);
595 uint64_t requestBodyBytesRead = 0;
596 bool initialized =
false;
597 bool requestInFlight =
false;
600 alignas(uint64_t)
char storage[512];
601#elif SC_PLATFORM_WINDOWS
602 alignas(uint64_t)
char storage[256];
603#elif SC_PLATFORM_LINUX
604 alignas(uint64_t)
char storage[512];
606 alignas(uint64_t)
char storage[8];
Compile-time backend capability report for the active HttpClient backend.
Definition HttpClient.h:101
Caller-owned cursor for iterating comma-separated Content-Encoding values.
Definition HttpClient.h:63
Parsed response content-coding token view.
Definition HttpClient.h:41
Event slot storage used by HttpClientOperation to hand off backend notifications.
Definition HttpClient.h:410
Listener receiving response notifications during HttpClientOperation::poll.
Definition HttpClient.h:367
virtual void onError(Result error)
Called when the request fails.
Definition HttpClient.h:383
virtual void onResponseComplete()
Called when the response body completed successfully.
Definition HttpClient.h:379
virtual void onResponseHead(HttpClientResponse &response)
Called once the response status code and headers are available.
Definition HttpClient.h:372
virtual void onResponseBody(Span< const char > data)
Called for each response body chunk delivered by poll()
Definition HttpClient.h:376
Caller-owned memory for one HttpClientOperation.
Definition HttpClient.h:433
Span< char > responseBufferMemory
Optional; split equally into responseBuffers if non-empty.
Definition HttpClient.h:437
Optional notifier used by external adapters to wake up their own event loop.
Definition HttpClient.h:390
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:504
void setNotifier(HttpClientOperationNotifier *notifierValue)
Registers an optional notifier used by adapters such as HttpClientAsyncT.
Definition HttpClient.h:532
Result start(const HttpClientRequest &request, HttpClientResponse &response, HttpClientOperationListener *listener=nullptr)
Starts a new request on this operation.
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:354
virtual Result pullRequestBody(Span< char > dest, size_t &bytesWritten, bool &endReached)=0
Writes the next request body chunk in dest.
Outgoing request body description.
Definition HttpClient.h:161
Framing
Transfer framing requested for the outgoing body.
Definition HttpClient.h:167
Extended request options grouped by transport concern.
Definition HttpClient.h:263
HTTP protocol preference for one request.
Definition HttpClient.h:227
Proxy policy for one request.
Definition HttpClient.h:244
StringSpan authorization
Optional exact Proxy-Authorization header value for Http
Definition HttpClient.h:254
StringSpan url
Required for Http, must use the http:// scheme.
Definition HttpClient.h:253
Mode
Definition HttpClient.h:246
@ NoProxy
Bypass proxies for this request.
Definition HttpClient.h:248
@ Default
Use the backend default proxy configuration.
Definition HttpClient.h:247
@ Http
Use url as an explicit HTTP proxy URL.
Definition HttpClient.h:249
StringSpan bypassList
Optional comma-separated proxy bypass list for Http
Definition HttpClient.h:255
Redirect handling policy for one request.
Definition HttpClient.h:197
Timeout policy for one request.
Definition HttpClient.h:214
TLS policy for one request.
Definition HttpClient.h:220
Configuration for an outgoing HTTP request.
Definition HttpClient.h:276
StringSpan url
Full URL including scheme (e.g. "https://example.com/path")
Definition HttpClient.h:290
Caller-owned response buffer descriptor for one HttpClientOperation.
Definition HttpClient.h:400
Parsed response metadata filled when headers arrive.
Definition HttpClient.h:305
Caller-owned cursor for iterating comma-separated Transfer-Encoding values.
Definition HttpClient.h:92
Parsed response transfer-coding token view.
Definition HttpClient.h:72
Reusable HTTP backend/session owner.
Definition HttpClient.h:449
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.