Skip to content
This repository was archived by the owner on Jun 12, 2018. It is now read-only.

Commit 080d6ba

Browse files
committed
Created non-templated base classes
1 parent 1056bd2 commit 080d6ba

File tree

5 files changed

+328
-290
lines changed

5 files changed

+328
-290
lines changed

client_http.hpp

Lines changed: 123 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
#include <unordered_set>
99
#include <vector>
1010

11+
; // <- libclang bug workaround
12+
1113
#ifdef USE_STANDALONE_ASIO
1214
#include <asio.hpp>
1315
#include <asio/steady_timer.hpp>
@@ -33,14 +35,11 @@ namespace SimpleWeb {
3335
#endif
3436

3537
namespace SimpleWeb {
36-
template <class socket_type>
37-
class Client;
38-
39-
template <class socket_type>
4038
class ClientBase {
4139
public:
40+
class Response;
4241
class Content : public std::istream {
43-
friend class ClientBase<socket_type>;
42+
friend class Response;
4443

4544
public:
4645
std::size_t size() noexcept {
@@ -64,8 +63,10 @@ namespace SimpleWeb {
6463
};
6564

6665
class Response {
67-
friend class ClientBase<socket_type>;
68-
friend class Client<socket_type>;
66+
template <typename SocketType>
67+
friend class ClientTemplate;
68+
template <typename SocketType>
69+
friend class Client;
6970

7071
asio::streambuf streambuf;
7172

@@ -80,7 +81,7 @@ namespace SimpleWeb {
8081
};
8182

8283
class Config {
83-
friend class ClientBase<socket_type>;
84+
friend class ClientBase;
8485

8586
private:
8687
Config() noexcept {}
@@ -97,67 +98,49 @@ namespace SimpleWeb {
9798
std::string proxy_server;
9899
};
99100

100-
protected:
101-
class Connection : public std::enable_shared_from_this<Connection> {
102-
public:
103-
template <typename... Args>
104-
Connection(std::shared_ptr<ScopeRunner> handler_runner, long timeout, Args &&... args) noexcept
105-
: handler_runner(std::move(handler_runner)), timeout(timeout), socket(new socket_type(std::forward<Args>(args)...)) {}
106-
107-
std::shared_ptr<ScopeRunner> handler_runner;
108-
long timeout;
109-
110-
std::unique_ptr<socket_type> socket; // Socket must be unique_ptr since asio::ssl::stream<asio::ip::tcp::socket> is not movable
111-
bool in_use = false;
112-
bool attempt_reconnect = true;
113-
114-
std::unique_ptr<asio::steady_timer> timer;
115-
116-
void set_timeout(long seconds = 0) noexcept {
117-
if(seconds == 0)
118-
seconds = timeout;
119-
if(seconds == 0) {
120-
timer = nullptr;
121-
return;
122-
}
123-
timer = std::unique_ptr<asio::steady_timer>(new asio::steady_timer(socket->get_io_service()));
124-
timer->expires_from_now(std::chrono::seconds(seconds));
125-
auto self = this->shared_from_this();
126-
timer->async_wait([self](const error_code &ec) {
127-
if(!ec) {
128-
error_code ec;
129-
self->socket->lowest_layer().cancel(ec);
130-
}
131-
});
132-
}
133-
134-
void cancel_timeout() noexcept {
135-
if(timer) {
136-
error_code ec;
137-
timer->cancel(ec);
138-
}
139-
}
140-
};
141-
142-
class Session {
143-
public:
144-
Session(std::size_t max_response_streambuf_size, std::shared_ptr<Connection> connection, std::unique_ptr<asio::streambuf> request_streambuf) noexcept
145-
: connection(std::move(connection)), request_streambuf(std::move(request_streambuf)), response(new Response(max_response_streambuf_size)) {}
146-
147-
std::shared_ptr<Connection> connection;
148-
std::unique_ptr<asio::streambuf> request_streambuf;
149-
std::shared_ptr<Response> response;
150-
std::function<void(const std::shared_ptr<Connection> &, const error_code &)> callback;
151-
};
152-
153-
public:
154101
/// Set before calling request
155102
Config config;
156103

157104
/// If you have your own asio::io_service, store its pointer here before calling request().
158105
/// When using asynchronous requests, running the io_service is up to the programmer.
159106
std::shared_ptr<asio::io_service> io_service;
160107

108+
/// Asynchronous request where setting and/or running Client's io_service is required.
109+
/// Do not use concurrently with the synchronous request functions.
110+
virtual void request(const std::string &method, const std::string &path, string_view content, const CaseInsensitiveMultimap &header,
111+
std::function<void(std::shared_ptr<Response>, const error_code &)> &&request_callback_) = 0;
112+
/// Asynchronous request where setting and/or running Client's io_service is required.
113+
/// Do not use concurrently with the synchronous request functions.
114+
virtual void request(const std::string &method, const std::string &path, std::istream &content, const CaseInsensitiveMultimap &header,
115+
std::function<void(std::shared_ptr<Response>, const error_code &)> &&request_callback_) = 0;
116+
117+
/// Asynchronous request where setting and/or running Client's io_service is required.
118+
/// Do not use concurrently with the synchronous request functions.
119+
void request(const std::string &method, const std::string &path, string_view content,
120+
std::function<void(std::shared_ptr<Response>, const error_code &)> &&request_callback) {
121+
request(method, path, content, CaseInsensitiveMultimap(), std::move(request_callback));
122+
}
123+
124+
/// Asynchronous request where setting and/or running Client's io_service is required.
125+
/// Do not use concurrently with the synchronous request functions.
126+
void request(const std::string &method, const std::string &path,
127+
std::function<void(std::shared_ptr<Response>, const error_code &)> &&request_callback) {
128+
request(method, path, std::string(), CaseInsensitiveMultimap(), std::move(request_callback));
129+
}
130+
131+
/// Asynchronous request where setting and/or running Client's io_service is required.
132+
/// Do not use concurrently with the synchronous request functions.
133+
void request(const std::string &method, std::function<void(std::shared_ptr<Response>, const error_code &)> &&request_callback) {
134+
request(method, std::string("/"), std::string(), CaseInsensitiveMultimap(), std::move(request_callback));
135+
}
136+
137+
/// Asynchronous request where setting and/or running Client's io_service is required.
138+
/// Do not use concurrently with the synchronous request functions.
139+
void request(const std::string &method, const std::string &path, std::istream &content,
140+
std::function<void(std::shared_ptr<Response>, const error_code &)> &&request_callback) {
141+
request(method, path, content, CaseInsensitiveMultimap(), std::move(request_callback));
142+
}
143+
161144
/// Convenience function to perform synchronous request. The io_service is run within this function.
162145
/// If reusing the io_service for other tasks, use the asynchronous request functions instead.
163146
/// Do not use concurrently with the asynchronous request functions.
@@ -218,10 +201,78 @@ namespace SimpleWeb {
218201
return response;
219202
}
220203

204+
/// Close connections
205+
virtual void stop() noexcept = 0;
206+
207+
virtual ~ClientBase() {}
208+
209+
protected:
210+
std::size_t concurrent_synchronous_requests = 0;
211+
std::mutex concurrent_synchronous_requests_mutex;
212+
};
213+
214+
template <typename SocketType>
215+
class ClientTemplate : public ClientBase {
216+
protected:
217+
class Connection : public std::enable_shared_from_this<Connection> {
218+
public:
219+
template <typename... Args>
220+
Connection(std::shared_ptr<ScopeRunner> handler_runner, long timeout, Args &&... args) noexcept
221+
: handler_runner(std::move(handler_runner)), timeout(timeout), socket(new SocketType(std::forward<Args>(args)...)) {}
222+
223+
std::shared_ptr<ScopeRunner> handler_runner;
224+
long timeout;
225+
226+
std::unique_ptr<SocketType> socket; // Socket must be unique_ptr since asio::ssl::stream<asio::ip::tcp::socket> is not movable
227+
bool in_use = false;
228+
bool attempt_reconnect = true;
229+
230+
std::unique_ptr<asio::steady_timer> timer;
231+
232+
void set_timeout(long seconds = 0) noexcept {
233+
if(seconds == 0)
234+
seconds = timeout;
235+
if(seconds == 0) {
236+
timer = nullptr;
237+
return;
238+
}
239+
timer = std::unique_ptr<asio::steady_timer>(new asio::steady_timer(socket->get_io_service()));
240+
timer->expires_from_now(std::chrono::seconds(seconds));
241+
auto self = this->shared_from_this();
242+
timer->async_wait([self](const error_code &ec) {
243+
if(!ec) {
244+
error_code ec;
245+
self->socket->lowest_layer().cancel(ec);
246+
}
247+
});
248+
}
249+
250+
void cancel_timeout() noexcept {
251+
if(timer) {
252+
error_code ec;
253+
timer->cancel(ec);
254+
}
255+
}
256+
};
257+
258+
class Session {
259+
public:
260+
Session(std::size_t max_response_streambuf_size, std::shared_ptr<Connection> connection, std::unique_ptr<asio::streambuf> request_streambuf) noexcept
261+
: connection(std::move(connection)), request_streambuf(std::move(request_streambuf)), response(new Response(max_response_streambuf_size)) {}
262+
263+
std::shared_ptr<Connection> connection;
264+
std::unique_ptr<asio::streambuf> request_streambuf;
265+
std::shared_ptr<Response> response;
266+
std::function<void(const std::shared_ptr<Connection> &, const error_code &)> callback;
267+
};
268+
269+
public:
270+
using ClientBase::request;
271+
221272
/// Asynchronous request where setting and/or running Client's io_service is required.
222273
/// Do not use concurrently with the synchronous request functions.
223274
void request(const std::string &method, const std::string &path, string_view content, const CaseInsensitiveMultimap &header,
224-
std::function<void(std::shared_ptr<Response>, const error_code &)> &&request_callback_) {
275+
std::function<void(std::shared_ptr<Response>, const error_code &)> &&request_callback_) override {
225276
auto session = std::make_shared<Session>(config.max_response_streambuf_size, get_connection(), create_request_header(method, path, header));
226277
auto response = session->response;
227278
auto request_callback = std::make_shared<std::function<void(std::shared_ptr<Response>, const error_code &)>>(std::move(request_callback_));
@@ -268,25 +319,8 @@ namespace SimpleWeb {
268319

269320
/// Asynchronous request where setting and/or running Client's io_service is required.
270321
/// Do not use concurrently with the synchronous request functions.
271-
void request(const std::string &method, const std::string &path, string_view content,
272-
std::function<void(std::shared_ptr<Response>, const error_code &)> &&request_callback) {
273-
request(method, path, content, CaseInsensitiveMultimap(), std::move(request_callback));
274-
}
275-
276-
/// Asynchronous request where setting and/or running Client's io_service is required.
277-
void request(const std::string &method, const std::string &path,
278-
std::function<void(std::shared_ptr<Response>, const error_code &)> &&request_callback) {
279-
request(method, path, std::string(), CaseInsensitiveMultimap(), std::move(request_callback));
280-
}
281-
282-
/// Asynchronous request where setting and/or running Client's io_service is required.
283-
void request(const std::string &method, std::function<void(std::shared_ptr<Response>, const error_code &)> &&request_callback) {
284-
request(method, std::string("/"), std::string(), CaseInsensitiveMultimap(), std::move(request_callback));
285-
}
286-
287-
/// Asynchronous request where setting and/or running Client's io_service is required.
288322
void request(const std::string &method, const std::string &path, std::istream &content, const CaseInsensitiveMultimap &header,
289-
std::function<void(std::shared_ptr<Response>, const error_code &)> &&request_callback_) {
323+
std::function<void(std::shared_ptr<Response>, const error_code &)> &&request_callback_) override {
290324
auto session = std::make_shared<Session>(config.max_response_streambuf_size, get_connection(), create_request_header(method, path, header));
291325
auto response = session->response;
292326
auto request_callback = std::make_shared<std::function<void(std::shared_ptr<Response>, const error_code &)>>(std::move(request_callback_));
@@ -335,14 +369,8 @@ namespace SimpleWeb {
335369
connect(session);
336370
}
337371

338-
/// Asynchronous request where setting and/or running Client's io_service is required.
339-
void request(const std::string &method, const std::string &path, std::istream &content,
340-
std::function<void(std::shared_ptr<Response>, const error_code &)> &&request_callback) {
341-
request(method, path, content, CaseInsensitiveMultimap(), std::move(request_callback));
342-
}
343-
344372
/// Close connections
345-
void stop() noexcept {
373+
void stop() noexcept override {
346374
std::unique_lock<std::mutex> lock(connections_mutex);
347375
for(auto it = connections.begin(); it != connections.end();) {
348376
error_code ec;
@@ -351,7 +379,7 @@ namespace SimpleWeb {
351379
}
352380
}
353381

354-
virtual ~ClientBase() noexcept {
382+
~ClientTemplate() {
355383
handler_runner->stop();
356384
stop();
357385
}
@@ -370,10 +398,7 @@ namespace SimpleWeb {
370398

371399
std::shared_ptr<ScopeRunner> handler_runner;
372400

373-
std::size_t concurrent_synchronous_requests = 0;
374-
std::mutex concurrent_synchronous_requests_mutex;
375-
376-
ClientBase(const std::string &host_port, unsigned short default_port) noexcept : default_port(default_port), handler_runner(new ScopeRunner()) {
401+
ClientTemplate(const std::string &host_port, unsigned short default_port) noexcept : default_port(default_port), handler_runner(new ScopeRunner()) {
377402
auto parsed_host_port = parse_host_port(host_port, default_port);
378403
host = parsed_host_port.first;
379404
port = parsed_host_port.second;
@@ -420,7 +445,7 @@ namespace SimpleWeb {
420445
auto corrected_path = path;
421446
if(corrected_path == "")
422447
corrected_path = "/";
423-
if(!config.proxy_server.empty() && std::is_same<socket_type, asio::ip::tcp::socket>::value)
448+
if(!config.proxy_server.empty() && std::is_same<SocketType, asio::ip::tcp::socket>::value)
424449
corrected_path = "http://" + host + ':' + std::to_string(port) + corrected_path;
425450

426451
std::unique_ptr<asio::streambuf> streambuf(new asio::streambuf());
@@ -638,15 +663,15 @@ namespace SimpleWeb {
638663
}
639664
};
640665

641-
template <class socket_type>
642-
class Client : public ClientBase<socket_type> {};
666+
template <typename = void>
667+
class Client : public ClientBase {};
643668

644669
using HTTP = asio::ip::tcp::socket;
645670

646671
template <>
647-
class Client<HTTP> : public ClientBase<HTTP> {
672+
class Client<HTTP> : public ClientTemplate<HTTP> {
648673
public:
649-
Client(const std::string &server_port_path) noexcept : ClientBase<HTTP>::ClientBase(server_port_path, 80) {}
674+
Client(const std::string &server_port_path) noexcept : ClientTemplate<HTTP>::ClientTemplate(server_port_path, 80) {}
650675

651676
protected:
652677
std::shared_ptr<Connection> create_connection() noexcept override {

client_https.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,11 @@ namespace SimpleWeb {
1313
using HTTPS = asio::ssl::stream<asio::ip::tcp::socket>;
1414

1515
template <>
16-
class Client<HTTPS> : public ClientBase<HTTPS> {
16+
class Client<HTTPS> : public ClientTemplate<HTTPS> {
1717
public:
1818
Client(const std::string &server_port_path, bool verify_certificate = true, const std::string &cert_file = std::string(),
1919
const std::string &private_key_file = std::string(), const std::string &verify_file = std::string())
20-
: ClientBase<HTTPS>::ClientBase(server_port_path, 443), context(asio::ssl::context::tlsv12) {
20+
: ClientTemplate<HTTPS>::ClientTemplate(server_port_path, 443), context(asio::ssl::context::tlsv12) {
2121
if(cert_file.size() > 0 && private_key_file.size() > 0) {
2222
context.use_certificate_chain_file(cert_file);
2323
context.use_private_key_file(private_key_file, asio::ssl::context::pem);

0 commit comments

Comments
 (0)