Mahesh
Mahesh
CDCloudflare Developers
Created by Mahesh on 3/13/2025 in #workers-help
CF Workers - Empty Body to origin servers
Hi Team, Any help on this will be highly appreciated.
3 replies
CDCloudflare Developers
Created by Mahesh on 3/13/2025 in #workers-help
CF Workers - Empty Body to origin servers
function rewriteUrlPath(url: URL): string {
// Rewrite path for primary domain
if (url.host === 'api.example.com' && url.pathname.startsWith('/api/v2/')) {
url.pathname = url.pathname.replace('/api/v2/', '/v1/');
}

// Rewrite paths for subdomains
if (url.host.startsWith('service.')) {
['/api/v2/', '/v1/', '/service/'].forEach((prefix) => {
if (url.pathname.startsWith(prefix)) {
url.pathname = url.pathname.replace(prefix, '/api/');
}
});
}

return url.toString();
}

export default {
async fetch(
request: Request,
env: {
PRIMARY_DOMAIN: string;
ALTERNATE_DOMAIN: string;
},
ctx: ExecutionContext,
): Promise<Response> {
ctx.passThroughOnException();

const url = new URL(request.url);
const params = new URLSearchParams(url.search);
const featureFlag = params.get('feature_enabled');
const isFeatureEnabled =
url.pathname.indexOf('/items/') > 0 &&
['y', '1', 'yes', 'true'].includes(featureFlag);

if (!isFeatureEnabled && url.host === env.PRIMARY_DOMAIN) {
// No feature flag and no need to rewrite domain, pass it to the origin
return fetch(request);
}

if (isFeatureEnabled) {
// Override domain if feature is enabled
url.host = env.ALTERNATE_DOMAIN || url.host;
} else {
url.host = env.PRIMARY_DOMAIN;
}

const headers = request.headers;
const method = request.method;
const baseParams = { headers, method };
const reqParams = ['get', 'head'].includes(request.method.toLowerCase())
? baseParams
: {
...baseParams,
body: await request.text(),
};
const newRequest = new Request(rewriteUrlPath(url), reqParams);
return fetch(newRequest);

},
};
function rewriteUrlPath(url: URL): string {
// Rewrite path for primary domain
if (url.host === 'api.example.com' && url.pathname.startsWith('/api/v2/')) {
url.pathname = url.pathname.replace('/api/v2/', '/v1/');
}

// Rewrite paths for subdomains
if (url.host.startsWith('service.')) {
['/api/v2/', '/v1/', '/service/'].forEach((prefix) => {
if (url.pathname.startsWith(prefix)) {
url.pathname = url.pathname.replace(prefix, '/api/');
}
});
}

return url.toString();
}

export default {
async fetch(
request: Request,
env: {
PRIMARY_DOMAIN: string;
ALTERNATE_DOMAIN: string;
},
ctx: ExecutionContext,
): Promise<Response> {
ctx.passThroughOnException();

const url = new URL(request.url);
const params = new URLSearchParams(url.search);
const featureFlag = params.get('feature_enabled');
const isFeatureEnabled =
url.pathname.indexOf('/items/') > 0 &&
['y', '1', 'yes', 'true'].includes(featureFlag);

if (!isFeatureEnabled && url.host === env.PRIMARY_DOMAIN) {
// No feature flag and no need to rewrite domain, pass it to the origin
return fetch(request);
}

if (isFeatureEnabled) {
// Override domain if feature is enabled
url.host = env.ALTERNATE_DOMAIN || url.host;
} else {
url.host = env.PRIMARY_DOMAIN;
}

const headers = request.headers;
const method = request.method;
const baseParams = { headers, method };
const reqParams = ['get', 'head'].includes(request.method.toLowerCase())
? baseParams
: {
...baseParams,
body: await request.text(),
};
const newRequest = new Request(rewriteUrlPath(url), reqParams);
return fetch(newRequest);

},
};
3 replies
CDCloudflare Developers
Created by Mahesh on 3/1/2025 in #workers-help
Workers transiently dropping REQUEST BODY sending empty body to ORIGIN Server.
export default {
async fetch(
request: Request,
env: Env,
ctx: ExecutionContext,
): Promise<Response> {
ctx.passThroughOnException();

const url = new URL(request.url);
const params = new URLSearchParams(url.search);
const regionalParam = params.get('regional');
const isRegional =
url.pathname.includes('/fasts/') &&
['y', '1', 'yes', 'true'].includes(regionalParam?.toLowerCase() || '');

if (!isRegional && url.host === env.CENTRAL_DOMAIN) {
// Not fast and no need to rewrite domain, pass it to the origin.
return await handleFetchWithTimeout(newRequest); // Pass the original request directly
}

if (isRegional) {
url.host = env.REGIONAL_DOMAIN || url.host;
} else {
url.host = env.CENTRAL_DOMAIN;
}

const headers = request.headers;
const method = request.method;
const baseParams = { headers, method };
const reqParams = ['get', 'head'].includes(request.method.toLowerCase())
? baseParams
: {
...baseParams,
body: await request.text(),
};

const newRequest = new Request(url, reqParams);
return await handleFetchWithTimeout(newRequest);
},
};

