better error code for del_vfs
Massimo Melina committed
Jan 24, 2026 at 12:01 UTC
7087c2ea8667ea799a31e55e01eb87c40c8d4a71
3 files changed
+13
-12
src/api.vfs.ts
+9
-10
@@ -151,21 +151,20 @@ export default {
151
errors: await Promise.all(uris.map(async uri => {
152
if (typeof uri !== 'string')
153
return HTTP_BAD_REQUEST
154
- if (uri === '/')
155
- return HTTP_NOT_ACCEPTABLE
154
const node = await urlToNodeOriginal(uri)
155
if (!node)
156
return HTTP_NOT_FOUND
159
- const parent = dirname(uri)
160
- const parentNode = await urlToNodeOriginal(parent)
161
- if (!parentNode) // shouldn't happen
157
+ if (isRoot(node))
158
+ return HTTP_NOT_ACCEPTABLE
159
+ const parentNode = await urlToNodeOriginal(dirname(uri))
160
+ const c = parentNode?.children // since node is not root, parentNode must exist and have children
161
+ if (!c) // inconsistent state
162
return HTTP_SERVER_ERROR
163
- const { children } = parentNode
164
- if (!children) // shouldn't happen
163
+ const idx = c.indexOf(node)
164
+ if (idx < 0) // inconsistent state
165
return HTTP_SERVER_ERROR
166
- const idx = children.indexOf(node)
167
- children.splice(idx, 1)
168
- if (!children.length)
166
+ c.splice(idx, 1)
167
+ if (!c.length)
168
parentNode.children = undefined
169
return 0 // error code 0 is OK
170
})).finally(saveVfs)
src/vfs.ts
+1
-1
@@ -42,7 +42,7 @@ export interface VfsNodeStored extends VfsPerms {
42
export interface VfsNode extends VfsNodeStored { // include fields that are only filled at run-time
43
isTemp?: true // this node doesn't belong to the tree and was created by necessity
44
original?: VfsNode // if this is a temp node but reflecting an existing node
45
- parent?: VfsNode // available when original is available
45
+ parent?: VfsNode // available when original is available (therefore, only for isTemp)
46
isFolder?: boolean // use nodeIsFolder() instead of relying on this field
47
stats?: Promise<Stats>
48
}
tests/test.ts
+3
-1
@@ -456,9 +456,11 @@ describe('admin', () => {
456
await reqList(name, { inList: ['plugins/'] })()
457
}
458
finally {
459
- await reqApi('del_vfs', { uris: ['/'+name] }, 200, { auth })() // remove
459
+ await reqApi('del_vfs', { uris: ['/'+name] }, data => data?.errors?.[0] === 0, { auth })() // remove
460
}
461
})
462
+ test('del_vfs.bad uris', reqApi('del_vfs', { uris: ['', '/', '//'] }, (res: any) =>
463
+ throwIf(res?.errors.some((x: any) => x === 406) ? '' : res?.errors || 'missing'), { auth }))
464
test('plugins.missing', reqApi('set_plugin', { id: 'missing-plugin', enabled: true }, { status: 400, re: /miss/ }, { auth }))
465
test('plugins.update.missing', reqApi('update_plugin', { id: 'missing-plugin' }, 404, { auth }))
466
test('monitor.connections safe path decode', async () => {