1 /**
2 ** \file HttpClientSocket.cpp
3 ** \date 2006-04-20
4 ** \author grymse@alhem.net
5 **/
6 /*
7 Copyright (C) 2007-2011 Anders Hedstrom
8
9 This library is made available under the terms of the GNU GPL, with
10 the additional exemption that compiling, linking, and/or using OpenSSL
11 is allowed.
12
13 If you would like to use this library in a closed-source application,
14 a separate license agreement is available. For information about
15 the closed-source license agreement for the C++ sockets library,
16 please visit http://www.alhem.net/Sockets/license.html and/or
17 email license@alhem.net.
18
19 This program is free software; you can redistribute it and/or
20 modify it under the terms of the GNU General Public License
21 as published by the Free Software Foundation; either version 2
22 of the License, or (at your option) any later version.
23
24 This program is distributed in the hope that it will be useful,
25 but WITHOUT ANY WARRANTY; without even the implied warranty of
26 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 GNU General Public License for more details.
28
29 You should have received a copy of the GNU General Public License
30 along with this program; if not, write to the Free Software
31 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
32 */
33 #ifdef _MSC_VER
34 #pragma warning(disable:4786)
35 #endif
36 #include "HttpClientSocket.h"
37 #include "StdLog.h"
38 #include "ISocketHandler.h"
39 #include "File.h"
40
41
42 #ifdef SOCKETS_NAMESPACE
43 namespace SOCKETS_NAMESPACE {
44 #endif
45
46
HttpClientSocket(ISocketHandler & h)47 HttpClientSocket::HttpClientSocket(ISocketHandler& h)
48 :HTTPSocket(h)
49 ,m_data_ptr(NULL)
50 ,m_data_size(0)
51 ,m_content_length(0)
52 ,m_content_length_is_set(false)
53 ,m_data_ptr_set(false)
54 ,m_fil(NULL)
55 ,m_content_ptr(0)
56 ,m_b_complete(false)
57 ,m_b_close_when_complete(false)
58 {
59 }
60
61
HttpClientSocket(ISocketHandler & h,const std::string & url_in)62 HttpClientSocket::HttpClientSocket(ISocketHandler& h,const std::string& url_in)
63 :HTTPSocket(h)
64 ,m_data_ptr(NULL)
65 ,m_data_size(0)
66 ,m_content_length(0)
67 ,m_content_length_is_set(false)
68 ,m_data_ptr_set(false)
69 ,m_fil(NULL)
70 ,m_content_ptr(0)
71 ,m_b_complete(false)
72 ,m_b_close_when_complete(false)
73 {
74 std::string url;
75 url_this(url_in, m_protocol, m_host, m_port, url, m_url_filename);
76 SetUrl( url );
77 }
78
79
HttpClientSocket(ISocketHandler & h,const std::string & host,port_t port,const std::string & url_in)80 HttpClientSocket::HttpClientSocket(ISocketHandler& h,const std::string& host, port_t port, const std::string& url_in)
81 :HTTPSocket(h)
82 ,m_data_ptr(NULL)
83 ,m_data_size(0)
84 ,m_content_length(0)
85 ,m_content_length_is_set(false)
86 ,m_data_ptr_set(false)
87 ,m_fil(NULL)
88 ,m_content_ptr(0)
89 ,m_b_complete(false)
90 ,m_b_close_when_complete(false)
91 {
92 std::string url;
93 std::string tmp = "http://" + host + ":" + Utility::l2string(port) + url_in;
94 url_this(tmp, m_protocol, m_host, m_port, url, m_url_filename);
95 SetUrl( url );
96 }
97
98
~HttpClientSocket()99 HttpClientSocket::~HttpClientSocket()
100 {
101 if (m_data_ptr && !m_data_ptr_set)
102 {
103 delete[] m_data_ptr;
104 }
105 if (m_fil)
106 {
107 m_fil -> fclose();
108 }
109 }
110
111
OnFirst()112 void HttpClientSocket::OnFirst()
113 {
114 if (!IsResponse())
115 {
116 Handler().LogError(this, "OnFirst", 0, "Response expected but not received - aborting", LOG_LEVEL_FATAL);
117 SetCloseAndDelete();
118 }
119 m_content = GetHttpVersion() + " " + GetStatus() + " " + GetStatusText() + "\r\n";
120 }
121
122
OnHeader(const std::string & key,const std::string & value)123 void HttpClientSocket::OnHeader(const std::string& key,const std::string& value)
124 {
125 m_content += key + ": " + value + "\r\n";
126 if (!strcasecmp(key.c_str(), "content-length"))
127 {
128 m_content_length = atoi(value.c_str());
129 m_content_length_is_set = true;
130 }
131 else
132 if (!strcasecmp(key.c_str(), "content-type"))
133 {
134 m_content_type = value;
135 }
136 }
137
138
OnHeaderComplete()139 void HttpClientSocket::OnHeaderComplete()
140 {
141 if (m_filename.size())
142 {
143 m_fil = new File;
144 if (!m_fil -> fopen(m_filename, "wb"))
145 {
146 delete m_fil;
147 m_fil = NULL;
148 }
149 }
150 if (!m_data_ptr && m_content_length > 0)
151 {
152 m_data_ptr = new unsigned char[m_content_length];
153 m_data_size = m_content_length;
154 }
155 // make sure we finish in a good way even when response
156 // has content-length: 0
157 if (m_content_length_is_set && m_content_length == 0)
158 {
159 EndConnection();
160 }
161 }
162
163
EndConnection()164 void HttpClientSocket::EndConnection()
165 {
166 if (m_fil)
167 {
168 m_fil -> fclose();
169 delete m_fil;
170 m_fil = NULL;
171 }
172 m_b_complete = true;
173 OnContent();
174 if (m_b_close_when_complete)
175 {
176 SetCloseAndDelete();
177 }
178 }
179
180
OnData(const char * buf,size_t len)181 void HttpClientSocket::OnData(const char *buf,size_t len)
182 {
183 if (m_fil)
184 {
185 m_fil -> fwrite(buf, 1, len);
186 }
187 if (m_data_ptr)
188 {
189 size_t left = m_data_size - m_content_ptr;
190 size_t sz = len < left ? len : left;
191 if (sz > 0)
192 memcpy(m_data_ptr + m_content_ptr, buf, sz);
193 m_content_ptr += sz;
194 if (len > left)
195 {
196 Handler().LogError(this, "OnData", -1, "content buffer overflow", LOG_LEVEL_ERROR);
197 }
198 }
199 if (m_content_ptr == m_content_length && m_content_length)
200 {
201 EndConnection();
202 }
203 }
204
205
OnDelete()206 void HttpClientSocket::OnDelete()
207 {
208 if (!m_b_complete)
209 {
210 if (m_fil)
211 {
212 m_fil -> fclose();
213 delete m_fil;
214 m_fil = NULL;
215 }
216 m_b_complete = true;
217 OnContent();
218 }
219 }
220
221
SetFilename(const std::string & x)222 void HttpClientSocket::SetFilename(const std::string& x)
223 {
224 m_filename = x;
225 }
226
227
SetDataPtr(unsigned char * buf,size_t len)228 void HttpClientSocket::SetDataPtr(unsigned char *buf,size_t len)
229 {
230 m_data_ptr = buf;
231 m_data_size = len;
232 m_data_ptr_set = true;
233 }
234
235
GetContent()236 const std::string& HttpClientSocket::GetContent()
237 {
238 return m_content;
239 }
240
241
GetContentLength()242 size_t HttpClientSocket::GetContentLength()
243 {
244 return m_content_length;
245 }
246
247
GetContentPtr()248 size_t HttpClientSocket::GetContentPtr()
249 {
250 return m_content_ptr;
251 }
252
253
GetPos()254 size_t HttpClientSocket::GetPos()
255 {
256 return m_content_ptr;
257 }
258
259
Complete()260 bool HttpClientSocket::Complete()
261 {
262 return m_b_complete;
263 }
264
265
GetDataPtr() const266 const unsigned char *HttpClientSocket::GetDataPtr() const
267 {
268 return m_data_ptr;
269 }
270
271
OnContent()272 void HttpClientSocket::OnContent()
273 {
274 }
275
276
SetCloseOnComplete(bool x)277 void HttpClientSocket::SetCloseOnComplete(bool x)
278 {
279 m_b_close_when_complete = x;
280 }
281
282
GetUrlProtocol()283 const std::string& HttpClientSocket::GetUrlProtocol()
284 {
285 return m_protocol;
286 }
287
288
GetUrlHost()289 const std::string& HttpClientSocket::GetUrlHost()
290 {
291 return m_host;
292 }
293
294
GetUrlPort()295 port_t HttpClientSocket::GetUrlPort()
296 {
297 return m_port;
298 }
299
300
GetUrlFilename()301 const std::string& HttpClientSocket::GetUrlFilename()
302 {
303 return m_url_filename;
304 }
305
306
GetContentType()307 const std::string& HttpClientSocket::GetContentType()
308 {
309 return m_content_type;
310 }
311
312
Url(const std::string & url_in,std::string & host,port_t & port)313 void HttpClientSocket::Url(const std::string& url_in,std::string& host,port_t& port)
314 {
315 std::string url;
316 url_this(url_in, m_protocol, m_host, m_port, url, m_url_filename);
317 SetUrl(url);
318 host = GetUrlHost();
319 port = GetUrlPort();
320 }
321
322
323 #ifdef SOCKETS_NAMESPACE
324 } // namespace SOCKETS_NAMESPACE {
325 #endif
326
327