Skip to content

Commit 36516ce

Browse files
committed
JSON-wrap HTML upstream errors
1 parent 9f7272b commit 36516ce

File tree

1 file changed

+32
-4
lines changed

1 file changed

+32
-4
lines changed

server/server.js

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,25 @@ function isJsonStatusError(payload) {
293293
);
294294
}
295295

296+
function isHtmlPayload(payload, headers = {}) {
297+
const contentType = headers?.['content-type'] || headers?.['Content-Type'] || '';
298+
if (typeof contentType === 'string' && contentType.toLowerCase().includes('text/html')) {
299+
return true;
300+
}
301+
if (typeof payload !== 'string') return false;
302+
return /<html[\s>]/i.test(payload) || /<!doctype html/i.test(payload);
303+
}
304+
305+
function normalizeUpstreamError(status, data, headers = {}) {
306+
if (isHtmlPayload(data, headers)) {
307+
return {
308+
status,
309+
data: { error: 'Server not reachable' }
310+
};
311+
}
312+
return { status, data };
313+
}
314+
296315
async function isServerUp(serverUrl) {
297316
if (!serverUrl || typeof serverUrl !== 'string') return false;
298317

@@ -475,15 +494,19 @@ app.post('/ios-request', trackProxyResponseTime(async (req, res) => {
475494

476495
if (isJsonStatusError(cobaltRes.data) && hasNextTarget) {
477496
logWithRequestIp('warn', req, `Server ${targetUrl} returned JSON status=error, trying next server`);
478-
lastServerResponse = { status: cobaltRes.status, data: cobaltRes.data };
497+
lastServerResponse = normalizeUpstreamError(cobaltRes.status, cobaltRes.data, cobaltRes.headers);
479498
continue;
480499
}
481500

482501
return res.status(cobaltRes.status).json(cobaltRes.data);
483502
} catch (err) {
484503
if (err.response && isJsonStatusError(err.response.data) && hasNextTarget) {
485504
logWithRequestIp('warn', req, `Server ${targetUrl} returned JSON status=error, trying next server`);
486-
lastServerResponse = { status: err.response.status, data: err.response.data };
505+
lastServerResponse = normalizeUpstreamError(
506+
err.response.status,
507+
err.response.data,
508+
err.response.headers
509+
);
487510
continue;
488511
}
489512
throw err;
@@ -496,8 +519,13 @@ app.post('/ios-request', trackProxyResponseTime(async (req, res) => {
496519
throw new Error('No server response available.');
497520
} catch (err) {
498521
if (err.response) {
499-
logWithRequestIp('error', req, 'Error in /ios-request:', err.response.data);
500-
res.status(err.response.status).json(err.response.data);
522+
const normalizedError = normalizeUpstreamError(
523+
err.response.status,
524+
err.response.data,
525+
err.response.headers
526+
);
527+
logWithRequestIp('error', req, 'Error in /ios-request:', normalizedError.data);
528+
res.status(normalizedError.status).json(normalizedError.data);
501529
} else {
502530
logWithRequestIp('error', req, 'Error in /ios-request:', err.message);
503531
res.status(500).json({ error: 'Internal server error' });

0 commit comments

Comments
 (0)