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