Minor adjustment for BOM strings
This commit is contained in:
@@ -42,6 +42,21 @@ void beginRequest(const char* operation) {
|
|||||||
KOReaderSyncClient::lastContigHeapAtFailure = heap_caps_get_largest_free_block(MALLOC_CAP_8BIT | MALLOC_CAP_DEFAULT);
|
KOReaderSyncClient::lastContigHeapAtFailure = heap_caps_get_largest_free_block(MALLOC_CAP_8BIT | MALLOC_CAP_DEFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Skip a leading UTF-8 BOM (EF BB BF) and ASCII whitespace, returning a pointer
|
||||||
|
// to the first content character. Used by response-body checks that verify the
|
||||||
|
// payload starts with '{' (JSON) rather than '<' (HTML captive-portal page).
|
||||||
|
const char* skipBomAndWhitespace(const char* p) {
|
||||||
|
// UTF-8 BOM
|
||||||
|
if (static_cast<unsigned char>(p[0]) == 0xEF && static_cast<unsigned char>(p[1]) == 0xBB &&
|
||||||
|
static_cast<unsigned char>(p[2]) == 0xBF) {
|
||||||
|
p += 3;
|
||||||
|
}
|
||||||
|
while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
// Device identifier for CrossPoint reader
|
// Device identifier for CrossPoint reader
|
||||||
constexpr char DEVICE_NAME[] = "CrossPoint";
|
constexpr char DEVICE_NAME[] = "CrossPoint";
|
||||||
constexpr char DEVICE_ID[] = "crosspoint-reader";
|
constexpr char DEVICE_ID[] = "crosspoint-reader";
|
||||||
@@ -377,19 +392,8 @@ KOReaderSyncClient::Error KOReaderSyncClient::authenticate() {
|
|||||||
if (err != ESP_OK) return NETWORK_ERROR;
|
if (err != ESP_OK) return NETWORK_ERROR;
|
||||||
if (httpCode >= 300 && httpCode < 400) return REDIRECT_ERROR;
|
if (httpCode >= 300 && httpCode < 400) return REDIRECT_ERROR;
|
||||||
if (httpCode == 200) {
|
if (httpCode == 200) {
|
||||||
// The kosync auth response is always a JSON object. Guard against a reverse
|
// Guard against a reverse proxy or captive portal returning HTTP 200 + HTML.
|
||||||
// proxy returning HTTP 200 + HTML (e.g. a login wall that followed all
|
if (!activeBuf->data || *skipBomAndWhitespace(activeBuf->data) != '{') {
|
||||||
// redirects and landed on an auth page instead of the API endpoint).
|
|
||||||
// Skip leading whitespace before checking for '{' so servers that emit
|
|
||||||
// a BOM or indent their JSON don't get incorrectly rejected.
|
|
||||||
if (!activeBuf->data) {
|
|
||||||
return INVALID_RESPONSE;
|
|
||||||
}
|
|
||||||
const char* p = activeBuf->data;
|
|
||||||
while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
|
|
||||||
p++;
|
|
||||||
}
|
|
||||||
if (*p != '{') {
|
|
||||||
return INVALID_RESPONSE;
|
return INVALID_RESPONSE;
|
||||||
}
|
}
|
||||||
return OK;
|
return OK;
|
||||||
@@ -577,14 +581,10 @@ KOReaderSyncClient::Error KOReaderSyncClient::updateProgress(const KOReaderProgr
|
|||||||
if (err != ESP_OK) return NETWORK_ERROR;
|
if (err != ESP_OK) return NETWORK_ERROR;
|
||||||
if (httpCode >= 300 && httpCode < 400) return REDIRECT_ERROR;
|
if (httpCode >= 300 && httpCode < 400) return REDIRECT_ERROR;
|
||||||
if (httpCode == 200 || httpCode == 202) {
|
if (httpCode == 200 || httpCode == 202) {
|
||||||
// Guard against a reverse proxy or captive portal returning HTTP 200 + HTML
|
// Guard against a reverse proxy or captive portal returning HTTP 200 + HTML.
|
||||||
// instead of the real API response, consistent with authenticate()'s check.
|
|
||||||
if (activeBuf->data) {
|
if (activeBuf->data) {
|
||||||
const char* p = activeBuf->data;
|
const char c = *skipBomAndWhitespace(activeBuf->data);
|
||||||
while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
|
if (c != '\0' && c != '{') {
|
||||||
p++;
|
|
||||||
}
|
|
||||||
if (*p != '\0' && *p != '{') {
|
|
||||||
return INVALID_RESPONSE;
|
return INVALID_RESPONSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -609,13 +609,13 @@ const char* KOReaderSyncClient::lastFailureDetail() {
|
|||||||
}
|
}
|
||||||
// Network/TLS case: esp_http_client_perform() failed before getting a status code.
|
// Network/TLS case: esp_http_client_perform() failed before getting a status code.
|
||||||
if (lastHttpCode == 0 && lastEspError != 0) {
|
if (lastHttpCode == 0 && lastEspError != 0) {
|
||||||
// Detect TLS handshake failures on HTTPS URLs — likely caused by the server
|
// HTTPS connect failures can be TLS version issues (ESP32 only supports up
|
||||||
// requiring TLS 1.3 which the ESP32 mbedTLS library does not support.
|
// to TLS 1.2), but also DNS, cert, or plain network problems. Include the
|
||||||
|
// error name and heap stats so the user/bug-report has enough to triage.
|
||||||
if (lastEspError == ESP_ERR_HTTP_CONNECT && KOREADER_STORE.getBaseUrl().rfind("https", 0) == 0) {
|
if (lastEspError == ESP_ERR_HTTP_CONNECT && KOREADER_STORE.getBaseUrl().rfind("https", 0) == 0) {
|
||||||
snprintf(
|
snprintf(g_failureDetailBuf, sizeof(g_failureDetailBuf),
|
||||||
g_failureDetailBuf, sizeof(g_failureDetailBuf),
|
"%s: connect failed — check network, DNS, certs, or TLS 1.2 compat (heap %u/%u contig)", lastOperation,
|
||||||
"%s: TLS handshake failed. Server may require TLS 1.3 (unsupported). Try a different server or use HTTP.",
|
lastHeapAtFailure, lastContigHeapAtFailure);
|
||||||
lastOperation);
|
|
||||||
} else {
|
} else {
|
||||||
snprintf(g_failureDetailBuf, sizeof(g_failureDetailBuf), "%s: %s (heap %u/%u contig)", lastOperation,
|
snprintf(g_failureDetailBuf, sizeof(g_failureDetailBuf), "%s: %s (heap %u/%u contig)", lastOperation,
|
||||||
esp_err_to_name(lastEspError), lastHeapAtFailure, lastContigHeapAtFailure);
|
esp_err_to_name(lastEspError), lastHeapAtFailure, lastContigHeapAtFailure);
|
||||||
|
|||||||
Reference in New Issue
Block a user