SNode.C
Loading...
Searching...
No Matches
echoclient.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#include "core/SNodeC.h"
21#include "web/http/legacy/in/Client.h"
22#include "web/http/tls/in/Client.h"
23
24#ifndef DOXYGEN_SHOULD_SKIP_THIS
25
26#include "log/Logger.h"
27
28#include <string>
29
30#endif /* DOXYGEN_SHOULD_SKIP_THIS */
31
32int main(int argc, char* argv[]) {
33 core::SNodeC::init(argc, argv);
34
35 {
36 using LegacyClient = web::http::legacy::in::Client;
37 using Request = LegacyClient::Request;
38 using Response = LegacyClient::Response;
39 using LegacySocketAddress = LegacyClient::SocketAddress;
40
41 const LegacyClient legacyClient(
42 "legacy",
43 [](const std::shared_ptr<Request>& req) {
44 VLOG(1) << "OnRequestBegin";
45
46 VLOG(1) << "Requesting upgrade to 'websocket' and any of the subprotocols 'subprotocol' and 'echo'";
47
48 req->set("Sec-WebSocket-Protocol", "subprotocol, echo");
49
50 if (!req->upgrade("/ws/",
51 "upgradeprotocol, websocket",
52 [](const std::shared_ptr<Request>& req, const std::shared_ptr<Response>& res) {
53 VLOG(1) << "OnResponse";
54 VLOG(2) << " Status:";
55 VLOG(2) << " " << res->httpVersion << " " << res->statusCode << " " << res->reason;
56 VLOG(2) << " Headers:";
57 for (const auto& [field, value] : res->headers) {
58 VLOG(2) << " " << field + " = " + value;
59 }
60
61 VLOG(2) << " Cookies:";
62 for (const auto& [name, cookie] : res->cookies) {
63 VLOG(2) << " " + name + " = " + cookie.getValue();
64 for (const auto& [option, value] : cookie.getOptions()) {
65 VLOG(2) << " " + option + " = " + value;
66 }
67 }
68
69 req->upgrade(res, [req](const std::string& name) {
70 if (!name.empty()) {
71 VLOG(1) << "Successful upgrade to '" << name << "' from options: " << req->header("Upgrade");
72 } else {
73 VLOG(1) << "Can not upgrade to any of '" << req->header("Upgrade") << "'";
74 }
75 });
76 })) {
77 VLOG(1) << "Initiating upgrade to any of 'upgradeprotocol, websocket' failed";
78 }
79 },
80 []([[maybe_unused]] const std::shared_ptr<Request>& req) {
81 VLOG(1) << "OnRequestEnd";
82 });
83
84 legacyClient.connect([instanceName = legacyClient.getConfig().getInstanceName()](const LegacySocketAddress& socketAddress,
85 const core::socket::State& state) {
86 switch (state) {
87 case core::socket::State::OK:
88 VLOG(1) << instanceName << " connected to '" << socketAddress.toString() << "'";
89 break;
90 case core::socket::State::DISABLED:
91 VLOG(1) << instanceName << " disabled";
92 break;
93 case core::socket::State::ERROR:
94 VLOG(1) << instanceName << " " << socketAddress.toString() << ": " << state.what();
95 break;
96 case core::socket::State::FATAL:
97 VLOG(1) << instanceName << " " << socketAddress.toString() << ": " << state.what();
98 break;
99 }
100 }); // Connection:keep-alive\r\n\r\n"
101
102 using TlsClient = web::http::tls::in::Client;
103 using Request = TlsClient::Request;
104 using Response = TlsClient::Response;
105 using TLSSocketAddress = TlsClient::SocketAddress;
106
107 const TlsClient tlsClient(
108 "tls",
109 [](const std::shared_ptr<Request>& req) {
110 VLOG(1) << "OnRequestBegin";
111
112 VLOG(1) << "Requesting upgrade to 'websocket' and any of the subprotocols 'subprotocol' and 'echo'";
113
114 req->set("Sec-WebSocket-Protocol", "subprotocol, echo");
115
116 if (!req->upgrade("/ws/",
117 "upgradeprotocol, websocket",
118 [](const std::shared_ptr<Request>& req, const std::shared_ptr<Response>& res) {
119 VLOG(1) << "OnResponse";
120 VLOG(2) << " Status:";
121 VLOG(2) << " " << res->httpVersion << " " << res->statusCode << " " << res->reason;
122 VLOG(2) << " Headers:";
123 for (const auto& [field, value] : res->headers) {
124 VLOG(2) << " " << field + " = " + value;
125 }
126
127 VLOG(2) << " Cookies:";
128 for (const auto& [name, cookie] : res->cookies) {
129 VLOG(2) << " " + name + " = " + cookie.getValue();
130 for (const auto& [option, value] : cookie.getOptions()) {
131 VLOG(2) << " " + option + " = " + value;
132 }
133 }
134
135 req->upgrade(res, [req](const std::string& name) {
136 if (!name.empty()) {
137 VLOG(1) << "Successful upgrade to '" << name << "' from options: " << req->header("Upgrade");
138 } else {
139 VLOG(1) << "Can not upgrade to any of '" << req->header("Upgrade") << "'";
140 }
141 });
142 })) {
143 VLOG(1) << "Initiating upgrade to any of 'upgradeprotocol, websocket' failed";
144 }
145 },
146 []([[maybe_unused]] const std::shared_ptr<Request>& req) {
147 VLOG(1) << "OnRequestEnd";
148 });
149
150 tlsClient.connect([instanceName = tlsClient.getConfig().getInstanceName()](const TLSSocketAddress& socketAddress,
151 const core::socket::State& state) {
152 switch (state) {
153 case core::socket::State::OK:
154 VLOG(1) << instanceName << " connected to '" << socketAddress.toString() << "'";
155 break;
156 case core::socket::State::DISABLED:
157 VLOG(1) << instanceName << " disabled";
158 break;
159 case core::socket::State::ERROR:
160 VLOG(1) << instanceName << " " << socketAddress.toString() << ": " << state.what();
161 break;
162 case core::socket::State::FATAL:
163 VLOG(1) << instanceName << " " << socketAddress.toString() << ": " << state.what();
164 break;
165 }
166 }); // Connection:keep-alive\r\n\r\n"
167 }
168
169 return core::SNodeC::start();
170}
int main(int argc, char *argv[])