diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
index 13be2d1..2d51ac0 100644
--- a/.idea/codeStyles/Project.xml
+++ b/.idea/codeStyles/Project.xml
@@ -19,6 +19,9 @@
+
+
+
diff --git a/src/index.ts b/src/index.ts
index 5cffc75..63bcae8 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -147,10 +147,12 @@ export default {
let password: string | undefined;
let read_limit: number | undefined;
let need_qrcode: boolean = false;
+ let paste_type: string | undefined;
// Content-Type: multipart/form-data
if (content_type.includes('multipart/form-data')) {
const formdata = await request.formData();
const data = formdata.get('u');
+ const type = formdata.get('paste-type');
if (data === null) {
return new Response('Invalid request.\n', {
status: 422,
@@ -167,6 +169,8 @@ export default {
mime_type = 'text/plain; charset=UTF-8;';
}
+ if (typeof type === 'string') paste_type = type;
+
// Set password
const pass = formdata.get('pass');
if (typeof pass === 'string') {
@@ -195,6 +199,7 @@ export default {
title = headers.get('x-title') || undefined;
mime_type = headers.get('x-content-type') || undefined;
password = headers.get('x-pass') || undefined;
+ paste_type = headers.get('x-paste-type') || undefined;
const count = headers.get('x-read-limit') || undefined;
if (typeof count === 'string') {
const n = parseInt(count);
@@ -213,6 +218,24 @@ export default {
need_qrcode = true;
}
+ // Validate paste type parameter
+ switch (paste_type) {
+ case 'link':
+ mime_type = 'text/x-uri';
+ paste_type = 'link';
+ break;
+
+ case 'paste':
+ case undefined:
+ paste_type = undefined;
+ break;
+
+ default:
+ return new Response('Unknown paste type.\n', {
+ status: 422,
+ });
+ }
+
// Check password rules
if (password && !check_password_rules(password)) {
return new Response('Invalid password. ' +
@@ -249,6 +272,7 @@ export default {
password: password ? sha256(password).slice(0, 16) : undefined,
read_count_remain: read_limit ?? undefined,
mime_type: mime_type || undefined,
+ type: paste_type,
size,
};
@@ -390,19 +414,41 @@ export default {
}
res.headers.set('cache-control', 'public, max-age=18000');
- // Alter content type to text/plain
- if (option === 'raw' || descriptor.mime_type === undefined) {
- res.headers.delete('content-type');
- } else {
- res.headers.set('content-type', descriptor.mime_type);
- }
-
res.headers.set('content-disposition',
`inline; filename="${encodeURIComponent(descriptor.title ?? uuid)}"`);
- if (option === 'download') {
+ if (descriptor.mime_type)
+ res.headers.set('content-type', descriptor.mime_type);
+ // Let the browser guess the content
+ else res.headers.delete('content-type');
+
+ // Handle option
+ if (option === 'raw') res.headers.delete('content-type');
+ else if (option === 'download')
res.headers.set('content-disposition',
`attachment; filename="${encodeURIComponent(descriptor.title ?? uuid)}"`);
+
+ // Link redirection
+ else if (descriptor.type === 'link' || option === 'link') {
+ const content = await res.clone().arrayBuffer();
+ try {
+ const href = new TextDecoder().decode(content);
+ new URL(href);
+ res.headers.set('location', href);
+ res = new Response(res.body, {
+ status: 301,
+ headers: {
+ location: href,
+ ...res.headers,
+ },
+ });
+ } catch (err) {
+ if (err instanceof TypeError) {
+ res = new Response('Invalid URL.', {
+ status: 422,
+ });
+ }
+ }
}
// res.body cannot be read twice
@@ -578,4 +624,5 @@ interface PasteIndexEntry {
password?: string,
editable?: boolean, // Default: True
read_count_remain?: number
+ type?: string;
}
\ No newline at end of file
diff --git a/wrangler.toml b/wrangler.toml
index 8eebd0c..66cbe2d 100644
--- a/wrangler.toml
+++ b/wrangler.toml
@@ -1,7 +1,6 @@
name = "paste"
main = "src/index.ts"
compatibility_date = "2022-05-30"
-node_compat = true
workers_dev = false
kv_namespaces = [
{ binding = "PASTE_INDEX", id = "a578863da0564cd7beadd9ce4a2d53e8", preview_id = "66d9440e13124099a5e508fe1ff0a489" }