Files
pages/src/index.ts

114 lines
3.7 KiB
TypeScript

export interface Env {}
export interface ExecutionContext {}
function getMimeType(filename: string): string {
const ext = filename.split('.').pop()?.toLowerCase();
switch (ext) {
case 'html': return 'text/html';
case 'css': return 'text/css';
case 'js': return 'application/javascript';
case 'json': return 'application/json';
case 'png': return 'image/png';
case 'jpg':
case 'jpeg': return 'image/jpeg';
case 'gif': return 'image/gif';
case 'svg': return 'image/svg+xml';
case 'ico': return 'image/x-icon';
case 'txt': return 'text/plain';
case 'xml': return 'application/xml';
case 'pdf': return 'application/pdf';
case 'woff': return 'font/woff';
case 'woff2': return 'font/woff2';
case 'ttf': return 'font/ttf';
case 'otf': return 'font/otf';
case 'eot': return 'application/vnd.ms-fontobject';
case 'md': return 'text/markdown';
default: return 'application/octet-stream';
}
}
export default {
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
const url = new URL(request.url);
const userAgent = request.headers.get('User-Agent') || '';
// 1. Check if request is coming from git
if (userAgent.toLowerCase().includes('git')) {
console.info("Redirecting to Chookspace, as useragent is Git");
const redirectUrl = new URL(url.toString());
redirectUrl.hostname = 'chookspace.com';
return Response.redirect(redirectUrl.toString(), 302);
}
// Parse path: /(user)/(repo)/(file...)
// Remove leading slash
const path = url.pathname.slice(1);
const parts = path.split('/');
// Need at least user and repo
// Otherwise, redirect to profile
if (parts.length < 2) {
console.info("Redirecting to Chookspace, not a long enough request");
const redirectUrl = new URL(url.toString());
redirectUrl.hostname = 'chookspace.com';
return Response.redirect(redirectUrl.toString(), 302);
}
const user = parts[0];
const repo = parts[1];
let filePath = parts.slice(2).join('/');
// 2. Handle index.html default
if (!filePath || filePath === '') {
filePath = 'index.html';
} else if (filePath.endsWith('/')) {
filePath += 'index.html';
}
// 3. Check if file exists at raw URL
// URL structure: https://chookspace.com/(user)/(repo)/raw/branch/master/chookspace/(file)
const rawBase = `https://chookspace.com/${user}/${repo}/raw/branch/master/chookspace`;
const rawUrl = `${rawBase}/${filePath}`;
console.log("Raw URL: ", rawUrl);
try {
// Prepare headers for the fetch request
const fetchHeaders = new Headers(request.headers);
fetchHeaders.set('User-Agent', 'Chsp-Worker-Proxy/1.0');
const rawResponse = await fetch(rawUrl, {
method: request.method,
headers: fetchHeaders,
redirect: 'follow'
});
console.info("Response from Chookspace was", rawResponse.status);
// 4. If success (2xx), proxy it
if (rawResponse.status >= 200 && rawResponse.status < 400) {
console.info("Proxying page");
const mimeType = getMimeType(filePath);
// Create new headers to override Content-Type
const newHeaders = new Headers(rawResponse.headers);
newHeaders.set('Content-Type', mimeType);
return new Response(rawResponse.body, {
status: rawResponse.status,
statusText: rawResponse.statusText,
headers: newHeaders
});
}
} catch (e) {
// Fetch failed (network error etc), proceed to fallback
console.error('Fetch error:', e);
}
// 5. If not found or error, redirect to chookspace site
console.info("Redirecting to Chookspace normally...");
const redirectUrl = new URL(url.toString());
redirectUrl.hostname = 'chookspace.com';
return Response.redirect(redirectUrl.toString(), 302);
},
};