Skip to content

Commit ea6b7dd

Browse files
authored
Merge pull request #1301 from dgreatwood/clientTimeoutNoNet
Fix: Avoid https_client_test_net Hang If No Network
2 parents 94be9f0 + a0301c5 commit ea6b7dd

File tree

2 files changed

+213
-105
lines changed

2 files changed

+213
-105
lines changed

tests/https_client_test_net.cc

+212-104
Original file line numberDiff line numberDiff line change
@@ -138,47 +138,114 @@ TEST(https_client_test, one_client_with_google_request)
138138
Http::Experimental::Client client;
139139
client.init();
140140

141-
auto rb = client.get(server_address);
142-
auto response = rb.header<Http::Header::Connection>(
143-
Http::ConnectionControl::KeepAlive).send();
144141
bool done = false;
145-
response.then(
146-
[&done](Http::Response rsp) {
147-
PS_LOG_DEBUG_ARGS("http rsp code: %d", rsp.code());
148-
if (rsp.code() == Http::Code::Ok)
149-
{
150-
done = true;
151-
// const std::string bdy(rsp.body());
152-
}
153-
else if (rsp.code() == Http::Code::Found)
154-
{
155-
// Feb-2025: These HTTP 302 (temporarily moved aka Found)
156-
// responses seem to come very roughly once every 3000 Google
157-
// search requests
158-
PS_LOG_INFO("Temporarily Moved (aka Found) from google.com");
159-
done = true;
160-
}
161-
else if ((rsp.code() == Http::Code::Temporary_Redirect) ||
162-
(rsp.code() == Http::Code::See_Other))
163-
{
164-
// Feb-2025: We have not seen these HTTP 307 (Temporary
165-
// Redirect) or HTTP 303 (See Other) responses from google.com,
166-
// but include them here since they are so similar to HTTP 302,
167-
// which we do see.
168-
PS_LOG_INFO("Temporary Redirect or See Other from google.com");
169-
done = true;
170-
}
171-
},
172-
Async::IgnoreException);
142+
auto rb = client.get(server_address);
143+
try {
144+
auto response = rb.header<Http::Header::Connection>(
145+
Http::ConnectionControl::KeepAlive).send();
146+
147+
response.then(
148+
[&done](Http::Response rsp) {
149+
PS_LOG_DEBUG_ARGS("http rsp code: %d", rsp.code());
150+
if (rsp.code() == Http::Code::Ok)
151+
{
152+
done = true;
153+
// const std::string bdy(rsp.body());
154+
}
155+
else if (rsp.code() == Http::Code::Found)
156+
{
157+
// Feb-2025: These HTTP 302 (temporarily moved aka Found)
158+
// responses seem to come very roughly once every 3000
159+
// Google search requests
160+
PS_LOG_INFO(
161+
"Temporarily Moved (aka Found) from google.com");
162+
done = true;
163+
}
164+
else if ((rsp.code() == Http::Code::Temporary_Redirect) ||
165+
(rsp.code() == Http::Code::See_Other))
166+
{
167+
// Feb-2025: We have not seen these HTTP 307 (Temporary
168+
// Redirect) or HTTP 303 (See Other) responses from
169+
// google.com, but include them here since they are so
170+
// similar to HTTP 302, which we do see.
171+
PS_LOG_INFO(
172+
"Temporary Redirect or See Other from google.com");
173+
done = true;
174+
}
175+
},
176+
Async::IgnoreException);
173177

174-
Async::Barrier<Http::Response> barrier(response);
175-
barrier.wait_for(std::chrono::seconds(5));
178+
Async::Barrier<Http::Response> barrier(response);
179+
barrier.wait_for(std::chrono::seconds(5));
180+
}
181+
catch (const std::exception& e)
182+
{
183+
PS_LOG_WARNING_ARGS("Exception fetching from google.com: %s",
184+
e.what());
185+
// This can happen if google.com is unreachable, e.g. we have no
186+
// network connection
187+
}
176188

177189
client.shutdown();
178190

179191
ASSERT_TRUE(done);
180192
}
181193

