• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 //
3 // Copyright 2015 gRPC authors.
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 //     http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17 //
18 
19 #include "src/core/util/http_client/httpcli.h"
20 
21 #include <ares.h>
22 #include <grpc/credentials.h>
23 #include <grpc/grpc.h>
24 #include <grpc/grpc_security.h>
25 #include <grpc/support/alloc.h>
26 #include <grpc/support/sync.h>
27 #include <grpc/support/time.h>
28 #include <gtest/gtest.h>
29 #include <string.h>
30 #include <sys/socket.h>
31 
32 #include <memory>
33 #include <string>
34 #include <thread>
35 #include <utility>
36 
37 #include "absl/log/check.h"
38 #include "absl/log/log.h"
39 #include "absl/strings/str_cat.h"
40 #include "absl/strings/str_format.h"
41 #include "absl/time/clock.h"
42 #include "absl/time/time.h"
43 #include "src/core/lib/iomgr/pollset.h"
44 #include "src/core/lib/iomgr/pollset_set.h"
45 #include "src/core/lib/security/credentials/credentials.h"
46 #include "src/core/resolver/dns/c_ares/grpc_ares_wrapper.h"
47 #include "src/core/util/status_helper.h"
48 #include "src/core/util/subprocess.h"
49 #include "src/core/util/time.h"
50 #include "src/core/util/time_util.h"
51 #include "test/core/test_util/fake_udp_and_tcp_server.h"
52 #include "test/core/test_util/port.h"
53 #include "test/core/test_util/test_config.h"
54 #include "test/core/util/http_client/httpcli_test_util.h"
55 
56 namespace {
57 
NSecondsTime(int seconds)58 grpc_core::Timestamp NSecondsTime(int seconds) {
59   return grpc_core::Timestamp::FromTimespecRoundUp(
60       grpc_timeout_seconds_to_deadline(seconds));
61 }
62 
AbslDeadlineSeconds(int s)63 absl::Time AbslDeadlineSeconds(int s) {
64   return grpc_core::ToAbslTime(grpc_timeout_seconds_to_deadline(s));
65 }
66 
67 int g_argc;
68 char** g_argv;
69 int g_server_port;
70 gpr_subprocess* g_server;
71 
72 class HttpRequestTest : public ::testing::Test {
73  public:
HttpRequestTest()74   HttpRequestTest() {
75     grpc_init();
76     grpc_core::ExecCtx exec_ctx;
77     grpc_pollset* pollset =
78         static_cast<grpc_pollset*>(gpr_zalloc(grpc_pollset_size()));
79     grpc_pollset_init(pollset, &mu_);
80     pops_ = grpc_polling_entity_create_from_pollset(pollset);
81   }
~HttpRequestTest()82   ~HttpRequestTest() override {
83     {
84       grpc_core::ExecCtx exec_ctx;
85       grpc_pollset_shutdown(
86           grpc_polling_entity_pollset(&pops_),
87           GRPC_CLOSURE_CREATE(DestroyPops, &pops_, grpc_schedule_on_exec_ctx));
88     }
89     grpc_shutdown();
90   }
91 
RunAndKick(const std::function<void ()> & f)92   void RunAndKick(const std::function<void()>& f) {
93     grpc_core::MutexLockForGprMu lock(mu_);
94     f();
95     CHECK(GRPC_LOG_IF_ERROR(
96         "pollset_kick",
97         grpc_pollset_kick(grpc_polling_entity_pollset(&pops_), nullptr)));
98   }
99 
PollUntil(const std::function<bool ()> & predicate,absl::Time deadline)100   void PollUntil(const std::function<bool()>& predicate, absl::Time deadline) {
101     gpr_mu_lock(mu_);
102     while (!predicate()) {
103       CHECK(absl::Now() < deadline);
104       grpc_pollset_worker* worker = nullptr;
105       CHECK(GRPC_LOG_IF_ERROR(
106           "pollset_work", grpc_pollset_work(grpc_polling_entity_pollset(&pops_),
107                                             &worker, NSecondsTime(1))));
108       gpr_mu_unlock(mu_);
109       gpr_mu_lock(mu_);
110     }
111     gpr_mu_unlock(mu_);
112   }
113 
pops()114   grpc_polling_entity* pops() { return &pops_; }
115 
116  protected:
SetUpTestSuite()117   static void SetUpTestSuite() {
118     auto test_server = grpc_core::testing::StartHttpRequestTestServer(
119         g_argc, g_argv, false /* use_ssl */);
120     g_server = test_server.server;
121     g_server_port = test_server.port;
122   }
123 
TearDownTestSuite()124   static void TearDownTestSuite() { gpr_subprocess_destroy(g_server); }
125 
126  private:
DestroyPops(void * p,grpc_error_handle)127   static void DestroyPops(void* p, grpc_error_handle /*error*/) {
128     grpc_polling_entity* pops = static_cast<grpc_polling_entity*>(p);
129     grpc_pollset_destroy(grpc_polling_entity_pollset(pops));
130     gpr_free(grpc_polling_entity_pollset(pops));
131   }
132 
133   gpr_mu* mu_;
134   grpc_polling_entity pops_;
135 };
136 
137 struct RequestState {
RequestState__anon44ee580b0111::RequestState138   explicit RequestState(HttpRequestTest* test) : test(test) {}
139 
~RequestState__anon44ee580b0111::RequestState140   ~RequestState() {
141     grpc_core::ExecCtx exec_ctx;
142     grpc_http_response_destroy(&response);
143   }
144 
145   HttpRequestTest* test;
146   bool done = false;
147   grpc_http_response response = {};
148   grpc_pollset_set* pollset_set_to_destroy_eagerly = nullptr;
149 };
150 
OnFinish(void * arg,grpc_error_handle error)151 void OnFinish(void* arg, grpc_error_handle error) {
152   RequestState* request_state = static_cast<RequestState*>(arg);
153   if (request_state->pollset_set_to_destroy_eagerly != nullptr) {
154     // Destroy the request's polling entity param. The goal is to try to catch a
155     // bug where we might still be referencing the polling entity by
156     // a pending TCP connect.
157     grpc_pollset_set_destroy(request_state->pollset_set_to_destroy_eagerly);
158   }
159   const char* expect =
160       "<html><head><title>Hello world!</title></head>"
161       "<body><p>This is a test</p></body></html>";
162   grpc_http_response response = request_state->response;
163   LOG(INFO) << "response status=" << response.status
164             << " error=" << grpc_core::StatusToString(error);
165   CHECK(error.ok());
166   CHECK_EQ(response.status, 200);
167   CHECK(response.body_length == strlen(expect));
168   CHECK_EQ(memcmp(expect, response.body, response.body_length), 0);
169   request_state->test->RunAndKick(
170       [request_state]() { request_state->done = true; });
171 }
172 
OnFinishExpectFailure(void * arg,grpc_error_handle error)173 void OnFinishExpectFailure(void* arg, grpc_error_handle error) {
174   RequestState* request_state = static_cast<RequestState*>(arg);
175   if (request_state->pollset_set_to_destroy_eagerly != nullptr) {
176     // Destroy the request's polling entity param. The goal is to try to catch a
177     // bug where we might still be referencing the polling entity by
178     // a pending TCP connect.
179     grpc_pollset_set_destroy(request_state->pollset_set_to_destroy_eagerly);
180   }
181   grpc_http_response response = request_state->response;
182   LOG(INFO) << "response status=" << response.status
183             << " error=" << grpc_core::StatusToString(error);
184   CHECK(!error.ok());
185   request_state->test->RunAndKick(
186       [request_state]() { request_state->done = true; });
187 }
188 
TEST_F(HttpRequestTest,Get)189 TEST_F(HttpRequestTest, Get) {
190   RequestState request_state(this);
191   grpc_http_request req;
192   grpc_core::ExecCtx exec_ctx;
193   std::string host = absl::StrFormat("localhost:%d", g_server_port);
194   LOG(INFO) << "requesting from " << host;
195   memset(&req, 0, sizeof(req));
196   auto uri = grpc_core::URI::Create(
197       "http", host, "/get",
198       /*query_parameter_pairs=*/{{"foo", "bar"}, {"baz", "quux"}},
199       /*fragment=*/"");
200   CHECK(uri.ok());
201   grpc_core::OrphanablePtr<grpc_core::HttpRequest> http_request =
202       grpc_core::HttpRequest::Get(
203           std::move(*uri), nullptr /* channel args */, pops(), &req,
204           NSecondsTime(15),
205           GRPC_CLOSURE_CREATE(OnFinish, &request_state,
206                               grpc_schedule_on_exec_ctx),
207           &request_state.response,
208           grpc_core::RefCountedPtr<grpc_channel_credentials>(
209               grpc_insecure_credentials_create()));
210   http_request->Start();
211   PollUntil([&request_state]() { return request_state.done; },
212             AbslDeadlineSeconds(60));
213 }
214 
TEST_F(HttpRequestTest,Post)215 TEST_F(HttpRequestTest, Post) {
216   RequestState request_state(this);
217   grpc_http_request req;
218   grpc_core::ExecCtx exec_ctx;
219   std::string host = absl::StrFormat("localhost:%d", g_server_port);
220   LOG(INFO) << "posting to " << host;
221   memset(&req, 0, sizeof(req));
222   req.body = const_cast<char*>("hello");
223   req.body_length = 5;
224   auto uri = grpc_core::URI::Create(
225       "http", host, "/post",
226       /*query_parameter_pairs=*/{{"foo", "bar"}, {"mumble", "frotz"}},
227       /*fragment=*/"");
228   CHECK(uri.ok());
229   grpc_core::OrphanablePtr<grpc_core::HttpRequest> http_request =
230       grpc_core::HttpRequest::Post(
231           std::move(*uri), nullptr /* channel args */, pops(), &req,
232           NSecondsTime(15),
233           GRPC_CLOSURE_CREATE(OnFinish, &request_state,
234                               grpc_schedule_on_exec_ctx),
235           &request_state.response,
236           grpc_core::RefCountedPtr<grpc_channel_credentials>(
237               grpc_insecure_credentials_create()));
238   http_request->Start();
239   PollUntil([&request_state]() { return request_state.done; },
240             AbslDeadlineSeconds(60));
241 }
242 
243 int g_fake_non_responsive_dns_server_port;
244 
InjectNonResponsiveDNSServer(ares_channel * channel)245 void InjectNonResponsiveDNSServer(ares_channel* channel) {
246   VLOG(2) << "Injecting broken nameserver list. Bad server address:|[::1]:"
247           << g_fake_non_responsive_dns_server_port << "|.";
248   // Configure a non-responsive DNS server at the front of c-ares's nameserver
249   // list.
250   struct ares_addr_port_node dns_server_addrs[1];
251   dns_server_addrs[0].family = AF_INET6;
252   (reinterpret_cast<char*>(&dns_server_addrs[0].addr.addr6))[15] = 0x1;
253   dns_server_addrs[0].tcp_port = g_fake_non_responsive_dns_server_port;
254   dns_server_addrs[0].udp_port = g_fake_non_responsive_dns_server_port;
255   dns_server_addrs[0].next = nullptr;
256   CHECK(ares_set_servers_ports(*channel, dns_server_addrs) == ARES_SUCCESS);
257 }
258 
TEST_F(HttpRequestTest,CancelGetDuringDNSResolution)259 TEST_F(HttpRequestTest, CancelGetDuringDNSResolution) {
260   // Inject an unresponsive DNS server into the resolver's DNS server config
261   grpc_core::testing::FakeUdpAndTcpServer fake_dns_server(
262       grpc_core::testing::FakeUdpAndTcpServer::AcceptMode::
263           kWaitForClientToSendFirstBytes,
264       grpc_core::testing::FakeUdpAndTcpServer::CloseSocketUponCloseFromPeer);
265   g_fake_non_responsive_dns_server_port = fake_dns_server.port();
266   void (*prev_test_only_inject_config)(ares_channel* channel) =
267       grpc_ares_test_only_inject_config;
268   grpc_ares_test_only_inject_config = InjectNonResponsiveDNSServer;
269   // Run the same test on several threads in parallel to try to trigger races
270   // etc.
271   int kNumThreads = 10;
272   std::vector<std::thread> threads;
273   threads.reserve(kNumThreads);
274   for (int i = 0; i < kNumThreads; i++) {
275     threads.push_back(std::thread([this]() {
276       RequestState request_state(this);
277       grpc_http_request req;
278       grpc_core::ExecCtx exec_ctx;
279       memset(&req, 0, sizeof(grpc_http_request));
280       auto uri = grpc_core::URI::Create(
281           "http", "dont-care-since-wont-be-resolved.test.com:443", "/get",
282           {} /* query params */, "" /* fragment */);
283       CHECK(uri.ok());
284       grpc_core::OrphanablePtr<grpc_core::HttpRequest> http_request =
285           grpc_core::HttpRequest::Get(
286               std::move(*uri), nullptr /* channel args */, pops(), &req,
287               NSecondsTime(120),
288               GRPC_CLOSURE_CREATE(OnFinishExpectFailure, &request_state,
289                                   grpc_schedule_on_exec_ctx),
290               &request_state.response,
291               grpc_core::RefCountedPtr<grpc_channel_credentials>(
292                   grpc_insecure_credentials_create()));
293       http_request->Start();
294       std::thread cancel_thread([&http_request]() {
295         gpr_sleep_until(grpc_timeout_seconds_to_deadline(1));
296         grpc_core::ExecCtx exec_ctx;
297         http_request.reset();
298       });
299       // Poll with a deadline explicitly lower than the request timeout, so
300       // that we know that the request timeout isn't just kicking in.
301       PollUntil([&request_state]() { return request_state.done; },
302                 AbslDeadlineSeconds(60));
303       cancel_thread.join();
304     }));
305   }
306   for (auto& t : threads) {
307     t.join();
308   }
309   grpc_ares_test_only_inject_config = prev_test_only_inject_config;
310 }
311 
TEST_F(HttpRequestTest,CancelGetWhileReadingResponse)312 TEST_F(HttpRequestTest, CancelGetWhileReadingResponse) {
313   // Start up a fake HTTP server which just accepts connections
314   // and then hangs, i.e. does not send back any bytes to the client.
315   // The goal here is to get the client to connect to this fake server
316   // and send a request, and then sit waiting for a response. Then, a
317   // separate thread will cancel the HTTP request, and that should let it
318   // complete.
319   grpc_core::testing::FakeUdpAndTcpServer fake_http_server(
320       grpc_core::testing::FakeUdpAndTcpServer::AcceptMode::
321           kWaitForClientToSendFirstBytes,
322       grpc_core::testing::FakeUdpAndTcpServer::CloseSocketUponCloseFromPeer);
323   // Run the same test on several threads in parallel to try to trigger races
324   // etc.
325   int kNumThreads = 10;
326   std::vector<std::thread> threads;
327   threads.reserve(kNumThreads);
328   for (int i = 0; i < kNumThreads; i++) {
329     grpc_core::testing::FakeUdpAndTcpServer* fake_http_server_ptr =
330         &fake_http_server;
331     threads.push_back(std::thread([this, fake_http_server_ptr]() {
332       RequestState request_state(this);
333       grpc_http_request req;
334       grpc_core::ExecCtx exec_ctx;
335       memset(&req, 0, sizeof(req));
336       auto uri = grpc_core::URI::Create("http", fake_http_server_ptr->address(),
337                                         "/get", {} /* query params */,
338                                         "" /* fragment */);
339       CHECK(uri.ok());
340       grpc_core::OrphanablePtr<grpc_core::HttpRequest> http_request =
341           grpc_core::HttpRequest::Get(
342               std::move(*uri), nullptr /* channel args */, pops(), &req,
343               NSecondsTime(120),
344               GRPC_CLOSURE_CREATE(OnFinishExpectFailure, &request_state,
345                                   grpc_schedule_on_exec_ctx),
346               &request_state.response,
347               grpc_core::RefCountedPtr<grpc_channel_credentials>(
348                   grpc_insecure_credentials_create()));
349       http_request->Start();
350       exec_ctx.Flush();
351       std::thread cancel_thread([&http_request]() {
352         gpr_sleep_until(grpc_timeout_seconds_to_deadline(1));
353         grpc_core::ExecCtx exec_ctx;
354         http_request.reset();
355       });
356       // Poll with a deadline explicitly lower than the request timeout, so
357       // that we know that the request timeout isn't just kicking in.
358       PollUntil([&request_state]() { return request_state.done; },
359                 AbslDeadlineSeconds(60));
360       cancel_thread.join();
361     }));
362   }
363   for (auto& t : threads) {
364     t.join();
365   }
366 }
367 
368 // The main point of this test is just to exercise the machinery around
369 // cancellation during TCP connection establishment, to make sure there are no
370 // crashes/races etc. This test doesn't actually verify that cancellation during
371 // TCP setup is happening, though. For that, we would need to induce packet loss
372 // in the test.
TEST_F(HttpRequestTest,CancelGetRacesWithConnectionFailure)373 TEST_F(HttpRequestTest, CancelGetRacesWithConnectionFailure) {
374   // Grab an unoccupied port but don't listen on it. The goal
375   // here is just to have a server address that will reject
376   // TCP connection setups.
377   // Note that because the server is rejecting TCP connections, we
378   // don't really need to cancel the HTTP requests in this test case
379   // in order for them proceed i.e. in order for them to pass. The test
380   // is still beneficial though because it can exercise the same code paths
381   // that would get taken if the HTTP request was cancelled while the TCP
382   // connect attempt was actually hanging.
383   int fake_server_port = grpc_pick_unused_port_or_die();
384   std::string fake_server_address =
385       absl::StrCat("[::1]:", std::to_string(fake_server_port));
386   // Run the same test on several threads in parallel to try to trigger races
387   // etc.
388   int kNumThreads = 10;
389   std::vector<std::thread> threads;
390   threads.reserve(kNumThreads);
391   for (int i = 0; i < kNumThreads; i++) {
392     threads.push_back(std::thread([this, fake_server_address]() {
393       RequestState request_state(this);
394       grpc_http_request req;
395       grpc_core::ExecCtx exec_ctx;
396       memset(&req, 0, sizeof(req));
397       auto uri =
398           grpc_core::URI::Create("http", fake_server_address, "/get",
399                                  {} /* query params */, "" /* fragment */);
400       CHECK(uri.ok());
401       grpc_core::OrphanablePtr<grpc_core::HttpRequest> http_request =
402           grpc_core::HttpRequest::Get(
403               std::move(*uri), nullptr /* channel args */, pops(), &req,
404               NSecondsTime(120),
405               GRPC_CLOSURE_CREATE(OnFinishExpectFailure, &request_state,
406                                   grpc_schedule_on_exec_ctx),
407               &request_state.response,
408               grpc_core::RefCountedPtr<grpc_channel_credentials>(
409                   grpc_insecure_credentials_create()));
410       // Start the HTTP request. We will ~immediately begin a TCP connect
411       // attempt because there's no name to resolve.
412       http_request->Start();
413       exec_ctx.Flush();
414       // Spawn a separate thread which ~immediately cancels the HTTP request.
415       // Note that even though the server is rejecting TCP connections, it can
416       // still take some time for the client to receive that rejection. So
417       // cancelling the request now can trigger the code paths that would get
418       // taken if the TCP connection was truly hanging e.g. from  packet loss.
419       // The goal is just to make sure there are no crashes, races, etc.
420       std::thread cancel_thread([&http_request]() {
421         grpc_core::ExecCtx exec_ctx;
422         http_request.reset();
423       });
424       // Poll with a deadline explicitly lower than the request timeout, so
425       // that we know that the request timeout isn't just kicking in.
426       PollUntil([&request_state]() { return request_state.done; },
427                 AbslDeadlineSeconds(60));
428       cancel_thread.join();
429     }));
430   }
431   for (auto& t : threads) {
432     t.join();
433   }
434 }
435 
436 // The pollent parameter passed to HttpRequest::Get or Post is owned by
437 // the caller and must not be referenced by the HttpRequest after the
438 // requests's on_done callback is invoked. This test verifies that this
439 // isn't happening by destroying the request's pollset set within the
440 // on_done callback.
TEST_F(HttpRequestTest,CallerPollentsAreNotReferencedAfterCallbackIsRan)441 TEST_F(HttpRequestTest, CallerPollentsAreNotReferencedAfterCallbackIsRan) {
442   // Grab an unoccupied port but don't listen on it. The goal
443   // here is just to have a server address that will reject
444   // TCP connection setups.
445   // Note that we could have used a different server for this test case, e.g.
446   // one which accepts TCP connections. All we need here is something for the
447   // client to connect to, since it will be cancelled roughly during the
448   // connection attempt anyways.
449   int fake_server_port = grpc_pick_unused_port_or_die();
450   std::string fake_server_address =
451       absl::StrCat("[::1]:", std::to_string(fake_server_port));
452   RequestState request_state(this);
453   grpc_http_request req;
454   grpc_core::ExecCtx exec_ctx;
455   memset(&req, 0, sizeof(req));
456   req.path = const_cast<char*>("/get");
457   request_state.pollset_set_to_destroy_eagerly = grpc_pollset_set_create();
458   grpc_polling_entity_add_to_pollset_set(
459       pops(), request_state.pollset_set_to_destroy_eagerly);
460   grpc_polling_entity wrapped_pollset_set_to_destroy_eagerly =
461       grpc_polling_entity_create_from_pollset_set(
462           request_state.pollset_set_to_destroy_eagerly);
463   auto uri = grpc_core::URI::Create("http", fake_server_address, "/get",
464                                     {} /* query params */, "" /* fragment */);
465   CHECK(uri.ok());
466   grpc_core::OrphanablePtr<grpc_core::HttpRequest> http_request =
467       grpc_core::HttpRequest::Get(
468           std::move(*uri), nullptr /* channel args */,
469           &wrapped_pollset_set_to_destroy_eagerly, &req, NSecondsTime(15),
470           GRPC_CLOSURE_CREATE(OnFinishExpectFailure, &request_state,
471                               grpc_schedule_on_exec_ctx),
472           &request_state.response,
473           grpc_core::RefCountedPtr<grpc_channel_credentials>(
474               grpc_insecure_credentials_create()));
475   // Start the HTTP request. We'll start the TCP connect attempt right away.
476   http_request->Start();
477   exec_ctx.Flush();
478   http_request.reset();  // cancel the request
479   // With iomgr polling:
480   // Since the request was cancelled, the on_done callback should be flushed
481   // out on the ExecCtx flush below. When the on_done callback is ran, it will
482   // eagerly destroy 'request_state.pollset_set_to_destroy_eagerly'. PollUntil's
483   // predicate should return true immediately.
484   //
485   // With EventEngine polling:
486   // Since the callback will be run asynchronously in another thread, with an
487   // independent ExecCtx, PollUntil is used here to ensure this test does not
488   // finish before the callback is run.
489   exec_ctx.Flush();
490   PollUntil([&request_state]() { return request_state.done; },
491             AbslDeadlineSeconds(60));
492 }
493 
CancelRequest(grpc_core::HttpRequest * req)494 void CancelRequest(grpc_core::HttpRequest* req) {
495   LOG(INFO) << "test only HttpRequest::OnHandshakeDone intercept orphaning "
496                "request: "
497             << req;
498   req->Orphan();
499 }
500 
501 // This exercises the code paths that happen when we cancel an HTTP request
502 // before the security handshake callback runs, but after that callback has
503 // already been scheduled with a success result. This case is interesting
504 // because the current security handshake API transfers ownership of output
505 // arguments to the caller only if the handshake is successful, rendering
506 // this code path as something that only occurs with just the right timing.
TEST_F(HttpRequestTest,CancelDuringSecurityHandshakeButHandshakeStillSucceeds)507 TEST_F(HttpRequestTest,
508        CancelDuringSecurityHandshakeButHandshakeStillSucceeds) {
509   RequestState request_state(this);
510   grpc_http_request req;
511   grpc_core::ExecCtx exec_ctx;
512   std::string host = absl::StrFormat("localhost:%d", g_server_port);
513   LOG(INFO) << "requesting from " << host;
514   memset(&req, 0, sizeof(req));
515   auto uri = grpc_core::URI::Create("http", host, "/get", {} /* query params */,
516                                     "" /* fragment */);
517   CHECK(uri.ok());
518   grpc_core::OrphanablePtr<grpc_core::HttpRequest> http_request =
519       grpc_core::HttpRequest::Get(
520           std::move(*uri), nullptr /* channel args */, pops(), &req,
521           NSecondsTime(15),
522           GRPC_CLOSURE_CREATE(OnFinishExpectFailure, &request_state,
523                               grpc_schedule_on_exec_ctx),
524           &request_state.response,
525           grpc_core::RefCountedPtr<grpc_channel_credentials>(
526               grpc_insecure_credentials_create()));
527   grpc_core::HttpRequest::TestOnlySetOnHandshakeDoneIntercept(CancelRequest);
528   http_request->Start();
529   (void)http_request.release();  // request will be orphaned by CancelRequest
530   exec_ctx.Flush();
531   PollUntil([&request_state]() { return request_state.done; },
532             AbslDeadlineSeconds(60));
533   grpc_core::HttpRequest::TestOnlySetOnHandshakeDoneIntercept(nullptr);
534 }
535 
536 }  // namespace
537 
main(int argc,char ** argv)538 int main(int argc, char** argv) {
539   ::testing::InitGoogleTest(&argc, argv);
540   grpc::testing::TestEnvironment env(&argc, argv);
541   // launch the test server later, so that --gtest_list_tests works
542   g_argc = argc;
543   g_argv = argv;
544   // run tests
545   return RUN_ALL_TESTS();
546 }
547