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 };
400
401 struct H2State {
402 uint32_t streamId = 0;
403 bool headersSent = false;
404 bool serverPrefaceSent = false;
405 size_t expectedContentLength = 0;
406 size_t bodyBytesSent = 0;
407 std::deque<H2PendingResponse> pendingResponses;
408 std::map<uint32_t, H2PendingIncoming> pendingIncoming;
409 hpack::Decoder hpackDecoder;
410 // Peer flow-control windows (RFC 7540 §6.9)
411 int32_t peerConnWindow = 65535; // connection-level
412 int32_t peerInitialStreamWindow = 65535; // from peer SETTINGS
413 size_t peerMaxFrameSize = 16384; // from peer SETTINGS_MAX_FRAME_SIZE (0x05)
414 std::map<uint32_t, int32_t> peerStreamWindows; // per-stream
415 // Active streaming responses (one per stream)
416 std::map<uint32_t, std::shared_ptr<H2StreamingResponse>> activeStreams;
417 };
418
419 // Lazily allocated when the connection is upgraded to HTTP/2.
420 std::unique_ptr<H2State> _h2;
421
422 // Allocate H2 state if not yet present; return reference.
423 H2State &h2state() {
424 if (!_h2) _h2 = std::make_unique<H2State>();
425 return *_h2;
426 }
427
428 friend class HttpForm;
429 friend class HttpResponse;
430 friend class HttpEvent;
431 };
432
433 class HttpForm {
434 public:
435 // ─── Multipart form-data (RFC 2046) ───────────────────
437 struct Header {
438 std::string key; // lowercased header name (e.g. "content-disposition")
439 std::string value; // full header value
440 };
441
442 struct Disposition {
443 std::string key; // e.g. "name", "filename"
444 std::string value; // e.g. "field1", "upload.txt"
445 };
446
447 std::vector<Header> headers;
448 std::vector<Disposition> dispositions;
449 std::vector<char> value; // raw body (binary-safe for file uploads)
450 };
451
452 // ─── URL-encoded form data ────────────────────────────
453 struct UrlEntry {
454 std::string key;
455 std::string value;
456 };
457
458 HttpForm() = default;
459 ~HttpForm() = default;
460
461 void parse(HttpRequest &request);
462
463 // Accessors
464 const std::string &getContentType() const { return _contentType; }
465 const std::string &getBoundary() const { return _boundary; }
466 const std::vector<MultipartEntry> &multipartData() const { return _multipartEntries; }
467 const std::vector<UrlEntry> &urlData() const { return _urlEntries; }
468
469 // URL encoding / decoding utilities
470 static void urlDecode(const std::string &in, std::string &out);
471 static void urlEncode(const std::string &in, std::string &out);
472
473 private:
474 void _parseMultipart(const char *data, size_t len);
475 void _parseMultiSection(const char *data, size_t len, size_t start, size_t end);
476 void _parseUrlDecode(const char *data, size_t len);
477
478 std::string _boundary;
479 std::string _contentType;
480 std::vector<MultipartEntry> _multipartEntries;
481 std::vector<UrlEntry> _urlEntries;
482 };
483
485 public:
487 public:
488 CookieData *nextCookieData() const;
489 const std::string &getKey() const;
490 const std::string &getValue() const;
491 CookieData()=default;
492 CookieData(const CookieData& src);
493 ~CookieData();
494 private:
495 std::string _Key;
496 std::string _Value;
497 std::unique_ptr <CookieData> _nextCookieData=nullptr;
498
499 friend class HttpCookie;
500 };
501 HttpCookie();
502 ~HttpCookie();
503 void parse(libhttppp::HttpRequest& curreq);
504 void setcookie(libhttppp::HttpResponse& curresp,
505 const std::string &key,const std::string &value,
506 const std::string &comment="",const std::string &domain="",
507 int maxage=-1,const std::string &path="",
508 bool secure=false,const std::string &version="1",const std::string &samesite="",bool httponly=false);
509 CookieData *getfirstCookieData();
510 CookieData *getlastCookieData();
511 CookieData *addCookieData();
512 private:
513 std::unique_ptr <CookieData> _firstCookieData;
514 CookieData *_lastCookieData;
515 };
516
517#define BASICAUTH 0
518#define DIGESTAUTH 1
519#define NTLMAUTH 2
520
521 class HttpAuth {
522 public:
523 HttpAuth();
524 ~HttpAuth();
525 void parse(libhttppp::HttpRequest &curreq);
526 void setAuth(libhttppp::HttpResponse &curresp);
527
528 void setAuthType(int authtype);
529 void setRealm(const std::string &realm);
530 void setUsername(const std::string &username);
531 void setPassword(const std::string &password);
532
533 const std::string &getUsername();
534 const std::string &getPassword();
535 int getAuthType();
536 const std::string &getAuthRequest();
537
538 private:
539 int _Authtype;
540 std::string _Username;
541 std::string _Password;
542 std::string _Realm;
543 std::string _Nonce;
544
545 };
546};
Definition https.h:38
Definition http.h:521
Definition http.h:87
Definition http.h:484
Definition httpd.h:49
Definition http.h:433
Definition http.h:186
Definition http.h:309
Definition http.h:263
Definition http.h:53
Definition hpack.h:68
Definition http.h:453