Merge branch 'develop' into main
This commit is contained in:
commit
e134745dd4
10
README.adoc
10
README.adoc
@ -32,7 +32,7 @@ This is still a work in progress; here is a rough overview of the features:
|
|||||||
* [ ] Requests
|
* [ ] Requests
|
||||||
** [x] `GET` requests.
|
** [x] `GET` requests.
|
||||||
** [x] Streaming `GET` requests.
|
** [x] Streaming `GET` requests.
|
||||||
** [ ] `POST` requests.
|
** [x] `POST` requests.
|
||||||
** [ ] `PATCH` requests.
|
** [ ] `PATCH` requests.
|
||||||
** [ ] `PUT` requests.
|
** [ ] `PUT` requests.
|
||||||
** [ ] `DELETE` requests.
|
** [ ] `DELETE` requests.
|
||||||
@ -84,7 +84,7 @@ link:{uri-reference}/examples.html[More examples] are included in the reference.
|
|||||||
* Tested OS: Linux
|
* Tested OS: Linux
|
||||||
* C++ compiler (tested: link:{uri-gcc}[GCC] 7/8/9, link:{uri-lang}[clang] 6/7)
|
* C++ compiler (tested: link:{uri-gcc}[GCC] 7/8/9, link:{uri-lang}[clang] 6/7)
|
||||||
* link:{uri-cmake}[CMake] (at least: 3.9)
|
* link:{uri-cmake}[CMake] (at least: 3.9)
|
||||||
* link:{uri-libcurl}[libcurl] (at least: 7.32)
|
* link:{uri-libcurl}[libcurl] (at least: 7.56)
|
||||||
* Optional
|
* Optional
|
||||||
** Documentation: link:{uri-doxygen}[Doxygen] (tested: 1.8)
|
** Documentation: link:{uri-doxygen}[Doxygen] (tested: 1.8)
|
||||||
** Tests: link:{uri-catch}[Catch] (tested: 2.5 / 1.2)
|
** Tests: link:{uri-catch}[Catch] (tested: 2.5 / 1.2)
|
||||||
@ -117,8 +117,8 @@ cmake --build . -- -j$(nproc --ignore=1)
|
|||||||
* `-DCMAKE_BUILD_TYPE=Debug` for a debug build.
|
* `-DCMAKE_BUILD_TYPE=Debug` for a debug build.
|
||||||
* `-DWITH_TESTS=YES` if you want to compile the tests.
|
* `-DWITH_TESTS=YES` if you want to compile the tests.
|
||||||
* `-DWITH_EXAMPLES=YES` if you want to compile the examples.
|
* `-DWITH_EXAMPLES=YES` if you want to compile the examples.
|
||||||
// * One of:
|
* One of:
|
||||||
// ** `-DWITH_DEB=YES` if you want to be able to generate a deb-package.
|
** `-DWITH_DEB=YES` if you want to be able to generate a deb-package.
|
||||||
// ** `-DWITH_RPM=YES` if you want to be able to generate an rpm-package.
|
** `-DWITH_RPM=YES` if you want to be able to generate an rpm-package.
|
||||||
|
|
||||||
include::{uri-base}/raw/branch/main/CONTRIBUTING.adoc[]
|
include::{uri-base}/raw/branch/main/CONTRIBUTING.adoc[]
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
include(CMakeFindDependencyMacro)
|
include(CMakeFindDependencyMacro)
|
||||||
|
|
||||||
find_dependency(CURL REQUIRED)
|
find_dependency(CURL 7.56 REQUIRED)
|
||||||
|
|
||||||
include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake")
|
include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake")
|
||||||
|
@ -68,7 +68,7 @@ int main(int argc, char *argv[])
|
|||||||
sleep_for(2s);
|
sleep_for(2s);
|
||||||
for (const auto &event : connection.get_new_events())
|
for (const auto &event : connection.get_new_events())
|
||||||
{
|
{
|
||||||
// Print typo of event and the beginning of the data.
|
// Print type of event and the beginning of the data.
|
||||||
cout << event.type << ": "
|
cout << event.type << ": "
|
||||||
<< event.data.substr(0, 70) << " …" << endl;
|
<< event.data.substr(0, 70) << " …" << endl;
|
||||||
}
|
}
|
||||||
@ -76,8 +76,7 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
// Cancel the stream, …
|
// Cancel the stream, …
|
||||||
connection.cancel_stream();
|
connection.cancel_stream();
|
||||||
// … and get the rest of the data.
|
// … and wait for the thread.
|
||||||
cout << connection.get_new_stream_contents() << endl;
|
|
||||||
stream_thread.join();
|
stream_thread.join();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -124,6 +124,43 @@ public:
|
|||||||
return get(endpoint, {});
|
return get(endpoint, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* @brief Make a HTTP POST call with parameters.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* @code
|
||||||
|
* auto answer{connection.post(
|
||||||
|
* mastodonpp::API::v1::statuses,
|
||||||
|
* {
|
||||||
|
* {"status", "How is the wheather?"},
|
||||||
|
* {"poll[options]", vector<string_view>{"Nice", "not nice"}},
|
||||||
|
* {"poll[expires_in]", to_string(poll_seconds)}
|
||||||
|
* })};
|
||||||
|
* @endcode
|
||||||
|
*
|
||||||
|
* @param endpoint Endpoint as API::endpoint_type or `std::string_view`.
|
||||||
|
* @param parameters A map of parameters.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @since 0.1.0
|
||||||
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
|
answer_type post(const endpoint_variant &endpoint,
|
||||||
|
const parametermap ¶meters);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* @brief Make a HTTP POST call.
|
||||||
|
*
|
||||||
|
* @param endpoint Endpoint as API::endpoint_type or `std::string_view`.
|
||||||
|
*
|
||||||
|
* @since 0.1.0
|
||||||
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
|
inline answer_type post(const endpoint_variant &endpoint)
|
||||||
|
{
|
||||||
|
return post(endpoint, {});
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* @brief Copy new stream contents and delete the “original”.
|
* @brief Copy new stream contents and delete the “original”.
|
||||||
*
|
*
|
||||||
@ -144,9 +181,17 @@ public:
|
|||||||
*/
|
*/
|
||||||
vector<event_type> get_new_events();
|
vector<event_type> get_new_events();
|
||||||
|
|
||||||
|
//! @copydoc CURLWrapper::cancel_stream
|
||||||
|
inline void cancel_stream()
|
||||||
|
{
|
||||||
|
CURLWrapper::cancel_stream();
|
||||||
|
}
|
||||||
private:
|
private:
|
||||||
Instance &_instance;
|
Instance &_instance;
|
||||||
const string_view _baseuri;
|
const string_view _baseuri;
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
string endpoint_to_uri(const endpoint_variant &endpoint) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace mastodonpp
|
} // namespace mastodonpp
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
#include <utility>
|
||||||
#include <variant>
|
#include <variant>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@ -35,6 +36,7 @@ using std::map;
|
|||||||
using std::mutex;
|
using std::mutex;
|
||||||
using std::string;
|
using std::string;
|
||||||
using std::string_view;
|
using std::string_view;
|
||||||
|
using std::pair;
|
||||||
using std::variant;
|
using std::variant;
|
||||||
using std::vector;
|
using std::vector;
|
||||||
|
|
||||||
@ -53,7 +55,7 @@ enum class http_method
|
|||||||
};
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* @brief std::map of parameters for %API calls.
|
* @brief `std::map` of parameters for %API calls.
|
||||||
*
|
*
|
||||||
* Example:
|
* Example:
|
||||||
* @code
|
* @code
|
||||||
@ -66,7 +68,16 @@ enum class http_method
|
|||||||
*
|
*
|
||||||
* @since 0.1.0
|
* @since 0.1.0
|
||||||
*/
|
*/
|
||||||
using parametermap = map<string_view, variant<string_view, vector<string_view>>>;
|
using parametermap =
|
||||||
|
map<string_view, variant<string_view, vector<string_view>>>;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* @brief A single parameter of a parametermap.
|
||||||
|
*
|
||||||
|
* @since 0.1.0
|
||||||
|
*/
|
||||||
|
using parameterpair =
|
||||||
|
pair<string_view, variant<string_view, vector<string_view>>>;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* @brief Handles the details of network connections.
|
* @brief Handles the details of network connections.
|
||||||
@ -141,24 +152,12 @@ public:
|
|||||||
*/
|
*/
|
||||||
void set_proxy(string_view proxy);
|
void set_proxy(string_view proxy);
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief Cancel the stream.
|
|
||||||
*
|
|
||||||
* The stream will be cancelled, usually whithin a second. The @link
|
|
||||||
* answer_type::curl_error_code curl_error_code @endlink of the answer will
|
|
||||||
* be set to 42 (`CURLE_ABORTED_BY_CALLBACK`).
|
|
||||||
*
|
|
||||||
* @since 0.1.0
|
|
||||||
*/
|
|
||||||
void cancel_stream();
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/*!
|
/*!
|
||||||
* @brief Mutex for #get_buffer a.k.a. _curl_buffer_body.
|
* @brief Mutex for #get_buffer a.k.a. _curl_buffer_body.
|
||||||
*
|
*
|
||||||
* This mutex is locked in `writer_body()` and
|
* This mutex is locked before anything is read or written from/to
|
||||||
* Connection::get_new_stream_contents before anything is read or written
|
* _curl_buffer_body.
|
||||||
* from/to _curl_buffer_body.
|
|
||||||
*
|
*
|
||||||
* @since 0.1.0
|
* @since 0.1.0
|
||||||
*/
|
*/
|
||||||
@ -188,6 +187,27 @@ protected:
|
|||||||
return _curl_buffer_body;
|
return _curl_buffer_body;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* @brief Cancel the stream.
|
||||||
|
*
|
||||||
|
* The stream will be cancelled, usually whithin a second. The @link
|
||||||
|
* answer_type::curl_error_code curl_error_code @endlink of the answer will
|
||||||
|
* be set to 42 (`CURLE_ABORTED_BY_CALLBACK`).
|
||||||
|
*
|
||||||
|
* @since 0.1.0
|
||||||
|
*/
|
||||||
|
inline void cancel_stream()
|
||||||
|
{
|
||||||
|
_stream_cancelled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* @brief Set OAuth 2.0 Bearer Access Token.
|
||||||
|
*
|
||||||
|
* @since 0.1.0
|
||||||
|
*/
|
||||||
|
void set_access_token(const string_view access_token);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CURL *_connection;
|
CURL *_connection;
|
||||||
char _curl_buffer_error[CURL_ERROR_SIZE];
|
char _curl_buffer_error[CURL_ERROR_SIZE];
|
||||||
@ -252,6 +272,18 @@ private:
|
|||||||
*/
|
*/
|
||||||
void setup_curl();
|
void setup_curl();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* @brief Replace parameter in URI.
|
||||||
|
*
|
||||||
|
* @param uri Reference to the URI.
|
||||||
|
* @param parameter The parameter.
|
||||||
|
*
|
||||||
|
* @return true if parameter was replaced.
|
||||||
|
*
|
||||||
|
* @since 0.1.0
|
||||||
|
*/
|
||||||
|
bool replace_parameter_in_uri(string &uri, const parameterpair ¶meter);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* @brief Add parameters to URI.
|
* @brief Add parameters to URI.
|
||||||
*
|
*
|
||||||
@ -261,6 +293,23 @@ private:
|
|||||||
* @since 0.1.0
|
* @since 0.1.0
|
||||||
*/
|
*/
|
||||||
void add_parameters_to_uri(string &uri, const parametermap ¶meters);
|
void add_parameters_to_uri(string &uri, const parametermap ¶meters);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* @brief Convert parametermap to `*curl_mime`.
|
||||||
|
*
|
||||||
|
* For more information consult [curl_mime_init(3)]
|
||||||
|
* (https://curl.haxx.se/libcurl/c/curl_mime_init.html). Calls
|
||||||
|
* replace_parameter_in_uri().
|
||||||
|
*
|
||||||
|
* @param uri Reference to the URI.
|
||||||
|
* @param parameters The parametermap.
|
||||||
|
*
|
||||||
|
* @return `*curl_mime`.
|
||||||
|
*
|
||||||
|
* @since 0.1.0
|
||||||
|
*/
|
||||||
|
curl_mime *parameters_to_curl_mime(string &uri,
|
||||||
|
const parametermap ¶meters);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace mastodonpp
|
} // namespace mastodonpp
|
||||||
|
@ -55,6 +55,13 @@ public:
|
|||||||
explicit CURLException(const CURLcode &error, string message,
|
explicit CURLException(const CURLcode &error, string message,
|
||||||
string error_buffer);
|
string error_buffer);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* @brief Constructor with message.
|
||||||
|
*
|
||||||
|
* @since 0.1.0
|
||||||
|
*/
|
||||||
|
explicit CURLException(string message);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* @brief The error code returned by libcurl.
|
* @brief The error code returned by libcurl.
|
||||||
*
|
*
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
namespace mastodonpp
|
namespace mastodonpp
|
||||||
{
|
{
|
||||||
@ -29,6 +30,7 @@ namespace mastodonpp
|
|||||||
using std::uint64_t;
|
using std::uint64_t;
|
||||||
using std::string;
|
using std::string;
|
||||||
using std::string_view;
|
using std::string_view;
|
||||||
|
using std::move;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* @brief Holds the access data of an instance.
|
* @brief Holds the access data of an instance.
|
||||||
@ -87,6 +89,19 @@ public:
|
|||||||
return _access_token;
|
return _access_token;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* @brief Set OAuth 2.0 Bearer Access Token.
|
||||||
|
*
|
||||||
|
* Sets also the access token for all Connection%s that are initialized
|
||||||
|
* with this Instance afterwards.
|
||||||
|
*
|
||||||
|
* @since 0.1.0
|
||||||
|
*/
|
||||||
|
inline void set_access_token(string access_token)
|
||||||
|
{
|
||||||
|
_access_token = move(access_token);
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* @brief Returns the maximum number of characters per post.
|
* @brief Returns the maximum number of characters per post.
|
||||||
*
|
*
|
||||||
@ -113,6 +128,7 @@ public:
|
|||||||
*
|
*
|
||||||
* @since 0.1.0
|
* @since 0.1.0
|
||||||
*/
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
string_view get_proxy() const
|
string_view get_proxy() const
|
||||||
{
|
{
|
||||||
return _proxy;
|
return _proxy;
|
||||||
|
@ -1,10 +1,8 @@
|
|||||||
name=@PROJECT_NAME@
|
|
||||||
prefix=@CMAKE_INSTALL_PREFIX@
|
prefix=@CMAKE_INSTALL_PREFIX@
|
||||||
exec_prefix=${prefix}
|
|
||||||
libdir=${prefix}/@CMAKE_INSTALL_LIBDIR@
|
libdir=${prefix}/@CMAKE_INSTALL_LIBDIR@
|
||||||
includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@
|
includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@
|
||||||
|
|
||||||
Name: ${name}
|
Name: @PROJECT_NAME@
|
||||||
Description: @PROJECT_DESCRIPTION@
|
Description: @PROJECT_DESCRIPTION@
|
||||||
Version: @PROJECT_VERSION@
|
Version: @PROJECT_VERSION@
|
||||||
Cflags: -I${includedir}
|
Cflags: -I${includedir}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
include(GNUInstallDirs)
|
include(GNUInstallDirs)
|
||||||
|
|
||||||
find_package(CURL 7.32 REQUIRED)
|
find_package(CURL 7.56 REQUIRED)
|
||||||
|
|
||||||
# Write version in header.
|
# Write version in header.
|
||||||
configure_file ("version.hpp.in"
|
configure_file ("version.hpp.in"
|
||||||
|
@ -30,22 +30,35 @@ Connection::Connection(Instance &instance)
|
|||||||
{
|
{
|
||||||
CURLWrapper::set_proxy(proxy);
|
CURLWrapper::set_proxy(proxy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!_instance.get_access_token().empty())
|
||||||
|
{
|
||||||
|
CURLWrapper::set_access_token(_instance.get_access_token());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
string Connection::endpoint_to_uri(const endpoint_variant &endpoint) const
|
||||||
|
{
|
||||||
|
if (holds_alternative<API::endpoint_type>(endpoint))
|
||||||
|
{
|
||||||
|
return string(_baseuri)
|
||||||
|
+= API{std::get<API::endpoint_type>(endpoint)}.to_string_view();
|
||||||
|
}
|
||||||
|
return string(_baseuri) += std::get<string_view>(endpoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
answer_type Connection::get(const endpoint_variant &endpoint,
|
answer_type Connection::get(const endpoint_variant &endpoint,
|
||||||
const parametermap ¶meters)
|
const parametermap ¶meters)
|
||||||
{
|
{
|
||||||
const string uri{[&]
|
return make_request(http_method::GET,
|
||||||
{
|
endpoint_to_uri(endpoint), parameters);
|
||||||
if (holds_alternative<API::endpoint_type>(endpoint))
|
}
|
||||||
{
|
|
||||||
return string(_baseuri)
|
|
||||||
+= API{std::get<API::endpoint_type>(endpoint)}.to_string_view();
|
|
||||||
}
|
|
||||||
return string(_baseuri) += std::get<string_view>(endpoint);
|
|
||||||
}()};
|
|
||||||
|
|
||||||
return make_request(http_method::GET, uri, parameters);
|
answer_type Connection::post(const endpoint_variant &endpoint,
|
||||||
|
const parametermap ¶meters)
|
||||||
|
{
|
||||||
|
return make_request(http_method::POST,
|
||||||
|
endpoint_to_uri(endpoint), parameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
string Connection::get_new_stream_contents()
|
string Connection::get_new_stream_contents()
|
||||||
|
@ -23,7 +23,6 @@
|
|||||||
#include <array>
|
#include <array>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstring>
|
|
||||||
|
|
||||||
namespace mastodonpp
|
namespace mastodonpp
|
||||||
{
|
{
|
||||||
@ -68,18 +67,13 @@ CURLWrapper::~CURLWrapper() noexcept
|
|||||||
void CURLWrapper::set_proxy(const string_view proxy)
|
void CURLWrapper::set_proxy(const string_view proxy)
|
||||||
{
|
{
|
||||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
|
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
|
||||||
CURLcode code = curl_easy_setopt(_connection, CURLOPT_PROXY, proxy);
|
CURLcode code{curl_easy_setopt(_connection, CURLOPT_PROXY, proxy.data())};
|
||||||
if (code != CURLE_OK)
|
if (code != CURLE_OK)
|
||||||
{
|
{
|
||||||
throw CURLException{code, "Failed to set proxy", _curl_buffer_error};
|
throw CURLException{code, "Failed to set proxy", _curl_buffer_error};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CURLWrapper::cancel_stream()
|
|
||||||
{
|
|
||||||
_stream_cancelled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
answer_type CURLWrapper::make_request(const http_method &method, string uri,
|
answer_type CURLWrapper::make_request(const http_method &method, string uri,
|
||||||
const parametermap ¶meters)
|
const parametermap ¶meters)
|
||||||
{
|
{
|
||||||
@ -101,8 +95,18 @@ answer_type CURLWrapper::make_request(const http_method &method, string uri,
|
|||||||
}
|
}
|
||||||
case http_method::POST:
|
case http_method::POST:
|
||||||
{
|
{
|
||||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
|
if (parameters.empty())
|
||||||
code = curl_easy_setopt(_connection, CURLOPT_POST, 1L);
|
{
|
||||||
|
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
|
||||||
|
code = curl_easy_setopt(_connection, CURLOPT_POST, 1L);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
curl_mime *mime{parameters_to_curl_mime(uri, parameters)};
|
||||||
|
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
|
||||||
|
code = curl_easy_setopt(_connection, CURLOPT_MIMEPOST, mime);
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case http_method::PATCH:
|
case http_method::PATCH:
|
||||||
@ -163,6 +167,32 @@ answer_type CURLWrapper::make_request(const http_method &method, string uri,
|
|||||||
return answer;
|
return answer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CURLWrapper::set_access_token(const string_view access_token)
|
||||||
|
{
|
||||||
|
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, hicpp-signed-bitwise)
|
||||||
|
CURLcode code{curl_easy_setopt(_connection, CURLOPT_XOAUTH2_BEARER,
|
||||||
|
access_token.data())};
|
||||||
|
if (code != CURLE_OK)
|
||||||
|
{
|
||||||
|
throw CURLException{code, "Could not set authorization token.",
|
||||||
|
_curl_buffer_error};
|
||||||
|
}
|
||||||
|
|
||||||
|
#if (LIBCURL_VERSION_NUM < 0x073d00) // libcurl < 7.61.0.
|
||||||
|
#define CURLAUTH_BEARER CURLAUTH_ANY
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, hicpp-signed-bitwise)
|
||||||
|
code = curl_easy_setopt(_connection, CURLOPT_HTTPAUTH, CURLAUTH_BEARER);
|
||||||
|
if (code != CURLE_OK)
|
||||||
|
{
|
||||||
|
throw CURLException{code, "Could not set authorization token.",
|
||||||
|
_curl_buffer_error};
|
||||||
|
}
|
||||||
|
|
||||||
|
debuglog << "Set authorization token.\n";
|
||||||
|
}
|
||||||
|
|
||||||
size_t CURLWrapper::writer_body(char *data, size_t size, size_t nmemb)
|
size_t CURLWrapper::writer_body(char *data, size_t size, size_t nmemb)
|
||||||
{
|
{
|
||||||
if(data == nullptr)
|
if(data == nullptr)
|
||||||
@ -229,7 +259,7 @@ void CURLWrapper::setup_curl()
|
|||||||
|
|
||||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
|
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
|
||||||
CURLcode code{curl_easy_setopt(_connection, CURLOPT_USERAGENT,
|
CURLcode code{curl_easy_setopt(_connection, CURLOPT_USERAGENT,
|
||||||
(string("mastorss/") += version).c_str())};
|
(string("mastodonpp/") += version).c_str())};
|
||||||
if (code != CURLE_OK)
|
if (code != CURLE_OK)
|
||||||
{
|
{
|
||||||
throw CURLException{code, "Failed to set User-Agent",
|
throw CURLException{code, "Failed to set User-Agent",
|
||||||
@ -247,27 +277,38 @@ void CURLWrapper::setup_curl()
|
|||||||
curl_easy_setopt(_connection, CURLOPT_MAXREDIRS, 10L);
|
curl_easy_setopt(_connection, CURLOPT_MAXREDIRS, 10L);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CURLWrapper::replace_parameter_in_uri(string &uri,
|
||||||
|
const parameterpair ¶meter)
|
||||||
|
{
|
||||||
|
static constexpr array replace
|
||||||
|
{
|
||||||
|
"id", "nickname", "nickname_or_id",
|
||||||
|
"hashtag", "permission_group"
|
||||||
|
};
|
||||||
|
if (any_of(replace.begin(), replace.end(),
|
||||||
|
[¶meter](const auto &s) { return s == parameter.first; }))
|
||||||
|
{
|
||||||
|
const auto pos{uri.find('<')};
|
||||||
|
if (pos != string::npos)
|
||||||
|
{
|
||||||
|
uri.replace(pos, parameter.first.size() + 2,
|
||||||
|
get<string_view>(parameter.second));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void CURLWrapper::add_parameters_to_uri(string &uri,
|
void CURLWrapper::add_parameters_to_uri(string &uri,
|
||||||
const parametermap ¶meters)
|
const parametermap ¶meters)
|
||||||
{
|
{
|
||||||
// Replace <ID> with the value of parameter “id” and so on.
|
// Replace <ID> with the value of parameter “id” and so on.
|
||||||
for (const auto ¶m : parameters)
|
for (const auto ¶m : parameters)
|
||||||
{
|
{
|
||||||
static constexpr array replace_in_uri
|
if (replace_parameter_in_uri(uri, param))
|
||||||
{
|
|
||||||
"id", "nickname", "nickname_or_id",
|
|
||||||
"hashtag", "permission_group"
|
|
||||||
};
|
|
||||||
if (any_of(replace_in_uri.begin(), replace_in_uri.end(),
|
|
||||||
[¶m](const auto &s) { return s == param.first; }))
|
|
||||||
{
|
{
|
||||||
const auto pos{uri.find('<')};
|
continue;
|
||||||
if (pos != string::npos)
|
|
||||||
{
|
|
||||||
uri.replace(pos, param.first.size() + 2,
|
|
||||||
get<string_view>(param.second));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool first{true};
|
static bool first{true};
|
||||||
@ -298,4 +339,70 @@ void CURLWrapper::add_parameters_to_uri(string &uri,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
curl_mime *CURLWrapper::parameters_to_curl_mime(string &uri,
|
||||||
|
const parametermap ¶meters)
|
||||||
|
{
|
||||||
|
debuglog << "Building HTTP form.\n";
|
||||||
|
|
||||||
|
curl_mime *mime{curl_mime_init(_connection)};
|
||||||
|
for (const auto ¶m : parameters)
|
||||||
|
{
|
||||||
|
if (replace_parameter_in_uri(uri, param))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
CURLcode code;
|
||||||
|
if (holds_alternative<string_view>(param.second))
|
||||||
|
{
|
||||||
|
curl_mimepart *part{curl_mime_addpart(mime)};
|
||||||
|
if (part == nullptr)
|
||||||
|
{
|
||||||
|
throw CURLException{"Could not build HTTP form."};
|
||||||
|
}
|
||||||
|
|
||||||
|
code = curl_mime_name(part, param.first.data());
|
||||||
|
if (code != CURLE_OK)
|
||||||
|
{
|
||||||
|
throw CURLException{code, "Could not build HTTP form."};
|
||||||
|
}
|
||||||
|
|
||||||
|
code = curl_mime_data(part, get<string_view>(param.second).data(),
|
||||||
|
CURL_ZERO_TERMINATED);
|
||||||
|
if (code != CURLE_OK)
|
||||||
|
{
|
||||||
|
throw CURLException{code, "Could not build HTTP form."};
|
||||||
|
}
|
||||||
|
debuglog << "Set form part: " << param.first << " = "
|
||||||
|
<< get<string_view>(param.second) << '\n';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (const auto &arg : get<vector<string_view>>(param.second))
|
||||||
|
{
|
||||||
|
curl_mimepart *part{curl_mime_addpart(mime)};
|
||||||
|
if (part == nullptr)
|
||||||
|
{
|
||||||
|
throw CURLException{"Could not build HTTP form."};
|
||||||
|
}
|
||||||
|
|
||||||
|
const string name{string(param.first) += "[]"};
|
||||||
|
code = curl_mime_name(part, name.c_str());
|
||||||
|
if (code != CURLE_OK)
|
||||||
|
{
|
||||||
|
throw CURLException{code, "Could not build HTTP form."};
|
||||||
|
}
|
||||||
|
code = curl_mime_data(part, arg.data(), CURL_ZERO_TERMINATED);
|
||||||
|
if (code != CURLE_OK)
|
||||||
|
{
|
||||||
|
throw CURLException{code, "Could not build HTTP form."};
|
||||||
|
}
|
||||||
|
debuglog << "Set form part: " << name << " = " << arg << '\n';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return mime;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace mastodonpp
|
} // namespace mastodonpp
|
||||||
|
@ -36,10 +36,19 @@ CURLException::CURLException(const CURLcode &error, string message,
|
|||||||
, _error_buffer{move(error_buffer)}
|
, _error_buffer{move(error_buffer)}
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
CURLException::CURLException(string message)
|
||||||
|
: error_code{CURLE_OK}
|
||||||
|
, _message{move(message)}
|
||||||
|
{}
|
||||||
|
|
||||||
const char *CURLException::what() const noexcept
|
const char *CURLException::what() const noexcept
|
||||||
{
|
{
|
||||||
static string error_string{"libCURL error: " + to_string(error_code)
|
static string error_string{"libCURL error: "};
|
||||||
+ " - " + _message};
|
if (error_code != CURLE_OK)
|
||||||
|
{
|
||||||
|
error_string += to_string(error_code) + " - ";
|
||||||
|
}
|
||||||
|
error_string += _message;
|
||||||
if (!_error_buffer.empty())
|
if (!_error_buffer.empty())
|
||||||
{
|
{
|
||||||
error_string += " [" + _error_buffer + "]";
|
error_string += " [" + _error_buffer + "]";
|
||||||
|
@ -20,39 +20,20 @@
|
|||||||
#include <catch.hpp>
|
#include <catch.hpp>
|
||||||
|
|
||||||
#include <exception>
|
#include <exception>
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace mastodonpp
|
namespace mastodonpp
|
||||||
{
|
{
|
||||||
|
|
||||||
using std::string;
|
|
||||||
|
|
||||||
SCENARIO ("Instantiations.")
|
SCENARIO ("mastodonpp::Connection.")
|
||||||
{
|
{
|
||||||
bool exception = false;
|
bool exception = false;
|
||||||
|
|
||||||
WHEN ("Instance is instantiated.")
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Instance instance{"example.com", ""};
|
|
||||||
}
|
|
||||||
catch (const std::exception &e)
|
|
||||||
{
|
|
||||||
exception = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
THEN ("No exception is thrown")
|
|
||||||
{
|
|
||||||
REQUIRE_FALSE(exception);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
WHEN ("Connection is instantiated.")
|
WHEN ("Connection is instantiated.")
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Instance instance{"example.com", ""};
|
Instance instance{"example.com", {}};
|
||||||
Connection connection{instance};
|
Connection connection{instance};
|
||||||
}
|
}
|
||||||
catch (const std::exception &e)
|
catch (const std::exception &e)
|
82
tests/test_instance.cpp
Normal file
82
tests/test_instance.cpp
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
/* This file is part of mastodonpp.
|
||||||
|
* Copyright © 2020 tastytea <tastytea@tastytea.de>
|
||||||
|
*
|
||||||
|
* 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, version 3.
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "instance.hpp"
|
||||||
|
|
||||||
|
#include <catch.hpp>
|
||||||
|
|
||||||
|
#include <exception>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace mastodonpp
|
||||||
|
{
|
||||||
|
|
||||||
|
using std::string;
|
||||||
|
|
||||||
|
SCENARIO ("mastopp::Instance")
|
||||||
|
{
|
||||||
|
bool exception = false;
|
||||||
|
|
||||||
|
WHEN ("Instance is instantiated.")
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Instance instance{"example.com", {}};
|
||||||
|
}
|
||||||
|
catch (const std::exception &e)
|
||||||
|
{
|
||||||
|
exception = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
THEN ("No exception is thrown")
|
||||||
|
{
|
||||||
|
REQUIRE_FALSE(exception);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WHEN ("Variables are set.")
|
||||||
|
{
|
||||||
|
constexpr auto hostname{"likeable.space"};
|
||||||
|
constexpr auto proxy{"socks4a://[::1]:9050"};
|
||||||
|
constexpr auto access_token{"abc123"};
|
||||||
|
Instance instance{hostname, {}};
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
instance.set_proxy(proxy);
|
||||||
|
instance.set_access_token(access_token);
|
||||||
|
}
|
||||||
|
catch (const std::exception &e)
|
||||||
|
{
|
||||||
|
exception = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
THEN ("No exception is thrown")
|
||||||
|
AND_THEN ("get_proxy() returns the set value.")
|
||||||
|
AND_THEN ("get_access_token() returns the set value.")
|
||||||
|
AND_THEN ("get_hostname() returns the set value.")
|
||||||
|
AND_THEN ("get_baseuri() returns the expected value.")
|
||||||
|
{
|
||||||
|
REQUIRE_FALSE(exception);
|
||||||
|
REQUIRE(instance.get_proxy() == proxy);
|
||||||
|
REQUIRE(instance.get_access_token() == access_token);
|
||||||
|
REQUIRE(instance.get_hostname() == hostname);
|
||||||
|
REQUIRE(instance.get_baseuri() == (string("https://") += hostname));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace mastodonpp
|
Loading…
x
Reference in New Issue
Block a user