xref: /aosp_15_r20/external/grpc-grpc/test/core/http/httpscli_test.cc (revision cc02d7e222339f7a4f6ba5f422e6413f4bd931f2)
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 <string.h>
20 
21 #include <algorithm>
22 #include <functional>
23 #include <memory>
24 #include <string>
25 #include <thread>
26 #include <utility>
27 #include <vector>
28 
29 #include <gtest/gtest.h>
30 
31 #include "absl/status/statusor.h"
32 #include "absl/strings/str_format.h"
33 #include "absl/time/clock.h"
34 #include "absl/time/time.h"
35 
36 #include <grpc/grpc.h>
37 #include <grpc/impl/channel_arg_names.h>
38 #include <grpc/support/alloc.h>
39 #include <grpc/support/log.h>
40 #include <grpc/support/sync.h>
41 #include <grpc/support/time.h>
42 
43 #include "src/core/lib/channel/channel_args.h"
44 #include "src/core/lib/gpr/subprocess.h"
45 #include "src/core/lib/gprpp/orphanable.h"
46 #include "src/core/lib/gprpp/status_helper.h"
47 #include "src/core/lib/gprpp/sync.h"
48 #include "src/core/lib/gprpp/time.h"
49 #include "src/core/lib/gprpp/time_util.h"
50 #include "src/core/lib/http/httpcli.h"
51 #include "src/core/lib/http/httpcli_ssl_credentials.h"
52 #include "src/core/lib/http/parser.h"
53 #include "src/core/lib/iomgr/closure.h"
54 #include "src/core/lib/iomgr/error.h"
55 #include "src/core/lib/iomgr/exec_ctx.h"
56 #include "src/core/lib/iomgr/iomgr_fwd.h"
57 #include "src/core/lib/iomgr/polling_entity.h"
58 #include "src/core/lib/iomgr/pollset.h"
59 #include "src/core/lib/security/credentials/credentials.h"  // IWYU pragma: keep
60 #include "src/core/lib/uri/uri_parser.h"
61 #include "test/core/http/httpcli_test_util.h"
62 #include "test/core/util/fake_udp_and_tcp_server.h"
63 #include "test/core/util/test_config.h"
64 
65 namespace {
66 
NSecondsTime(int seconds)67 grpc_core::Timestamp NSecondsTime(int seconds) {
68   return grpc_core::Timestamp::FromTimespecRoundUp(
69       grpc_timeout_seconds_to_deadline(seconds));
70 }
71 
AbslDeadlineSeconds(int s)72 absl::Time AbslDeadlineSeconds(int s) {
73   return grpc_core::ToAbslTime(grpc_timeout_seconds_to_deadline(s));
74 }
75 
76 int g_argc;
77 char** g_argv;
78 int g_server_port;
79 gpr_subprocess* g_server;
80 
81 class HttpsCliTest : public ::testing::Test {
82  public:
HttpsCliTest()83   HttpsCliTest() {
84     grpc_init();
85     grpc_core::ExecCtx exec_ctx;
86     grpc_pollset* pollset =
87         static_cast<grpc_pollset*>(gpr_zalloc(grpc_pollset_size()));
88     grpc_pollset_init(pollset, &mu_);
89     pops_ = grpc_polling_entity_create_from_pollset(pollset);
90   }
~HttpsCliTest()91   ~HttpsCliTest() override {
92     {
93       grpc_core::ExecCtx exec_ctx;
94       grpc_pollset_shutdown(
95           grpc_polling_entity_pollset(&pops_),
96           GRPC_CLOSURE_CREATE(DestroyPops, &pops_, grpc_schedule_on_exec_ctx));
97     }
98     grpc_shutdown();
99   }
100 
RunAndKick(const std::function<void ()> & f)101   void RunAndKick(const std::function<void()>& f) {
102     grpc_core::MutexLockForGprMu lock(mu_);
103     f();
104     GPR_ASSERT(GRPC_LOG_IF_ERROR(
105         "pollset_kick",
106         grpc_pollset_kick(grpc_polling_entity_pollset(&pops_), nullptr)));
107   }
108 
PollUntil(const std::function<bool ()> & predicate,absl::Time deadline)109   void PollUntil(const std::function<bool()>& predicate, absl::Time deadline) {
110     gpr_mu_lock(mu_);
111     while (!predicate()) {
112       GPR_ASSERT(absl::Now() < deadline);
113       grpc_pollset_worker* worker = nullptr;
114       GPR_ASSERT(GRPC_LOG_IF_ERROR(
115           "pollset_work", grpc_pollset_work(grpc_polling_entity_pollset(&pops_),
116                                             &worker, NSecondsTime(1))));
117       gpr_mu_unlock(mu_);
118       gpr_mu_lock(mu_);
119     }
120     gpr_mu_unlock(mu_);
121   }
122 
pops()123   grpc_polling_entity* pops() { return &pops_; }
124 
125  protected:
SetUpTestSuite()126   static void SetUpTestSuite() {
127     auto test_server = grpc_core::testing::StartHttpRequestTestServer(
128         g_argc, g_argv, true /* use_ssl */);
129     g_server = test_server.server;
130     g_server_port = test_server.port;
131   }
132 
TearDownTestSuite()133   static void TearDownTestSuite() { gpr_subprocess_destroy(g_server); }
134 
135  private:
DestroyPops(void * p,grpc_error_handle)136   static void DestroyPops(void* p, grpc_error_handle /*error*/) {
137     grpc_polling_entity* pops = static_cast<grpc_polling_entity*>(p);
138     grpc_pollset_destroy(grpc_polling_entity_pollset(pops));
139     gpr_free(grpc_polling_entity_pollset(pops));
140   }
141 
142   gpr_mu* mu_;
143   grpc_polling_entity pops_;
144 };
145 
146 struct RequestState {
RequestState__anonbec7438f0111::RequestState147   explicit RequestState(HttpsCliTest* test) : test(test) {}
148 
~RequestState__anonbec7438f0111::RequestState149   ~RequestState() {
150     grpc_core::ExecCtx exec_ctx;
151     grpc_http_response_destroy(&response);
152   }
153 
154   HttpsCliTest* test;
155   bool done = false;
156   grpc_http_response response = {};
157 };
158 
OnFinish(void * arg,grpc_error_handle error)159 void OnFinish(void* arg, grpc_error_handle error) {
160   RequestState* request_state = static_cast<RequestState*>(arg);
161   const char* expect =
162       "<html><head><title>Hello world!</title></head>"
163       "<body><p>This is a test</p></body></html>";
164   grpc_http_response response = request_state->response;
165   gpr_log(GPR_INFO, "response status=%d error=%s", response.status,
166           grpc_core::StatusToString(error).c_str());
167   GPR_ASSERT(error.ok());
168   GPR_ASSERT(response.status == 200);
169   GPR_ASSERT(response.body_length == strlen(expect));
170   GPR_ASSERT(0 == memcmp(expect, response.body, response.body_length));
171   request_state->test->RunAndKick(
172       [request_state]() { request_state->done = true; });
173 }
174 
OnFinishExpectFailure(void * arg,grpc_error_handle error)175 void OnFinishExpectFailure(void* arg, grpc_error_handle error) {
176   RequestState* request_state = static_cast<RequestState*>(arg);
177   grpc_http_response response = request_state->response;
178   gpr_log(GPR_INFO, "response status=%d error=%s", response.status,
179           grpc_core::StatusToString(error).c_str());
180   GPR_ASSERT(!error.ok());
181   request_state->test->RunAndKick(
182       [request_state]() { request_state->done = true; });
183 }
184 
TEST_F(HttpsCliTest,Get)185 TEST_F(HttpsCliTest, Get) {
186   RequestState request_state(this);
187   grpc_http_request req;
188   grpc_core::ExecCtx exec_ctx;
189   std::string host = absl::StrFormat("localhost:%d", g_server_port);
190   gpr_log(GPR_INFO, "requesting from %s", host.c_str());
191   memset(&req, 0, sizeof(req));
192   grpc_arg ssl_override_arg = grpc_channel_arg_string_create(
193       const_cast<char*>(GRPC_SSL_TARGET_NAME_OVERRIDE_ARG),
194       const_cast<char*>("foo.test.google.fr"));
195   grpc_channel_args args = {1, &ssl_override_arg};
196   auto uri = grpc_core::URI::Create("https", host, "/get",
197                                     {} /* query params */, "" /* fragment */);
198   GPR_ASSERT(uri.ok());
199   grpc_core::OrphanablePtr<grpc_core::HttpRequest> http_request =
200       grpc_core::HttpRequest::Get(
201           std::move(*uri), &args, pops(), &req, NSecondsTime(15),
202           GRPC_CLOSURE_CREATE(OnFinish, &request_state,
203                               grpc_schedule_on_exec_ctx),
204           &request_state.response,
205           grpc_core::CreateHttpRequestSSLCredentials());
206   http_request->Start();
207   PollUntil([&request_state]() { return request_state.done; },
208             AbslDeadlineSeconds(60));
209 }
210 
TEST_F(HttpsCliTest,Post)211 TEST_F(HttpsCliTest, Post) {
212   RequestState request_state(this);
213   grpc_http_request req;
214   grpc_core::ExecCtx exec_ctx;
215   std::string host = absl::StrFormat("localhost:%d", g_server_port);
216   gpr_log(GPR_INFO, "posting to %s", host.c_str());
217   memset(&req, 0, sizeof(req));
218   req.body = const_cast<char*>("hello");
219   req.body_length = 5;
220   grpc_arg ssl_override_arg = grpc_channel_arg_string_create(
221       const_cast<char*>(GRPC_SSL_TARGET_NAME_OVERRIDE_ARG),
222       const_cast<char*>("foo.test.google.fr"));
223   grpc_channel_args args = {1, &ssl_override_arg};
224   auto uri = grpc_core::URI::Create("https", host, "/post",
225                                     {} /* query params */, "" /* fragment */);
226   GPR_ASSERT(uri.ok());
227   grpc_core::OrphanablePtr<grpc_core::HttpRequest> http_request =
228       grpc_core::HttpRequest::Post(
229           std::move(*uri), &args /* channel args */, pops(), &req,
230           NSecondsTime(15),
231           GRPC_CLOSURE_CREATE(OnFinish, &request_state,
232                               grpc_schedule_on_exec_ctx),
233           &request_state.response,
234           grpc_core::CreateHttpRequestSSLCredentials());
235   http_request->Start();
236   PollUntil([&request_state]() { return request_state.done; },
237             AbslDeadlineSeconds(60));
238 }
239 
240 // The goal of this test is to make sure that we can cancel HTTP requests
241 // while they're waiting for a response from the server to finish their
242 // SSL handshakes. Note that the main focus of this test is to just exercise
243 // the relevant code paths and make sure there aren't any crashes etc., rather
244 // than to make sure that cancellation happens in a timely manner.
TEST_F(HttpsCliTest,CancelGetDuringSSLHandshake)245 TEST_F(HttpsCliTest, CancelGetDuringSSLHandshake) {
246   // Start up a fake TCP server which accepts connections and then hangs,
247   // i.e. it won't send any bytes back to the client.
248   grpc_core::testing::FakeUdpAndTcpServer fake_http_server(
249       grpc_core::testing::FakeUdpAndTcpServer::AcceptMode::
250           kWaitForClientToSendFirstBytes,
251       grpc_core::testing::FakeUdpAndTcpServer::CloseSocketUponCloseFromPeer);
252   // Use multiple threads to try to trigger races etc.
253   int kNumThreads = 10;
254   std::vector<std::thread> threads;
255   threads.reserve(kNumThreads);
256   for (int i = 0; i < kNumThreads; i++) {
257     grpc_core::testing::FakeUdpAndTcpServer* fake_http_server_ptr =
258         &fake_http_server;
259     threads.push_back(std::thread([this, fake_http_server_ptr]() {
260       RequestState request_state(this);
261       grpc_http_request req;
262       grpc_core::ExecCtx exec_ctx;
263       memset(&req, 0, sizeof(req));
264       grpc_arg ssl_override_arg = grpc_channel_arg_string_create(
265           const_cast<char*>(GRPC_SSL_TARGET_NAME_OVERRIDE_ARG),
266           const_cast<char*>("foo.test.google.fr"));
267       grpc_channel_args args = {1, &ssl_override_arg};
268       auto uri = grpc_core::URI::Create(
269           "https", fake_http_server_ptr->address(), "/get",
270           {} /* query params */, "" /* fragment */);
271       grpc_core::OrphanablePtr<grpc_core::HttpRequest> http_request =
272           grpc_core::HttpRequest::Get(
273               std::move(*uri), &args, pops(), &req, NSecondsTime(120),
274               GRPC_CLOSURE_CREATE(OnFinishExpectFailure, &request_state,
275                                   grpc_schedule_on_exec_ctx),
276               &request_state.response,
277               grpc_core::CreateHttpRequestSSLCredentials());
278       // Start a request. It will establish a TCP connection to the
279       // server and then begin an SSL handshake. The server won't send
280       // anything back though, so it will be stuck in its SSL handshake,
281       // waiting for the firt response from the server.
282       http_request->Start();
283       exec_ctx.Flush();
284       std::thread cancel_thread([&http_request]() {
285         // Give one second to let the client get into the middle of its
286         // SSL handshake, and then cancel the request.
287         gpr_sleep_until(grpc_timeout_seconds_to_deadline(1));
288         grpc_core::ExecCtx exec_ctx;
289         http_request.reset();
290       });
291       // Poll with a deadline explicitly lower than the request timeout, so
292       // that we know that the request timeout isn't just kicking in.
293       PollUntil([&request_state]() { return request_state.done; },
294                 AbslDeadlineSeconds(60));
295       cancel_thread.join();
296     }));
297   }
298   for (auto& t : threads) {
299     t.join();
300   }
301 }
302 
303 }  // namespace
304 
main(int argc,char ** argv)305 int main(int argc, char** argv) {
306   ::testing::InitGoogleTest(&argc, argv);
307   grpc::testing::TestEnvironment env(&argc, argv);
308   // launch the test server later, so that --gtest_list_tests works
309   g_argc = argc;
310   g_argv = argv;
311   // run tests
312   return RUN_ALL_TESTS();
313 }
314