Rename Request() to Send().

master
Chunting Gu 6 years ago
parent 1a21989b2e
commit ad1016734e

@ -4,7 +4,7 @@
Lightweight C++ HTTP client and server library based on [Boost Asio](https://www.boost.org/doc/libs/release/libs/asio/). Lightweight C++ HTTP client and server library based on [Boost Asio](https://www.boost.org/doc/libs/release/libs/asio/).
Please turn to our [Wiki](https://github.com/sprinfall/webcc/wiki) (under construction) for more tutorials and guides. Please turn to our [Wiki](https://github.com/sprinfall/webcc/wiki) for more tutorials and guides.
Wondering how to build Webcc? Check [Build Instructions](https://github.com/sprinfall/webcc/wiki/Build-Instructions). Wondering how to build Webcc? Check [Build Instructions](https://github.com/sprinfall/webcc/wiki/Build-Instructions).
@ -12,7 +12,7 @@ Git repo: https://github.com/sprinfall/webcc. Please check this one instead of t
**Features** **Features**
- Cross-platform: Linux, Windows and Mac - Cross-platform: Windows, Linux and MacOS
- Easy-to-use client API inspired by Python [requests](https://2.python-requests.org//en/master/) - Easy-to-use client API inspired by Python [requests](https://2.python-requests.org//en/master/)
- SSL/HTTPS support with OpenSSL (optional) - SSL/HTTPS support with OpenSSL (optional)
- GZip compression support with Zlib (optional) - GZip compression support with Zlib (optional)
@ -25,7 +25,6 @@ Git repo: https://github.com/sprinfall/webcc. Please check this one instead of t
- Source code follows [Google C++ Style](https://google.github.io/styleguide/cppguide.html) - Source code follows [Google C++ Style](https://google.github.io/styleguide/cppguide.html)
- Automation tests and unit tests included - Automation tests and unit tests included
- No memory leak detected by [VLD](https://kinddragon.github.io/vld/) - No memory leak detected by [VLD](https://kinddragon.github.io/vld/)
- etc.
## Client API ## Client API
@ -48,7 +47,9 @@ int main() {
// Catch exceptions for error handling. // Catch exceptions for error handling.
try { try {
// Send a HTTP GET request. // Send a HTTP GET request.
auto r = session.Get("http://httpbin.org/get"); auto r = session.Send(webcc::RequestBuilder{}.
Get("http://httpbin.org/get")
());
// Print the response data. // Print the response data.
std::cout << r->data() << std::endl; std::cout << r->data() << std::endl;
@ -61,46 +62,30 @@ int main() {
} }
``` ```
The `Get()` method is nothing but a shortcut of `Request()`. Using `Request()` directly is more complicated:
```cpp
auto r = session.Request(webcc::RequestBuilder{}.Get("http://httpbin.org/get")());
```
As you can see, a helper class named `RequestBuilder` is used to chain the parameters and finally build a request object. Please pay attention to the `()` operator. As you can see, a helper class named `RequestBuilder` is used to chain the parameters and finally build a request object. Please pay attention to the `()` operator.
Both the shortcut and `Request()` accept URL query parameters: URL query parameters can be easily added through `Query()` method:
```cpp ```cpp
// Query parameters are passed using a std::vector. session.Send(webcc::RequestBuilder{}.
session.Get("http://httpbin.org/get", { "key1", "value1", "key2", "value2" }); Get("http://httpbin.org/get").
Query("key1", "value1").Query("key2", "value2")
session.Request(webcc::RequestBuilder{}. ());
Get("http://httpbin.org/get").
Query("key1", "value1").
Query("key2", "value2")
());
``` ```
Adding additional headers is also easy: Adding additional headers is also easy:
```cpp ```cpp
session.Get("http://httpbin.org/get", session.Send(webcc::RequestBuilder{}.
{"key1", "value1", "key2", "value2"}, Get("http://httpbin.org/get").
{"Accept", "application/json"}); // Also a std::vector Header("Accept", "application/json")
());
session.Request(webcc::RequestBuilder{}.
Get("http://httpbin.org/get").
Query("key1", "value1").
Query("key2", "value2").
Header("Accept", "application/json")
());
``` ```
Accessing HTTPS has no difference from HTTP: Accessing HTTPS has no difference from HTTP:
```cpp ```cpp
session.Get("https://httpbin.org/get"); session.Send(webcc::RequestBuilder{}.Get("https://httpbin.org/get")());
``` ```
*NOTE: The HTTPS/SSL support requires the build option `WEBCC_ENABLE_SSL` to be enabled.* *NOTE: The HTTPS/SSL support requires the build option `WEBCC_ENABLE_SSL` to be enabled.*
@ -108,38 +93,40 @@ session.Get("https://httpbin.org/get");
Listing GitHub public events is not a big deal: Listing GitHub public events is not a big deal:
```cpp ```cpp
auto r = session.Get("https://api.github.com/events"); auto r = session.Send(webcc::RequestBuilder{}.
Get("https://api.github.com/events")
());
``` ```
You can then parse `r->data()` to JSON object with your favorite JSON library. My choice for the examples is [jsoncpp](https://github.com/open-source-parsers/jsoncpp). But Webcc itself doesn't understand JSON nor require one. It's up to you to choose the most appropriate JSON library. You can then parse `r->data()` to JSON object with your favorite JSON library. My choice for the examples is [jsoncpp](https://github.com/open-source-parsers/jsoncpp). But Webcc itself doesn't understand JSON nor require one. It's up to you to choose the most appropriate JSON library.
The shortcuts (`Get()`, `Post()`, etc.) are easier to use but `RequestBuilder` is more powerful. It provides a lot of functions for you to customize the request. Let's see more examples. `RequestBuilder` provides a lot of functions for you to customize the request. Let's see more examples.
In order to list the followers of an authorized GitHub user, you need either **Basic Authorization**: In order to list the followers of an authorized GitHub user, you need either **Basic Authorization**:
```cpp ```cpp
session.Request(webcc::RequestBuilder{}. session.Send(webcc::RequestBuilder{}.
Get("https://api.github.com/user/followers"). Get("https://api.github.com/user/followers").
AuthBasic(login, password) // Should be replaced by real login and password AuthBasic(login, password) // Should be replaced by valid login and passwords
()); ());
``` ```
Or **Token Authorization**: Or **Token Authorization**:
```cpp ```cpp
session.Request(webcc::RequestBuilder{}. session.Send(webcc::RequestBuilder{}.
Get("https://api.github.com/user/followers"). Get("https://api.github.com/user/followers").
AuthToken(token) // Should be replaced by a valid token AuthToken(token) // Should be replaced by a valid token
()); ());
``` ```
Though **Keep-Alive** (i.e., persistent connection) is a good feature and enabled by default, you can turn it off: Though **Keep-Alive** (i.e., persistent connection) is a good feature and enabled by default, you can turn it off:
```cpp ```cpp
auto r = session.Request(webcc::RequestBuilder{}. auto r = session.Send(webcc::RequestBuilder{}.
Get("http://httpbin.org/get"). Get("http://httpbin.org/get").
KeepAlive(false) // No Keep-Alive KeepAlive(false) // No Keep-Alive
()); ());
``` ```
The API for other HTTP requests is no different from GET. The API for other HTTP requests is no different from GET.
@ -147,24 +134,36 @@ The API for other HTTP requests is no different from GET.
POST request needs a body which is normally a JSON string for REST API. Let's post a small UTF-8 encoded JSON string: POST request needs a body which is normally a JSON string for REST API. Let's post a small UTF-8 encoded JSON string:
```cpp ```cpp
session.Request(webcc::RequestBuilder{}. session.Send(webcc::RequestBuilder{}.
Post("http://httpbin.org/post"). Post("http://httpbin.org/post").
Body("{'name'='Adam', 'age'=20}"). Body("{'name'='Adam', 'age'=20}").Json().Utf8()
Json().Utf8() ());
());
``` ```
Webcc has the ability to stream large response data to a file. This is especially useful when downloading files. Webcc has the ability to stream large response data to a file. This is especially useful when downloading files.
```cpp ```cpp
auto r = session.Request(webcc::RequestBuilder{}. auto r = session.Send(webcc::RequestBuilder{}.
Get("http://httpbin.org/image/jpeg")(), Get("http://httpbin.org/image/jpeg")
true); // !!! (), true); // stream = true
// Move the streamed file to your destination. // Move the streamed file to your destination.
r->file_body()->Move("./wolf.jpeg"); r->file_body()->Move("./wolf.jpeg");
``` ```
Streaming is also available for uploading:
```cpp
auto r = session.Send(webcc::RequestBuilder{}.
Post("http://httpbin.org/post").
File(path) // Should be replaced by a valid file path
());
```
The file will not be loaded into the memory all at once, instead, it will be read and sent piece by piece.
Please note that `Content-Length` header will still be set to the true size of the file, this is different from the handling of chunked data (`Transfer-Encoding: chunked`).
Please check the [examples](https://github.com/sprinfall/webcc/tree/master/examples/) for more information. Please check the [examples](https://github.com/sprinfall/webcc/tree/master/examples/) for more information.
## Server API ## Server API

@ -41,7 +41,9 @@ int main() {
try { try {
// 发起一个 HTTP GET 请求 // 发起一个 HTTP GET 请求
auto r = session.Get("http://httpbin.org/get"); auto r = session.Send(webcc::RequestBuilder{}.
Get("http://httpbin.org/get")
());
// 输出响应数据 // 输出响应数据
std::cout << r->data() << std::endl; std::cout << r->data() << std::endl;
@ -55,47 +57,30 @@ int main() {
} }
``` ```
因为 `Get()` 不过是 `Request()` 的一种快捷方式,直接调用 `Request()` 会更复杂一些: 如你所见,这里通过一个辅助类 `RequestBuilder`,串联起各种参数,最后再生成一个请求对象。注意不要漏了最后的 `()` 操作符。
```cpp 通过 `Query()` 可以方便地指定 URL 查询参数:
auto r = session.Request(webcc::RequestBuilder{}.Get("http://httpbin.org/get")());
```
这里多了个辅助类 `RequestBuilder`,用来串联起各种参数,最后再生成一个请求对象。注意不要漏了 `()` 操作符。
不管是 `Get` 还是 `Request()`,都接受 URL 查询参数:
```cpp ```cpp
// 查询参数由 std::vector 一起指定,键值成对出现 session.Send(webcc::RequestBuilder{}.
session.Get("http://httpbin.org/get", { "key1", "value1", "key2", "value2" }); Get("http://httpbin.org/get").
Query("key1", "value1").Query("key2", "value2")
// 查询参数由 Query() 挨个指定 ());
session.Request(webcc::RequestBuilder{}.
Get("http://httpbin.org/get").
Query("key1", "value1").
Query("key2", "value2")
());
``` ```
要添加额外的头部也很简单: 要添加额外的头部也很简单:
```cpp ```cpp
session.Get("http://httpbin.org/get", session.Send(webcc::RequestBuilder{}.
{"key1", "value1", "key2", "value2"}, Get("http://httpbin.org/get").
{"Accept", "application/json"}); // 也是 std::vector Header("Accept", "application/json")
());
session.Request(webcc::RequestBuilder{}.
Get("http://httpbin.org/get").
Query("key1", "value1").
Query("key2", "value2").
Header("Accept", "application/json")
());
``` ```
访问 HTTPS 和访问 HTTP 没有差别,对用户是透明的: 访问 HTTPS 和访问 HTTP 没有差别,对用户是透明的:
```cpp ```cpp
session.Get("https://httpbin.org/get"); session.Send(webcc::RequestBuilder{}.Get("https://httpbin.org/get")());
``` ```
*注意:对 HTTPS/SSL 的支持,需要启用编译选项 `WEBCC_ENABLE_SSL`,也会依赖 OpenSSL。* *注意:对 HTTPS/SSL 的支持,需要启用编译选项 `WEBCC_ENABLE_SSL`,也会依赖 OpenSSL。*
@ -103,40 +88,42 @@ session.Get("https://httpbin.org/get");
列出 GitHub 公开事件 (public events) 也不是什么难题: 列出 GitHub 公开事件 (public events) 也不是什么难题:
```cpp ```cpp
auto r = session.Get("https://api.github.com/events"); auto r = session.Send(webcc::RequestBuilder{}.
Get("https://api.github.com/events")
());
``` ```
然后,你可以把 `r->data()` 解析成 JSON 对象,随便用个什么 JSON 程序库。 然后,你可以把 `r->data()` 解析成 JSON 对象,随便用个什么 JSON 程序库。
我在示例程序里用的是 [jsoncpp](https://github.com/open-source-parsers/jsoncpp),但是 Webcc 本身并不理解 JSON用什么 JSON 程序库,完全是你自己的选择。 我在示例程序里用的是 [jsoncpp](https://github.com/open-source-parsers/jsoncpp),但是 Webcc 本身并不理解 JSON用什么 JSON 程序库,完全是你自己的选择。
快捷函数(`Get()``Post()`,等)用起来方便,但是参数有限,限制比较多。`RequestBuilder` 更灵活更强大,它提供了很多函数供你定制请求的样子。 `RequestBuilder` 本质上是为了解决 C++ 没有“键值参数”的问题,它提供了很多函数供你定制请求的样子。
为了列出一个授权的 (authorized) GitHub 用户的“粉丝” (followers),要么使用 **Basic 认证** 为了列出一个授权的 (authorized) GitHub 用户的“粉丝” (followers),要么使用 **Basic 认证**
```cpp ```cpp
session.Request(webcc::RequestBuilder{}. session.Send(webcc::RequestBuilder{}.
Get("https://api.github.com/user/followers"). Get("https://api.github.com/user/followers").
AuthBasic(login, password) // 应该替换成具体的账号、密码 AuthBasic(login, password) // 应该替换成具体的账号、密码
()); ());
``` ```
要么使用 **Token 认证** 要么使用 **Token 认证**
```cpp ```cpp
session.Request(webcc::RequestBuilder{}. session.Send(webcc::RequestBuilder{}.
Get("https://api.github.com/user/followers"). Get("https://api.github.com/user/followers").
AuthToken(token) // 应该替换成具体合法的 token AuthToken(token) // 应该替换成具体合法的 token
()); ());
``` ```
尽管**持久连接** (Keep-Alive) 这个功能不错,你也可以手动关掉它: 尽管 **持久连接** (Keep-Alive) 这个功能不错,你也可以手动关掉它:
```cpp ```cpp
auto r = session.Request(webcc::RequestBuilder{}. auto r = session.Send(webcc::RequestBuilder{}.
Get("http://httpbin.org/get"). Get("http://httpbin.org/get").
KeepAlive(false) // 不要 Keep-Alive KeepAlive(false) // 不要 Keep-Alive
()); ());
``` ```
其他 HTTP 请求的 API 跟 GET 并无太多差别。 其他 HTTP 请求的 API 跟 GET 并无太多差别。
@ -144,19 +131,18 @@ auto r = session.Request(webcc::RequestBuilder{}.
POST 请求需要一个“体” (body),就 REST API 来说通常是一个 JSON 字符串。让我们 POST 一个 UTF-8 编码的 JSON 字符串: POST 请求需要一个“体” (body),就 REST API 来说通常是一个 JSON 字符串。让我们 POST 一个 UTF-8 编码的 JSON 字符串:
```cpp ```cpp
session.Request(webcc::RequestBuilder{}. session.Send(webcc::RequestBuilder{}.
Post("http://httpbin.org/post"). Post("http://httpbin.org/post").
Body("{'name'='Adam', 'age'=20}"). Body("{'name'='Adam', 'age'=20}").Json().Utf8()
Json().Utf8() ());
());
``` ```
Webcc 可以把大型的响应数据串流到临时文件,串流在下载文件时特别有用。 Webcc 可以把大型的响应数据串流到临时文件,串流在下载文件时特别有用。
```cpp ```cpp
auto r = session.Request(webcc::RequestBuilder{}. auto r = session.Send(webcc::RequestBuilder{}.
Get("http://httpbin.org/image/jpeg")(), Get("http://httpbin.org/image/jpeg")
true); // stream = true (), true); // stream = true
// 把串流的文件移到目标位置 // 把串流的文件移到目标位置
r->file_body()->Move("./wolf.jpeg"); r->file_body()->Move("./wolf.jpeg");
@ -165,13 +151,13 @@ r->file_body()->Move("./wolf.jpeg");
不光下载,上传也可以串流: 不光下载,上传也可以串流:
```cpp ```cpp
auto r = session.Request(webcc::RequestBuilder{}. auto r = session.Send(webcc::RequestBuilder{}.
Post("http://httpbin.org/post"). Post("http://httpbin.org/post").
File(path) // 应该替换成具体的文件路径 File(path) // 应该替换成具体的文件路径
()); ());
``` ```
这个文件在 POST 时,不会一次加载到内存,读一块数据发一块数据,直到发送完。 这个文件在 POST 时,不会一次加载到内存,而是读一块数据发一块数据,直到发送完。
注意,`Content-Length` 头部还是会设置为文件的真实大小,不同于 `Transfer-Encoding: chunked` 的分块数据形式。 注意,`Content-Length` 头部还是会设置为文件的真实大小,不同于 `Transfer-Encoding: chunked` 的分块数据形式。

@ -37,9 +37,9 @@ TEST(ClientTest, Head) {
webcc::ClientSession session; webcc::ClientSession session;
try { try {
auto r = session.Request(webcc::RequestBuilder{}. auto r = session.Send(webcc::RequestBuilder{}.
Head("http://httpbin.org/get") Head("http://httpbin.org/get")
()); ());
EXPECT_EQ(webcc::Status::kOK, r->status()); EXPECT_EQ(webcc::Status::kOK, r->status());
EXPECT_EQ("OK", r->reason()); EXPECT_EQ("OK", r->reason());
@ -59,10 +59,10 @@ TEST(ClientTest, Head_AcceptEncodingIdentity) {
webcc::ClientSession session; webcc::ClientSession session;
try { try {
auto r = session.Request(webcc::RequestBuilder{}. auto r = session.Send(webcc::RequestBuilder{}.
Head("http://httpbin.org/get"). Head("http://httpbin.org/get").
Header("Accept-Encoding", "identity") Header("Accept-Encoding", "identity")
()); ());
EXPECT_EQ(webcc::Status::kOK, r->status()); EXPECT_EQ(webcc::Status::kOK, r->status());
EXPECT_EQ("OK", r->reason()); EXPECT_EQ("OK", r->reason());
@ -106,12 +106,11 @@ TEST(ClientTest, Get) {
webcc::ClientSession session; webcc::ClientSession session;
try { try {
auto r = session.Request(webcc::RequestBuilder{}. auto r = session.Send(webcc::RequestBuilder{}.
Get("http://httpbin.org/get"). Get("http://httpbin.org/get").
Query("key1", "value1"). Query("key1", "value1").Query("key2", "value2").
Query("key2", "value2"). Header("Accept", "application/json")
Header("Accept", "application/json") ());
());
AssertGet(r); AssertGet(r);
@ -125,10 +124,9 @@ TEST(ClientTest, Get_QueryEncode) {
webcc::ClientSession session; webcc::ClientSession session;
try { try {
auto r = session.Request(webcc::RequestBuilder{}. auto r = session.Send(webcc::RequestBuilder{}.Get("http://httpbin.org/get").
Get("http://httpbin.org/get"). Query("name", "Chunting Gu", true)
Query("name", "Chunting Gu", true) ());
());
EXPECT_EQ(webcc::Status::kOK, r->status()); EXPECT_EQ(webcc::Status::kOK, r->status());
EXPECT_EQ("OK", r->reason()); EXPECT_EQ("OK", r->reason());
@ -151,12 +149,11 @@ TEST(ClientTest, Get_SSL) {
try { try {
// HTTPS is auto-detected from the URL scheme. // HTTPS is auto-detected from the URL scheme.
auto r = session.Request(webcc::RequestBuilder{}. auto r = session.Send(webcc::RequestBuilder{}.
Get("https://httpbin.org/get"). Get("https://httpbin.org/get").
Query("key1", "value1"). Query("key1", "value1").Query("key2", "value2").
Query("key2", "value2"). Header("Accept", "application/json")
Header("Accept", "application/json") ());
());
AssertGet(r); AssertGet(r);
@ -171,9 +168,9 @@ TEST(ClientTest, Get_Jpeg_NoStream) {
webcc::ClientSession session; webcc::ClientSession session;
try { try {
auto r = session.Request(webcc::RequestBuilder{}. auto r = session.Send(webcc::RequestBuilder{}.
Get("http://httpbin.org/image/jpeg") Get("http://httpbin.org/image/jpeg")
()); ());
// TODO: Verify the response is a valid JPEG image. // TODO: Verify the response is a valid JPEG image.
//std::ofstream ofs(<path>, std::ios::binary); //std::ofstream ofs(<path>, std::ios::binary);
@ -188,10 +185,9 @@ TEST(ClientTest, Get_Jpeg_Stream) {
webcc::ClientSession session; webcc::ClientSession session;
try { try {
auto r = session.Request(webcc::RequestBuilder{}. auto r = session.Send(webcc::RequestBuilder{}.
Get("http://httpbin.org/image/jpeg") Get("http://httpbin.org/image/jpeg")
(), (), true);
true);
auto file_body = r->file_body(); auto file_body = r->file_body();
@ -227,10 +223,9 @@ TEST(ClientTest, Get_Jpeg_Stream_NoMove) {
webcc::Path ori_path; webcc::Path ori_path;
{ {
auto r = session.Request(webcc::RequestBuilder{}. auto r = session.Send(webcc::RequestBuilder{}.
Get("http://httpbin.org/image/jpeg") Get("http://httpbin.org/image/jpeg")
(), (), true);
true);
auto file_body = r->file_body(); auto file_body = r->file_body();
@ -258,9 +253,9 @@ TEST(ClientTest, Get_Gzip) {
webcc::ClientSession session; webcc::ClientSession session;
try { try {
auto r = session.Request(webcc::RequestBuilder{}. auto r = session.Send(webcc::RequestBuilder{}.
Get("http://httpbin.org/gzip") Get("http://httpbin.org/gzip")
()); ());
Json::Value json = StringToJson(r->data()); Json::Value json = StringToJson(r->data());
@ -278,9 +273,9 @@ TEST(ClientTest, Get_Deflate) {
webcc::ClientSession session; webcc::ClientSession session;
try { try {
auto r = session.Request(webcc::RequestBuilder{}. auto r = session.Send(webcc::RequestBuilder{}.
Get("http://httpbin.org/deflate") Get("http://httpbin.org/deflate")
()); ());
Json::Value json = StringToJson(r->data()); Json::Value json = StringToJson(r->data());
@ -300,10 +295,9 @@ TEST(ClientTest, Post) {
try { try {
const std::string data = "{'name'='Adam', 'age'=20}"; const std::string data = "{'name'='Adam', 'age'=20}";
auto r = session.Request(webcc::RequestBuilder{}. auto r = session.Send(webcc::RequestBuilder{}.
Post("http://httpbin.org/post"). Post("http://httpbin.org/post").Body(data).Json()
Body(data).Json() ());
());
EXPECT_EQ(webcc::Status::kOK, r->status()); EXPECT_EQ(webcc::Status::kOK, r->status());
EXPECT_EQ("OK", r->reason()); EXPECT_EQ("OK", r->reason());
@ -347,10 +341,9 @@ TEST(ClientTest, Post_FileBody) {
} }
try { try {
auto r = session.Request(webcc::RequestBuilder{}. auto r = session.Send(webcc::RequestBuilder{}.
Post("http://httpbin.org/post"). Post("http://httpbin.org/post").File(path)
File(path) // Use the file as body ());
());
EXPECT_EQ(webcc::Status::kOK, r->status()); EXPECT_EQ(webcc::Status::kOK, r->status());
EXPECT_EQ("OK", r->reason()); EXPECT_EQ("OK", r->reason());
@ -377,11 +370,10 @@ TEST(ClientTest, Post_Gzip_SmallData) {
const std::string data = "{'name'='Adam', 'age'=20}"; const std::string data = "{'name'='Adam', 'age'=20}";
// This doesn't really compress the body! // This doesn't really compress the body!
auto r = session.Request(webcc::RequestBuilder{}. auto r = session.Send(webcc::RequestBuilder{}.
Post("http://httpbin.org/post"). Post("http://httpbin.org/post").Body(data).Json().
Body(data).Json(). Gzip()
Gzip() ());
());
//Json::Value json = StringToJson(r->data()); //Json::Value json = StringToJson(r->data());
@ -398,16 +390,15 @@ TEST(ClientTest, Post_Gzip) {
try { try {
// Use Boost.org home page as the POST data. // Use Boost.org home page as the POST data.
auto r1 = session.Request(webcc::RequestBuilder{}. auto r1 = session.Send(webcc::RequestBuilder{}.
Get("https://www.boost.org/") Get("https://www.boost.org/")
()); ());
const std::string& data = r1->data(); const std::string& data = r1->data();
auto r2 = session.Request(webcc::RequestBuilder{}. auto r2 = session.Send(webcc::RequestBuilder{}.
Post("http://httpbin.org/post"). Post("http://httpbin.org/post").Body(data).Gzip()
Body(data).Gzip() ());
());
EXPECT_EQ(webcc::Status::kOK, r2->status()); EXPECT_EQ(webcc::Status::kOK, r2->status());
EXPECT_EQ("OK", r2->reason()); EXPECT_EQ("OK", r2->reason());
@ -440,33 +431,26 @@ TEST(ClientTest, KeepAlive) {
try { try {
// Keep-Alive by default. // Keep-Alive by default.
auto r = session.Request(webcc::RequestBuilder{}.Get(url)()); auto r = session.Send(webcc::RequestBuilder{}.Get(url)());
using boost::iequals; using boost::iequals;
EXPECT_TRUE(iequals(r->GetHeader("Connection"), "Keep-alive")); EXPECT_TRUE(iequals(r->GetHeader("Connection"), "Keep-alive"));
// Close by setting Connection header directly. // Close by setting Connection header directly.
r = session.Request(webcc::RequestBuilder{}. r = session.Send(webcc::RequestBuilder{}.Get(url).
Get(url). Header("Connection", "Close")
Header("Connection", "Close") ());
());
EXPECT_TRUE(iequals(r->GetHeader("Connection"), "Close")); EXPECT_TRUE(iequals(r->GetHeader("Connection"), "Close"));
// Close by using request builder. // Close by using request builder.
r = session.Request(webcc::RequestBuilder{}. r = session.Send(webcc::RequestBuilder{}.Get(url).KeepAlive(false)());
Get(url).
KeepAlive(false)
());
EXPECT_TRUE(iequals(r->GetHeader("Connection"), "Close")); EXPECT_TRUE(iequals(r->GetHeader("Connection"), "Close"));
// Keep-Alive explicitly by using request builder. // Keep-Alive explicitly by using request builder.
r = session.Request(webcc::RequestBuilder{}. r = session.Send(webcc::RequestBuilder{}.Get(url).KeepAlive(true)());
Get(url).
KeepAlive(true)
());
EXPECT_TRUE(iequals(r->GetHeader("Connection"), "Keep-alive")); EXPECT_TRUE(iequals(r->GetHeader("Connection"), "Keep-alive"));

@ -12,30 +12,28 @@ int main() {
webcc::ResponsePtr r; webcc::ResponsePtr r;
try { try {
r = session.Request(webcc::RequestBuilder{}. r = session.Send(webcc::RequestBuilder{}.
Get("http://httpbin.org/get"). Get("http://httpbin.org/get").
Query("name", "Adam Gu", /*encode*/true). Query("name", "Adam Gu", /*encode*/true).
Header("Accept", "application/json"). Header("Accept", "application/json").Date()
Date() ());
());
assert(r->status() == webcc::Status::kOK); assert(r->status() == webcc::Status::kOK);
assert(!r->data().empty()); assert(!r->data().empty());
r = session.Request(webcc::RequestBuilder{}. r = session.Send(webcc::RequestBuilder{}.
Post("http://httpbin.org/post"). Post("http://httpbin.org/post").
Body("{'name'='Adam', 'age'=20}"). Body("{'name'='Adam', 'age'=20}").Json().Utf8()
Json().Utf8() ());
());
assert(r->status() == webcc::Status::kOK); assert(r->status() == webcc::Status::kOK);
assert(!r->data().empty()); assert(!r->data().empty());
#if WEBCC_ENABLE_SSL #if WEBCC_ENABLE_SSL
r = session.Request(webcc::RequestBuilder{}. r = session.Send(webcc::RequestBuilder{}.
Get("https://httpbin.org/get") Get("https://httpbin.org/get")
()); ());
assert(r->status() == webcc::Status::kOK); assert(r->status() == webcc::Status::kOK);
assert(!r->data().empty()); assert(!r->data().empty());

@ -26,8 +26,7 @@ int main(int argc, char* argv[]) {
webcc::ClientSession session; webcc::ClientSession session;
try { try {
auto r = session.Request(webcc::RequestBuilder{}.Get(url)(), auto r = session.Send(webcc::RequestBuilder{}.Get(url)(), true);
true); // Stream the response data to file.
if (auto file_body = r->file_body()) { if (auto file_body = r->file_body()) {
file_body->Move(path); file_body->Move(path);

@ -41,11 +41,10 @@ int main(int argc, char* argv[]) {
webcc::ClientSession session; webcc::ClientSession session;
try { try {
auto r = session.Request(webcc::RequestBuilder{}. auto r = session.Send(webcc::RequestBuilder{}.Post(url).
Post(url). FormFile("file", upload_dir / "remember.txt").
FormFile("file", upload_dir / "remember.txt"). FormData("json", "{}", "application/json")
FormData("json", "{}", "application/json") ());
());
std::cout << r->status() << std::endl; std::cout << r->status() << std::endl;

@ -55,9 +55,8 @@ void PrettyPrintJsonString(const std::string& str) {
// List public events. // List public events.
void ListEvents(webcc::ClientSession& session) { void ListEvents(webcc::ClientSession& session) {
try { try {
auto r = session.Request(webcc::RequestBuilder{}. auto r = session.Send(webcc::RequestBuilder{}.Get(kUrlRoot).Path("events")
Get(kUrlRoot).Path("events") ());
());
PRINT_JSON_STRING(r->data()); PRINT_JSON_STRING(r->data());
@ -71,10 +70,9 @@ void ListEvents(webcc::ClientSession& session) {
// ListUserFollowers(session, "<user>") // ListUserFollowers(session, "<user>")
void ListUserFollowers(webcc::ClientSession& session, const std::string& user) { void ListUserFollowers(webcc::ClientSession& session, const std::string& user) {
try { try {
auto r = session.Request(webcc::RequestBuilder{}. auto r = session.Send(webcc::RequestBuilder{}.Get(kUrlRoot).
Get(kUrlRoot).Path("users").Path(user). Path("users").Path(user).Path("followers")
Path("followers") ());
());
PRINT_JSON_STRING(r->data()); PRINT_JSON_STRING(r->data());
@ -90,10 +88,9 @@ void ListAuthUserFollowers(webcc::ClientSession& session,
const std::string& login, const std::string& login,
const std::string& password) { const std::string& password) {
try { try {
auto r = session.Request(webcc::RequestBuilder{}. auto r = session.Send(webcc::RequestBuilder{}.Get(kUrlRoot).
Get(kUrlRoot).Path("user/followers"). Path("user/followers").AuthBasic(login, password)
AuthBasic(login, password) ());
());
PRINT_JSON_STRING(r->data()); PRINT_JSON_STRING(r->data());
@ -112,12 +109,10 @@ void CreateAuthorization(webcc::ClientSession& session,
" 'scopes': ['public_repo', 'repo', 'repo:status', 'user']\n" " 'scopes': ['public_repo', 'repo', 'repo:status', 'user']\n"
"}"; "}";
auto r = session.Request(webcc::RequestBuilder{}. auto r = session.Send(webcc::RequestBuilder{}.Post(kUrlRoot).
Post(kUrlRoot).Path("authorizations"). Path("authorizations").AuthBasic(login, password).
Body(std::move(data)). Body(std::move(data)).Json().Utf8()
Json().Utf8(). ());
AuthBasic(login, password)
());
std::cout << r->data() << std::endl; std::cout << r->data() << std::endl;

@ -57,7 +57,7 @@ BookClient::BookClient(const std::string& url, int timeout)
bool BookClient::ListBooks(std::list<Book>* books) { bool BookClient::ListBooks(std::list<Book>* books) {
try { try {
auto r = session_.Request(WEBCC_GET(url_).Path("books")()); auto r = session_.Send(WEBCC_GET(url_).Path("books")());
if (!CheckStatus(r, webcc::Status::kOK)) { if (!CheckStatus(r, webcc::Status::kOK)) {
// Response HTTP status error. // Response HTTP status error.
@ -89,9 +89,9 @@ bool BookClient::CreateBook(const std::string& title, double price,
req_json["price"] = price; req_json["price"] = price;
try { try {
auto r = session_.Request(WEBCC_POST(url_).Path("books"). auto r = session_.Send(WEBCC_POST(url_).Path("books").
Body(JsonToString(req_json)) Body(JsonToString(req_json))
()); ());
if (!CheckStatus(r, webcc::Status::kCreated)) { if (!CheckStatus(r, webcc::Status::kCreated)) {
return false; return false;
@ -110,7 +110,7 @@ bool BookClient::CreateBook(const std::string& title, double price,
bool BookClient::GetBook(const std::string& id, Book* book) { bool BookClient::GetBook(const std::string& id, Book* book) {
try { try {
auto r = session_.Request(WEBCC_GET(url_).Path("books").Path(id)()); auto r = session_.Send(WEBCC_GET(url_).Path("books").Path(id)());
if (!CheckStatus(r, webcc::Status::kOK)) { if (!CheckStatus(r, webcc::Status::kOK)) {
return false; return false;
@ -131,9 +131,9 @@ bool BookClient::UpdateBook(const std::string& id, const std::string& title,
json["price"] = price; json["price"] = price;
try { try {
auto r = session_.Request(WEBCC_PUT(url_).Path("books").Path(id). auto r = session_.Send(WEBCC_PUT(url_).Path("books").Path(id).
Body(JsonToString(json)) Body(JsonToString(json))
()); ());
if (!CheckStatus(r, webcc::Status::kOK)) { if (!CheckStatus(r, webcc::Status::kOK)) {
return false; return false;
@ -149,7 +149,7 @@ bool BookClient::UpdateBook(const std::string& id, const std::string& title,
bool BookClient::DeleteBook(const std::string& id) { bool BookClient::DeleteBook(const std::string& id) {
try { try {
auto r = session_.Request(WEBCC_DELETE(url_).Path("books").Path(id)()); auto r = session_.Send(WEBCC_DELETE(url_).Path("books").Path(id)());
if (!CheckStatus(r, webcc::Status::kOK)) { if (!CheckStatus(r, webcc::Status::kOK)) {
return false; return false;

@ -28,7 +28,7 @@ void ClientSession::AuthToken(const std::string& token) {
return Auth("Token", token); return Auth("Token", token);
} }
ResponsePtr ClientSession::Request(RequestPtr request, bool stream) { ResponsePtr ClientSession::Send(RequestPtr request, bool stream) {
assert(request); assert(request);
for (auto& h : headers_.data()) { for (auto& h : headers_.data()) {
@ -44,7 +44,7 @@ ResponsePtr ClientSession::Request(RequestPtr request, bool stream) {
request->Prepare(); request->Prepare();
return Send(request, stream); return DoSend(request, stream);
} }
void ClientSession::InitHeaders() { void ClientSession::InitHeaders() {
@ -85,7 +85,7 @@ void ClientSession::InitHeaders() {
headers_.Set(kConnection, "Keep-Alive"); headers_.Set(kConnection, "Keep-Alive");
} }
ResponsePtr ClientSession::Send(RequestPtr request, bool stream) { ResponsePtr ClientSession::DoSend(RequestPtr request, bool stream) {
const ClientPool::Key key{ request->url() }; const ClientPool::Key key{ request->url() };
// Reuse a pooled connection. // Reuse a pooled connection.

@ -61,12 +61,12 @@ public:
// the response body will be FileBody, and you can easily move the temp file // the response body will be FileBody, and you can easily move the temp file
// to another path with FileBody::Move(). So, |stream| is really useful for // to another path with FileBody::Move(). So, |stream| is really useful for
// downloading files (JPEG, etc.) or saving memory for huge data responses. // downloading files (JPEG, etc.) or saving memory for huge data responses.
ResponsePtr Request(RequestPtr request, bool stream = false); ResponsePtr Send(RequestPtr request, bool stream = false);
private: private:
void InitHeaders(); void InitHeaders();
ResponsePtr Send(RequestPtr request, bool stream); ResponsePtr DoSend(RequestPtr request, bool stream);
private: private:
// Default media type for `Content-Type` header. // Default media type for `Content-Type` header.

Loading…
Cancel
Save