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/TransferEncoding.h"
48#include "web/http/client/SocketContext.h"
49#include "web/http/client/SocketContextUpgradeFactorySelector.h"
50
51//
52
53#include "commands/EndCommand.h"
54#include "commands/SendFileCommand.h"
55#include "commands/SendFragmentCommand.h"
56#include "commands/SendHeaderCommand.h"
57#include "commands/SseCommand.h"
58#include "commands/UpgradeCommand.h"
59
60#ifndef DOXYGEN_SHOULD_SKIP_THIS
61
62#include "log/Logger.h"
63#include "web/http/http_utils.h"
64
65#include <cerrno>
66#include <filesystem>
67#include <sstream>
68#include <system_error>
69#include <utility>
70
71#endif /* DOXYGEN_SHOULD_SKIP_THIS */
72
73#define to_hex_str(int_val) (static_cast<std::ostringstream const&>(std::ostringstream() << std::uppercase << std::hex << int_val)).str()
74
75namespace web::http::client {
76
77 Request::Request(SocketContext* socketContext, const std::string& hostFieldValue)
78 : hostFieldValue(hostFieldValue)
79 , socketContext(socketContext) {
80 host(hostFieldValue);
81 set("X-Powered-By", "snode.c");
82 }
83
84 Request::Request(Request&& request) noexcept
85 : hostFieldValue(request.hostFieldValue) // NOLINT
86 , method(std::move(request.method))
87 , url(std::move(request.url))
88 , httpMajor(request.httpMajor)
89 , httpMinor(request.httpMinor)
90 , count(request.count)
91 , queries(std::move(request.queries))
92 , headers(std::move(request.headers))
93 , cookies(std::move(request.cookies))
94 , trailer(std::move(request.trailer))
96 , masterRequest(request.masterRequest) // NOLINT
100 request.count++;
101
103 set("X-Powered-By", "snode.c");
104 }
105
106 void Request::setMasterRequest(const std::shared_ptr<MasterRequest>& masterRequest) {
107 this->masterRequest = masterRequest;
108 }
109
110 std::shared_ptr<MasterRequest> Request::getMasterRequest() const {
111 return masterRequest.lock();
112 }
113
115 return socketContext;
116 }
117
118 Request& Request::host(const std::string& hostFieldValue) {
119 set("Host", hostFieldValue, true);
120
121 return *this;
122 }
123
124 Request& Request::append(const std::string& field, const std::string& value) {
125 const std::map<std::string, std::string>::iterator it = headers.find(field);
126
127 if (it != headers.end()) {
128 set(field, it->second.append(", ").append(value));
129 } else {
130 set(field, value);
131 }
132
133 return *this;
134 }
135
136 Request& Request::set(const std::string& field, const std::string& value, bool overwrite) {
137 if (!value.empty()) {
138 if (overwrite) {
139 headers.insert_or_assign(field, value);
140 } else {
141 headers.insert({field, value});
142 }
143
144 if (web::http::ciEquals(field, "Connection")) {
145 if (web::http::ciContains(headers[field], "close")) {
147 } else if (web::http::ciContains(headers[field], "keep-alive")) {
149 }
150 } else if (web::http::ciEquals(field, "Content-Length")) {
151 contentLength = std::stoul(value);
153 headers.erase("Transfer-Encoding");
154 } else if (web::http::ciEquals(field, "Transfer-Encoding")) {
155 if (web::http::ciContains(headers[field], "chunked")) {
157 headers.erase("Content-Length");
158 }
159 if (web::http::ciContains(headers[field], "compressed")) {
160 }
161 if (web::http::ciContains(headers[field], "deflate")) {
162 }
163 if (web::http::ciContains(headers[field], "gzip")) {
164 }
165 } else if (web::http::ciEquals(field, "Content-Encoding")) {
166 if (web::http::ciContains(headers[field], "compressed")) {
167 }
168 if (web::http::ciContains(headers[field], "deflate")) {
169 }
170 if (web::http::ciContains(headers[field], "gzip")) {
171 }
172 if (web::http::ciContains(headers[field], "br")) {
173 }
174 }
175 } else {
176 headers.erase(field);
177 }
178
179 return *this;
180 }
181
182 Request& Request::set(const std::map<std::string, std::string>& headers, bool overwrite) {
183 for (const auto& [field, value] : headers) {
184 set(field, value, overwrite);
185 }
186
187 return *this;
188 }
189
190 Request& Request::type(const std::string& type) {
191 headers.insert({"Content-Type", type});
192
193 return *this;
194 }
195
196 Request& Request::cookie(const std::string& name, const std::string& value) {
197 cookies.insert({name, value});
198
199 return *this;
200 }
201
202 Request& Request::cookie(const std::map<std::string, std::string>& cookies) {
203 for (const auto& [name, value] : cookies) {
204 cookie(name, value);
205 }
206
207 return *this;
208 }
209
210 Request& Request::query(const std::string& key, const std::string& value) {
211 queries.insert({key, value});
212
213 return *this;
214 }
215
216 Request& Request::setTrailer(const std::string& field, const std::string& value, bool overwrite) {
217 if (!value.empty()) {
218 if (overwrite) {
219 trailer.insert_or_assign(field, value);
220 } else {
221 trailer.insert({field, value});
222 }
223 if (!headers.contains("Trailer")) {
224 set("Trailer", field);
225 } else {
226 headers["Trailer"].append("," + field);
227 }
228 } else {
229 trailer.erase(field);
230 }
231
232 return *this;
233 }
234
235 std::string Request::header(const std::string& field) const {
236 auto fieldElement = headers.find(field);
237
238 return fieldElement != headers.end() ? fieldElement->second : "";
239 }
240
241 const CiStringMap<std::string>& Request::getQueries() const {
242 return queries;
243 }
244
245 const CiStringMap<std::string>& Request::getHeaders() const {
246 return headers;
247 }
248
249 const CiStringMap<std::string>& Request::getTrailer() const {
250 return trailer;
251 }
252
253 const CiStringMap<std::string>& Request::getCookies() const {
254 return cookies;
255 }
256
257 void Request::upgrade(const std::shared_ptr<Response>& response, const std::function<void(const std::string&)>& status) {
258 const std::string connectionName = socketContext->getSocketConnection()->getConnectionName();
259
260 std::string name;
261
262 if (!masterRequest.expired()) {
263 if (response != nullptr) {
264 if (web::http::ciContains(response->get("connection"), "Upgrade")) {
265 SocketContextUpgradeFactory* socketContextUpgradeFactory =
267
268 if (socketContextUpgradeFactory != nullptr) {
269 name = socketContextUpgradeFactory->name();
270
271 LOG(DEBUG) << connectionName << " HTTP upgrade: SocketContextUpgradeFactory create success for: " << name;
272
273 core::socket::stream::SocketContext* socketContextUpgrade =
274 socketContextUpgradeFactory->create(socketContext->getSocketConnection());
275
276 if (socketContextUpgrade != nullptr) {
277 LOG(DEBUG) << connectionName << " HTTP upgrade: SocketContextUpgrade create success for: " << name;
278
279 socketContext->switchSocketContext(socketContextUpgrade);
280 } else {
281 LOG(DEBUG) << connectionName << " HTTP upgrade: SocketContextUpgrade create failed for: " << name;
282
284 }
285 } else {
286 LOG(DEBUG) << connectionName
287 << " HTTP upgrade: SocketContextUpgradeFactory not supported by server: " << header("upgrade");
288
290 }
291 } else {
292 LOG(DEBUG) << connectionName << " HTTP upgrade: No upgrade requested";
293
295 }
296 } else {
297 LOG(ERROR) << connectionName << " HTTP upgrade: Response has gone away";
298
300 }
301 } else {
302 LOG(ERROR) << connectionName << " HTTP upgrade: Unexpected disconnect";
303 }
304
305 status(name);
306 }
307
308 MasterRequest::MasterRequest(SocketContext* socketContext, const std::string& host)
309 : Request(socketContext, host) {
310 this->init();
311 }
312
314 : Request(std::move(request))
315 , requestCommands(std::move(request.requestCommands))
317 , onResponseReceived(std::move(request.onResponseReceived))
318 , onResponseParseError(std::move(request.onResponseParseError)) {
319 request.init();
320 }
321
323 for (const RequestCommand* requestCommand : requestCommands) {
324 delete requestCommand;
325 }
326
327 if (!masterRequest.expired() && Sink::isStreaming()) {
329 }
330 }
331
333 method = "GET";
334 url = "/";
335 httpMajor = 1;
336 httpMinor = 1;
337 queries.clear();
338 headers.clear();
339 cookies.clear();
340 trailer.clear();
341 requestCommands.clear();
343 contentLength = 0;
346 }
347
348 bool
349 MasterRequest::send(const char* chunk,
350 std::size_t chunkLen,
351 const std::function<void(const std::shared_ptr<Request>&, const std::shared_ptr<Response>&)>& onResponseReceived,
352 const std::function<void(const std::shared_ptr<Request>&, const std::string&)>& onResponseParseError) {
353 bool queued = true;
354
355 if (!masterRequest.expired()) {
356 const std::shared_ptr<MasterRequest> newRequest = std::make_shared<MasterRequest>(std::move(*this));
357
358 if (chunkLen > 0) {
359 newRequest->set("Content-Type", "application/octet-stream", false);
360 }
361
362 newRequest->sendHeader();
363 newRequest->sendFragment(chunk, chunkLen);
364
365 newRequest->requestCommands.push_back(new commands::EndCommand(onResponseReceived, onResponseParseError));
366
367 newRequest->requestPrepared(newRequest);
368
369 } else {
370 queued = false;
371 }
372
373 return queued;
374 }
375
376 bool
377 MasterRequest::send(const std::string& chunk,
378 const std::function<void(const std::shared_ptr<Request>&, const std::shared_ptr<Response>&)>& onResponseReceived,
379 const std::function<void(const std::shared_ptr<Request>&, const std::string&)>& onResponseParseError) {
380 if (!chunk.empty()) {
381 set("Content-Type", "text/html; charset=utf-8", false);
382 }
383
384 return send(chunk.data(), chunk.size(), onResponseReceived, onResponseParseError);
385 }
386
388 const std::string& url,
389 const std::string& protocols,
390 const std::function<void(bool)>& onUpgradeInitiate,
391 const std::function<void(const std::shared_ptr<Request>&, const std::shared_ptr<Response>&, bool)>& onResponseReceived,
392 const std::function<void(const std::shared_ptr<Request>&, const std::string&)>& onResponseParseError) {
393 if (!masterRequest.expired()) {
394 const std::shared_ptr<MasterRequest> newRequest = std::make_shared<MasterRequest>(std::move(*this));
395
396 newRequest->url = url;
397
398 newRequest->requestCommands.push_back(new commands::UpgradeCommand(
399 url,
400 protocols,
401 onUpgradeInitiate,
402 [onResponseReceived](const std::shared_ptr<Request>& request, const std::shared_ptr<Response>& response) {
403 if (request != nullptr) {
404 const std::string connectionName = request->getSocketContext()->getSocketConnection()->getConnectionName();
405
406 LOG(DEBUG) << connectionName << " HTTP upgrade: Response to upgrade request: " << request->method << " "
407 << request->url << " "
408 << "HTTP/" << request->httpMajor << "." << request->httpMinor << "\n"
410 response->statusCode,
411 response->reason,
412 response->headers,
413 response->cookies,
414 response->body);
415
416 request->upgrade(response, [request, response, connectionName, &onResponseReceived](const std::string& name) {
417 LOG(DEBUG) << connectionName << " HTTP upgrade: bootstrap " << (!name.empty() ? "success" : "failed");
418 LOG(DEBUG) << " Protocol selected: " << name;
419 LOG(DEBUG) << " requested: " << request->header("upgrade");
420 LOG(DEBUG) << " Subprotocol selected: " << response->get("Sec-WebSocket-Protocol");
421 LOG(DEBUG) << " requested: " << request->header("Sec-WebSocket-Protocol");
422
423 onResponseReceived(request, response, !name.empty());
424 });
425 }
426 },
427 onResponseParseError));
428
429 requestPrepared(newRequest);
430 }
431
432 return !masterRequest.expired();
433 }
434
435 bool MasterRequest::requestEventSource(const std::string& url,
436 const std::function<std::size_t()>& onServerSentEvent,
437 const std::function<void()>& onOpen,
438 const std::function<void()>& onError) {
439 if (!masterRequest.expired()) {
440 const std::shared_ptr<MasterRequest> newRequest = std::make_shared<MasterRequest>(std::move(*this));
441
442 newRequest->url = url;
443 newRequest->httpMajor = 1;
444 newRequest->httpMinor = 1;
445
446 newRequest->set("Connection", "keep-alive", true);
447 newRequest->set("Accept", "text/event-stream", true);
448 newRequest->set("Cache-Control", "no-cache", true);
449
450 newRequest->sendHeader();
451 newRequest->requestCommands.push_back(new commands::SseCommand(
452 [masterRequest = this->masterRequest, onServerSentEvent, onOpen, onError](const std::shared_ptr<Request>& request,
453 const std::shared_ptr<Response>& response) {
454 if (!masterRequest.expired()) {
455 if (web::http::ciContains(response->headers["Content-Type"], "text/event-stream") &&
456 web::http::ciContains(request->header("Accept"), "text/event-stream")) {
457 masterRequest.lock()->getSocketContext()->setSseEventReceiver(onServerSentEvent);
458
459 const std::string connectionName = request->getSocketContext()->getSocketConnection()->getConnectionName();
460 onOpen();
461 } else {
462 masterRequest.lock()->getSocketContext()->shutdownWrite(true);
463 onError();
464 }
465 }
466 },
467 [masterRequest = this->masterRequest](const std::shared_ptr<Request>& request, const std::string& status) {
468 if (!masterRequest.expired()) {
470 << " error in response: " << status;
471 masterRequest.lock()->getSocketContext()->shutdownWrite(true);
472 }
473 }));
474
475 requestPrepared(newRequest);
476 }
477
478 return !masterRequest.expired();
479 }
480
482 const std::string& file,
483 const std::function<void(int)>& onStatus,
484 const std::function<void(const std::shared_ptr<Request>&, const std::shared_ptr<Response>&)>& onResponseReceived,
485 const std::function<void(const std::shared_ptr<Request>&, const std::string&)>& onResponseParseError) {
486 bool queued = false;
487
488 if (!masterRequest.expired()) {
489 const std::shared_ptr<MasterRequest> newRequest = std::make_shared<MasterRequest>(std::move(*this));
490
491 newRequest->requestCommands.push_back(new commands::SendFileCommand(file, onStatus, onResponseReceived, onResponseParseError));
492
493 requestPrepared(newRequest);
494
495 queued = true;
496 }
497
498 return queued;
499 }
500
502 if (!masterRequest.expired()) {
504 }
505
506 return *this;
507 }
508
509 MasterRequest& MasterRequest::sendFragment(const char* chunk, std::size_t chunkLen) {
510 if (!masterRequest.expired()) {
511 contentLength += chunkLen;
512
513 requestCommands.push_back(new commands::SendFragmentCommand(chunk, chunkLen));
514 }
515
516 return *this;
517 }
518
519 MasterRequest& MasterRequest::sendFragment(const std::string& data) {
520 return sendFragment(data.data(), data.size());
521 }
522
523 bool
524 MasterRequest::end(const std::function<void(const std::shared_ptr<Request>&, const std::shared_ptr<Response>&)>& onResponseReceived,
525 const std::function<void(const std::shared_ptr<Request>&, const std::string&)>& onResponseParseError) {
526 bool queued = true;
527
528 if (!masterRequest.expired()) {
529 const std::shared_ptr<MasterRequest> newRequest = std::make_shared<MasterRequest>(std::move(*this));
530
531 newRequest->sendHeader();
532
533 newRequest->requestCommands.push_back(new commands::EndCommand(onResponseReceived, onResponseParseError));
534
535 requestPrepared(newRequest);
536 } else {
537 queued = false;
538 }
539
540 return queued;
541 }
542
543 bool MasterRequest::initiate(const std::shared_ptr<MasterRequest>& request) {
544 bool error = false;
545 bool atomar = true;
546
547 for (RequestCommand* requestCommand : requestCommands) {
548 if (!error) {
550 this->onResponseReceived = requestCommand->onResponseReceived;
551
552 atomar = requestCommand->execute(request);
553 error = requestCommand->getError();
554 }
555
556 delete requestCommand;
557 }
558 requestCommands.clear();
559
560 if (atomar && !error) {
562 }
563
564 return !error;
565 }
566
567 bool MasterRequest::executeSendFile(const std::string& file, const std::function<void(int)>& onStatus) {
568 bool atomar = true;
569
570 std::string absolutFileName = file;
571
572 if (std::filesystem::exists(absolutFileName)) {
573 std::error_code ec;
574 absolutFileName = std::filesystem::canonical(absolutFileName);
575
576 if (std::filesystem::is_regular_file(absolutFileName, ec) && !ec) {
577 core::file::FileReader::open(absolutFileName, [this, &absolutFileName, &onStatus, &atomar](int fd) {
578 onStatus(errno);
579
580 if (fd >= 0) {
581 if (httpMajor == 1) {
582 atomar = false;
583
584 set("Content-Type", web::http::MimeTypes::contentType(absolutFileName), false);
585 set("Last-Modified", httputils::file_mod_http_date(absolutFileName), false);
586 if (httpMinor == 1 && contentLength == 0) {
587 set("Transfer-Encoding", "chunked");
588 } else {
589 set("Content-Length", std::to_string(std::filesystem::file_size(absolutFileName) + contentLength));
590 }
591
593 }
594 } else {
596 }
597 })->pipe(this);
598 } else {
599 errno = EINVAL;
600 onStatus(errno);
601 }
602 } else {
603 errno = ENOENT;
604 onStatus(errno);
605 }
606
607 return atomar;
608 }
609
610 bool MasterRequest::executeUpgrade(const std::string& url, const std::string& protocols, const std::function<void(bool)>& onStatus) {
611 const std::string connectionName = this->getSocketContext()->getSocketConnection()->getConnectionName();
612 this->url = url;
613
614 set("Connection", "Upgrade", true);
615 set("Upgrade", protocols, true);
616
617 web::http::client::SocketContextUpgradeFactory* socketContextUpgradeFactory =
619
620 if (socketContextUpgradeFactory != nullptr) {
621 LOG(DEBUG) << connectionName << " HTTP: "
622 << "SocketContextUpgradeFactory create success: " << socketContextUpgradeFactory->name();
623 LOG(DEBUG) << connectionName << " HTTP: Initiating upgrade: " << method << " " << url
624 << " HTTP/" + std::to_string(httpMajor) + "." + std::to_string(httpMinor);
625
626 } else {
627 LOG(DEBUG) << connectionName << " HTTP: "
628 << "SocketContextUpgradeFactory create failed: " << protocols;
629 LOG(DEBUG) << connectionName << " HTTP: Not initiating upgrade " << method << " " << url
630 << " HTTP/" + std::to_string(httpMajor) + "." + std::to_string(httpMinor);
631 }
632
633 LOG(DEBUG) << connectionName << " HTTP: Upgrade request:\n"
635 url,
636 "HTTP/" + std::to_string(httpMajor) + "." + std::to_string(httpMinor),
641 std::vector<char>());
642
643 onStatus(socketContextUpgradeFactory != nullptr);
644
645 if (socketContextUpgradeFactory != nullptr) {
647
648 socketContextUpgradeFactory->checkRefCount();
649 } else {
651 }
652
653 return true;
654 }
655
657 return true;
658 }
659
661 return true;
662 }
663
665 const std::string httpVersion = "HTTP/" + std::to_string(httpMajor) + "." + std::to_string(httpMinor);
666
667 std::string queryString;
668 if (!queries.empty()) {
669 queryString += "?";
670 for (auto& [key, value] : queries) {
671 queryString += httputils::url_encode(key) + "=" + httputils::url_encode(value) + "&";
672 }
673 queryString.pop_back();
674 }
675
676 socketContext->sendToPeer(method + " " + url + queryString + " " + httpVersion + "\r\n");
678
679 if (!headers.contains("Transfer-Encoding") && contentLength > 0) {
680 set("Content-Length", std::to_string(contentLength));
681 }
682
683 for (const auto& [field, value] : headers) {
684 socketContext->sendToPeer(std::string(field).append(":").append(value).append("\r\n"));
685 }
686
687 for (const auto& [name, value] : cookies) {
688 socketContext->sendToPeer(std::string("Cookie:").append(name).append("=").append(value).append("\r\n"));
689 }
690
692
693 return true;
694 }
695
696 bool MasterRequest::executeSendFragment(const char* chunk, std::size_t chunkLen) {
698 socketContext->sendToPeer(to_hex_str(chunkLen).append("\r\n"));
699 }
700
701 socketContext->sendToPeer(chunk, chunkLen);
702 contentLengthSent += chunkLen;
703
706 contentLength += chunkLen;
707 }
708
709 return true;
710 }
711
712 void MasterRequest::requestPrepared(const std::shared_ptr<MasterRequest>& request) {
714 }
715
716 void MasterRequest::deliverResponse(const std::shared_ptr<MasterRequest>& request, const std::shared_ptr<Response>& response) {
717 onResponseReceived(request, response);
718 }
719
720 void MasterRequest::deliverResponseParseError(const std::shared_ptr<MasterRequest>& request, const std::string& message) {
721 onResponseParseError(request, message);
722 }
723
725 if (!masterRequest.expired()) {
727 executeSendFragment("", 0); // For transfer encoding chunked. Terminate the chunk sequence.
728
729 if (!trailer.empty()) {
730 for (auto& [field, value] : trailer) {
731 socketContext->sendToPeer(std::string(field).append(":").append(value).append("\r\n"));
732 }
734 }
735 }
736
738 }
739 }
740
741 void MasterRequest::onSourceConnect(core::pipe::Source* source) {
742 if (!masterRequest.expired()) {
744 source->start();
745 }
746 } else {
747 source->stop();
748 }
749 }
750
751 void MasterRequest::onSourceData(const char* chunk, std::size_t chunkLen) {
752 executeSendFragment(chunk, chunkLen);
753 }
754
756 if (!masterRequest.expired()) {
758
760 }
761 }
762
763 void MasterRequest::onSourceError(int errnum) {
764 errno = errnum;
765
766 if (!masterRequest.expired()) {
769
771 }
772 }
773
774} // namespace web::http::client
static FileReader * open(const std::string &path, const std::function< void(int)> &callback)
bool isStreaming()
Definition Sink.cpp:65
virtual void stop()=0
bool pipe(Sink *sink)
Definition Source.cpp:60
virtual void start()=0
void sendToPeer(const std::string &data) const
const std::string & getConnectionName() const
SocketConnection * getSocketConnection() const
void switchSocketContext(SocketContext *newSocketContext)
void sendToPeer(const char *chunk, std::size_t chunkLen) const final
void shutdownWrite(bool forceClose=false)
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
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)
Definition Request.cpp:377
bool executeUpgrade(const std::string &url, const std::string &protocols, const std::function< void(bool)> &onStatus)
Definition Request.cpp:610
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)
Definition Request.cpp:349
void onSourceData(const char *chunk, std::size_t chunkLen) override
Definition Request.cpp:751
void onSourceConnect(core::pipe::Source *source) override
Definition Request.cpp:741
bool requestEventSource(const std::string &url, const std::function< std::size_t()> &onServerSentEvent, const std::function< void()> &onOpen, const std::function< void()> &onError)
Definition Request.cpp:435
MasterRequest(MasterRequest &&) noexcept
Definition Request.cpp:313
std::function< void(const std::shared_ptr< Request > &, const std::string &message)> onResponseParseError
Definition Request.h:223
void requestPrepared(const std::shared_ptr< MasterRequest > &request)
Definition Request.cpp:712
void deliverResponseParseError(const std::shared_ptr< MasterRequest > &request, const std::string &message)
Definition Request.cpp:720
std::function< void(const std::shared_ptr< Request > &, const std::shared_ptr< Response > &)> onResponseReceived
Definition Request.h:222
void deliverResponse(const std::shared_ptr< MasterRequest > &request, const std::shared_ptr< Response > &response)
Definition Request.cpp:716
void onSourceError(int errnum) override
Definition Request.cpp:763
bool upgrade(const std::string &url, const std::string &protocols, const std::function< void(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)
Definition Request.cpp:387
bool executeSendFragment(const char *chunk, std::size_t chunkLen)
Definition Request.cpp:696
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)
Definition Request.cpp:481
std::list< RequestCommand * > requestCommands
Definition Request.h:218
MasterRequest(SocketContext *socketContext, const std::string &hostFieldValue)
Definition Request.cpp:308
MasterRequest & sendFragment(const std::string &data)
Definition Request.cpp:519
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)
Definition Request.cpp:524
MasterRequest & sendFragment(const char *chunk, std::size_t chunkLen)
Definition Request.cpp:509
bool executeSendFile(const std::string &file, const std::function< void(int)> &onStatus)
Definition Request.cpp:567
bool initiate(const std::shared_ptr< MasterRequest > &request)
Definition Request.cpp:543
virtual bool execute(const std::shared_ptr< MasterRequest > &request)=0
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
CiStringMap< std::string > headers
Definition Request.h:132
Request & set(const std::string &field, const std::string &value, bool overwrite=true)
Definition Request.cpp:136
TransferEncoding transferEncoding
Definition Request.h:141
void setMasterRequest(const std::shared_ptr< MasterRequest > &masterRequest)
Definition Request.cpp:106
const CiStringMap< std::string > & getCookies() const
Definition Request.cpp:253
Request(Request &&request) noexcept
Definition Request.cpp:84
ConnectionState connectionState
Definition Request.h:142
CiStringMap< std::string > cookies
Definition Request.h:133
Request & cookie(const std::string &name, const std::string &value)
Definition Request.cpp:196
CiStringMap< std::string > trailer
Definition Request.h:134
const CiStringMap< std::string > & getQueries() const
Definition Request.cpp:241
Request & query(const std::string &key, const std::string &value)
Definition Request.cpp:210
Request(SocketContext *socketContext, const std::string &host)
Definition Request.cpp:77
std::weak_ptr< MasterRequest > masterRequest
Definition Request.h:138
Request & setTrailer(const std::string &field, const std::string &value, bool overwrite=true)
Definition Request.cpp:216
Request & cookie(const std::map< std::string, std::string > &cookies)
Definition Request.cpp:202
SocketContext * getSocketContext() const
Definition Request.cpp:114
std::string header(const std::string &field) const
Definition Request.cpp:235
CiStringMap< std::string > queries
Definition Request.h:131
Request & set(const std::map< std::string, std::string > &headers, bool overwrite=true)
Definition Request.cpp:182
std::size_t contentLength
Definition Request.h:136
web::http::client::SocketContext * socketContext
Definition Request.h:139
std::string hostFieldValue
Definition Request.h:120
const CiStringMap< std::string > & getTrailer() const
Definition Request.cpp:249
Request & append(const std::string &field, const std::string &value)
Definition Request.cpp:124
Request & host(const std::string &hostFieldValue)
Definition Request.cpp:118
std::shared_ptr< MasterRequest > getMasterRequest() const
Definition Request.cpp:110
Request & type(const std::string &type)
Definition Request.cpp:190
const CiStringMap< std::string > & getHeaders() const
Definition Request.cpp:245
void upgrade(const std::shared_ptr< Response > &response, const std::function< void(const std::string &)> &status)
Definition Request.cpp:257
CiStringMap< std::string > headers
Definition Response.h:83
CiStringMap< CookieOptions > cookies
Definition Response.h:84
const std::string & get(const std::string &key, int i=0) const
Definition Response.cpp:53
std::vector< char > body
Definition Response.h:85
SocketContextUpgradeFactory * select(Request &req, Response &res) override
SocketContextUpgradeFactory * select(const std::string &protocols, Request &req)
void setSseEventReceiver(const std::function< std::size_t()> &onServerSentEvent)
void requestPrepared(const std::shared_ptr< MasterRequest > &request)
EndCommand(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)
SendFileCommand(const std::string &file, const std::function< void(int)> &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)
SendFragmentCommand(const char *chunk, std::size_t chunkLen)
SseCommand(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)
UpgradeCommand(const std::string &url, const std::string &protocols, const std::function< void(bool)> &onUpgradeInitiate, 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)
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 > &trailer, 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:73