7#include "../Async/Async.h"
8#include "../AsyncStreams/AsyncRequestStreams.h"
9#include "../Common/StringSpan.h"
10#include "Internal/HttpFixedBufferWriter.h"
11#include "Internal/HttpParsedHeaders.h"
18enum class HttpBodyFramingKind : uint8_t
26enum class HttpContentEncoding : uint8_t
33SC_HTTP_EXPORT StringSpan httpContentEncodingName(HttpContentEncoding encoding);
34SC_HTTP_EXPORT Result httpContentEncodingFromHeader(StringSpan headerValue, HttpContentEncoding& encoding);
36struct HttpAsyncClient;
37struct SyncZLibTransformStream;
45 StringSpan contentType;
47 Span<const char> body;
50 static constexpr size_t MaxParts = 8;
54 Result setBoundary(StringSpan boundaryValue);
55 Result addField(StringSpan fieldName, StringSpan value);
56 Result addFile(StringSpan fieldName, StringSpan fileName, Span<const char> body,
57 StringSpan contentType =
"application/octet-stream");
59 [[nodiscard]] StringSpan getBoundary()
const {
return boundary; }
60 [[nodiscard]]
size_t getNumParts()
const {
return numParts; }
61 [[nodiscard]]
const Part& getPart(
size_t idx)
const {
return parts[idx]; }
62 [[nodiscard]]
size_t getContentLength()
const;
67 char boundaryStorage[71] = {0};
83 void setHeaderMemory(Span<char> memory) { headerMemory = memory; }
85 [[nodiscard]] Span<char> getHeaderMemory()
const {
return headerMemory; }
88 void resetTransportStreams();
90 [[nodiscard]]
AsyncReadableStream& getReadableTransportStream() {
return *readableTransportStream; }
91 [[nodiscard]]
AsyncWritableStream& getWritableTransportStream() {
return *writableTransportStream; }
93 [[nodiscard]]
const AsyncReadableStream& getReadableTransportStream()
const {
return *readableTransportStream; }
94 [[nodiscard]]
const AsyncWritableStream& getWritableTransportStream()
const {
return *writableTransportStream; }
99 Span<char> headerMemory;
113 Result begin(
AsyncBuffersPool& buffersPool, Function<Result()>&& onReadRequest);
116 void failBody(Result result);
118 Function<Result()> onReadRequest;
122 virtual Result asyncRead()
override;
123 virtual Result asyncResumeReading()
override;
133 [[nodiscard]]
bool getKeepAlive()
const {
return parsedHeaders.parser.connectionKeepAlive; }
157 [[nodiscard]]
bool getHeader(StringSpan headerName, StringSpan& value)
const;
171 [[nodiscard]] Span<char> getUnusedHeaderMemory()
const {
return parsedHeaders.availableHeader; }
173 Result initBodyStream(
AsyncBuffersPool& buffersPool, Function<Result()>&& onReadRequest);
174 Result startBodyStream();
176 void finishBodyStream();
177 void failBodyStream(Result result);
178 void abortBodyStream();
179 Result prepareBodyStream(
AsyncBuffersPool& buffersPool, Function<Result()>&& onReadRequest,
180 bool allowCloseDelimited);
182 bool allowTrailingData);
184 void setBodyBytesRemaining(uint64_t value) { bodyBytesRemaining = value; }
185 void setBodyFramingKind(HttpBodyFramingKind value) { bodyFramingKind = value; }
186 void setBodyComplete(
bool value) { bodyComplete = value; }
187 void attachReadableStream(AsyncReadableStream& stream) { readableStream = &stream; }
198 AsyncBufferView::ID bufferID,
bool stopAtHeadersEnd,
bool unshiftPendingBodyToStream =
true);
203 enum class ChunkedState : uint8_t
216 HttpParsedHeaders parsedHeaders;
217 Span<char> headerMemory;
219 uint64_t bodyBytesRemaining = 0;
220 HttpBodyFramingKind bodyFramingKind = HttpBodyFramingKind::None;
221 bool bodyComplete =
true;
222 bool bodyStreamStarted =
false;
223 BodyStream bodyStream;
224 ChunkedState chunkedState = ChunkedState::Size;
225 uint64_t chunkedChunkSize = 0;
226 uint64_t chunkedBytesRemaining = 0;
227 bool chunkedSizeHasDigits =
false;
237 StringSpan
getURL()
const {
return url; }
247 void setHeaderMemory(Span<char> memory);
250 Result writeHeaders(
const uint32_t maxHeaderSize, Span<const char> readData,
AsyncReadableStream& stream,
262 void reset(Span<char> memory);
263 Result writeHeaders(uint32_t maxHeaderSize, Span<const char> readData,
AsyncReadableStream& stream,
265 BodyStream& rawBodyStream() {
return bodyStream; }
292 bool finalChunkStarted =
false;
293 bool finalChunkWritten =
false;
295 char headerStorage[20] = {0};
303 Result
addHeader(StringSpan headerName, StringSpan headerValue);
330 [[nodiscard]]
bool getKeepAlive()
const {
return forceDisableKeepAlive ? false : keepAlive; }
333 enum class KnownHeader : uint8_t
345 void setHeaderMemory(Span<char> memory);
346 void setWritableStream(AsyncWritableStream& stream)
348 destinationStream = &stream;
349 writableStream = &stream;
352 [[nodiscard]]
bool hasHeader(KnownHeader header)
const;
353 [[nodiscard]]
bool hasSentHeaders()
const {
return headersSent; }
354 [[nodiscard]]
bool hasEnded()
const {
return endCalled; }
355 [[nodiscard]]
bool isChunkedTransferEncodingEnabled()
const {
return chunkedTransferEncodingEnabled; }
357 HttpFixedBufferWriter responseHeaders;
358 Span<char> headerMemory;
360 bool headersSent =
false;
361 bool endCalled =
false;
363 bool forceDisableKeepAlive =
false;
364 bool keepAlive =
true;
365 bool connectionHeaderAdded =
false;
366 bool hostHeaderAdded =
false;
367 bool userAgentHeaderAdded =
false;
368 bool contentLengthAdded =
false;
369 bool contentTypeAdded =
false;
370 bool transferEncodingAdded =
false;
371 bool contentEncodingAdded =
false;
372 bool acceptEncodingAdded =
false;
373 bool chunkedTransferEncodingEnabled =
false;
390 Result
startBody(
int httpCode, uint64_t contentLength, StringSpan contentType = {});
394 Result
sendBytes(
int httpCode, Span<const char> body, StringSpan contentType = {});
398 Result
sendBody(
int httpCode, StringSpan body, StringSpan contentType = {});
428 enum class BodyType : uint8_t
440 Result setExpectedBodyLength(uint64_t value);
441 Result setBody(Span<const char> value);
442 Result setBody(StringSpan value) {
return setBody(value.toCharSpan()); }
446 HttpContentEncoding encoding);
452 [[nodiscard]] StringSpan getRequestTarget()
const {
return url; }
453 [[nodiscard]] StringSpan getURL()
const {
return url; }
454 [[nodiscard]] BodyType getBodyType()
const {
return bodyType; }
455 [[nodiscard]] uint64_t getContentLength()
const {
return contentLength; }
456 [[nodiscard]]
bool usesChunkedTransferEncoding()
const {
return chunkedTransferEncodingEnabled; }
457 [[nodiscard]] HttpContentEncoding getContentEncoding()
const {
return contentEncoding; }
462 void setDefaultHost(StringSpan value) { defaultHost = value; }
464 [[nodiscard]]
bool hasTransferEncodingHeader()
const {
return hasHeader(KnownHeader::TransferEncoding); }
465 [[nodiscard]]
bool hasAcceptEncodingHeader()
const {
return hasHeader(KnownHeader::AcceptEncoding); }
469 [[nodiscard]]
const HttpMultipartWriter* getMultipartWriter()
const {
return multipartWriter; }
470 [[nodiscard]] Span<const char> getBodySpan()
const {
return bodySpan; }
476 BodyType bodyType = BodyType::None;
477 Span<const char> bodySpan;
478 uint64_t contentLength = 0;
479 HttpContentEncoding contentEncoding = HttpContentEncoding::Identity;
481 StringSpan defaultHost;
492 struct SC_HTTP_EXPORT
ID
494 size_t getIndex()
const {
return index; }
514 Result
sendBodyCopy(
int httpCode, StringSpan body, StringSpan contentType = {});
525 uint32_t requestCount = 0;
536 State state = State::Inactive;
538 bool webSocketUpgraded =
false;
542template <
typename Type>
552 constexpr SpanWithStride(
void* data,
size_t sizeInElements,
size_t strideInBytes)
553 : data(data), sizeElements(sizeInElements), strideInBytes(strideInBytes)
556 template <
typename U>
558 : data(span.data()), sizeElements(span.sizeInElements()), strideInBytes(sizeof(U))
561 [[nodiscard]]
constexpr size_t sizeInElements()
const {
return sizeElements; }
562 [[nodiscard]]
constexpr bool empty()
const {
return sizeElements == 0; }
564 template <
typename U>
565 SpanWithStride<U> castTo()
567 return {
static_cast<U*
>(
reinterpret_cast<Type*
>(data)), sizeElements, strideInBytes};
570 [[nodiscard]] Type& operator[](
size_t idx)
572 return *
reinterpret_cast<Type*
>(
reinterpret_cast<char*
>(data) + idx * strideInBytes);
575 [[nodiscard]]
const Type& operator[](
size_t idx)
const
577 return *
reinterpret_cast<const Type*
>(
reinterpret_cast<const char*
>(data) + idx * strideInBytes);
583 size_t strideInBytes;
591 size_t readQueueSize = 3;
592 size_t writeQueueSize = 3;
593 size_t buffersQueueSize = 6;
594 size_t headerBytesLength = 8 * 1024;
595 size_t streamBytesLength = 512 * 1024;
600 Span<AsyncReadableStream::Request> allReadQueue;
601 Span<AsyncWritableStream::Request> allWriteQueue;
603 Span<AsyncBufferView> allBuffers;
605 Span<char> allHeaders;
606 Span<char> allStreams;
629 return connections[connectionID.index];
647 size_t numConnections = 0;
650 size_t highestActiveConnection = 0;
654template <
int ReadQueue,
int WriteQueue,
int HeaderBytes,
int StreamBytes,
int ExtraBuffers,
typename BaseClass>
662 char headerStorage[HeaderBytes];
663 char streamStorage[StreamBytes];
667 constexpr const size_t NumSlices = ReadQueue;
668 constexpr const size_t SliceLength = StreamBytes / NumSlices;
670 Span<char> memory = streamStorage;
671 for (
size_t idx = 0; idx < NumSlices; ++idx)
674 (void)memory.sliceStartLength(idx * SliceLength, SliceLength, slice);
675 buffers[idx] = slice;
678 this->setHeaderMemory(headerStorage);
680 this->readableSocketStream.setReadQueue(readQueue);
681 this->writableSocketStream.setWriteQueue(writeQueue);
Definition AsyncStreams.h:67
A Span of bytes memory to be read or written by async streams.
Definition AsyncStreams.h:65
void setReusable(bool reusable)
Tags this AsyncBufferView as reusable after its refCount goes to zero.
Definition AsyncStreams.h:106
Holds a Span of AsyncBufferView (allocated by user) holding available memory for the streams.
Definition AsyncStreams.h:178
void setBuffers(Span< AsyncBufferView > newBuffers)
Sets memory for the new buffers.
Definition AsyncStreams.h:208
Pipes read data from SC::AsyncReadableStream, forwarding them to SC::AsyncWritableStream.
Definition AsyncStreams.h:561
Definition AsyncStreams.h:234
Async source abstraction emitting data events in caller provided byte buffers.
Definition AsyncStreams.h:229
Definition AsyncStreams.h:372
Async destination abstraction where bytes can be written to.
Definition AsyncStreams.h:365
Outgoing HTTP request sent by the client.
Definition HttpConnection.h:427
Incoming HTTP response received by the client.
Definition HttpConnection.h:258
Asynchronous HTTP/1.1 client using caller-provided fixed storage.
Definition HttpAsyncClient.h:85
Async Http Server.
Definition HttpAsyncServer.h:54
Shared async transport storage for HTTP client and server endpoints.
Definition HttpConnection.h:73
Definition HttpConnection.h:493
Http connection abstraction holding both the incoming and outgoing messages in an HTTP transaction.
Definition HttpConnection.h:489
Result sendBodyCopy(int httpCode, StringSpan body, StringSpan contentType={})
Sends a fixed-size response body by copying it into this connection's async buffer pool.
bool isWebSocketUpgraded() const
Returns true after the HTTP layer handed this connection to WebSocket code.
Definition HttpConnection.h:511
void reset()
Prepare this client for re-use, marking it as Inactive.
void markWebSocketUpgraded()
Marks this HTTP connection as handed off to a WebSocket owner after a successful upgrade.
Definition HttpConnection.h:508
ID getConnectionID() const
The ID used to find this client in HttpConnectionsPool.
Definition HttpConnection.h:505
Result sendTextCopy(int httpCode, StringSpan body)
Sends a text/plain; charset=utf-8 response body by copying it into this connection's async buffer poo...
Result sendJsonCopy(int httpCode, StringSpan body)
Sends an application/json response body by copying it into this connection's async buffer pool.
Definition HttpConnection.h:590
Definition HttpConnection.h:599
A pool of HttpConnection that can be active or inactive.
Definition HttpConnection.h:588
size_t getNumActiveConnections() const
Returns only the number of active connections.
Definition HttpConnection.h:618
size_t getHighestActiveConnection() const
Returns only the number of active connections.
Definition HttpConnection.h:624
HttpConnection & getConnectionAt(size_t idx)
Returns a connection in the [0, getNumTotalConnections] range.
Definition HttpConnection.h:633
bool activate(HttpConnection &connection, HttpConnection::ID &connectionID)
Activates a specific inactive connection owned by this pool.
Result init(SpanWithStride< HttpConnection > connectionsStorage)
Initializes the server with memory buffers for connections and headers.
bool activateNew(HttpConnection::ID &connectionID)
Finds an available connection (if any), activates it and returns its ID to use with getConnection(id)
HttpConnection & getConnection(HttpConnection::ID connectionID)
Returns a connection by ID.
Definition HttpConnection.h:627
size_t getNumTotalConnections() const
Returns the total number of connections (active + inactive)
Definition HttpConnection.h:621
Result close()
Closes the server, removing references to the memory buffers passed during init.
bool deactivate(HttpConnection::ID connectionID)
De-activates a connection previously returned by activateNew.
Definition HttpConnection.h:110
Incoming message from the perspective of the participants of an HTTP transaction.
Definition HttpConnection.h:108
Result writeHeaders(const uint32_t maxHeaderSize, Span< const char > readData, AsyncReadableStream &stream, AsyncBufferView::ID bufferID, bool stopAtHeadersEnd, bool unshiftPendingBodyToStream=true)
Parses an incoming slice of data eventually copying it to the availableHeader.
bool getKeepAlive() const
Gets whether the other party requested the connection to stay alive.
Definition HttpConnection.h:133
const AsyncReadableStream & getReadableStream() const
Obtains the readable stream for the message body.
AsyncReadableStream & getReadableStream()
Obtains the readable stream for the message body.
bool isMultipart() const
Checks if the request is a multipart/form-data request.
const HttpParser & getParser() const
Gets the associated HttpParser.
Definition HttpConnection.h:127
bool getHeader(StringSpan headerName, StringSpan &value) const
Gets the value of a specific header (case-insensitive name matching)
StringSpan getVersion() const
Gets the parsed HTTP protocol version token, for example HTTP/1.1
size_t getHeadersLength() const
Gets the length of the headers in bytes.
StringSpan getBoundary() const
Gets the multipart boundary string (if isMultipart() returns true)
bool findParserToken(HttpParser::Token token, StringSpan &res) const
Finds a specific HttpParser::Result in the list of parsed header.
Result consumeBodyBytes(size_t bytes)
Decrements the remaining body bytes after consuming data.
bool isBodyComplete() const
Returns true once the full body has been received according to its framing.
Definition HttpConnection.h:145
uint64_t getBodyBytesRemaining() const
Returns how many body bytes are still expected for this message.
Definition HttpConnection.h:142
bool hasReceivedHeaders() const
Returns true once the incoming message headers have been parsed.
Definition HttpConnection.h:130
HttpBodyFramingKind getBodyFramingKind() const
Returns the effective framing mode for the incoming body.
Definition HttpConnection.h:139
Definition HttpConnection.h:42
Definition HttpConnection.h:40
Definition HttpConnection.h:272
virtual Result asyncWrite(AsyncBufferView::ID bufferID, Function< void(AsyncBufferView::ID)> cb) override
Function that every stream must define to implement its custom write operation.
virtual bool canEndWritable() override
Allows keeping a writable in ENDING state until it has finished flushing all pending data.
Outgoing message from the perspective of the participants of an HTTP transaction.
Definition HttpConnection.h:270
Result setChunkedTransferEncoding()
Enables chunked transfer-encoding for subsequent body writes.
bool getKeepAlive() const
Gets whether the connection should be kept alive after this response.
Definition HttpConnection.h:330
Result end()
Finalizes the writable stream after sending all in progress writes.
void reset()
Resets this object for it to be re-usable.
Result sendHeaders(Function< void(AsyncBufferView::ID)> callback={})
Start sending response headers, before sending any data.
Result addContentLength(uint64_t value)
Adds a formatted Content-Length header without caller-side temporary formatting.
Result addHeader(StringSpan headerName, StringSpan headerValue)
Writes an http header to this response.
void setKeepAlive(bool keepAlive)
Sets whether to keep the connection alive after this response.
AsyncWritableStream & getWritableStream()
Obtain writable stream for sending content back to connected client.
Definition HttpConnection.h:321
Incremental HTTP request or response parser.
Definition HttpParser.h:16
Token
One possible Token reported by the parser.
Definition HttpParser.h:46
Method
Method of the current request / response.
Definition HttpParser.h:19
Type
Type of the stream to be parsed (Request or Response)
Definition HttpParser.h:63
Incoming HTTP request received by the server.
Definition HttpConnection.h:232
StringSpan getURL() const
Gets the request URL.
Definition HttpConnection.h:237
void reset()
Resets this object for it to be re-usable.
StringSpan getRequestTarget() const
Gets the raw request target from the request line.
Definition HttpConnection.h:234
Outgoing HTTP response sent by the server.
Definition HttpConnection.h:382
Result sendJson(int httpCode, StringSpan body)
Sends a caller-owned application/json response body.
Result startResponse(int httpCode)
Starts the response with a http standard code (200 OK, 404 NOT FOUND etc.)
Result startResponse(int httpCode, StringSpan reasonPhrase)
Starts the response with an explicit status code and reason phrase.
Result sendMethodNotAllowed(StringSpan allow)
Sends a 405 Method Not Allowed response with an Allow header and Content-Length: 0.
Result sendRedirect(int httpCode, StringSpan location)
Sends a 3xx redirect response with a Location header and Content-Length: 0.
Result sendBody(int httpCode, StringSpan body, StringSpan contentType={})
Sends a caller-owned fixed-size body response.
Result sendText(int httpCode, StringSpan body)
Sends a caller-owned text/plain; charset=utf-8 response body.
Result sendBytes(int httpCode, Span< const char > body, StringSpan contentType={})
Sends a caller-owned fixed-size byte response.
Result sendEmpty(int httpCode)
Sends an empty response with Content-Length: 0.
Result startBody(int httpCode, uint64_t contentLength, StringSpan contentType={})
Starts a fixed-size body response and adds Content-Length plus optional Content-Type.
Adds compile-time configurable read and write queues to any class subclassing HttpConnectionBase.
Definition HttpConnection.h:656
Low-level OS socket handle.
Definition Socket.h:207
View over a contiguous sequence of items with a custom stride between elements.
Definition HttpConnection.h:544
constexpr SpanWithStride(void *data, size_t sizeInElements, size_t strideInBytes)
Builds a SpanWithStride from data, size, and stride.
Definition HttpConnection.h:552
constexpr SpanWithStride()
Builds an empty SpanWithStride.
Definition HttpConnection.h:546