72 lines
2.6 KiB
JavaScript
72 lines
2.6 KiB
JavaScript
export default {
|
|
async fetch(request) {
|
|
const url = new URL(request.url);
|
|
const tunnelHost = 'instructional-qty-curriculum-protected.trycloudflare.com';
|
|
const targetUrl = `https://${tunnelHost}${url.pathname}${url.search}`;
|
|
|
|
const modifiedHeaders = new Headers(request.headers);
|
|
modifiedHeaders.set('Host', tunnelHost);
|
|
modifiedHeaders.delete('cf-connecting-ip');
|
|
modifiedHeaders.delete('cf-ray');
|
|
modifiedHeaders.delete('cf-visitor');
|
|
|
|
const init = {
|
|
method: request.method,
|
|
headers: modifiedHeaders,
|
|
redirect: 'manual', // Handle redirects ourselves
|
|
};
|
|
if (request.method !== 'GET' && request.method !== 'HEAD') {
|
|
init.body = request.body;
|
|
}
|
|
|
|
const response = await fetch(targetUrl, init);
|
|
|
|
// Build response headers
|
|
const newHeaders = new Headers();
|
|
|
|
// Copy content-type
|
|
const ct = response.headers.get('content-type');
|
|
if (ct) newHeaders.set('Content-Type', ct);
|
|
|
|
// Copy ALL set-cookie headers (critical for Flask sessions)
|
|
const cookies = response.headers.getAll ? response.headers.getAll('set-cookie') : [];
|
|
if (cookies.length === 0) {
|
|
// Fallback for environments without getAll
|
|
const sc = response.headers.get('set-cookie');
|
|
if (sc) newHeaders.append('Set-Cookie', sc);
|
|
} else {
|
|
for (const c of cookies) {
|
|
newHeaders.append('Set-Cookie', c);
|
|
}
|
|
}
|
|
|
|
// Handle redirects — rewrite tunnel URLs to our domain
|
|
if (response.status >= 300 && response.status < 400) {
|
|
let loc = response.headers.get('location') || '';
|
|
loc = loc.replace(`https://${tunnelHost}`, 'https://thenichequiz.com');
|
|
// Also handle relative redirects
|
|
if (loc.startsWith('/')) loc = `https://thenichequiz.com${loc}`;
|
|
newHeaders.set('Location', loc);
|
|
return new Response(null, { status: response.status, headers: newHeaders });
|
|
}
|
|
|
|
// Copy content-disposition for CSV downloads
|
|
const cd = response.headers.get('content-disposition');
|
|
if (cd) newHeaders.set('Content-Disposition', cd);
|
|
|
|
// Copy content-length
|
|
const cl = response.headers.get('content-length');
|
|
if (cl) newHeaders.set('Content-Length', cl);
|
|
|
|
newHeaders.set('Cache-Control', 'no-cache, no-store, must-revalidate');
|
|
newHeaders.set('X-Content-Type-Options', 'nosniff');
|
|
|
|
// Stream the body directly (works for images, HTML, JSON, CSV, everything)
|
|
return new Response(response.body, {
|
|
status: response.status,
|
|
statusText: response.statusText,
|
|
headers: newHeaders,
|
|
});
|
|
}
|
|
};
|