upload: content-length mandatory
Massimo Melina committed
May 29, 2024 at 19:38 UTC
118c737dd2be842187fcb89608f4495f7f5e981f
4 files changed
+17
-9
src/middlewares.ts
+1
-1
@@ -47,7 +47,7 @@ export const headRequests: Koa.Middleware = async (ctx, next) => {
47
}
48
49
let proxyDetected: undefined | Koa.Context
50
-export const someSecurity: Koa.Middleware = async (ctx, next) => {
50
+export const someSecurity: Koa.Middleware = (ctx, next) => {
51
ctx.request.ip = normalizeIp(ctx.ip)
52
// don't allow sessions to change ip
53
const ss = ctx.session
src/selfCheck.ts
+1
-1
@@ -9,7 +9,7 @@ import { httpString } from './util-http'
9
let selfChecking = false
10
11
const CHECK_URL = SPECIAL_URI + 'self-check'
12
-export const selfCheckMiddleware: Middleware = async (ctx, next) => {
12
+export const selfCheckMiddleware: Middleware = (ctx, next) => {
13
if (!selfChecking || !ctx.url.startsWith(CHECK_URL))
14
return next()
15
ctx.body = 'HFS'
src/upload.ts
+10
-3
@@ -1,6 +1,7 @@
1
import { getNodeByName, hasPermission, statusCodeForMissingPerm, VfsNode } from './vfs'
2
import Koa from 'koa'
3
-import { HTTP_CONFLICT, HTTP_FOOL, HTTP_PAYLOAD_TOO_LARGE, HTTP_RANGE_NOT_SATISFIABLE, HTTP_SERVER_ERROR } from './const'
3
+import { HTTP_CONFLICT, HTTP_FOOL, HTTP_PAYLOAD_TOO_LARGE, HTTP_RANGE_NOT_SATISFIABLE, HTTP_SERVER_ERROR,
4
+ HTTP_BAD_REQUEST } from './const'
5
import { basename, dirname, extname, join } from 'path'
6
import fs from 'fs'
7
import { Callback, dirTraversal, escapeHTML, loadFileAttr, pendingPromise, storeFileAttr, try_ } from './misc'
@@ -52,7 +53,11 @@ export function uploadWriter(base: VfsNode, path: string, ctx: Koa.Context) {
53
const dir = dirname(fullPath)
54
const min = minAvailableMb.get() * (1 << 20)
55
const reqSize = Number(ctx.headers["content-length"])
55
- if (reqSize)
56
+ if (isNaN(reqSize)) {
57
+ if (min)
58
+ return fail(HTTP_BAD_REQUEST, 'content-length mandatory')
59
+ }
60
+ else
61
try {
62
if (!Object.hasOwn(cache, dir)) {
63
cache[dir] = getDiskSpaceSync(dir)
@@ -191,9 +196,11 @@ export function uploadWriter(base: VfsNode, path: string, ctx: Koa.Context) {
196
delete waitingToBeDeleted[path]
197
}
198
194
- function fail(status?: number) {
199
+ function fail(status?: number, msg?: string) {
200
if (status)
201
ctx.status = status
202
+ if (msg)
203
+ ctx.body = msg
204
notifyClient(ctx, 'upload.status', { [path]: ctx.status }) // allow browsers to detect failure while still sending body
205
}
206
}
tests/test.ts
+5
-4
@@ -1,12 +1,11 @@
1
import { srpClientSequence } from '../src/srp'
2
-import { createReadStream } from 'fs'
2
+import { createReadStream, statSync } from 'fs'
3
import { dirname, join } from 'path'
4
import _ from 'lodash'
5
import { findDefined, randomId, tryJson, wait } from '../src/cross'
6
import { httpStream, stream2string, XRequestOptions } from '../src/util-http'
7
import { ThrottledStream, ThrottleGroup } from '../src/ThrottledStream'
8
import { rm, writeFile } from 'fs/promises'
9
-import { Readable } from 'stream'
9
/*
10
import { PORT, srv } from '../src'
11
@@ -154,10 +153,12 @@ function login(usr: string, pwd=password) {
153
reqApi(cmd, params, (x,res)=> res.statusCode < 400)())
154
}
155
157
-function reqUpload(dest: string, tester: Tester, body?: Readable | string) {
156
+function reqUpload(dest: string, tester: Tester, body?: string) {
157
+ const fn = join(__dirname, 'page/gpl.png')
158
return req(dest, tester, {
159
method: 'PUT',
160
- body: body ?? createReadStream(join(__dirname, 'page/gpl.png'))
160
+ headers: { 'content-length': body?.length ?? statSync(fn).size },
161
+ body: body ?? createReadStream(fn)
162
})
163
}
164