Skip to content

Commit eeb00a8

Browse files
authored
Merge pull request #74 from lawmaestro/master
Added support for progress reporting when downloading/uploading
2 parents e7824f4 + b3f7e2b commit eeb00a8

File tree

4 files changed

+93
-0
lines changed

4 files changed

+93
-0
lines changed

README.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,21 @@ The connection object stores the curl easy handle in an instance variable and
159159
uses that for the lifetime of the object. This means curl will [automatically
160160
reuse connections][curl_keepalive] made with that handle.
161161

162+
## Progress callback
163+
164+
Two wrapper functions are provided to setup the progress callback for uploads/downloads.
165+
166+
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.
167+
168+
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`.
169+
170+
```cpp
171+
// set CURLOPT_NOPROGRESS
172+
// set CURLOPT_PROGRESSFUNCTION
173+
conn->SetFileProgressCallback(progressFunc);
174+
// set CURLOPT_PROGRESSDATA
175+
conn->SetFileProgressCallbackData(data);
176+
```
162177
163178
## Thread Safety
164179
restclient-cpp leans heavily on libcurl as it aims to provide a thin wrapper

include/restclient-cpp/connection.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,10 @@ class Connection {
8181
* Member 'followRedirects' contains whether or not to follow redirects
8282
* @var Info::maxRedirects
8383
* Member 'maxRedirects' contains the maximum number of redirect to follow (-1 unlimited)
84+
* @var Info::progressFn
85+
* Member 'progressFn' file progress callback function
86+
* @var Info::progressFnData
87+
* Member 'progressFnData' file progress callback data
8488
* @var Info::basicAuth
8589
* Member 'basicAuth' contains information about basic auth
8690
* @var basicAuth::username
@@ -109,6 +113,8 @@ class Connection {
109113
bool followRedirects;
110114
int maxRedirects;
111115
bool noSignal;
116+
curl_progress_callback progressFn;
117+
void* progressFnData;
112118
struct {
113119
std::string username;
114120
std::string password;
@@ -136,6 +142,12 @@ class Connection {
136142
// set connection timeout to seconds
137143
void SetTimeout(int seconds);
138144

145+
// set file progress callback
146+
void SetFileProgressCallback(curl_progress_callback progressFn);
147+
148+
// set file progress callback data
149+
void SetFileProgressCallbackData(void* data);
150+
139151
// set to not use signals
140152
void SetNoSignal(bool no);
141153

@@ -204,6 +216,8 @@ class Connection {
204216
bool followRedirects;
205217
int maxRedirects;
206218
bool noSignal;
219+
curl_progress_callback progressFn;
220+
void* progressFnData;
207221
struct {
208222
std::string username;
209223
std::string password;

source/connection.cc

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ RestClient::Connection::Connection(const std::string& baseUrl)
3636
this->followRedirects = false;
3737
this->maxRedirects = -1l;
3838
this->noSignal = false;
39+
this->progressFn = NULL;
40+
this->progressFnData = NULL;
3941
}
4042

4143
RestClient::Connection::~Connection() {
@@ -60,6 +62,8 @@ RestClient::Connection::GetInfo() {
6062
ret.followRedirects = this->followRedirects;
6163
ret.maxRedirects = this->maxRedirects;
6264
ret.noSignal = this->noSignal;
65+
ret.progressFn = this->progressFn;
66+
ret.progressFnData = this->progressFnData;
6367
ret.basicAuth.username = this->basicAuth.username;
6468
ret.basicAuth.password = this->basicAuth.password;
6569
ret.customUserAgent = this->customUserAgent;
@@ -188,6 +192,29 @@ RestClient::Connection::SetNoSignal(bool no) {
188192
this->noSignal = no;
189193
}
190194

195+
/**
196+
* @brief set file progress callback function
197+
*
198+
* @param callback function pointer
199+
*
200+
*/
201+
void
202+
RestClient::Connection::SetFileProgressCallback(curl_progress_callback
203+
progressFn) {
204+
this->progressFn = progressFn;
205+
}
206+
207+
/**
208+
* @brief set file progress callback data
209+
*
210+
* @param callback data pointer
211+
*
212+
*/
213+
void
214+
RestClient::Connection::SetFileProgressCallbackData(void* data) {
215+
this->progressFnData = data;
216+
}
217+
191218
/**
192219
* @brief set username and password for basic auth
193220
*
@@ -354,6 +381,23 @@ RestClient::Connection::performCurlRequest(const std::string& uri) {
354381
curl_easy_setopt(this->curlHandle, CURLOPT_NOSIGNAL, 1);
355382
}
356383

384+
// set file progress callback
385+
if (this->progressFn) {
386+
curl_easy_setopt(this->curlHandle, CURLOPT_NOPROGRESS, 0);
387+
curl_easy_setopt(this->curlHandle,
388+
CURLOPT_PROGRESSFUNCTION,
389+
this->progressFn);
390+
if (this->progressFnData) {
391+
curl_easy_setopt(this->curlHandle,
392+
CURLOPT_PROGRESSDATA,
393+
this->progressFnData);
394+
} else {
395+
curl_easy_setopt(this->curlHandle,
396+
CURLOPT_PROGRESSDATA,
397+
this);
398+
}
399+
}
400+
357401
// if provided, supply CA path
358402
if (!this->caInfoFilePath.empty()) {
359403
curl_easy_setopt(this->curlHandle, CURLOPT_CAINFO,

test/test_connection.cc

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,26 @@ TEST_F(ConnectionTest, TestNoSignal)
232232
EXPECT_EQ(200, res.code);
233233
}
234234

235+
TEST_F(ConnectionTest, TestSetProgress)
236+
{
237+
static double totalToDownload = 0;
238+
static double totalDownloaded = 0;
239+
240+
auto progressCallback = [](void* pData, double downloadTotal, double downloaded, double uploadTotal, double uploaded) -> int {
241+
totalToDownload = downloadTotal;
242+
totalDownloaded = downloaded;
243+
return 0;
244+
};
245+
246+
conn->SetFileProgressCallback(progressCallback);
247+
conn->SetFileProgressCallbackData(NULL);
248+
249+
RestClient::Response res = conn->get("/anything/{test_data}");
250+
EXPECT_EQ(200, res.code);
251+
EXPECT_GT(totalDownloaded, 0);
252+
EXPECT_EQ(totalDownloaded, totalToDownload);
253+
}
254+
235255
TEST_F(ConnectionTest, TestProxy)
236256
{
237257
conn->SetProxy("127.0.0.1:3128");

0 commit comments

Comments
 (0)