SNode.C
Loading...
Searching...
No Matches
Request.cpp
Go to the documentation of this file.
1/*
2 * SNode.C - A Slim Toolkit for Network Communication
3 * Copyright (C) Volker Christian <me@vchrist.at>
4 * 2020, 2021, 2022, 2023, 2024, 2025
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as published
8 * by the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20/*
21 * MIT License
22 *
23 * Permission is hereby granted, free of charge, to any person obtaining a copy
24 * of this software and associated documentation files (the "Software"), to deal
25 * in the Software without restriction, including without limitation the rights
26 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
27 * copies of the Software, and to permit persons to whom the Software is
28 * furnished to do so, subject to the following conditions:
29 *
30 * The above copyright notice and this permission notice shall be included in
31 * all copies or substantial portions of the Software.
32 *
33 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
39 * THE SOFTWARE.
40 */
41
42#include "web/http/client/Request.h"
43
44#include "core/file/FileReader.h"
45#include "core/socket/stream/SocketConnection.h"
46#include "web/http/MimeTypes.h"
47#include "web/http/client/SocketContext.h"
48#include "web/http/client/SocketContextUpgradeFactorySelector.h"
49
50//
51
52#include "commands/EndCommand.h"
53#include "commands/SendFileCommand.h"
54#include "commands/SendFragmentCommand.h"
55#include "commands/SendHeaderCommand.h"
56#include "commands/UpgradeCommand.h"
57
58#ifndef DOXYGEN_SHOULD_SKIP_THIS
59
60#include "log/Logger.h"
61#include "web/http/http_utils.h"
62
63#include <cerrno>
64#include <filesystem>
65#include <sstream>
66#include <system_error>
67#include <utility>
68
69#endif /* DOXYGEN_SHOULD_SKIP_THIS */
70
71#define to_hex_str(int_val) (static_cast<std::ostringstream const&>(std::ostringstream() << std::uppercase << std::hex << int_val)).str()
72
73namespace web::http::client {
74
75 Request::Request(SocketContext* socketContext, const std::string& host)
76 : hostFieldValue(host)
77 , socketContext(socketContext) {
79 }
80
81 Request::Request(Request&& request) noexcept
82 : hostFieldValue(request.hostFieldValue) // NOLINT
83 , method(std::move(request.method))
84 , url(std::move(request.url))
85 , httpMajor(request.httpMajor)
86 , httpMinor(request.httpMinor)
87 , queries(std::move(request.queries))
88 , headers(std::move(request.headers))
89 , cookies(std::move(request.cookies))
90 , trailer(std::move(request.trailer))
91 , requestCommands(std::move(request.requestCommands))
96 , onResponseReceived(std::move(request.onResponseReceived))
98 , masterRequest(request.masterRequest) // NOLINT
100 request.init();
101 }
102
104 for (const RequestCommand* requestCommand : requestCommands) {
105 delete requestCommand;
106 }
107
108 if (!masterRequest.expired() && Sink::isStreaming()) {
110 }
111 }
112
113 void Request::setMasterRequest(const std::shared_ptr<Request>& masterRequest) {
114 this->masterRequest = masterRequest;
115 }
116
117 void Request::init() {
118 method = "GET";
119 url = "/";
120 httpMajor = 1;
121 httpMinor = 1;
122 queries.clear();
123 headers.clear();
124 cookies.clear();
125 trailer.clear();
126 for (const RequestCommand* requestCommand : requestCommands) {
127 delete requestCommand;
128 }
129 requestCommands.clear();
131 contentLength = 0;
134 onResponseReceived = nullptr;
135 onResponseParseError = nullptr;
136
138 set("X-Powered-By", "snode.c");
139 }
140
141 Request& Request::host(const std::string& hostFieldValue) {
142 set("Host", hostFieldValue);
143
144 return *this;
145 }
146
147 Request& Request::append(const std::string& field, const std::string& value) {
148 const std::map<std::string, std::string>::iterator it = headers.find(field);
149
150 if (it != headers.end()) {
151 set(field, it->second.append(", ").append(value));
152 } else {
153 set(field, value);
154 }
155
156 return *this;
157 }
158
159 Request& Request::set(const std::string& field, const std::string& value, bool overwrite) {
160 if (!value.empty()) {
161 if (overwrite) {
162 headers.insert_or_assign(field, value);
163 } else {
164 headers.insert({field, value});
165 }
166
167 if (web::http::ciEquals(field, "Connection")) {
168 if (web::http::ciContains(headers[field], "close")) {
170 } else if (web::http::ciContains(headers[field], "keep-alive")) {
172 }
173 } else if (web::http::ciEquals(field, "Content-Length")) {
174 contentLength = std::stoul(value);
176 headers.erase("Transfer-Encoding");
177 } else if (web::http::ciEquals(field, "Transfer-Encoding")) {
178 if (web::http::ciContains(headers[field], "chunked")) {
180 headers.erase("Content-Length");
181 }
182 if (web::http::ciContains(headers[field], "compressed")) {
183 }
184 if (web::http::ciContains(headers[field], "deflate")) {
185 }
186 if (web::http::ciContains(headers[field], "gzip")) {
187 }
188 } else if (web::http::ciEquals(field, "Content-Encoding")) {
189 if (web::http::ciContains(headers[field], "compressed")) {
190 }
191 if (web::http::ciContains(headers[field], "deflate")) {
192 }
193 if (web::http::ciContains(headers[field], "gzip")) {
194 }
195 if (web::http::ciContains(headers[field], "br")) {
196 }
197 }
198 } else {
199 headers.erase(field);
200 }
201
202 return *this;
203 }
204
205 Request& Request::set(const std::map<std::string, std::string>& headers, bool overwrite) {
206 for (const auto& [field, value] : headers) {
207 set(field, value, overwrite);
208 }
209
210 return *this;
211 }
212
213 Request& Request::type(const std::string& type) {
214 headers.insert({"Content-Type", type});
215
216 return *this;
217 }
218
219 Request& Request::cookie(const std::string& name, const std::string& value) {
220 cookies.insert({name, value});
221
222 return *this;
223 }
224
225 Request& Request::cookie(const std::map<std::string, std::string>& cookies) {
226 for (const auto& [name, value] : cookies) {
227 cookie(name, value);
228 }
229
230 return *this;
231 }
232
233 Request& Request::query(const std::string& key, const std::string& value) {
234 queries.insert({key, value});
235
236 return *this;
237 }
238
239 Request& Request::setTrailer(const std::string& field, const std::string& value, bool overwrite) {
240 if (!value.empty()) {
241 if (overwrite) {
242 trailer.insert_or_assign(field, value);
243 } else {
244 trailer.insert({field, value});
245 }
246 if (!headers.contains("Trailer")) {
247 set("Trailer", field);
248 } else {
249 headers["Trailer"].append("," + field);
250 }
251 } else {
252 trailer.erase(field);
253 }
254
255 return *this;
256 }
257
258 void Request::responseParseError(const std::shared_ptr<Request>& request, const std::string& message) {
260 << " HTTP: Response parse error: " << request->method << " " << request->url << " "
261 << "HTTP/" << request->httpMajor << "." << request->httpMinor << ": " << message;
262 }
263
264 bool Request::send(const char* chunk,
265 std::size_t chunkLen,
266 const std::function<void(const std::shared_ptr<Request>&, const std::shared_ptr<Response>&)>& onResponseReceived,
267 const std::function<void(const std::shared_ptr<Request>&, const std::string&)>& onResponseParseError) {
268 bool queued = true;
269
270 if (!masterRequest.expired()) {
271 this->onResponseReceived = onResponseReceived;
272 this->onResponseParseError = onResponseParseError;
273
274 if (chunkLen > 0) {
275 set("Content-Type", "application/octet-stream", false);
276 }
277
279 sendFragment(chunk, chunkLen);
280
281 requestCommands.push_back(new commands::EndCommand());
282
284 } else {
285 queued = false;
286 }
287
288 return queued;
289 }
290
291 bool Request::send(const std::string& chunk,
292 const std::function<void(const std::shared_ptr<Request>&, const std::shared_ptr<Response>&)>& onResponseReceived,
293 const std::function<void(const std::shared_ptr<Request>&, const std::string&)>& onResponseParseError) {
294 if (!chunk.empty()) {
295 set("Content-Type", "text/html; charset=utf-8", false);
296 }
297
298 return send(chunk.data(), chunk.size(), onResponseReceived, onResponseParseError);
299 }
300
301 bool
302 Request::upgrade(const std::string& url,
303 const std::string& protocols,
304 const std::function<void(const std::shared_ptr<Request>&, bool)>& onUpgradeInitiate,
305 const std::function<void(const std::shared_ptr<Request>&, const std::shared_ptr<Response>&, bool)>& onResponseReceived,
306 const std::function<void(const std::shared_ptr<Request>&, const std::string&)>& onResponseParseError) {
307 if (!masterRequest.expired()) {
308 this->url = url;
309
310 this->onResponseParseError = onResponseParseError;
311
312 this->onResponseReceived = [onResponseReceived](const std::shared_ptr<Request>& req, const std::shared_ptr<Response>& res) {
313 const std::string connectionName = req->getSocketContext()->getSocketConnection()->getConnectionName();
314
315 LOG(DEBUG) << connectionName << " HTTP: Response to upgrade request: " << req->method << " " << req->url << " " << "HTTP/"
316 << req->httpMajor << "." << req->httpMinor << "\n"
318
319 req->upgrade(res, [req, res, connectionName, &onResponseReceived](const std::string& name) {
320 LOG(DEBUG) << connectionName << " HTTP: Upgrade bootstrap " << (!name.empty() ? "success" : "failed");
321 LOG(DEBUG) << " Protocol selected: " << name;
322 LOG(DEBUG) << " requested: " << req->header("upgrade");
323 LOG(DEBUG) << " Subprotocol selected: " << res->get("Sec-WebSocket-Protocol");
324 LOG(DEBUG) << " requested: " << req->header("Sec-WebSocket-Protocol");
325
326 onResponseReceived(req, res, !name.empty());
327 });
328 };
329
330 requestCommands.push_back(new commands::UpgradeCommand(url, protocols, onUpgradeInitiate));
331
333 }
334
335 return !masterRequest.expired();
336 }
337
338 void Request::upgrade(const std::shared_ptr<Response>& response, const std::function<void(const std::string&)>& status) {
339 const std::string connectionName = socketContext->getSocketConnection()->getConnectionName();
340
341 std::string name;
342
343 if (!masterRequest.expired()) {
344 if (response != nullptr) {
345 if (web::http::ciContains(response->get("connection"), "Upgrade")) {
346 SocketContextUpgradeFactory* socketContextUpgradeFactory =
348
349 if (socketContextUpgradeFactory != nullptr) {
350 name = socketContextUpgradeFactory->name();
351
352 LOG(DEBUG) << connectionName << " HTTP upgrade: SocketContextUpgradeFactory create success for: " << name;
353
354 core::socket::stream::SocketContext* socketContextUpgrade =
355 socketContextUpgradeFactory->create(socketContext->getSocketConnection());
356
357 if (socketContextUpgrade != nullptr) {
358 LOG(DEBUG) << connectionName << " HTTP upgrade: SocketContextUpgrade create success for: " << name;
359
360 socketContext->switchSocketContext(socketContextUpgrade);
361 } else {
362 LOG(DEBUG) << connectionName << " HTTP upgrade: SocketContextUpgrade create failed for: " << name;
363
365 }
366 } else {
367 LOG(DEBUG) << connectionName
368 << " HTTP upgrade: SocketContextUpgradeFactory not supported by server: " << header("upgrade");
369
371 }
372 } else {
373 LOG(DEBUG) << connectionName << " HTTP upgrade: No upgrade requested";
374
376 }
377 } else {
378 LOG(ERROR) << connectionName << " HTTP upgrade: Response has gone away";
379
381 }
382 } else {
383 LOG(ERROR) << connectionName << " HTTP upgrade: Unexpected disconnect";
384 }
385
386 status(name);
387 }
388
389 bool Request::sendFile(const std::string& file,
390 const std::function<void(int)>& onStatus,
391 const std::function<void(const std::shared_ptr<Request>&, const std::shared_ptr<Response>&)>& onResponseReceived,
392 const std::function<void(const std::shared_ptr<Request>&, const std::string&)>& onResponseParseError) {
393 bool queued = false;
394
395 if (!masterRequest.expired()) {
396 this->onResponseReceived = onResponseReceived;
397 this->onResponseParseError = onResponseParseError;
398
399 requestCommands.push_back(new commands::SendFileCommand(file, onStatus));
400
402
403 queued = true;
404 }
405
406 return queued;
407 }
408
410 if (!masterRequest.expired()) {
412 }
413
414 return *this;
415 }
416
417 Request& Request::sendFragment(const char* chunk, std::size_t chunkLen) {
418 if (!masterRequest.expired()) {
419 contentLength += chunkLen;
420
421 requestCommands.push_back(new commands::SendFragmentCommand(chunk, chunkLen));
422 }
423
424 return *this;
425 }
426
427 Request& Request::sendFragment(const std::string& data) {
428 return sendFragment(data.data(), data.size());
429 }
430
431 bool Request::end(const std::function<void(const std::shared_ptr<Request>&, const std::shared_ptr<Response>&)>& onResponseReceived,
432 const std::function<void(const std::shared_ptr<Request>&, const std::string&)>& onResponseParseError) {
433 bool queued = true;
434
435 if (!masterRequest.expired()) {
436 this->onResponseReceived = onResponseReceived;
437 this->onResponseParseError = onResponseParseError;
438
440
441 requestCommands.push_back(new commands::EndCommand());
442
444 } else {
445 queued = false;
446 }
447
448 return queued;
449 }
450
451 bool Request::initiate(const std::shared_ptr<Request>& request) {
452 bool error = false;
453 bool atomar = true;
454
455 for (RequestCommand* requestCommand : requestCommands) {
456 if (!error) {
457 const bool atomarCommand = requestCommand->execute(request);
458 if (atomar) {
459 atomar = atomarCommand;
460 }
461
462 error = requestCommand->getError();
463 }
464
465 delete requestCommand;
466 }
467 requestCommands.clear();
468
469 if (atomar && (!error || contentLengthSent != 0)) {
471 }
472
473 return !error || contentLengthSent != 0;
474 }
475
476 bool Request::executeSendFile(const std::string& file, const std::function<void(int)>& onStatus) {
477 bool atomar = true;
478
479 std::string absolutFileName = file;
480
481 if (std::filesystem::exists(absolutFileName)) {
482 std::error_code ec;
483 absolutFileName = std::filesystem::canonical(absolutFileName);
484
485 if (std::filesystem::is_regular_file(absolutFileName, ec) && !ec) {
486 core::file::FileReader::open(absolutFileName)->pipe(this, [this, &atomar, &absolutFileName, &onStatus](int errnum) {
487 errno = errnum;
488 onStatus(errnum);
489
490 if (errnum == 0) {
491 if (httpMajor == 1) {
492 atomar = false;
493
494 set("Content-Type", web::http::MimeTypes::contentType(absolutFileName), false);
495 set("Last-Modified", httputils::file_mod_http_date(absolutFileName), false);
496 if (httpMinor == 1 && contentLength == 0) {
497 set("Transfer-Encoding", "chunked");
498 } else {
499 set("Content-Length", std::to_string(std::filesystem::file_size(absolutFileName) + contentLength));
500 }
501
503 }
504 }
505 });
506 } else {
507 errno = EINVAL;
508 onStatus(errno);
509 }
510 } else {
511 errno = ENOENT;
512 onStatus(errno);
513 }
514
515 return atomar;
516 }
517
518 bool Request::executeUpgrade(const std::string& url, const std::string& protocols, const std::function<void(bool)>& onStatus) {
519 const std::string connectionName = this->getSocketContext()->getSocketConnection()->getConnectionName();
520 this->url = url;
521
522 set("Connection", "Upgrade", true);
523 set("Upgrade", protocols, true);
524
525 web::http::client::SocketContextUpgradeFactory* socketContextUpgradeFactory =
527
528 if (socketContextUpgradeFactory != nullptr) {
529 LOG(DEBUG) << connectionName << " HTTP: "
530 << "SocketContextUpgradeFactory create success: " << socketContextUpgradeFactory->name();
531 LOG(DEBUG) << connectionName << " HTTP: Initiating upgrade: " << method << " " << url
532 << " HTTP/" + std::to_string(httpMajor) + "." + std::to_string(httpMinor);
533
534 } else {
535 LOG(DEBUG) << connectionName << " HTTP: "
536 << "SocketContextUpgradeFactory create failed: " << protocols;
537 LOG(DEBUG) << connectionName << " HTTP: Not initiating upgrade " << method << " " << url
538 << " HTTP/" + std::to_string(httpMajor) + "." + std::to_string(httpMinor);
539 }
540
541 LOG(DEBUG) << connectionName << " HTTP: Upgrade request:\n"
543 url,
544 "HTTP/" + std::to_string(httpMajor) + "." + std::to_string(httpMinor),
548 std::vector<char>());
549
550 onStatus(socketContextUpgradeFactory != nullptr);
551
552 if (socketContextUpgradeFactory != nullptr) {
554
555 socketContextUpgradeFactory->checkRefCount();
556 } else {
558 }
559
560 return true;
561 }
562
563 bool Request::executeEnd() { // NOLINT
564 return true;
565 }
566
568 const std::string httpVersion = "HTTP/" + std::to_string(httpMajor) + "." + std::to_string(httpMinor);
569
570 std::string queryString;
571 if (!queries.empty()) {
572 queryString += "?";
573 for (auto& [key, value] : queries) {
574 queryString += httputils::url_encode(key) + "=" + httputils::url_encode(value) + "&";
575 }
576 queryString.pop_back();
577 }
578
579 socketContext->sendToPeer(method + " " + url + queryString + " " + httpVersion + "\r\n");
581
582 if (!headers.contains("Transfer-Encoding") && contentLength > 0) {
583 set("Content-Length", std::to_string(contentLength));
584 }
585
586 for (const auto& [field, value] : headers) {
587 socketContext->sendToPeer(std::string(field).append(":").append(value).append("\r\n"));
588 }
589
590 for (const auto& [name, value] : cookies) {
591 socketContext->sendToPeer(std::string("Cookie:").append(name).append("=").append(value).append("\r\n"));
592 }
593
595
596 return true;
597 }
598
599 bool Request::executeSendFragment(const char* chunk, std::size_t chunkLen) {
601 socketContext->sendToPeer(to_hex_str(chunkLen).append("\r\n"));
602 }
603
604 socketContext->sendToPeer(chunk, chunkLen);
605 contentLengthSent += chunkLen;
606
609 contentLength += chunkLen;
610 }
611
612 return true;
613 }
614
616 socketContext->requestPrepared(std::move(*this));
617 init();
618 }
619
620 void Request::deliverResponse(const std::shared_ptr<Request>& request, const std::shared_ptr<Response>& response) {
621 onResponseReceived(request, response);
622 }
623
624 void Request::deliverResponseParseError(const std::shared_ptr<Request>& request, const std::string& message) {
625 onResponseParseError(request, message);
626 }
627
629 if (!masterRequest.expired()) {
631 executeSendFragment("", 0); // For transfer encoding chunked. Terminate the chunk sequence.
632
633 if (!trailer.empty()) {
634 for (auto& [field, value] : trailer) {
635 socketContext->sendToPeer(std::string(field).append(":").append(value).append("\r\n"));
636 }
638 }
639 }
640
642 }
643 }
644
645 void Request::onSourceConnect(core::pipe::Source* source) {
646 if (!masterRequest.expired()) {
648 source->start();
649 }
650 } else {
651 source->stop();
652 }
653 }
654
655 void Request::onSourceData(const char* chunk, std::size_t chunkLen) {
656 executeSendFragment(chunk, chunkLen);
657 }
658
660 if (!masterRequest.expired()) {
662
664 }
665 }
666
667 void Request::onSourceError(int errnum) {
668 errno = errnum;
669
670 if (!masterRequest.expired()) {
673
675 }
676 }
677
678 std::string Request::header(const std::string& field) {
679 return headers.contains(field) ? headers[field] : "";
680 }
681
682 const web::http::CiStringMap<std::string>& Request::getQueries() const {
683 return queries;
684 }
685
686 const web::http::CiStringMap<std::string>& Request::getHeaders() const {
687 return headers;
688 }
689
690 const web::http::CiStringMap<std::string>& Request::getCookies() const {
691 return cookies;
692 }
693
695 return socketContext;
696 }
697
698} // namespace web::http::client
static FileReader * open(const std::string &path)
bool isStreaming()
Definition Sink.cpp:64
virtual void stop()=0
void pipe(Sink *sink, const std::function< void(int)> &callback)
Definition Source.cpp:60
virtual void start()=0
void sendToPeer(const std::string &data) const
const std::string & getConnectionName() const
SocketConnection * getSocketConnection() const
virtual void switchSocketContext(SocketContext *newSocketContext)
void sendToPeer(const char *chunk, std::size_t chunkLen) const final
bool streamToPeer(core::pipe::Source *source) const
static std::string contentType(const std::string &file)
core::socket::stream::SocketContext * create(core::socket::stream::SocketConnection *socketConnection) final
virtual bool execute(const std::shared_ptr< Request > &request)=0
CiStringMap< std::string > headers
Definition Request.h:174
Request & set(const std::string &field, const std::string &value, bool overwrite=true)
Definition Request.cpp:159
TransferEncoding transferEncoding
Definition Request.h:181
ConnectionState connectionState
Definition Request.h:186
std::size_t contentLengthSent
Definition Request.h:184
void onSourceEof() override
Definition Request.cpp:659
CiStringMap< std::string > cookies
Definition Request.h:175
Request & cookie(const std::string &name, const std::string &value)
Definition Request.cpp:219
bool upgrade(const std::string &url, const std::string &protocols, const std::function< void(const std::shared_ptr< Request > &, bool)> &onUpgradeInitiate, const std::function< void(const std::shared_ptr< Request > &, const std::shared_ptr< Response > &, bool)> &onResponseReceived, const std::function< void(const std::shared_ptr< Request > &, const std::string &)> &onResponseParseError=responseParseError)
Definition Request.cpp:302
Request(Request &&) noexcept
Definition Request.cpp:81
CiStringMap< std::string > trailer
Definition Request.h:176
void onSourceError(int errnum) override
Definition Request.cpp:667
std::string header(const std::string &field)
Definition Request.cpp:678
std::function< void(const std::shared_ptr< Request > &, const std::shared_ptr< Response > &)> onResponseReceived
Definition Request.h:188
Request & sendFragment(const std::string &data)
Definition Request.cpp:427
bool sendFile(const std::string &file, const std::function< void(int errnum)> &onStatus, const std::function< void(const std::shared_ptr< Request > &, const std::shared_ptr< Response > &)> &onResponseReceived, const std::function< void(const std::shared_ptr< Request > &, const std::string &)> &onResponseParseError=responseParseError)
Definition Request.cpp:389
Request & query(const std::string &key, const std::string &value)
Definition Request.cpp:233
void onSourceData(const char *chunk, std::size_t chunkLen) override
Definition Request.cpp:655
Request(SocketContext *socketContext, const std::string &host)
Definition Request.cpp:75
bool executeSendFragment(const char *chunk, std::size_t chunkLen)
Definition Request.cpp:599
const CiStringMap< std::string > & getQueries() const
Definition Request.cpp:682
const CiStringMap< std::string > & getCookies() const
Definition Request.cpp:690
Request & setTrailer(const std::string &field, const std::string &value, bool overwrite=true)
Definition Request.cpp:239
Request & cookie(const std::map< std::string, std::string > &cookies)
Definition Request.cpp:225
SocketContext * getSocketContext() const
Definition Request.cpp:694
bool initiate(const std::shared_ptr< Request > &request)
Definition Request.cpp:451
static void responseParseError(const std::shared_ptr< Request > &request, const std::string &message)
Definition Request.cpp:258
void setMasterRequest(const std::shared_ptr< Request > &masterRequest)
Definition Request.cpp:113
std::function< void(const std::shared_ptr< Request > &request, const std::string &message)> onResponseParseError
Definition Request.h:189
CiStringMap< std::string > queries
Definition Request.h:173
Request & set(const std::map< std::string, std::string > &headers, bool overwrite=true)
Definition Request.cpp:205
std::size_t contentLength
Definition Request.h:183
web::http::client::SocketContext * socketContext
Definition Request.h:193
std::string hostFieldValue
Definition Request.h:166
Request & append(const std::string &field, const std::string &value)
Definition Request.cpp:147
Request & sendFragment(const char *chunk, std::size_t chunkLen)
Definition Request.cpp:417
std::list< RequestCommand * > requestCommands
Definition Request.h:179
void deliverResponse(const std::shared_ptr< Request > &request, const std::shared_ptr< Response > &response)
Definition Request.cpp:620
bool send(const char *chunk, std::size_t chunkLen, const std::function< void(const std::shared_ptr< Request > &, const std::shared_ptr< Response > &)> &onResponseReceived, const std::function< void(const std::shared_ptr< Request > &, const std::string &)> &onResponseParseError=responseParseError)
Definition Request.cpp:264
const CiStringMap< std::string > & getHeaders() const
Definition Request.cpp:686
Request & host(const std::string &hostFieldValue)
Definition Request.cpp:141
bool send(const std::string &chunk, const std::function< void(const std::shared_ptr< Request > &, const std::shared_ptr< Response > &)> &onResponseReceived, const std::function< void(const std::shared_ptr< Request > &, const std::string &)> &onResponseParseError=responseParseError)
Definition Request.cpp:291
std::weak_ptr< Request > masterRequest
Definition Request.h:191
Request & type(const std::string &type)
Definition Request.cpp:213
bool end(const std::function< void(const std::shared_ptr< Request > &, const std::shared_ptr< Response > &)> &onResponseReceived, const std::function< void(const std::shared_ptr< Request > &, const std::string &)> &onResponseParseError=responseParseError)
Definition Request.cpp:431
bool executeUpgrade(const std::string &url, const std::string &protocols, const std::function< void(bool)> &onStatus)
Definition Request.cpp:518
void deliverResponseParseError(const std::shared_ptr< Request > &request, const std::string &message)
Definition Request.cpp:624
void upgrade(const std::shared_ptr< Response > &response, const std::function< void(const std::string &)> &status)
Definition Request.cpp:338
bool executeSendFile(const std::string &file, const std::function< void(int)> &onStatus)
Definition Request.cpp:476
void onSourceConnect(core::pipe::Source *source) override
Definition Request.cpp:645
CiStringMap< std::string > headers
Definition Response.h:84
CiStringMap< CookieOptions > cookies
Definition Response.h:85
const std::string & get(const std::string &key, int i=0) const
Definition Response.cpp:53
std::vector< char > body
Definition Response.h:86
SocketContextUpgradeFactory * select(Request &req, Response &res) override
SocketContextUpgradeFactory * select(const std::string &protocols, Request &req)
void requestPrepared(Request &&request)
void requestDelivered(Request &&request, bool success)
SendFileCommand(const std::string &file, const std::function< void(int)> &onStatus)
SendFragmentCommand(const char *chunk, std::size_t chunkLen)
UpgradeCommand(const std::string &url, const std::string &protocols, const std::function< void(const std::shared_ptr< Request > &, bool)> &onUpgradeInitiate)
std::string to_http_date(struct tm *tm)
std::string toString(const std::string &version, const std::string &statusCode, const std::string &reason, const web::http::CiStringMap< std::string > &header, const web::http::CiStringMap< web::http::CookieOptions > &cookies, const std::vector< char > &body)
std::string url_encode(const std::string &text)
std::string file_mod_http_date(const std::string &filePath)
std::string toString(const std::string &method, const std::string &url, const std::string &version, const web::http::CiStringMap< std::string > &queries, const web::http::CiStringMap< std::string > &header, const web::http::CiStringMap< std::string > &cookies, const std::vector< char > &body)
bool ciEquals(const std::string &str1, const std::string &str2)
bool ciContains(const std::string &str1, const std::string &str2)
#define to_hex_str(int_val)
Definition Request.cpp:71