]> git.tdb.fi Git - libs/net.git/blob - source/http/client.cpp
e09057684957cac17acdeb17adeaf272efdc1952
[libs/net.git] / source / http / client.cpp
1 #include <msp/core/refptr.h>
2 #include <msp/net/resolve.h>
3 #include <msp/time/timedelta.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         resolver(0),
17         resolve_listener(0),
18         resolve_tag(0),
19         user_agent("libmsphttp/0.1"),
20         request(0),
21         response(0)
22 { }
23
24 Client::~Client()
25 {
26         delete sock;
27         delete request;
28         delete response;
29 }
30
31 void Client::use_event_dispatcher(IO::EventDispatcher *ed)
32 {
33         if(event_disp && sock)
34                 event_disp->remove(*sock);
35         event_disp = ed;
36         if(event_disp && sock)
37                 event_disp->add(*sock);
38 }
39
40 void Client::use_resolver(Net::Resolver *r)
41 {
42         if(resolver)
43         {
44                 delete resolve_listener;
45                 resolve_listener = 0;
46         }
47
48         resolver = r;
49         if(resolver)
50                 resolve_listener = new ResolveListener(*this);
51 }
52
53 void Client::start_request(const Request &r)
54 {
55         if(request)
56                 throw client_busy();
57
58         delete sock;
59         sock = 0;
60
61         request = new Request(r);
62         if(!user_agent.empty())
63                 request->set_header("User-Agent", user_agent);
64
65         delete response;
66         response = 0;
67         in_buf.clear();
68
69         string host = r.get_header("Host");
70         if(host.find(':')==string::npos)
71                 host += ":80";
72         if(resolver)
73                 resolve_tag = resolver->resolve(host);
74         else
75         {
76                 RefPtr<Net::SockAddr> addr = Net::resolve(host);
77                 address_resolved(resolve_tag, *addr);
78         }
79 }
80
81 const Response *Client::get_url(const std::string &url)
82 {
83         start_request(Request::from_url(url));
84         wait_response();
85         return response;
86 }
87
88 void Client::tick()
89 {
90         if(!request)
91                 return;
92
93         while(IO::PollEvent ev = IO::poll(*sock, sock->get_events(), Time::zero))
94                 sock->event(ev);
95
96         if(response && response->is_complete())
97         {
98                 signal_response_complete.emit(*response);
99
100                 delete sock;
101                 sock = 0;
102                 delete request;
103                 request = 0;
104         }
105 }
106
107 void Client::wait_response()
108 {
109         while(request && (!response || !response->is_complete()))
110                 tick();
111 }
112
113 void Client::abort()
114 {
115         delete sock;
116         sock = 0;
117         delete request;
118         request = 0;
119 }
120
121 void Client::address_resolved(unsigned tag, const Net::SockAddr &addr)
122 {
123         if(tag!=resolve_tag)
124                 return;
125         resolve_tag = 0;
126
127         sock = new Net::StreamSocket(addr.get_family());
128         sock->set_block(false);
129
130         sock->signal_data_available.connect(sigc::mem_fun(this, &Client::data_available));
131         sock->signal_connect_finished.connect(sigc::mem_fun(this, &Client::connect_finished));
132         if(event_disp)
133                 event_disp->add(*sock);
134
135         sock->connect(addr);
136 }
137
138 void Client::resolve_failed(unsigned tag, const exception &err)
139 {
140         if(tag!=resolve_tag)
141                 return;
142         resolve_tag = 0;
143
144         delete request;
145         request = 0;
146
147         if(signal_socket_error.empty())
148                 throw err;
149         signal_socket_error.emit(err);
150 }
151
152 void Client::connect_finished(const exception *err)
153 {
154         if(err)
155         {
156                 delete request;
157                 request = 0;
158
159                 if(signal_socket_error.empty())
160                         throw *err;
161                 signal_socket_error.emit(*err);
162         }
163         else
164         {
165                 try
166                 {
167                         sock->write(request->str());
168                 }
169                 catch(const exception &e)
170                 {
171                         if(signal_socket_error.empty())
172                                 throw;
173                         signal_socket_error.emit(e);
174                         return;
175                 }
176         }
177 }
178
179 void Client::data_available()
180 {
181         char rbuf[4096];
182         unsigned len;
183         try
184         {
185                 len = sock->read(rbuf, sizeof(rbuf));
186         }
187         catch(const exception &e)
188         {
189                 if(signal_socket_error.empty())
190                         throw;
191                 signal_socket_error.emit(e);
192                 return;
193         }
194
195         if(!len)
196                 return;
197         in_buf.append(rbuf, len);
198
199         if(!response)
200         {
201                 if(in_buf.find("\r\n\r\n")!=string::npos || in_buf.find("\n\n")!=string::npos)
202                 {
203                         response = new Response(Response::parse(in_buf));
204                         response->set_user_data(request->get_user_data());
205                         in_buf = string();
206                 }
207         }
208         else
209         {
210                 len = response->parse_content(in_buf);
211                 in_buf.erase(0, len);
212         }
213
214         if(response && response->is_complete())
215         {
216                 signal_response_complete.emit(*response);
217
218                 delete request;
219                 request = 0;
220         }
221 }
222
223
224 Client::ResolveListener::ResolveListener(Client &c):
225         client(c)
226 {
227         client.resolver->signal_address_resolved.connect(sigc::mem_fun(this, &ResolveListener::address_resolved));
228         client.resolver->signal_resolve_failed.connect(sigc::mem_fun(this, &ResolveListener::resolve_failed));
229 }
230
231 void Client::ResolveListener::address_resolved(unsigned tag, const Net::SockAddr &addr)
232 {
233         client.address_resolved(tag, addr);
234 }
235
236 void Client::ResolveListener::resolve_failed(unsigned tag, const exception &err)
237 {
238         client.resolve_failed(tag, err);
239 }
240
241 } // namespace Http
242 } // namespace Msp