async function handleFetchWithTimeout(
request: Request,
): Promise<Response> {
ctx.passThroughOnException();
const requestForContent = request.clone();

try {
const response = await fetch(request);

if (response.status >= 520 && response.status <= 526) {
const errorMessages: Record<number, string> = {
520: 'Unknown error from origin server',
521: 'Web server is down',
522: 'Connection timed out to origin',
523: 'Origin is unreachable',
524: 'Origin server timeout',
525: 'SSL handshake failed',
526: 'Invalid SSL certificate',
};

const requestContent = await getRequestContent(requestForContent);
const responseForContent = response.clone();
const responseContent = await getResponseContent(responseForContent);

console.error({
application: 'XXXXXXXXXX',
level: 'error',
message: errorMessages[response.status] || 'Unknown origin error',
request_id: request.headers.get('cf-ray') || 'no-ray-id',
timestamp: new Date().toISOString(),
// Request details
// request_content_value: redactPII(requestContent),
// request_method: request.method,
// request_path: new URL(request.url).pathname,
// request_headers: sanitizeHeaders(request.headers),
// Response details
response_status: response.status,
// response_headers: sanitizeHeaders(response.headers),
// response_content_value: redactPII(responseContent),
});
}

return response; // Return the response, even if an error occurred
} catch (error) {
console.error({
application: 'XXXXXXXXXX',
level: 'error',
message: 'An unexpected error occurred',
error: error.message || String(error), // include the error message
request_id: request.headers.get('cf-ray') || 'no-ray-id',
timestamp: new Date().toISOString()
});
return new Response('Internal Server Error', { status: 500 }); // Return a 500 response on error
}
};

async function getRequestContent(request: Request): Promise<string> {
try {
// More error handling
return await request.text();
} catch (error) {
return 'Could not retrieve request body';
}
}

async function getResponseContent(response: Response): Promise<string> {
try {
// More error handling
return await response.text();
} catch (error) {
return 'Could not retrieve response body';
}
}
export default {
async fetch(
request: Request,
env: Env,
ctx: ExecutionContext,
): Promise<Response> {
ctx.passThroughOnException();

const url = new URL(request.url);
const params = new URLSearchParams(url.search);
const regionalParam = params.get('regional');
const isRegional =
url.pathname.includes('/fasts/') &&
['y', '1', 'yes', 'true'].includes(regionalParam?.toLowerCase() || '');

if (!isRegional && url.host === env.CENTRAL_DOMAIN) {
// Not fast and no need to rewrite domain, pass it to the origin.
return await handleFetchWithTimeout(newRequest); // Pass the original request directly
}

if (isRegional) {
url.host = env.REGIONAL_DOMAIN || url.host;
} else {
url.host = env.CENTRAL_DOMAIN;
}

const headers = request.headers;
const method = request.method;
const baseParams = { headers, method };
const reqParams = ['get', 'head'].includes(request.method.toLowerCase())
? baseParams
: {
...baseParams,
body: await request.text(),
};

const newRequest = new Request(url, reqParams);
return await handleFetchWithTimeout(newRequest);
},
};

