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