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