async function handleFetchWithTimeout(
request: Request,
): Promise<Response> {
ctx.passThroughOnException();
const requestForContent = request.clone();

try {
const response = await fetch(request);

if (response.status >= 520 && response.status <= 526) {
const errorMessages: Record<number, string> = {
520: 'Unknown error from origin server',
521: 'Web server is down',
522: 'Connection timed out to origin',
523: 'Origin is unreachable',
524: 'Origin server timeout',
525: 'SSL handshake failed',
526: 'Invalid SSL certificate',
};

const requestContent = await getRequestContent(requestForContent);
const responseForContent = response.clone();
const responseContent = await getResponseContent(responseForContent);

console.error({
application: 'XXXXXXXXXX',
level: 'error',
message: errorMessages[response.status] || 'Unknown origin error',
request_id: request.headers.get('cf-ray') || 'no-ray-id',
timestamp: new Date().toISOString(),
// Request details
// request_content_value: redactPII(requestContent),
// request_method: request.method,
// request_path: new URL(request.url).pathname,
// request_headers: sanitizeHeaders(request.headers),
// Response details
response_status: response.status,
// response_headers: sanitizeHeaders(response.headers),
// response_content_value: redactPII(responseContent),
});
}

return response; // Return the response, even if an error occurred
} catch (error) {
console.error({
application: 'XXXXXXXXXX',
level: 'error',
message: 'An unexpected error occurred',
error: error.message || String(error), // include the error message
request_id: request.headers.get('cf-ray') || 'no-ray-id',
timestamp: new Date().toISOString()
});
return new Response('Internal Server Error', { status: 500 }); // Return a 500 response on error
}
};

async function getRequestContent(request: Request): Promise<string> {
try {
// More error handling
return await request.text();
} catch (error) {
return 'Could not retrieve request body';
}
}

