00001
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #ifdef _MSC_VER
00033 #pragma warning(disable:4786)
00034 #endif
00035 #include "HTTPSocket.h"
00036 #include "Parse.h"
00037 #include "ISocketHandler.h"
00038 #include <stdarg.h>
00039 #include <stdio.h>
00040
00041 #ifdef SOCKETS_NAMESPACE
00042 namespace SOCKETS_NAMESPACE {
00043 #endif
00044
00045
00046 HTTPSocket::HTTPSocket(ISocketHandler& h)
00047 :TcpSocket(h)
00048 ,m_first(true)
00049 ,m_header(true)
00050 ,m_http_version("HTTP/1.0")
00051 ,m_request(false)
00052 ,m_response(false)
00053 ,m_body_size_left(0)
00054 ,m_b_http_1_1(false)
00055 ,m_b_keepalive(false)
00056 ,m_b_chunked(false)
00057 ,m_chunk_size(0)
00058 ,m_chunk_state(0)
00059 ,m_header_count(0)
00060 ,m_max_header_count(MAX_HTTP_HEADER_COUNT)
00061 {
00062 SetLineProtocol();
00063 DisableInputBuffer();
00064 }
00065
00066
00067 HTTPSocket::~HTTPSocket()
00068 {
00069 }
00070
00071
00072 void HTTPSocket::OnRawData(const char *buf,size_t len)
00073 {
00074 if (!m_header)
00075 {
00076 if (m_b_chunked)
00077 {
00078 size_t ptr = 0;
00079 while (ptr < len)
00080 {
00081 switch (m_chunk_state)
00082 {
00083 case 4:
00084 while (ptr < len && (m_chunk_line.size() < 2 || m_chunk_line.substr(m_chunk_line.size() - 2) != "\r\n"))
00085 m_chunk_line += buf[ptr++];
00086 if (m_chunk_line.size() > 1 && m_chunk_line.substr(m_chunk_line.size() - 2) == "\r\n")
00087 {
00088 OnDataComplete();
00089
00090 m_b_chunked = false;
00091 SetLineProtocol( true );
00092 m_first = true;
00093 m_header = true;
00094 m_body_size_left = 0;
00095 if (len - ptr > 0)
00096 {
00097 char tmp[TCP_BUFSIZE_READ];
00098 memcpy(tmp, buf + ptr, len - ptr);
00099 tmp[len - ptr] = 0;
00100 OnRead( tmp, len - ptr );
00101 ptr = len;
00102 }
00103 }
00104 break;
00105 case 0:
00106 while (ptr < len && (m_chunk_line.size() < 2 || m_chunk_line.substr(m_chunk_line.size() - 2) != "\r\n"))
00107 m_chunk_line += buf[ptr++];
00108 if (m_chunk_line.size() > 1 && m_chunk_line.substr(m_chunk_line.size() - 2) == "\r\n")
00109 {
00110 m_chunk_line.resize(m_chunk_line.size() - 2);
00111 Parse pa(m_chunk_line, ";");
00112 std::string size_str = pa.getword();
00113 m_chunk_size = Utility::hex2unsigned(size_str);
00114 if (!m_chunk_size)
00115 {
00116 m_chunk_state = 4;
00117 m_chunk_line = "";
00118 }
00119 else
00120 {
00121 m_chunk_state = 1;
00122 m_chunk_line = "";
00123 }
00124 }
00125 break;
00126 case 1:
00127 {
00128 size_t left = len - ptr;
00129 size_t sz = m_chunk_size < left ? m_chunk_size : left;
00130 OnData(buf + ptr, sz);
00131 m_chunk_size -= sz;
00132 ptr += sz;
00133 if (!m_chunk_size)
00134 {
00135 m_chunk_state = 2;
00136 }
00137 }
00138 break;
00139 case 2:
00140 ptr++;
00141 m_chunk_state = 3;
00142 break;
00143 case 3:
00144 ptr++;
00145 m_chunk_state = 0;
00146 break;
00147 }
00148 }
00149 }
00150 else
00151 if (!m_b_http_1_1 || !m_b_keepalive)
00152 {
00153 OnData(buf, len);
00154
00155
00156
00157
00158
00159
00160
00161 m_body_size_left -= len;
00162 if (!m_body_size_left)
00163 {
00164 OnDataComplete();
00165 }
00166 }
00167 else
00168 {
00169 size_t sz = m_body_size_left < len ? m_body_size_left : len;
00170 OnData(buf, sz);
00171 m_body_size_left -= sz;
00172 if (!m_body_size_left)
00173 {
00174 OnDataComplete();
00175
00176 SetLineProtocol( true );
00177 m_first = true;
00178 m_header = true;
00179 m_body_size_left = 0;
00180 if (len - sz > 0)
00181 {
00182 char tmp[TCP_BUFSIZE_READ];
00183 memcpy(tmp, buf + sz, len - sz);
00184 tmp[len - sz] = 0;
00185 OnRead( tmp, len - sz );
00186 }
00187 }
00188 }
00189 }
00190 }
00191
00192
00193 void HTTPSocket::OnLine(const std::string& line)
00194 {
00195 if (m_first)
00196 {
00197 Parse pa(line);
00198 std::string str = pa.getword();
00199 if (str.size() > 4 && Utility::ToLower(str.substr(0,5)) == "http/")
00200 {
00201 m_http_version = str;
00202 m_status = pa.getword();
00203 m_status_text = pa.getrest();
00204 m_response = true;
00205 }
00206 else
00207 {
00208 m_method = str;
00209 m_url = pa.getword();
00210 size_t spl = m_url.find("?");
00211 if (spl != std::string::npos)
00212 {
00213 m_uri = m_url.substr(0,spl);
00214 m_query_string = m_url.substr(spl + 1);
00215 }
00216 else
00217 {
00218 m_uri = m_url;
00219 m_query_string = "";
00220 }
00221 m_http_version = pa.getword();
00222 m_b_http_1_1 = m_http_version.size() > 4 && m_http_version.substr(4) == "/1.1";
00223 m_b_keepalive = m_b_http_1_1;
00224 m_request = true;
00225 }
00226 m_first = false;
00227 OnFirst();
00228 return;
00229 }
00230 if (!line.size())
00231 {
00232 if (m_body_size_left || !m_b_http_1_1 || !m_b_keepalive || m_b_chunked)
00233 {
00234 SetLineProtocol(false);
00235 m_header = false;
00236 }
00237 OnHeaderComplete();
00238 if (!m_body_size_left && !m_b_chunked)
00239 {
00240 OnDataComplete();
00241 }
00242 return;
00243 }
00244 Parse pa(line,":");
00245 std::string key = pa.getword();
00246 std::string value = pa.getrest();
00247 OnHeader(key,value);
00248 if (Utility::ToLower(key) == "content-length")
00249 {
00250 m_body_size_left = atol(value.c_str());
00251 }
00252 if (m_b_http_1_1 && Utility::ToLower(key) == "connection")
00253 {
00254 m_b_keepalive = Utility::ToLower(value) != "close";
00255 }
00256 if (Utility::ToLower(key) == "transfer-encoding" && Utility::ToLower(value) == "chunked")
00257 {
00258 m_b_chunked = true;
00259 }
00260
00261
00262
00263 #ifdef ENABLE_POOL
00264 if (m_b_http_1_1 && m_b_keepalive)
00265 {
00266 SetRetain();
00267 }
00268 #endif
00269 if (m_header_count++ > m_max_header_count)
00270 {
00271 SetCloseAndDelete();
00272 Handler().LogError(this, "OnLine", m_header_count, "http header count exceeds builtin limit of (" + Utility::l2string(m_max_header_count) + ")", LOG_LEVEL_FATAL);
00273 }
00274 }
00275
00276
00277 void HTTPSocket::SendResponse()
00278 {
00279 std::string msg;
00280 msg = m_http_version + " " + m_status + " " + m_status_text + "\r\n";
00281 for (string_m::iterator it = m_response_header.begin(); it != m_response_header.end(); ++it)
00282 {
00283 std::string key = (*it).first;
00284 std::string val = (*it).second;
00285 msg += key + ": " + val + "\r\n";
00286 }
00287 for (std::list<std::pair<std::string, std::string> >::iterator it2 = m_response_header_append.begin(); it2 != m_response_header_append.end(); ++it2)
00288 {
00289 msg += it2 -> first + ": " + it2 -> second + "\r\n";
00290 }
00291 msg += "\r\n";
00292 Send( msg );
00293 }
00294
00295
00296 void HTTPSocket::AddResponseHeader(const std::string& header, const char *format, ...)
00297 {
00298 char slask[8192];
00299 va_list ap;
00300
00301 va_start(ap, format);
00302 vsnprintf(slask, sizeof(slask), format, ap);
00303 va_end(ap);
00304
00305 m_response_header[header] = slask;
00306 }
00307
00308
00309 void HTTPSocket::SendRequest()
00310 {
00311 std::string msg;
00312 msg = m_method + " " + m_url + " " + m_http_version + "\r\n";
00313 for (string_m::iterator it = m_response_header.begin(); it != m_response_header.end(); ++it)
00314 {
00315 std::string key = (*it).first;
00316 std::string val = (*it).second;
00317 msg += key + ": " + val + "\r\n";
00318 }
00319 msg += "\r\n";
00320 Send( msg );
00321 }
00322
00323
00324 std::string HTTPSocket::MyUseragent()
00325 {
00326 std::string version = "C++Sockets/";
00327 #ifdef _VERSION
00328 version += _VERSION;
00329 #endif
00330 return version;
00331 }
00332
00333
00334 void HTTPSocket::Reset()
00335 {
00336 m_first = true;
00337 m_header = true;
00338 m_request = false;
00339 m_response = false;
00340 SetLineProtocol(true);
00341 while (m_response_header.size())
00342 {
00343 string_m::iterator it = m_response_header.begin();
00344 m_response_header.erase(it);
00345 }
00346 while (m_response_header_append.size())
00347 {
00348 std::list<std::pair<std::string, std::string> >::iterator it = m_response_header_append.begin();
00349 m_response_header_append.erase(it);
00350 }
00351 m_header_count = 0;
00352
00353 }
00354
00355
00356 const std::string& HTTPSocket::GetMethod() const
00357 {
00358 return m_method;
00359 }
00360
00361
00362 void HTTPSocket::SetMethod(const std::string& x)
00363 {
00364 m_method = x;
00365 }
00366
00367
00368 const std::string& HTTPSocket::GetUrl() const
00369 {
00370 return m_url;
00371 }
00372
00373
00374 void HTTPSocket::SetUrl(const std::string& x)
00375 {
00376 m_url = x;
00377 }
00378
00379
00380 const std::string& HTTPSocket::GetUri() const
00381 {
00382 return m_uri;
00383 }
00384
00385
00386 const std::string& HTTPSocket::GetQueryString() const
00387 {
00388 return m_query_string;
00389 }
00390
00391
00392 const std::string& HTTPSocket::GetHttpVersion() const
00393 {
00394 return m_http_version;
00395 }
00396
00397
00398 const std::string& HTTPSocket::GetStatus() const
00399 {
00400 return m_status;
00401 }
00402
00403
00404 const std::string& HTTPSocket::GetStatusText() const
00405 {
00406 return m_status_text;
00407 }
00408
00409
00410 bool HTTPSocket::IsRequest() const
00411 {
00412 return m_request;
00413 }
00414
00415
00416 bool HTTPSocket::IsResponse() const
00417 {
00418 return m_response;
00419 }
00420
00421
00422 void HTTPSocket::SetHttpVersion(const std::string& x)
00423 {
00424 m_http_version = x;
00425 }
00426
00427
00428 void HTTPSocket::SetStatus(const std::string& x)
00429 {
00430 m_status = x;
00431 }
00432
00433
00434 void HTTPSocket::SetStatusText(const std::string& x)
00435 {
00436 m_status_text = x;
00437 }
00438
00439
00440 void HTTPSocket::AddResponseHeader(const std::string& x,const std::string& y)
00441 {
00442 m_response_header[x] = y;
00443 }
00444
00445
00446 void HTTPSocket::AppendResponseHeader(const std::string& x,const std::string& y)
00447 {
00448 m_response_header_append.push_back(std::pair<std::string, std::string>(x,y));
00449 }
00450
00451
00452 void HTTPSocket::SetUri(const std::string& x)
00453 {
00454 m_uri = x;
00455 }
00456
00457
00458 void HTTPSocket::url_this(const std::string& url_in,std::string& protocol,std::string& host,port_t& port,std::string& url,std::string& file)
00459 {
00460 Parse pa(url_in,"/");
00461 std::string user;
00462 std::string auth;
00463 protocol = pa.getword();
00464 if (!strcasecmp(protocol.c_str(), "https:"))
00465 {
00466 #ifdef HAVE_OPENSSL
00467 EnableSSL();
00468 #else
00469 Handler().LogError(this, "url_this", -1, "SSL not available", LOG_LEVEL_WARNING);
00470 #endif
00471 port = 443;
00472 }
00473 else
00474 {
00475 port = 80;
00476 }
00477 host = pa.getword();
00478 size_t pos = host.find("@");
00479 if (pos != std::string::npos)
00480 {
00481 user = host.substr(0, pos);
00482 host = host.substr(pos + 1);
00483 if (user.find(":") != std::string::npos)
00484 {
00485 AddResponseHeader("Authorization", "Basic " + Utility::base64(user));
00486 }
00487 }
00488 if (strstr(host.c_str(),":"))
00489 {
00490 Parse pa(host,":");
00491 pa.getword(host);
00492 port = static_cast<port_t>(pa.getvalue());
00493 }
00494 url = "/" + pa.getrest();
00495 {
00496 Parse pa(url,"/");
00497 std::string tmp = pa.getword();
00498 while (tmp.size())
00499 {
00500 file = tmp;
00501 tmp = pa.getword();
00502 }
00503 }
00504 }
00505
00506
00507 bool HTTPSocket::ResponseHeaderIsSet(const std::string& name) const
00508 {
00509 string_m::const_iterator it = m_response_header.find( name );
00510 if (it != m_response_header.end())
00511 {
00512 return true;
00513 }
00514 std::list<std::pair<std::string, std::string> >::const_iterator it2;
00515 for (it2 = m_response_header_append.begin(); it2 != m_response_header_append.end(); ++it2)
00516 {
00517 const std::pair<std::string, std::string>& ref = *it2;
00518 if (!strcasecmp(ref.first.c_str(), name.c_str()) )
00519 {
00520 return true;
00521 }
00522 }
00523 return false;
00524 }
00525
00526
00527 #ifdef SOCKETS_NAMESPACE
00528 }
00529 #endif
00530
00531