mirror of
https://github.com/Lissy93/web-check.git
synced 2026-05-13 06:01:02 -04:00
When the WebsiteCarbon API is protected by Cloudflare and requests originate from datacenter IPs, Cloudflare may return an HTML challenge page instead of JSON. This caused JSON.parse() to throw an uncaught SyntaxError exception, crashing the entire application. This fix: - Checks if the response starts with HTML markers before parsing - Wraps JSON.parse in try-catch for additional safety - Returns a descriptive error message instead of crashing Fixes #268
63 lines
2.0 KiB
JavaScript
63 lines
2.0 KiB
JavaScript
import https from 'https';
|
|
import middleware from './_common/middleware.js';
|
|
|
|
const carbonHandler = async (url) => {
|
|
|
|
// First, get the size of the website's HTML
|
|
const getHtmlSize = (url) => new Promise((resolve, reject) => {
|
|
https.get(url, res => {
|
|
let data = '';
|
|
res.on('data', chunk => {
|
|
data += chunk;
|
|
});
|
|
res.on('end', () => {
|
|
const sizeInBytes = Buffer.byteLength(data, 'utf8');
|
|
resolve(sizeInBytes);
|
|
});
|
|
}).on('error', reject);
|
|
});
|
|
|
|
try {
|
|
const sizeInBytes = await getHtmlSize(url);
|
|
const apiUrl = `https://api.websitecarbon.com/data?bytes=${sizeInBytes}&green=0`;
|
|
|
|
// Then use that size to get the carbon data
|
|
const carbonData = await new Promise((resolve, reject) => {
|
|
https.get(apiUrl, res => {
|
|
let data = '';
|
|
res.on('data', chunk => {
|
|
data += chunk;
|
|
});
|
|
res.on('end', () => {
|
|
// Check if response looks like HTML (e.g., Cloudflare challenge page)
|
|
const trimmedData = data.trim();
|
|
if (trimmedData.startsWith('<!DOCTYPE') || trimmedData.startsWith('<html') || trimmedData.startsWith('<')) {
|
|
reject(new Error('WebsiteCarbon API returned HTML instead of JSON. This may be due to Cloudflare protection when running from a datacenter IP.'));
|
|
return;
|
|
}
|
|
try {
|
|
resolve(JSON.parse(data));
|
|
} catch (parseError) {
|
|
reject(new Error(`Failed to parse WebsiteCarbon API response as JSON: ${parseError.message}`));
|
|
}
|
|
});
|
|
}).on('error', reject);
|
|
});
|
|
|
|
if (!carbonData.statistics || (carbonData.statistics.adjustedBytes === 0 && carbonData.statistics.energy === 0)) {
|
|
return {
|
|
statusCode: 200,
|
|
body: JSON.stringify({ skipped: 'Not enough info to get carbon data' }),
|
|
};
|
|
}
|
|
|
|
carbonData.scanUrl = url;
|
|
return carbonData;
|
|
} catch (error) {
|
|
throw new Error(`Error: ${error.message}`);
|
|
}
|
|
};
|
|
|
|
export const handler = middleware(carbonHandler);
|
|
export default handler;
|