Skip to content

Commit 2cd043e

Browse files
authored
Merge pull request #36 from RuleOfThrees/multiasync_doc
Documentation for MultiAsync
2 parents 9d19399 + f212342 commit 2cd043e

File tree

1 file changed

+49
-23
lines changed

1 file changed

+49
-23
lines changed

advanced-usage.md

Lines changed: 49 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ std::cout << r.header["Content-Type"] << std::endl;
8787
std::cout << r.header["CoNtEnT-tYpE"] << std::endl;
8888
```
8989
90-
All of these should print the same value, `"application/json"`.
90+
All of these should print the same value, `"application/json"`.
9191
9292
On the other hand, Cookies are accessed through a vector-like interface, and you could access and check kinds of fields of a cookie:
9393
@@ -101,7 +101,7 @@ for(const auto &cookie : r.cookies) {
101101
std::cout << cookie.GetExpiresString() << ":";
102102
std::cout << cookie.GetName() << ":";
103103
std::cout << cookie.GetValue() << std::endl;
104-
// For example, this will print:
104+
// For example, this will print:
105105
// www.httpbin.org:0:/:0:Thu, 01 Jan 1970 00:00:00 GMT:cookies:yummy
106106
}
107107
```
@@ -147,7 +147,7 @@ std::cout << r.text << std::endl;
147147
/*
148148
* "headers": {
149149
* "Accept": "application/json",
150-
* "Accept-Encoding": "deflate, gzip",
150+
* "Accept-Encoding": "deflate, gzip",
151151
* "Authorization": "token",
152152
* "Host": "www.httpbin.org",
153153
* "User-Agent": "curl/7.81.0"
@@ -253,21 +253,21 @@ cpr::Response response = session.Complete(curl_result);
253253
254254
## HTTP Compression
255255
256-
HTTP compression is a capability that can improve transfer speed and bandwidth utilization between web servers and web clients.
257-
When you issue a HTTP request, you could specify the supported compression schemes in the header: Accept-Encoding.
256+
HTTP compression is a capability that can improve transfer speed and bandwidth utilization between web servers and web clients.
257+
When you issue a HTTP request, you could specify the supported compression schemes in the header: Accept-Encoding.
258258
With this setting, you could avoid unexpected compression schemes or use the desired schemes:
259259
260260
{% raw %}
261261
```c++
262262
cpr::Response r = cpr::Get(cpr::Url{"http://www.httpbin.org/get"},
263-
cpr::AcceptEncoding{{cpr::AcceptEncodingMethods::deflate, cpr::AcceptEncodingMethods::gzip, cpr::AcceptEncodingMethods::zlib}});
263+
cpr::AcceptEncoding{{cpr::AcceptEncodingMethods::deflate, cpr::AcceptEncodingMethods::gzip, cpr::AcceptEncodingMethods::zlib}});
264264
// or you could specify specific schemes with the customized string
265265
cpr::Response r = cpr::Get(cpr::Url{"http://www.httpbin.org/get"},
266-
cpr::AcceptEncoding{{"deflate", "gzip", "zlib"}});
266+
cpr::AcceptEncoding{{"deflate", "gzip", "zlib"}});
267267
```
268268
{% endraw %}
269269

270-
Also, you could use `cpr::Session` to make the connection stateful:
270+
Also, you could use `cpr::Session` to make the connection stateful:
271271

272272
{% raw %}
273273
```c++
@@ -310,7 +310,7 @@ cpr::Response r = fr.get(); // This blocks until the request is complete
310310
std::cout << r.text << std::endl;
311311
```
312312
313-
The call is otherwise identical except instead of `Get`, it's `GetAsync`. Similarly for POST requests, you would call `PostAsync`. The return value of an asynchronous call is actually a `std::future<Response>`:
313+
The call is otherwise identical except instead of `Get`, it's `GetAsync`. Similarly for POST requests, you would call `PostAsync`. The return value of an asynchronous call is actually an `AsyncWrapper<Response>`, which exposes public member functions analogous to those of [`std::future<T>`](https://en.cppreference.com/w/cpp/thread/future):
314314
315315
```c++
316316
cpr::AsyncResponse fr = cpr::GetAsync(cpr::Url{"http://www.httpbin.org/get"});
@@ -323,19 +323,45 @@ You can even put a bunch of requests into a `std` container and get them all lat
323323

324324
{% raw %}
325325
```c++
326-
std::vector<std::future<cpr::Response>> container{};
326+
std::vector<cpr::AsyncResponse> container{};
327327
cpr::Url url = cpr::Url{"http://www.httpbin.org/get"};
328328
for (int i = 0; i < 10; ++i) {
329329
container.emplace_back(cpr::GetAsync(url, cpr::Parameters{{"i", std::to_string(i)}}));
330330
}
331331
// Sometime later
332-
for (std::future<cpr::Response>& fr: container) {
333-
cpr::Response r = fr.get();
332+
for (cpr::AsyncResponse& ar: container) {
333+
cpr::Response r = ar.get();
334334
std::cout << r.text << std::endl;
335335
}
336336
```
337337
{% endraw %}
338338

339+
Alternatively, you can use the `Multi<method>Async` to bundle multiple requests and execute them in parallel. The requests' parameters are delivered as positional arguments to an async method of your choice, packed in `std::tuple` or `std::array`s, just like the `Multi<method>` API functions. `MultiAsync` makes use of `cpr`'s threadpool-based parallelism, and also offers the capability to **cancel transactions** while they are underway. Here's an example:
340+
341+
{% raw %}
342+
```c++
343+
// The second template parameter denotes a cancellable transaction
344+
using AsyncResC = cpr::AsyncWrapper<Response, true>;
345+
346+
cpr::Url postUrl{"http://www.httpbin.org/post"};
347+
std::vector<AsyncResC>responses{MultiPostAsync(
348+
std::tuple{post_url, cpr::Payload{{"name", "Alice"}}},
349+
std::tuple{post_url, cpr::Payload{{"role", "admin"}}}
350+
// ...
351+
)};
352+
// If the first transaction isn't completed within 10 ms, we'd like to cancel all of them
353+
bool all_cancelled{false};
354+
if(responses.at(0).wait_for(std::chrono::milliseconds(10)) == std::future_status::timeout) {
355+
all_cancelled = true;
356+
for(AsyncResC& res: responses) {
357+
all_cancelled &= (res.Cancel() == CancellationResult::success);
358+
}
359+
}
360+
// If not cancelled, process results
361+
```
362+
{% endraw %}
363+
364+
339365
Asynchronous requests can also be performed using a `cpr::Session` object. It is important to note that the asynchronous request is performed directly on the session object, modifying it in the process.
340366
To ensure that the lifetime of the session is properly extended, the session object used **must be** managed by a `std::shared_ptr`. This restriction is necessary because the implementation uses `std::shared_from_this` to pass a pointer to the ansynchronous lambda function which would otherwise throw a `std::bad_weak_ptr` exception.
341367
Here is an example for an asynchronous get request which uses a session object:
@@ -586,7 +612,7 @@ for(const auto &cookie : r.cookies) {
586612
std::cout << cookie.GetExpiresString() << ":";
587613
std::cout << cookie.GetName() << ":";
588614
std::cout << cookie.GetValue() << std::endl;
589-
// For example, this will print:
615+
// For example, this will print:
590616
// www.httpbin.org:0:/:0:Thu, 01 Jan 1970 00:00:00 GMT:cookies:yummy
591617
}
592618
```
@@ -988,7 +1014,7 @@ X509v3 Authority Key Identifier:keyid:0A:BC:08:29:17:8C:A5:39:6D:7A:0E:CE:33:C7:
9881014
It is also possible to specify the outgoing interface used by [libcurl](http://curl.haxx.se/libcurl/).
9891015
By default the TCP stack decides which interface to use for this request.
9901016
You can change this behavior by passing the `cpr::Interface` option to your request.
991-
Passing an empty string corresponds to passing a `nullptr` to `CURLOPT_INTERFACE`.
1017+
Passing an empty string corresponds to passing a `nullptr` to `CURLOPT_INTERFACE`.
9921018
Further details: https://curl.se/libcurl/c/CURLOPT_INTERFACE.html
9931019

9941020
{% raw %}
@@ -1079,7 +1105,7 @@ std::cout << r.text << std::endl;
10791105
/*
10801106
* {
10811107
* "headers": {
1082-
* "Range": "bytes=1-5",
1108+
* "Range": "bytes=1-5",
10831109
* ...
10841110
* }
10851111
* }
@@ -1097,7 +1123,7 @@ std::cout << r.text << std::endl;
10971123
/*
10981124
* {
10991125
* "headers": {
1100-
* "Range": "bytes=-5",
1126+
* "Range": "bytes=-5",
11011127
* ...
11021128
* }
11031129
* }
@@ -1109,13 +1135,13 @@ Moreover, multiple ranges can be specified in a single request with `cpr::MultiR
11091135
11101136
{% raw %}
11111137
```c++
1112-
cpr::Response r = cpr::Get(cpr::Url{"http://www.httpbin.org/headers"},
1138+
cpr::Response r = cpr::Get(cpr::Url{"http://www.httpbin.org/headers"},
11131139
cpr::MultiRange{cpr::Range{1, 3}, cpr::Range{5, 6}});
11141140
std::cout << r.text << std::endl;
11151141
/*
11161142
* {
11171143
* "headers": {
1118-
* "Range": "bytes=1-3, 5-6",
1144+
* "Range": "bytes=1-3, 5-6",
11191145
* ...
11201146
* }
11211147
* }
@@ -1129,7 +1155,7 @@ As always, there is of course also the possibility to set the range of a session
11291155
```c++
11301156
cpr::Session session;
11311157
session.SetOption(cpr::Range{1, 3}); // Alternative: SetRange()
1132-
session.SetOption(cpr::MultiRange{cpr::Range{1, 3},
1158+
session.SetOption(cpr::MultiRange{cpr::Range{1, 3},
11331159
cpr::Range{5, 6}}); // Alternative: SetMultiRange()
11341160
```
11351161
{% endraw %}
@@ -1141,7 +1167,7 @@ Cpr offers the possibility to pass user-implemented interceptors to a session, w
11411167
### Single Session
11421168
11431169
Each interceptor implementation must inherit from the abstract class `cpr::Interceptor` for intercepting regular `cpr::Sessions` objects.
1144-
The inherited class has to implement the function `cpr::Response intercept(cpr::Session& session)`.
1170+
The inherited class has to implement the function `cpr::Response intercept(cpr::Session& session)`.
11451171
This function is automatically called for every added interceptor during the request with the session object belonging to the request passed as a parameter.
11461172
An essential point of the intercept function is that it must call the `cpr::Response proceed(Session& session)` function implemented in `cpr::Interceptor`.
11471173
This is necessary to continue the request and get the `cpr::Response` object.
@@ -1198,7 +1224,7 @@ Response response = session.Get();
11981224
```
11991225
{% endraw %}
12001226

1201-
It should be noted that interceptors can make changes to the session object that is later passed to the proceed function and can thus fundamentally change the request. Of course, the returned response object can also be modified.
1227+
It should be noted that interceptors can make changes to the session object that is later passed to the proceed function and can thus fundamentally change the request. Of course, the returned response object can also be modified.
12021228

12031229
In addition, interceptors can even change the http method of the request by passing the proceed method another parameter of the enum type `cpr::Interceptor::ProceedHttpMethod`. The parameter required for download requests is also simply passed to the proceed method. For example we can implement an interceptor which changes the request method to `HEAD`:
12041230

@@ -1218,7 +1244,7 @@ class ChangeRequestMethodToHeadInterceptor : public Interceptor {
12181244
12191245
It is also possible to intercept `cpr::InterceptorMulti` calls.
12201246
Each interceptor implementation must inherit from the abstract class `cpr::InterceptorMulti` for intercepting `cpr::MultiPerform` objects.
1221-
The inherited class has to implement the function `std::vector<Response> intercept(MultiPerform&)`.
1247+
The inherited class has to implement the function `std::vector<Response> intercept(MultiPerform&)`.
12221248
This function is automatically called for every added interceptor during the request with the session object belonging to the request passed as a parameter.
12231249
An essential point of the intercept function is that it must call the `std::vector<Response> proceed()` for `cpr::InterceptorMulti`) function implemented in `cpr::Interceptor` (`cpr::InterceptorMulti`). This is necessary to continue the request and get the `cpr::Response` (`std::vector<Response>`) object.
12241250
@@ -1338,7 +1364,7 @@ It is possible to specify which IP address should a specific domain name and por
13381364
{% raw %}
13391365
```c++
13401366
cpr::Response getResponse = cpr::Get(cpr::Url{"https://www.example.com"},
1341-
std::vector<cpr::Resolve>({cpr::Resolve{"www.example.com", "127.0.0.1", {443}},
1367+
std::vector<cpr::Resolve>({cpr::Resolve{"www.example.com", "127.0.0.1", {443}},
13421368
cpr::Resolve{"www.example.com", "127.0.0.2", {80}}},
13431369
cpr::Resolve{"subdomain.example.com", "127.0.0.3"}}));
13441370
// Not specifying any ports defaults to 80 and 443

0 commit comments

Comments
 (0)