1 /** \file HTTPSocket.cpp
3 ** \author grymse@alhem.net
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.
31 #pragma warning(disable:4786)
33 #include "HTTPSocket.h"
35 #include "ISocketHandler.h"
39 #ifdef SOCKETS_NAMESPACE
40 namespace SOCKETS_NAMESPACE
{
44 HTTPSocket::HTTPSocket(ISocketHandler
& h
)
48 ,m_http_version("HTTP/1.0")
60 HTTPSocket::~HTTPSocket()
65 void HTTPSocket::OnRawData(const char *buf
,size_t len
)
69 if (!m_b_http_1_1
|| !m_b_keepalive
)
75 size_t sz
= m_body_size_left
< len
? m_body_size_left
: len
;
77 m_body_size_left
-= sz
;
78 if (!m_body_size_left
)
80 SetLineProtocol( true );
86 char tmp
[TCP_BUFSIZE_READ
];
87 memcpy(tmp
, buf
+ sz
, len
- sz
);
89 OnRead( tmp
, len
- sz
);
97 void HTTPSocket::OnLine(const std::string
& 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();
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);
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
;
136 if (m_body_size_left
|| !m_b_http_1_1
|| !m_b_keepalive
)
138 SetLineProtocol(false);
145 std::string key
= pa
.getword();
146 std::string value
= pa
.getrest();
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
160 if (m_b_http_1_1
&& m_b_keepalive
)
168 void HTTPSocket::SendResponse()
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";
187 void HTTPSocket::AddResponseHeader(const std::string
& header
, const char *format
, ...)
189 char slask
[5000]; // temporary for vsprintf / vsnprintf
192 va_start(ap
, format
);
194 vsprintf(slask
, format
, ap
);
196 vsnprintf(slask
, 5000, format
, ap
);
200 m_response_header
[header
] = slask
;
204 void HTTPSocket::SendRequest()
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";
219 std::string
HTTPSocket::MyUseragent()
221 std::string version
= "C++Sockets/";
229 void HTTPSocket::Reset()
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()
256 void HTTPSocket::SetMethod(const std::string
& x
)
262 const std::string
& HTTPSocket::GetUrl()
268 void HTTPSocket::SetUrl(const std::string
& x
)
274 const std::string
& HTTPSocket::GetUri()
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()
298 const std::string
& HTTPSocket::GetStatusText()
300 return m_status_text
;
304 bool HTTPSocket::IsRequest()
310 bool HTTPSocket::IsResponse()
316 void HTTPSocket::SetHttpVersion(const std::string
& x
)
322 void HTTPSocket::SetStatus(const std::string
& x
)
328 void HTTPSocket::SetStatusText(const std::string
& 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
)
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:"))
361 Handler().LogError(this, "url_this", -1, "SSL not available", LOG_LEVEL_WARNING
);
370 if (strstr(host
.c_str(),":"))
374 port
= static_cast<port_t
>(pa
.getvalue());
376 url
= "/" + pa
.getrest();
379 std::string tmp
= pa
.getword();
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())
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
) )
409 #ifdef SOCKETS_NAMESPACE