libhttppp ..
Loading...
Searching...
No Matches
http.h
1/*******************************************************************************
2Copyright (c) 2014, Jan Koester jan.koester@gmx.net
3All rights reserved.
4
5Redistribution and use in source and binary forms, with or without
6modification, are permitted provided that the following conditions are met:
7 * Redistributions of source code must retain the above copyright
8 notice, this list of conditions and the following disclaimer.
9 * Redistributions in binary form must reproduce the above copyright
10 notice, this list of conditions and the following disclaimer in the
11 documentation and/or other materials provided with the distribution.
12 * Neither the name of the <organization> nor the
13 names of its contributors may be used to endorse or promote products
14 derived from this software without specific prior written permission.
15
16THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
20DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*******************************************************************************/
27
28#include <stddef.h>
29#include <sys/types.h>
30
31#include <vector>
32#include <string>
33#include <memory>
34#include <deque>
35#include <map>
36
37#include <netplus/socket.h>
38#include <netplus/connection.h>
39#include <netplus/eventapi.h>
40
41#include "config.h"
42
43#include "httpdefinitions.h"
44#include "hpack.h"
45
46#pragma once
47
48namespace libhttppp::qpack { struct HeaderField; }
49
50namespace libhttppp {
51 class HttpRequest;
52
53 class HttpUrl {
54 public:
55 enum HttpProtocol{
56 HTTP=0,
57 HTTPS=1,
58 HTTP3=2
59 };
60
61 HttpUrl();
62 HttpUrl(const std::string &url,bool http3=false);
63 HttpUrl(const HttpUrl &src);
64 ~HttpUrl();
65
66 bool operator==(const HttpUrl& other) const;
67 bool operator<(const HttpUrl& other) const;
68
69 int getProtocol() const;
70 const std::string &getHost() const;
71 int getPort() const;
72 const std::string &getPath() const;
73
74 void clear();
75
76 std::string print() const;
77
78 private:
79 int _protocol;
80 std::string _host;
81 int _port;
82 std::string _path;
83 };
84
85 class HttpResponse;
86
88 public:
89 HttpClient( const HttpUrl &desturl, int vers = 2);
90 ~HttpClient()=default;
91 void reconnect();
92 void setTimeout(int timeout_sec);
93 const std::vector<char> Get(HttpRequest &nreq, size_t maxTries=0);
94 const std::vector<char> Post(HttpRequest &nreq,const std::vector<char> &post, size_t maxTries=0);
95 const std::vector<char> Put(HttpRequest &nreq,const std::vector<char> &put, size_t maxTries=0);
96 const std::vector<char> Delete(HttpRequest &nreq, size_t maxTries=0);
97
98 // Streaming API: send request, return parsed response headers only.
99 // After this call, use readBodyChunk() to read body data incrementally.
100 HttpResponse GetStream(HttpRequest &nreq);
101
102 // Read the next chunk of body data (up to bufsize bytes).
103 // Returns number of bytes written to buf, 0 when body is complete.
104 size_t readBodyChunk(char *buf, size_t bufsize);
105
106 // Non-blocking variant: returns 0 immediately if no data available yet.
107 // Returns (size_t)-1 when stream is complete (no more data will come).
108 size_t readBodyChunkNonBlocking(char *buf, size_t bufsize);
109
110 // True while a streaming read is in progress.
111 bool isStreaming() const;
112
113 // Wait until upstream socket has data to read (or timeout expires).
114 // timeout_ms: -1 = infinite, 0 = return immediately, >0 = milliseconds
115 // Returns true if readable, false on timeout.
116 bool waitReadable(int timeout_ms);
117
118 // Shared TLS session cache — enables abbreviated TLS 1.2 handshakes
119 // across reconnects to the same host. One cache per process.
120 static netplus::TlsSessionCache& tlsSessionCache();
121 private:
122 void resetConnection();
123 void _ensureConnected();
124 bool tryHttp3First();
125 int readchunk(const char *data,int datasize,int &pos);
126
127 // Non-blocking I/O helpers using poll() for efficient waiting
128 size_t _recvBlocking(netplus::buffer &b, int timeout_sec = 0);
129 // Returns 0 on EAGAIN (no data yet), otherwise bytes read
130 size_t _recvNonBlocking(netplus::buffer &b);
131 void _sendAll(const char *data, size_t len);
132 void _sendAll(const std::string &data);
133
134 // Shared HTTP/1.x response reader (avoids code duplication)
135 std::vector<char> _h1ReadResponse(const std::string &label);
136
137 // HTTP/2 client helpers
138 bool _isH2 = false;
139 bool _h2PrefaceSent = false; // true after connection preface sent
140
141 // HTTP/3 client helpers
142 uint32_t _h2NextStreamId = 1; // next client-initiated stream ID (odd)
143 std::unique_ptr<hpack::Decoder> _h2Decoder; // persistent HPACK decoder for connection
144 const std::vector<char> _h2Request(const std::string &method,
145 HttpRequest &nreq,
146 const std::vector<char> *postBody = nullptr);
147 const std::vector<char> _h3Request(const std::string &method,
148 HttpRequest &nreq,
149 const std::vector<char> *postBody = nullptr);
150
151 // Streaming state
152 enum StreamMode { STREAM_NONE, STREAM_CONTENT_LENGTH, STREAM_CHUNKED, STREAM_EOF,
153 STREAM_H2, STREAM_H3 };
154 StreamMode _streamMode = STREAM_NONE;
155 size_t _streamRemaining = 0; // bytes left for content-length mode
156 std::vector<char> _streamBuf; // leftover data from header read
157 size_t _streamBufPos = 0;
158 // Chunked streaming sub-state
159 bool _streamChunkDone = false; // true after final 0-length chunk
160 size_t _streamChunkRemaining = 0; // bytes left in current chunk
161
162 // HTTP/2 streaming state
163 uint32_t _streamH2Sid = 0; // stream ID for active H2 stream
164 bool _streamH2EndStream = false;
165 std::vector<uint8_t> _streamH2Raw; // raw frame buffer
166
167 // HTTP/3 streaming state
168 uint64_t _streamH3Sid = 0; // stream ID for active H3 stream
169 bool _streamH3EndStream = false;
170 std::vector<uint8_t> _streamH3Raw; // raw frame buffer
171 std::vector<char> _streamH3Body; // decoded DATA frames not yet consumed
172 size_t _streamH3BodyPos = 0; // consumed offset into _streamH3Body
173 bool _streamH3InDataFrame = false; // true when inside a partial DATA frame
174 uint64_t _streamH3DataRemaining = 0; // bytes left in current DATA frame
175
176 private:
177 HttpUrl _url;
178 std::unique_ptr<netplus::socket> _cltsock;
179 netplus::socketwait _sw;
180 netplus::x509cert _cert;
181 int _recvTimeoutSec = 60;
182 int _sendTimeoutSec = 30;
183 };
184
185
187 public:
189 public:
190 class Values{
191 public:
192 Values &operator=(const std::string &val);
193 Values &operator=(size_t val);
194 Values &operator=(int val);
195 Values& operator=(const Values &val);
196
197 Values &operator<<(const std::string &value);
198 Values &operator<<(size_t value);
199 Values &operator<<(int value);
200
201 const std::string &getvalue();
202 int getIntvalue();
203 size_t getSizetValue();
204
205 Values *nextvalue();
206 Values(const std::string& val);
207 Values(const Values& val);
208 Values()=default;
209 ~Values() = default;
210 private:
211 std::string _value;
212 std::unique_ptr<Values> _nextvalue=nullptr;
213 friend class HeaderData;
214 };
215
216 Values *getfirstValue();
217 Values &at(int pos);
218 Values &operator[](int pos);
219
220 void push_back(const Values &val);
221 void push_back(const std::string &val);
222 void push_back(const char* val);
223 void push_back(size_t val);
224 void push_back(int val);
225
226 bool empty();
227
228 void erase(int pos);
229
230 void clear();
231
232 const std ::string &getkey();
233
234 HeaderData *nextHeaderData();
235 HeaderData(const std ::string &key);
236 ~HeaderData() = default;
237 private:
238 std::string _Key;
239 std::unique_ptr<Values> _firstValue=nullptr;
240 Values *_lastValue=nullptr;
241 std::unique_ptr<HeaderData> _nextHeaderData=nullptr;
242 friend class HttpHeader;
243 };
244
245 HeaderData *getfirstHeaderData();
246 HeaderData *getHeaderData(const std ::string &key) const;
247 HeaderData *setHeaderData(const std ::string &key);
248
249 void deldata(const std ::string &key);
250 void deldata(HeaderData*pos);
251
252 size_t getElements();
253 size_t getHeaderSize();
254
255 void clear();
256 protected:
257 HttpHeader();
258 virtual ~HttpHeader()=default;
259 std::unique_ptr<HeaderData> _firstHeaderData;
260 HeaderData *_lastHeaderData;
261 };
262
263 class HttpResponse : public HttpHeader,public netplus::con {
264 public:
265 HttpResponse();
266 HttpResponse(const HttpResponse &src);
268
269 /*server methods*/
270 void setState(const std ::string &httpstate);
271 void setContentType(const std ::string &type);
272 void setContentLength(size_t len);
273 void setConnection(const std ::string &type);
274 void setTransferEncoding(const std ::string &enc);
275
276 /*client methods*/
277 const std ::string &getState() const;
278 int getStatusCode() const;
279 const std ::string &getContentType() const;
280 size_t getContentLength() const;
281 const std ::string &getConnection() const;
282 const std ::string &getVersion() const;
283 HttpHeader::HeaderData::Values *getTransferEncoding() const;
284
285 size_t printHeader(std::vector<char> &buffer);
286
287 /*server methods*/
288 void send(netplus::con &curconnection,const std::string &data,int datalen=0); //only use as server
289 void send(netplus::con &curconnection,const unsigned char *data,int datalen); //only use as server
290 void send(netplus::con &curconnection,const std::vector<char> &data,int datalen=0); //only use as server
291
292 /*client method*/
293 size_t parse(const char *in,size_t inlen);
294
295 private:
296 bool _storeResponseInfo(netplus::con &curconnection, int datalen);
297
298 std::string _State=HTTP200;
299 std::string _Version;
300 int _StatusCode=200;
301 HeaderData *_TransferEncoding;
302 HeaderData *_Connection;
303 HeaderData *_ContentType;
304 HeaderData *_ContentLength;
305 mutable std::string _ContentTypeCache;
306 };
307
308
309 class HttpRequest : public HttpHeader, public netplus::con{
310 public:
311 HttpRequest();
312 HttpRequest(netplus::eventapi *evapi);
313 ~HttpRequest();
314
315 void clear();
316
317 /*server methods*/
318
319 size_t parse(); //only use as server
320
321 /*protocol-specific parse helpers (all store into _firstHeaderData)*/
322 size_t parseH2(const std::vector<hpack::HeaderField> &headers, uint32_t stream_id = 0);
323 size_t parseH3(const std::vector<qpack::HeaderField> &headers);
324
325 void printHeader(std::string &buffer);
326 int getRequestType();
327 const std::string &getRequestURL();
328 const std::string &getRequest();
329 size_t getRequestLength();
330 const std::string &getRequestVersion();
331 size_t getContentLength();
332 size_t getMaxUploadSize();
333
334 /*mobilphone switch*/
335 bool isMobile();
336
337 /*Client methods*/
338 void setRequestType(int req);
339 void setRequestURL(const std::string &url);
340 void setRequestVersion(const std::string &version);
341 /*only for post Reuquesttype*/
342 void setRequestData(const std::string &data,size_t len);
343 void setMaxUploadSize(size_t upsize);
344
345 void send(const HttpUrl &dest,std::unique_ptr<netplus::socket> &sock);
346
347 private:
348 size_t parseH1(); // HTTP/1.x request parsing
349
350 /*
351 * Helper: extracts URL path from :path header (strips query string).
352 * Used by getRequestURL() and parse helpers.
353 */
354 static std::string extractPath(const std::string &target);
355
356 int _RequestType = PARSEREQUEST;
357 size_t _MaxUploadSize = DEFAULT_UPLOADSIZE;
358
359 // Cached strings derived from _firstHeaderData pseudo-headers.
360 // Populated by parseH1/parseH2/parseH3, read by getters.
361 mutable std::string _cachedRequestURL;
362 mutable std::string _cachedRequest;
363 mutable std::string _cachedRequestVersion;
364
365 // HTTP/2 and HTTP/3 protocol state (managed by HttpEvent).
366 // All H2-specific mutable state lives in a heap-allocated struct so
367 // that inline-layout corruption of HttpRequest cannot trash the
368 // deque / map / decoder internals.
369 int _httpProtocol = 0; // 0=HTTP/1.x, 1=HTTP/2, 2=HTTP/3
370
371 struct H2PendingResponse {
372 uint32_t streamId;
373 std::string body; // remaining body data to send as DATA frames
374 size_t offset = 0; // how far into body we've sent
375 };
376
377 // Active streaming response state — lives on the connection's H2State
378 // so Http2RequestEvent can resume sending after WINDOW_UPDATE.
379 struct H2StreamingResponse {
380 uint32_t streamId = 0;
381 size_t contentLength = 0;
382 size_t totalSent = 0;
383 std::string pendingData; // buffered DATA not yet framed
384 size_t pendingOffset = 0;
385 std::unique_ptr<HttpRequest> tempreq; // per-stream request for ResponseEvent
386 int tid = 0;
387 ULONG_PTR args = 0;
388 size_t emptyCount = 0;
389 unsigned int backoffMs = 1;
390 bool finished = false;
391 };
392
393 struct H2PendingIncoming {
394 std::vector<hpack::HeaderField> headers;
395 std::string body;
396 std::vector<uint8_t> rawHpack; // accumulates HPACK across CONTINUATION frames
397 bool headersComplete = false; // true once END_HEADERS received
398 bool endStreamOnHeaders = false; // END_STREAM was on HEADERS frame
399 bool streaming = false; // body handled by onH2DataChunk callback
400 };
401
402 struct H2State {
403 uint32_t streamId = 0;
404 bool headersSent = false;
405 bool serverPrefaceSent = false;
406 size_t expectedContentLength = 0;
407 size_t bodyBytesSent = 0;
408 std::deque<H2PendingResponse> pendingResponses;
409 std::map<uint32_t, H2PendingIncoming> pendingIncoming;
410 hpack::Decoder hpackDecoder;
411 // Peer flow-control windows (RFC 7540 §6.9)
412 int32_t peerConnWindow = 65535; // connection-level
413 int32_t peerInitialStreamWindow = 65535; // from peer SETTINGS
414 size_t peerMaxFrameSize = 16384; // from peer SETTINGS_MAX_FRAME_SIZE (0x05)
415 std::map<uint32_t, int32_t> peerStreamWindows; // per-stream
416 // Active streaming responses (one per stream)
417 std::map<uint32_t, std::shared_ptr<H2StreamingResponse>> activeStreams;
418 };
419
420 // Lazily allocated when the connection is upgraded to HTTP/2.
421 std::unique_ptr<H2State> _h2;
422
423 // Allocate H2 state if not yet present; return reference.
424 H2State &h2state() {
425 if (!_h2) _h2 = std::make_unique<H2State>();
426 return *_h2;
427 }
428
429 friend class HttpForm;
430 friend class HttpResponse;
431 friend class HttpEvent;
432 };
433
434 class HttpForm {
435 public:
436 // ─── Multipart form-data (RFC 2046) ───────────────────
438 struct Header {
439 std::string key; // lowercased header name (e.g. "content-disposition")
440 std::string value; // full header value
441 };
442
443 struct Disposition {
444 std::string key; // e.g. "name", "filename"
445 std::string value; // e.g. "field1", "upload.txt"
446 };
447
448 std::vector<Header> headers;
449 std::vector<Disposition> dispositions;
450 std::vector<char> value; // raw body (binary-safe for file uploads)
451 };
452
453 // ─── URL-encoded form data ────────────────────────────
454 struct UrlEntry {
455 std::string key;
456 std::string value;
457 };
458
459 HttpForm() = default;
460 ~HttpForm() = default;
461
462 void parse(HttpRequest &request);
463
464 // Accessors
465 const std::string &getContentType() const { return _contentType; }
466 const std::string &getBoundary() const { return _boundary; }
467 const std::vector<MultipartEntry> &multipartData() const { return _multipartEntries; }
468 const std::vector<UrlEntry> &urlData() const { return _urlEntries; }
469
470 // URL encoding / decoding utilities
471 static void urlDecode(const std::string &in, std::string &out);
472 static void urlEncode(const std::string &in, std::string &out);
473
474 private:
475 void _parseMultipart(const char *data, size_t len);
476 void _parseMultiSection(const char *data, size_t len, size_t start, size_t end);
477 void _parseUrlDecode(const char *data, size_t len);
478
479 std::string _boundary;
480 std::string _contentType;
481 std::vector<MultipartEntry> _multipartEntries;
482 std::vector<UrlEntry> _urlEntries;
483 };
484
486 public:
488 public:
489 CookieData *nextCookieData() const;
490 const std::string &getKey() const;
491 const std::string &getValue() const;
492 CookieData()=default;
493 CookieData(const CookieData& src);
494 ~CookieData();
495 private:
496 std::string _Key;
497 std::string _Value;
498 std::unique_ptr <CookieData> _nextCookieData=nullptr;
499
500 friend class HttpCookie;
501 };
502 HttpCookie();
503 ~HttpCookie();
504 void parse(libhttppp::HttpRequest& curreq);
505 void setcookie(libhttppp::HttpResponse& curresp,
506 const std::string &key,const std::string &value,
507 const std::string &comment="",const std::string &domain="",
508 int maxage=-1,const std::string &path="",
509 bool secure=false,const std::string &version="1",const std::string &samesite="",bool httponly=false);
510 CookieData *getfirstCookieData();
511 CookieData *getlastCookieData();
512 CookieData *addCookieData();
513 private:
514 std::unique_ptr <CookieData> _firstCookieData;
515 CookieData *_lastCookieData;
516 };
517
518#define BASICAUTH 0
519#define DIGESTAUTH 1
520#define NTLMAUTH 2
521
522 class HttpAuth {
523 public:
524 HttpAuth();
525 ~HttpAuth();
526 void parse(libhttppp::HttpRequest &curreq);
527 void setAuth(libhttppp::HttpResponse &curresp);
528
529 void setAuthType(int authtype);
530 void setRealm(const std::string &realm);
531 void setUsername(const std::string &username);
532 void setPassword(const std::string &password);
533
534 const std::string &getUsername();
535 const std::string &getPassword();
536 int getAuthType();
537 const std::string &getAuthRequest();
538
539 private:
540 int _Authtype;
541 std::string _Username;
542 std::string _Password;
543 std::string _Realm;
544 std::string _Nonce;
545
546 };
547};
Definition https.h:38
Definition http.h:522
Definition http.h:87
Definition http.h:485
Definition httpd.h:50
Definition http.h:434
Definition http.h:186
Definition http.h:309
Definition http.h:263
Definition http.h:53
Definition hpack.h:68
Definition http.h:454