Stroika Library 3.0d18
 
Loading...
Searching...
No Matches
Frameworks/WebServer/Connection.h
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4#ifndef _Stroika_Framework_WebServer_Connection_h_
5#define _Stroika_Framework_WebServer_Connection_h_ 1
6
7#include "Stroika/Frameworks/StroikaPreComp.h"
8
9#include <optional>
10
12#include "Stroika/Foundation/Common/Common.h"
13#include "Stroika/Foundation/Common/Property.h"
15#include "Stroika/Foundation/IO/Network/HTTP/KeepAlive.h"
18#include "Stroika/Foundation/Streams/TextToBinary.h"
20
21#include "Stroika/Frameworks/WebServer/InterceptorChain.h"
22#include "Stroika/Frameworks/WebServer/Message.h"
23
24/*
25 * \note Code-Status: <a href="Code-Status.md#Beta">Beta</a>
26 */
27
29
30 using namespace Stroika::Foundation;
31 using namespace Stroika::Foundation::IO;
33
36
38
39 /**
40 * Write out files to %TEMP% dir, with logs of the details of the HTTP conversation, for debugging
41 * HTTP conversations.
42 */
43//#define qStroika_Framework_WebServer_Connection_DetailedMessagingLog 1
44#ifndef qStroika_Framework_WebServer_Connection_DetailedMessagingLog
45#define qStroika_Framework_WebServer_Connection_DetailedMessagingLog 0
46#endif
47
48 /**
49 * This has a slight cost, so you might want to compile it out of the implementation.
50 * At least useful when debugging.
51 */
52//#define qStroika_Framework_WebServer_Connection_TrackExtraStats 0
53#ifndef qStroika_Framework_WebServer_Connection_TrackExtraStats
54#define qStroika_Framework_WebServer_Connection_TrackExtraStats 1
55#endif
56
57 /**
58 * \brief A Connection object represents the state (and socket) for an ongoing, active, HTTP Connection, managed by the ConnectionManager class
59 *
60 * This tends to get used internally by the ConnectionManager, but you can use it directly. For example:
61 *
62 * \par Example Usage
63 * \code
64 * Connection conn{acceptedSocketConnection,
65 * Connection::Options{.fInterceptorChain = Sequence<Interceptor>{
66 * Interceptor{
67 * [=](Message* m) {
68 * Response& response = m->rwResponse ();
69 * response.rwHeaders().server = "stroika-ssdp-server-demo";
70 * response.write (Stroika::Frameworks::UPnP::Serialize (d, dd));
71 * response.contentType = DataExchange::InternetMediaTypes::kXML;
72 * }}}}};
73 * conn.SetRemainingConnectionMessages (Connection::Remaining{0, 0}); // disable keep-alives
74 * conn.ReadAndProcessMessage ();
75 * \endcode
76 *
77 * \note \em Thread-Safety <a href="Thread-Safety.md#C++-Standard-Thread-Safety">C++-Standard-Thread-Safety</a>
78 */
80 public:
81 struct Options {
82 /**
83 * This is largely required (though can be provided later). Without it, you don't get notified about progress of the HTTP connection.
84 */
85 InterceptorChain fInterceptorChain;
86
87 /**
88 * These are the default/baseline response headers which will be provided on all responses (except possibly GET)
89 */
90 Headers fDefaultResponseHeaders;
91
92 /**
93 * These are the default response headers for GET requests (if not provided, defaults to fDefaultResponseHeaders)
94 */
95 optional<Headers> fDefaultGETResponseHeaders;
96
97 /**
98 * \see WebServer::Response::autoComputeETagResponse
99 */
100 optional<bool> fAutoComputeETagResponse;
101
102 /**
103 * \see WebServer::Response::automaticTransferChunkSize (default is usually fine)
104 */
105 optional<size_t> fAutomaticTransferChunkSize;
106
107 /**
108 * \see WebServer::Request::bodyEncoding;
109 * This set is intersected with REQUEST.acceptEncoding headers to select encoding to use in Response bodyEncoding
110 * (if nullopt, auto-computed based on what is supported in Stroika)
111 */
112 optional<Containers::Set<HTTP::ContentEncoding>> fSupportedCompressionEncodings;
113 };
114
115 public:
116 /**
117 */
118 Connection () = delete;
119 Connection (const Connection&) = delete;
120 [[deprecated ("Since Stroika v3.0d7 - use the Options object with basically the same values")]] explicit Connection (
121 const ConnectionOrientedStreamSocket::Ptr& s, const InterceptorChain& interceptorChain = {}, const Headers& defaultResponseHeaders = {},
122 const optional<Headers>& defaultGETResponseHeaders = nullopt, const optional<bool> autoComputeETagResponse = nullopt);
123 Connection (const ConnectionOrientedStreamSocket::Ptr& s, const Options& options);
124
125 public:
126 ~Connection ();
127
128 public:
129 nonvirtual Connection& operator= (const Connection&) = delete;
130
131 public:
132 /**
133 * This returns the (two way) connection oriented stream socket (ptr) used by this connection.
134 */
136
137 public:
138 /**
139 * Access a (read-only) reference of the underlying connection request
140 */
142
143 public:
144 /**
145 * Access a (read-only) reference of the underlying connection request
146 */
148
149 public:
150 /**
151 * Access a (read-only) reference to the underlying (modifiable) connection response (meaning you cannot assign to the response itself, but you can modify the response object)
152 */
154
155 public:
156 /**
157 * Mostly for debugging, but also for ongoing operational diagnostics (late season debugging ;-)).
158 *
159 * \todo - https://stroika.atlassian.net/browse/STK-1025 - Stats should have STATE flag
160 * \todo - Consider ALSO adding a Request URI - which might be helpful for debugging when deadlocks happen.
161 */
162 struct Stats {
163 /**
164 * Unique (at a given time) 'ID' which can be used to track the connection stats across calls to get stats.
165 * (note fUniqueID is opaque integer)
166 */
168
169 /**
170 * Is this connection object currently 'connected' (socket level listen or accept returned).
171 */
172 optional<bool> fActive;
173
174 /**
175 * When the connection object was created
176 */
177 TimePointSeconds fCreatedAt;
178
179#if qStroika_Framework_WebServer_Connection_TrackExtraStats
180 /**
181 */
182 optional<Traversal::Range<TimePointSeconds>> fMostRecentMessage;
183
184 /**
185 */
186 optional<thread::id> fHandlingThread;
187
188 /**
189 * \brief the address of the client which is talking to the server
190 */
191 optional<SocketAddress> fRemotePeerAddress;
192
193 /**
194 * \brief last request
195 */
196 optional<String> fRequestWebMethod;
197
198 /**
199 * \brief last requested URI (always relative uri)
200 */
201 optional<URI> fRequestURI;
202#endif
203
204 /**
205 * @see Characters::ToString ();
206 */
207 nonvirtual String ToString () const;
208 };
209
210 public:
211 /**
212 * \brief retrieve stats about this connection, like threads used, start/end times. NB: INTERNALLY SYNCRONIZED
213 *
214 * \note \em Thread-Safety <a href='#Internally-Synchronized-Thread-Safety'>Internally-Synchronized-Thread-Safety</a>
215 */
217
218 public:
219 /**
220 */
221 enum ReadAndProcessResult {
222 eTryAgainLater, // Could mean success or some kinds of failure (like incomplete header/data), but try again later (so keep-alive results in this)
223 eClose,
224 };
225
226 public:
227 /**
228 * Return eTryAgainLater if 'keep alive' (or otherwise should try again - like incomplete input).
229 */
230 nonvirtual ReadAndProcessResult ReadAndProcessMessage () noexcept;
231
232 public:
233 /**
234 * \note set Remaining::fMessages := 0 to prevent keep-alives.
235 *
236 * \par Example Usage
237 * \code
238 * conn.remainingConnectionLimits = KeepAlive{0, 0}; // disable keep-alives
239 * \endcode
240 */
241 Common::Property<optional<HTTP::KeepAlive>> remainingConnectionLimits;
242
243#if qStroika_Framework_WebServer_Connection_DetailedMessagingLog
244 private:
245 nonvirtual void WriteLogConnectionMsg_ (const String& msg) const;
246#endif
247
248 public:
249 /**
250 * @see Characters::ToString ();
251 */
252 nonvirtual String ToString (bool abbreviatedOutput = true) const;
253
254 private:
255 struct MyMessage_ : Message {
257 const Headers& defaultResponseHeaders, const optional<bool> autoComputeETagResponse);
258
259 // Only valid until the end of a successful ReadHeaders
261
262 // If result bad, throw exception
263 enum ReadHeadersResult {
264 eIncompleteButMoreMayBeAvailable,
265 eIncompleteDeadEnd,
266 eCompleteGood
267 };
268 nonvirtual ReadHeadersResult ReadHeaders (
269#if qStroika_Framework_WebServer_Connection_DetailedMessagingLog
270 const function<void (const String&)>& logMsg
271#endif
272 );
273 };
274
275 private:
276 const InterceptorChain fInterceptorChain_;
277 const Headers fDefaultResponseHeaders_;
278 const optional<Headers> fDefaultGETResponseHeaders_;
279 const optional<bool> fAutoComputeETagResponse_;
280 const optional<Containers::Set<HTTP::ContentEncoding>> fSupportedCompressionEncodings_;
283 const TimePointSeconds fConnectionStartedAt_{};
284 unique_ptr<MyMessage_> fMessage_; // always there, but ptr so it can be replaced
285 optional<HTTP::KeepAlive> fRemaining_;
286#if qStroika_Framework_WebServer_Connection_TrackExtraStats
287 struct Stats2Capture_ {
288 optional<TimePointSeconds> fMessageStart;
289 optional<TimePointSeconds> fMessageCompleted;
290 optional<SocketAddress> fPeer;
291 optional<String> fWebMethod;
292 optional<URI> fRequestURI;
293 thread::id fHandlingThread; // thread::id{} sentinel
294 };
295 static_assert (is_default_constructible_v<Stats2Capture_>);
297#endif
298#if qStroika_Framework_WebServer_Connection_DetailedMessagingLog
299 Streams::OutputStream::Ptr<Character> fLogConnectionState_;
300#endif
301 };
302
303}
304
305/*
306 ********************************************************************************
307 ***************************** Implementation Details ***************************
308 ********************************************************************************
309 */
310#include "Connection.inl"
311
312#endif /*_Stroika_Framework_WebServer_Connection_h_*/
time_point< RealtimeClock, DurationSeconds > TimePointSeconds
TimePointSeconds is a simpler approach to chrono::time_point, which doesn't require using templates e...
Definition Realtime.h:82
String is like std::u32string, except it is much easier to use, often much more space efficient,...
Definition String.h:201
NOT a real mutex - just a debugging infrastructure support tool so in debug builds can be assured thr...
Wrap any object with Synchronized<> and it can be used similarly to the base type,...
roughly equivalent to Association<String,String>, except that the class is smart about certain keys a...
Definition Headers.h:129
InputOutputStream is single stream object that acts much as a InputStream::Ptr and an OutputStream::P...
OutputStream<>::Ptr is Smart pointer to a stream-based sink of data.
A Connection object represents the state (and socket) for an ongoing, active, HTTP Connection,...
Common::Property< optional< HTTP::KeepAlive > > remainingConnectionLimits
const Common::ReadOnlyProperty< Stats > stats
retrieve stats about this connection, like threads used, start/end times. NB: INTERNALLY SYNCRONIZED
const Common::ReadOnlyProperty< ConnectionOrientedStreamSocket::Ptr > socket
nonvirtual ReadAndProcessResult ReadAndProcessMessage() noexcept
const Common::ReadOnlyProperty< const Request & > request
const Common::ReadOnlyProperty< const Response & > response
nonvirtual String ToString(bool abbreviatedOutput=true) const
optional< URI > fRequestURI
last requested URI (always relative uri)
optional< SocketAddress > fRemotePeerAddress
the address of the client which is talking to the server