Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JoeyBurzynski/44cbe15343d64ff611c2998fc0d51dd9 to your computer and use it in GitHub Desktop.
Save JoeyBurzynski/44cbe15343d64ff611c2998fc0d51dd9 to your computer and use it in GitHub Desktop.
Vercel Function to Echo HTTP Headers
// "cf-connecting-ip" should contain true client IP when Cloudflare managed
// transform rule ("Add visitor location headers") is enabled.
// See: https://share.marketkarma.com/cloudflare-managed-transform-add-geoip-http-headers.png
const HTTP_OK = 200;
const HTTP_INTERNAL_SERVER_ERROR = 500;
/**
* Filters out headers that are not allowed, sorts headers alphabetically,
* and converts headers to JSON.
* @param {Object} headers - The headers object.
* @returns {Object} - The filtered and sorted headers object.
*/
const filterAndSortHeaders = (headers) => {
return Object.keys(headers)
.sort((a, b) => a.localeCompare(b))
.filter(header => allowedHeadersSet.has(header))
.reduce((obj, header) => {
obj[header] = headers[header];
return obj;
}, {});
};
/**
* Sets CORS headers for the response.
* @param {Object} res - The response object.
*/
const setCORSHeaders = (res) => {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET,OPTIONS');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
};
/**
* Returns the HTTP headers of the request.
* @param {Object} req - The request object.
* @param {Object} res - The response object.
* @returns {Promise<void>} - A promise that resolves with the response.
*/
module.exports = async (req, res) => {
try {
const prettyPrintedJSON = JSON.stringify({
headers: filterAndSortHeaders(req.headers)
}, null, 2);
setCORSHeaders(res);
res.setHeader('Content-Type', 'application/json');
res.status(HTTP_OK).send(prettyPrintedJSON);
} catch (error) {
console.error(`Error processing request: ${error.message}`);
const errorMessage = process.env.NODE_ENV === 'development' ? `Internal server error: ${error.message}` : 'Internal server error';
res.status(HTTP_INTERNAL_SERVER_ERROR).send(errorMessage);
}
};
/**
* An array of allowed headers.
* @type {string[]}
*/
const allowedHeadersSet = new Set([
"accept",
"accept-encoding",
"accept-language",
"cache-control",
"cdn-loop",
"cf-connecting-ip",
"cf-ipcity",
"cf-ipcontinent",
"cf-ipcountry",
"cf-iplatitude",
"cf-iplongitude",
"cf-metro-code",
"cf-postal-code",
"cf-ray",
"cf-region",
"cf-region-code",
"cf-timezone",
"cf-visitor",
"connection",
"forwarded",
"host",
"priority",
"sec-ch-ua",
"sec-ch-ua-mobile",
"sec-ch-ua-platform",
"sec-fetch-dest",
"sec-fetch-mode",
"sec-fetch-site",
"sec-fetch-user",
"upgrade-insecure-requests",
"user-agent",
"x-forwarded-for",
"x-forwarded-host",
"x-forwarded-proto",
"x-real-ip",
"x-vercel-deployment-url",
"x-vercel-forwarded-for",
"x-vercel-id",
"x-vercel-ip-city",
"x-vercel-ip-country",
"x-vercel-ip-country-region",
"x-vercel-ip-latitude",
"x-vercel-ip-longitude",
"x-vercel-ip-timezone",
"x-vercel-proxied-for",
"x-vercel-proxy-signature",
"x-vercel-proxy-signature-ts"
]);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment