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 size_t getContentLength();
333 size_t getMaxUploadSize();
334
335 /*mobilphone switch*/
336 bool isMobile();
337
338 /*Client methods*/
339 void setRequestType(int req);
340 void setRequestURL(const std::string &url);
341 void setRequestVersion(const std::string &version);
342 /*only for post Reuquesttype*/
343 void setRequestData(const std::string &data,size_t len);
344 void setMaxUploadSize(size_t upsize);
345
346 void send(const HttpUrl &dest,std::unique_ptr<netplus::socket> &sock);
347
348 private:
349 size_t parseH1(); // HTTP/1.x request parsing
350
351 /*
352 * Helper: extracts URL path from :path header (strips query string).
353 * Used by getRequestURL() and parse helpers.
354 */
355 static std::string extractPath(const std::string &target);
356
357 int _RequestType = PARSEREQUEST;
358 size_t _MaxUploadSize = DEFAULT_UPLOADSIZE;
359
360 // Cached strings derived from _firstHeaderData pseudo-headers.
361 // Populated by parseH1/parseH2/parseH3, read by getters.
362 mutable std::string _cachedRequestURL;
363 mutable std::string _cachedRequest;
364 mutable std::string _cachedRequestVersion;
365
366 // HTTP/2 and HTTP/3 protocol state (managed by HttpEvent).
367 // All H2-specific mutable state lives in a heap-allocated struct so
368 // that inline-layout corruption of HttpRequest cannot trash the
369 // deque / map / decoder internals.
370 int _httpProtocol = 0; // 0=HTTP/1.x, 1=HTTP/2, 2=HTTP/3
371
372 struct H2PendingResponse {
373 uint32_t streamId;
374 std::string body; // remaining body data to send as DATA frames
375 size_t offset = 0; // how far into body we've sent
376 };
377
378 // Active streaming response state — lives on the connection's H2State
379 // so Http2RequestEvent can resume sending after WINDOW_UPDATE.
380 struct H2StreamingResponse {
381 uint32_t streamId = 0;
382 size_t contentLength = 0;
383 size_t totalSent = 0;
384 std::string pendingData; // buffered DATA not yet framed
385 size_t pendingOffset = 0;
386 std::unique_ptr<HttpRequest> tempreq; // per-stream request for ResponseEvent
387 int tid = 0;
388 ULONG_PTR args = 0;
389 size_t emptyCount = 0;
390 unsigned int backoffMs = 1;
391 bool finished = false;
392 };
393
394 struct H2PendingIncoming {
395 std::vector<hpack::HeaderField> headers;
396 std::string body;
397 std::vector<uint8_t> rawHpack; // accumulates HPACK across CONTINUATION frames
398 bool headersComplete = false; // true once END_HEADERS received
399 bool endStreamOnHeaders = false; // END_STREAM was on HEADERS frame
400 bool streaming = false; // body handled by onH2DataChunk callback
401 };
402
403 struct H2State {
404 uint32_t streamId = 0;
405 bool headersSent = false;
406 bool serverPrefaceSent = false;
407 size_t expectedContentLength = 0;
408 size_t bodyBytesSent = 0;
409 std::deque<H2PendingResponse> pendingResponses;
410 std::map<uint32_t, H2PendingIncoming> pendingIncoming;
411 hpack::Decoder hpackDecoder;
412 // Peer flow-control windows (RFC 7540 §6.9)
413 int32_t peerConnWindow = 65535; // connection-level
414 int32_t peerInitialStreamWindow = 65535; // from peer SETTINGS
415 size_t peerMaxFrameSize = 16384; // from peer SETTINGS_MAX_FRAME_SIZE (0x05)
416 std::map<uint32_t, int32_t> peerStreamWindows; // per-stream
417 // Active streaming responses (one per stream)
418 std::map<uint32_t, std::shared_ptr<H2StreamingResponse>> activeStreams;
419 };
420
421 // Lazily allocated when the connection is upgraded to HTTP/2.
422 std::unique_ptr<H2State> _h2;
423
424 // Allocate H2 state if not yet present; return reference.
425 H2State &h2state() {
426 if (!_h2) _h2 = std::make_unique<H2State>();
427 return *_h2;
428 }
429
430 friend class HttpForm;
431 friend class HttpResponse;
432 friend class HttpEvent;
433 };
434
435 class HttpForm {
436 public:
437 // ─── Multipart form-data (RFC 2046) ───────────────────
439 struct Header {
440 std::string key; // lowercased header name (e.g. "content-disposition")
441 std::string value; // full header value
442 };
443
444 struct Disposition {
445 std::string key; // e.g. "name", "filename"
446 std::string value; // e.g. "field1", "upload.txt"
447 };
448
449 std::vector<Header> headers;
450 std::vector<Disposition> dispositions;
451 std::vector<char> value; // raw body (binary-safe for file uploads)
452 };
453
454 // ─── URL-encoded form data ────────────────────────────
455 struct UrlEntry {
456 std::string key;
457 std::string value;
458 };
459
460 HttpForm() = default;
461 ~HttpForm() = default;
462
463 void parse(HttpRequest &request);
464
465 // Accessors
466 const std::string &getContentType() const { return _contentType; }
467 const std::string &getBoundary() const { return _boundary; }
468 const std::vector<MultipartEntry> &multipartData() const { return _multipartEntries; }
469 const std::vector<UrlEntry> &urlData() const { return _urlEntries; }
470
471 // URL encoding / decoding utilities
472 static void urlDecode(const std::string &in, std::string &out);
473 static void urlEncode(const std::string &in, std::string &out);
474
475 private:
476 void _parseMultipart(const char *data, size_t len);
477 void _parseMultiSection(const char *data, size_t len, size_t start, size_t end);
478 void _parseUrlDecode(const char *data, size_t len);
479
480 std::string _boundary;
481 std::string _contentType;
482 std::vector<MultipartEntry> _multipartEntries;
483 std::vector<UrlEntry> _urlEntries;
484 };
485
487 public:
489 public:
490 CookieData *nextCookieData() const;
491 const std::string &getKey() const;
492 const std::string &getValue() const;
493 CookieData()=default;
494 CookieData(const CookieData& src);
495 ~CookieData();
496 private:
497 std::string _Key;
498 std::string _Value;
499 std::unique_ptr <CookieData> _nextCookieData=nullptr;
500
501 friend class HttpCookie;
502 };
503 HttpCookie();
504 ~HttpCookie();
505 void parse(libhttppp::HttpRequest& curreq);
506 void setcookie(libhttppp::HttpResponse& curresp,
507 const std::string &key,const std::string &value,
508 const std::string &comment="",const std::string &domain="",
509 int maxage=-1,const std::string &path="",
510 bool secure=false,const std::string &version="1",const std::string &samesite="",bool httponly=false);
511 CookieData *getfirstCookieData();
512 CookieData *getlastCookieData();
513 CookieData *addCookieData();
514 private:
515 std::unique_ptr <CookieData> _firstCookieData;
516 CookieData *_lastCookieData;
517 };
518
519#define BASICAUTH 0
520#define DIGESTAUTH 1
521#define NTLMAUTH 2
522
523 class HttpAuth {
524 public:
525 HttpAuth();
526 ~HttpAuth();
527 void parse(libhttppp::HttpRequest &curreq);
528 void setAuth(libhttppp::HttpResponse &curresp);
529
530 void setAuthType(int authtype);
531 void setRealm(const std::string &realm);
532 void setUsername(const std::string &username);
533 void setPassword(const std::string &password);
534
535 const std::string &getUsername();
536 const std::string &getPassword();
537 int getAuthType();
538 const std::string &getAuthRequest();
539
540 private:
541 int _Authtype;
542 std::string _Username;
543 std::string _Password;
544 std::string _Realm;
545 std::string _Nonce;
546
547 };
548};
Definition https.h:38
Definition http.h:523
Definition http.h:88
Definition http.h:486
Definition httpd.h:50
Definition http.h:435
Definition http.h:187
Definition http.h:310
Definition http.h:264
Definition http.h:53
Definition hpack.h:68
Definition http.h:455