194+
TEST(https_client_test, one_client_with_nonexisitent_url_request)
195+
{
196+
PS_TIMEDBG_START;
197+
198+
const std::string server_address(
199+
"https://www.gog27isnothere2xajsh.com/search?q=pistache+HTTP+REST");
200+
201+
Http::Experimental::Client client;
202+
client.init();
203+
204+
bool done = false;
205+
bool excep = false;
206+
auto rb = client.get(server_address);
207+
try {
208+
auto response = rb.header<Http::Header::Connection>(
209+
Http::ConnectionControl::KeepAlive).send();
210+
211+
response.then(
212+
[&done](Http::Response rsp) {
213+
PS_LOG_DEBUG_ARGS("http rsp code: %d", rsp.code());
214+
if (rsp.code() == Http::Code::Ok)
215+
{
216+
done = true;
217+
// const std::string bdy(rsp.body());
218+
}
219+
else if (rsp.code() == Http::Code::Found)
220+
{
221+
PS_LOG_INFO("Temporarily Moved (aka Found)");
222+
done = true;
223+
}
224+
else if ((rsp.code() == Http::Code::Temporary_Redirect) ||
225+
(rsp.code() == Http::Code::See_Other))
226+
{
227+
PS_LOG_INFO("Temporary Redirect or See Other");
228+
done = true;
229+
}
230+
},
231+
Async::IgnoreException);
232+
233+
Async::Barrier<Http::Response> barrier(response);
234+
barrier.wait_for(std::chrono::seconds(5));
235+
}
236+
catch (const std::exception& e)
237+
{
238+
PS_LOG_DEBUG_ARGS("Exception fetching from nonexisitent URL: %s",
239+
e.what());
240+
excep = true;
241+
}
242+
243+
client.shutdown();
244+
245+
ASSERT_TRUE(excep);
246+
ASSERT_FALSE(done);
247+
}
248+
182249
TEST(https_client_test, one_client_with_bad_google_request)
183250
{
184251
PS_TIMEDBG_START;
@@ -189,28 +256,39 @@ TEST(https_client_test, one_client_with_bad_google_request)
189256
Http::Experimental::Client client;
190257
client.init();
191258

192-
auto rb = client.get(server_address);
193-
auto response = rb.header<Http::Header::Connection>(
194-
Http::ConnectionControl::KeepAlive) .send();
259+
auto rb = client.get(server_address);
195260
bool done = false;
196261
bool error_404 = false;
197262

198-
response.then(
199-
[&done, &error_404](Http::Response rsp) {
200-
PS_LOG_DEBUG_ARGS("http rsp code (expect 404): %d", rsp.code());
201-
if (rsp.code() == Http::Code::Ok)
202-
{
203-
done = true;
204-
}
205-
else if (rsp.code() == Http::Code::Not_Found)
206-
{
207-
error_404 = true;
208-
}
209-
},
210-
Async::IgnoreException);
263+
try {
264+
auto response = rb.header<Http::Header::Connection>(
265+
Http::ConnectionControl::KeepAlive) .send();
211266

212-
Async::Barrier<Http::Response> barrier(response);
213-
barrier.wait_for(std::chrono::seconds(5));
267+
response.then(
268+
[&done, &error_404](Http::Response rsp) {
269+
PS_LOG_DEBUG_ARGS("http rsp code (expect 404): %d",
270+
rsp.code());
271+
if (rsp.code() == Http::Code::Ok)
272+
{
273+
done = true;
274+
}
275+
else if (rsp.code() == Http::Code::Not_Found)
276+
{
277+
error_404 = true;
278+
}
279+
},
280+
Async::IgnoreException);
281+
282+
Async::Barrier<Http::Response> barrier(response);
283+
barrier.wait_for(std::chrono::seconds(5));
284+
}
285+
catch (const std::exception& e)
286+
{
287+
PS_LOG_WARNING_ARGS("Exception fetching from google.com: %s",
288+
e.what());
289+
// This can happen if google.com is unreachable, e.g. we have no
290+
// network connection
291+
}
214292

215293
client.shutdown();
216294

@@ -283,62 +361,76 @@ TEST(https_client_test, multiple_clients_with_multiple_search_requests)
283361
server_address_start[server_address_idx] + query[i]);
284362
auto rb = client[j].get(server_address);
285363

