SNode.C
Loading...
Searching...
No Matches
clients.h
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#ifndef APPS_HTTP_MODEL_CLIENTS_H
43#define APPS_HTTP_MODEL_CLIENTS_H
44
45#define QUOTE_INCLUDE(a) STR_INCLUDE(a)
46#define STR_INCLUDE(a) #a
47
48// clang-format off
49#define CLIENT_INCLUDE QUOTE_INCLUDE(web/http/STREAM/NET/Client.h)
50// clang-format on
51
52#include CLIENT_INCLUDE // IWYU pragma: export
53
54#ifndef DOXYGEN_SHOULD_SKIP_THIS
55
56#include "log/Logger.h"
57#include "web/http/http_utils.h"
58
59#if (STREAM_TYPE == TLS) // tls
60#include <cstddef>
61#include <openssl/ssl.h>
62#include <openssl/x509v3.h>
63#endif
64
65#endif /* DOXYGEN_SHOULD_SKIP_THIS */
66
67static void logResponse(const std::shared_ptr<web::http::client::Request>& req, const std::shared_ptr<web::http::client::Response>& res) {
68 VLOG(1) << req->getSocketContext()->getSocketConnection()->getConnectionName() << " HTTP response: " << req->method << " " << req->url
69 << " HTTP/" << req->httpMajor << "." << req->httpMinor << "\n"
70 << httputils::toString(req->method,
71 req->url,
72 "HTTP/" + std::to_string(req->httpMajor) + "." + std::to_string(req->httpMinor),
73 req->getQueries(),
74 req->getHeaders(),
75 req->getCookies(),
76 {})
77 << "\n"
78 << httputils::toString(res->httpVersion, res->statusCode, res->reason, res->headers, res->cookies, res->body);
79}
80
81#if (STREAM_TYPE == LEGACY) // legacy
82
83namespace apps::http::legacy {
84
89
90 static Client getClient() {
91 Client client(
92 "httpclient",
93 [](const std::shared_ptr<Request>& req) {
94 VLOG(1) << req->getSocketContext()->getSocketConnection()->getConnectionName() << ": OnRequestStart";
95
96 req->httpMinor = 0;
97 req->url = "/";
98 req->set("Connection", "keep-alive");
99 req->setTrailer("MyTrailer",
100 "MyTrailerValue"); // The "Trailer" header field should be populated but the Trailer itself should not be
101 // send here because there is no content which is send using "Transfer-Encoding:chunked"
102 req->end([](const std::shared_ptr<Request>& req, const std::shared_ptr<Response>& res) {
103 logResponse(req, res);
104 });
105#define LONG
106#ifdef LONG
107 req->url = "/hihihih";
108 req->set("Connection", "keep-alive");
109 req->end([](const std::shared_ptr<Request>& req, const std::shared_ptr<Response>& res) {
110 logResponse(req, res);
111 });
112
113 req->httpMinor = 1;
114 req->url = "/index.html";
115 // req->set("Connection", "keep-alive");
116 req->end([](const std::shared_ptr<Request>& req, const std::shared_ptr<Response>& res) {
117 logResponse(req, res);
118 });
119 req->url = "/";
120 req->set("Connection", "keep-alive");
121 req->end([](const std::shared_ptr<Request>& req, const std::shared_ptr<Response>& res) {
122 logResponse(req, res);
123 });
124 req->url = "/index.html";
125 req->set("Connection", "keep-alive");
126 req->end([](const std::shared_ptr<Request>& req, const std::shared_ptr<Response>& res) {
127 logResponse(req, res);
128 });
129 req->url = "/";
130 req->set("Connection", "keep-alive");
131 req->end([](const std::shared_ptr<Request>& req, const std::shared_ptr<Response>& res) {
132 logResponse(req, res);
133 });
134 req->url = "/index.html";
135 req->set("Connection", "keep-alive");
136 req->end([](const std::shared_ptr<Request>& req, const std::shared_ptr<Response>& res) {
137 logResponse(req, res);
138 });
139 req->url = "/";
140 req->set("Connection", "keep-alive");
141 req->end([](const std::shared_ptr<Request>& req, const std::shared_ptr<Response>& res) {
142 logResponse(req, res);
143 });
144 req->url = "/index.html";
145 req->set("Connection", "keep-alive");
146 req->end([](const std::shared_ptr<Request>& req, const std::shared_ptr<Response>& res) {
147 logResponse(req, res);
148 });
149 req->url = "/";
150 req->set("Connection", "keep-alive");
151 req->end([](const std::shared_ptr<Request>& req, const std::shared_ptr<Response>& res) {
152 logResponse(req, res);
153 });
154 req->url = "/index.html";
155 req->set("Connection", "keep-alive");
156 req->end([](const std::shared_ptr<Request>& req, const std::shared_ptr<Response>& res) {
157 logResponse(req, res);
158 });
159 req->url = "/";
160 req->set("Connection", "keep-alive");
161 req->end([](const std::shared_ptr<Request>& req, const std::shared_ptr<Response>& res) {
162 logResponse(req, res);
163 });
164 req->url = "/index.html";
165 req->set("Connection", "keep-alive");
166 req->end([](const std::shared_ptr<Request>& req, const std::shared_ptr<Response>& res) {
167 logResponse(req, res);
168 });
169 req->url = "/";
170 req->set("Connection", "keep-alive");
171 req->end([](const std::shared_ptr<Request>& req, const std::shared_ptr<Response>& res) {
172 logResponse(req, res);
173 });
174 req->url = "/index.html";
175 req->set("Connection", "keep-alive");
176 req->end([](const std::shared_ptr<Request>& req, const std::shared_ptr<Response>& res) {
177 logResponse(req, res);
178 });
179 req->url = "/";
180 req->set("Connection", "keep-alive");
181 req->end([](const std::shared_ptr<Request>& req, const std::shared_ptr<Response>& res) {
182 logResponse(req, res);
183 });
184 req->url = "/index.html";
185 req->set("Connection", "keep-alive");
186 req->end([](const std::shared_ptr<Request>& req, const std::shared_ptr<Response>& res) {
187 logResponse(req, res);
188 });
189 req->url = "/";
190 req->set("Connection", "keep-alive");
191 req->end([](const std::shared_ptr<Request>& req, const std::shared_ptr<Response>& res) {
192 logResponse(req, res);
193 });
194
195 req->httpMinor = 1;
196 req->method = "POST";
197 req->url = "/";
198 req->set("Test", "aaa");
199 req->setTrailer("MyTrailer1",
200 "MyTrailerValue1"); // Full trailer processing. Header field "Trailer" set and the Trailer itself is also
201 // sent because here content will be sent with "Transfer-Encoding:chunked"
202 req->setTrailer("MyTrailer2", "MyTrailerValue2");
203 req->setTrailer("MyTrailer3", "MyTrailerValue3");
204 req->setTrailer("MyTrailer4", "MyTrailerValue4");
205 req->setTrailer("MyTrailer5", "MyTrailerValue5");
206 req->setTrailer("MyTrailer6", "MyTrailerValue6");
207 req->query("Query1", "QueryValue1");
208 req->query("Query2", "QueryValue2");
209 req->sendFile(
210 "/home/voc/projects/snodec/snode.c/CMakeLists.txt",
211 [req](int ret) {
212 if (ret == 0) {
213 VLOG(1) << req->getSocketContext()->getSocketConnection()->getConnectionName()
214 << " HTTP: Request accepted: POST / HTTP/" << req->httpMajor << "." << req->httpMinor;
215 VLOG(1) << " /home/voc/projects/snodec/snode.c/CMakeLists.txt";
216 } else {
217 LOG(ERROR) << req->getSocketContext()->getSocketConnection()->getConnectionName()
218 << " HTTP: Request failed: POST / HTTP/" << req->httpMajor << "." << req->httpMinor;
219 PLOG(ERROR) << " /home/voc/projects/snodec/snode.c/CMakeLists.txt";
220
221 req->set("Connection", "close");
222 req->end([]([[maybe_unused]] const std::shared_ptr<Request>& req,
223 [[maybe_unused]] const std::shared_ptr<Response>& res) {
224 });
225 }
226 },
227 [](const std::shared_ptr<Request>& req, const std::shared_ptr<Response>& res) {
228 logResponse(req, res);
229
230 req->init();
231 req->method = "POST";
232 req->url = "/";
233 req->set("Connection", "keep-alive");
234 req->set("Test", "bbb");
235 req->sendFile(
236 "/home/voc/projects/snodec/snode.c/CMakeLists.tt",
237 [req](int ret) {
238 if (ret == 0) {
239 VLOG(1) << req->getSocketContext()->getSocketConnection()->getConnectionName()
240 << " HTTP: Request accepted: POST / HTTP/" << req->httpMajor << "." << req->httpMinor;
241 VLOG(1) << " /home/voc/projects/snodec/snode.c/CMakeLists.tt";
242 } else {
243 LOG(ERROR) << req->getSocketContext()->getSocketConnection()->getConnectionName()
244 << " HTTP: Request failed: POST / HTTP/" << req->httpMajor << "." << req->httpMinor;
245 PLOG(ERROR) << " /home/voc/projects/snodec/snode.c/CMakeLists.tt";
246
247 req->init();
248 req->method = "GET";
249 req->url = "/";
250 req->set("Connection", "close");
251 req->set("Test", "ccc");
252 req->end([](const std::shared_ptr<Request>& req, const std::shared_ptr<Response>& res) {
253 logResponse(req, res);
254 });
255 }
256 },
257 [](const std::shared_ptr<Request>& req, const std::shared_ptr<Response>& res) {
258 logResponse(req, res);
259 });
260 });
261 req->init();
262 req->method = "GET";
263 req->url = "/";
264 req->set("Connection", "close");
265 req->set("Test", "xxx");
266 req->end([](const std::shared_ptr<Request>& req, const std::shared_ptr<Response>& res) {
267 logResponse(req, res);
268 });
269 core::EventReceiver::atNextTick([req]() {
270 req->method = "POST";
271 req->url = "/";
272 req->set("Connection", "keep-alive");
273 req->set("Test", "ddd");
274 req->sendFile(
275 "/home/voc/projects/snodec/snode.c/CMakeLists.txt",
276 [req](int ret) {
277 if (ret == 0) {
278 VLOG(1) << req->getSocketContext()->getSocketConnection()->getConnectionName()
279 << " HTTP: Request accepted: POST / HTTP/" << req->httpMajor << "." << req->httpMinor;
280 VLOG(1) << " /home/voc/projects/snodec/snode.c/CMakeLists.txt";
281 } else {
282 LOG(ERROR) << req->getSocketContext()->getSocketConnection()->getConnectionName()
283 << " HTTP: Request failed: POST / HTTP/" << req->httpMajor << "." << req->httpMinor;
284 PLOG(ERROR) << " /home/voc/projects/snodec/snode.c/CMakeLists.txt";
285
286 req->set("Connection", "close");
287 req->end([]([[maybe_unused]] const std::shared_ptr<Request>& req,
288 [[maybe_unused]] const std::shared_ptr<Response>& res) {
289 });
290 }
291 },
292 [](const std::shared_ptr<Request>& req, const std::shared_ptr<Response>& res) {
293 logResponse(req, res);
294 });
295
296 req->method = "POST";
297 req->url = "/";
298 req->set("Connection", "keep-alive");
299 req->set("Test", "eee");
300 req->setTrailer("MyTrailer1", "MyTrailerValue1");
301 req->setTrailer("MyTrailer2", "MyTrailerValue2");
302 req->sendFile(
303 "/home/voc/projects/snodec/snode.c/CMakeLists.txt",
304 [req](int ret) {
305 if (ret == 0) {
306 VLOG(1) << req->getSocketContext()->getSocketConnection()->getConnectionName()
307 << " HTTP: Request accepted: POST / HTTP/" << req->httpMajor << "." << req->httpMinor;
308 VLOG(1) << " /home/voc/projects/snodec/snode.c/CMakeLists.txt";
309 } else {
310 LOG(ERROR) << req->getSocketContext()->getSocketConnection()->getConnectionName()
311 << " HTTP: Request failed: POST / HTTP/" << req->httpMajor << "." << req->httpMinor;
312 PLOG(ERROR) << " /home/voc/projects/snodec/snode.c/CMakeLists.txt";
313
314 req->set("Connection", "close");
315 req->end([]([[maybe_unused]] const std::shared_ptr<Request>& req,
316 [[maybe_unused]] const std::shared_ptr<Response>& res) {
317 });
318 }
319 },
320 [](const std::shared_ptr<Request>& req, const std::shared_ptr<Response>& res) {
321 logResponse(req, res);
322 });
323 });
324#endif
325 },
326 []([[maybe_unused]] const std::shared_ptr<Request>& req) {
327 VLOG(1) << req->getSocketContext()->getSocketConnection()->getConnectionName() << ": OnRequestEnd";
328 });
329
330 client.setOnConnect([](SocketConnection* socketConnection) { // onConnect
331 VLOG(1) << socketConnection->getConnectionName() << ": OnConnect";
332
333 VLOG(1) << "\tLocal: " << socketConnection->getLocalAddress().toString();
334 VLOG(1) << "\tPeer: " << socketConnection->getRemoteAddress().toString();
335 });
336
337 client.setOnDisconnect([](SocketConnection* socketConnection) { // onDisconnect
338 VLOG(1) << socketConnection->getConnectionName() << ": OnDisconnect";
339
340 VLOG(1) << "\tLocal: " << socketConnection->getLocalAddress().toString();
341 VLOG(1) << "\tPeer: " << socketConnection->getRemoteAddress().toString();
342 });
343
344 return client;
345 }
346
347} // namespace apps::http::legacy
348
349#endif // (STREAM_TYPE == LEGACY) // legacy
350
351#if (STREAM_TYPE == TLS) // tls
352
353namespace apps::http::tls {
354
359
360 static Client getClient() {
361 Client client(
362 "httpclient",
363 [](const std::shared_ptr<Request>& req) {
364 VLOG(1) << req->getSocketContext()->getSocketConnection()->getConnectionName() << ": OnRequestStart";
365
366 req->url = "/";
367 req->set("Connection", "keep-alive");
368 req->end([](const std::shared_ptr<Request>& req, const std::shared_ptr<Response>& res) {
369 logResponse(req, res);
370 });
371 req->url = "/";
372 req->set("Connection", "keep-alive");
373 req->end([](const std::shared_ptr<Request>& req, const std::shared_ptr<Response>& res) {
374 logResponse(req, res);
375 });
376 req->url = "/index.html";
377 req->set("Connection", "keep-alive");
378 req->end([](const std::shared_ptr<Request>& req, const std::shared_ptr<Response>& res) {
379 logResponse(req, res);
380 });
381 req->url = "/";
382 req->set("Connection", "keep-alive");
383 req->end([](const std::shared_ptr<Request>& req, const std::shared_ptr<Response>& res) {
384 logResponse(req, res);
385 });
386 req->url = "/index.html";
387 req->set("Connection", "keep-alive");
388 req->end([](const std::shared_ptr<Request>& req, const std::shared_ptr<Response>& res) {
389 logResponse(req, res);
390 });
391 req->url = "/";
392 req->set("Connection", "keep-alive");
393 req->end([](const std::shared_ptr<Request>& req, const std::shared_ptr<Response>& res) {
394 logResponse(req, res);
395 });
396 req->url = "/index.html";
397 req->set("Connection", "keep-alive");
398 req->end([](const std::shared_ptr<Request>& req, const std::shared_ptr<Response>& res) {
399 logResponse(req, res);
400 });
401 req->url = "/";
402 req->set("Connection", "keep-alive");
403 req->end([](const std::shared_ptr<Request>& req, const std::shared_ptr<Response>& res) {
404 logResponse(req, res);
405 });
406 req->url = "/index.html";
407 req->set("Connection", "keep-alive");
408 req->end([](const std::shared_ptr<Request>& req, const std::shared_ptr<Response>& res) {
409 logResponse(req, res);
410 });
411 req->url = "/";
412 req->set("Connection", "keep-alive");
413 req->end([](const std::shared_ptr<Request>& req, const std::shared_ptr<Response>& res) {
414 logResponse(req, res);
415 });
416 req->url = "/index.html";
417 req->set("Connection", "keep-alive");
418 req->end([](const std::shared_ptr<Request>& req, const std::shared_ptr<Response>& res) {
419 logResponse(req, res);
420 });
421 req->url = "/";
422 req->set("Connection", "keep-alive");
423 req->end([](const std::shared_ptr<Request>& req, const std::shared_ptr<Response>& res) {
424 logResponse(req, res);
425 });
426 req->url = "/index.html";
427 req->set("Connection", "keep-alive");
428 req->end([](const std::shared_ptr<Request>& req, const std::shared_ptr<Response>& res) {
429 logResponse(req, res);
430 });
431 req->url = "/";
432 req->set("Connection", "keep-alive");
433 req->end([](const std::shared_ptr<Request>& req, const std::shared_ptr<Response>& res) {
434 logResponse(req, res);
435 });
436 req->url = "/index.html";
437 req->set("Connection", "keep-alive");
438 req->end([](const std::shared_ptr<Request>& req, const std::shared_ptr<Response>& res) {
439 logResponse(req, res);
440 });
441 req->url = "/";
442 req->set("Connection", "keep-alive");
443 req->end([](const std::shared_ptr<Request>& req, const std::shared_ptr<Response>& res) {
444 logResponse(req, res);
445 });
446 req->url = "/index.html";
447 req->set("Connection", "keep-alive");
448 req->end([](const std::shared_ptr<Request>& req, const std::shared_ptr<Response>& res) {
449 logResponse(req, res);
450 });
451 req->url = "/";
452 req->set("Connection", "close");
453 req->end([](const std::shared_ptr<Request>& req, const std::shared_ptr<Response>& res) {
454 logResponse(req, res);
455 });
456 },
457 []([[maybe_unused]] const std::shared_ptr<Request>& req) {
458 VLOG(1) << req->getSocketContext()->getSocketConnection()->getConnectionName() << ": OnRequestEnd";
459 });
460
461 client.setOnConnect([](SocketConnection* socketConnection) { // onConnect
462 VLOG(1) << "OnConnect " << socketConnection->getConnectionName();
463
464 VLOG(1) << "\tLocal: " << socketConnection->getLocalAddress().toString();
465 VLOG(1) << "\tPeer: " << socketConnection->getRemoteAddress().toString();
466
467 /* Enable automatic hostname checks */
468 // X509_VERIFY_PARAM* param = SSL_get0_param(socketConnection->getSSL());
469
470 // X509_VERIFY_PARAM_set_hostflags(param, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
471 // if (!X509_VERIFY_PARAM_set1_host(param, "localhost", sizeof("localhost") - 1)) {
472 // // handle error
473 // socketConnection->close();
474 // }
475 });
476
477 client.setOnConnected([](SocketConnection* socketConnection) { // onConnected
478 VLOG(1) << socketConnection->getConnectionName() << ": OnConnected";
479 X509* server_cert = SSL_get_peer_certificate(socketConnection->getSSL());
480 if (server_cert != nullptr) {
481 long verifyErr = SSL_get_verify_result(socketConnection->getSSL());
482
483 VLOG(1) << "\tPeer certificate verifyErr = " + std::to_string(verifyErr) + ": " +
484 std::string(X509_verify_cert_error_string(verifyErr));
485
486 char* str = X509_NAME_oneline(X509_get_subject_name(server_cert), nullptr, 0);
487 VLOG(1) << "\t Subject: " + std::string(str);
488 OPENSSL_free(str);
489
490 str = X509_NAME_oneline(X509_get_issuer_name(server_cert), nullptr, 0);
491 VLOG(1) << "\t Issuer: " + std::string(str);
492 OPENSSL_free(str);
493
494 // We could do all sorts of certificate verification stuff here before deallocating the certificate.
495
496 GENERAL_NAMES* subjectAltNames =
497 static_cast<GENERAL_NAMES*>(X509_get_ext_d2i(server_cert, NID_subject_alt_name, nullptr, nullptr));
498#ifdef __GNUC__
499#pragma GCC diagnostic push
500#ifdef __has_warning
501#if __has_warning("-Wused-but-marked-unused")
502#pragma GCC diagnostic ignored "-Wused-but-marked-unused"
503#endif
504#endif
505#endif
506 int32_t altNameCount = sk_GENERAL_NAME_num(subjectAltNames);
507#ifdef __GNUC_
508#pragma GCC diagnostic pop
509#endif
510 VLOG(1) << "\t Subject alternative name count: " << altNameCount;
511 for (int32_t i = 0; i < altNameCount; ++i) {
512#ifdef __GNUC__
513#pragma GCC diagnostic push
514#ifdef __has_warning
515#if __has_warning("-Wused-but-marked-unused")
516#pragma GCC diagnostic ignored "-Wused-but-marked-unused"
517#endif
518#endif
519#endif
520 GENERAL_NAME* generalName = sk_GENERAL_NAME_value(subjectAltNames, i);
521#ifdef __GNUC_
522#pragma GCC diagnostic pop
523#endif
524 if (generalName->type == GEN_URI) {
525 std::string subjectAltName =
526 std::string(reinterpret_cast<const char*>(ASN1_STRING_get0_data(generalName->d.uniformResourceIdentifier)),
527 static_cast<std::size_t>(ASN1_STRING_length(generalName->d.uniformResourceIdentifier)));
528 VLOG(1) << "\t SAN (URI): '" + subjectAltName;
529 } else if (generalName->type == GEN_DNS) {
530 std::string subjectAltName =
531 std::string(reinterpret_cast<const char*>(ASN1_STRING_get0_data(generalName->d.dNSName)),
532 static_cast<std::size_t>(ASN1_STRING_length(generalName->d.dNSName)));
533 VLOG(1) << "\t SAN (DNS): '" + subjectAltName;
534 } else {
535 VLOG(1) << "\t SAN (Type): '" + std::to_string(generalName->type);
536 }
537 }
538#ifdef __GNUC__
539#pragma GCC diagnostic push
540#ifdef __has_warning
541#if __has_warning("-Wused-but-marked-unused")
542#pragma GCC diagnostic ignored "-Wused-but-marked-unused"
543#endif
544#endif
545#endif
546 sk_GENERAL_NAME_pop_free(subjectAltNames, GENERAL_NAME_free);
547#ifdef __GNUC_
548#pragma GCC diagnostic pop
549#endif
550 X509_free(server_cert);
551 } else {
552 VLOG(1) << "\tPeer certificate: no certificate";
553 }
554 });
555
556 client.setOnDisconnect([](SocketConnection* socketConnection) { // onDisconnect
557 VLOG(1) << socketConnection->getConnectionName() << ": OnDisconnect";
558
559 VLOG(1) << "\tLocal: " << socketConnection->getLocalAddress().toString();
560 VLOG(1) << "\tPeer: " << socketConnection->getRemoteAddress().toString();
561 });
562
563 return client;
564 }
565
566} // namespace apps::http::tls
567
568#endif // (STREAM_TYPE == TLS) // tls
569
570#endif // APPS_HTTP_MODEL_CLIENTS_H
int main(int argc, char *argv[])
#define QUOTE_INCLUDE(a)
Definition clients.h:47
#define STR_INCLUDE(a)
Definition servers.h:48
static void logResponse(const std::shared_ptr< web::http::client::Request > &req, const std::shared_ptr< web::http::client::Response > &res)
Definition clients.h:67
#define LONG
static Client getClient()
Definition clients.h:90
static Client getClient()
Definition clients.h:360