/**
This file is a part of r0nk, atlas_moon, and rexy's matrix client
Copyright (C) 2019 rexy712
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 "matrix/client_base.hpp"
#include "raii/rjp_ptr.hpp"
#include "raii/static_string.hpp"
#include //size_t
#include //min, max
namespace matrix::internal{
client_base::client_base(void):
m_curl()
{
_set_curl_defaults(""_ss);
}
void client_base::_set_curl_useragent(const raii::string_base& useragent){
m_curl.setuseragent(useragent);
}
size_t client_base::_post_reply_curl_callback(char* ptr, size_t size, size_t nmemb, void* userdata){
raii::string* data = reinterpret_cast(userdata);
(*data) += ptr;
return size*nmemb;
}
raii::string client_base::_get_curl(const raii::string_base& url)const{
raii::string reply;
m_curl.getreq();
m_curl.seturl(url);
m_curl.setheader(raii::curl_llist{});
m_curl.setopt(CURLOPT_WRITEFUNCTION, _post_reply_curl_callback);
m_curl.setopt(CURLOPT_WRITEDATA, &reply);
CURLcode res = m_curl.perform();
if(res != CURLE_OK)
return {};
return reply;
}
raii::string client_base::_post_curl(const raii::string_base& postdata, const raii::string_base& url, const raii::curl_llist& header)const{
raii::string reply;
m_curl.postreq();
m_curl.setopt(CURLOPT_POSTFIELDS, postdata.get());
m_curl.setopt(CURLOPT_POSTFIELDSIZE_LARGE, (curl_off_t)postdata.length());
m_curl.seturl(url);
m_curl.setheader(header);
m_curl.setopt(CURLOPT_WRITEFUNCTION, _post_reply_curl_callback);
m_curl.setopt(CURLOPT_WRITEDATA, &reply);
CURLcode res = m_curl.perform();
if(res != CURLE_OK)
return {};
return reply;
}
struct put_data{
const char* data;
size_t len;
};
static size_t _put_read_curl_callback(char* buffer, size_t size, size_t nmemb, void* userdata){
put_data* src = reinterpret_cast(userdata);
size_t curl_size = size*nmemb;
size_t to_copy = std::min(curl_size, src->len);
memcpy(buffer, src->data, to_copy);
src->len -= to_copy;
src->data += to_copy;
return to_copy;
}
raii::string client_base::_put_curl(const raii::string_base& putdata, const raii::string_base& url, const raii::curl_llist& header)const{
raii::string reply;
put_data data{putdata.get(), putdata.length()};
m_curl.putreq();
m_curl.setopt(CURLOPT_POSTFIELDS, putdata.get());
m_curl.setopt(CURLOPT_POSTFIELDSIZE_LARGE, (curl_off_t)putdata.length());
m_curl.seturl(url);
m_curl.setheader(header);
m_curl.setopt(CURLOPT_WRITEFUNCTION, _post_reply_curl_callback);
m_curl.setopt(CURLOPT_WRITEDATA, &reply);
m_curl.setopt(CURLOPT_READFUNCTION, _put_read_curl_callback);
m_curl.setopt(CURLOPT_READDATA, &data);
m_curl.setopt(CURLOPT_INFILESIZE, (curl_off_t)data.len);
CURLcode res = m_curl.perform();
m_curl.setopt(CURLOPT_READDATA, NULL);
m_curl.setopt(CURLOPT_READFUNCTION, NULL);
if(res != CURLE_OK)
return {};
return reply;
}
raii::rjp_string client_base::_post_and_find(const raii::string_base& data, const raii::string_base& url,
const raii::curl_llist& header, const raii::string_base& target)const
{
raii::string reply = _post_curl(data, url, header);
if(!reply)
return {};
return _curl_reply_search(reply, target);
}
raii::rjp_string client_base::_get_and_find(const raii::string_base& url, const raii::string_base& target)const{
raii::string reply = _get_curl(url);
if(!reply)
return {};
return _curl_reply_search(reply, target);
}
raii::rjp_string client_base::_curl_reply_search(const raii::string_base& reply, const raii::string_base& target)const{
raii::rjp_ptr root(rjp_parse(reply));
if(!root)
return {};
RJP_search_res res = rjp_search_member(root.get(), target.get(), 0);
if(rjp_value_type(res.value) != json_string)
return {};
return raii::rjp_string(res.value);
}
void client_base::_set_curl_defaults(const raii::string_base& useragent)const{
m_curl.setopt(CURLOPT_BUFFERSIZE, 102400L);
m_curl.setopt(CURLOPT_NOPROGRESS, 1L);
m_curl.setuseragent(useragent);
m_curl.setopt(CURLOPT_MAXREDIRS, 50L);
m_curl.setopt(CURLOPT_FOLLOWLOCATION, 1L);
m_curl.forcessl(CURL_SSLVERSION_TLSv1_2);
m_curl.setopt(CURLOPT_TCP_KEEPALIVE, 1L);
m_curl.setopt(CURLOPT_FAILONERROR, 1L);
}
}