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