1 /*
2 * Copyright 2022 Google LLC
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "fcp/client/http/curl/curl_http_client.h"
18
19 #include <memory>
20 #include <string>
21 #include <utility>
22 #include <vector>
23
24 #include "absl/time/clock.h"
25 #include "fcp/client/http/in_memory_request_response.h"
26 #include "fcp/client/http/testing/http_test_server.h"
27 #include "fcp/client/http/testing/test_helpers.h"
28
29 namespace fcp::client::http::curl {
30 namespace {
31 using ::testing::_;
32 using ::testing::AllOf;
33 using ::testing::Field;
34 using ::testing::FieldsAre;
35 using ::testing::StrictMock;
36 using ::testing::UnorderedElementsAreArray;
37
SetUpOnResponseStarted(StrictMock<MockHttpRequestCallback> * request_callback,const std::string & request_uri,HttpRequest::Method method,int response_code,const HeaderList & expected_request_extra_headers,bool has_body,const HeaderList & expected_response_headers)38 void SetUpOnResponseStarted(
39 StrictMock<MockHttpRequestCallback>* request_callback,
40 const std::string& request_uri, HttpRequest::Method method,
41 int response_code, const HeaderList& expected_request_extra_headers,
42 bool has_body, const HeaderList& expected_response_headers) {
43 EXPECT_CALL(*request_callback, OnResponseStarted(_, _))
44 .WillOnce(::testing::Invoke([=, &request_uri](
45 const HttpRequest& request,
46 const HttpResponse& response) {
47 EXPECT_THAT(request.uri(), request_uri);
48 EXPECT_THAT(request.method(), method);
49 EXPECT_THAT(request.extra_headers(),
50 UnorderedElementsAreArray(expected_request_extra_headers));
51 EXPECT_THAT(request.HasBody(), has_body);
52 EXPECT_THAT(response.code(), response_code);
53 EXPECT_THAT(response.headers(),
54 UnorderedElementsAreArray(expected_response_headers));
55 return absl::OkStatus();
56 }));
57 }
58
SetUpOnResponseBody(StrictMock<MockHttpRequestCallback> * request_callback,const std::string & request_uri,HttpRequest::Method method,int response_code,const HeaderList & expected_request_extra_headers,bool has_body,const HeaderList & expected_response_headers,const std::string & expected_response_body)59 void SetUpOnResponseBody(StrictMock<MockHttpRequestCallback>* request_callback,
60 const std::string& request_uri,
61 HttpRequest::Method method, int response_code,
62 const HeaderList& expected_request_extra_headers,
63 bool has_body,
64 const HeaderList& expected_response_headers,
65 const std::string& expected_response_body) {
66 EXPECT_CALL(*request_callback, OnResponseBody(_, _, _))
67 .WillOnce(::testing::Invoke([=](const HttpRequest& request,
68 const HttpResponse& response,
69 absl::string_view data) {
70 EXPECT_THAT(request.uri(), request_uri);
71 EXPECT_THAT(request.method(), method);
72 EXPECT_THAT(request.extra_headers(),
73 UnorderedElementsAreArray(expected_request_extra_headers));
74 EXPECT_THAT(request.HasBody(), has_body);
75 EXPECT_THAT(response.code(), response_code);
76 EXPECT_THAT(response.headers(),
77 UnorderedElementsAreArray(expected_response_headers));
78 EXPECT_THAT(data, expected_response_body);
79 return absl::OkStatus();
80 }));
81 }
82
SetUpOnResponseBody(StrictMock<MockHttpRequestCallback> * request_callback,const std::string & request_uri,HttpRequest::Method method,int response_code,const HeaderList & expected_request_extra_headers,bool has_body,const HeaderList & expected_response_headers,const std::string & expected_response_body,size_t & total_bytes_downloaded)83 void SetUpOnResponseBody(StrictMock<MockHttpRequestCallback>* request_callback,
84 const std::string& request_uri,
85 HttpRequest::Method method, int response_code,
86 const HeaderList& expected_request_extra_headers,
87 bool has_body,
88 const HeaderList& expected_response_headers,
89 const std::string& expected_response_body,
90 size_t& total_bytes_downloaded) {
91 EXPECT_CALL(*request_callback, OnResponseBody(_, _, _))
92 .WillOnce(::testing::Invoke(
93 [=, &total_bytes_downloaded](const HttpRequest& request,
94 const HttpResponse& response,
95 absl::string_view data) {
96 EXPECT_THAT(request.uri(), request_uri);
97 EXPECT_THAT(request.method(), method);
98 EXPECT_THAT(
99 request.extra_headers(),
100 UnorderedElementsAreArray(expected_request_extra_headers));
101 EXPECT_THAT(request.HasBody(), has_body);
102 EXPECT_THAT(response.code(), response_code);
103 EXPECT_THAT(response.headers(),
104 UnorderedElementsAreArray(expected_response_headers));
105 EXPECT_THAT(data, expected_response_body);
106 total_bytes_downloaded += data.size();
107 return absl::OkStatus();
108 }));
109 }
110
SetUpOnResponseCompleted(StrictMock<MockHttpRequestCallback> * request_callback,const std::string & request_uri,HttpRequest::Method method,int response_code,const HeaderList & expected_request_extra_headers,bool has_body,const HeaderList & expected_response_headers)111 void SetUpOnResponseCompleted(
112 StrictMock<MockHttpRequestCallback>* request_callback,
113 const std::string& request_uri, HttpRequest::Method method,
114 int response_code, const HeaderList& expected_request_extra_headers,
115 bool has_body, const HeaderList& expected_response_headers) {
116 EXPECT_CALL(*request_callback, OnResponseCompleted(_, _))
117 .WillOnce(::testing::Invoke([=, &request_uri](
118 const HttpRequest& request,
119 const HttpResponse& response) {
120 EXPECT_THAT(request.uri(), request_uri);
121 EXPECT_THAT(request.method(), method);
122 EXPECT_THAT(request.extra_headers(),
123 UnorderedElementsAreArray(expected_request_extra_headers));
124 EXPECT_THAT(request.HasBody(), has_body);
125 EXPECT_THAT(response.code(), response_code);
126 EXPECT_THAT(response.headers(),
127 UnorderedElementsAreArray(expected_response_headers));
128 }));
129 }
130
SetUpGetRequestCallback(StrictMock<MockHttpRequestCallback> * request_callback,const std::string & request_uri,const HeaderList & expected_request_extra_headers,const HeaderList & expected_response_headers,const std::string & expected_response_body,size_t & total_bytes_downloaded)131 void SetUpGetRequestCallback(
132 StrictMock<MockHttpRequestCallback>* request_callback,
133 const std::string& request_uri,
134 const HeaderList& expected_request_extra_headers,
135 const HeaderList& expected_response_headers,
136 const std::string& expected_response_body, size_t& total_bytes_downloaded) {
137 SetUpOnResponseStarted(request_callback, request_uri,
138 HttpRequest::Method::kGet, /*response_code*/ 200,
139 expected_request_extra_headers,
140 /*has_body*/ false, expected_response_headers);
141 SetUpOnResponseBody(request_callback, request_uri, HttpRequest::Method::kGet,
142 /*response_code*/ 200, expected_request_extra_headers,
143 /*has_body*/ false, expected_response_headers,
144 expected_response_body, total_bytes_downloaded);
145
146 SetUpOnResponseCompleted(request_callback, request_uri,
147 HttpRequest::Method::kGet, /*response_code*/ 200,
148 expected_request_extra_headers,
149 /*has_body*/ false, expected_response_headers);
150 }
151
SetUpPostRequestCallback(StrictMock<MockHttpRequestCallback> * request_callback,const std::string & request_uri,const HeaderList & expected_request_extra_headers,const HeaderList & expected_response_headers,const std::string & expected_response_body,size_t & total_bytes_downloaded)152 void SetUpPostRequestCallback(
153 StrictMock<MockHttpRequestCallback>* request_callback,
154 const std::string& request_uri,
155 const HeaderList& expected_request_extra_headers,
156 const HeaderList& expected_response_headers,
157 const std::string& expected_response_body, size_t& total_bytes_downloaded) {
158 SetUpOnResponseStarted(request_callback, request_uri,
159 HttpRequest::Method::kPost, /*response_code*/ 200,
160 expected_request_extra_headers,
161 /*has_body*/ true, expected_response_headers);
162
163 SetUpOnResponseBody(request_callback, request_uri, HttpRequest::Method::kPost,
164 /*response_code*/ 200, expected_request_extra_headers,
165 /*has_body*/ true, expected_response_headers,
166 expected_response_body, total_bytes_downloaded);
167
168 SetUpOnResponseCompleted(request_callback, request_uri,
169 HttpRequest::Method::kPost, /*response_code*/ 200,
170 expected_request_extra_headers,
171 /*has_body*/ true, expected_response_headers);
172 }
173
SetUpPutRequestCallback(StrictMock<MockHttpRequestCallback> * request_callback,const std::string & request_uri,const HeaderList & expected_request_extra_headers,const HeaderList & expected_response_headers,const std::string & expected_response_body,size_t & total_bytes_downloaded)174 void SetUpPutRequestCallback(
175 StrictMock<MockHttpRequestCallback>* request_callback,
176 const std::string& request_uri,
177 const HeaderList& expected_request_extra_headers,
178 const HeaderList& expected_response_headers,
179 const std::string& expected_response_body, size_t& total_bytes_downloaded) {
180 SetUpOnResponseStarted(request_callback, request_uri,
181 HttpRequest::Method::kPut, /*response_code*/ 200,
182 expected_request_extra_headers,
183 /*has_body*/ true, expected_response_headers);
184
185 SetUpOnResponseBody(request_callback, request_uri, HttpRequest::Method::kPut,
186 /*response_code*/ 200, expected_request_extra_headers,
187 /*has_body*/ true, expected_response_headers,
188 expected_response_body, total_bytes_downloaded);
189
190 SetUpOnResponseCompleted(request_callback, request_uri,
191 HttpRequest::Method::kPut, /*response_code*/ 200,
192 expected_request_extra_headers,
193 /*has_body*/ true, expected_response_headers);
194 }
195
PerformTwoRequests(CurlHttpClient * http_client,int port,const std::string & request_uri1,const std::string & request_uri2)196 void PerformTwoRequests(CurlHttpClient* http_client, int port,
197 const std::string& request_uri1,
198 const std::string& request_uri2) {
199 std::string request1_body;
200 std::string request2_body = "test: 123-45";
201
202 auto request1 = InMemoryHttpRequest::Create(
203 request_uri1, HttpRequest::Method::kGet, HeaderList(), request1_body,
204 /*use_compression*/ false);
205 ASSERT_OK(request1);
206
207 auto request2 = InMemoryHttpRequest::Create(
208 request_uri2, HttpRequest::Method::kPost, HeaderList(), request2_body,
209 /*use_compression*/ false);
210 ASSERT_OK(request2);
211
212 auto handle1 = http_client->EnqueueRequest(std::move(request1.value()));
213 auto handle2 = http_client->EnqueueRequest(std::move(request2.value()));
214
215 auto request_callback1 =
216 std::make_unique<StrictMock<MockHttpRequestCallback>>();
217 auto request_callback2 =
218 std::make_unique<StrictMock<MockHttpRequestCallback>>();
219
220 size_t total_bytes_downloaded_handle1 = 0;
221 size_t total_bytes_downloaded_handle2 = 0;
222
223 HeaderList expected_request_extra_headers{{"Content-Length", "12"}};
224 HeaderList expected_response_headers{
225 {"Content-Type", "text/html"},
226 {"Date",
227 absl::FormatTime("%a, %d %b %Y %H", absl::Now(), absl::UTCTimeZone())}};
228
229 auto expected_response_body1 = absl::StrCat(
230 "HTTP Method: GET\n", "Request Uri: /test\n", "Request Headers:\n",
231 "Host: localhost:", port, "\nAccept: */*\n", "Accept-Encoding: gzip\n",
232 "Request Body:\n");
233
234 auto expected_response_body2 = absl::StrCat(
235 "HTTP Method: POST\nRequest Uri: /test\n",
236 "Request Headers:\nHost: localhost:", port,
237 "\nAccept: */*\nAccept-Encoding: gzip\n", "Content-Length: 12\n",
238 "Content-Type: application/x-www-form-urlencoded\n",
239 "Request Body:\ntest: 123-45");
240
241 SetUpGetRequestCallback(request_callback1.get(), request_uri1,
242 /*expected_request_extra_headers*/ {},
243 expected_response_headers, expected_response_body1,
244 total_bytes_downloaded_handle1);
245 SetUpPostRequestCallback(request_callback2.get(), request_uri2,
246 expected_request_extra_headers,
247 expected_response_headers, expected_response_body2,
248 total_bytes_downloaded_handle2);
249
250 std::vector<std::pair<HttpRequestHandle*, HttpRequestCallback*>> requests{
251 std::make_pair(handle1.get(), request_callback1.get()),
252 std::make_pair(handle2.get(), request_callback2.get())};
253
254 EXPECT_THAT(handle1->TotalSentReceivedBytes(), FieldsAre(0, 0));
255 EXPECT_THAT(handle2->TotalSentReceivedBytes(), FieldsAre(0, 0));
256
257 absl::Status status = http_client->PerformRequests(requests);
258
259 EXPECT_THAT(status, absl::OkStatus());
260 EXPECT_THAT(handle1->TotalSentReceivedBytes(),
261 AllOf(Field(&HttpRequestHandle::SentReceivedBytes::sent_bytes,
262 request1_body.size()),
263 Field(&HttpRequestHandle::SentReceivedBytes::received_bytes,
264 total_bytes_downloaded_handle1)));
265 EXPECT_THAT(handle2->TotalSentReceivedBytes(),
266 AllOf(Field(&HttpRequestHandle::SentReceivedBytes::sent_bytes,
267 request2_body.size()),
268 Field(&HttpRequestHandle::SentReceivedBytes::received_bytes,
269 total_bytes_downloaded_handle2)));
270 }
271
272 // Runs PerformRequests once in one thread.
TEST(CurlHttpClientTest,PerformTwoRequestsInParallelInOneThread)273 TEST(CurlHttpClientTest, PerformTwoRequestsInParallelInOneThread) {
274 const int port = 4568;
275 const std::string request_uri =
276 absl::StrCat("http://localhost:", port, "/test");
277
278 auto curl_api = std::make_unique<CurlApi>();
279 auto http_client = std::make_unique<CurlHttpClient>(curl_api.get());
280 auto http_server = CreateHttpTestServer("/test", port, /*num_threads*/ 5);
281 EXPECT_THAT(http_server.ok(), true);
282 EXPECT_THAT(http_server.value()->StartAcceptingRequests(), true);
283
284 PerformTwoRequests(http_client.get(), port, request_uri, request_uri);
285
286 curl_api.reset();
287 http_server.value()->Terminate();
288 http_server.value()->WaitForTermination();
289 }
290
TEST(CurlHttpClientTest,PutRequest)291 TEST(CurlHttpClientTest, PutRequest) {
292 const int port = 4568;
293 const std::string request_uri =
294 absl::StrCat("http://localhost:", port, "/test");
295
296 auto curl_api = std::make_unique<CurlApi>();
297 auto http_client = std::make_unique<CurlHttpClient>(curl_api.get());
298 auto http_server = CreateHttpTestServer("/test", port, /*num_threads*/ 5);
299 EXPECT_THAT(http_server.ok(), true);
300 EXPECT_THAT(http_server.value()->StartAcceptingRequests(), true);
301
302 std::string request_body = "test: 123-45";
303
304 auto request = InMemoryHttpRequest::Create(
305 request_uri, HttpRequest::Method::kPut, HeaderList(), request_body,
306 /*use_compression*/ false);
307 ASSERT_OK(request);
308
309 auto handle = http_client->EnqueueRequest(std::move(request.value()));
310
311 auto request_callback =
312 std::make_unique<StrictMock<MockHttpRequestCallback>>();
313
314 size_t total_bytes_downloaded_handle = 0;
315
316 HeaderList expected_request_extra_headers{{"Content-Length", "12"}};
317 HeaderList expected_response_headers{
318 {"Content-Type", "text/html"},
319 {"Date",
320 absl::FormatTime("%a, %d %b %Y %H", absl::Now(), absl::UTCTimeZone())}};
321
322 auto expected_response_body =
323 absl::StrCat("HTTP Method: PUT\nRequest Uri: /test\n",
324 "Request Headers:\nHost: localhost:", port,
325 "\nAccept: */*\nAccept-Encoding: gzip\n",
326 "Content-Length: 12\n", "Request Body:\ntest: 123-45");
327
328 SetUpPutRequestCallback(request_callback.get(), request_uri,
329 expected_request_extra_headers,
330 expected_response_headers, expected_response_body,
331 total_bytes_downloaded_handle);
332
333 std::vector<std::pair<HttpRequestHandle*, HttpRequestCallback*>> requests{
334 std::make_pair(handle.get(), request_callback.get())};
335
336 EXPECT_THAT(handle->TotalSentReceivedBytes(), FieldsAre(0, 0));
337
338 absl::Status status = http_client->PerformRequests(requests);
339
340 EXPECT_THAT(status, absl::OkStatus());
341 EXPECT_THAT(handle->TotalSentReceivedBytes(),
342 AllOf(Field(&HttpRequestHandle::SentReceivedBytes::sent_bytes,
343 request_body.size()),
344 Field(&HttpRequestHandle::SentReceivedBytes::received_bytes,
345 total_bytes_downloaded_handle)));
346
347 curl_api.reset();
348 http_server.value()->Terminate();
349 http_server.value()->WaitForTermination();
350 }
351
352 // Runs PerformRequests in five times in five threads.
TEST(CurlHttpClientTest,PerformTwoRequestsInParallelFiveTimesInFiveThreads)353 TEST(CurlHttpClientTest, PerformTwoRequestsInParallelFiveTimesInFiveThreads) {
354 const int port = 4568;
355 const std::string request_uri =
356 absl::StrCat("http://localhost:", port, "/test");
357
358 auto curl_api = std::make_unique<CurlApi>();
359 auto http_client = std::make_unique<CurlHttpClient>(curl_api.get());
360 auto http_server = CreateHttpTestServer("/test", port, /*num_threads*/ 10);
361 EXPECT_THAT(http_server.ok(), true);
362 EXPECT_THAT(http_server.value()->StartAcceptingRequests(), true);
363
364 auto thread_pool_scheduler = CreateThreadPoolScheduler(5);
365
366 thread_pool_scheduler->Schedule([&http_client, request_uri]() {
367 PerformTwoRequests(http_client.get(), port, request_uri, request_uri);
368 });
369 thread_pool_scheduler->Schedule([&http_client, request_uri]() {
370 PerformTwoRequests(http_client.get(), port, request_uri, request_uri);
371 });
372 thread_pool_scheduler->Schedule([&http_client, request_uri]() {
373 PerformTwoRequests(http_client.get(), port, request_uri, request_uri);
374 });
375 thread_pool_scheduler->Schedule([&http_client, request_uri]() {
376 PerformTwoRequests(http_client.get(), port, request_uri, request_uri);
377 });
378 thread_pool_scheduler->Schedule([&http_client, request_uri]() {
379 PerformTwoRequests(http_client.get(), port, request_uri, request_uri);
380 });
381
382 thread_pool_scheduler->WaitUntilIdle();
383
384 curl_api.reset();
385 http_server.value()->Terminate();
386 http_server.value()->WaitForTermination();
387 }
388
389 // Runs PerformRequests with two requests and cancels the second after
390 // OnResponseStarted received.
TEST(CurlHttpClientTest,CancelRequest)391 TEST(CurlHttpClientTest, CancelRequest) {
392 const int port = 4568;
393 const std::string request_uri1 =
394 absl::StrCat("http://localhost:", port, "/test");
395 const std::string request_uri2 =
396 absl::StrCat("http://localhost:", port, "/test");
397
398 auto curl_api = std::make_unique<CurlApi>();
399 auto http_client = std::make_unique<CurlHttpClient>(curl_api.get());
400 auto http_server = CreateHttpTestServer("/test", port, /*num_threads*/ 5);
401 EXPECT_THAT(http_server.ok(), true);
402 EXPECT_THAT(http_server.value()->StartAcceptingRequests(), true);
403
404 std::string request1_body;
405 std::string request2_body = "test: 123-45";
406
407 auto request1 = InMemoryHttpRequest::Create(
408 request_uri1, HttpRequest::Method::kGet, HeaderList(), request1_body,
409 /*use_compression*/ false);
410 ASSERT_OK(request1);
411
412 auto request2 = InMemoryHttpRequest::Create(
413 request_uri2, HttpRequest::Method::kPost, HeaderList(), request2_body,
414 /*use_compression*/ false);
415 ASSERT_OK(request2);
416
417 auto handle1 = http_client->EnqueueRequest(std::move(request1.value()));
418 auto handle2 = http_client->EnqueueRequest(std::move(request2.value()));
419
420 auto request_callback1 =
421 std::make_unique<StrictMock<MockHttpRequestCallback>>();
422 auto request_callback2 =
423 std::make_unique<StrictMock<MockHttpRequestCallback>>();
424
425 size_t total_bytes_downloaded_handle1 = 0;
426
427 HeaderList expected_request_extra_headers{{"Content-Length", "12"}};
428 HeaderList expected_response_headers{
429 {"Content-Type", "text/html"},
430 {"Date",
431 absl::FormatTime("%a, %d %b %Y %H", absl::Now(), absl::UTCTimeZone())}};
432
433 auto expected_response_body = absl::StrCat(
434 "HTTP Method: GET\n", "Request Uri: /test\n", "Request Headers:\n",
435 "Host: localhost:", port, "\nAccept: */*\n", "Accept-Encoding: gzip\n",
436 "Request Body:\n");
437
438 SetUpGetRequestCallback(request_callback1.get(), request_uri1,
439 /*expected_request_extra_headers*/ {},
440 expected_response_headers, expected_response_body,
441 total_bytes_downloaded_handle1);
442
443 EXPECT_CALL(*request_callback2, OnResponseStarted(_, _))
444 .WillOnce(::testing::Invoke(
445 [&handle2](const HttpRequest& request, const HttpResponse& response) {
446 handle2->Cancel();
447 return absl::OkStatus();
448 }));
449
450 auto expected_response_body2 = absl::StrCat(
451 "HTTP Method: POST\nRequest Uri: /test\n",
452 "Request Headers:\nHost: localhost:", port,
453 "\nAccept: */*\nAccept-Encoding: gzip\n", "Content-Length: 12\n",
454 "Content-Type: application/x-www-form-urlencoded\n",
455 "Request Body:\ntest: 123-45");
456
457 SetUpOnResponseBody(
458 request_callback2.get(), request_uri2, HttpRequest::Method::kPost,
459 /*response_code*/ 200, expected_request_extra_headers,
460 /*has_body*/ true, expected_response_headers, expected_response_body2);
461
462 EXPECT_CALL(*request_callback2, OnResponseBodyError(_, _, _))
463 .WillOnce(::testing::Invoke([&request_uri2](const HttpRequest& request,
464 const HttpResponse& response,
465 const absl::Status& error) {
466 EXPECT_THAT(request.uri(), request_uri2);
467 EXPECT_THAT(request.method(), HttpRequest::Method::kPost);
468 EXPECT_THAT(request.extra_headers().size(), 1);
469 EXPECT_THAT(request.HasBody(), true);
470 }));
471
472 std::vector<std::pair<HttpRequestHandle*, HttpRequestCallback*>> requests{
473 std::make_pair(handle1.get(), request_callback1.get()),
474 std::make_pair(handle2.get(), request_callback2.get())};
475
476 auto thread_pool_scheduler = CreateThreadPoolScheduler(2);
477 thread_pool_scheduler->Schedule([&http_client, &requests]() {
478 absl::Status status = http_client->PerformRequests(requests);
479
480 EXPECT_THAT(status, absl::OkStatus());
481 });
482
483 thread_pool_scheduler->WaitUntilIdle();
484
485 EXPECT_THAT(handle1->TotalSentReceivedBytes(),
486 AllOf(Field(&HttpRequestHandle::SentReceivedBytes::sent_bytes,
487 request1_body.size()),
488 Field(&HttpRequestHandle::SentReceivedBytes::received_bytes,
489 total_bytes_downloaded_handle1)));
490
491 curl_api.reset();
492 http_server.value()->Terminate();
493 http_server.value()->WaitForTermination();
494 }
495
496 // Runs PerformRequests once in one thread.
TEST(CurlHttpClientTest,TestExtraHeaders)497 TEST(CurlHttpClientTest, TestExtraHeaders) {
498 const int port = 4568;
499 const std::string request_uri =
500 absl::StrCat("http://localhost:", port, "/test");
501
502 auto curl_api = std::make_unique<CurlApi>();
503 auto http_client = std::make_unique<CurlHttpClient>(curl_api.get());
504
505 auto http_server = CreateHttpTestServer("/test", port, /*num_threads*/ 3);
506 EXPECT_THAT(http_server.ok(), true);
507 EXPECT_THAT(http_server.value()->StartAcceptingRequests(), true);
508
509 std::string request_body = "test: 123-45";
510 HeaderList extra_headers = {{"Content-Type", "application/x-protobuf"}};
511
512 auto request = InMemoryHttpRequest::Create(
513 request_uri, HttpRequest::Method::kPost, extra_headers, request_body,
514 /*use_compression*/ false);
515 ASSERT_OK(request);
516
517 auto handle = http_client->EnqueueRequest(std::move(request.value()));
518
519 auto request_callback =
520 std::make_unique<StrictMock<MockHttpRequestCallback>>();
521
522 HeaderList expected_request_extra_headers{
523 {"Content-Length", "12"},
524 {"Content-Type", "application/x-protobuf"},
525 };
526 HeaderList expected_response_headers{
527 {"Content-Type", "text/html"},
528 {"Date",
529 absl::FormatTime("%a, %d %b %Y %H", absl::Now(), absl::UTCTimeZone())}};
530 auto expected_response_body =
531 absl::StrCat("HTTP Method: POST\nRequest Uri: /test\n",
532 "Request Headers:\nHost: localhost:", port,
533 "\nAccept: */*\nAccept-Encoding: gzip\n",
534 "Content-Type: application/x-protobuf\n",
535 "Content-Length: 12\n", "Request Body:\ntest: 123-45");
536
537 SetUpOnResponseStarted(request_callback.get(), request_uri,
538 HttpRequest::Method::kPost, /*response_code*/ 200,
539 expected_request_extra_headers,
540 /*has_body*/ true, expected_response_headers);
541
542 SetUpOnResponseBody(
543 request_callback.get(), request_uri, HttpRequest::Method::kPost,
544 /*response_code*/ 200, expected_request_extra_headers,
545 /*has_body*/ true, expected_response_headers, expected_response_body);
546
547 SetUpOnResponseCompleted(request_callback.get(), request_uri,
548 HttpRequest::Method::kPost, /*response_code*/ 200,
549 expected_request_extra_headers,
550 /*has_body*/ true, expected_response_headers);
551
552 std::vector<std::pair<HttpRequestHandle*, HttpRequestCallback*>> requests{
553 std::make_pair(handle.get(), request_callback.get())};
554
555 absl::Status status = http_client->PerformRequests(requests);
556 EXPECT_THAT(status, absl::OkStatus());
557
558 curl_api.reset();
559 http_server.value()->Terminate();
560 http_server.value()->WaitForTermination();
561 }
562
563 } // namespace
564 } // namespace fcp::client::http::curl
565