mirror of
https://github.com/rikkaneko/paste.git
synced 2025-06-06 08:35:44 +00:00
Cache presigned URL for better caching
Signed-off-by: Joe Ma <rikkaneko23@gmail.com>
This commit is contained in:
parent
c5569ea30f
commit
a88c7321cf
4 changed files with 33 additions and 10 deletions
|
@ -1,3 +1,4 @@
|
|||
export const SERVICE_URL = 'pb.nekoid.cc';
|
||||
export const PASTE_WEB_URL = 'https://raw.githubusercontent.com/rikkaneko/paste/main/frontend';
|
||||
export const UUID_LENGTH = 4;
|
||||
export const CORS_DOMAIN = 'nekoid.cc';
|
||||
|
|
16
src/index.ts
16
src/index.ts
|
@ -22,7 +22,7 @@ import { Router, error } from 'itty-router';
|
|||
import { ERequest, Env, PasteIndexEntry, PASTE_TYPES } from './types';
|
||||
import { serve_static } from './proxy';
|
||||
import { check_password_rules, get_paste_info, get_basic_auth, gen_id } from './utils';
|
||||
import { UUID_LENGTH, PASTE_WEB_URL, SERVICE_URL } from './constant';
|
||||
import { UUID_LENGTH, PASTE_WEB_URL, SERVICE_URL, CORS_DOMAIN } from './constant';
|
||||
import { get_presign_url, router as large_upload } from './v2/large_upload';
|
||||
|
||||
const router = Router<ERequest, [Env, ExecutionContext]>();
|
||||
|
@ -44,7 +44,7 @@ router.options('*', (request) => {
|
|||
if (!request.origin) return new Response(null);
|
||||
const url = new URL(request.origin);
|
||||
// Allow all subdomain of nekoid.cc
|
||||
if (url.hostname.endsWith('nekoid.cc')) {
|
||||
if (url.hostname.endsWith(CORS_DOMAIN)) {
|
||||
return new Response(null, {
|
||||
status: 204,
|
||||
headers: {
|
||||
|
@ -217,6 +217,7 @@ router.post('/', async (request, env, ctx) => {
|
|||
const s3 = new AwsClient({
|
||||
accessKeyId: env.AWS_ACCESS_KEY_ID,
|
||||
secretAccessKey: env.AWS_SECRET_ACCESS_KEY,
|
||||
service: 's3', // required
|
||||
});
|
||||
|
||||
const res = await s3.fetch(`${env.ENDPOINT}/${uuid}`, {
|
||||
|
@ -344,10 +345,18 @@ router.get('/:uuid/:option?', async (request, env, ctx) => {
|
|||
}
|
||||
|
||||
const signed_url = await get_presign_url(uuid, descriptor, env);
|
||||
|
||||
ctx.waitUntil(
|
||||
env.PASTE_INDEX.put(uuid, JSON.stringify(descriptor), {
|
||||
expiration: descriptor.expiration! / 1000,
|
||||
})
|
||||
);
|
||||
|
||||
return new Response(null, {
|
||||
status: 301,
|
||||
headers: {
|
||||
location: signed_url,
|
||||
'cache-control': 'no-store',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
@ -372,6 +381,7 @@ router.get('/:uuid/:option?', async (request, env, ctx) => {
|
|||
const s3 = new AwsClient({
|
||||
accessKeyId: env.AWS_ACCESS_KEY_ID,
|
||||
secretAccessKey: env.AWS_SECRET_ACCESS_KEY,
|
||||
service: 's3', // required
|
||||
});
|
||||
// Fetch form origin if not hit cache
|
||||
let origin = await s3.fetch(`${env.ENDPOINT}/${uuid}`, {
|
||||
|
@ -559,7 +569,7 @@ export default {
|
|||
if (!req.origin) return res;
|
||||
const url = new URL(req.origin);
|
||||
// Allow all subdomain of nekoid.cc
|
||||
if (url.hostname.endsWith('nekoid.cc')) {
|
||||
if (url.hostname.endsWith(CORS_DOMAIN)) {
|
||||
res.headers.set('Access-Control-Allow-Origin', url.origin);
|
||||
res.headers.set('Vary', 'Origin');
|
||||
}
|
||||
|
|
2
src/types.d.ts
vendored
2
src/types.d.ts
vendored
|
@ -22,7 +22,7 @@ export interface PasteIndexEntry {
|
|||
upload_completed?: boolean;
|
||||
sha256_hash?: string;
|
||||
cached_presigned_url?: string;
|
||||
cached_presigned_url_expiration?: string;
|
||||
cached_presigned_url_expiration?: number;
|
||||
}
|
||||
|
||||
export interface Env {
|
||||
|
|
|
@ -9,8 +9,17 @@ import { UUID_LENGTH } from '../constant';
|
|||
export const router = Router<ERequest, [Env, ExecutionContext]>({ base: '/v2/large_upload' });
|
||||
|
||||
export async function get_presign_url(uuid: string, descriptor: PasteIndexEntry, env: Env) {
|
||||
// Use cached presigned url if expiration is more than 10 mins
|
||||
if (descriptor.cached_presigned_url) {
|
||||
const expiration = new Date(descriptor.cached_presigned_url_expiration ?? 0);
|
||||
const time_to_renew = new Date(Date.now() + 600 * 1000); // 10 mins after
|
||||
if (expiration >= time_to_renew) {
|
||||
return descriptor.cached_presigned_url;
|
||||
}
|
||||
}
|
||||
|
||||
const endpoint_url = new URL(`${env.LARGE_DOWNLOAD_ENDPOINT}/${uuid}`);
|
||||
endpoint_url.searchParams.set('X-Amz-Expires', '3600');
|
||||
endpoint_url.searchParams.set('X-Amz-Expires', '14400'); // Valid for 4 hours
|
||||
endpoint_url.searchParams.set(
|
||||
'response-content-disposition',
|
||||
`inline; filename*=UTF-8''${encodeURIComponent(descriptor.title ?? uuid)}`
|
||||
|
@ -21,7 +30,7 @@ export async function get_presign_url(uuid: string, descriptor: PasteIndexEntry,
|
|||
const s3 = new AwsClient({
|
||||
accessKeyId: env.LARGE_AWS_ACCESS_KEY_ID!,
|
||||
secretAccessKey: env.LARGE_AWS_SECRET_ACCESS_KEY!,
|
||||
service: 's3',
|
||||
service: 's3', // required
|
||||
});
|
||||
|
||||
const signed = await s3.sign(endpoint_url, {
|
||||
|
@ -32,6 +41,9 @@ export async function get_presign_url(uuid: string, descriptor: PasteIndexEntry,
|
|||
},
|
||||
});
|
||||
|
||||
descriptor.cached_presigned_url = signed.url;
|
||||
descriptor.cached_presigned_url_expiration = new Date(Date.now() + 14400 * 1000).getTime();
|
||||
|
||||
return signed.url;
|
||||
}
|
||||
|
||||
|
@ -111,13 +123,13 @@ router.post('/create', async (request, env, ctx) => {
|
|||
const s3 = new AwsClient({
|
||||
accessKeyId: env.LARGE_AWS_ACCESS_KEY_ID!,
|
||||
secretAccessKey: env.LARGE_AWS_SECRET_ACCESS_KEY!,
|
||||
service: 's3',
|
||||
service: 's3', // required
|
||||
});
|
||||
|
||||
const current = Date.now();
|
||||
const expiration = new Date(current + 14400 * 1000).getTime();
|
||||
const endpoint_url = new URL(`${env.LARGE_ENDPOINT}/${uuid}`);
|
||||
endpoint_url.searchParams.set('X-Amz-Expires', '14400');
|
||||
endpoint_url.searchParams.set('X-Amz-Expires', '900'); // Valid for 15 mins
|
||||
const required_headers = {
|
||||
'Content-Length': file_size.toString(),
|
||||
'X-Amz-Content-Sha256': file_hash,
|
||||
|
@ -147,7 +159,7 @@ router.post('/create', async (request, env, ctx) => {
|
|||
title: file_title || undefined,
|
||||
mime_type: file_mime || undefined,
|
||||
last_modified: current,
|
||||
expiration: new Date(Date.now() + 3600 * 1000).getTime(),
|
||||
expiration: new Date(Date.now() + 900 * 1000).getTime(),
|
||||
password: password ? sha256(password).slice(0, 16) : undefined,
|
||||
read_count_remain: read_limit ?? undefined,
|
||||
type: 'large_paste',
|
||||
|
@ -192,7 +204,7 @@ router.post('/complete/:uuid', async (request, env, ctx) => {
|
|||
const s3 = new AwsClient({
|
||||
accessKeyId: env.LARGE_AWS_ACCESS_KEY_ID!,
|
||||
secretAccessKey: env.LARGE_AWS_SECRET_ACCESS_KEY!,
|
||||
service: 's3',
|
||||
service: 's3', // required
|
||||
});
|
||||
|
||||
try {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue