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#include <unordered_map>
37#include <chrono>
38
39#include <netplus/socket.h>
40#include <netplus/connection.h>
41#include <netplus/eventapi.h>
42#include <netplus/crypto/tls.h>
43
44#include "config.h"
45
46#include "httpdefinitions.h"
47#include "hpack.h"
48
49#pragma once
50
51namespace libhttppp::qpack { struct HeaderField; }
52
53namespace libhttppp {
54 class HttpRequest;
55
56 class HttpUrl {
57 public:
58 enum HttpProtocol{
59 HTTP=0,
60 HTTPS=1,
61 HTTP3=2
62 };
63
64 HttpUrl();
65 HttpUrl(const std::string &url,bool http3=false);
66 HttpUrl(const HttpUrl &src);
67 HttpUrl& operator=(const HttpUrl &src) = default;
68 ~HttpUrl();
69
70 bool operator==(const HttpUrl& other) const;
71 bool operator<(const HttpUrl& other) const;
72
73 int getProtocol() const;
74 // The scheme (HTTP or HTTPS) as it actually appeared in the URL string,
75 // unaffected by the http3 ctor flag -- getProtocol() returns HTTP3 once
76 // that flag is set, which loses the info needed to fall back correctly
77 // when HTTP/3 isn't available.
78 int getOriginalProtocol() const;
79 const std::string &getHost() const;
80 int getPort() const;
81 const std::string &getPath() const;
82
83 void clear();
84
85 std::string print() const;
86
87 private:
88 int _protocol;
89 int _origProtocol;
90 std::string _host;
91 int _port;
92 std::string _path;
93 };
94
95 class HttpResponse;
96
98 public:
99 // timeoutSec bounds the constructor's own eager connection attempt
100 // (see resetConnection()) in addition to being the initial value
101 // setTimeout() would otherwise set afterward -- too late to affect
102 // that first connect.
103 HttpClient( const HttpUrl &desturl, int vers = 2, int timeoutSec = 60);
104 ~HttpClient()=default;
105 void reconnect();
106 void setTimeout(int timeout_sec);
107 const std::vector<char> Get(HttpRequest &nreq, size_t maxTries=0);
108 const std::vector<char> Post(HttpRequest &nreq,const std::vector<char> &post, size_t maxTries=0);
109 const std::vector<char> Put(HttpRequest &nreq,const std::vector<char> &put, size_t maxTries=0);
110 const std::vector<char> Delete(HttpRequest &nreq, size_t maxTries=0);
111
112 // Streaming API: send request, return parsed response headers only.
113 // After this call, use readBodyChunk() to read body data incrementally.
114 HttpResponse GetStream(HttpRequest &nreq);
115
116 // Same as GetStream, but POSTs a body first (e.g. an OpenAI-compatible
117 // "stream": true chat-completions request) before entering streaming-
118 // read mode. HTTP/1.1 upstream connections only -- throws HTTPException
119 // for HTTP/2 or HTTP/3 connections (no redirect handling either, unlike
120 // Post()); local LLM inference backends are plain HTTP/1.1 services, so
121 // this deliberately doesn't replicate Post()'s H2/H3/redirect handling.
122 HttpResponse PostStream(HttpRequest &nreq, const std::vector<char> &postBody);
123
124 // Read the next chunk of body data (up to bufsize bytes).
125 // Returns number of bytes written to buf, 0 when body is complete.
126 size_t readBodyChunk(char *buf, size_t bufsize);
127
128 // Non-blocking variant: returns 0 immediately if no data available yet.
129 // Returns (size_t)-1 when stream is complete (no more data will come).
130 size_t readBodyChunkNonBlocking(char *buf, size_t bufsize);
131
132 // True while a streaming read is in progress.
133 bool isStreaming() const;
134
135 // Wait until upstream socket has data to read (or timeout expires).
136 // timeout_ms: -1 = infinite, 0 = return immediately, >0 = milliseconds
137 // Returns true if readable, false on timeout.
138 bool waitReadable(int timeout_ms);
139
140 // Override the maximum number of redirects to follow (default: 5).
141 // Set to 0 to disable automatic redirect following.
142 void setMaxRedirects(int max) { _maxRedirects = max; }
143
144 // Returns the HTTP status code from the last response.
145 int lastStatusCode() const { return _lastStatusCode; }
146
147 // Returns the Content-Type from the last response.
148 const std::string &lastContentType() const { return _lastContentType; }
149
150 // Returns the full parsed response from the last request.
151 const HttpResponse *lastResponse() const { return _lastResponse.get(); }
152
153 // Drop the current connection so the next request opens a fresh one.
154 void resetConnection();
155
156 // Shared TLS session cache — enables abbreviated TLS 1.2 handshakes
157 // across reconnects to the same host. One cache per process.
158 static netplus::TlsSessionCache& tlsSessionCache();
159 private:
160 void _ensureConnected();
161 // Thin wrapper around netplus::tcp::connectTimeout() using
162 // _recvTimeoutSec, translating its NetException into HTTPException.
163 void _connectTcp(netplus::tcp &sock);
164 bool tryHttp3First();
165
166 // Non-blocking I/O helpers using poll() for efficient waiting
167 size_t _recvBlocking(netplus::buffer &b, int timeout_sec = 0);
168 // Returns 0 on EAGAIN (no data yet), otherwise bytes read
169 size_t _recvNonBlocking(netplus::buffer &b);
170 void _sendAll(const char *data, size_t len);
171 void _sendAll(const std::string &data);
172
173 // Shared HTTP/1.x response reader (avoids code duplication)
174 std::vector<char> _h1ReadResponse(const std::string &label);
175
176 // Shared blocking/non-blocking body readers for STREAM_CHUNKED and
177 // STREAM_EOF (used by both readBodyChunk() and
178 // readBodyChunkNonBlocking() -- a single implementation parameterized
179 // by `blocking` instead of two independently-maintained copies, the
180 // second of which used to not exist at all and silently fell back to
181 // the blocking one). Return value matches readBodyChunkNonBlocking's
182 // contract: 0 = no data yet (blocking=false only) or a benign empty
183 // read, (size_t)-1 = body complete, otherwise bytes written to buf.
184 bool _streamRecvMore(bool blocking, bool &eof);
185 size_t _streamReadChunked(char *buf, size_t bufsize, bool blocking);
186 size_t _streamReadEof(char *buf, size_t bufsize, bool blocking);
187
188 // Same idea for STREAM_H2: readBodyChunk() and
189 // readBodyChunkNonBlocking() previously carried two independently
190 // hand-copied H2 frame-dispatch switches, which had already drifted
191 // (the non-blocking copy had gained an explicit
192 // H2C_FRAME_WINDOW_UPDATE case the blocking one lacked). The frame
193 // dispatch itself is now written once; only how bytes are pulled off
194 // the wire (wait vs. one non-blocking attempt) differs by `blocking`.
195 size_t _streamReadH2(char *buf, size_t bufsize, bool blocking);
196
197 // Same idea for STREAM_H3: the QUIC varint frame-parsing loop (partial
198 // DATA-frame continuation handling included) was duplicated verbatim
199 // between readBodyChunk() and readBodyChunkNonBlocking(); now written
200 // once and shared, with only the "wait for more data vs. try once and
201 // return" difference kept per-mode.
202 size_t _streamReadH3(char *buf, size_t bufsize, bool blocking);
203
204 // Shared Get/Post/Put/Delete implementation: builds+sends the request
205 // over whichever transport is active (H1/H2/H3), follows redirects
206 // per RFC 7231 §6.4 (303 always converts to a bodyless GET; 307/308
207 // preserve the original method) when followRedirects is set, and
208 // retries up to maxTries times on transport errors.
209 const std::vector<char> _doH1Request(const std::string &method, int requestType,
210 HttpRequest &nreq, const std::vector<char> *body,
211 size_t maxTries, bool followRedirects);
212
213 // HTTP/2 client helpers
214 bool _isH2 = false;
215 bool _isH3 = false; // cached in place of repeated dynamic_cast<quic*>
216 bool _h2PrefaceSent = false; // true after connection preface sent
217
218 // HTTP/3 client helpers
219 uint32_t _h2NextStreamId = 1; // next client-initiated stream ID (odd)
220 std::unique_ptr<hpack::Decoder> _h2Decoder; // persistent HPACK decoder for connection
221 const std::vector<char> _h2Request(const std::string &method,
222 HttpRequest &nreq,
223 const std::vector<char> *postBody = nullptr);
224 const std::vector<char> _h3Request(const std::string &method,
225 HttpRequest &nreq,
226 const std::vector<char> *postBody = nullptr);
227
228 // Streaming state
229 enum StreamMode { STREAM_NONE, STREAM_CONTENT_LENGTH, STREAM_CHUNKED, STREAM_EOF,
230 STREAM_H2, STREAM_H3 };
231 StreamMode _streamMode = STREAM_NONE;
232 size_t _streamRemaining = 0; // bytes left for content-length mode
233 std::vector<char> _streamBuf; // leftover data from header read
234 size_t _streamBufPos = 0;
235 // Chunked streaming sub-state
236 bool _streamChunkDone = false; // true after final 0-length chunk
237 size_t _streamChunkRemaining = 0; // bytes left in current chunk
238
239 // HTTP/2 streaming state
240 uint32_t _streamH2Sid = 0; // stream ID for active H2 stream
241 bool _streamH2EndStream = false;
242 std::vector<uint8_t> _streamH2Raw; // raw frame buffer
243
244 // HTTP/3 streaming state
245 uint64_t _streamH3Sid = 0; // stream ID for active H3 stream
246 bool _streamH3EndStream = false;
247 std::vector<uint8_t> _streamH3Raw; // raw frame buffer
248 std::vector<char> _streamH3Body; // decoded DATA frames not yet consumed
249 size_t _streamH3BodyPos = 0; // consumed offset into _streamH3Body
250 bool _streamH3InDataFrame = false; // true when inside a partial DATA frame
251 uint64_t _streamH3DataRemaining = 0; // bytes left in current DATA frame
252
253 private:
254 HttpUrl _url;
255 std::unique_ptr<netplus::socket> _cltsock;
256 netplus::socketwait _sw;
257 netplus::x509cert _cert;
258 // Reused across every recv() call in this object's lifetime instead of
259 // constructing a fresh netplus::buffer per read: the Linux buffer ctor
260 // value-initializes (zero-fills) the whole CHUNKSIZE (64KB) allocation,
261 // so a fresh one per network read cost an alloc+memset+free even when
262 // only a few KB actually arrived. Safe to share across all call sites
263 // since each one copies out exactly the bytes recvData() reports before
264 // doing anything else with the buffer (nothing relies on unwritten
265 // bytes being zero, and HttpClient is not used from multiple threads
266 // concurrently -- _cltsock/_streamMode etc. already assume that).
267 netplus::buffer _recvScratch{CHUNKSIZE};
268 int _recvTimeoutSec = 60;
269 int _sendTimeoutSec = 30;
270 int _vers = 2; // HTTP version preference (0=h1 only, 1=h1+h2, 2=h2 preferred, 3=h3, 4=internal h2-only probe)
271
272 // Response tracking (populated by _h1ReadResponse / _h2Request / _h3Request)
273 int _lastStatusCode = 0;
274 std::string _lastLocation;
275 std::string _lastContentType;
276 std::unique_ptr<HttpResponse> _lastResponse;
277 static constexpr int MAX_REDIRECTS = 5;
278 int _maxRedirects = MAX_REDIRECTS;
279 };
280
281
283 public:
285 public:
286 class Values{
287 public:
288 Values &operator=(const std::string &val);
289 Values &operator=(size_t val);
290 Values &operator=(int val);
291 Values& operator=(const Values &val);
292
293 Values &operator<<(const std::string &value);
294 Values &operator<<(size_t value);
295 Values &operator<<(int value);
296
297 const std::string &getvalue();
298 int getIntvalue();
299 size_t getSizetValue();
300
301 Values *nextvalue();
302 Values(const std::string& val);
303 Values(const Values& val);
304 Values()=default;
305 ~Values() = default;
306 private:
307 std::string _value;
308 std::unique_ptr<Values> _nextvalue=nullptr;
309 friend class HeaderData;
310 };
311
312 Values *getfirstValue();
313 Values &at(int pos);
314 Values &operator[](int pos);
315
316 void push_back(const Values &val);
317 void push_back(const std::string &val);
318 void push_back(const char* val);
319 void push_back(size_t val);
320 void push_back(int val);
321
322 bool empty();
323
324 void erase(int pos);
325
326 void clear();
327
328 const std ::string &getkey();
329
330 HeaderData *nextHeaderData();
331 HeaderData(const std ::string &key);
332 ~HeaderData() = default;
333 private:
334 std::string _Key;
335 std::unique_ptr<Values> _firstValue=nullptr;
336 Values *_lastValue=nullptr;
337 std::unique_ptr<HeaderData> _nextHeaderData=nullptr;
338 friend class HttpHeader;
339 };
340
341 HeaderData *getfirstHeaderData();
342 HeaderData *getHeaderData(const std ::string &key) const;
343 HeaderData *setHeaderData(const std ::string &key);
344
345 void deldata(const std ::string &key);
346 void deldata(HeaderData*pos);
347
348 size_t getElements();
349 size_t getHeaderSize();
350
351 void clear();
352 protected:
353 HttpHeader();
354 virtual ~HttpHeader()=default;
355 std::unique_ptr<HeaderData> _firstHeaderData;
356 HeaderData *_lastHeaderData;
357 private:
358 // O(1)-average lookup by key, keyed exactly like the old linear scan
359 // compared (raw key string, case-sensitive -- callers already always
360 // pass pre-lowercased keys; HeaderData's own ctor separately lowercases
361 // _Key for storage). The linked list above remains the source of truth
362 // for iteration order and node lifetime/address stability (HeaderData*
363 // handed out to callers, e.g. HttpResponse's cached _ContentLength etc.,
364 // must stay valid -- nodes are never moved, only the index pointing at
365 // them changes), this is purely a lookup accelerator kept in sync by
366 // setHeaderData()/deldata()/clear().
367 std::unordered_map<std::string, HeaderData*> _index;
368 };
369
370 class HttpResponse : public HttpHeader,public netplus::con {
371 public:
372 HttpResponse();
373 HttpResponse(const HttpResponse &src);
375
376 /*server methods*/
377 void setState(const std ::string &httpstate);
378 void setContentType(const std ::string &type);
379 void setContentLength(size_t len);
380 void setConnection(const std ::string &type);
381 void setTransferEncoding(const std ::string &enc);
382
383 /*client methods*/
384 const std ::string &getState() const;
385 int getStatusCode() const;
386 const std ::string &getContentType() const;
387 size_t getContentLength() const;
388 const std ::string &getConnection() const;
389 const std ::string &getVersion() const;
390 HttpHeader::HeaderData::Values *getTransferEncoding() const;
391
392 size_t printHeader(std::vector<char> &buffer);
393
394 /*server methods*/
395 void send(netplus::con &curconnection,const std::string &data,int datalen=0); //only use as server
396 void send(netplus::con &curconnection,const unsigned char *data,int datalen); //only use as server
397 void send(netplus::con &curconnection,const std::vector<char> &data,int datalen=0); //only use as server
398
399 // Outbound chunked-transfer-encoding streaming (HTTP/1.1 only -- caller
400 // is responsible for only using these on a connection confirmed to be
401 // HTTP/1.1; they don't go through _storeResponseInfo's H2/H3 path).
402 // Usage: sendChunkedHeaders() once, then sendChunk() any number of
403 // times as data becomes available, then endChunked() exactly once.
404 void sendChunkedHeaders(netplus::con &curconnection);
405 void sendChunk(netplus::con &curconnection, const char *data, size_t len);
406 void endChunked(netplus::con &curconnection);
407
408 /*client method*/
409 size_t parse(const char *in,size_t inlen);
410
411 // Ingest already-decoded HPACK/QPACK header fields directly (client
412 // side, HTTP/2 and HTTP/3). Avoids building a synthetic HTTP/1.1-style
413 // text block and reparsing it -- besides the redundant copy/reparse,
414 // that round-trip had no way to reject a header value containing an
415 // embedded "\r\n", letting a malicious/compromised peer inject extra
416 // header lines (including a premature blank line truncating the block).
417 // Returns the number of header fields ingested.
418 size_t parseH2(const std::vector<hpack::HeaderField> &headers);
419 size_t parseH3(const std::vector<qpack::HeaderField> &headers);
420
421 private:
422 bool _storeResponseInfo(netplus::con &curconnection, int datalen);
423
424 std::string _State=HTTP200;
425 std::string _Version;
426 int _StatusCode=200;
427 HeaderData *_TransferEncoding;
428 HeaderData *_Connection;
429 HeaderData *_ContentType;
430 HeaderData *_ContentLength;
431 mutable std::string _ContentTypeCache;
432 };
433
434
435 class HttpRequest : public HttpHeader, public netplus::con{
436 public:
437 HttpRequest();
438 HttpRequest(netplus::eventapi *evapi);
439 ~HttpRequest();
440
441 void clear();
442
443 /*server methods*/
444
445 size_t parse(); //only use as server
446
447 /*protocol-specific parse helpers (all store into _firstHeaderData)*/
448 size_t parseH2(const std::vector<hpack::HeaderField> &headers, uint32_t stream_id = 0);
449 size_t parseH3(const std::vector<qpack::HeaderField> &headers);
450
451 void printHeader(std::string &buffer);
452 int getRequestType();
453 const std::string &getRequestURL();
454 const std::string &getRequest();
455 size_t getRequestLength();
456 const std::string &getRequestVersion();
457 const std::string &getHost();
458 size_t getContentLength();
459 size_t getMaxUploadSize();
460
461 /* HTTP/1.1 chunked request-body support (server side).
462 * Traefik and other reverse proxies downgrade HTTP/2 POSTs to HTTP/1.1
463 * using Transfer-Encoding: chunked (no Content-Length). These helpers let
464 * the server loop de-chunk the body before dispatching RequestEvent. */
465 bool isChunkedRequest();
466 int decodeChunkedBody();
467
468 /*mobilphone switch*/
469 bool isMobile();
470
471 /*Client methods*/
472 void setRequestType(int req);
473 void setRequestURL(const std::string &url);
474 void setRequestVersion(const std::string &version);
475 /*only for post Reuquesttype*/
476 void setRequestData(const std::string &data,size_t len);
477 void setMaxUploadSize(size_t upsize);
478
479 void send(const HttpUrl &dest,std::unique_ptr<netplus::socket> &sock);
480
481 private:
482 size_t parseH1(); // HTTP/1.x request parsing
483
484 /*
485 * Helper: extracts URL path from :path header (strips query string).
486 * Used by getRequestURL() and parse helpers.
487 */
488 static std::string extractPath(const std::string &target);
489
490 int _RequestType = PARSEREQUEST;
491 size_t _MaxUploadSize = DEFAULT_UPLOADSIZE;
492
493 // Cached strings derived from _firstHeaderData pseudo-headers.
494 // Populated by parseH1/parseH2/parseH3, read by getters.
495 mutable std::string _cachedRequestURL;
496 mutable std::string _cachedRequest;
497 mutable std::string _cachedRequestVersion;
498 mutable std::string _cachedHost;
499
500 // HTTP/2 and HTTP/3 protocol state (managed by HttpEvent).
501 // All H2-specific mutable state lives in a heap-allocated struct so
502 // that inline-layout corruption of HttpRequest cannot trash the
503 // deque / map / decoder internals.
504 int _httpProtocol = 0; // 0=HTTP/1.x, 1=HTTP/2, 2=HTTP/3
505
506 struct H2PendingResponse {
507 uint32_t streamId;
508 std::string body; // remaining body data to send as DATA frames
509 size_t offset = 0; // how far into body we've sent
510 };
511
512 // Active streaming response state — lives on the connection's H2State
513 // so Http2RequestEvent can resume sending after WINDOW_UPDATE.
514 struct H2StreamingResponse {
515 uint32_t streamId = 0;
516 size_t contentLength = 0;
517 size_t totalSent = 0;
518 std::string pendingData; // buffered DATA not yet framed
519 size_t pendingOffset = 0;
520 std::unique_ptr<HttpRequest> tempreq; // per-stream request for ResponseEvent
521 int tid = 0;
522 ULONG_PTR args = 0;
523 size_t emptyCount = 0;
524 unsigned int backoffMs = 1;
525 bool finished = false;
526 // Set while totalSent < contentLength and the peer's flow-control
527 // window is the reason no DATA can go out (not an upstream stall).
528 // Reaped by _reapStalledH2Streams() if it stays true too long —
529 // guards against a peer that stops sending WINDOW_UPDATE entirely,
530 // which would otherwise leave the stream (and its tempreq) parked
531 // in activeStreams forever.
532 bool windowBlocked = false;
533 std::chrono::steady_clock::time_point blockedSince{};
534 };
535
536 struct H2PendingIncoming {
537 std::vector<hpack::HeaderField> headers;
538 std::string body;
539 std::vector<uint8_t> rawHpack; // accumulates HPACK across CONTINUATION frames
540 bool headersComplete = false; // true once END_HEADERS received
541 bool endStreamOnHeaders = false; // END_STREAM was on HEADERS frame
542 bool streaming = false; // body handled by onH2DataChunk callback
543 };
544
545 struct H2State {
546 uint32_t streamId = 0;
547 bool headersSent = false;
548 bool serverPrefaceSent = false;
549 size_t expectedContentLength = 0;
550 size_t bodyBytesSent = 0;
551 std::deque<H2PendingResponse> pendingResponses;
552 std::map<uint32_t, H2PendingIncoming> pendingIncoming;
553 hpack::Decoder hpackDecoder;
554 // Peer flow-control windows (RFC 7540 §6.9)
555 int32_t peerConnWindow = 65535; // connection-level
556 int32_t peerInitialStreamWindow = 65535; // from peer SETTINGS
557 size_t peerMaxFrameSize = 16384; // from peer SETTINGS_MAX_FRAME_SIZE (0x05)
558 std::map<uint32_t, int32_t> peerStreamWindows; // per-stream
559 // Active streaming responses (one per stream)
560 std::map<uint32_t, std::shared_ptr<H2StreamingResponse>> activeStreams;
561 };
562
563 // Lazily allocated when the connection is upgraded to HTTP/2.
564 std::unique_ptr<H2State> _h2;
565
566 // Allocate H2 state if not yet present; return reference.
567 H2State &h2state() {
568 if (!_h2) _h2 = std::make_unique<H2State>();
569 return *_h2;
570 }
571
572 friend class HttpForm;
573 friend class HttpResponse;
574 friend class HttpEvent;
575 };
576
577 class HttpForm {
578 public:
579 // ─── Multipart form-data (RFC 2046) ───────────────────
581 struct Header {
582 std::string key; // lowercased header name (e.g. "content-disposition")
583 std::string value; // full header value
584 };
585
586 struct Disposition {
587 std::string key; // e.g. "name", "filename"
588 std::string value; // e.g. "field1", "upload.txt"
589 };
590
591 std::vector<Header> headers;
592 std::vector<Disposition> dispositions;
593 std::vector<char> value; // raw body (binary-safe for file uploads)
594 };
595
596 // ─── URL-encoded form data ────────────────────────────
597 struct UrlEntry {
598 std::string key;
599 std::string value;
600 };
601
602 HttpForm() = default;
603 ~HttpForm() = default;
604
605 void parse(HttpRequest &request);
606
607 // Accessors
608 const std::string &getContentType() const { return _contentType; }
609 const std::string &getBoundary() const { return _boundary; }
610 const std::vector<MultipartEntry> &multipartData() const { return _multipartEntries; }
611 const std::vector<UrlEntry> &urlData() const { return _urlEntries; }
612
613 // URL encoding / decoding utilities
614 static void urlDecode(const std::string &in, std::string &out);
615 static void urlEncode(const std::string &in, std::string &out);
616
617 private:
618 void _parseMultipart(const char *data, size_t len);
619 void _parseMultiSection(const char *data, size_t len, size_t start, size_t end);
620 void _parseUrlDecode(const char *data, size_t len);
621
622 std::string _boundary;
623 std::string _contentType;
624 std::vector<MultipartEntry> _multipartEntries;
625 std::vector<UrlEntry> _urlEntries;
626 };
627
629 public:
631 public:
632 CookieData *nextCookieData() const;
633 const std::string &getKey() const;
634 const std::string &getValue() const;
635 CookieData()=default;
636 CookieData(const CookieData& src);
637 ~CookieData();
638 private:
639 std::string _Key;
640 std::string _Value;
641 std::unique_ptr <CookieData> _nextCookieData=nullptr;
642
643 friend class HttpCookie;
644 };
645 HttpCookie();
646 ~HttpCookie();
647 void parse(libhttppp::HttpRequest& curreq);
648 void setcookie(libhttppp::HttpResponse& curresp,
649 const std::string &key,const std::string &value,
650 const std::string &comment="",const std::string &domain="",
651 int maxage=-1,const std::string &path="",
652 bool secure=false,const std::string &version="1",const std::string &samesite="",bool httponly=false);
653 CookieData *getfirstCookieData();
654 CookieData *getlastCookieData();
655 CookieData *addCookieData();
656 private:
657 std::unique_ptr <CookieData> _firstCookieData;
658 CookieData *_lastCookieData;
659 };
660
661#define BASICAUTH 0
662#define DIGESTAUTH 1
663#define NTLMAUTH 2
664
665 class HttpAuth {
666 public:
667 HttpAuth();
668 ~HttpAuth();
669 void parse(libhttppp::HttpRequest &curreq);
670 void setAuth(libhttppp::HttpResponse &curresp);
671
672 void setAuthType(int authtype);
673 void setRealm(const std::string &realm);
674 void setUsername(const std::string &username);
675 void setPassword(const std::string &password);
676
677 const std::string &getUsername();
678 const std::string &getPassword();
679 int getAuthType();
680 const std::string &getAuthRequest();
681
682 private:
683 int _Authtype;
684 std::string _Username;
685 std::string _Password;
686 std::string _Realm;
687 std::string _Nonce;
688
689 };
690};
Definition https.h:38
Definition http.h:665
Definition http.h:97
Definition http.h:628
Definition httpd.h:51
Definition http.h:577
Definition http.h:282
Definition http.h:435
Definition http.h:370
Definition http.h:56
Definition hpack.h:68
Definition http.h:597