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