fix: logs: bad file name was registered for PUT requests

Massimo Melina committed Dec 20, 2023 at 16:24 UTC c0f6678e49ae7e0d186a13c5ce80820d7eddd3df
4 files changed +18 -10
admin/src/LogsPage.ts
+6 -4
@@ -4,7 +4,7 @@ import { createElement as h, Fragment, useMemo, useState } from 'react';
4 import { Box, Tab, Tabs, Tooltip } from '@mui/material'
5 import { API_URL, useApiList } from './api'
6 import { DataTable } from './DataTable'
7 -import { Dict, formatBytes, HTTP_UNAUTHORIZED, prefix, shortenAgent, tryJson } from '@hfs/shared'
7 +import { Dict, formatBytes, HTTP_UNAUTHORIZED, prefix, shortenAgent, splitAt, tryJson } from '@hfs/shared'
8 import { logLabels } from './OptionsPage'
9 import { Flex, typedKeys, useBreakpoint, usePauseButton, useToggleButton } from './misc';
10 import { GridColDef } from '@mui/x-data-grid'
@@ -49,7 +49,7 @@ function LogFile({ file, pause, showApi }: { file: string, pause?: boolean, show
49 if (extra?.ua && !showAgent)
50 setShowAgent(true)
51 x.notes = extra?.dl ? "fully downloaded"
52 - : extra?.ul ? "uploaded " + formatBytes(extra.size)
52 + : (x.method === 'PUT' || extra?.ul) ? "uploaded " + formatBytes(extra.size)
53 : x.status === HTTP_UNAUTHORIZED && x.uri?.startsWith(API_URL + 'loginSrp') ? "login failed" + prefix(':\n', extra?.u)
54 : x.notes
55 return x
@@ -162,9 +162,11 @@ function LogFile({ file, pause, showApi }: { file: string, pause?: boolean, show
162 minWidth: 100,
163 mergeRender: { other: 'method', fontSize: 'small' },
164 renderCell: ({ value, row }) => {
165 - if (row.extra?.ul)
166 - return row.extra?.ul
165 value = decodeURIComponent(value)
166 + const ul = row.extra?.ul
167 + if (ul)
168 + return typeof ul === 'string' ? ul // legacy pre-0.51
169 + : splitAt('?', value)[0] + ul.join(' + ')
170 if (!value.startsWith(API_URL))
171 return value
172 const ofs = API_URL.length
src/log.ts
+1 -1
@@ -107,7 +107,7 @@ export const logMw: Koa.Middleware = async (ctx, next) => {
107 const length = ctx.state.length ?? ctx.length
108 const uri = ctx.originalUrl
109 ctx.logExtra(ctx.state.includesLastByte && ctx.vfsNode && ctx.res.finished && { dl: 1 }
110 - || ctx.state.uploadPath && { ul: ctx.state.uploadPath, size: ctx.state.uploadSize })
110 + || ctx.state.uploadSize !== undefined && { size: ctx.state.uploadSize, ul: ctx.state.uploads })
111 const conn = getConnection(ctx)
112 if (conn?.country)
113 ctx.logExtra({ country: conn.country })
src/middlewares.ts
+11 -3
@@ -13,7 +13,7 @@ import { zipStreamFromFolder } from './zip'
13 import { serveFile, serveFileNode } from './serveFile'
14 import { serveGuiFiles } from './serveGuiFiles'
15 import mount from 'koa-mount'
16 -import { Readable } from 'stream'
16 +import { Readable, Writable } from 'stream'
17 import { applyBlock } from './block'
18 import { Account, accountCanLogin, getAccount } from './perm'
19 import { socket2connection, updateConnection, normalizeIp, disconnect, Connection } from './connections'
@@ -99,6 +99,7 @@ export const serveGuiAndSharedFiles: Koa.Middleware = async (ctx, next) => {
99 const folder = await urlToNode(dirname(decPath), ctx, vfs, v => rest = v+'/'+rest)
100 if (!folder)
101 return sendErrorPage(ctx, HTTP_NOT_FOUND)
102 + ctx.state.uploadPath = decPath
103 const dest = uploadWriter(folder, rest, ctx)
104 if (dest) {
105 await pipeline(ctx.req, dest)
@@ -115,11 +116,16 @@ export const serveGuiAndSharedFiles: Koa.Middleware = async (ctx, next) => {
116 if (ctx.request.type !== 'multipart/form-data')
117 return ctx.status = HTTP_BAD_REQUEST
118 ctx.body = {}
119 + ctx.state.uploads = []
120 const form = formidable({
121 maxFileSize: Infinity,
122 allowEmptyFiles: true,
121 - //@ts-ignore wrong in the .d.ts file
122 - fileWriteStreamHandler: f => uploadWriter(node, f.originalFilename, ctx)
123 + fileWriteStreamHandler: f => {
124 + const fn = (f as any).originalFilename
125 + ctx.state.uploadPath = decodeURI(ctx.path) + fn
126 + ctx.state.uploads!.push(fn)
127 + return uploadWriter(node!, fn, ctx) || new Writable()
128 + }
129 })
130 return new Promise<void>(res => form.parse(ctx.req, err => {
131 if (err) console.error(String(err))
@@ -256,6 +262,8 @@ declare module "koa" {
262 connection: Connection
263 serveApp?: boolean // please, serve the frontend app
264 browsing?: string // for admin/monitoring
265 + uploadPath?: string // current one
266 + uploads?: string[] // in case of request with potentially multiple uploads (POST), we register all filenames (no full path)
267 }
268 }
269 export const paramsDecoder: Koa.Middleware = async (ctx, next) => {
src/upload.ts
-2
@@ -132,7 +132,6 @@ export function uploadWriter(base: VfsNode, path: string, ctx: Koa.Context) {
132 const conn = socket2connection(ctx.socket)
133 if (!conn) return ()=>{}
134 const opTotal = reqSize + resume
135 - ctx.state.uploadPath = ctx.path + path
135 ctx.state.uploadSize = opTotal
136 updateConnection(conn, { ctx, op: 'upload', opTotal, opOffset: resume / opTotal })
137 const h = setInterval(() => {
@@ -169,6 +168,5 @@ export function uploadWriter(base: VfsNode, path: string, ctx: Koa.Context) {
168 declare module "koa" {
169 interface DefaultState {
170 uploadSize?: number
172 - uploadPath?: string
171 }
172 }
\ No newline at end of file