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 { 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); }, };