From ebbf753626c9e5dd26743c379741c53f9f11866e Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Wed, 14 Sep 2016 13:51:56 +0300 Subject: [PATCH] Support asynchronous name resolution in Http::Client --- source/http/client.cpp | 89 +++++++++++++++++++++++++++++++++++------- source/http/client.h | 17 ++++++++ 2 files changed, 92 insertions(+), 14 deletions(-) diff --git a/source/http/client.cpp b/source/http/client.cpp index 80815e0..6f22181 100644 --- a/source/http/client.cpp +++ b/source/http/client.cpp @@ -13,6 +13,9 @@ namespace Http { Client::Client(): sock(0), event_disp(0), + resolver(0), + resolve_listener(0), + resolve_tag(0), user_agent("libmsphttp/0.1"), request(0), response(0) @@ -34,26 +37,26 @@ void Client::use_event_dispatcher(IO::EventDispatcher *ed) event_disp->add(*sock); } +void Client::use_resolver(Net::Resolver *r) +{ + if(resolver) + { + delete resolve_listener; + resolve_listener = 0; + } + + resolver = r; + if(resolver) + resolve_listener = new ResolveListener(*this); +} + void Client::start_request(const Request &r) { if(request) throw client_busy(); - string host = r.get_header("Host"); - if(host.find(':')==string::npos) - host += ":80"; - RefPtr addr = Net::resolve(host); - delete sock; - sock = new Net::StreamSocket(addr->get_family()); - sock->set_block(false); - - sock->signal_data_available.connect(sigc::mem_fun(this, &Client::data_available)); - sock->signal_connect_finished.connect(sigc::mem_fun(this, &Client::connect_finished)); - if(event_disp) - event_disp->add(*sock); - - sock->connect(*addr); + sock = 0; request = new Request(r); if(!user_agent.empty()) @@ -62,6 +65,17 @@ void Client::start_request(const Request &r) delete response; response = 0; in_buf.clear(); + + string host = r.get_header("Host"); + if(host.find(':')==string::npos) + host += ":80"; + if(resolver) + resolve_tag = resolver->resolve(host); + else + { + RefPtr addr = Net::resolve(host); + address_resolved(resolve_tag, *addr); + } } const Response *Client::get_url(const std::string &url) @@ -104,6 +118,35 @@ void Client::abort() request = 0; } +void Client::address_resolved(unsigned tag, const Net::SockAddr &addr) +{ + if(tag!=resolve_tag) + return; + resolve_tag = 0; + + sock = new Net::StreamSocket(addr.get_family()); + sock->set_block(false); + + sock->signal_data_available.connect(sigc::mem_fun(this, &Client::data_available)); + sock->signal_connect_finished.connect(sigc::mem_fun(this, &Client::connect_finished)); + if(event_disp) + event_disp->add(*sock); + + sock->connect(addr); +} + +void Client::resolve_failed(unsigned tag, const exception &err) +{ + if(tag!=resolve_tag) + return; + resolve_tag = 0; + + signal_socket_error.emit(err); + + delete request; + request = 0; +} + void Client::connect_finished(const exception *err) { if(err) @@ -159,5 +202,23 @@ void Client::data_available() } } + +Client::ResolveListener::ResolveListener(Client &c): + client(c) +{ + client.resolver->signal_address_resolved.connect(sigc::mem_fun(this, &ResolveListener::address_resolved)); + client.resolver->signal_resolve_failed.connect(sigc::mem_fun(this, &ResolveListener::resolve_failed)); +} + +void Client::ResolveListener::address_resolved(unsigned tag, const Net::SockAddr &addr) +{ + client.address_resolved(tag, addr); +} + +void Client::ResolveListener::resolve_failed(unsigned tag, const exception &err) +{ + client.resolve_failed(tag, err); +} + } // namespace Http } // namespace Msp diff --git a/source/http/client.h b/source/http/client.h index 37acf0c..ebb7321 100644 --- a/source/http/client.h +++ b/source/http/client.h @@ -4,6 +4,7 @@ #include #include #include +#include #include namespace Msp { @@ -26,8 +27,21 @@ public: sigc::signal signal_socket_error; private: + struct ResolveListener: public sigc::trackable + { + Client &client; + + ResolveListener(Client &); + + void address_resolved(unsigned, const Net::SockAddr &); + void resolve_failed(unsigned, const std::exception &); + }; + Net::StreamSocket *sock; IO::EventDispatcher *event_disp; + Net::Resolver *resolver; + ResolveListener *resolve_listener; + unsigned resolve_tag; std::string user_agent; Request *request; Response *response; @@ -40,6 +54,7 @@ public: ~Client(); void use_event_dispatcher(IO::EventDispatcher *); + void use_resolver(Net::Resolver *); void set_user_agent(const std::string &); void start_request(const Request &); const Response *get_url(const std::string &); @@ -49,6 +64,8 @@ public: const Request *get_request() const { return request; } const Response *get_response() const { return response; } private: + void address_resolved(unsigned, const Net::SockAddr &); + void resolve_failed(unsigned, const std::exception &); void connect_finished(const std::exception *); void data_available(); }; -- 2.43.0