Skip to content

Commit ad2ab78

Browse files
authored
📚 Update cpp-httplib, log error code on failed HTTP requests (#81)
This change updates us to `v0.8.4` of [cpp-httplib](https://github.com/yhirose/cpp-httplib), which includes a decent number of fixes to bugs that I suspect may be causing some of our HTTPS request failures we're seeing in production. As a result of some of the changes in the httplib update, a few changes were made to the ServiceConnection implementations to avoid copying of `httplib::Client` and `httplib::Result` instances (they are now backed by `unique_ptr`). Additional logging detail was also added in the Glimesh HTTP request failure case so we can determine root cause if this doesn't resolve the failures. Verified by testing against local glimesh.tv instance.
1 parent 526aca4 commit ad2ab78

5 files changed

Lines changed: 34 additions & 53 deletions

File tree

src/ServiceConnections/GlimeshServiceConnection.cpp

Lines changed: 14 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
#include "../Utilities/FtlTypes.h"
1414

15+
#include <fmt/core.h>
1516
#include <jansson.h>
1617
#include <string.h>
1718
#include <spdlog/spdlog.h>
@@ -23,6 +24,7 @@ GlimeshServiceConnection::GlimeshServiceConnection(
2324
bool useHttps,
2425
std::string clientId,
2526
std::string clientSecret) :
27+
httpClient(fmt::format("{}://{}:{}", (useHttps ? "https" : "http"), hostname, port).c_str()),
2628
hostname(hostname),
2729
port(port),
2830
useHttps(useHttps),
@@ -193,30 +195,11 @@ Result<void> GlimeshServiceConnection::SendJpegPreviewImage(
193195
#pragma endregion
194196

195197
#pragma region Private methods
196-
httplib::Client GlimeshServiceConnection::getHttpClient()
197-
{
198-
std::stringstream baseUri;
199-
baseUri << (useHttps ? "https" : "http") << "://" << hostname << ":" << port;
200-
httplib::Client client = httplib::Client(baseUri.str().c_str());
201-
202-
if (accessToken.length() > 0)
203-
{
204-
httplib::Headers headers
205-
{
206-
{"Authorization", "Bearer " + accessToken}
207-
};
208-
client.set_default_headers(headers);
209-
}
210-
211-
return client;
212-
}
213-
214198
void GlimeshServiceConnection::ensureAuth()
215199
{
216200
std::lock_guard<std::mutex> lock(authMutex);
217201

218202
// Do we already have an access token that hasn't expired?
219-
// TODO: Check expiration
220203
if (accessToken.length() > 0)
221204
{
222205
std::time_t currentTime = std::time(nullptr);
@@ -235,7 +218,6 @@ void GlimeshServiceConnection::ensureAuth()
235218
{ "scope", "streamkey" }
236219
};
237220

238-
httplib::Client httpClient = getHttpClient();
239221
if (httplib::Result res = httpClient.Post("/api/oauth/token", params))
240222
{
241223
if (res->status == 200)
@@ -267,6 +249,13 @@ void GlimeshServiceConnection::ensureAuth()
267249
std::time_t currentTime = std::time(nullptr);
268250
spdlog::info("Received new access token: {}, expires in {} - {} = {} seconds",
269251
accessToken, expirationTime, currentTime, (expirationTime - currentTime));
252+
253+
// Update HTTP client Authorization header
254+
httplib::Headers headers
255+
{
256+
{"Authorization", "Bearer " + accessToken}
257+
};
258+
httpClient.set_default_headers(headers);
270259
return;
271260
}
272261
}
@@ -311,7 +300,6 @@ JsonPtr GlimeshServiceConnection::runGraphQlQuery(
311300
int numRetries = 0;
312301
while (true)
313302
{
314-
httplib::Client httpClient = getHttpClient();
315303
JsonPtr result = nullptr;
316304

317305
// If we're doing files, use a multipart http request
@@ -334,7 +322,7 @@ JsonPtr GlimeshServiceConnection::runGraphQlQuery(
334322

335323
if (numRetries < MAX_RETRIES)
336324
{
337-
spdlog::warn("Attempt {} / {}: Glimesh file upload GraphQL query failed. "
325+
spdlog::warn("Attempt {} / {}: Glimesh GraphQL query failed. "
338326
"Retrying in {} ms...", (numRetries + 1), MAX_RETRIES, TIME_BETWEEN_RETRIES_MS);
339327

340328
std::this_thread::sleep_for(std::chrono::milliseconds(TIME_BETWEEN_RETRIES_MS));
@@ -347,13 +335,13 @@ JsonPtr GlimeshServiceConnection::runGraphQlQuery(
347335
}
348336

349337
// We've exceeded our retry limit
350-
spdlog::error("Aborting Glimesh file upload GraphQL query after {} failed attempts.",
338+
spdlog::error("Aborting Glimesh GraphQL query after {} failed attempts.",
351339
MAX_RETRIES);
352340

353341
throw ServiceConnectionCommunicationFailedException("Glimesh GraphQL query failed.");
354342
}
355343

356-
JsonPtr GlimeshServiceConnection::processGraphQlResponse(httplib::Result result)
344+
JsonPtr GlimeshServiceConnection::processGraphQlResponse(const httplib::Result& result)
357345
{
358346
if (result)
359347
{
@@ -382,7 +370,8 @@ JsonPtr GlimeshServiceConnection::processGraphQlResponse(httplib::Result result)
382370
}
383371
else
384372
{
385-
spdlog::warn("Glimesh service connection HTTP request failed.");
373+
spdlog::warn("Glimesh service connection HTTP request failed with error {}",
374+
result.error());
386375
return nullptr;
387376
}
388377
}

src/ServiceConnections/GlimeshServiceConnection.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,9 @@ class GlimeshServiceConnection :
4747

4848
private:
4949
/* Private members */
50-
const int MAX_RETRIES = 5;
50+
const int MAX_RETRIES = 10;
5151
const int TIME_BETWEEN_RETRIES_MS = 3000;
52+
httplib::Client httpClient;
5253
std::string hostname;
5354
uint16_t port;
5455
bool useHttps;
@@ -59,9 +60,8 @@ class GlimeshServiceConnection :
5960
std::mutex authMutex;
6061

6162
/* Private methods */
62-
httplib::Client getHttpClient();
6363
void ensureAuth();
6464
JsonPtr runGraphQlQuery(std::string query, JsonPtr variables = nullptr, httplib::MultipartFormDataItems fileData = httplib::MultipartFormDataItems());
65-
JsonPtr processGraphQlResponse(httplib::Result result);
65+
JsonPtr processGraphQlResponse(const httplib::Result& result);
6666
tm parseIso8601DateTime(std::string dateTimeString);
6767
};

src/ServiceConnections/RestServiceConnection.cpp

Lines changed: 12 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,22 @@ RestServiceConnection::RestServiceConnection(
2424
std::string pathBase,
2525
std::string authToken)
2626
:
27+
httpClient(createBaseUri(false).c_str()),
2728
hostname(hostname),
2829
port(port),
2930
useHttps(useHttps),
3031
pathBase(pathBase),
3132
authToken(authToken)
32-
{ }
33+
{
34+
if (authToken.length() > 0)
35+
{
36+
httplib::Headers headers
37+
{
38+
{"Authorization", authToken}
39+
};
40+
httpClient.set_default_headers(headers);
41+
}
42+
}
3343
#pragma endregion
3444

3545
#pragma region Public methods
@@ -203,30 +213,12 @@ std::string RestServiceConnection::constructPath(std::string path)
203213
return ss.str();
204214
}
205215

206-
httplib::Client RestServiceConnection::getHttpClient()
207-
{
208-
std::string baseUri = createBaseUri(false);
209-
httplib::Client client = httplib::Client(baseUri.c_str());
210-
211-
if (authToken.length() > 0)
212-
{
213-
httplib::Headers headers
214-
{
215-
{"Authorization", authToken}
216-
};
217-
client.set_default_headers(headers);
218-
}
219-
220-
return client;
221-
}
222-
223216
httplib::Result RestServiceConnection::runGetRequest(std::string url)
224217
{
225218
// Make the request, and retry if necessary
226219
int numRetries = 0;
227220
while (true)
228221
{
229-
httplib::Client httpClient = getHttpClient();
230222
std::string fullUrl = constructPath(url);
231223

232224
httplib::Result response = httpClient.Get(fullUrl.c_str());
@@ -277,7 +269,6 @@ httplib::Result RestServiceConnection::runPostRequest(
277269
int numRetries = 0;
278270
while (true)
279271
{
280-
httplib::Client httpClient = getHttpClient();
281272
std::string fullUrl = constructPath(url);
282273

283274
httplib::Result response = (fileData.size() > 0)
@@ -312,7 +303,7 @@ httplib::Result RestServiceConnection::runPostRequest(
312303
throw ServiceConnectionCommunicationFailedException("REST POST request failed.");
313304
}
314305

315-
JsonPtr RestServiceConnection::decodeRestResponse(httplib::Result result)
306+
JsonPtr RestServiceConnection::decodeRestResponse(const httplib::Result& result)
316307
{
317308
if (result)
318309
{

src/ServiceConnections/RestServiceConnection.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ class RestServiceConnection : public ServiceConnection
4545
/* Private members */
4646
const int MAX_RETRIES = 5;
4747
const int TIME_BETWEEN_RETRIES_MS = 3000;
48+
httplib::Client httpClient;
4849
std::string hostname;
4950
uint16_t port;
5051
bool useHttps;
@@ -56,8 +57,8 @@ class RestServiceConnection : public ServiceConnection
5657
std::string createBaseUri(bool includeBase);
5758
std::string constructPath(std::string path);
5859

59-
httplib::Client getHttpClient();
6060
httplib::Result runGetRequest(std::string url);
61-
httplib::Result runPostRequest(std::string url, JsonPtr body = nullptr, httplib::MultipartFormDataItems fileData = httplib::MultipartFormDataItems());
62-
JsonPtr decodeRestResponse(httplib::Result result);
61+
httplib::Result runPostRequest(std::string url, JsonPtr body = nullptr,
62+
httplib::MultipartFormDataItems fileData = httplib::MultipartFormDataItems());
63+
JsonPtr decodeRestResponse(const httplib::Result& result);
6364
};

0 commit comments

Comments
 (0)