]> git.tdb.fi Git - libs/net.git/blobdiff - source/http/client.cpp
Support asynchronous name resolution in Http::Client
[libs/net.git] / source / http / client.cpp
index 80815e0c9f6c33a5ced29e65cb6c82674c8b8b97..6f221810c922a78f85289934b36ce4d6b71b2100 100644 (file)
@@ -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<Net::SockAddr> 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<Net::SockAddr> 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