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