]> git.tdb.fi Git - libs/net.git/blob - source/http/client.cpp
80815e0c9f6c33a5ced29e65cb6c82674c8b8b97
[libs/net.git] / source / http / client.cpp
1 #include <msp/core/refptr.h>
2 #include <msp/net/resolve.h>
3 #include <msp/time/units.h>
4 #include "client.h"
5 #include "request.h"
6 #include "response.h"
7
8 using namespace std;
9
10 namespace Msp {
11 namespace Http {
12
13 Client::Client():
14         sock(0),
15         event_disp(0),
16         user_agent("libmsphttp/0.1"),
17         request(0),
18         response(0)
19 { }
20
21 Client::~Client()
22 {
23         delete sock;
24         delete request;
25         delete response;
26 }
27
28 void Client::use_event_dispatcher(IO::EventDispatcher *ed)
29 {
30         if(event_disp && sock)
31                 event_disp->remove(*sock);
32         event_disp = ed;
33         if(event_disp && sock)
34                 event_disp->add(*sock);
35 }
36
37 void Client::start_request(const Request &r)
38 {
39         if(request)
40                 throw client_busy();
41
42         string host = r.get_header("Host");
43         if(host.find(':')==string::npos)
44                 host += ":80";
45         RefPtr<Net::SockAddr> addr = Net::resolve(host);
46
47         delete sock;
48         sock = new Net::StreamSocket(addr->get_family());
49         sock->set_block(false);
50
51         sock->signal_data_available.connect(sigc::mem_fun(this, &Client::data_available));
52         sock->signal_connect_finished.connect(sigc::mem_fun(this, &Client::connect_finished));
53         if(event_disp)
54                 event_disp->add(*sock);
55
56         sock->connect(*addr);
57
58         request = new Request(r);
59         if(!user_agent.empty())
60                 request->set_header("User-Agent", user_agent);
61
62         delete response;
63         response = 0;
64         in_buf.clear();
65 }
66
67 const Response *Client::get_url(const std::string &url)
68 {
69         start_request(Request::from_url(url));
70         wait_response();
71         return response;
72 }
73
74 void Client::tick()
75 {
76         if(!request)
77                 return;
78
79         while(IO::PollEvent ev = IO::poll(*sock, sock->get_events(), Time::zero))
80                 sock->event(ev);
81
82         if(response && response->is_complete())
83         {
84                 signal_response_complete.emit(*response);
85
86                 delete sock;
87                 sock = 0;
88                 delete request;
89                 request = 0;
90         }
91 }
92
93 void Client::wait_response()
94 {
95         while(request && (!response || !response->is_complete()))
96                 tick();
97 }
98
99 void Client::abort()
100 {
101         delete sock;
102         sock = 0;
103         delete request;
104         request = 0;
105 }
106
107 void Client::connect_finished(const exception *err)
108 {
109         if(err)
110         {
111                 signal_socket_error.emit(*err);
112
113                 delete request;
114                 request = 0;
115         }
116         else
117                 sock->write(request->str());
118 }
119
120 void Client::data_available()
121 {
122         char rbuf[4096];
123         unsigned len;
124         try
125         {
126                 len = sock->read(rbuf, sizeof(rbuf));
127         }
128         catch(const exception &e)
129         {
130                 signal_socket_error.emit(e);
131                 return;
132         }
133
134         if(!len)
135                 return;
136         in_buf.append(rbuf, len);
137
138         if(!response)
139         {
140                 if(in_buf.find("\r\n\r\n")!=string::npos || in_buf.find("\n\n")!=string::npos)
141                 {
142                         response = new Response(Response::parse(in_buf));
143                         response->set_user_data(request->get_user_data());
144                         in_buf = string();
145                 }
146         }
147         else
148         {
149                 len = response->parse_content(in_buf);
150                 in_buf.erase(0, len);
151         }
152
153         if(response && response->is_complete())
154         {
155                 signal_response_complete.emit(*response);
156
157                 delete request;
158                 request = 0;
159         }
160 }
161
162 } // namespace Http
163 } // namespace Msp