Skip to content

Commit

Permalink
Multipart upload
Browse files Browse the repository at this point in the history
  • Loading branch information
longern committed Jul 11, 2024
1 parent dc5cb78 commit 258da4b
Show file tree
Hide file tree
Showing 14 changed files with 123 additions and 270 deletions.
23 changes: 9 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ Free serverless backend with a limit of 100,000 invocation requests per day.

## Features

- Drag-and-drop upload
- Upload large files
- Create folders
- Search files
Expand All @@ -26,23 +25,19 @@ Before starting, you should make sure that
Steps:

1. Fork this project and connect your fork with Cloudflare Pages
2. Bind your R2 bucket to `BUCKET` varaible
- Set `WEBDAV_USERNAME` and `WEBDAV_PASSWORD` in `Settings`->`Functions`->`Environment Variables`
- (Optional) Set `WEBDAV_PUBLIC_READ` to enable public read access
2. Setup environment variables
- Bind your R2 bucket to `BUCKET` variable
- Set `WEBDAV_USERNAME` and `WEBDAV_PASSWORD`
- (Optional) Set `WEBDAV_PUBLIC_READ` to `1` to enable public read
3. Retry deployment in `Deployments` page to apply the changes
4. (Optional) Add a custom domain

### Authentication
You can also deploy this project using Wrangler CLI:

There is no built-in authentication support.
By default everyone can read and write your storage.
But Cloudflare Zero Trust can be used to protect your data.
Do these steps to enable authentication:

1. Enable Cloudflare Zero Trust
2. In **Access**->**Applications**, create a self-hosted application
3. Set **Path** as `api/write/` to disable public write or leave it blank to disable public read
4. Create a policy which accepts your email only
```bash
npm run build
npx wrangler pages deploy build
```

### WebDAV endpoint

Expand Down
69 changes: 0 additions & 69 deletions functions/api/buckets.ts

This file was deleted.

144 changes: 0 additions & 144 deletions functions/api/write/items/[[path]].ts

This file was deleted.

21 changes: 0 additions & 21 deletions functions/api/write/s3/[[path]].ts

This file was deleted.

4 changes: 3 additions & 1 deletion functions/webdav/[[path]].ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { notFound, parseBucketPath } from "@/utils/bucket";
import { notFound, parseBucketPath } from "./utils";
import { handleRequestCopy } from "./copy";
import { handleRequestDelete } from "./delete";
import { handleRequestGet } from "./get";
Expand All @@ -8,6 +8,7 @@ import { handleRequestMove } from "./move";
import { handleRequestPropfind } from "./propfind";
import { handleRequestPut } from "./put";
import { RequestHandlerParams } from "./utils";
import { handleRequestPost } from "./post";

async function handleRequestOptions() {
return new Response(null, {
Expand All @@ -27,6 +28,7 @@ const HANDLERS: Record<
MKCOL: handleRequestMkcol,
HEAD: handleRequestHead,
GET: handleRequestGet,
POST: handleRequestPost,
PUT: handleRequestPut,
COPY: handleRequestCopy,
MOVE: handleRequestMove,
Expand Down
2 changes: 1 addition & 1 deletion functions/webdav/copy.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import pLimit from "p-limit";

import { notFound } from "@/utils/bucket";
import { notFound } from "./utils";
import { listAll, RequestHandlerParams, WEBDAV_ENDPOINT } from "./utils";

export async function handleRequestCopy({
Expand Down
2 changes: 1 addition & 1 deletion functions/webdav/delete.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { notFound } from "@/utils/bucket";
import { notFound } from "./utils";
import { listAll, RequestHandlerParams } from "./utils";

export async function handleRequestDelete({
Expand Down
2 changes: 1 addition & 1 deletion functions/webdav/get.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { notFound } from "@/utils/bucket";
import { notFound } from "./utils";
import { RequestHandlerParams } from "./utils";

export async function handleRequestGet({
Expand Down
2 changes: 1 addition & 1 deletion functions/webdav/head.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { notFound } from "@/utils/bucket";
import { notFound } from "./utils";
import { RequestHandlerParams } from "./utils";

export async function handleRequestHead({
Expand Down
60 changes: 60 additions & 0 deletions functions/webdav/post.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { notFound } from "./utils";
import { RequestHandlerParams } from "./utils";

export async function handleRequestPostCreateMultipart({
bucket,
path,
request,
}: RequestHandlerParams) {
const thumbnail = request.headers.get("fd-thumbnail");
const customMetadata = thumbnail ? { thumbnail } : undefined;

const multipartUpload = await bucket.createMultipartUpload(path, {
httpMetadata: request.headers,
customMetadata,
});

const { key, uploadId } = multipartUpload;
return new Response(JSON.stringify({ key, uploadId }));
}

export async function handleRequestPostCompleteMultipart({
bucket,
path,
request,
}: RequestHandlerParams) {
const url = new URL(request.url);
const uploadId = new URLSearchParams(url.search).get("uploadId");
if (!uploadId) return notFound();
const multipartUpload = bucket.resumeMultipartUpload(path, uploadId);

const completeBody: { parts: Array<any> } = await request.json();

try {
const object = await multipartUpload.complete(completeBody.parts);
return new Response(null, {
headers: { etag: object.httpEtag },
});
} catch (error: any) {
return new Response(error.message, { status: 400 });
}
}

export const handleRequestPost = async function ({
bucket,
path,
request,
}: RequestHandlerParams) {
const url = new URL(request.url);
const searchParams = new URLSearchParams(url.search);

if (searchParams.has("uploads")) {
return handleRequestPostCreateMultipart({ bucket, path, request });
}

if (searchParams.has("uploadId")) {
return handleRequestPostCompleteMultipart({ bucket, path, request });
}

return new Response("Method not allowed", { status: 405 });
};
Loading

0 comments on commit 258da4b

Please sign in to comment.