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