SNode.C
Loading...
Searching...
No Matches
echoserver.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 "express/legacy/in/WebApp.h"
21#include "express/middleware/VerboseRequest.h"
22#include "express/tls/in/WebApp.h"
23
24#ifndef DOXYGEN_SHOULD_SKIP_THIS
25
26#include "log/Logger.h"
27
28#include <cstring>
29#include <string>
30
31#endif /* DOXYGEN_SHOULD_SKIP_THIS */
32
33using namespace express;
34
35int main(int argc, char* argv[]) {
36 express::WebApp::init(argc, argv);
37
38 using LegacyWebApp = express::legacy::in::WebApp;
39 using Request = LegacyWebApp::Request;
40 using Response = LegacyWebApp::Response;
41 using SocketAddress = LegacyWebApp::SocketAddress;
42
43 const LegacyWebApp legacyApp("legacy");
44
45 legacyApp.use(express::middleware::VerboseRequest());
46
47 legacyApp.get("/", [] APPLICATION(req, res) {
48 VLOG(1) << "HTTP GET on "
49 << "/";
50 if (req->url == "/" || req->url == "/index.html") {
51 req->url = "/wstest.html";
52 }
53
54 VLOG(1) << CMAKE_CURRENT_SOURCE_DIR "/html" + req->url;
55 res->sendFile(CMAKE_CURRENT_SOURCE_DIR "/html" + req->url, [req](int errnum) {
56 if (errnum == 0) {
57 VLOG(1) << req->url;
58 } else {
59 VLOG(1) << "HTTP response send file failed: " << std::strerror(errnum);
60 }
61 });
62 });
63
64 legacyApp.get("/ws", [](const std::shared_ptr<Request>& req, const std::shared_ptr<Response>& res) {
65 VLOG(1) << "HTTP GET on legacy /ws";
66
67 const std::string uri = req->originalUrl;
68
69 VLOG(2) << "OriginalUri: " << uri;
70 VLOG(2) << "Uri: " << req->url;
71
72 VLOG(2) << "Host: " << req->get("host");
73 VLOG(2) << "Connection: " << req->get("connection");
74 VLOG(2) << "Origin: " << req->get("origin");
75 VLOG(2) << "Sec-WebSocket-Protocol: " << req->get("sec-websocket-protocol");
76 VLOG(2) << "sec-web-socket-extensions: " << req->get("sec-websocket-extensions");
77 VLOG(2) << "sec-websocket-key: " << req->get("sec-websocket-key");
78 VLOG(2) << "sec-websocket-version: " << req->get("sec-websocket-version");
79 VLOG(2) << "upgrade: " << req->get("upgrade");
80 VLOG(2) << "user-agent: " << req->get("user-agent");
81
82 if (req->get("sec-websocket-protocol").find("echo") != std::string::npos) {
83 res->upgrade(req, [req, res](const std::string& name) {
84 if (!name.empty()) {
85 VLOG(1) << "Successful upgrade to '" << name << "' from options: " << req->get("upgrade");
86 } else {
87 VLOG(1) << "Can not upgrade to any of '" << req->get("upgrade") << "'";
88 }
89 res->end();
90 });
91 } else {
92 res->sendStatus(404);
93 }
94 });
95
96 legacyApp.listen(
97 [instanceName = legacyApp.getConfig().getInstanceName()](const SocketAddress& socketAddress, const core::socket::State& state) {
98 switch (state) {
99 case core::socket::State::OK:
100 VLOG(1) << instanceName << " listening on '" << socketAddress.toString() << "'";
101 break;
102 case core::socket::State::DISABLED:
103 VLOG(1) << instanceName << " disabled";
104 break;
105 case core::socket::State::ERROR:
106 VLOG(1) << instanceName << " " << socketAddress.toString() << ": " << state.what();
107 break;
108 case core::socket::State::FATAL:
109 VLOG(1) << instanceName << " " << socketAddress.toString() << ": " << state.what();
110 break;
111 }
112 });
113
114 {
115 using TlsWebApp = express::tls::in::WebApp;
116 using Request = TlsWebApp::Request;
117 using Response = TlsWebApp::Response;
118 using SocketAddress = TlsWebApp::SocketAddress;
119
120 const TlsWebApp tlsApp("tls");
121
122 tlsApp.use(express::middleware::VerboseRequest());
123
124 tlsApp.get("/", [] APPLICATION(req, res) {
125 if (req->url == "/" || req->url == "/index.html") {
126 req->url = "/wstest.html";
127 }
128
129 VLOG(1) << CMAKE_CURRENT_SOURCE_DIR "/html" + req->url;
130 res->sendFile(CMAKE_CURRENT_SOURCE_DIR "/html" + req->url, [req](int ret) {
131 if (ret != 0) {
132 PLOG(ERROR) << req->url;
133 }
134 });
135 });
136
137 tlsApp.get("/ws", [](const std::shared_ptr<Request>& req, const std::shared_ptr<Response>& res) {
138 VLOG(1) << "HTTP GET on tls /ws";
139
140 const std::string uri = req->originalUrl;
141
142 VLOG(2) << "OriginalUri: " << uri;
143 VLOG(2) << "Uri: " << req->url;
144
145 VLOG(2) << "Connection: " << req->get("connection");
146 VLOG(2) << "Host: " << req->get("host");
147 VLOG(2) << "Origin: " << req->get("origin");
148 VLOG(2) << "Sec-WebSocket-Protocol: " << req->get("sec-websocket-protocol");
149 VLOG(2) << "sec-web-socket-extensions: " << req->get("sec-websocket-extensions");
150 VLOG(2) << "sec-websocket-key: " << req->get("sec-websocket-key");
151 VLOG(2) << "sec-websocket-version: " << req->get("sec-websocket-version");
152 VLOG(2) << "upgrade: " << req->get("upgrade");
153 VLOG(2) << "user-agent: " << req->get("user-agent");
154
155 if (req->get("sec-websocket-protocol").find("echo") != std::string::npos) {
156 res->upgrade(req, [req, res](const std::string& name) {
157 if (!name.empty()) {
158 VLOG(1) << "Successful upgrade to '" << name << "' from options: " << req->get("upgrade");
159 } else {
160 VLOG(1) << "Can not upgrade to any of '" << req->get("upgrade") << "'";
161 }
162 res->end();
163 });
164 } else {
165 res->sendStatus(404);
166 }
167 });
168
169 tlsApp.listen(
170 [instanceName = tlsApp.getConfig().getInstanceName()](const SocketAddress& socketAddress, const core::socket::State& state) {
171 switch (state) {
172 case core::socket::State::OK:
173 VLOG(1) << instanceName << " listening on '" << socketAddress.toString() << "'";
174 break;
175 case core::socket::State::DISABLED:
176 VLOG(1) << instanceName << " disabled";
177 break;
178 case core::socket::State::ERROR:
179 VLOG(1) << instanceName << " " << socketAddress.toString() << ": " << state.what();
180 break;
181 case core::socket::State::FATAL:
182 VLOG(1) << instanceName << " " << socketAddress.toString() << ": " << state.what();
183 break;
184 }
185 });
186 }
187
188 return express::WebApp::start();
189}
190
191/*
1922021-05-14 10:21:39 0000000002: accept-encoding: gzip, deflate, br
1932021-05-14 10:21:39 0000000002: accept-language: en-us,en;q=0.9,de-at;q=0.8,de-de;q=0.7,de;q=0.6
1942021-05-14 10:21:39 0000000002: cache-control: no-cache
1952021-05-14 10:21:39 0000000002: connection: upgrade, keep-alive
1962021-05-14 10:21:39 0000000002: host: localhost:8080
1972021-05-14 10:21:39 0000000002: origin: file://
1982021-05-14 10:21:39 0000000002: pragma: no-cache
1992021-05-14 10:21:39 0000000002: sec-websocket-extensions: permessage-deflate; client_max_window_bits
2002021-05-14 10:21:39 0000000002: sec-websocket-key: et6vtby1wwyooittpidflw==
2012021-05-14 10:21:39 0000000002: sec-websocket-version: 13
2022021-05-14 10:21:39 0000000002: upgrade: websocket
2032021-05-14 10:21:39 0000000002: user-agent: mozilla/5.0 (x11; linux x86_64) applewebkit/537.36 (khtml, like gecko)
204chrome/90.0.4430.212 safari/537.36
205*/
#define APPLICATION(req, res)
Definition Router.h:45
static void init(int argc, char *argv[])
Definition WebApp.cpp:34
static int start(const utils::Timeval &timeOut={LONG_MAX, 0})
Definition WebApp.cpp:38
int main(int argc, char *argv[])