added generic tool code
[anytun.git] / Sockets / HTTPSocket.cpp
blobca498221a8d212c2289461a69a76d8c476908a68
1 /** \file HTTPSocket.cpp
2 ** \date 2004-04-06
3 ** \author grymse@alhem.net
4 **/
5 /*
6 Copyright (C) 2004-2007 Anders Hedstrom
8 This library is made available under the terms of the GNU GPL.
10 If you would like to use this library in a closed-source application,
11 a separate license agreement is available. For information about
12 the closed-source license agreement for the C++ sockets library,
13 please visit http://www.alhem.net/Sockets/license.html and/or
14 email license@alhem.net.
16 This program is free software; you can redistribute it and/or
17 modify it under the terms of the GNU General Public License
18 as published by the Free Software Foundation; either version 2
19 of the License, or (at your option) any later version.
21 This program is distributed in the hope that it will be useful,
22 but WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 GNU General Public License for more details.
26 You should have received a copy of the GNU General Public License
27 along with this program; if not, write to the Free Software
28 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
30 #ifdef _MSC_VER
31 #pragma warning(disable:4786)
32 #endif
33 #include "HTTPSocket.h"
34 #include "Parse.h"
35 #include "ISocketHandler.h"
36 #include "Utility.h"
37 #include <stdarg.h>
39 #ifdef SOCKETS_NAMESPACE
40 namespace SOCKETS_NAMESPACE {
41 #endif
44 HTTPSocket::HTTPSocket(ISocketHandler& h)
45 :TcpSocket(h)
46 ,m_first(true)
47 ,m_header(true)
48 ,m_http_version("HTTP/1.0")
49 ,m_request(false)
50 ,m_response(false)
51 ,m_body_size_left(0)
52 ,m_b_http_1_1(false)
53 ,m_b_keepalive(false)
55 SetLineProtocol();
56 DisableInputBuffer();
60 HTTPSocket::~HTTPSocket()
65 void HTTPSocket::OnRawData(const char *buf,size_t len)
67 if (!m_header)
69 if (!m_b_http_1_1 || !m_b_keepalive)
71 OnData(buf, len);
73 else
75 size_t sz = m_body_size_left < len ? m_body_size_left : len;
76 OnData(buf, sz);
77 m_body_size_left -= sz;
78 if (!m_body_size_left)
80 SetLineProtocol( true );
81 m_first = true;
82 m_header = true;
83 m_body_size_left = 0;
84 if (len - sz > 0)
86 char tmp[TCP_BUFSIZE_READ];
87 memcpy(tmp, buf + sz, len - sz);
88 tmp[len - sz] = 0;
89 OnRead( tmp, len - sz );
97 void HTTPSocket::OnLine(const std::string& line)
99 if (m_first)
101 Parse pa(line);
102 std::string str = pa.getword();
103 if (str.size() > 4 && Utility::ToLower(str.substr(0,5)) == "http/") // response
105 m_http_version = str;
106 m_status = pa.getword();
107 m_status_text = pa.getrest();
108 m_response = true;
110 else // request
112 m_method = str;
113 m_url = pa.getword();
114 size_t spl = m_url.find("?");
115 if (spl != std::string::npos)
117 m_uri = m_url.substr(0,spl);
118 m_query_string = m_url.substr(spl + 1);
120 else
122 m_uri = m_url;
123 m_query_string = "";
125 m_http_version = pa.getword();
126 m_b_http_1_1 = m_http_version.size() > 4 && m_http_version.substr(4) == "/1.1";
127 m_b_keepalive = m_b_http_1_1;
128 m_request = true;
130 m_first = false;
131 OnFirst();
132 return;
134 if (!line.size())
136 if (m_body_size_left || !m_b_http_1_1 || !m_b_keepalive)
138 SetLineProtocol(false);
139 m_header = false;
141 OnHeaderComplete();
142 return;
144 Parse pa(line,":");
145 std::string key = pa.getword();
146 std::string value = pa.getrest();
147 OnHeader(key,value);
148 if (Utility::ToLower(key) == "content-length")
150 m_body_size_left = atol(value.c_str());
152 if (m_b_http_1_1 && Utility::ToLower(key) == "connection")
154 m_b_keepalive = Utility::ToLower(value) != "close";
156 /* If remote end tells us to keep connection alive, and we're operating
157 in http/1.1 mode (not http/1.0 mode), then we mark the socket to be
158 retained. */
159 #ifdef ENABLE_POOL
160 if (m_b_http_1_1 && m_b_keepalive)
162 SetRetain();
164 #endif
168 void HTTPSocket::SendResponse()
170 std::string msg;
171 msg = m_http_version + " " + m_status + " " + m_status_text + "\r\n";
172 for (string_m::iterator it = m_response_header.begin(); it != m_response_header.end(); it++)
174 std::string key = (*it).first;
175 std::string val = (*it).second;
176 msg += key + ": " + val + "\r\n";
178 for (std::list<std::pair<std::string, std::string> >::iterator it2 = m_response_header_append.begin(); it2 != m_response_header_append.end(); ++it2)
180 msg += it2 -> first + ": " + it2 -> second + "\r\n";
182 msg += "\r\n";
183 Send( msg );
187 void HTTPSocket::AddResponseHeader(const std::string& header, const char *format, ...)
189 char slask[5000]; // temporary for vsprintf / vsnprintf
190 va_list ap;
192 va_start(ap, format);
193 #ifdef _WIN32
194 vsprintf(slask, format, ap);
195 #else
196 vsnprintf(slask, 5000, format, ap);
197 #endif
198 va_end(ap);
200 m_response_header[header] = slask;
204 void HTTPSocket::SendRequest()
206 std::string msg;
207 msg = m_method + " " + m_url + " " + m_http_version + "\r\n";
208 for (string_m::iterator it = m_response_header.begin(); it != m_response_header.end(); it++)
210 std::string key = (*it).first;
211 std::string val = (*it).second;
212 msg += key + ": " + val + "\r\n";
214 msg += "\r\n";
215 Send( msg );
219 std::string HTTPSocket::MyUseragent()
221 std::string version = "C++Sockets/";
222 #ifdef _VERSION
223 version += _VERSION;
224 #endif
225 return version;
229 void HTTPSocket::Reset()
231 m_first = true;
232 m_header = true;
233 m_request = false;
234 m_response = false;
235 SetLineProtocol(true);
236 while (m_response_header.size())
238 string_m::iterator it = m_response_header.begin();
239 m_response_header.erase(it);
241 while (m_response_header_append.size())
243 std::list<std::pair<std::string, std::string> >::iterator it = m_response_header_append.begin();
244 m_response_header_append.erase(it);
250 const std::string& HTTPSocket::GetMethod()
252 return m_method;
256 void HTTPSocket::SetMethod(const std::string& x)
258 m_method = x;
262 const std::string& HTTPSocket::GetUrl()
264 return m_url;
268 void HTTPSocket::SetUrl(const std::string& x)
270 m_url = x;
274 const std::string& HTTPSocket::GetUri()
276 return m_uri;
280 const std::string& HTTPSocket::GetQueryString()
282 return m_query_string;
286 const std::string& HTTPSocket::GetHttpVersion()
288 return m_http_version;
292 const std::string& HTTPSocket::GetStatus()
294 return m_status;
298 const std::string& HTTPSocket::GetStatusText()
300 return m_status_text;
304 bool HTTPSocket::IsRequest()
306 return m_request;
310 bool HTTPSocket::IsResponse()
312 return m_response;
316 void HTTPSocket::SetHttpVersion(const std::string& x)
318 m_http_version = x;
322 void HTTPSocket::SetStatus(const std::string& x)
324 m_status = x;
328 void HTTPSocket::SetStatusText(const std::string& x)
330 m_status_text = x;
334 void HTTPSocket::AddResponseHeader(const std::string& x,const std::string& y)
336 m_response_header[Utility::ToLower(x)] = y;
340 void HTTPSocket::AppendResponseHeader(const std::string& x,const std::string& y)
342 m_response_header_append.push_back(std::pair<std::string, std::string>(Utility::ToLower(x),y));
346 void HTTPSocket::SetUri(const std::string& x)
348 m_uri = x;
352 void HTTPSocket::url_this(const std::string& url_in,std::string& protocol,std::string& host,port_t& port,std::string& url,std::string& file)
354 Parse pa(url_in,"/");
355 protocol = pa.getword(); // http
356 if (!strcasecmp(protocol.c_str(), "https:"))
358 #ifdef HAVE_OPENSSL
359 EnableSSL();
360 #else
361 Handler().LogError(this, "url_this", -1, "SSL not available", LOG_LEVEL_WARNING);
362 #endif
363 port = 443;
365 else
367 port = 80;
369 host = pa.getword();
370 if (strstr(host.c_str(),":"))
372 Parse pa(host,":");
373 pa.getword(host);
374 port = static_cast<port_t>(pa.getvalue());
376 url = "/" + pa.getrest();
378 Parse pa(url,"/");
379 std::string tmp = pa.getword();
380 while (tmp.size())
382 file = tmp;
383 tmp = pa.getword();
386 } // url_this
389 bool HTTPSocket::ResponseHeaderIsSet(const std::string& name)
391 string_m::iterator it = m_response_header.find( Utility::ToLower(name) );
392 if (it != m_response_header.end())
394 return true;
396 std::list<std::pair<std::string, std::string> >::iterator it2;
397 for (it2 = m_response_header_append.begin(); it2 != m_response_header_append.end(); it2++)
399 std::pair<std::string, std::string>& ref = *it2;
400 if (ref.first == Utility::ToLower(name) )
402 return true;
405 return false;
409 #ifdef SOCKETS_NAMESPACE
411 #endif