yum-mirror/slang

Making it easier to work with shaders

git clone https://git.yummers.dev/yum-mirror/slang

Ellie Hermaszewskaformatf65d756bf

master
5.8 KiB182 linesraw
1#ifndef SLANG_CORE_HTTP_H
2#define SLANG_CORE_HTTP_H
3
4#include "slang-com-helper.h"
5#include "slang-com-ptr.h"
6#include "slang-list.h"
7#include "slang-memory-arena.h"
8#include "slang-stream.h"
9#include "slang-string.h"
10#include "slang.h"
11
12namespace Slang
13{
14
15/// All of the contained UnownedStringSlice can be stored in m_header. This can be checked via
16/// testing if the memory overlaps.
17///
18/// The m_arena can be used to store slices in an ad-hoc manner to keep in scope with the Header.
19struct HTTPHeader
20{
21    struct Pair
22    {
23        UnownedStringSlice key;
24        UnownedStringSlice value;
25    };
26
27    /// Append the header (including termination) to out
28    void append(StringBuilder& out) const;
29
30    /// Reset the contents
31    void reset();
32
33    SLANG_INLINE Index indexOfKey(const UnownedStringSlice& slice) const;
34
35    /// Ctor
36    HTTPHeader()
37        : m_arena(1024)
38    {
39    }
40
41    /// Reads from stream until the buffer contains all of the header. The outEndIndex will point
42    /// past the header termination.
43    static SlangResult readHeaderText(BufferedReadStream* stream, Index& outEndIndex);
44
45    /// Returns the index of the end of the header (index of first byte *after* the header), or < if
46    /// doesn't have an end
47    static Index findHeaderEnd(BufferedReadStream* stream);
48
49    /// Parse the slice (holding a header) into out.
50    /// Will allocate the slice on the array and store in m_header.
51    /// Slices will reference sections of m_header, that may be useful in some scenarios.
52    static SlangResult parse(const UnownedStringSlice& slice, HTTPHeader& out);
53
54    /// Read from buffered stream header, and place parsed header into out
55    static SlangResult read(BufferedReadStream* stream, HTTPHeader& out);
56
57    size_t m_contentLength; ///< Content length in bytes
58
59    UnownedStringSlice m_mimeType; ///< The mime type
60    UnownedStringSlice m_encoding; ///< The character encoding
61
62    UnownedStringSlice m_header; ///< Optionally holds the whole of the header
63
64    List<Pair> m_valuePairs; /// All of the value pairs
65
66    MemoryArena m_arena; ///< Used to store backing memory
67
68private:
69    // Disable
70    HTTPHeader(const HTTPHeader&) = delete;
71    void operator=(const HTTPHeader&) = delete;
72};
73
74// -----------------------------------------------------------------
75Index HTTPHeader::indexOfKey(const UnownedStringSlice& slice) const
76{
77    return m_valuePairs.findFirstIndex(
78        [&](const HTTPHeader::Pair& pair) -> bool { return pair.key == slice; });
79}
80
81/// Implements a way to communicate over Streams via the HTTP *protocol*.
82///
83/// Allows for reading without blocking, via calls to 'update'. When a complete
84/// HTTP 'packet' (combination of header and content) is available, the ReadState will
85/// become 'Done'. For this to work without blocking it relies on the stream backing the
86/// BufferedReadStream to be non blocking.
87///
88/// If it is only necessary to respond on complete packets 'waitForContent' can be used.
89/// If this returns and ReadState is Done, then getHeader holds the current header, and getContent
90/// holds the content of the 'packet'.
91///
92/// Once the packet has been processed 'consumeContent' can be used. Once consumeContent is called
93/// both contents of getContent and getReadHeader will no longer be valid.
94///
95/// Ie using the slice returned from getContent *after* consumeContent is called is *undefined
96/// behavior*.
97///
98/// NOTE! that this does not implement HTTP over TCP/IP.
99/// That said it could be used to communicate via the HTTP protocol over TCP/IP
100/// if the Streams supplied were TCP/IP sockets.
101class HTTPPacketConnection : public RefObject
102{
103public:
104    enum class ReadState
105    {
106        Header,  ///< Reading reader
107        Content, ///< Reading content (ie header is read)
108        Done,    ///< The content is read
109        Closed,  ///< The read stream is closed - no further packets can be read
110        Error,   ///< In an error state - no further packets can be read
111    };
112
113    /// Update state
114    SlangResult update();
115    /// Get the current read staet
116    ReadState getReadState() const { return m_readState; }
117    /// Get the read header
118    const HTTPHeader& getReadHeader() const
119    {
120        SLANG_ASSERT(hasHeader());
121        return m_readHeader;
122    }
123    /// Get the content
124    ConstArrayView<Byte> getContent() const
125    {
126        SLANG_ASSERT(m_readState == ReadState::Done);
127        return ConstArrayView<Byte>(
128            (const Byte*)m_readStream->getBuffer(),
129            m_readHeader.m_contentLength);
130    }
131
132    /// Write. Will potentially block if write stream is blocking.
133    SlangResult write(const void* content, size_t sizeInBytes);
134
135    /// Blocks until some result - a packet, closure, or some kind of error or timeout.
136    /// TimeOut of -1 means no timeout.
137    SlangResult waitForResult(Int timeOutInMs = -1);
138    /// Consume the content - so can read next content
139    void consumeContent();
140
141    /// True if connection is active.
142    bool isActive() const
143    {
144        return m_readState != ReadState::Error && m_readState != ReadState::Closed;
145    }
146
147    bool hasHeader() const
148    {
149        return m_readState == ReadState::Content || m_readState == ReadState::Done;
150    }
151    /// True if has content (implies has header)
152    bool hasContent() const { return m_readState == ReadState::Done; }
153
154    /// Ctor
155    HTTPPacketConnection(BufferedReadStream* readStream, Stream* writeStream);
156
157protected:
158    SlangResult _updateReadResult(SlangResult res)
159    {
160        if (SLANG_FAILED(res) && SLANG_SUCCEEDED(m_readResult))
161        {
162            m_readState = ReadState::Error;
163            m_readResult = res;
164        }
165        return res;
166    }
167
168    SlangResult _handleHeader();
169    SlangResult _handleContent();
170
171    SlangResult m_readResult;
172    HTTPHeader m_readHeader;
173
174    ReadState m_readState;
175
176    RefPtr<BufferedReadStream> m_readStream;
177    RefPtr<Stream> m_writeStream;
178};
179
180} // namespace Slang
181
182#endif // SLANG_CORE_HTTP_H