2013-09-15 17:56:47 +00:00
|
|
|
#include "HttpReq.h"
|
2017-11-01 22:21:10 +00:00
|
|
|
|
2018-01-09 22:55:09 +00:00
|
|
|
#include "utils/FileSystemUtil.h"
|
2013-09-15 17:56:47 +00:00
|
|
|
#include "Log.h"
|
2018-01-09 22:55:09 +00:00
|
|
|
#include <assert.h>
|
2013-09-15 17:56:47 +00:00
|
|
|
|
2013-10-10 18:11:01 +00:00
|
|
|
CURLM* HttpReq::s_multi_handle = curl_multi_init();
|
|
|
|
|
|
|
|
std::map<CURL*, HttpReq*> HttpReq::s_requests;
|
2013-09-15 17:56:47 +00:00
|
|
|
|
2013-09-24 07:02:14 +00:00
|
|
|
std::string HttpReq::urlEncode(const std::string &s)
|
|
|
|
{
|
|
|
|
const std::string unreserved = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.~";
|
|
|
|
|
|
|
|
std::string escaped="";
|
|
|
|
for(size_t i=0; i<s.length(); i++)
|
|
|
|
{
|
|
|
|
if (unreserved.find_first_of(s[i]) != std::string::npos)
|
|
|
|
{
|
|
|
|
escaped.push_back(s[i]);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
escaped.append("%");
|
|
|
|
char buf[3];
|
2014-11-29 20:42:30 +00:00
|
|
|
sprintf(buf, "%.2X", (unsigned char)s[i]);
|
2013-09-24 07:02:14 +00:00
|
|
|
escaped.append(buf);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return escaped;
|
|
|
|
}
|
|
|
|
|
2013-10-10 00:50:42 +00:00
|
|
|
bool HttpReq::isUrl(const std::string& str)
|
|
|
|
{
|
|
|
|
//the worst guess
|
2019-08-25 15:23:02 +00:00
|
|
|
return (!str.empty() && !Utils::FileSystem::exists(str) &&
|
2013-10-10 00:50:42 +00:00
|
|
|
(str.find("http://") != std::string::npos || str.find("https://") != std::string::npos || str.find("www.") != std::string::npos));
|
|
|
|
}
|
|
|
|
|
2013-09-20 23:55:05 +00:00
|
|
|
HttpReq::HttpReq(const std::string& url)
|
2013-10-10 18:11:01 +00:00
|
|
|
: mStatus(REQ_IN_PROGRESS), mHandle(NULL)
|
2013-09-20 23:55:05 +00:00
|
|
|
{
|
2013-10-10 18:11:01 +00:00
|
|
|
mHandle = curl_easy_init();
|
2013-09-20 23:55:05 +00:00
|
|
|
|
2013-10-10 18:11:01 +00:00
|
|
|
if(mHandle == NULL)
|
2013-10-05 20:28:59 +00:00
|
|
|
{
|
2013-10-10 18:11:01 +00:00
|
|
|
mStatus = REQ_IO_ERROR;
|
|
|
|
onError("curl_easy_init failed");
|
|
|
|
return;
|
2013-10-05 20:28:59 +00:00
|
|
|
}
|
2013-09-20 23:55:05 +00:00
|
|
|
|
2013-10-10 18:11:01 +00:00
|
|
|
//set the url
|
|
|
|
CURLcode err = curl_easy_setopt(mHandle, CURLOPT_URL, url.c_str());
|
|
|
|
if(err != CURLE_OK)
|
2013-09-15 17:56:47 +00:00
|
|
|
{
|
2013-10-10 18:11:01 +00:00
|
|
|
mStatus = REQ_IO_ERROR;
|
|
|
|
onError(curl_easy_strerror(err));
|
|
|
|
return;
|
2013-09-15 17:56:47 +00:00
|
|
|
}
|
|
|
|
|
2018-05-23 20:42:53 +00:00
|
|
|
//set curl to handle redirects
|
|
|
|
err = curl_easy_setopt(mHandle, CURLOPT_FOLLOWLOCATION, 1L);
|
|
|
|
if(err != CURLE_OK)
|
|
|
|
{
|
|
|
|
mStatus = REQ_IO_ERROR;
|
|
|
|
onError(curl_easy_strerror(err));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
//set curl max redirects
|
|
|
|
err = curl_easy_setopt(mHandle, CURLOPT_MAXREDIRS, 2L);
|
|
|
|
if(err != CURLE_OK)
|
|
|
|
{
|
|
|
|
mStatus = REQ_IO_ERROR;
|
|
|
|
onError(curl_easy_strerror(err));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
//set curl restrict redirect protocols
|
2019-08-25 15:23:02 +00:00
|
|
|
err = curl_easy_setopt(mHandle, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS);
|
2018-05-23 20:42:53 +00:00
|
|
|
if(err != CURLE_OK)
|
|
|
|
{
|
|
|
|
mStatus = REQ_IO_ERROR;
|
|
|
|
onError(curl_easy_strerror(err));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-10-10 18:11:01 +00:00
|
|
|
//tell curl how to write the data
|
|
|
|
err = curl_easy_setopt(mHandle, CURLOPT_WRITEFUNCTION, &HttpReq::write_content);
|
|
|
|
if(err != CURLE_OK)
|
2013-09-15 17:56:47 +00:00
|
|
|
{
|
2013-10-10 18:11:01 +00:00
|
|
|
mStatus = REQ_IO_ERROR;
|
|
|
|
onError(curl_easy_strerror(err));
|
|
|
|
return;
|
2013-09-15 17:56:47 +00:00
|
|
|
}
|
|
|
|
|
2013-10-10 18:11:01 +00:00
|
|
|
//give curl a pointer to this HttpReq so we know where to write the data *to* in our write function
|
|
|
|
err = curl_easy_setopt(mHandle, CURLOPT_WRITEDATA, this);
|
|
|
|
if(err != CURLE_OK)
|
2013-09-15 17:56:47 +00:00
|
|
|
{
|
2013-10-10 18:11:01 +00:00
|
|
|
mStatus = REQ_IO_ERROR;
|
|
|
|
onError(curl_easy_strerror(err));
|
|
|
|
return;
|
2013-09-15 17:56:47 +00:00
|
|
|
}
|
2013-10-10 18:11:01 +00:00
|
|
|
|
|
|
|
//add the handle to our multi
|
|
|
|
CURLMcode merr = curl_multi_add_handle(s_multi_handle, mHandle);
|
|
|
|
if(merr != CURLM_OK)
|
2013-09-15 17:56:47 +00:00
|
|
|
{
|
2013-10-10 18:11:01 +00:00
|
|
|
mStatus = REQ_IO_ERROR;
|
|
|
|
onError(curl_multi_strerror(merr));
|
|
|
|
return;
|
2013-09-15 17:56:47 +00:00
|
|
|
}
|
2013-10-10 18:11:01 +00:00
|
|
|
|
|
|
|
s_requests[mHandle] = this;
|
2013-09-15 17:56:47 +00:00
|
|
|
}
|
|
|
|
|
2013-10-10 18:11:01 +00:00
|
|
|
HttpReq::~HttpReq()
|
2013-09-15 17:56:47 +00:00
|
|
|
{
|
2013-10-10 18:11:01 +00:00
|
|
|
if(mHandle)
|
2013-09-15 17:56:47 +00:00
|
|
|
{
|
2013-10-10 18:11:01 +00:00
|
|
|
s_requests.erase(mHandle);
|
2013-09-15 17:56:47 +00:00
|
|
|
|
2013-10-10 18:11:01 +00:00
|
|
|
CURLMcode merr = curl_multi_remove_handle(s_multi_handle, mHandle);
|
2013-09-15 17:56:47 +00:00
|
|
|
|
2013-10-10 18:11:01 +00:00
|
|
|
if(merr != CURLM_OK)
|
|
|
|
LOG(LogError) << "Error removing curl_easy handle from curl_multi: " << curl_multi_strerror(merr);
|
2013-09-15 17:56:47 +00:00
|
|
|
|
2013-10-10 18:11:01 +00:00
|
|
|
curl_easy_cleanup(mHandle);
|
2013-09-15 17:56:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-10-10 18:11:01 +00:00
|
|
|
HttpReq::Status HttpReq::status()
|
2013-09-15 17:56:47 +00:00
|
|
|
{
|
2013-10-10 18:11:01 +00:00
|
|
|
if(mStatus == REQ_IN_PROGRESS)
|
2013-09-15 17:56:47 +00:00
|
|
|
{
|
2013-10-10 18:11:01 +00:00
|
|
|
int handle_count;
|
|
|
|
CURLMcode merr = curl_multi_perform(s_multi_handle, &handle_count);
|
|
|
|
if(merr != CURLM_OK && merr != CURLM_CALL_MULTI_PERFORM)
|
2013-09-15 17:56:47 +00:00
|
|
|
{
|
2013-10-10 18:11:01 +00:00
|
|
|
mStatus = REQ_IO_ERROR;
|
|
|
|
onError(curl_multi_strerror(merr));
|
|
|
|
return mStatus;
|
2013-09-15 17:56:47 +00:00
|
|
|
}
|
|
|
|
|
2013-10-10 18:11:01 +00:00
|
|
|
int msgs_left;
|
|
|
|
CURLMsg* msg;
|
2017-10-28 20:07:31 +00:00
|
|
|
while((msg = curl_multi_info_read(s_multi_handle, &msgs_left)) != nullptr)
|
2013-10-10 18:11:01 +00:00
|
|
|
{
|
|
|
|
if(msg->msg == CURLMSG_DONE)
|
|
|
|
{
|
|
|
|
HttpReq* req = s_requests[msg->easy_handle];
|
2019-08-25 15:23:02 +00:00
|
|
|
|
2013-10-10 18:11:01 +00:00
|
|
|
if(req == NULL)
|
|
|
|
{
|
|
|
|
LOG(LogError) << "Cannot find easy handle!";
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(msg->data.result == CURLE_OK)
|
|
|
|
{
|
|
|
|
req->mStatus = REQ_SUCCESS;
|
|
|
|
}else{
|
|
|
|
req->mStatus = REQ_IO_ERROR;
|
|
|
|
req->onError(curl_easy_strerror(msg->data.result));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-09-29 02:54:15 +00:00
|
|
|
}
|
|
|
|
|
2013-09-15 17:56:47 +00:00
|
|
|
return mStatus;
|
|
|
|
}
|
|
|
|
|
2014-03-19 00:55:37 +00:00
|
|
|
std::string HttpReq::getContent() const
|
2013-09-15 17:56:47 +00:00
|
|
|
{
|
2014-03-19 00:55:37 +00:00
|
|
|
assert(mStatus == REQ_SUCCESS);
|
2013-09-15 17:56:47 +00:00
|
|
|
return mContent.str();
|
|
|
|
}
|
|
|
|
|
2013-10-10 18:11:01 +00:00
|
|
|
void HttpReq::onError(const char* msg)
|
2013-09-15 17:56:47 +00:00
|
|
|
{
|
2013-10-10 18:11:01 +00:00
|
|
|
mErrorMsg = msg;
|
2013-09-15 17:56:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
std::string HttpReq::getErrorMsg()
|
|
|
|
{
|
2013-10-10 18:11:01 +00:00
|
|
|
return mErrorMsg;
|
2013-09-15 17:56:47 +00:00
|
|
|
}
|
2013-10-10 18:11:01 +00:00
|
|
|
|
|
|
|
//used as a curl callback
|
|
|
|
//size = size of an element, nmemb = number of elements
|
|
|
|
//return value is number of elements successfully read
|
|
|
|
size_t HttpReq::write_content(void* buff, size_t size, size_t nmemb, void* req_ptr)
|
|
|
|
{
|
|
|
|
std::stringstream& ss = ((HttpReq*)req_ptr)->mContent;
|
|
|
|
ss.write((char*)buff, size * nmemb);
|
|
|
|
|
|
|
|
return nmemb;
|
|
|
|
}
|
|
|
|
|
|
|
|
//used as a curl callback
|
|
|
|
/*int HttpReq::update_progress(void* req_ptr, double dlTotal, double dlNow, double ulTotal, double ulNow)
|
|
|
|
{
|
2019-08-25 15:23:02 +00:00
|
|
|
|
2013-10-10 18:11:01 +00:00
|
|
|
}*/
|