Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,21 @@ The connection object stores the curl easy handle in an instance variable and
uses that for the lifetime of the object. This means curl will [automatically
reuse connections][curl_keepalive] made with that handle.

## Progress callback

Two wrapper functions are provided to setup the progress callback for uploads/downloads.

Calling `conn->SetFileProgressCallback(callback)` with a callback parameter matching the prototype `int progress_callback(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow)` will setup the progress callback.

Calling `conn->SetFileProgressCallbackData(data)` is optional. This will set the data pointer which is the first parameter fed back to the progress callback - `clientp`. If this isn't set then `clientp` will default to the connection object `conn`.

```cpp
// set CURLOPT_NOPROGRESS
// set CURLOPT_PROGRESSFUNCTION
conn->SetFileProgressCallback(progressFunc);
// set CURLOPT_PROGRESSDATA
conn->SetFileProgressCallbackData(data);
```

## Thread Safety
restclient-cpp leans heavily on libcurl as it aims to provide a thin wrapper
Expand Down
14 changes: 14 additions & 0 deletions include/restclient-cpp/connection.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@ class Connection {
* Member 'followRedirects' contains whether or not to follow redirects
* @var Info::maxRedirects
* Member 'maxRedirects' contains the maximum number of redirect to follow (-1 unlimited)
* @var Info::progressFn
* Member 'progressFn' file progress callback function
* @var Info::progressFnData
* Member 'progressFnData' file progress callback data
* @var Info::basicAuth
* Member 'basicAuth' contains information about basic auth
* @var basicAuth::username
Expand Down Expand Up @@ -109,6 +113,8 @@ class Connection {
bool followRedirects;
int maxRedirects;
bool noSignal;
curl_progress_callback progressFn;
void* progressFnData;
struct {
std::string username;
std::string password;
Expand Down Expand Up @@ -136,6 +142,12 @@ class Connection {
// set connection timeout to seconds
void SetTimeout(int seconds);

// set file progress callback
void SetFileProgressCallback(curl_progress_callback progressFn);

// set file progress callback data
void SetFileProgressCallbackData(void* data);

// set to not use signals
void SetNoSignal(bool no);

Expand Down Expand Up @@ -204,6 +216,8 @@ class Connection {
bool followRedirects;
int maxRedirects;
bool noSignal;
curl_progress_callback progressFn;
void* progressFnData;
struct {
std::string username;
std::string password;
Expand Down
44 changes: 44 additions & 0 deletions source/connection.cc
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ RestClient::Connection::Connection(const std::string& baseUrl)
this->followRedirects = false;
this->maxRedirects = -1l;
this->noSignal = false;
this->progressFn = NULL;
this->progressFnData = NULL;
}

RestClient::Connection::~Connection() {
Expand All @@ -60,6 +62,8 @@ RestClient::Connection::GetInfo() {
ret.followRedirects = this->followRedirects;
ret.maxRedirects = this->maxRedirects;
ret.noSignal = this->noSignal;
ret.progressFn = this->progressFn;
ret.progressFnData = this->progressFnData;
ret.basicAuth.username = this->basicAuth.username;
ret.basicAuth.password = this->basicAuth.password;
ret.customUserAgent = this->customUserAgent;
Expand Down Expand Up @@ -188,6 +192,29 @@ RestClient::Connection::SetNoSignal(bool no) {
this->noSignal = no;
}

/**
* @brief set file progress callback function
*
* @param callback function pointer
*
*/
void
RestClient::Connection::SetFileProgressCallback(curl_progress_callback
progressFn) {
this->progressFn = progressFn;
}

/**
* @brief set file progress callback data
*
* @param callback data pointer
*
*/
void
RestClient::Connection::SetFileProgressCallbackData(void* data) {
this->progressFnData = data;
}

/**
* @brief set username and password for basic auth
*
Expand Down Expand Up @@ -354,6 +381,23 @@ RestClient::Connection::performCurlRequest(const std::string& uri) {
curl_easy_setopt(this->curlHandle, CURLOPT_NOSIGNAL, 1);
}

// set file progress callback
if (this->progressFn) {
curl_easy_setopt(this->curlHandle, CURLOPT_NOPROGRESS, 0);
curl_easy_setopt(this->curlHandle,
CURLOPT_PROGRESSFUNCTION,
this->progressFn);
if (this->progressFnData) {
curl_easy_setopt(this->curlHandle,
CURLOPT_PROGRESSDATA,
this->progressFnData);
} else {
curl_easy_setopt(this->curlHandle,
CURLOPT_PROGRESSDATA,
this);
}
}

// if provided, supply CA path
if (!this->caInfoFilePath.empty()) {
curl_easy_setopt(this->curlHandle, CURLOPT_CAINFO,
Expand Down
20 changes: 20 additions & 0 deletions test/test_connection.cc
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,26 @@ TEST_F(ConnectionTest, TestNoSignal)
EXPECT_EQ(200, res.code);
}

TEST_F(ConnectionTest, TestSetProgress)
{
static double totalToDownload = 0;
static double totalDownloaded = 0;

auto progressCallback = [](void* pData, double downloadTotal, double downloaded, double uploadTotal, double uploaded) -> int {
totalToDownload = downloadTotal;
totalDownloaded = downloaded;
return 0;
};

conn->SetFileProgressCallback(progressCallback);
conn->SetFileProgressCallbackData(NULL);

RestClient::Response res = conn->get("/anything/{test_data}");
EXPECT_EQ(200, res.code);
EXPECT_GT(totalDownloaded, 0);
EXPECT_EQ(totalDownloaded, totalToDownload);
}

TEST_F(ConnectionTest, TestProxy)
{
conn->SetProxy("127.0.0.1:3128");
Expand Down