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