Compare commits

...

16 Commits
ci ... worker

Author SHA1 Message Date
5fae701f01 Specify R2 binding 2024-10-09 17:31:56 +08:00
Velih Dzen
5f272ec046
Implement partial content support for GET: Add Content-Length and Content-Range headers (#9) 2024-09-15 00:31:07 +08:00
dependabot[bot]
7503d6115b
Bump braces from 3.0.2 to 3.0.3 (#8)
Bumps [braces](https://github.com/micromatch/braces) from 3.0.2 to 3.0.3.
- [Changelog](https://github.com/micromatch/braces/blob/master/CHANGELOG.md)
- [Commits](https://github.com/micromatch/braces/compare/3.0.2...3.0.3)

---
updated-dependencies:
- dependency-name: braces
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-19 09:47:53 +08:00
dependabot[bot]
3afcdcfe46
Bump ws from 8.16.0 to 8.17.1 (#7)
Bumps [ws](https://github.com/websockets/ws) from 8.16.0 to 8.17.1.
- [Release notes](https://github.com/websockets/ws/releases)
- [Commits](https://github.com/websockets/ws/compare/8.16.0...8.17.1)

---
updated-dependencies:
- dependency-name: ws
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-19 09:46:59 +08:00
dependabot[bot]
ab7622cc5b
Bump undici from 5.28.3 to 5.28.4 (#6)
Bumps [undici](https://github.com/nodejs/undici) from 5.28.3 to 5.28.4.
- [Release notes](https://github.com/nodejs/undici/releases)
- [Commits](https://github.com/nodejs/undici/compare/v5.28.3...v5.28.4)

---
updated-dependencies:
- dependency-name: undici
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-05 17:38:46 +08:00
abersheeran
2e6d001c0d Update lock 2024-03-02 14:01:25 +08:00
abersheeran
b3c8753308 prettierrc printWidth 120 2024-03-02 13:54:52 +08:00
Aber
11d1825dae
Close #3 2024-03-02 13:51:34 +08:00
Aber
9450ba3577
Merge pull request #2 from abersheeran/dependabot/npm_and_yarn/undici-5.28.3
Bump undici from 5.28.2 to 5.28.3
2024-02-18 09:34:53 +08:00
dependabot[bot]
237ff01c22
Bump undici from 5.28.2 to 5.28.3
Bumps [undici](https://github.com/nodejs/undici) from 5.28.2 to 5.28.3.
- [Release notes](https://github.com/nodejs/undici/releases)
- [Commits](https://github.com/nodejs/undici/compare/v5.28.2...v5.28.3)

---
updated-dependencies:
- dependency-name: undici
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-16 18:36:26 +00:00
abersheeran
c104601ab1 Refactor content headers and handle move operation 2024-01-06 11:28:32 +08:00
abersheeran
f81cee4647 Refactor DAV handling and remove unused code 2024-01-06 10:10:37 +08:00
abersheeran
4788813c39 Refactor content metadata handling in index.ts 2024-01-06 10:08:16 +08:00
abersheeran
a534702d24 Refactor handle_propfind function to use a helper function for generating propfind response 2024-01-06 10:04:51 +08:00
abersheeran
e740a54af9 Update README.md and wrangler.toml 2023-12-26 19:44:27 +08:00
abersheeran
988fc29dda pettier . --write 2023-12-24 13:51:38 +08:00
7 changed files with 357 additions and 257 deletions

View File

@ -1,5 +1,5 @@
{
"printWidth": 140,
"printWidth": 120,
"singleQuote": true,
"semi": true,
"useTabs": true

View File

@ -4,22 +4,24 @@
Use Cloudflare Workers to provide a WebDav interface for Cloudflare R2.
## Configuration
## Usage
Change wrangler.toml to your own.
```toml
[[r2_buckets]]
binding = 'webdav' # <~ valid JavaScript variable name, don't change this
binding = 'bucket' # <~ valid JavaScript variable name, don't change this
bucket_name = 'webdav'
[vars]
USERNAME = "USERNAME"
PASSWORD = "PASSWORD"
```
* USERNAME: The username of WebDav.
* PASSWORD: The password of WebDav.
Then use wrangler to deploy.
```bash
wrangler deploy
wrangler secret put USERNAME
wrangler secret put PASSWORD
```
## Development

267
package-lock.json generated
View File

@ -9,23 +9,24 @@
"version": "0.0.0",
"devDependencies": {
"@cloudflare/workers-types": "^4.20231121.0",
"prettier": "3.1.1",
"typescript": "^5.0.4",
"wrangler": "^3.0.0"
}
},
"node_modules/@cloudflare/kv-asset-handler": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/@cloudflare/kv-asset-handler/-/kv-asset-handler-0.2.0.tgz",
"integrity": "sha512-MVbXLbTcAotOPUj0pAMhVtJ+3/kFkwJqc5qNOleOZTv6QkZZABDMS21dSrSlVswEHwrpWC03e4fWytjqKvuE2A==",
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/@cloudflare/kv-asset-handler/-/kv-asset-handler-0.3.1.tgz",
"integrity": "sha512-lKN2XCfKCmpKb86a1tl4GIwsJYDy9TGuwjhDELLmpKygQhw8X2xR4dusgpC5Tg7q1pB96Eb0rBo81kxSILQMwA==",
"dev": true,
"dependencies": {
"mime": "^3.0.0"
}
},
"node_modules/@cloudflare/workerd-darwin-64": {
"version": "1.20231030.0",
"resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20231030.0.tgz",
"integrity": "sha512-J4PQ9utPxLya9yHdMMx3AZeC5M/6FxcoYw6jo9jbDDFTy+a4Gslqf4Im9We3aeOEdPXa3tgQHVQOSelJSZLhIw==",
"version": "1.20240223.1",
"resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20240223.1.tgz",
"integrity": "sha512-GgHnvkazLFZ7bmR96+dTX0+WS13a+5CHOOP3qNUSR9oEnR4hHzpNIO75MuZsm9RPAXrvtT7nSJmYwiGCZXh6og==",
"cpu": [
"x64"
],
@ -39,9 +40,9 @@
}
},
"node_modules/@cloudflare/workerd-darwin-arm64": {
"version": "1.20231030.0",
"resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20231030.0.tgz",
"integrity": "sha512-WSJJjm11Del4hSneiNB7wTXGtBXI4QMCH9l5qf4iT5PAW8cESGcCmdHtWDWDtGAAGcvmLT04KNvmum92vRKKQQ==",
"version": "1.20240223.1",
"resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20240223.1.tgz",
"integrity": "sha512-ZF98vUmVlC0EVEd3RRuhMq4HYWFcqmPtMIMPUN2+ivEHR92TE+6E/AvdeE6wcE7fKHQ+fk3dH+ZgB0GcfptfnA==",
"cpu": [
"arm64"
],
@ -55,9 +56,9 @@
}
},
"node_modules/@cloudflare/workerd-linux-64": {
"version": "1.20231030.0",
"resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20231030.0.tgz",
"integrity": "sha512-2HUeRTvoCC17fxE0qdBeR7J9dO8j4A8ZbdcvY8pZxdk+zERU6+N03RTbk/dQMU488PwiDvcC3zZqS4gwLfVT8g==",
"version": "1.20240223.1",
"resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20240223.1.tgz",
"integrity": "sha512-1kH41ewNTGMmAk2zUX0Xj9VSfidl26GQ0ZrWMdi5kwf6gAHd3oVWNigJN078Jx56SgQxNcqVGX1LunqF949asw==",
"cpu": [
"x64"
],
@ -71,9 +72,9 @@
}
},
"node_modules/@cloudflare/workerd-linux-arm64": {
"version": "1.20231030.0",
"resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20231030.0.tgz",
"integrity": "sha512-4/GK5zHh+9JbUI6Z5xTCM0ZmpKKHk7vu9thmHjUxtz+o8Ne9DoD7DlDvXQWgMF6XGaTubDWyp3ttn+Qv8jDFuQ==",
"version": "1.20240223.1",
"resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20240223.1.tgz",
"integrity": "sha512-Ro8Og5C4evh890JrRm0B8sHyumRtgL+mUqPeNcEsyG45jAQy5xHpapHnmJAMJV6ah+zDc1cZtQq+en39SojXvQ==",
"cpu": [
"arm64"
],
@ -87,9 +88,9 @@
}
},
"node_modules/@cloudflare/workerd-windows-64": {
"version": "1.20231030.0",
"resolved": "https://registry.npmjs.org/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20231030.0.tgz",
"integrity": "sha512-fb/Jgj8Yqy3PO1jLhk7mTrHMkR8jklpbQFud6rL/aMAn5d6MQbaSrYOCjzkKGp0Zng8D2LIzSl+Fc0C9Sggxjg==",
"version": "1.20240223.1",
"resolved": "https://registry.npmjs.org/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20240223.1.tgz",
"integrity": "sha512-eNP5sfaP6WL07DaoigYou5ASPF7jHsFiNzzD2vGOI7yFd5sPlb7sJ4SpIy+BCX0LdqFnjmlUo5Xr+/I6qJ2Nww==",
"cpu": [
"x64"
],
@ -103,9 +104,9 @@
}
},
"node_modules/@cloudflare/workers-types": {
"version": "4.20231121.0",
"resolved": "https://registry.npmjs.org/@cloudflare/workers-types/-/workers-types-4.20231121.0.tgz",
"integrity": "sha512-+kWfpCkqiepwAKXyHoE0gnkPgkLhz0/9HOBIGhHRsUvUKvhUtm3mbqqoGRWgF1qcjzrDUBbrrOq4MYHfFtc2RA==",
"version": "4.20240222.0",
"resolved": "https://registry.npmjs.org/@cloudflare/workers-types/-/workers-types-4.20240222.0.tgz",
"integrity": "sha512-luO0BdK3rLlCv3B240+cTrfqm+XSbHtpk+88aJtGwzyVK9QF/Xz8lBgE/oZZLN8nCTmOvxAZnszyxUuZ8GP8Cg==",
"dev": true
},
"node_modules/@cspotcode/source-map-support": {
@ -495,18 +496,18 @@
}
},
"node_modules/@fastify/busboy": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.0.tgz",
"integrity": "sha512-+KpH+QxZU7O4675t3mnkQKcZZg56u+K/Ct2K+N2AZYNVK8kyeo/bI18tI8aPm3tvNNRyTWfj6s5tnGNlcbQRsA==",
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz",
"integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==",
"dev": true,
"engines": {
"node": ">=14"
}
},
"node_modules/@jridgewell/resolve-uri": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz",
"integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==",
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
"integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
"dev": true,
"engines": {
"node": ">=6.0.0"
@ -529,27 +530,27 @@
}
},
"node_modules/@types/node": {
"version": "20.10.5",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.5.tgz",
"integrity": "sha512-nNPsNE65wjMxEKI93yOP+NPGGBJz/PoN3kZsVLee0XMiJolxSekEVD8wRwBUBqkwc7UWop0edW50yrCQW4CyRw==",
"version": "20.11.24",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.24.tgz",
"integrity": "sha512-Kza43ewS3xoLgCEpQrsT+xRo/EJej1y0kVYGiLFE1NEODXGzTfwiC6tXTLMQskn1X4/Rjlh0MQUvx9W+L9long==",
"dev": true,
"dependencies": {
"undici-types": "~5.26.4"
}
},
"node_modules/@types/node-forge": {
"version": "1.3.10",
"resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.10.tgz",
"integrity": "sha512-y6PJDYN4xYBxwd22l+OVH35N+1fCYWiuC3aiP2SlXVE6Lo7SS+rSx9r89hLxrP4pn6n1lBGhHJ12pj3F3Mpttw==",
"version": "1.3.11",
"resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.11.tgz",
"integrity": "sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==",
"dev": true,
"dependencies": {
"@types/node": "*"
}
},
"node_modules/acorn": {
"version": "8.11.2",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz",
"integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==",
"version": "8.11.3",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz",
"integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==",
"dev": true,
"bin": {
"acorn": "bin/acorn"
@ -559,9 +560,9 @@
}
},
"node_modules/acorn-walk": {
"version": "8.3.1",
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.1.tgz",
"integrity": "sha512-TgUZgYvqZprrl7YldZNoa9OciCAyZR+Ejm9eXzKCmjsF5IKp/wgQ7Z/ZpjpGTIUPwrHQIcYeI8qDh4PsEwxMbw==",
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz",
"integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==",
"dev": true,
"engines": {
"node": ">=0.4.0"
@ -605,23 +606,17 @@
"dev": true
},
"node_modules/braces": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
"dev": true,
"dependencies": {
"fill-range": "^7.0.1"
"fill-range": "^7.1.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/buffer-from": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
"dev": true
},
"node_modules/capnp-ts": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/capnp-ts/-/capnp-ts-0.7.0.tgz",
@ -633,16 +628,10 @@
}
},
"node_modules/chokidar": {
"version": "3.5.3",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
"integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
"integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
"dev": true,
"funding": [
{
"type": "individual",
"url": "https://paulmillr.com/funding/"
}
],
"dependencies": {
"anymatch": "~3.1.2",
"braces": "~3.0.2",
@ -655,6 +644,9 @@
"engines": {
"node": ">= 8.10.0"
},
"funding": {
"url": "https://paulmillr.com/funding/"
},
"optionalDependencies": {
"fsevents": "~2.3.2"
}
@ -759,9 +751,9 @@
}
},
"node_modules/fill-range": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
"dev": true,
"dependencies": {
"to-regex-range": "^5.0.1"
@ -784,6 +776,15 @@
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
"node_modules/function-bind": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
"dev": true,
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/get-source": {
"version": "2.0.12",
"resolved": "https://registry.npmjs.org/get-source/-/get-source-2.0.12.tgz",
@ -812,6 +813,18 @@
"integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==",
"dev": true
},
"node_modules/hasown": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.1.tgz",
"integrity": "sha512-1/th4MHjnwncwXsIW6QMzlvYL9kG5e/CpVvLRZe4XPa8TOUNbCELqmvhDmnkNsAjwaG4+I8gJJL0JBvTTLO9qA==",
"dev": true,
"dependencies": {
"function-bind": "^1.1.2"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/is-binary-path": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
@ -824,6 +837,18 @@
"node": ">=8"
}
},
"node_modules/is-core-module": {
"version": "2.13.1",
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz",
"integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==",
"dev": true,
"dependencies": {
"hasown": "^2.0.0"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-extglob": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
@ -876,20 +901,20 @@
}
},
"node_modules/miniflare": {
"version": "3.20231030.4",
"resolved": "https://registry.npmjs.org/miniflare/-/miniflare-3.20231030.4.tgz",
"integrity": "sha512-7MBz0ArLuDop1WJGZC6tFgN6c5MRyDOIlxbm3yp0TRBpvDS/KsTuWCQcCjsxN4QQ5zvL3JTkuIZbQzRRw/j6ow==",
"version": "3.20240223.0",
"resolved": "https://registry.npmjs.org/miniflare/-/miniflare-3.20240223.0.tgz",
"integrity": "sha512-8T/36FEfvsL4aMF7SLZ28v+PQL0jsUlVw/u114GYcdobkyPax9E6Ahn0XePOHEqLxQSndwPee+eS1phHANFePA==",
"dev": true,
"dependencies": {
"@cspotcode/source-map-support": "0.8.1",
"acorn": "^8.8.0",
"acorn-walk": "^8.2.0",
"capnp-ts": "^0.7.0",
"exit-hook": "^2.2.1",
"glob-to-regexp": "^0.4.1",
"source-map-support": "0.5.21",
"stoppable": "^1.1.0",
"undici": "^5.22.1",
"workerd": "1.20231030.0",
"undici": "^5.28.2",
"workerd": "1.20240223.1",
"ws": "^8.11.0",
"youch": "^3.2.2",
"zod": "^3.20.6"
@ -952,6 +977,12 @@
"node": ">=0.10.0"
}
},
"node_modules/path-parse": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
"dev": true
},
"node_modules/path-to-regexp": {
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.1.tgz",
@ -970,6 +1001,21 @@
"url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/prettier": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.1.1.tgz",
"integrity": "sha512-22UbSzg8luF4UuZtzgiUOfcGM8s4tjBv6dJRT7j275NXsy2jb4aJa4NNveul5x4eqlF1wuhuR2RElK71RvmVaw==",
"dev": true,
"bin": {
"prettier": "bin/prettier.cjs"
},
"engines": {
"node": ">=14"
},
"funding": {
"url": "https://github.com/prettier/prettier?sponsor=1"
}
},
"node_modules/printable-characters": {
"version": "1.0.42",
"resolved": "https://registry.npmjs.org/printable-characters/-/printable-characters-1.0.42.tgz",
@ -988,6 +1034,23 @@
"node": ">=8.10.0"
}
},
"node_modules/resolve": {
"version": "1.22.8",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
"integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==",
"dev": true,
"dependencies": {
"is-core-module": "^2.13.0",
"path-parse": "^1.0.7",
"supports-preserve-symlinks-flag": "^1.0.0"
},
"bin": {
"resolve": "bin/resolve"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/resolve.exports": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz",
@ -1049,16 +1112,6 @@
"node": ">=0.10.0"
}
},
"node_modules/source-map-support": {
"version": "0.5.21",
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
"integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
"dev": true,
"dependencies": {
"buffer-from": "^1.0.0",
"source-map": "^0.6.0"
}
},
"node_modules/sourcemap-codec": {
"version": "1.4.8",
"resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz",
@ -1086,6 +1139,18 @@
"npm": ">=6"
}
},
"node_modules/supports-preserve-symlinks-flag": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
"dev": true,
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
@ -1118,9 +1183,9 @@
}
},
"node_modules/undici": {
"version": "5.28.2",
"resolved": "https://registry.npmjs.org/undici/-/undici-5.28.2.tgz",
"integrity": "sha512-wh1pHJHnUeQV5Xa8/kyQhO7WFa8M34l026L5P/+2TYiakvGy5Rdc8jWZVyG7ieht/0WgJLEd3kcU5gKx+6GC8w==",
"version": "5.28.4",
"resolved": "https://registry.npmjs.org/undici/-/undici-5.28.4.tgz",
"integrity": "sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==",
"dev": true,
"dependencies": {
"@fastify/busboy": "^2.0.0"
@ -1136,9 +1201,9 @@
"dev": true
},
"node_modules/workerd": {
"version": "1.20231030.0",
"resolved": "https://registry.npmjs.org/workerd/-/workerd-1.20231030.0.tgz",
"integrity": "sha512-+FSW+d31f8RrjHanFf/R9A+Z0csf3OtsvzdPmAKuwuZm/5HrBv83cvG9fFeTxl7/nI6irUUXIRF9xcj/NomQzQ==",
"version": "1.20240223.1",
"resolved": "https://registry.npmjs.org/workerd/-/workerd-1.20240223.1.tgz",
"integrity": "sha512-Mo1fwdp6DLva4/fWdL09ZdYllkO45I4YpWG5PbF/YUGFlu2aMk24fmU6Pd6fo5/cWek4F+n3LmYEKKHfqjiJIA==",
"dev": true,
"hasInstallScript": true,
"bin": {
@ -1148,29 +1213,29 @@
"node": ">=16"
},
"optionalDependencies": {
"@cloudflare/workerd-darwin-64": "1.20231030.0",
"@cloudflare/workerd-darwin-arm64": "1.20231030.0",
"@cloudflare/workerd-linux-64": "1.20231030.0",
"@cloudflare/workerd-linux-arm64": "1.20231030.0",
"@cloudflare/workerd-windows-64": "1.20231030.0"
"@cloudflare/workerd-darwin-64": "1.20240223.1",
"@cloudflare/workerd-darwin-arm64": "1.20240223.1",
"@cloudflare/workerd-linux-64": "1.20240223.1",
"@cloudflare/workerd-linux-arm64": "1.20240223.1",
"@cloudflare/workerd-windows-64": "1.20240223.1"
}
},
"node_modules/wrangler": {
"version": "3.21.0",
"resolved": "https://registry.npmjs.org/wrangler/-/wrangler-3.21.0.tgz",
"integrity": "sha512-DLoo4XfjeyuGRAVWZFHmU1jWnZIfyLGDm6Ika9oy/CLCPfJzVJvf2jI70EU5BlEHWDZXMSJKw7FDdgSqwhaQXg==",
"version": "3.30.1",
"resolved": "https://registry.npmjs.org/wrangler/-/wrangler-3.30.1.tgz",
"integrity": "sha512-cT6Ezx8h2v5QiI0HWhnHVy32ng4omdMVdhaMQLuMnyMIHmyDoRg7pmrbhtZfj0663gExLdVtE4ucK//yncVTwg==",
"dev": true,
"dependencies": {
"@cloudflare/kv-asset-handler": "^0.2.0",
"@cspotcode/source-map-support": "0.8.1",
"@cloudflare/kv-asset-handler": "0.3.1",
"@esbuild-plugins/node-globals-polyfill": "^0.2.3",
"@esbuild-plugins/node-modules-polyfill": "^0.2.2",
"blake3-wasm": "^2.1.5",
"chokidar": "^3.5.3",
"esbuild": "0.17.19",
"miniflare": "3.20231030.4",
"miniflare": "3.20240223.0",
"nanoid": "^3.3.3",
"path-to-regexp": "^6.2.0",
"resolve": "^1.22.8",
"resolve.exports": "^2.0.2",
"selfsigned": "^2.0.1",
"source-map": "0.6.1",
@ -1185,12 +1250,20 @@
},
"optionalDependencies": {
"fsevents": "~2.3.2"
},
"peerDependencies": {
"@cloudflare/workers-types": "^4.20230914.0"
},
"peerDependenciesMeta": {
"@cloudflare/workers-types": {
"optional": true
}
}
},
"node_modules/ws": {
"version": "8.15.1",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.15.1.tgz",
"integrity": "sha512-W5OZiCjXEmk0yZ66ZN82beM5Sz7l7coYxpRkzS+p9PP+ToQry8szKh+61eNktr7EA9DOwvFGhfC605jDHbP6QQ==",
"version": "8.17.1",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
"integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
"dev": true,
"engines": {
"node": ">=10.0.0"

View File

@ -5,10 +5,13 @@
"scripts": {
"deploy": "wrangler deploy",
"dev": "wrangler dev",
"start": "wrangler dev"
"start": "wrangler dev",
"lint-perttier": "prettier . --write",
"check-perttier": "prettier . --check"
},
"devDependencies": {
"@cloudflare/workers-types": "^4.20231121.0",
"prettier": "3.1.1",
"typescript": "^5.0.4",
"wrangler": "^3.0.0"
},

View File

@ -46,22 +46,9 @@ async function* listAll(bucket: R2Bucket, prefix: string, isRecursive: boolean =
if (r2_objects.truncated) {
cursor = r2_objects.cursor;
}
} while (r2_objects.truncated)
} while (r2_objects.truncated);
}
const DAV_CLASS = "1";
const SUPPORT_METHODS = [
"OPTIONS",
"PROPFIND",
"MKCOL",
"GET",
"HEAD",
"PUT",
"COPY",
"MOVE",
];
type DavProperties = {
creationdate: string | undefined;
displayname: string | undefined;
@ -71,7 +58,7 @@ type DavProperties = {
getetag: string | undefined;
getlastmodified: string | undefined;
resourcetype: string;
}
};
function fromR2Object(object: R2Object | null | undefined): DavProperties {
if (object === null || object === undefined) {
@ -79,11 +66,11 @@ function fromR2Object(object: R2Object | null | undefined): DavProperties {
creationdate: new Date().toUTCString(),
displayname: undefined,
getcontentlanguage: undefined,
getcontentlength: "0",
getcontentlength: '0',
getcontenttype: undefined,
getetag: undefined,
getlastmodified: new Date().toUTCString(),
resourcetype: "<collection />",
resourcetype: '<collection />',
};
}
@ -99,23 +86,12 @@ function fromR2Object(object: R2Object | null | undefined): DavProperties {
};
}
function make_resource_path(request: Request): string {
let path = new URL(request.url).pathname.slice(1);
path = path.endsWith('/') ? path.slice(0, -1) : path;
return path;
}
async function handle_options(request: Request, bucket: R2Bucket): Promise<Response> {
return new Response(null, {
status: 204,
headers: {
'DAV': DAV_CLASS,
'Allow': SUPPORT_METHODS.join(', '),
}
});
}
async function handle_head(request: Request, bucket: R2Bucket): Promise<Response> {
let response = await handle_get(request, bucket);
return new Response(null, {
@ -133,12 +109,15 @@ async function handle_get(request: Request, bucket: R2Bucket): Promise<Response>
if (resource_path !== '') page += `<a href="../">..</a><br>`;
for await (const object of listAll(bucket, resource_path)) {
if (object.key === resource_path) {
continue
continue;
}
let href = `/${object.key + (object.customMetadata?.resourcetype === '<collection />' ? '/' : '')}`;
page += `<a href="${href}">${object.httpMetadata?.contentDisposition ?? object.key}</a><br>`;
}
return new Response(page, { status: 200, headers: { 'Content-Type': 'text/html; charset=utf-8' } });
return new Response(page, {
status: 200,
headers: { 'Content-Type': 'text/html; charset=utf-8' },
});
} else {
let object = await bucket.get(resource_path, {
onlyIf: request.headers,
@ -147,40 +126,70 @@ async function handle_get(request: Request, bucket: R2Bucket): Promise<Response>
let isR2ObjectBody = (object: R2Object | R2ObjectBody): object is R2ObjectBody => {
return 'body' in object;
}
};
if (object === null) {
return new Response('Not Found', { status: 404 });
} else if (!isR2ObjectBody(object)) {
return new Response("Precondition Failed", { status: 412 });
return new Response('Precondition Failed', { status: 412 });
} else {
const { rangeOffset, rangeEnd } = calcContentRange(object);
const contentLength = rangeEnd - rangeOffset + 1;
return new Response(object.body, {
status: object.range ? 206 : 200,
status: (object.range && contentLength !== object.size) ? 206 : 200,
headers: {
'Content-Type': object.httpMetadata?.contentType ?? 'application/octet-stream',
// TODO: Content-Length, Content-Range
...(object.httpMetadata?.contentDisposition ? {
'Content-Disposition': object.httpMetadata.contentDisposition,
} : {}),
...(object.httpMetadata?.contentEncoding ? {
'Content-Encoding': object.httpMetadata.contentEncoding,
} : {}),
...(object.httpMetadata?.contentLanguage ? {
'Content-Language': object.httpMetadata.contentLanguage,
} : {}),
...(object.httpMetadata?.cacheControl ? {
'Cache-Control': object.httpMetadata.cacheControl,
} : {}),
...(object.httpMetadata?.cacheExpiry ? {
'Cache-Expiry': object.httpMetadata.cacheExpiry.toISOString(),
} : {}),
}
'Content-Length': contentLength.toString(),
...({ 'Content-Range': `bytes ${rangeOffset}-${rangeEnd}/${object.size}` }),
...(object.httpMetadata?.contentDisposition
? {
'Content-Disposition': object.httpMetadata.contentDisposition,
}
: {}),
...(object.httpMetadata?.contentEncoding
? {
'Content-Encoding': object.httpMetadata.contentEncoding,
}
: {}),
...(object.httpMetadata?.contentLanguage
? {
'Content-Language': object.httpMetadata.contentLanguage,
}
: {}),
...(object.httpMetadata?.cacheControl
? {
'Cache-Control': object.httpMetadata.cacheControl,
}
: {}),
...(object.httpMetadata?.cacheExpiry
? {
'Cache-Expiry': object.httpMetadata.cacheExpiry.toISOString(),
}
: {}),
},
});
}
}
}
function calcContentRange(object: R2ObjectBody) {
let rangeOffset = 0;
let rangeEnd = object.size - 1;
if (object.range) {
if ('suffix' in object.range) {
// Case 3: {suffix: number}
rangeOffset = object.size - object.range.suffix;
} else {
// Case 1: {offset: number, length?: number}
// Case 2: {offset?: number, length: number}
rangeOffset = object.range.offset ?? 0;
let length = object.range.length ?? (object.size - rangeOffset);
rangeEnd = Math.min(rangeOffset + length - 1, object.size - 1);
}
}
return { rangeOffset, rangeEnd };
}
async function handle_put(request: Request, bucket: R2Bucket): Promise<Response> {
if (request.url.endsWith('/')) {
return new Response('Method Not Allowed', { status: 405 });
@ -209,10 +218,11 @@ async function handle_delete(request: Request, bucket: R2Bucket): Promise<Respon
let resource_path = make_resource_path(request);
if (resource_path === '') {
let r2_objects, cursor: string | undefined = undefined;
let r2_objects,
cursor: string | undefined = undefined;
do {
r2_objects = await bucket.list({ cursor: cursor });
let keys = r2_objects.objects.map(object => object.key);
let keys = r2_objects.objects.map((object) => object.key);
if (keys.length > 0) {
await bucket.delete(keys);
}
@ -234,13 +244,14 @@ async function handle_delete(request: Request, bucket: R2Bucket): Promise<Respon
return new Response(null, { status: 204 });
}
let r2_objects, cursor: string | undefined = undefined;
let r2_objects,
cursor: string | undefined = undefined;
do {
r2_objects = await bucket.list({
prefix: resource_path + "/",
prefix: resource_path + '/',
cursor: cursor,
});
let keys = r2_objects.objects.map(object => object.key);
let keys = r2_objects.objects.map((object) => object.key);
if (keys.length > 0) {
await bucket.delete(keys);
}
@ -267,28 +278,22 @@ async function handle_mkcol(request: Request, bucket: R2Bucket): Promise<Respons
}
// Check if the parent directory exists
let parent_dir = resource_path.split('/').slice(0, -1).join("/");
let parent_dir = resource_path.split('/').slice(0, -1).join('/');
if (parent_dir !== '' && !await bucket.head(parent_dir)) {
if (parent_dir !== '' && !(await bucket.head(parent_dir))) {
return new Response('Conflict', { status: 409 });
}
await bucket.put(resource_path, new Uint8Array(), {
httpMetadata: request.headers,
customMetadata: { resourcetype: '<collection />' }
customMetadata: { resourcetype: '<collection />' },
});
return new Response('', { status: 201 });
}
async function handle_propfind(request: Request, bucket: R2Bucket): Promise<Response> {
let resource_path = make_resource_path(request);
let is_collection: boolean;
let page = `<?xml version="1.0" encoding="utf-8"?>
<multistatus xmlns="DAV:">`;
if (resource_path === "") {
page += `
function generate_propfind_response(object: R2Object | null): string {
if (object === null) {
return `
<response>
<href>/</href>
<propstat>
@ -301,15 +306,10 @@ async function handle_propfind(request: Request, bucket: R2Bucket): Promise<Resp
<status>HTTP/1.1 200 OK</status>
</propstat>
</response>`;
is_collection = true;
} else {
let object = await bucket.head(resource_path);
if (object === null) {
return new Response('Not Found', { status: 404 });
}
is_collection = object.customMetadata?.resourcetype === '<collection />';
let href = `/${object.key + (object.customMetadata?.resourcetype === '<collection />' ? '/' : '')}`;
page += `
}
let href = `/${object.key + (object.customMetadata?.resourcetype === '<collection />' ? '/' : '')}`;
return `
<response>
<href>${href}</href>
<propstat>
@ -321,53 +321,48 @@ async function handle_propfind(request: Request, bucket: R2Bucket): Promise<Resp
</prop>
<status>HTTP/1.1 200 OK</status>
</propstat>
</response>`
};
</response>`;
}
async function handle_propfind(request: Request, bucket: R2Bucket): Promise<Response> {
let resource_path = make_resource_path(request);
let is_collection: boolean;
let page = `<?xml version="1.0" encoding="utf-8"?>
<multistatus xmlns="DAV:">`;
if (resource_path === '') {
page += generate_propfind_response(null);
is_collection = true;
} else {
let object = await bucket.head(resource_path);
if (object === null) {
return new Response('Not Found', { status: 404 });
}
is_collection = object.customMetadata?.resourcetype === '<collection />';
page += generate_propfind_response(object);
}
if (is_collection) {
let depth = request.headers.get('Depth') ?? 'infinity';
switch (depth) {
case '0': break;
case '1': {
let prefix = resource_path === "" ? resource_path : resource_path + '/';
for await (let object of listAll(bucket, prefix)) {
let href = `/${object.key + (object.customMetadata?.resourcetype === '<collection />' ? '/' : '')}`;
page += `
<response>
<href>${href}</href>
<propstat>
<prop>
${Object.entries(fromR2Object(object))
.filter(([_, value]) => value !== undefined)
.map(([key, value]) => `<${key}>${value}</${key}>`)
.join('\n ')}
</prop>
<status>HTTP/1.1 200 OK</status>
</propstat>
</response>`;
}
}
case '0':
break;
case 'infinity': {
let prefix = resource_path === "" ? resource_path : resource_path + '/';
for await (let object of listAll(bucket, prefix, true)) {
let href = `/${object.key + (object.customMetadata?.resourcetype === '<collection />' ? '/' : '')}`;
page += `
<response>
<href>${href}</href>
<propstat>
<prop>
${Object.entries(fromR2Object(object))
.filter(([_, value]) => value !== undefined)
.map(([key, value]) => `<${key}>${value}</${key}>`)
.join('\n ')
}
</prop>
<status>HTTP/1.1 200 OK</status>
</propstat>
</response>`;
case '1':
{
let prefix = resource_path === '' ? resource_path : resource_path + '/';
for await (let object of listAll(bucket, prefix)) {
page += generate_propfind_response(object);
}
}
break;
case 'infinity':
{
let prefix = resource_path === '' ? resource_path : resource_path + '/';
for await (let object of listAll(bucket, prefix, true)) {
page += generate_propfind_response(object);
}
}
}
break;
default: {
return new Response('Forbidden', { status: 403 });
@ -395,8 +390,11 @@ async function handle_copy(request: Request, bucket: R2Bucket): Promise<Response
destination = destination.endsWith('/') ? destination.slice(0, -1) : destination;
// Check if the parent directory exists
let destination_parent = destination.split('/').slice(0, destination.endsWith('/') ? -2 : -1).join('/');
if (destination_parent !== '' && !await bucket.head(destination_parent)) {
let destination_parent = destination
.split('/')
.slice(0, destination.endsWith('/') ? -2 : -1)
.join('/');
if (destination_parent !== '' && !(await bucket.head(destination_parent))) {
return new Response('Conflict', { status: 409 });
}
@ -417,10 +415,10 @@ async function handle_copy(request: Request, bucket: R2Bucket): Promise<Response
let depth = request.headers.get('Depth') ?? 'infinity';
switch (depth) {
case 'infinity': {
let prefix = resource_path + "/";
let prefix = resource_path + '/';
const copy = async (object: R2Object) => {
let target = destination + "/" + object.key.slice(prefix.length);
target = target.endsWith("/") ? target.slice(0, -1) : target;
let target = destination + '/' + object.key.slice(prefix.length);
target = target.endsWith('/') ? target.slice(0, -1) : target;
let src = await bucket.get(object.key);
if (src !== null) {
await bucket.put(target, src.body, {
@ -487,8 +485,11 @@ async function handle_move(request: Request, bucket: R2Bucket): Promise<Response
destination = destination.endsWith('/') ? destination.slice(0, -1) : destination;
// Check if the parent directory exists
let destination_parent = destination.split('/').slice(0, destination.endsWith('/') ? -2 : -1).join('/');
if (destination_parent !== '' && !await bucket.head(destination_parent)) {
let destination_parent = destination
.split('/')
.slice(0, destination.endsWith('/') ? -2 : -1)
.join('/');
if (destination_parent !== '' && !(await bucket.head(destination_parent))) {
return new Response('Conflict', { status: 409 });
}
@ -506,7 +507,8 @@ async function handle_move(request: Request, bucket: R2Bucket): Promise<Response
return new Response('Bad Request', { status: 400 });
}
if (destination_exists) { // Delete the destination first
if (destination_exists) {
// Delete the destination first
await handle_delete(new Request(new URL(destination_header), request), bucket);
}
@ -516,10 +518,10 @@ async function handle_move(request: Request, bucket: R2Bucket): Promise<Response
let depth = request.headers.get('Depth') ?? 'infinity';
switch (depth) {
case 'infinity': {
let prefix = resource_path + "/";
const copy = async (object: R2Object) => {
let target = destination + "/" + object.key.slice(prefix.length);
target = target.endsWith("/") ? target.slice(0, -1) : target;
let prefix = resource_path + '/';
const move = async (object: R2Object) => {
let target = destination + '/' + object.key.slice(prefix.length);
target = target.endsWith('/') ? target.slice(0, -1) : target;
let src = await bucket.get(object.key);
if (src !== null) {
await bucket.put(target, src.body, {
@ -529,9 +531,9 @@ async function handle_move(request: Request, bucket: R2Bucket): Promise<Response
await bucket.delete(object.key);
}
};
let promise_array = [copy(resource)];
let promise_array = [move(resource)];
for await (let object of listAll(bucket, prefix, true)) {
promise_array.push(copy(object));
promise_array.push(move(object));
}
await Promise.all(promise_array);
if (destination_exists) {
@ -578,10 +580,19 @@ async function handle_move(request: Request, bucket: R2Bucket): Promise<Response
}
}
const DAV_CLASS = '1';
const SUPPORT_METHODS = ['OPTIONS', 'PROPFIND', 'MKCOL', 'GET', 'HEAD', 'PUT', 'COPY', 'MOVE'];
async function dispatch_handler(request: Request, bucket: R2Bucket): Promise<Response> {
switch (request.method) {
case 'OPTIONS': {
return await handle_options(request, bucket);
return new Response(null, {
status: 204,
headers: {
Allow: SUPPORT_METHODS.join(', '),
DAV: DAV_CLASS,
},
});
}
case 'HEAD': {
return await handle_head(request, bucket);
@ -611,9 +622,9 @@ async function dispatch_handler(request: Request, bucket: R2Bucket): Promise<Res
return new Response('Method Not Allowed', {
status: 405,
headers: {
'Allow': SUPPORT_METHODS.join(', '),
'DAV': DAV_CLASS,
}
Allow: SUPPORT_METHODS.join(', '),
DAV: DAV_CLASS,
},
});
}
}
@ -623,11 +634,15 @@ export default {
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
const { bucket } = env;
if (request.headers.get('Authorization') !== `Basic ${btoa(`${env.USERNAME}:${env.PASSWORD}`)}`) {
if (
request.method !== 'OPTIONS' &&
request.headers.get('Authorization') !== `Basic ${btoa(`${env.USERNAME}:${env.PASSWORD}`)}`
) {
return new Response('Unauthorized', {
status: 401, headers: {
status: 401,
headers: {
'WWW-Authenticate': 'Basic realm="webdav"',
}
},
});
}
@ -636,15 +651,19 @@ export default {
// Set CORS headers
response.headers.set('Access-Control-Allow-Origin', request.headers.get('Origin') ?? '*');
response.headers.set('Access-Control-Allow-Methods', SUPPORT_METHODS.join(', '));
response.headers.set('Access-Control-Allow-Headers',
["authorization", "content-type", "depth", "overwrite", "destination", "range"].join(', ')
response.headers.set(
'Access-Control-Allow-Headers',
['authorization', 'content-type', 'depth', 'overwrite', 'destination', 'range'].join(', '),
);
response.headers.set('Access-Control-Expose-Headers',
["content-type", "content-length", "dav", "etag", "last-modified", "location", "date", "content-range"].join(', ')
response.headers.set(
'Access-Control-Expose-Headers',
['content-type', 'content-length', 'dav', 'etag', 'last-modified', 'location', 'date', 'content-range'].join(
', ',
),
);
response.headers.set('Access-Control-Allow-Credentials', 'false');
response.headers.set('Access-Control-Max-Age', '86400');
return response
return response;
},
};

View File

@ -12,7 +12,9 @@
/* Language and Environment */
"target": "es2021" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
"lib": ["es2021"] /* Specify a set of bundled library declaration files that describe the target runtime environment. */,
"lib": [
"es2021"
] /* Specify a set of bundled library declaration files that describe the target runtime environment. */,
"jsx": "react" /* Specify what JSX code is generated. */,
// "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */
// "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
@ -31,7 +33,9 @@
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
// "typeRoots": [], /* Specify multiple folders that act like `./node_modules/@types`. */
"types": ["@cloudflare/workers-types"] /* Specify type package names to be included without being referenced in a source file. */,
"types": [
"@cloudflare/workers-types"
] /* Specify type package names to be included without being referenced in a source file. */,
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
"resolveJsonModule": true /* Enable importing .json files */,
// "noResolve": true, /* Disallow `import`s, `require`s or `<reference>`s from expanding the number of files TypeScript should add to a project. */

View File

@ -7,9 +7,8 @@ node_compat = true
# Variable bindings. These are arbitrary, plaintext strings (similar to environment variables)
# Note: Use secrets to store sensitive data.
# Docs: https://developers.cloudflare.com/workers/platform/environment-variables
[vars]
USERNAME = "USERNAME"
PASSWORD = "PASSWORD"
# [vars]
# MY_VARIABLE = "my-value"
# Bind a KV Namespace. Use KV as persistent storage for small key-value pairs.
# Docs: https://developers.cloudflare.com/workers/runtime-apis/kv
@ -21,7 +20,7 @@ PASSWORD = "PASSWORD"
# Docs: https://developers.cloudflare.com/r2/api/workers/workers-api-usage/
[[r2_buckets]]
binding = "bucket" # <~ valid JavaScript variable name
bucket_name = "webdav"
bucket_name = "zotero"
# Bind a Queue producer. Use this binding to schedule an arbitrary task that may be processed later by a Queue consumer.
# Docs: https://developers.cloudflare.com/queues/get-started