/** 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); } }