mirror of
https://github.com/rikkaneko/paste.git
synced 2025-06-06 16:45:41 +00:00
Forward client HTPP headers to improve caching
Signed-off-by: Joe Ma <rikkaneko23@gmail.com>
This commit is contained in:
parent
601bd0b7dc
commit
e53deac322
3 changed files with 80 additions and 17 deletions
48
src/index.ts
48
src/index.ts
|
@ -20,7 +20,8 @@ import { AwsClient } from 'aws4fetch';
|
|||
import { customAlphabet } from 'nanoid';
|
||||
import { sha256 } from 'js-sha256';
|
||||
import dedent from 'dedent-js';
|
||||
import { PasteIndexEntry } from './types';
|
||||
import { Env, PasteIndexEntry } from './types';
|
||||
import { serve_static } from './proxy';
|
||||
|
||||
// Constants
|
||||
const SERVICE_URL = 'pb.nekoid.cc';
|
||||
|
@ -28,14 +29,6 @@ const PASTE_WEB_URL_v1 = 'https://raw.githubusercontent.com/rikkaneko/paste/main
|
|||
const PASTE_WEB_URL = 'https://raw.githubusercontent.com/rikkaneko/paste/main/static/v2';
|
||||
const UUID_LENGTH = 4;
|
||||
|
||||
export interface Env {
|
||||
PASTE_INDEX: KVNamespace;
|
||||
QRCODE: ServiceWorkerGlobalScope;
|
||||
AWS_ACCESS_KEY_ID: string;
|
||||
AWS_SECRET_ACCESS_KEY: string;
|
||||
ENDPOINT: string;
|
||||
}
|
||||
|
||||
const gen_id = customAlphabet('1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz', UUID_LENGTH);
|
||||
|
||||
export default {
|
||||
|
@ -43,6 +36,7 @@ export default {
|
|||
const { url, method, headers } = request;
|
||||
const { pathname, searchParams } = new URL(url);
|
||||
const path = pathname.replace(/\/+$/, '') || '/';
|
||||
const match_etag = headers.get('If-None-Match') || undefined;
|
||||
let cache = caches.default;
|
||||
|
||||
const agent = headers.get('user-agent') ?? '';
|
||||
|
@ -67,18 +61,18 @@ export default {
|
|||
}
|
||||
|
||||
if (path === '/v1' && method == 'GET') {
|
||||
return await proxy_uri(PASTE_WEB_URL_v1 + '/paste.html');
|
||||
return await serve_static(PASTE_WEB_URL_v1 + '/paste.html', headers);
|
||||
}
|
||||
|
||||
if (/\/(js|css)\/.*$/.test(path) && method == 'GET') {
|
||||
return await proxy_uri(PASTE_WEB_URL + path);
|
||||
return await serve_static(PASTE_WEB_URL + path, headers);
|
||||
}
|
||||
|
||||
if (path === '/') {
|
||||
switch (method) {
|
||||
case 'GET': {
|
||||
// Fetch the HTML for uploading text/file
|
||||
return await proxy_uri(PASTE_WEB_URL + '/paste.html');
|
||||
return await serve_static(PASTE_WEB_URL + '/paste.html', headers);
|
||||
}
|
||||
|
||||
// Create new paste
|
||||
|
@ -343,14 +337,32 @@ export default {
|
|||
|
||||
// Enable CF cache for authorized request
|
||||
// Match in existing cache
|
||||
let res = await cache.match(request.url);
|
||||
let res = await cache.match(
|
||||
new Request(`https://${SERVICE_URL}/${uuid}`, {
|
||||
method: 'GET',
|
||||
headers: match_etag
|
||||
? {
|
||||
// ETag to cache file
|
||||
'if-none-match': match_etag,
|
||||
}
|
||||
: undefined,
|
||||
})
|
||||
);
|
||||
if (res === undefined) {
|
||||
// Fetch form origin if not hit cache
|
||||
let origin = await s3.fetch(`${env.ENDPOINT}/${uuid}`, {
|
||||
method: 'GET',
|
||||
headers: match_etag
|
||||
? {
|
||||
'if-none-match': match_etag,
|
||||
}
|
||||
: undefined,
|
||||
});
|
||||
|
||||
res = new Response(origin.body);
|
||||
// Reserve ETag header
|
||||
res = new Response(origin.body, { status: origin.status });
|
||||
const etag = origin.headers.get('etag');
|
||||
if (etag) res.headers.append('etag', etag);
|
||||
|
||||
if (res.status == 404) {
|
||||
// UUID exists in index but not found in remote object storage service, probably expired
|
||||
|
@ -361,7 +373,7 @@ export default {
|
|||
return new Response('Paste expired.\n', {
|
||||
status: 410,
|
||||
});
|
||||
} else if (!res.ok) {
|
||||
} else if (!res.ok && res.status !== 304) {
|
||||
// Other error
|
||||
return new Response('Internal server error.\n', {
|
||||
status: 500,
|
||||
|
@ -410,13 +422,15 @@ export default {
|
|||
|
||||
// res.body cannot be read twice
|
||||
// Do not block when writing to cache
|
||||
ctx.waitUntil(cache.put(url, res.clone()));
|
||||
if (res.ok) ctx.waitUntil(cache.put(url, res.clone()));
|
||||
return res;
|
||||
}
|
||||
|
||||
// Cache hit
|
||||
// Matched Etag, no body
|
||||
if (res.status == 304) return res;
|
||||
let { readable, writable } = new TransformStream();
|
||||
res.body!.pipeTo(writable);
|
||||
res.body?.pipeTo(writable);
|
||||
return new Response(readable, res);
|
||||
}
|
||||
|
||||
|
|
41
src/proxy.ts
Normal file
41
src/proxy.ts
Normal file
|
@ -0,0 +1,41 @@
|
|||
// Proxy URI (Accept *.js, *.css, *.html, *.ico only)
|
||||
// Use ETag and If-None-Match to cache file
|
||||
export async function serve_static(path: string, req_headers?: Headers): Promise<Response> {
|
||||
// Filter static file extension
|
||||
let mime = 'text/plain; charset=UTF-8;';
|
||||
if (path.endsWith('.js')) mime = 'application/javascript; charset=UTF-8;';
|
||||
else if (path.endsWith('.css')) mime = 'text/css; charset=UTF-8;';
|
||||
else if (path.endsWith('.html')) mime = 'text/html; charset=UTF-8;';
|
||||
else if (path.endsWith('.ico')) mime = 'image/x-icon';
|
||||
else
|
||||
return new Response(null, {
|
||||
headers: {
|
||||
'cache-control': 'public, max-age=14400',
|
||||
},
|
||||
status: 404,
|
||||
});
|
||||
|
||||
try {
|
||||
const res = await fetch(path, {
|
||||
headers: req_headers,
|
||||
cf: {
|
||||
cacheEverything: true,
|
||||
},
|
||||
});
|
||||
// Append ETag and Cache
|
||||
const etag = res.headers.get('etag');
|
||||
const nres = new Response(res.body, {
|
||||
headers: {
|
||||
'content-type': mime,
|
||||
'cache-control': 'public, max-age=14400',
|
||||
},
|
||||
status: res.status,
|
||||
});
|
||||
if (etag) nres.headers.append('etag', etag);
|
||||
return nres;
|
||||
} catch (err) {
|
||||
return new Response('Internal server error.\n', {
|
||||
status: 500,
|
||||
});
|
||||
}
|
||||
}
|
8
src/types.d.ts
vendored
8
src/types.d.ts
vendored
|
@ -8,3 +8,11 @@ export interface PasteIndexEntry {
|
|||
read_count_remain?: number;
|
||||
type?: string;
|
||||
}
|
||||
|
||||
export interface Env {
|
||||
PASTE_INDEX: KVNamespace;
|
||||
QRCODE: ServiceWorkerGlobalScope;
|
||||
AWS_ACCESS_KEY_ID: string;
|
||||
AWS_SECRET_ACCESS_KEY: string;
|
||||
ENDPOINT: string;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue