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