+/* $Id$
+
+This file is part of libmsphttp
+Copyright © 2008 Mikkosoft Productions, Mikko Rasa
+Distributed under the LGPL
+*/
+
+#include <msp/core/except.h>
+#include <msp/core/refptr.h>
+#include <msp/net/resolve.h>
+#include <msp/time/units.h>
+#include "client.h"
+#include "request.h"
+#include "response.h"
+
+using namespace std;
+
+#include <iostream>
+
+namespace Msp {
+namespace Http {
+
+Client::Client():
+ sock(0),
+ event_disp(0),
+ request(0),
+ response(0)
+{ }
+
+Client::~Client()
+{
+ delete sock;
+ delete request;
+ delete response;
+}
+
+void Client::use_event_dispatcher(IO::EventDispatcher *ed)
+{
+ event_disp=ed;
+ if(sock)
+ event_disp->add(*sock);
+}
+
+void Client::start_request(const Request &r)
+{
+ if(request)
+ throw InvalidState("Already processing a request");
+
+ RefPtr<Net::SockAddr> addr=Net::resolve(r.get_header("host")+":"+r.get_header("x-port"));
+
+ 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);
+
+ request=new Request(r);
+
+ delete response;
+ response=0;
+ in_buf.clear();
+}
+
+void Client::get_url(const std::string &url)
+{
+ start_request(Request::from_url(url));
+ wait_response();
+}
+
+void Client::tick()
+{
+ if(!request)
+ return;
+
+ while(IO::PollEvent ev=IO::poll(*sock, sock->get_events(), Time::zero))
+ sock->event(ev);
+
+ if(response && response->get_complete())
+ {
+ signal_response_complete.emit(*response);
+
+ delete sock;
+ sock=0;
+ delete request;
+ request=0;
+ }
+}
+
+void Client::wait_response()
+{
+ while(!response || !response->get_complete())
+ tick();
+}
+
+void Client::abort()
+{
+ delete sock;
+ sock=0;
+ delete request;
+ request=0;
+}
+
+void Client::connect_finished(int err)
+{
+ if(err)
+ {
+ signal_socket_error.emit(err);
+
+ sock->close();
+ delete request;
+ request=0;
+ }
+ else
+ sock->write(request->str());
+}
+
+void Client::data_available()
+{
+ char rbuf[4096];
+ unsigned len=sock->read(rbuf, sizeof(rbuf));
+ in_buf.append(rbuf, len);
+
+ if(!response)
+ {
+ if(in_buf.find("\r\n\r\n")!=string::npos || in_buf.find("\n\n")!=string::npos)
+ {
+ response=new Response(Response::parse(in_buf));
+ in_buf=string();
+ }
+ }
+ else
+ {
+ len=response->parse_data(in_buf);
+ in_buf.erase(0, len);
+ }
+
+ if(response && response->get_complete())
+ {
+ signal_response_complete.emit(*response);
+
+ sock->close();
+ delete request;
+ request=0;
+ }
+}
+
+} // namespace Http
+} // namespace Msp