async function getResponseContent(response: Response): Promise<string> {
try {
// More error handling
return await response.text();
} catch (error) {
return 'Could not retrieve response body';
}
}
9 replies
CDCloudflare Developers
Created by Mahesh on 3/1/2025 in #workers-help
Workers transiently dropping REQUEST BODY sending empty body to ORIGIN Server.
This is code which saw uptick. We added code cpature 524 error reasons where in we are cloing request.
9 replies
CDCloudflare Developers
Created by Mahesh on 3/1/2025 in #workers-help
Workers transiently dropping REQUEST BODY sending empty body to ORIGIN Server.
This was code before uptick -
export default {
async fetch(
request: Request,
env: Env,
ctx: ExecutionContext,
): Promise<Response> {
ctx.passThroughOnException();

const url = new URL(request.url);
const params = new URLSearchParams(url.search);
const regionalParam = params.get('regional');
const isRegional =
url.pathname.includes('/fasts/') &&
['y', '1', 'yes', 'true'].includes(regionalParam?.toLowerCase() || '');

if (!isRegional && url.host === env.CENTRAL_DOMAIN) {
// Not fast and no need to rewrite domain, pass it to the origin.
return fetch(request); // Pass the original request directly
}

if (isRegional) {
url.host = env.REGIONAL_DOMAIN || url.host;
} else {
url.host = env.CENTRAL_DOMAIN;
}

const headers = request.headers;
const method = request.method;
const baseParams = { headers, method };
const reqParams = ['get', 'head'].includes(request.method.toLowerCase())
? baseParams
: {
...baseParams,
body: await request.text(),
};

const newRequest = new Request(url, reqParams);
return fetch(newRequest);
},
};
export default {
async fetch(
request: Request,
env: Env,
ctx: ExecutionContext,
): Promise<Response> {
ctx.passThroughOnException();

const url = new URL(request.url);
const params = new URLSearchParams(url.search);
const regionalParam = params.get('regional');
const isRegional =
url.pathname.includes('/fasts/') &&
['y', '1', 'yes', 'true'].includes(regionalParam?.toLowerCase() || '');

if (!isRegional && url.host === env.CENTRAL_DOMAIN) {
// Not fast and no need to rewrite domain, pass it to the origin.
return fetch(request); // Pass the original request directly
}

if (isRegional) {
url.host = env.REGIONAL_DOMAIN || url.host;
} else {
url.host = env.CENTRAL_DOMAIN;
}

const headers = request.headers;
const method = request.method;
const baseParams = { headers, method };
const reqParams = ['get', 'head'].includes(request.method.toLowerCase())
? baseParams
: {
...baseParams,
body: await request.text(),
};

const newRequest = new Request(url, reqParams);
return fetch(newRequest);
},
};
9 replies
CDCloudflare Developers
Created by Mahesh on 3/1/2025 in #workers-help
Workers transiently dropping REQUEST BODY sending empty body to ORIGIN Server.
Thanks @Erisa @downeydabber We were getting this erros before as well, but for fewer, after recent deployment with some changes. We started getting more of them.
9 replies
CDCloudflare Developers
Created by Mahesh on 3/1/2025 in #workers-help
Workers transiently dropping REQUEST BODY sending empty body to ORIGIN Server.
Code -
`export default {
async fetch(
request: Request,
env: Env,
ctx: ExecutionContext,
): Promise<Response> {
ctx.passThroughOnException();
const requestForContent = request.clone();
try {
const response = await fetch(request);
if (response.status >= 520 && response.status <= 526) {
const errorMessages: Record<number, string> = {
520: 'Unknown error from origin server',
521: 'Web server is down',
522: 'Connection timed out to origin',
523: 'Origin is unreachable',
524: 'Origin server timeout',
525: 'SSL handshake failed',
526: 'Invalid SSL certificate'
};

const requestContent = await getRequestContent(requestForContent);
// Clone response once for content
const responseForContent = response.clone();
const responseContent = await getResponseContent(responseForContent);

console.error({
application: 'XXXXXXXXXX',
level: 'error',
message: errorMessages[response.status] || 'Unknown origin error',
request_id: request.headers.get('cf-ray') || 'no-ray-id',
timestamp: new Date().toISOString(),
// Request details
// request_content_value: redactPII(requestContent),
// request_method: request.method,
// request_path: new URL(request.url).pathname,
// request_headers: sanitizeHeaders(request.headers),
// Response details
response_status: response.status,
// response_headers: sanitizeHeaders(response.headers),
// response_content_value: redactPII(responseContent)
});

};
`export default {
async fetch(
request: Request,
env: Env,
ctx: ExecutionContext,
): Promise<Response> {
ctx.passThroughOnException();
const requestForContent = request.clone();
try {
const response = await fetch(request);
if (response.status >= 520 && response.status <= 526) {
const errorMessages: Record<number, string> = {
520: 'Unknown error from origin server',
521: 'Web server is down',
522: 'Connection timed out to origin',
523: 'Origin is unreachable',
524: 'Origin server timeout',
525: 'SSL handshake failed',
526: 'Invalid SSL certificate'
};

const requestContent = await getRequestContent(requestForContent);
// Clone response once for content
const responseForContent = response.clone();
const responseContent = await getResponseContent(responseForContent);

console.error({
application: 'XXXXXXXXXX',
level: 'error',
message: errorMessages[response.status] || 'Unknown origin error',
request_id: request.headers.get('cf-ray') || 'no-ray-id',
timestamp: new Date().toISOString(),
// Request details
// request_content_value: redactPII(requestContent),
// request_method: request.method,
// request_path: new URL(request.url).pathname,
// request_headers: sanitizeHeaders(request.headers),
// Response details
response_status: response.status,
// response_headers: sanitizeHeaders(response.headers),
// response_content_value: redactPII(responseContent)
});

};
9 replies