Sane C++ Libraries
C++ Platform Abstraction Libraries
Loading...
Searching...
No Matches
HttpAsyncClient.h
1// Copyright (c) Stefano Cristiano
2// SPDX-License-Identifier: MIT
3#pragma once
4#include "HttpConnection.h"
5#include "HttpExport.h"
6#include "HttpURLParser.h"
7
8namespace SC
9{
12
13template <int ReadQueue, int WriteQueue, int HeaderBytes, int StreamBytes>
14struct SC_HTTP_EXPORT HttpAsyncClientConnection
15 : public HttpStaticConnection<ReadQueue, WriteQueue, HeaderBytes, StreamBytes, 8, HttpConnectionBase>
16{
17 static constexpr int ExtraBuffers = 8;
18
20 {
21 this->readableSocketStream.setAutoDestroy(false);
22 this->writableSocketStream.setAutoDestroy(false);
23 }
24};
25
45struct SC_HTTP_EXPORT HttpAsyncClient
46{
50
53
57 Result start(AsyncEventLoop& loop, HttpParser::Method method, StringSpan url, bool keepAlive = false);
58
60 Result get(AsyncEventLoop& loop, StringSpan url, bool keepAlive = false);
61
63 Result put(AsyncEventLoop& loop, StringSpan url, Span<const char> body, bool keepAlive = false);
64 Result put(AsyncEventLoop& loop, StringSpan url, StringSpan body, bool keepAlive = false)
65 {
66 return put(loop, url, body.toCharSpan(), keepAlive);
67 }
68
70 Result post(AsyncEventLoop& loop, StringSpan url, Span<const char> body, bool keepAlive = false);
71 Result post(AsyncEventLoop& loop, StringSpan url, StringSpan body, bool keepAlive = false)
72 {
73 return post(loop, url, body.toCharSpan(), keepAlive);
74 }
75
77 Result postMultipart(AsyncEventLoop& loop, StringSpan url, HttpMultipartWriter& writer, bool keepAlive = false);
78
79 [[nodiscard]] HttpAsyncClientResponse& getResponse() { return response; }
80 [[nodiscard]] const HttpAsyncClientResponse& getResponse() const { return response; }
81
84
87
90
91 private:
92 struct RequestPreset
93 {
94 enum class BodyMode : uint8_t
95 {
96 None,
97 Span,
98 Stream,
99 Multipart,
100 };
101
102 HttpParser::Method method = HttpParser::Method::HttpGET;
103
104 StringSpan url;
105
106 bool keepAlive = false;
107 bool autoSend = false;
108
109 Span<const char> bodySpan;
110
111 BodyMode bodyMode = BodyMode::None;
112 uint64_t contentLength = 0;
113
114 AsyncReadableStream* bodyStream = nullptr;
115 HttpMultipartWriter* multipartWriter = nullptr;
116 };
117
118 enum class State : uint8_t
119 {
120 Idle,
121 Connecting,
122 Sending,
123 WaitingResponse,
124 StreamingResponse,
125 };
126
127 Result startRequest(AsyncEventLoop& loop, const RequestPreset& preset);
128 Result prepareRequest(const RequestPreset& preset);
129 Result startPreparedRequest(const RequestPreset& preset);
130 Result ensureConnected();
131 Result beginSocketConnection();
132 Result beginResponseRead();
133 Result beginRequestSend();
134 Result onResponseBodyStreamRead();
135 Result validateActiveRequest() const;
136
137 void finalizeResponse(bool finishBodyStream);
138 void closeConnection();
139 void finishResponse();
140 void fail(Result error);
141
142 void onConnected(AsyncSocketConnect::Result& result);
143 void onReadableError(Result result);
144 void onWritableError(Result result);
145 void onPipelineError(Result result);
146 void onReadableEnd();
147 void onHeadersBufferWritten(AsyncBufferView::ID bufferID);
148 void onResponseData(AsyncBufferView::ID bufferID);
149 void onResponseBodyData(AsyncBufferView::ID bufferID);
150
151 [[nodiscard]] bool canReuseConnectionFor(StringSpan host, uint16_t port) const;
152 [[nodiscard]] bool responseMustNotHaveBody() const;
153 [[nodiscard]] bool responseHasKnownLength() const;
154
155 HttpConnectionBase* connection = nullptr;
156
157 AsyncEventLoop* eventLoop = nullptr;
158 HttpAsyncClientRequest* currentRequest = nullptr;
159 HttpAsyncClientRequest request;
160 HttpAsyncClientResponse response;
161 AsyncSocketConnect connectAsync;
162 RequestPreset currentPreset;
163
164 State state = State::Idle;
165
166 StringSpan currentHost;
167 char currentHostStorage[256] = {0};
168 uint16_t currentPort = 0;
169
170 HttpURLParser currentURL;
171 uint32_t requestCount = 0;
172
173 bool hasOpenConnection = false;
174 bool responseDelivered = false;
175 bool responseFinalized = false;
176};
177
179} // namespace SC
unsigned short uint16_t
Platform independent (2) bytes unsigned int.
Definition PrimitiveTypes.h:37
struct SC_FOUNDATION_EXPORT Function
Wraps function pointers, member functions and lambdas without ever allocating.
Definition Function.h:19
unsigned char uint8_t
Platform independent (1) byte unsigned int.
Definition PrimitiveTypes.h:36
unsigned long long uint64_t
Platform independent (8) bytes unsigned int.
Definition PrimitiveTypes.h:42
unsigned int uint32_t
Platform independent (4) bytes unsigned int.
Definition PrimitiveTypes.h:38
Asynchronous I/O (files, sockets, timers, processes, fs events, threads wake-up) (see Async) AsyncEve...
Definition Async.h:1394
Async source abstraction emitting data events in caller provided byte buffers.
Definition AsyncStreams.h:220
Definition HttpAsyncClient.h:16
Outgoing HTTP request sent by the client.
Definition HttpConnection.h:356
Incoming HTTP response received by the client.
Definition HttpConnection.h:226
Asynchronous HTTP/1.1 client using caller-provided fixed storage.
Definition HttpAsyncClient.h:46
Function< void(HttpAsyncClientResponse &)> onResponse
Called after the response headers have been parsed.
Definition HttpAsyncClient.h:86
Result start(AsyncEventLoop &loop, HttpParser::Method method, StringSpan url, bool keepAlive=false)
Starts a request that must be configured inside onPrepareRequest onPrepareRequest must send the heade...
Function< void(Result)> onError
Called on connection, protocol or streaming errors.
Definition HttpAsyncClient.h:89
Result postMultipart(AsyncEventLoop &loop, StringSpan url, HttpMultipartWriter &writer, bool keepAlive=false)
Convenience wrapper for a multipart/form-data POST request.
Result close()
Closes any active connection and releases references to the initialized storage.
Result get(AsyncEventLoop &loop, StringSpan url, bool keepAlive=false)
Convenience wrapper for a GET request without a request body.
Result init(HttpConnectionBase &storage)
Initializes the client with caller-provided connection storage The storage must outlive the client an...
Result post(AsyncEventLoop &loop, StringSpan url, Span< const char > body, bool keepAlive=false)
Convenience wrapper for a POST request with a fixed in-memory body.
Function< void(HttpAsyncClientRequest &)> onPrepareRequest
Called after the request has been created and can still be customized.
Definition HttpAsyncClient.h:83
Result put(AsyncEventLoop &loop, StringSpan url, Span< const char > body, bool keepAlive=false)
Convenience wrapper for a PUT request with a fixed in-memory body.
Shared async transport storage for HTTP client and server endpoints.
Definition HttpConnection.h:62
Definition HttpConnection.h:29
Method
Method of the current request / response.
Definition HttpParser.h:19
Adds compile-time configurable read and write queues to any class subclassing HttpConnectionBase.
Definition HttpConnection.h:558
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
Span< const char > toCharSpan() const
Obtain a const char Span from this StringView.
Definition StringSpan.h:82