FETPAPI 0.3.0.0
This project provides C++ classes which facilitate the developement of ETP1.2 clients and servers.
Loading...
Searching...
No Matches
SslClientSession.h
1/*-----------------------------------------------------------------------
2Licensed to the Apache Software Foundation (ASF) under one
3or more contributor license agreements. See the NOTICE file
4distributed with this work for additional information
5regarding copyright ownership. The ASF licenses this file
6to you under the Apache License, Version 2.0 (the
7"License"; you may not use this file except in compliance
8with the License. You may obtain a copy of the License at
9
10 http://www.apache.org/licenses/LICENSE-2.0
11
12Unless required by applicable law or agreed to in writing,
13software distributed under the License is distributed on an
14"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15KIND, either express or implied. See the License for the
16specific language governing permissions and limitations
17under the License.
18-----------------------------------------------------------------------*/
19#pragma once
20
21#include "../AbstractClientSessionCRTP.h"
22
23#include <boost/version.hpp>
24#if BOOST_VERSION < 106800
25#include "ssl_stream.h"
26#elif BOOST_VERSION < 107000
27#include <boost/beast/experimental/core/ssl_stream.hpp>
28#else
29#include <boost/beast/http.hpp>
30#include <boost/beast/ssl.hpp>
31#include <boost/beast/websocket/ssl.hpp>
32#endif
33
34namespace http = boost::beast::http; // from <boost/beast/http.hpp>
35
36namespace ETP_NS
37{
38 class SslClientSession : public AbstractClientSessionCRTP<SslClientSession>
39 {
40 private:
41 websocket::stream<boost::beast::ssl_stream<tcp::socket>> ws_;
42 http::request<http::empty_body> proxyHandshake;
43 http::response<http::empty_body> proxyHandshakeResponse;
44 // use own response parser
45 // NOTE: 200 response to a CONNECT request from a tunneling proxy do not carry a body
46 http::response_parser<http::empty_body> http_proxy_handshake_parser;
47
48 public:
49 /*
50 * @param frameSize Sets the size of the write buffer used by the implementation to send frames : https://www.boost.org/doc/libs/1_75_0/libs/beast/doc/html/beast/ref/boost__beast__websocket__stream/write_buffer_bytes/overload1.html.
51 */
52 FETPAPI_DLL_IMPORT_OR_EXPORT SslClientSession(boost::asio::ssl::context& ctx,
53 InitializationParameters const* initializationParams, const std::string& target, const std::string& authorization, const std::string& proxyAuthorization = "",
54 const std::map<std::string, std::string>& additionalHandshakeHeaderFields = {}, std::size_t frameSize = 4096);
55
56 virtual ~SslClientSession() {}
57
58 // Called by the base class
59 FETPAPI_DLL_IMPORT_OR_EXPORT websocket::stream<boost::beast::ssl_stream<tcp::socket>>& ws() { return ws_; }
60
61 bool isTls() const final { return true; }
62
63 void on_resolve(boost::system::error_code ec, tcp::resolver::results_type results)
64 {
65 if (ec) {
66 std::cerr << "on_resolve : " << ec.message() << std::endl;
67 }
68
69 // Make the connection on the IP address we get from a lookup
70 boost::asio::async_connect(
71 ws_.next_layer().next_layer(),
72 results.begin(),
73 results.end(),
74 std::bind(
75 &SslClientSession::on_ssl_connect,
76 std::static_pointer_cast<SslClientSession>(shared_from_this()),
77 std::placeholders::_1));
78 }
79
80 void on_ssl_connect(boost::system::error_code ec) {
81 if (ec) {
82 std::cerr << "on_ssl_connect : " << ec.message() << std::endl;
83 }
84
85 if (!proxyHost.empty()) {
86 proxyHandshake.version(11);
87 proxyHandshake.method(http::verb::connect);
88 proxyHandshake.target(etpServerHost + ':' + etpServerPort);
89 proxyHandshake.set(http::field::host, etpServerHost + ':' + etpServerPort);
90 if (!etpServerAuthorization.empty()) {
91 proxyHandshake.set(http::field::authorization, etpServerAuthorization);
92 }
93 if (!proxyAuthorization.empty()) {
94 proxyHandshake.set(http::field::proxy_authorization, proxyAuthorization);
95 }
96
97 // Send the handshake to the proxy
98 http::async_write(ws_.next_layer().next_layer(), proxyHandshake,
99 std::bind(
100 &SslClientSession::on_proxy_handshake_write,
101 std::static_pointer_cast<SslClientSession>(shared_from_this()),
102 std::placeholders::_1,
103 std::placeholders::_2));
104 }
105 else {
106 // Perform the SSL handshake
107 ws_.next_layer().async_handshake(
108 boost::asio::ssl::stream_base::client,
109 std::bind(
110 &AbstractClientSessionCRTP::on_connect,
111 std::static_pointer_cast<AbstractClientSessionCRTP>(shared_from_this()),
112 std::placeholders::_1));
113 }
114 }
115
116 void
118 boost::system::error_code ec,
119 std::size_t bytes_transferred)
120 {
121 boost::ignore_unused(bytes_transferred);
122
123 if (ec) {
124 std::cerr << "Proxy handshake write : " << ec.message() << std::endl;
125 return;
126 }
127
140 http_proxy_handshake_parser.skip(true); // see https://stackoverflow.com/a/49837467/10904212
141
142 // Receive the HTTP response
143 http::async_read(ws_.next_layer().next_layer(), receivedBuffer, http_proxy_handshake_parser,
144 std::bind(
145 &SslClientSession::on_proxy_handshake_read,
146 std::static_pointer_cast<SslClientSession>(shared_from_this()),
147 std::placeholders::_1,
148 std::placeholders::_2));
149 }
150
151 void
152 on_proxy_handshake_read(
153 boost::system::error_code ec,
154 std::size_t bytes_transferred)
155 {
156 boost::ignore_unused(bytes_transferred);
157 if (ec) {
158 std::cerr << "read : " << ec.message() << std::endl;
159 return;
160 }
161
162 // Perform the SSL handshake
163 ws_.next_layer().async_handshake(
164 boost::asio::ssl::stream_base::client,
165 std::bind(
166 &AbstractClientSessionCRTP::on_connect,
167 std::static_pointer_cast<AbstractClientSessionCRTP>(shared_from_this()),
168 std::placeholders::_1));
169 }
170 };
171}
Definition AbstractClientSessionCRTP.h:28
Definition InitializationParameters.h:41
Definition SslClientSession.h:39
void on_proxy_handshake_write(boost::system::error_code ec, std::size_t bytes_transferred)
Definition SslClientSession.h:117