-#include <msp/core/refptr.h>
-#include <msp/net/resolve.h>
-#include <msp/time/units.h>
#include "client.h"
+#include <msp/core/except.h>
+#include <msp/net/resolve.h>
+#include <msp/time/timedelta.h>
#include "request.h"
#include "response.h"
namespace Msp {
namespace Http {
-Client::Client():
- sock(0),
- event_disp(0),
- user_agent("libmsphttp/0.1"),
- request(0),
- response(0)
-{ }
-
Client::~Client()
{
- delete sock;
- delete request;
- delete response;
}
void Client::use_event_dispatcher(IO::EventDispatcher *ed)
event_disp->add(*sock);
}
-void Client::start_request(const Request &r)
+void Client::use_resolver(Net::Resolver *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);
+ if(resolver)
+ resolve_listener.reset();
- delete sock;
- sock = new Net::StreamSocket(addr->get_family());
- sock->set_block(false);
+ resolver = r;
+ if(resolver)
+ resolve_listener = make_unique<ResolveListener>(*this);
+}
- 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);
+void Client::start_request(const Request &r)
+{
+ if(request)
+ throw invalid_state("already processing a request");
- sock->connect(*addr);
+ sock.reset();
- request = new Request(r);
+ request = make_unique<Request>(r);
if(!user_agent.empty())
request->set_header("User-Agent", user_agent);
- delete response;
- response = 0;
+ response.reset();
in_buf.clear();
+
+ string host = r.get_header("Host");
+ if(host.find(':')==string::npos)
+ host += ":80";
+ if(resolver)
+ resolve_tag = resolver->resolve(host);
+ else
+ {
+ unique_ptr<Net::SockAddr> addr(Net::resolve(host));
+ address_resolved(resolve_tag, *addr);
+ }
}
const Response *Client::get_url(const std::string &url)
{
start_request(Request::from_url(url));
wait_response();
- return response;
+ return response.get();
}
void Client::tick()
{
signal_response_complete.emit(*response);
- delete sock;
- sock = 0;
- delete request;
- request = 0;
+ sock.reset();
+ request.reset();
}
}
void Client::abort()
{
- delete sock;
- sock = 0;
- delete request;
- request = 0;
+ sock.reset();
+ request.reset();
+}
+
+void Client::address_resolved(unsigned tag, const Net::SockAddr &addr)
+{
+ if(tag!=resolve_tag)
+ return;
+ resolve_tag = 0;
+
+ sock = make_unique<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;
+
+ request.reset();
+
+ if(signal_socket_error.empty())
+ throw err;
+ signal_socket_error.emit(err);
}
void Client::connect_finished(const exception *err)
{
if(err)
{
- signal_socket_error.emit(*err);
+ request.reset();
- delete request;
- request = 0;
+ if(signal_socket_error.empty())
+ throw *err;
+ signal_socket_error.emit(*err);
}
else
- sock->write(request->str());
+ {
+ try
+ {
+ sock->write(request->str());
+ }
+ catch(const exception &e)
+ {
+ if(signal_socket_error.empty())
+ throw;
+ signal_socket_error.emit(e);
+ return;
+ }
+ }
}
void Client::data_available()
}
catch(const exception &e)
{
+ if(signal_socket_error.empty())
+ throw;
signal_socket_error.emit(e);
return;
}
{
if(in_buf.find("\r\n\r\n")!=string::npos || in_buf.find("\n\n")!=string::npos)
{
- response = new Response(Response::parse(in_buf));
+ response = make_unique<Response>(Response::parse(in_buf));
response->set_user_data(request->get_user_data());
in_buf = string();
}
{
signal_response_complete.emit(*response);
- delete request;
- request = 0;
+ request.reset();
}
}
+
+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