Skip to content

Commit

Permalink
refactor: rewrite of multipart file handling
Browse files Browse the repository at this point in the history
Now one can selectively stream files and still make bodyparser validate
the files for them.
  • Loading branch information
thetutlage committed Jul 31, 2019
1 parent d23e117 commit 0e88ef5
Show file tree
Hide file tree
Showing 37 changed files with 1,542 additions and 838 deletions.
78 changes: 43 additions & 35 deletions adonis-typings/bodyparser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ declare module '@ioc:Adonis/Addons/BodyParser' {
import { FileTypeResult } from 'file-type'

/**
* Readable stream along with some extra
* data
* Readable stream along with some extra data. This is what
* is passed to `onFile` handlers.
*/
export type MultipartStream = Readable & {
headers: any,
Expand All @@ -23,7 +23,8 @@ declare module '@ioc:Adonis/Addons/BodyParser' {
}

/**
* File validation options
* The options that can be used to validate a given
* file
*/
export type FileValidationOptions = {
size: string | number,
Expand All @@ -32,14 +33,12 @@ declare module '@ioc:Adonis/Addons/BodyParser' {
}

/**
* Stream part handler
* The callback handler for a given file part
*/
export type PartHandler = (part: MultipartStream) => Promise<void>

/**
* Field handler
*/
export type FieldHandler = (key: string, value: string) => void
export type PartHandlerContract = (
part: MultipartStream,
reportChunk: (chunk: Buffer) => void,
) => Promise<({ filePath?: string, tmpPath?: string } & { [key: string]: any }) | void>

/**
* Qs module config
Expand Down Expand Up @@ -72,28 +71,28 @@ declare module '@ioc:Adonis/Addons/BodyParser' {
/**
* Body parser config for parsing JSON requests
*/
type BodyParserJSONConfig = BodyParserBaseConfig & {
export type BodyParserJSONConfigContract = BodyParserBaseConfig & {
strict: boolean,
}

/**
* Parser config for parsing form data
*/
type BodyParserFormConfig = BodyParserBaseConfig & {
export type BodyParserFormConfigContract = BodyParserBaseConfig & {
queryString: QueryStringConfig,
}

/**
* Parser config for parsing raw body (untouched)
*/
type BodyParserRawConfig = BodyParserBaseConfig & {
export type BodyParserRawConfigContract = BodyParserBaseConfig & {
queryString: QueryStringConfig,
}

/**
* Parser config for parsing multipart requests
*/
type BodyParserMultipartConfig = BodyParserBaseConfig & {
export type BodyParserMultipartConfigContract = BodyParserBaseConfig & {
autoProcess: boolean,
maxFields: number,
processManually: string[],
Expand All @@ -103,24 +102,27 @@ declare module '@ioc:Adonis/Addons/BodyParser' {
/**
* Body parser config for all different types
*/
export type BodyParserConfig = {
export type BodyParserConfigContract = {
whitelistedMethods: string[],
json: BodyParserJSONConfig,
form: BodyParserFormConfig,
raw: BodyParserRawConfig,
multipart: BodyParserMultipartConfig,
json: BodyParserJSONConfigContract,
form: BodyParserFormConfigContract,
raw: BodyParserRawConfigContract,
multipart: BodyParserMultipartConfigContract,
}

/**
* Multipart class contract, since it's exposed on the
* Multipart class contract, since it is exposed on the
* request object, we need the interface to extend
* typings
*/
export interface MultipartContract {
consumed: boolean,
onFile (name: string, callback: PartHandler): this,
onField (key: string, value: any): this,
process (): Promise<void>,
onFile (
name: string,
options: Partial<FileValidationOptions & { deferValidations: boolean }>,
callback: PartHandlerContract,
): this,
process (config?: Partial<{ limit: string | number, maxFields: number }>): Promise<void>,
}

/**
Expand All @@ -130,38 +132,44 @@ declare module '@ioc:Adonis/Addons/BodyParser' {
fieldName: string,
clientName: string,
message: string,
type: 'size' | 'extname',
type: 'size' | 'extname' | 'fatal',
}

/**
* New file constructor options shape
*/
export type FileInputNode = {
fieldName: string,
fileName: string,
tmpPath: string,
clientName: string,
bytes: number,
headers: {
[key: string]: string,
},
fileType?: FileTypeResult,
filePath?: string,
tmpPath?: string,
meta: any,
fileType: {
ext: string,
type: string,
subtype: string,
},
}

/**
* Multipart file interface, used to loose coupling
* Multipart file interface
*/
export interface MultipartFileContract {
isValid: boolean,
clientName: string,
fileName?: string,
fieldName: string,
tmpPath: string,
clientName: string,
tmpPath?: string,
filePath?: string,
size: number,
type?: string,
subtype?: string,
type: string,
subtype: string,
isValid: boolean,
status: 'pending' | 'moved' | 'error',
extname: string,
setValidationOptions (options: Partial<FileValidationOptions>): this,
validated: boolean,
errors: FileUploadError[],
}
}
12 changes: 11 additions & 1 deletion adonis-typings/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,19 @@ import {
MultipartContract,
} from '@ioc:Adonis/Addons/BodyParser'

/**
* Extending the `request` interface on the core module
*/
declare module '@ioc:Adonis/Core/Request' {
interface RequestContract {
file (key: string, options?: Partial<FileValidationOptions>): MultipartFileContract,
file (
key: string,
options?: Partial<FileValidationOptions>,
): MultipartFileContract | null,
files (
key: string,
options?: Partial<FileValidationOptions>,
): MultipartFileContract[],
multipart: MultipartContract,
}
}
4 changes: 2 additions & 2 deletions config/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@
*/

import * as uuid from 'uuid/v1'
import { BodyParserConfig } from '@ioc:Adonis/Addons/BodyParser'
import { BodyParserConfigContract } from '@ioc:Adonis/Addons/BodyParser'

/**
* Default config to be used. It will be deep merged
* with the user config
*/
export const config: BodyParserConfig = {
export const config: BodyParserConfigContract = {
/*
|--------------------------------------------------------------------------
| White listed methods
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,17 @@

* **BodyParserProvider**

### Index
## Index

#### Constructors
### Constructors

* [constructor](_providers_bodyparserprovider_.bodyparserprovider.md#constructor)

#### Properties
### Properties

* [$container](_providers_bodyparserprovider_.bodyparserprovider.md#protected-$container)

#### Methods
### Methods

* [boot](_providers_bodyparserprovider_.bodyparserprovider.md#boot)
* [register](_providers_bodyparserprovider_.bodyparserprovider.md#register)
Expand Down
10 changes: 5 additions & 5 deletions docs/classes/_src_bodyparser_index_.bodyparsermiddleware.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,27 +11,27 @@ request body to be read later in the request lifecycle.

* **BodyParserMiddleware**

### Index
## Index

#### Constructors
### Constructors

* [constructor](_src_bodyparser_index_.bodyparsermiddleware.md#constructor)

#### Methods
### Methods

* [handle](_src_bodyparser_index_.bodyparsermiddleware.md#handle)

## Constructors

### constructor

\+ **new BodyParserMiddleware**(`_config`: `BodyParserConfig`): *[BodyParserMiddleware](_src_bodyparser_index_.bodyparsermiddleware.md)*
\+ **new BodyParserMiddleware**(`_config`: `BodyParserConfigContract`): *[BodyParserMiddleware](_src_bodyparser_index_.bodyparsermiddleware.md)*

**Parameters:**

Name | Type |
------ | ------ |
`_config` | `BodyParserConfig` |
`_config` | `BodyParserConfigContract` |

**Returns:** *[BodyParserMiddleware](_src_bodyparser_index_.bodyparsermiddleware.md)*

Expand Down
4 changes: 2 additions & 2 deletions docs/classes/_src_formfields_index_.formfields.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ array gracefully

* **FormFields**

### Index
## Index

#### Methods
### Methods

* [add](_src_formfields_index_.formfields.md#add)
* [get](_src_formfields_index_.formfields.md#get)
Expand Down
Loading

0 comments on commit 0e88ef5

Please sign in to comment.