Skip to content

Commit

Permalink
merge: upstream/main
Browse files Browse the repository at this point in the history
  • Loading branch information
fenos committed Dec 7, 2023
2 parents 71ab778 + 562a875 commit 965484d
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 7 deletions.
6 changes: 6 additions & 0 deletions packages/server/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,11 @@ This can be used to implement post-processing validation.
This can be used for things like access control.
You can `throw` an Object and the HTTP request will be aborted with the provided `body` and `status_code` (or their fallbacks).

#### `options.onResponseError`

`onResponseError` will be invoked when an error response is about to be sent by the server.
you use this function to map custom errors to tus errors or for custom observability. (`(req, res, err) => Promise<{status_code: number; body: string} | void> | {status_code: number; body: string} | void`)

#### `server.handle(req, res)`

The main server request handler invoked on every request.
Expand Down Expand Up @@ -203,6 +208,7 @@ const port = 1080
const app = express()
const uploadApp = express()
const server = new Server({
path: '/uploads',
datastore: new FileStore({directory: '/files'}),
})

Expand Down
15 changes: 11 additions & 4 deletions packages/server/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,14 +156,21 @@ export class Server<
req.method = (req.headers['x-http-method-override'] as string).toUpperCase()
}

const onError = (error: {
const onError = async (error: {
status_code?: number
body?: string
message: string
name?: string
}) => {
const status_code = error.status_code || ERRORS.UNKNOWN_ERROR.status_code
const body = error.body || `${ERRORS.UNKNOWN_ERROR.body}${error.message || ''}\n`
let status_code = error.status_code || ERRORS.UNKNOWN_ERROR.status_code
let body = error.body || `${ERRORS.UNKNOWN_ERROR.body}${error.message || ''}\n`

if (this.options.onResponseError) {
const errorMapping = await this.options.onResponseError(req, res, error as Error)
if (errorMapping) {
status_code = errorMapping.status_code
body = errorMapping.body
}
}

return this.write(context, req, res, status_code, body)
}
Expand Down
10 changes: 10 additions & 0 deletions packages/server/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,16 @@ export type ServerOptions<
uploadId: string,
context: Context
) => Promise<void>
// `onResponseError` will be invoked when an error response is about to be sent by the server.
// you use this function to map custom errors to tus errors or for custom observability.
onResponseError?: (
req: http.IncomingMessage,
res: http.ServerResponse,
err: Error | {status_code: number; body: string}
) =>
| Promise<{status_code: number; body: string} | void>
| {status_code: number; body: string}
| void
}

export type RouteHandler = (req: http.IncomingMessage, res: http.ServerResponse) => void
30 changes: 27 additions & 3 deletions packages/server/test/Server.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -172,14 +172,12 @@ describe('Server', () => {
})

describe('handle', () => {
let server: InstanceType<typeof Server<{id: string}>>
let server: InstanceType<typeof Server>
let listener: http.Server

before(() => {
server = new Server({
path: '/test/output',
createContext: () => ({id: '1234'}),
namingFunction: (_, context) => context.id,
datastore: new FileStore({directory: './test/output'}),
})
listener = server.listen()
Expand Down Expand Up @@ -551,5 +549,31 @@ describe('Server', () => {
})
})
})

it('should fire onResponseError hook when an error is thrown', async () => {
const spy = sinon.spy()
const server = new Server({
path: '/test/output',
datastore: new FileStore({directory: './test/output'}),
onResponseError: () => {
spy()
return {status_code: 404, body: 'custom-error'}
},
onUploadFinish() {
throw {body: 'no', status_code: 500}
},
})

await request(server.listen())
.post(server.options.path)
.set('Tus-Resumable', TUS_RESUMABLE)
.set('Upload-Length', '4')
.set('Upload-Offset', '0')
.set('Content-Type', 'application/offset+octet-stream')
.send('test')
.expect(404, 'custom-error')

assert.equal(spy.calledOnce, true)
})
})
})

0 comments on commit 965484d

Please sign in to comment.