Merge lp:~gary-wzl77/net-cpp/bug-fixing-and-features into lp:net-cpp
- bug-fixing-and-features
- Merge into trunk
Status: | Merged | ||||||||
---|---|---|---|---|---|---|---|---|---|
Merged at revision: | 50 | ||||||||
Proposed branch: | lp:~gary-wzl77/net-cpp/bug-fixing-and-features | ||||||||
Merge into: | lp:net-cpp | ||||||||
Diff against target: |
804 lines (+407/-9) 14 files modified
CMakeLists.txt (+2/-2) include/core/net/http/client.h (+19/-0) include/core/net/http/method.h (+3/-1) include/core/net/http/request.h (+21/-0) include/core/net/http/streaming_client.h (+21/-1) include/core/net/http/streaming_request.h (+13/-0) src/core/net/http/impl/curl/client.cpp (+82/-2) src/core/net/http/impl/curl/client.h (+7/-0) src/core/net/http/impl/curl/easy.cpp (+23/-0) src/core/net/http/impl/curl/easy.h (+14/-1) src/core/net/http/impl/curl/request.h (+33/-0) tests/http_client_test.cpp (+73/-0) tests/http_streaming_client_test.cpp (+90/-2) tests/httpbin.h.in (+6/-0) |
||||||||
To merge this branch: | bzr merge lp:~gary-wzl77/net-cpp/bug-fixing-and-features | ||||||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Thomas Voß (community) | Approve | ||
Review via email: mp+291975@code.launchpad.net |
Commit message
1.Fix crash issue when sending large chunk data via PUT method (lp:1570686)
3.Support DELETE method (lp:1570687)
2.Support POST method with istream
4.Support pause and resume mechanism
5.Add some test cases
Description of the change
1.Fix crash issue when sending large chunk data via PUT method (lp:1570686)
3.Support DELETE method (lp:1570687)
2.Support POST method with istream
4.Support pause and resume mechanism
5.Add some test cases
Thomas Voß (thomas-voss) wrote : | # |
Thanks for your changes, the MP looks good to me. I tried to further understand your remarks about only setting abort_request_
Hope that addresses your remark :) Or did I miss something?
Gary.Wang (gary-wzl77) wrote : | # |
Thanks, Please add the following test case in http_streaming_
http://
Then we can see the potential issue we have in this MP after it is run. (I use the async api to reproduce this issue.)
Log:
....
Download progress: 0.0154666
Download progress: 0.0154666
we pause
Download progress: 0.0154666
Download progress: 0.0154666
Download progress: 0.0154666
we resume.
I resume download after the request is paused for 5 secs. But there is no "Download progress" log printing out any more even if I resume it. It causes the curl thread to hang as well. The issue can be reproduces 100%.
However if I explicitly set async_abort_
Log:
Download progress: 0.0077333
Download progress: 0.0077333
Download progress: 0.0077333
we pause
Download progress: 0.0077333
we resume.
Download progress: 0.0077333
Download progress: 0.0077333
Download progress: 0.0077333
Download progress: 0.00883806
Download progress: 0.00883806
So it's better to mention this case in doc somewhere to reminder developer of setting abort_request_
Otherwise developer doesn't figure out why it doesn't work out after resuming from paused state.
But anyway, it works fine if developers don't use pause/resume API.
P.S:
curl utilizes progress callback(
Preview Diff
1 | === modified file 'CMakeLists.txt' | |||
2 | --- CMakeLists.txt 2015-04-01 06:23:30 +0000 | |||
3 | +++ CMakeLists.txt 2016-05-23 10:51:40 +0000 | |||
4 | @@ -26,8 +26,8 @@ | |||
5 | 26 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Werror -Wall -fno-strict-aliasing -fvisibility=hidden -fvisibility-inlines-hidden -pedantic -Wextra") | 26 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Werror -Wall -fno-strict-aliasing -fvisibility=hidden -fvisibility-inlines-hidden -pedantic -Wextra") |
6 | 27 | set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--no-undefined") | 27 | set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--no-undefined") |
7 | 28 | 28 | ||
10 | 29 | set(NET_CPP_VERSION_MAJOR 1) | 29 | set(NET_CPP_VERSION_MAJOR 2) |
11 | 30 | set(NET_CPP_VERSION_MINOR 2) | 30 | set(NET_CPP_VERSION_MINOR 0) |
12 | 31 | set(NET_CPP_VERSION_PATCH 0) | 31 | set(NET_CPP_VERSION_PATCH 0) |
13 | 32 | 32 | ||
14 | 33 | include(CTest) | 33 | include(CTest) |
15 | 34 | 34 | ||
16 | === modified file 'include/core/net/http/client.h' | |||
17 | --- include/core/net/http/client.h 2014-06-10 14:19:14 +0000 | |||
18 | +++ include/core/net/http/client.h 2016-05-23 10:51:40 +0000 | |||
19 | @@ -14,6 +14,7 @@ | |||
20 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
21 | 15 | * | 15 | * |
22 | 16 | * Authored by: Thomas Voß <thomas.voss@canonical.com> | 16 | * Authored by: Thomas Voß <thomas.voss@canonical.com> |
23 | 17 | * Gary Wang <gary.wang@canonical.com> | ||
24 | 17 | */ | 18 | */ |
25 | 18 | #ifndef CORE_NET_HTTP_CLIENT_H_ | 19 | #ifndef CORE_NET_HTTP_CLIENT_H_ |
26 | 19 | #define CORE_NET_HTTP_CLIENT_H_ | 20 | #define CORE_NET_HTTP_CLIENT_H_ |
27 | @@ -154,6 +155,16 @@ | |||
28 | 154 | */ | 155 | */ |
29 | 155 | virtual std::shared_ptr<Request> post(const Request::Configuration& configuration, const std::string& payload, const std::string& type) = 0; | 156 | virtual std::shared_ptr<Request> post(const Request::Configuration& configuration, const std::string& payload, const std::string& type) = 0; |
30 | 156 | 157 | ||
31 | 158 | /** | ||
32 | 159 | * @brief post is a convenience method for issuing a POST request for the given URI. | ||
33 | 160 | * @throw Errors::HttpMethodNotSupported if the underlying implementation does not support the pro vided HTTP method. | ||
34 | 161 | * @param configuration The configuration to issue a get request for. | ||
35 | 162 | * @param payload The data to be transmitted as part of the POST request. | ||
36 | 163 | * @param size Size of the payload data in bytes. | ||
37 | 164 | * @return An executable instance of class Request. | ||
38 | 165 | */ | ||
39 | 166 | virtual std::shared_ptr<Request> post(const Request::Configuration& configuration, std::istream& payload, std::size_t size) = 0; | ||
40 | 167 | |||
41 | 157 | /** | 168 | /** |
42 | 158 | * @brief post_form is a convenience method for issuing a POST request for the given URI, with url-encoded payload. | 169 | * @brief post_form is a convenience method for issuing a POST request for the given URI, with url-encoded payload. |
43 | 159 | * @throw Errors::HttpMethodNotSupported if the underlying implementation does not support the provided HTTP method. | 170 | * @throw Errors::HttpMethodNotSupported if the underlying implementation does not support the provided HTTP method. |
44 | @@ -163,6 +174,14 @@ | |||
45 | 163 | */ | 174 | */ |
46 | 164 | virtual std::shared_ptr<Request> post_form(const Request::Configuration& configuration, const std::map<std::string, std::string>& values); | 175 | virtual std::shared_ptr<Request> post_form(const Request::Configuration& configuration, const std::map<std::string, std::string>& values); |
47 | 165 | 176 | ||
48 | 177 | /** | ||
49 | 178 | * @brief del is a convenience method for issueing a DELETE request for the given URI. | ||
50 | 179 | * @throw Errors::HttpMethodNotSupported if the underlying implementation does not support the provided HTTP method. | ||
51 | 180 | * @param configuration The configuration to issue a get request for. | ||
52 | 181 | * @return An executable instance of class Request. | ||
53 | 182 | */ | ||
54 | 183 | virtual std::shared_ptr<Request> del(const Request::Configuration& configuration) = 0; | ||
55 | 184 | |||
56 | 166 | protected: | 185 | protected: |
57 | 167 | Client() = default; | 186 | Client() = default; |
58 | 168 | }; | 187 | }; |
59 | 169 | 188 | ||
60 | === modified file 'include/core/net/http/method.h' | |||
61 | --- include/core/net/http/method.h 2013-12-04 07:23:43 +0000 | |||
62 | +++ include/core/net/http/method.h 2016-05-23 10:51:40 +0000 | |||
63 | @@ -14,6 +14,7 @@ | |||
64 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
65 | 15 | * | 15 | * |
66 | 16 | * Authored by: Thomas Voß <thomas.voss@canonical.com> | 16 | * Authored by: Thomas Voß <thomas.voss@canonical.com> |
67 | 17 | * Gary Wang <gary.wang@canonical.com> | ||
68 | 17 | */ | 18 | */ |
69 | 18 | #ifndef CORE_NET_HTTP_METHOD_H_ | 19 | #ifndef CORE_NET_HTTP_METHOD_H_ |
70 | 19 | #define CORE_NET_HTTP_METHOD_H_ | 20 | #define CORE_NET_HTTP_METHOD_H_ |
71 | @@ -33,7 +34,8 @@ | |||
72 | 33 | get, | 34 | get, |
73 | 34 | head, | 35 | head, |
74 | 35 | post, | 36 | post, |
76 | 36 | put | 37 | put, |
77 | 38 | del | ||
78 | 37 | }; | 39 | }; |
79 | 38 | } | 40 | } |
80 | 39 | } | 41 | } |
81 | 40 | 42 | ||
82 | === modified file 'include/core/net/http/request.h' | |||
83 | --- include/core/net/http/request.h 2014-05-06 11:05:04 +0000 | |||
84 | +++ include/core/net/http/request.h 2016-05-23 10:51:40 +0000 | |||
85 | @@ -14,6 +14,7 @@ | |||
86 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
87 | 15 | * | 15 | * |
88 | 16 | * Authored by: Thomas Voß <thomas.voss@canonical.com> | 16 | * Authored by: Thomas Voß <thomas.voss@canonical.com> |
89 | 17 | * Gary Wang <gary.wang@canonical.com> | ||
90 | 17 | */ | 18 | */ |
91 | 18 | #ifndef CORE_NET_HTTP_REQUEST_H_ | 19 | #ifndef CORE_NET_HTTP_REQUEST_H_ |
92 | 19 | #define CORE_NET_HTTP_REQUEST_H_ | 20 | #define CORE_NET_HTTP_REQUEST_H_ |
93 | @@ -248,6 +249,18 @@ | |||
94 | 248 | virtual void async_execute(const Handler& handler) = 0; | 249 | virtual void async_execute(const Handler& handler) = 0; |
95 | 249 | 250 | ||
96 | 250 | /** | 251 | /** |
97 | 252 | * @brief Pause the request | ||
98 | 253 | * @throw core::net::http::Error in case of http-related errors. | ||
99 | 254 | */ | ||
100 | 255 | virtual void pause() = 0; | ||
101 | 256 | |||
102 | 257 | /** | ||
103 | 258 | * @brief Resume the request | ||
104 | 259 | * @throw core::net::http::Error in case of http-related errors. | ||
105 | 260 | */ | ||
106 | 261 | virtual void resume() = 0; | ||
107 | 262 | |||
108 | 263 | /** | ||
109 | 251 | * @brief Returns the input string in URL-escaped format. | 264 | * @brief Returns the input string in URL-escaped format. |
110 | 252 | * @param s The string to be URL escaped. | 265 | * @param s The string to be URL escaped. |
111 | 253 | */ | 266 | */ |
112 | @@ -259,6 +272,14 @@ | |||
113 | 259 | */ | 272 | */ |
114 | 260 | virtual std::string url_unescape(const std::string& s) = 0; | 273 | virtual std::string url_unescape(const std::string& s) = 0; |
115 | 261 | 274 | ||
116 | 275 | /** | ||
117 | 276 | * @brief Sets options for aborting the request. | ||
118 | 277 | * The request will be aborted if transfer speed belows \a limit bytes per second for \a time seconds | ||
119 | 278 | * @param limit The transfer speed in seconds. | ||
120 | 279 | * @param time waiting period(seconds) to abort the request. | ||
121 | 280 | */ | ||
122 | 281 | virtual void abort_request_if(std::uint64_t limit, const std::chrono::seconds& time) = 0; | ||
123 | 282 | |||
124 | 262 | protected: | 283 | protected: |
125 | 263 | /** @cond */ | 284 | /** @cond */ |
126 | 264 | Request() = default; | 285 | Request() = default; |
127 | 265 | 286 | ||
128 | === modified file 'include/core/net/http/streaming_client.h' | |||
129 | --- include/core/net/http/streaming_client.h 2015-03-23 16:09:05 +0000 | |||
130 | +++ include/core/net/http/streaming_client.h 2016-05-23 10:51:40 +0000 | |||
131 | @@ -14,6 +14,7 @@ | |||
132 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
133 | 15 | * | 15 | * |
134 | 16 | * Authored by: Thomas Voß <thomas.voss@canonical.com> | 16 | * Authored by: Thomas Voß <thomas.voss@canonical.com> |
135 | 17 | * Gary Wang <gary.wang@canonical.com> | ||
136 | 17 | */ | 18 | */ |
137 | 18 | #ifndef CORE_NET_HTTP_STREAMING_CLIENT_H_ | 19 | #ifndef CORE_NET_HTTP_STREAMING_CLIENT_H_ |
138 | 19 | #define CORE_NET_HTTP_STREAMING_CLIENT_H_ | 20 | #define CORE_NET_HTTP_STREAMING_CLIENT_H_ |
139 | @@ -69,7 +70,17 @@ | |||
140 | 69 | * @return An executable instance of class Request. | 70 | * @return An executable instance of class Request. |
141 | 70 | */ | 71 | */ |
142 | 71 | virtual std::shared_ptr<StreamingRequest> streaming_post(const Request::Configuration& configuration, const std::string& payload, const std::string& type) = 0; | 72 | virtual std::shared_ptr<StreamingRequest> streaming_post(const Request::Configuration& configuration, const std::string& payload, const std::string& type) = 0; |
144 | 72 | 73 | ||
145 | 74 | /** | ||
146 | 75 | * @brief streaming_post is a convenience method for issuing a POST request for the given URI. | ||
147 | 76 | * @throw Errors::HttpMethodNotSupported if the underlying implementation does not support the pro vided HTTP method. | ||
148 | 77 | * @param configuration The configuration to issue a get request for. | ||
149 | 78 | * @param payload The data to be transmitted as part of the POST request. | ||
150 | 79 | * @param size Size of the payload data in bytes. | ||
151 | 80 | * @return An executable instance of class Request. | ||
152 | 81 | */ | ||
153 | 82 | virtual std::shared_ptr<StreamingRequest> streaming_post(const Request::Configuration& configuration, std::istream& payload, std::size_t size) = 0; | ||
154 | 83 | |||
155 | 73 | /** | 84 | /** |
156 | 74 | * @brief streaming_post_form is a convenience method for issuing a POST request for the given URI, with url-encoded payload. | 85 | * @brief streaming_post_form is a convenience method for issuing a POST request for the given URI, with url-encoded payload. |
157 | 75 | * @throw Errors::HttpMethodNotSupported if the underlying implementation does not support the provided HTTP method. | 86 | * @throw Errors::HttpMethodNotSupported if the underlying implementation does not support the provided HTTP method. |
158 | @@ -78,6 +89,15 @@ | |||
159 | 78 | * @return An executable instance of class Request. | 89 | * @return An executable instance of class Request. |
160 | 79 | */ | 90 | */ |
161 | 80 | virtual std::shared_ptr<StreamingRequest> streaming_post_form(const Request::Configuration& configuration, const std::map<std::string, std::string>& values) = 0; | 91 | virtual std::shared_ptr<StreamingRequest> streaming_post_form(const Request::Configuration& configuration, const std::map<std::string, std::string>& values) = 0; |
162 | 92 | |||
163 | 93 | |||
164 | 94 | /** | ||
165 | 95 | * @brief streaming_del is a convenience method for issuing a DELETE request for the given URI. | ||
166 | 96 | * @throw Errors::HttpMethodNotSupported if the underlying implementation does not support the provided HTTP method. | ||
167 | 97 | * @param configuration The configuration to issue a del request for. | ||
168 | 98 | * @return An executable instance of class Request. | ||
169 | 99 | */ | ||
170 | 100 | virtual std::shared_ptr<StreamingRequest> streaming_del(const Request::Configuration& configuration) = 0; | ||
171 | 81 | }; | 101 | }; |
172 | 82 | 102 | ||
173 | 83 | /** @brief Dispatches to the default implementation and returns a streaming client instance. */ | 103 | /** @brief Dispatches to the default implementation and returns a streaming client instance. */ |
174 | 84 | 104 | ||
175 | === modified file 'include/core/net/http/streaming_request.h' | |||
176 | --- include/core/net/http/streaming_request.h 2015-03-23 16:09:05 +0000 | |||
177 | +++ include/core/net/http/streaming_request.h 2016-05-23 10:51:40 +0000 | |||
178 | @@ -14,6 +14,7 @@ | |||
179 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
180 | 15 | * | 15 | * |
181 | 16 | * Authored by: Thomas Voß <thomas.voss@canonical.com> | 16 | * Authored by: Thomas Voß <thomas.voss@canonical.com> |
182 | 17 | * Gary Wang <gary.wang@canonical.com> | ||
183 | 17 | */ | 18 | */ |
184 | 18 | #ifndef CORE_NET_HTTP_STREAMING_REQUEST_H_ | 19 | #ifndef CORE_NET_HTTP_STREAMING_REQUEST_H_ |
185 | 19 | #define CORE_NET_HTTP_STREAMING_REQUEST_H_ | 20 | #define CORE_NET_HTTP_STREAMING_REQUEST_H_ |
186 | @@ -52,6 +53,18 @@ | |||
187 | 52 | * @return The response to the request. | 53 | * @return The response to the request. |
188 | 53 | */ | 54 | */ |
189 | 54 | virtual void async_execute(const Handler& handler, const DataHandler& dh) = 0; | 55 | virtual void async_execute(const Handler& handler, const DataHandler& dh) = 0; |
190 | 56 | |||
191 | 57 | /** | ||
192 | 58 | * @brief Pause the request | ||
193 | 59 | * @throw core::net::http::Error in case of http-related errors. | ||
194 | 60 | */ | ||
195 | 61 | virtual void pause() = 0; | ||
196 | 62 | |||
197 | 63 | /** | ||
198 | 64 | * @brief Resume the request | ||
199 | 65 | * @throw core::net::http::Error in case of http-related errors. | ||
200 | 66 | */ | ||
201 | 67 | virtual void resume() = 0; | ||
202 | 55 | }; | 68 | }; |
203 | 56 | } | 69 | } |
204 | 57 | } | 70 | } |
205 | 58 | 71 | ||
206 | === modified file 'src/core/net/http/impl/curl/client.cpp' | |||
207 | --- src/core/net/http/impl/curl/client.cpp 2015-03-23 16:09:05 +0000 | |||
208 | +++ src/core/net/http/impl/curl/client.cpp 2016-05-23 10:51:40 +0000 | |||
209 | @@ -14,6 +14,7 @@ | |||
210 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
211 | 15 | * | 15 | * |
212 | 16 | * Authored by: Thomas Voß <thomas.voss@canonical.com> | 16 | * Authored by: Thomas Voß <thomas.voss@canonical.com> |
213 | 17 | * Gary Wang <gary.wang@canonical.com> | ||
214 | 17 | */ | 18 | */ |
215 | 18 | 19 | ||
216 | 19 | #include "client.h" | 20 | #include "client.h" |
217 | @@ -176,6 +177,39 @@ | |||
218 | 176 | return std::shared_ptr<http::impl::curl::Request>{new http::impl::curl::Request{multi, handle}}; | 177 | return std::shared_ptr<http::impl::curl::Request>{new http::impl::curl::Request{multi, handle}}; |
219 | 177 | } | 178 | } |
220 | 178 | 179 | ||
221 | 180 | std::shared_ptr<http::impl::curl::Request> http::impl::curl::Client::post_impl( | ||
222 | 181 | const Request::Configuration& configuration, | ||
223 | 182 | std::istream& payload, | ||
224 | 183 | std::size_t size) | ||
225 | 184 | { | ||
226 | 185 | ::curl::easy::Handle handle; | ||
227 | 186 | handle.method(http::Method::post) | ||
228 | 187 | .url(configuration.uri.c_str()) | ||
229 | 188 | .header(configuration.header) | ||
230 | 189 | .on_read_data([&payload, size](void* dest, std::size_t in_size, std::size_t nmemb) | ||
231 | 190 | { | ||
232 | 191 | //use internal buffer size(in_size *nmemb) instread of size passed by parameter | ||
233 | 192 | //to avoid client crashing when sending large chuck of data via POST method | ||
234 | 193 | auto result = payload.readsome(static_cast<char *>(dest), in_size * nmemb); | ||
235 | 194 | return result; | ||
236 | 195 | }, size); | ||
237 | 196 | |||
238 | 197 | |||
239 | 198 | handle.set_option(::curl::Option::post_field_size, size); | ||
240 | 199 | handle.set_option(::curl::Option::ssl_verify_host, | ||
241 | 200 | configuration.ssl.verify_host ? ::curl::easy::enable_ssl_host_verification : ::curl::easy::disable); | ||
242 | 201 | handle.set_option(::curl::Option::ssl_verify_peer, | ||
243 | 202 | configuration.ssl.verify_peer ? ::curl::easy::enable : ::curl::easy::disable); | ||
244 | 203 | |||
245 | 204 | if (configuration.authentication_handler.for_http) | ||
246 | 205 | { | ||
247 | 206 | auto credentials = configuration.authentication_handler.for_http(configuration.uri); | ||
248 | 207 | handle.http_credentials(credentials.username, credentials.password); | ||
249 | 208 | } | ||
250 | 209 | |||
251 | 210 | return std::shared_ptr<http::impl::curl::Request>{new http::impl::curl::Request{multi, handle}}; | ||
252 | 211 | } | ||
253 | 212 | |||
254 | 179 | std::shared_ptr<http::impl::curl::Request> http::impl::curl::Client::put_impl( | 213 | std::shared_ptr<http::impl::curl::Request> http::impl::curl::Client::put_impl( |
255 | 180 | const Request::Configuration& configuration, | 214 | const Request::Configuration& configuration, |
256 | 181 | std::istream& payload, | 215 | std::istream& payload, |
257 | @@ -185,9 +219,11 @@ | |||
258 | 185 | handle.method(http::Method::put) | 219 | handle.method(http::Method::put) |
259 | 186 | .url(configuration.uri.c_str()) | 220 | .url(configuration.uri.c_str()) |
260 | 187 | .header(configuration.header) | 221 | .header(configuration.header) |
262 | 188 | .on_read_data([&payload, size](void* dest, std::size_t /*in_size*/, std::size_t /*nmemb*/) | 222 | .on_read_data([&payload, size](void* dest, std::size_t in_size, std::size_t nmemb) |
263 | 189 | { | 223 | { |
265 | 190 | auto result = payload.readsome(static_cast<char*>(dest), size); | 224 | //use internal buffer size(in_size *nmemb) instread of size passed by parameter |
266 | 225 | //to avoid client crashing when sending large chuck of data via PUT method | ||
267 | 226 | auto result = payload.readsome(static_cast<char*>(dest), in_size * nmemb); | ||
268 | 191 | return result; | 227 | return result; |
269 | 192 | }, size); | 228 | }, size); |
270 | 193 | 229 | ||
271 | @@ -205,6 +241,27 @@ | |||
272 | 205 | return std::shared_ptr<http::impl::curl::Request>{new http::impl::curl::Request{multi, handle}}; | 241 | return std::shared_ptr<http::impl::curl::Request>{new http::impl::curl::Request{multi, handle}}; |
273 | 206 | } | 242 | } |
274 | 207 | 243 | ||
275 | 244 | std::shared_ptr<http::impl::curl::Request> http::impl::curl::Client::del_impl(const http::Request::Configuration& configuration) | ||
276 | 245 | { | ||
277 | 246 | ::curl::easy::Handle handle; | ||
278 | 247 | handle.method(http::Method::del) | ||
279 | 248 | .url(configuration.uri.c_str()) | ||
280 | 249 | .header(configuration.header); | ||
281 | 250 | |||
282 | 251 | handle.set_option(::curl::Option::ssl_verify_host, | ||
283 | 252 | configuration.ssl.verify_host ? ::curl::easy::enable_ssl_host_verification : ::curl::easy::disable); | ||
284 | 253 | handle.set_option(::curl::Option::ssl_verify_peer, | ||
285 | 254 | configuration.ssl.verify_peer ? ::curl::easy::enable : ::curl::easy::disable); | ||
286 | 255 | |||
287 | 256 | if (configuration.authentication_handler.for_http) | ||
288 | 257 | { | ||
289 | 258 | auto credentials = configuration.authentication_handler.for_http(configuration.uri); | ||
290 | 259 | handle.http_credentials(credentials.username, credentials.password); | ||
291 | 260 | } | ||
292 | 261 | |||
293 | 262 | return std::shared_ptr<http::impl::curl::Request>{new http::impl::curl::Request{multi, handle}}; | ||
294 | 263 | } | ||
295 | 264 | |||
296 | 208 | std::shared_ptr<http::StreamingRequest> http::impl::curl::Client::streaming_get(const http::Request::Configuration& configuration) | 265 | std::shared_ptr<http::StreamingRequest> http::impl::curl::Client::streaming_get(const http::Request::Configuration& configuration) |
297 | 209 | { | 266 | { |
298 | 210 | return get_impl(configuration); | 267 | return get_impl(configuration); |
299 | @@ -225,6 +282,11 @@ | |||
300 | 225 | return post_impl(configuration, payload, type); | 282 | return post_impl(configuration, payload, type); |
301 | 226 | } | 283 | } |
302 | 227 | 284 | ||
303 | 285 | std::shared_ptr<http::StreamingRequest> http::impl::curl::Client::streaming_post(const http::Request ::Configuration& configuration, std::istream& payload, std::size_t size) | ||
304 | 286 | { | ||
305 | 287 | return post_impl(configuration, payload, size); | ||
306 | 288 | } | ||
307 | 289 | |||
308 | 228 | std::shared_ptr<http::StreamingRequest> http::impl::curl::Client::streaming_post_form(const http::Request::Configuration& configuration, const std::map<std::string, std::string>& values) | 290 | std::shared_ptr<http::StreamingRequest> http::impl::curl::Client::streaming_post_form(const http::Request::Configuration& configuration, const std::map<std::string, std::string>& values) |
309 | 229 | { | 291 | { |
310 | 230 | std::stringstream ss; | 292 | std::stringstream ss; |
311 | @@ -239,6 +301,11 @@ | |||
312 | 239 | return post_impl(configuration, ss.str(), http::ContentType::x_www_form_urlencoded); | 301 | return post_impl(configuration, ss.str(), http::ContentType::x_www_form_urlencoded); |
313 | 240 | } | 302 | } |
314 | 241 | 303 | ||
315 | 304 | std::shared_ptr<http::StreamingRequest> http::impl::curl::Client::streaming_del(const http::Request::Configuration& configuration) | ||
316 | 305 | { | ||
317 | 306 | return del_impl(configuration); | ||
318 | 307 | } | ||
319 | 308 | |||
320 | 242 | std::shared_ptr<http::Request> http::impl::curl::Client::head(const http::Request::Configuration& configuration) | 309 | std::shared_ptr<http::Request> http::impl::curl::Client::head(const http::Request::Configuration& configuration) |
321 | 243 | { | 310 | { |
322 | 244 | return head_impl(configuration); | 311 | return head_impl(configuration); |
323 | @@ -257,6 +324,19 @@ | |||
324 | 257 | return post_impl(configuration, payload, ct); | 324 | return post_impl(configuration, payload, ct); |
325 | 258 | } | 325 | } |
326 | 259 | 326 | ||
327 | 327 | std::shared_ptr<http::Request> http::impl::curl::Client::post( | ||
328 | 328 | const Request::Configuration& configuration, | ||
329 | 329 | std::istream& payload, | ||
330 | 330 | std::size_t size) | ||
331 | 331 | { | ||
332 | 332 | return post_impl(configuration, payload, size); | ||
333 | 333 | } | ||
334 | 334 | |||
335 | 335 | std::shared_ptr<http::Request> http::impl::curl::Client::del(const Request::Configuration& configuration) | ||
336 | 336 | { | ||
337 | 337 | return del_impl(configuration); | ||
338 | 338 | } | ||
339 | 339 | |||
340 | 260 | std::shared_ptr<http::Request> http::impl::curl::Client::put( | 340 | std::shared_ptr<http::Request> http::impl::curl::Client::put( |
341 | 261 | const Request::Configuration& configuration, | 341 | const Request::Configuration& configuration, |
342 | 262 | std::istream& payload, | 342 | std::istream& payload, |
343 | 263 | 343 | ||
344 | === modified file 'src/core/net/http/impl/curl/client.h' | |||
345 | --- src/core/net/http/impl/curl/client.h 2015-03-24 11:56:02 +0000 | |||
346 | +++ src/core/net/http/impl/curl/client.h 2016-05-23 10:51:40 +0000 | |||
347 | @@ -14,6 +14,7 @@ | |||
348 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
349 | 15 | * | 15 | * |
350 | 16 | * Authored by: Thomas Voß <thomas.voss@canonical.com> | 16 | * Authored by: Thomas Voß <thomas.voss@canonical.com> |
351 | 17 | * Gary Wang <gary.wang@canonical.com> | ||
352 | 17 | */ | 18 | */ |
353 | 18 | #ifndef CORE_NET_HTTP_IMPL_CURL_CLIENT_H_ | 19 | #ifndef CORE_NET_HTTP_IMPL_CURL_CLIENT_H_ |
354 | 19 | #define CORE_NET_HTTP_IMPL_CURL_CLIENT_H_ | 20 | #define CORE_NET_HTTP_IMPL_CURL_CLIENT_H_ |
355 | @@ -55,19 +56,25 @@ | |||
356 | 55 | std::shared_ptr<http::Request> get(const Request::Configuration& configuration) override; | 56 | std::shared_ptr<http::Request> get(const Request::Configuration& configuration) override; |
357 | 56 | std::shared_ptr<http::Request> head(const Request::Configuration& configuration) override; | 57 | std::shared_ptr<http::Request> head(const Request::Configuration& configuration) override; |
358 | 57 | std::shared_ptr<http::Request> post(const Request::Configuration& configuration, const std::string&, const std::string&) override; | 58 | std::shared_ptr<http::Request> post(const Request::Configuration& configuration, const std::string&, const std::string&) override; |
359 | 59 | std::shared_ptr<http::Request> post(const Request::Configuration& configuration, std::istream& payload, std::size_t size) override; | ||
360 | 58 | std::shared_ptr<http::Request> put(const Request::Configuration& configuration, std::istream& payload, std::size_t size) override; | 60 | std::shared_ptr<http::Request> put(const Request::Configuration& configuration, std::istream& payload, std::size_t size) override; |
361 | 61 | std::shared_ptr<http::Request> del(const Request::Configuration& configuration) override; | ||
362 | 59 | 62 | ||
363 | 60 | std::shared_ptr<http::StreamingRequest> streaming_get(const Request::Configuration& configuration) override; | 63 | std::shared_ptr<http::StreamingRequest> streaming_get(const Request::Configuration& configuration) override; |
364 | 61 | std::shared_ptr<http::StreamingRequest> streaming_head(const Request::Configuration& configuration) override; | 64 | std::shared_ptr<http::StreamingRequest> streaming_head(const Request::Configuration& configuration) override; |
365 | 62 | std::shared_ptr<http::StreamingRequest> streaming_put(const Request::Configuration& configuration, std::istream& payload, std::size_t size) override; | 65 | std::shared_ptr<http::StreamingRequest> streaming_put(const Request::Configuration& configuration, std::istream& payload, std::size_t size) override; |
366 | 63 | std::shared_ptr<http::StreamingRequest> streaming_post(const Request::Configuration& configuration, const std::string& payload, const std::string& type) override; | 66 | std::shared_ptr<http::StreamingRequest> streaming_post(const Request::Configuration& configuration, const std::string& payload, const std::string& type) override; |
367 | 67 | std::shared_ptr<http::StreamingRequest> streaming_post(const Request::Configuration& configuration, std::istream& payload, std::size_t size) override; | ||
368 | 64 | std::shared_ptr<http::StreamingRequest> streaming_post_form(const Request::Configuration& configuration, const std::map<std::string, std::string>& values) override; | 68 | std::shared_ptr<http::StreamingRequest> streaming_post_form(const Request::Configuration& configuration, const std::map<std::string, std::string>& values) override; |
369 | 69 | std::shared_ptr<http::StreamingRequest> streaming_del(const Request::Configuration& configuration) override; | ||
370 | 65 | 70 | ||
371 | 66 | private: | 71 | private: |
372 | 67 | std::shared_ptr<curl::Request> get_impl(const Request::Configuration& configuration); | 72 | std::shared_ptr<curl::Request> get_impl(const Request::Configuration& configuration); |
373 | 68 | std::shared_ptr<curl::Request> head_impl(const Request::Configuration& configuration); | 73 | std::shared_ptr<curl::Request> head_impl(const Request::Configuration& configuration); |
374 | 69 | std::shared_ptr<curl::Request> post_impl(const Request::Configuration& configuration, const std::string&, const std::string&); | 74 | std::shared_ptr<curl::Request> post_impl(const Request::Configuration& configuration, const std::string&, const std::string&); |
375 | 75 | std::shared_ptr<curl::Request> post_impl(const Request::Configuration& configuration, std::istream& payload, std::size_t size); | ||
376 | 70 | std::shared_ptr<curl::Request> put_impl(const Request::Configuration& configuration, std::istream& payload, std::size_t size); | 76 | std::shared_ptr<curl::Request> put_impl(const Request::Configuration& configuration, std::istream& payload, std::size_t size); |
377 | 77 | std::shared_ptr<curl::Request> del_impl(const Request::Configuration& configuration); | ||
378 | 71 | 78 | ||
379 | 72 | ::curl::multi::Handle multi; | 79 | ::curl::multi::Handle multi; |
380 | 73 | }; | 80 | }; |
381 | 74 | 81 | ||
382 | === modified file 'src/core/net/http/impl/curl/easy.cpp' | |||
383 | --- src/core/net/http/impl/curl/easy.cpp 2015-03-03 11:12:12 +0000 | |||
384 | +++ src/core/net/http/impl/curl/easy.cpp 2016-05-23 10:51:40 +0000 | |||
385 | @@ -14,6 +14,7 @@ | |||
386 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
387 | 15 | * | 15 | * |
388 | 16 | * Authored by: Thomas Voß <thomas.voss@canonical.com> | 16 | * Authored by: Thomas Voß <thomas.voss@canonical.com> |
389 | 17 | * Gary Wang <gary.wang@canonical.com> | ||
390 | 17 | */ | 18 | */ |
391 | 18 | 19 | ||
392 | 19 | #include "easy.h" | 20 | #include "easy.h" |
393 | @@ -96,6 +97,11 @@ | |||
394 | 96 | return static_cast<curl::Code>(curl_easy_perform(handle)); | 97 | return static_cast<curl::Code>(curl_easy_perform(handle)); |
395 | 97 | } | 98 | } |
396 | 98 | 99 | ||
397 | 100 | ::curl::Code easy::native::pause(easy::native::Handle handle, int bitmask) | ||
398 | 101 | { | ||
399 | 102 | return static_cast<curl::Code>(curl_easy_pause(handle, bitmask)); | ||
400 | 103 | } | ||
401 | 104 | |||
402 | 99 | std::string easy::native::escape(easy::native::Handle handle, const std::string& in) | 105 | std::string easy::native::escape(easy::native::Handle handle, const std::string& in) |
403 | 100 | { | 106 | { |
404 | 101 | auto escaped = curl_easy_escape(handle, in.c_str(), in.size()); | 107 | auto escaped = curl_easy_escape(handle, in.c_str(), in.size()); |
405 | @@ -355,6 +361,8 @@ | |||
406 | 355 | { | 361 | { |
407 | 356 | if (!d) throw easy::Handle::HandleHasBeenAbandoned{}; | 362 | if (!d) throw easy::Handle::HandleHasBeenAbandoned{}; |
408 | 357 | 363 | ||
409 | 364 | static constexpr const char* http_delete = "DELETE"; | ||
410 | 365 | |||
411 | 358 | switch(method) | 366 | switch(method) |
412 | 359 | { | 367 | { |
413 | 360 | case core::net::http::Method::get: | 368 | case core::net::http::Method::get: |
414 | @@ -371,6 +379,9 @@ | |||
415 | 371 | case core::net::http::Method::put: | 379 | case core::net::http::Method::put: |
416 | 372 | set_option(Option::http_put, enable); | 380 | set_option(Option::http_put, enable); |
417 | 373 | break; | 381 | break; |
418 | 382 | case core::net::http::Method::del: | ||
419 | 383 | set_option(Option::customrequest, http_delete); | ||
420 | 384 | break; | ||
421 | 374 | default: throw core::net::http::Client::Errors::HttpMethodNotSupported{method, CORE_FROM_HERE()}; | 385 | default: throw core::net::http::Client::Errors::HttpMethodNotSupported{method, CORE_FROM_HERE()}; |
422 | 375 | } | 386 | } |
423 | 376 | 387 | ||
424 | @@ -431,6 +442,18 @@ | |||
425 | 431 | throw_if_not<curl::Code::ok>(easy::native::perform(native()), [this]() { return std::string{d->error};}); | 442 | throw_if_not<curl::Code::ok>(easy::native::perform(native()), [this]() { return std::string{d->error};}); |
426 | 432 | } | 443 | } |
427 | 433 | 444 | ||
428 | 445 | void easy::Handle::pause() | ||
429 | 446 | { | ||
430 | 447 | if (!d) throw easy::Handle::HandleHasBeenAbandoned{}; | ||
431 | 448 | throw_if_not<curl::Code::ok>(easy::native::pause(native(), CURLPAUSE_ALL), [this]() { return std::string{d->error};}); | ||
432 | 449 | } | ||
433 | 450 | |||
434 | 451 | void easy::Handle::resume() | ||
435 | 452 | { | ||
436 | 453 | if (!d) throw easy::Handle::HandleHasBeenAbandoned{}; | ||
437 | 454 | throw_if_not<curl::Code::ok>(easy::native::pause(native(), CURLPAUSE_RECV_CONT), [this]() { return std::string{d->error};}); | ||
438 | 455 | } | ||
439 | 456 | |||
440 | 434 | // URL escapes the given input string. | 457 | // URL escapes the given input string. |
441 | 435 | std::string easy::Handle::escape(const std::string& in) | 458 | std::string easy::Handle::escape(const std::string& in) |
442 | 436 | { | 459 | { |
443 | 437 | 460 | ||
444 | === modified file 'src/core/net/http/impl/curl/easy.h' | |||
445 | --- src/core/net/http/impl/curl/easy.h 2015-03-03 11:12:12 +0000 | |||
446 | +++ src/core/net/http/impl/curl/easy.h 2016-05-23 10:51:40 +0000 | |||
447 | @@ -14,6 +14,7 @@ | |||
448 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
449 | 15 | * | 15 | * |
450 | 16 | * Authored by: Thomas Voß <thomas.voss@canonical.com> | 16 | * Authored by: Thomas Voß <thomas.voss@canonical.com> |
451 | 17 | * Gary Wang <gary.wang@canonical.com> | ||
452 | 17 | */ | 18 | */ |
453 | 18 | #ifndef CORE_NET_HTTP_IMPL_CURL_EASY_H_ | 19 | #ifndef CORE_NET_HTTP_IMPL_CURL_EASY_H_ |
454 | 19 | #define CORE_NET_HTTP_IMPL_CURL_EASY_H_ | 20 | #define CORE_NET_HTTP_IMPL_CURL_EASY_H_ |
455 | @@ -136,7 +137,10 @@ | |||
456 | 136 | timeout_ms = CURLOPT_TIMEOUT_MS, | 137 | timeout_ms = CURLOPT_TIMEOUT_MS, |
457 | 137 | ssl_engine_default = CURLOPT_SSLENGINE_DEFAULT, | 138 | ssl_engine_default = CURLOPT_SSLENGINE_DEFAULT, |
458 | 138 | ssl_verify_peer = CURLOPT_SSL_VERIFYPEER, | 139 | ssl_verify_peer = CURLOPT_SSL_VERIFYPEER, |
460 | 139 | ssl_verify_host = CURLOPT_SSL_VERIFYHOST | 140 | ssl_verify_host = CURLOPT_SSL_VERIFYHOST, |
461 | 141 | customrequest = CURLOPT_CUSTOMREQUEST, | ||
462 | 142 | low_speed_limit = CURLOPT_LOW_SPEED_LIMIT, | ||
463 | 143 | low_speed_time = CURLOPT_LOW_SPEED_TIME | ||
464 | 140 | }; | 144 | }; |
465 | 141 | 145 | ||
466 | 142 | namespace native | 146 | namespace native |
467 | @@ -209,6 +213,9 @@ | |||
468 | 209 | // Executes the operation configured on the handle. | 213 | // Executes the operation configured on the handle. |
469 | 210 | ::curl::Code perform(Handle handle); | 214 | ::curl::Code perform(Handle handle); |
470 | 211 | 215 | ||
471 | 216 | // Executes pause operation on the handle. | ||
472 | 217 | ::curl::Code pause(Handle handle, int bitmask); | ||
473 | 218 | |||
474 | 212 | // URL escapes the given input string. | 219 | // URL escapes the given input string. |
475 | 213 | std::string escape(Handle handle, const std::string& in); | 220 | std::string escape(Handle handle, const std::string& in); |
476 | 214 | 221 | ||
477 | @@ -339,6 +346,12 @@ | |||
478 | 339 | // Executes the operation associated with this handle. | 346 | // Executes the operation associated with this handle. |
479 | 340 | void perform(); | 347 | void perform(); |
480 | 341 | 348 | ||
481 | 349 | // Executes pause operation associated with this handle. | ||
482 | 350 | void pause(); | ||
483 | 351 | |||
484 | 352 | // Executes resume operation associated with this handle. | ||
485 | 353 | void resume(); | ||
486 | 354 | |||
487 | 342 | // URL escapes the given input string. | 355 | // URL escapes the given input string. |
488 | 343 | std::string escape(const std::string& in); | 356 | std::string escape(const std::string& in); |
489 | 344 | 357 | ||
490 | 345 | 358 | ||
491 | === modified file 'src/core/net/http/impl/curl/request.h' | |||
492 | --- src/core/net/http/impl/curl/request.h 2015-03-23 16:09:05 +0000 | |||
493 | +++ src/core/net/http/impl/curl/request.h 2016-05-23 10:51:40 +0000 | |||
494 | @@ -14,6 +14,7 @@ | |||
495 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
496 | 15 | * | 15 | * |
497 | 16 | * Authored by: Thomas Voß <thomas.voss@canonical.com> | 16 | * Authored by: Thomas Voß <thomas.voss@canonical.com> |
498 | 17 | * Gary Wang <gary.wang@canonical.com> | ||
499 | 17 | */ | 18 | */ |
500 | 18 | #ifndef CORE_NET_HTTP_IMPL_CURL_REQUEST_H_ | 19 | #ifndef CORE_NET_HTTP_IMPL_CURL_REQUEST_H_ |
501 | 19 | #define CORE_NET_HTTP_IMPL_CURL_REQUEST_H_ | 20 | #define CORE_NET_HTTP_IMPL_CURL_REQUEST_H_ |
502 | @@ -273,6 +274,28 @@ | |||
503 | 273 | multi.add(easy); | 274 | multi.add(easy); |
504 | 274 | } | 275 | } |
505 | 275 | 276 | ||
506 | 277 | void pause() | ||
507 | 278 | { | ||
508 | 279 | try | ||
509 | 280 | { | ||
510 | 281 | easy.pause(); | ||
511 | 282 | } catch(const std::system_error& se) | ||
512 | 283 | { | ||
513 | 284 | throw core::net::http::Error(se.what(), CORE_FROM_HERE()); | ||
514 | 285 | } | ||
515 | 286 | } | ||
516 | 287 | |||
517 | 288 | void resume() | ||
518 | 289 | { | ||
519 | 290 | try | ||
520 | 291 | { | ||
521 | 292 | easy.resume(); | ||
522 | 293 | } catch(const std::system_error& se) | ||
523 | 294 | { | ||
524 | 295 | throw core::net::http::Error(se.what(), CORE_FROM_HERE()); | ||
525 | 296 | } | ||
526 | 297 | } | ||
527 | 298 | |||
528 | 276 | std::string url_escape(const std::string& s) | 299 | std::string url_escape(const std::string& s) |
529 | 277 | { | 300 | { |
530 | 278 | return easy.escape(s); | 301 | return easy.escape(s); |
531 | @@ -282,6 +305,16 @@ | |||
532 | 282 | { | 305 | { |
533 | 283 | return easy.unescape(s); | 306 | return easy.unescape(s); |
534 | 284 | } | 307 | } |
535 | 308 | |||
536 | 309 | void abort_request_if(std::uint64_t limit, const std::chrono::seconds& time) | ||
537 | 310 | { | ||
538 | 311 | if (atomic_state.load() != core::net::http::Request::State::ready) | ||
539 | 312 | throw core::net::http::Request::Errors::AlreadyActive{CORE_FROM_HERE()}; | ||
540 | 313 | |||
541 | 314 | easy.set_option(::curl::Option::low_speed_limit, limit); | ||
542 | 315 | easy.set_option(::curl::Option::low_speed_time, time.count()); | ||
543 | 316 | } | ||
544 | 317 | |||
545 | 285 | private: | 318 | private: |
546 | 286 | std::atomic<core::net::http::Request::State> atomic_state; | 319 | std::atomic<core::net::http::Request::State> atomic_state; |
547 | 287 | ::curl::multi::Handle multi; | 320 | ::curl::multi::Handle multi; |
548 | 288 | 321 | ||
549 | === modified file 'tests/http_client_test.cpp' | |||
550 | --- tests/http_client_test.cpp 2014-11-13 12:57:24 +0000 | |||
551 | +++ tests/http_client_test.cpp 2016-05-23 10:51:40 +0000 | |||
552 | @@ -14,6 +14,7 @@ | |||
553 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
554 | 15 | * | 15 | * |
555 | 16 | * Authored by: Thomas Voß <thomas.voss@canonical.com> | 16 | * Authored by: Thomas Voß <thomas.voss@canonical.com> |
556 | 17 | * Gary Wang <gary.wang@canonical.com> | ||
557 | 17 | */ | 18 | */ |
558 | 18 | 19 | ||
559 | 19 | #include <core/net/error.h> | 20 | #include <core/net/error.h> |
560 | @@ -30,6 +31,7 @@ | |||
561 | 30 | #include <json/json.h> | 31 | #include <json/json.h> |
562 | 31 | 32 | ||
563 | 32 | #include <future> | 33 | #include <future> |
564 | 34 | #include <fstream> | ||
565 | 33 | 35 | ||
566 | 34 | namespace http = core::net::http; | 36 | namespace http = core::net::http; |
567 | 35 | namespace json = Json; | 37 | namespace json = Json; |
568 | @@ -456,6 +458,33 @@ | |||
569 | 456 | EXPECT_EQ("test", root["form"]["test"].asString()); | 458 | EXPECT_EQ("test", root["form"]["test"].asString()); |
570 | 457 | } | 459 | } |
571 | 458 | 460 | ||
572 | 461 | TEST(HttpClient, post_request_for_file_with_large_chunk_succeeds) | ||
573 | 462 | { | ||
574 | 463 | auto client = http::make_client(); | ||
575 | 464 | auto url = std::string(httpbin::host) + httpbin::resources::post(); | ||
576 | 465 | |||
577 | 466 | // create temp file with large chunk | ||
578 | 467 | const std::size_t size = 1024*1024; | ||
579 | 468 | std::ofstream ofs("tmp.dat", std::ios::binary | std::ios::out); | ||
580 | 469 | ofs.seekp(size); | ||
581 | 470 | ofs.write("", 1); | ||
582 | 471 | ofs.close(); | ||
583 | 472 | |||
584 | 473 | std::ifstream payload("tmp.dat"); | ||
585 | 474 | auto request = client->post(http::Request::Configuration::from_uri_as_string(url), | ||
586 | 475 | payload, | ||
587 | 476 | size); | ||
588 | 477 | |||
589 | 478 | json::Value root; | ||
590 | 479 | json::Reader reader; | ||
591 | 480 | |||
592 | 481 | auto response = request->execute(default_progress_reporter); | ||
593 | 482 | |||
594 | 483 | EXPECT_EQ(core::net::http::Status::ok, response.status); | ||
595 | 484 | EXPECT_TRUE(reader.parse(response.body, root)); | ||
596 | 485 | EXPECT_EQ(url, root["url"].asString()); | ||
597 | 486 | } | ||
598 | 487 | |||
599 | 459 | TEST(HttpClient, put_request_for_existing_resource_succeeds) | 488 | TEST(HttpClient, put_request_for_existing_resource_succeeds) |
600 | 460 | { | 489 | { |
601 | 461 | auto client = http::make_client(); | 490 | auto client = http::make_client(); |
602 | @@ -478,6 +507,50 @@ | |||
603 | 478 | EXPECT_EQ(payload.str(), root["data"].asString()); | 507 | EXPECT_EQ(payload.str(), root["data"].asString()); |
604 | 479 | } | 508 | } |
605 | 480 | 509 | ||
606 | 510 | TEST(HttpClient, put_request_for_file_with_large_chunk_succeeds) | ||
607 | 511 | { | ||
608 | 512 | auto client = http::make_client(); | ||
609 | 513 | auto url = std::string(httpbin::host) + httpbin::resources::put(); | ||
610 | 514 | |||
611 | 515 | // create temp file with large chunk | ||
612 | 516 | const std::size_t size = 1024*1024; | ||
613 | 517 | std::ofstream ofs("tmp.dat", std::ios::binary | std::ios::out); | ||
614 | 518 | ofs.seekp(size); | ||
615 | 519 | ofs.write("", 1); | ||
616 | 520 | ofs.close(); | ||
617 | 521 | |||
618 | 522 | std::ifstream payload("tmp.dat"); | ||
619 | 523 | auto request = client->put(http::Request::Configuration::from_uri_as_string(url), | ||
620 | 524 | payload, | ||
621 | 525 | size); | ||
622 | 526 | |||
623 | 527 | json::Value root; | ||
624 | 528 | json::Reader reader; | ||
625 | 529 | |||
626 | 530 | auto response = request->execute(default_progress_reporter); | ||
627 | 531 | |||
628 | 532 | EXPECT_EQ(core::net::http::Status::ok, response.status); | ||
629 | 533 | EXPECT_TRUE(reader.parse(response.body, root)); | ||
630 | 534 | EXPECT_EQ(url, root["url"].asString()); | ||
631 | 535 | } | ||
632 | 536 | |||
633 | 537 | TEST(HttpClient, del_request_for_existing_resource_succeeds) | ||
634 | 538 | { | ||
635 | 539 | auto client = http::make_client(); | ||
636 | 540 | auto url = std::string(httpbin::host) + httpbin::resources::del(); | ||
637 | 541 | |||
638 | 542 | auto request = client->del(http::Request::Configuration::from_uri_as_string(url)); | ||
639 | 543 | |||
640 | 544 | json::Value root; | ||
641 | 545 | json::Reader reader; | ||
642 | 546 | |||
643 | 547 | auto response = request->execute(default_progress_reporter); | ||
644 | 548 | |||
645 | 549 | EXPECT_EQ(core::net::http::Status::ok, response.status); | ||
646 | 550 | EXPECT_TRUE(reader.parse(response.body, root)); | ||
647 | 551 | EXPECT_EQ(url, root["url"].asString()); | ||
648 | 552 | } | ||
649 | 553 | |||
650 | 481 | namespace com | 554 | namespace com |
651 | 482 | { | 555 | { |
652 | 483 | namespace mozilla | 556 | namespace mozilla |
653 | 484 | 557 | ||
654 | === modified file 'tests/http_streaming_client_test.cpp' | |||
655 | --- tests/http_streaming_client_test.cpp 2015-03-23 16:24:27 +0000 | |||
656 | +++ tests/http_streaming_client_test.cpp 2016-05-23 10:51:40 +0000 | |||
657 | @@ -14,6 +14,7 @@ | |||
658 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
659 | 15 | * | 15 | * |
660 | 16 | * Authored by: Thomas Voß <thomas.voss@canonical.com> | 16 | * Authored by: Thomas Voß <thomas.voss@canonical.com> |
661 | 17 | * Gary Wang <gary.wang@canonical.com> | ||
662 | 17 | */ | 18 | */ |
663 | 18 | 19 | ||
664 | 19 | #include <core/net/error.h> | 20 | #include <core/net/error.h> |
665 | @@ -33,6 +34,8 @@ | |||
666 | 33 | #include <future> | 34 | #include <future> |
667 | 34 | #include <memory> | 35 | #include <memory> |
668 | 35 | 36 | ||
669 | 37 | #include <fstream> | ||
670 | 38 | |||
671 | 36 | namespace http = core::net::http; | 39 | namespace http = core::net::http; |
672 | 37 | namespace json = Json; | 40 | namespace json = Json; |
673 | 38 | namespace net = core::net; | 41 | namespace net = core::net; |
674 | @@ -480,6 +483,37 @@ | |||
675 | 480 | EXPECT_EQ("test", root["form"]["test"].asString()); | 483 | EXPECT_EQ("test", root["form"]["test"].asString()); |
676 | 481 | } | 484 | } |
677 | 482 | 485 | ||
678 | 486 | TEST(StreamingHttpClient, post_request_for_file_with_large_chunk_succeeds) | ||
679 | 487 | { | ||
680 | 488 | using namespace ::testing; | ||
681 | 489 | |||
682 | 490 | auto client = http::make_streaming_client(); | ||
683 | 491 | auto url = std::string(httpbin::host) + httpbin::resources::post(); | ||
684 | 492 | |||
685 | 493 | // create temp file with large chunk | ||
686 | 494 | const std::size_t size = 1024*1024; | ||
687 | 495 | std::ofstream ofs("tmp.dat", std::ios::binary | std::ios::out); | ||
688 | 496 | ofs.seekp(size); | ||
689 | 497 | ofs.write("", 1); | ||
690 | 498 | ofs.close(); | ||
691 | 499 | |||
692 | 500 | std::ifstream payload("tmp.dat"); | ||
693 | 501 | auto request = client->streaming_post(http::Request::Configuration::from_uri_as_string(url), | ||
694 | 502 | payload, | ||
695 | 503 | size); | ||
696 | 504 | |||
697 | 505 | auto dh = MockDataHandler::create(); EXPECT_CALL(*dh, on_new_data(_)).Times(AtLeast(1)); | ||
698 | 506 | |||
699 | 507 | auto response = request->execute(default_progress_reporter, dh->to_data_handler()); | ||
700 | 508 | |||
701 | 509 | json::Value root; | ||
702 | 510 | json::Reader reader; | ||
703 | 511 | |||
704 | 512 | EXPECT_EQ(core::net::http::Status::ok, response.status); | ||
705 | 513 | EXPECT_TRUE(reader.parse(response.body, root)); | ||
706 | 514 | EXPECT_EQ(url, root["url"].asString()); | ||
707 | 515 | } | ||
708 | 516 | |||
709 | 483 | TEST(StreamingHttpClient, put_request_for_existing_resource_succeeds) | 517 | TEST(StreamingHttpClient, put_request_for_existing_resource_succeeds) |
710 | 484 | { | 518 | { |
711 | 485 | using namespace ::testing; | 519 | using namespace ::testing; |
712 | @@ -497,12 +531,66 @@ | |||
713 | 497 | // Our mocked data handler. | 531 | // Our mocked data handler. |
714 | 498 | auto dh = MockDataHandler::create(); EXPECT_CALL(*dh, on_new_data(_)).Times(AtLeast(1)); | 532 | auto dh = MockDataHandler::create(); EXPECT_CALL(*dh, on_new_data(_)).Times(AtLeast(1)); |
715 | 499 | 533 | ||
716 | 534 | auto response = request->execute(default_progress_reporter, dh->to_data_handler()); | ||
717 | 535 | |||
718 | 500 | json::Value root; | 536 | json::Value root; |
719 | 501 | json::Reader reader; | 537 | json::Reader reader; |
720 | 502 | 538 | ||
721 | 503 | auto response = request->execute(default_progress_reporter, dh->to_data_handler()); | ||
722 | 504 | |||
723 | 505 | EXPECT_EQ(core::net::http::Status::ok, response.status); | 539 | EXPECT_EQ(core::net::http::Status::ok, response.status); |
724 | 506 | EXPECT_TRUE(reader.parse(response.body, root)); | 540 | EXPECT_TRUE(reader.parse(response.body, root)); |
725 | 507 | EXPECT_EQ(payload.str(), root["data"].asString()); | 541 | EXPECT_EQ(payload.str(), root["data"].asString()); |
726 | 508 | } | 542 | } |
727 | 543 | |||
728 | 544 | TEST(StreamingHttpClient, put_request_for_file_with_large_chunk_succeeds) | ||
729 | 545 | { | ||
730 | 546 | using namespace ::testing; | ||
731 | 547 | |||
732 | 548 | auto client = http::make_streaming_client(); | ||
733 | 549 | auto url = std::string(httpbin::host) + httpbin::resources::put(); | ||
734 | 550 | |||
735 | 551 | // create temp file with large chunk | ||
736 | 552 | const std::size_t size = 1024*1024; | ||
737 | 553 | std::ofstream ofs("tmp.dat", std::ios::binary | std::ios::out); | ||
738 | 554 | ofs.seekp(size); | ||
739 | 555 | ofs.write("", 1); | ||
740 | 556 | ofs.close(); | ||
741 | 557 | |||
742 | 558 | std::ifstream payload("tmp.dat"); | ||
743 | 559 | auto request = client->streaming_put(http::Request::Configuration::from_uri_as_string(url), | ||
744 | 560 | payload, | ||
745 | 561 | size); | ||
746 | 562 | |||
747 | 563 | auto dh = MockDataHandler::create(); EXPECT_CALL(*dh, on_new_data(_)).Times(AtLeast(1)); | ||
748 | 564 | |||
749 | 565 | auto response = request->execute(default_progress_reporter, dh->to_data_handler()); | ||
750 | 566 | |||
751 | 567 | json::Value root; | ||
752 | 568 | json::Reader reader; | ||
753 | 569 | |||
754 | 570 | EXPECT_EQ(core::net::http::Status::ok, response.status); | ||
755 | 571 | EXPECT_TRUE(reader.parse(response.body, root)); | ||
756 | 572 | EXPECT_EQ(url, root["url"].asString()); | ||
757 | 573 | } | ||
758 | 574 | |||
759 | 575 | TEST(StreamingHttpClient, del_request_for_existing_resource_succeeds) | ||
760 | 576 | { | ||
761 | 577 | using namespace ::testing; | ||
762 | 578 | |||
763 | 579 | auto client = http::make_streaming_client(); | ||
764 | 580 | auto url = std::string(httpbin::host) + httpbin::resources::del(); | ||
765 | 581 | |||
766 | 582 | auto request = client->streaming_del(http::Request::Configuration::from_uri_as_string(url)); | ||
767 | 583 | |||
768 | 584 | // Our mocked data handler. | ||
769 | 585 | auto dh = MockDataHandler::create(); EXPECT_CALL(*dh, on_new_data(_)).Times(AtLeast(1)); | ||
770 | 586 | |||
771 | 587 | auto response = request->execute(default_progress_reporter, dh->to_data_handler()); | ||
772 | 588 | |||
773 | 589 | json::Value root; | ||
774 | 590 | json::Reader reader; | ||
775 | 591 | |||
776 | 592 | EXPECT_EQ(core::net::http::Status::ok, response.status); | ||
777 | 593 | EXPECT_TRUE(reader.parse(response.body, root)); | ||
778 | 594 | EXPECT_EQ(url, root["url"].asString()); | ||
779 | 595 | } | ||
780 | 596 | |||
781 | 509 | 597 | ||
782 | === modified file 'tests/httpbin.h.in' | |||
783 | --- tests/httpbin.h.in 2014-05-22 11:50:55 +0000 | |||
784 | +++ tests/httpbin.h.in 2016-05-23 10:51:40 +0000 | |||
785 | @@ -14,6 +14,7 @@ | |||
786 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
787 | 15 | * | 15 | * |
788 | 16 | * Authored by: Thomas Voß <thomas.voss@canonical.com> | 16 | * Authored by: Thomas Voß <thomas.voss@canonical.com> |
789 | 17 | * Gary Wang <gary.wang@canonical.com> | ||
790 | 17 | */ | 18 | */ |
791 | 18 | 19 | ||
792 | 19 | #ifndef HTTPBIN_H_ | 20 | #ifndef HTTPBIN_H_ |
793 | @@ -104,6 +105,11 @@ | |||
794 | 104 | { | 105 | { |
795 | 105 | return "/put"; | 106 | return "/put"; |
796 | 106 | } | 107 | } |
797 | 108 | /** Returns DELETE data. */ | ||
798 | 109 | const char* del() | ||
799 | 110 | { | ||
800 | 111 | return "/delete"; | ||
801 | 112 | } | ||
802 | 107 | /** Challenges basic authentication. */ | 113 | /** Challenges basic authentication. */ |
803 | 108 | const char* basic_auth() | 114 | const char* basic_auth() |
804 | 109 | { | 115 | { |
Thanks for the changes, looking good. A few minor niggles inline,