00001
00002
00003
00004
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 #include <sstream>
00030
00031 #include <stdio.h>
00032 #include <errno.h>
00033 #include <string.h>
00034
00035 #include <stdlib.h>
00036
00037 #ifndef WIN32
00038
00039
00040 #include <unistd.h>
00041 #include <arpa/inet.h>
00042 #include <sys/types.h>
00043 #include <sys/socket.h>
00044 #include <netdb.h>
00045 #define closesocket(s) close(s)
00046 #endif
00047
00048 #include "httprequest.h"
00049
00050
00051 #include <iostream>
00052
00053
00054 namespace HTTP {
00055
00056
00057 GetRequest::GetRequest()
00058 {
00059 m_useragent = "";
00060 }
00061
00062 GetRequest::~GetRequest() { }
00063
00064 void GetRequest::setUserAgent(const std::string& ua)
00065 {
00066 m_useragent = ua;
00067 }
00068
00069 std::string GetRequest::getUserAgent() const
00070 {
00071 return m_useragent;
00072 }
00073
00074 void GetRequest::addHeader(const std::string& key, const std::string& value)
00075 {
00076 m_additionalHeader[key] = value;
00077 }
00078
00079 void GetRequest::addHeader(const std::string& key, int value)
00080 {
00081
00082 std::string str;
00083 std::stringstream ss;
00084 ss << value;
00085 ss >> str;
00086
00087 addHeader(key, str);
00088 }
00089
00090 void GetRequest::clearHeaders()
00091 {
00092 m_additionalHeader.clear();
00093 }
00094
00095 void GetRequest::reset()
00096 {
00097 m_useragent = "";
00098 clearHeaders();
00099 }
00100
00101 bool GetRequest::connect(const std::string& host, int port)
00102 {
00103 m_success = true;
00104 m_host = host;
00105 unsigned long addr;
00106 struct hostent *host_info;
00107
00108 #ifdef WIN32
00109
00110 short wVersionRequested;
00111 WSADATA wsaData;
00112 wVersionRequested = MAKEWORD (1, 1);
00113 if (WSAStartup (wVersionRequested, &wsaData) != 0) {
00114 setError("HTTP request error: failed to init windows sockets\n");
00115 m_success = false;
00116 return false;
00117 }
00118 #endif
00119
00120
00121 sock = socket( PF_INET, SOCK_STREAM, 0);
00122 if (sock < 0) {
00123 setError("HTTP request error: failed to create socket.");
00124 m_success = false;
00125 return false;
00126 }
00127
00128
00129
00130 memset(&server, 0, sizeof (server));
00131 if ((addr = inet_addr(host.c_str())) != INADDR_NONE) {
00132
00133 memcpy((char *)&server.sin_addr, &addr, sizeof(addr));
00134 } else {
00135
00136 host_info = gethostbyname(host.c_str());
00137 if (host_info == 0L) {
00138 setError("HTTP request error: unknown server: " + host + "\n");
00139 m_success = false;
00140 return false;
00141 }
00142 memcpy((char *)&server.sin_addr, host_info->h_addr, host_info->h_length);
00143 }
00144
00145 server.sin_family = AF_INET;
00146 server.sin_port = htons(port);
00147
00148 return true;
00149 }
00150
00151 bool GetRequest::request(const std::string& page)
00152 {
00153 m_success = true;
00154 m_header = "";
00155 m_data = "";
00156 m_rawdata = "";
00157 m_rawdata.reserve( 1048576 );
00158
00159 setError("HTTP request: no error occured.");
00160
00161 char buffer[8192];
00162
00163 if ( ::connect(sock, (struct sockaddr*)&server, sizeof(server)) < 0 ) {
00164 setError("HTTP request error: cannot connect to server");
00165 m_success = false;
00166 return false;
00167 }
00168
00169
00170 std::string cmd = "GET /" + page + " HTTP/1.1\r\n"
00171 "Host: " + m_host;
00172
00173 if ( m_useragent.size() > 0 ) {
00174 cmd += "\r\nUser-Agent: " + m_useragent;
00175 }
00176
00177 std::map <std::string, std::string>::iterator it = m_additionalHeader.begin();
00178 while ( it != m_additionalHeader.end() ) {
00179 cmd += "\r\n" + it->first + ": " + it->second;
00180 it++;
00181 }
00182
00183
00184 cmd += "\n\n";
00185
00186 sprintf(buffer, cmd.c_str());
00187
00188 send(sock, buffer, strlen(buffer), 0);
00189
00190 return true;
00191 }
00192
00193 bool GetRequest::process( )
00194 {
00195 int count;
00196 char buffer[8192];
00197
00198
00199 count = recv(sock, buffer, sizeof(buffer), 0);
00200
00201
00202 m_rawdata.append(buffer, count);
00203
00204
00205 if (count == 0 || isTransferFinished())
00206 {
00207
00208 closesocket(sock);
00209
00210
00211 m_success = splitData();
00212
00213 return false;
00214 }
00215
00216 return true;
00217 }
00218
00219 bool GetRequest::success() const
00220 {
00221 return m_success;
00222 }
00223
00224
00225 std::string GetRequest::getHeader() const
00226 {
00227 return m_header;
00228 }
00229
00230 std::string GetRequest::getHeaderAsString(const std::string& key) const
00231 {
00232 if (m_header.size() > 0) {
00233 unsigned int pos = m_header.find("\r\n" + key + ": ", 0);
00234 if (pos == std::string::npos) return "";
00235
00236 pos += 4 + key.size();
00237
00238 unsigned int end = m_rawdata.find("\r\n", pos);
00239 if (end == std::string::npos) return "";
00240
00241 return m_header.substr(pos, end - pos);
00242 }
00243
00244 return "";
00245 }
00246
00247 int GetRequest::getHeaderAsInt(const std::string& key) const
00248 {
00249 std::string str = getHeaderAsString(key);
00250
00251 if (str.size() == 0) {
00252 return 0;
00253 } else {
00254 int value;
00255 std::stringstream ss;
00256 ss << str;
00257 ss >> value;
00258 return value;
00259 }
00260 }
00261
00262 std::string GetRequest::getData() const
00263 {
00264 return m_data;
00265 }
00266
00267 std::string GetRequest::getFooter() const
00268 {
00269 return m_footer;
00270 }
00271
00272 std::string GetRequest::getRaw() const
00273 {
00274 return m_rawdata;
00275 }
00276
00277 unsigned int GetRequest::getHeaderSize() const
00278 {
00279 return m_header.size();
00280 }
00281
00282 unsigned int GetRequest::getDataSize() const
00283 {
00284 return m_data.size();
00285 }
00286
00287 unsigned int GetRequest::getFooterSize() const
00288 {
00289 return m_footer.size();
00290 }
00291
00292 unsigned int GetRequest::getRawSize() const
00293 {
00294 return m_rawdata.size();
00295 }
00296
00297 std::string GetRequest::getError() const
00298 {
00299 return m_errorMessage;
00300 }
00301
00302
00303 void GetRequest::setError(std::string message)
00304 {
00305 m_errorMessage = message;
00306 }
00307
00308 bool GetRequest::isChunkedTransfer() const
00309 {
00310 return ( m_rawdata.find("\r\nContent-Length: ", 0) == std::string::npos );
00311 }
00312
00313 bool GetRequest::isTransferFinished() const
00314 {
00315 if ( !isChunkedTransfer() ) return false;
00316
00317
00318 unsigned int pos = m_rawdata.find("\r\n\r\n", 0);
00319 if (pos == std::string::npos) return false;
00320 pos += 4;
00321
00322 unsigned int size;
00323
00324
00325
00326
00327 while ( (size = findSize(pos, m_rawdata)) != std::string::npos ) {
00328 if ( size == 0 ) return true;
00329
00330
00331 pos = m_rawdata.find("\r\n", pos);
00332 if (pos == std::string::npos) return false;
00333 pos += 2;
00334 pos += size + 2;
00335 }
00336
00337 return false;
00338 }
00339
00340 unsigned int GetRequest::getContentLength() const
00341 {
00342 unsigned int pos = m_rawdata.find("\r\nContent-Length: ", 0) + 18;
00343 unsigned int end = m_rawdata.find("\r\n", pos);
00344
00345 std::string tmp = m_rawdata.substr(pos, end - pos);
00346
00347 return atoi( tmp.c_str() );
00348 }
00349
00350 bool GetRequest::postProcessData()
00351 {
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369 unsigned int size, pos, prev;
00370
00371 size = findSize(0, m_data);
00372 if (size == std::string::npos) {
00373 m_success = false;
00374 return false;
00375 }
00376
00377
00378 pos = m_data.find("\r\n", 0);
00379 if (pos == std::string::npos) {
00380 m_success = false;
00381 return false;
00382 }
00383
00384 pos += 2;
00385
00386 m_data = m_data.erase(0, pos);
00387 prev = pos = size;
00388
00389
00390 m_data = m_data.erase(pos, 2);
00391
00392 while (true) {
00393 size = findSize(pos, m_data);
00394
00395 if (size == std::string::npos) {
00396 m_success = false;
00397 return false;
00398 } else if (size == 0) {
00399
00400 m_data = m_data.erase(pos, std::string::npos);
00401 m_success = true;
00402 return true;
00403 }
00404
00405
00406 pos = m_data.find("\r\n", pos);
00407 if (pos == std::string::npos) {
00408 m_success = false;
00409 return false;
00410 }
00411
00412 pos += 2;
00413 m_data = m_data.erase(prev, pos - prev);
00414 pos = prev + size;
00415 prev = pos;
00416
00417
00418 m_data = m_data.erase(pos, 2);
00419 }
00420
00421
00422 return true;
00423 }
00424
00425 unsigned int GetRequest::findSize(unsigned int n, const std::string& source) const
00426 {
00427 unsigned int end, crlf, semicolon, size;
00428
00429 crlf = source.find("\r\n", n);
00430 if (crlf == std::string::npos)
00431 return std::string::npos;
00432
00433 semicolon = source.find(";", n);
00434 if (semicolon == std::string::npos)
00435 semicolon = crlf;
00436
00437 if (semicolon < crlf)
00438 end = semicolon;
00439 else
00440 end = crlf;
00441
00442 std::stringstream ss;
00443 ss << source.substr(n, end - n);
00444 ss.setf(std::ios_base::hex, std::ios_base::basefield);
00445 ss >> size;
00446
00447
00448
00449 return size;
00450 }
00451
00452 bool GetRequest::splitData()
00453 {
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479 if ( !isChunkedTransfer() ) {
00480
00481
00482 unsigned int size = getContentLength();
00483
00484 unsigned int pos = m_rawdata.find("\r\n\r\n", 0);
00485 if (pos == std::string::npos) {
00486 setError("HTTP request error: no header information available");
00487 m_success = false;
00488 return false;
00489 }
00490
00491 pos += 4;
00492
00493 m_header = m_rawdata.substr(0, pos);
00494
00495 m_data = m_rawdata.substr(pos, size);
00496 m_footer = "";
00497
00498 } else {
00499
00500
00501
00502 unsigned int pos = m_rawdata.find("\r\n\r\n", 0);
00503 if (pos == std::string::npos) {
00504 setError("HTTP request error: no valid header found (chunked)");
00505 m_success = false;
00506 return false;
00507 } else {
00508 m_header = m_rawdata.substr(0, pos + 2);
00509 }
00510 pos += 4;
00511
00512
00513 unsigned int end = m_rawdata.rfind("\r\n0", std::string::npos);
00514 if (end == std::string::npos) {
00515 setError("HTTP request error: no valid footer found (chunked)");
00516 m_success = false;
00517 return false;
00518 } else {
00519
00520 end += 2;
00521 end = m_rawdata.find("\r\n", end);
00522 if (end == std::string::npos) {
00523 setError("HTTP request error: no valid footer found (chunked*)");
00524 m_success = false;
00525 return false;
00526 }
00527 end += 2;
00528 m_footer = m_rawdata.substr(end, std::string::npos);
00529 }
00530
00531
00532 m_data = m_rawdata.substr(pos, end - pos);
00533
00534
00535
00536
00537 if (!postProcessData()) {
00538 setError("HTTP request error: the data part seems to be corrupted (chunked)");
00539 m_success = false;
00540 return false;
00541 }
00542 }
00543
00544 return true;
00545 }
00546
00547
00548 }
00549
00550