286-
auto response = rb.header<Http::Header::Connection>(
287-
Http::ConnectionControl::KeepAlive)
288-
.send();
289-
response.then(
290-
[&response_counter, &response_correct_counter,
291-
server_address_idx,
292-
i,
293-
j,
294-
resp_substr](Http::Response rsp) {
295-
PS_LOG_DEBUG("Http::Response");
296-
297-
if (rsp.code() == Http::Code::Ok)
298-
{
299-
++response_counter;
300-
if (0 == server_address_idx)
364+
try {
365+
auto response = rb.header<Http::Header::Connection>(
366+
Http::ConnectionControl::KeepAlive)
367+
.send();
368+
response.then(
369+
[&response_counter, &response_correct_counter,
370+
server_address_idx,
371+
i,
372+
j,
373+
resp_substr](Http::Response rsp) {
374+
PS_LOG_DEBUG("Http::Response");
375+
376+
if (rsp.code() == Http::Code::Ok)
301377
{
302-
const std::string bdy(rsp.body());
303-
auto it = std::search(
304-
bdy.begin(), bdy.end(),
305-
resp_substr[i].begin(), resp_substr[i].end(),
306-
[](unsigned char ch1, unsigned char ch2)
307-
{ return std::toupper(ch1) == std::toupper(ch2);
308-
});
309-
if (it != bdy.end())
310-
++response_correct_counter;
311-
else
312-
PS_LOG_WARNING_ARGS(
313-
"For i=%d, j=%d, %s not found in resp %s",
314-
i, j,
315-
resp_substr[i].c_str(), bdy.c_str());
316-
}
378+
++response_counter;
379+
if (0 == server_address_idx)
380+
{
381+
const std::string bdy(rsp.body());
382+
auto it = std::search(
383+
bdy.begin(), bdy.end(),
384+
resp_substr[i].begin(), resp_substr[i].end(),
385+
[](unsigned char ch1, unsigned char ch2)
386+
{ return std::toupper(ch1) == std::toupper(ch2);
387+
});
388+
if (it != bdy.end())
389+
++response_correct_counter;
390+
else
391+
PS_LOG_WARNING_ARGS(
392+
"For i=%d, j=%d, %s "
393+
"not found in resp %s",
394+
i, j,
395+
resp_substr[i].c_str(), bdy.c_str());
396+
}
317397

318-
}
319-
else if ((rsp.code() == Http::Code::Found) ||
320-
(rsp.code() == Http::Code::Temporary_Redirect) ||
321-
(rsp.code() == Http::Code::See_Other))
322-
{
323-
// Feb-2025: See prior comment re: Http::Code::Found
324-
PS_LOG_INFO("Temporary redirect");
325-
++response_counter;
326-
}
327-
else
328-
{
329-
PS_LOG_WARNING_ARGS("Http::Response error code %d",
330-
rsp.code());
331-
}
332-
},
333-
Async::IgnoreException);
334-
responses.push_back(std::move(response));
398+
}
399+
else if ((rsp.code() == Http::Code::Found) ||
400+
(rsp.code() == Http::Code::Temporary_Redirect) ||
401+
(rsp.code() == Http::Code::See_Other))
402+
{
403+
// Feb-2025: See prior comment re:
404+
// Http::Code::Found
405+
PS_LOG_INFO("Temporary redirect");
406+
++response_counter;
407+
}
408+
else
409+
{
410+
PS_LOG_WARNING_ARGS("Http::Response error code %d",
411+
rsp.code());
412+
}
413+
},
414+
Async::IgnoreException);
415+
responses.push_back(std::move(response));
416+
}
417+
catch (const std::exception& e)
418+
{
419+
PS_LOG_WARNING_ARGS("Exception fetching from %s: %s",
420+
server_address.c_str(), e.what());
421+
// This can happen if URL is unreachable, e.g. we have no
422+
// network connection
423+
}
335424
}
336425
}
337426

338-
auto sync = Async::whenAll(responses.begin(), responses.end());
339-
Async::Barrier<std::vector<Http::Response>> barrier(sync);
427+
if (!responses.empty())
428+
{
429+
auto sync = Async::whenAll(responses.begin(), responses.end());
430+
Async::Barrier<std::vector<Http::Response>> barrier(sync);
340431

341-
barrier.wait_for(std::chrono::seconds(15));
432+
barrier.wait_for(std::chrono::seconds(15));
433+
}
342434

343435
for (unsigned int j = 0; j < CLIENT_SIZE; ++j)
344436
{
@@ -413,10 +505,12 @@ TEST(https_client_test, one_cli_mult_reqs_force_https_verification_that_fails)
413505
std::vector<Async::Promise<Http::Response>> responses;
414506
const int RESPONSE_SIZE = 3;
415507
int response_counter = 0;
508+
bool excep = false;
416509

417510
auto rb = client.get(server_address);
418511
for (int i = 0; i < RESPONSE_SIZE; ++i)
419512
{
513+
try {
420514
auto response = rb.send();
421515
response.then(
422516
[&response_counter](Http::Response rsp) {
@@ -426,15 +520,29 @@ TEST(https_client_test, one_cli_mult_reqs_force_https_verification_that_fails)
426520
Async::IgnoreException);
427521

428522
responses.push_back(std::move(response));
523+
}
524+
catch (const std::exception& e)
525+
{
526+
PS_LOG_WARNING_ARGS("Exception fetching from %s: %s",
527+
server_address.c_str(), e.what());
528+
// This can happen if URL is unreachable, e.g. we have no network
529+
// connection
530+
531+
excep = true;
532+
}
429533
}
430534

431-
auto sync = Async::whenAll(responses.begin(), responses.end());
432-
Async::Barrier<std::vector<Http::Response>> barrier(sync);
535+
if (!responses.empty())
536+
{
537+
auto sync = Async::whenAll(responses.begin(), responses.end());
538+
Async::Barrier<std::vector<Http::Response>> barrier(sync);
433539

434-
barrier.wait_for(std::chrono::seconds(5));
540+
barrier.wait_for(std::chrono::seconds(5));
541+
}
435542

436543
server.shutdown();
437544
client.shutdown();
438545

439546
ASSERT_EQ(response_counter, 0);
547+
ASSERT_FALSE(excep);
440548
}

version.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
0.5.4.20250315
1+
0.5.5.20250316

0 commit comments

Comments
 (0)