// Ryzom - MMORPG Framework
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see .
#include "stdpch.h"
#include "game_share/http_client.h"
using namespace NLMISC;
using namespace NLNET;
using namespace std;
// ***************************************************************************
bool CHttpClient::connect(std::string server)
{
try
{
// Convert an URL to a host if needed
if (server.substr(0, 7) == "http://")
server = server.substr(7);
server = server.substr(0, server.find( "/" ));
// Add the default port if no port in the cfg, and check if not already connected
if(server.find(':') == string::npos)
server+=":80";
CInetAddress addr = CInetAddress(server);
if (_Sock.connected())
{
if (addr == _Sock.remoteAddr())
return true;
else
_Sock.disconnect();
}
// Actually connect
_Sock.connect(addr);
if(!_Sock.connected())
{
nlwarning("Can't connect to web server '%s'", server.c_str());
goto end;
}
else
{
nldebug("Connected to web server '%s'", server.c_str());
}
}
catch(const Exception &e)
{
nlwarning("Can't connect to web server '%s': %s", server.c_str(), e.what());
goto end;
}
return true;
end:
if(_Sock.connected())
_Sock.close ();
return false;
}
// ***************************************************************************
bool CHttpClient::send(const std::string& buffer, bool verbose)
{
nlassert(_Sock.connected());
if(verbose)
{
nldebug("Sending '%s' to '%s'", trim(buffer).c_str(), _Sock.remoteAddr().asString().c_str());
}
uint32 size = (uint32)buffer.size();
if(!buffer.empty())
{
if(_Sock.send((uint8 *)buffer.c_str(), size, false) != CSock::Ok)
{
nlwarning ("Can't send data to the server");
return false;
}
}
return true;
}
// ***************************************************************************
bool CHttpClient::sendRequest(const std::string& methodWB, const std::string &url, const std::string &cookieName, const std::string &cookieValue, const std::string& postParams, bool verbose)
{
std::string path, host;
// Remove the protocol from the URL
if (url.substr(0, 7) == "http://")
path = url.substr(7);
else
path = url;
std::string::size_type pos = path.find("/");
// Remove the host from the URL
if (pos != std::string::npos)
{
host = path.substr(0, pos);
path = path.substr(pos);
}
else
{
host = path;
path.clear();
}
// build HTTP request
std::string request;
request += methodWB + " " + path + " HTTP/1.1\r\n";
request += "Host: " + host + "\r\n";
request += "Connection: close\r\n";
// Send
if (cookieName.empty() && postParams.empty())
{
request += "\r\n";
return send(request, verbose);
}
else
{
if (!cookieName.empty())
request += "Cookie: " + cookieName + "=" + cookieValue + "\r\n";
if (!postParams.empty())
{
request += "Content-Type: application/x-www-form-urlencoded\r\n";
request += "Content-Length: " + toString(postParams.size()) + "\r\n";
request += "\r\n";
request += postParams;
}
request += "\r\n";
return send(request, verbose);
}
}
// ***************************************************************************
bool CHttpClient::sendGet(const string &url, const string& params, bool verbose)
{
return sendRequest("GET", url + (params.empty() ? "" : ("?" + params)), string(), string(), string(), verbose);
}
// ***************************************************************************
bool CHttpClient::sendGetWithCookie(const string &url, const string &name, const string &value, const string& params, bool verbose)
{
return sendRequest("GET", url + (params.empty() ? "" : ("?" + params)), name, value, string(), verbose);
}
// ***************************************************************************
bool CHttpClient::sendPost(const string &url, const string& params, bool verbose)
{
return sendRequest("POST", url, string(), string(), params, verbose);
}
// ***************************************************************************
bool CHttpClient::sendPostWithCookie(const string &url, const string &name, const string &value, const string& params, bool verbose)
{
return sendRequest("POST", url, name, value, params, verbose);
}
// ***************************************************************************
bool CHttpClient::receive(string &res, bool verbose)
{
nlassert(_Sock.connected());
uint32 size;
res.clear();
uint8 buf[1024];
if(verbose) nlinfo("Receiving");
for(;;)
{
size = 1023;
if (_Sock.receive((uint8*)buf, size, false) == CSock::Ok)
{
if (verbose) nlinfo("Received OK %u bytes", size);
buf[1023] = '\0';
res += (char*)buf;
//nlinfo("block received '%s'", buf);
}
else
{
if (verbose) nlinfo("Received CLOSE %u bytes", size);
buf[size] = '\0';
res += (char*)buf;
//nlwarning ("server connection closed");
break;
}
}
//nlinfo("all received '%s'", res.c_str());
// only keep content (delimited by two \r\n) and discard server headers
std::string::size_type pos = res.find("\r\n\r\n");
if (pos != std::string::npos)
{
res = res.substr(pos + 4);
}
return true;
}
// ***************************************************************************
void CHttpClient::disconnect()
{
//if(_Sock.connected())
// NB Nico : close all the time, to avoid printing into the log after release
// in CSock dtor -> causes a crash
_Sock.close ();
}
// ***************************************************************************
CHttpPostTask::CHttpPostTask(const std::string &host, const std::string &page, const std::string ¶ms)
: _Host(host)
, _Page(page)
, _Params(params)
{
}
// ***************************************************************************
void CHttpPostTask::run(void)
{
CHttpClient httpClient;
std::string ret;
if ( ! httpClient.connect(_Host))
{
return;
}
if ( ! httpClient.sendPost(_Host + _Page, _Params))
{
return;
}
httpClient.receive(ret);
httpClient.disconnect();
}