2
2
3
3
const Dicer = require ( 'dicer' )
4
4
const Content = require ( '@hapi/content' )
5
- const stream = require ( 'stream' )
6
- const util = require ( 'util' )
7
- const Transform = stream . Transform
5
+ const {
6
+ EventIterator
7
+ } = require ( 'event-iterator' )
8
8
9
9
const multipartFormdataType = 'multipart/form-data'
10
10
const applicationDirectory = 'application/x-directory'
11
11
const applicationSymlink = 'application/symlink'
12
12
13
+ function subscribe ( emitter , dataEvent = 'data' , endEvent = 'end' , evOptions = { } ) {
14
+ return new EventIterator ( ( push , stop , fail ) => {
15
+ emitter . addListener ( dataEvent , push )
16
+ emitter . addListener ( endEvent , stop )
17
+ emitter . addListener ( 'error' , fail )
18
+ } , ( push , stop , fail ) => {
19
+ emitter . removeListener ( dataEvent , push )
20
+ emitter . removeListener ( endEvent , stop )
21
+ emitter . removeListener ( 'error' , fail )
22
+
23
+ if ( emitter . destroy ) {
24
+ emitter . destroy ( )
25
+ } else if ( typeof emitter . close === 'function' ) {
26
+ emitter . close ( )
27
+ }
28
+ } , evOptions )
29
+ }
30
+
13
31
const isDirectory = ( mediatype ) => mediatype === multipartFormdataType || mediatype === applicationDirectory
14
32
15
33
const parseDisposition = ( disposition ) => {
@@ -29,75 +47,61 @@ const parseHeader = (header) => {
29
47
const disposition = parseDisposition ( header [ 'content-disposition' ] [ 0 ] )
30
48
31
49
const details = type
32
- details . name = disposition . name
50
+ details . name = decodeURIComponent ( disposition . name )
33
51
details . type = disposition . type
34
52
35
53
return details
36
54
}
37
55
38
- /**
39
- * Parser
40
- *
41
- * @constructor
42
- * @param {Object } options
43
- * @returns {Parser }
44
- */
45
- function Parser ( options ) {
46
- // allow use without new
47
- if ( ! ( this instanceof Parser ) ) {
48
- return new Parser ( options )
49
- }
50
-
51
- this . dicer = new Dicer ( { boundary : options . boundary } )
52
-
53
- this . dicer . on ( 'part' , ( part ) => this . handlePart ( part ) )
54
-
55
- this . dicer . on ( 'error' , ( err ) => this . emit ( 'err' , err ) )
56
-
57
- this . dicer . on ( 'finish' , ( ) => {
58
- this . emit ( 'finish' )
59
- this . emit ( 'end' )
60
- } )
61
-
62
- Transform . call ( this , options )
63
- }
64
- util . inherits ( Parser , Transform )
65
-
66
- Parser . prototype . _transform = function ( chunk , enc , cb ) {
67
- this . dicer . write ( chunk , enc )
68
- cb ( )
69
- }
70
-
71
- Parser . prototype . _flush = function ( cb ) {
72
- this . dicer . end ( )
73
- cb ( )
74
- }
75
-
76
- Parser . prototype . handlePart = function ( part ) {
77
- part . on ( 'header' , ( header ) => {
78
- const partHeader = parseHeader ( header )
79
-
80
- if ( isDirectory ( partHeader . mime ) ) {
81
- part . on ( 'data' , ( ) => false )
82
- this . emit ( 'directory' , partHeader . name )
83
- return
56
+ async function * parser ( boundary , stream ) {
57
+ const dicer = new Dicer ( { boundary } )
58
+ stream . pipe ( dicer )
59
+
60
+ for await ( const part of subscribe ( dicer , 'part' , 'finish' ) ) {
61
+ for await ( const header of subscribe ( part , 'header' ) ) {
62
+ const partHeader = parseHeader ( header )
63
+
64
+ if ( isDirectory ( partHeader . mime ) ) {
65
+ // consume data from stream so we move on to the next header/part
66
+ part . on ( 'data' , ( ) => { } )
67
+
68
+ yield {
69
+ type : 'directory' ,
70
+ name : partHeader . name
71
+ }
72
+
73
+ continue
74
+ }
75
+
76
+ if ( partHeader . mime === applicationSymlink ) {
77
+ // consume data from stream so we move on to the next header/part
78
+ part . on ( 'data' , ( ) => { } )
79
+
80
+ yield {
81
+ type : 'symlink' ,
82
+ name : partHeader . name ,
83
+ target : partHeader . target
84
+ }
85
+
86
+ continue
87
+ }
88
+
89
+ if ( partHeader . boundary ) {
90
+ // recursively parse nested multiparts
91
+ for await ( const entry of parser ( partHeader . boundary , part ) ) {
92
+ yield entry
93
+ }
94
+
95
+ continue
96
+ }
97
+
98
+ yield {
99
+ type : 'file' ,
100
+ name : partHeader . name ,
101
+ content : subscribe ( part )
102
+ }
84
103
}
85
-
86
- if ( partHeader . mime === applicationSymlink ) {
87
- part . on ( 'data' , ( target ) => this . emit ( 'symlink' , partHeader . name , target . toString ( ) ) )
88
- return
89
- }
90
-
91
- if ( partHeader . boundary ) {
92
- // recursively parse nested multiparts
93
- const parser = new Parser ( { boundary : partHeader . boundary } )
94
- parser . on ( 'file' , ( file ) => this . emit ( 'file' , file ) )
95
- part . pipe ( parser )
96
- return
97
- }
98
-
99
- this . emit ( 'file' , partHeader . name , part )
100
- } )
104
+ }
101
105
}
102
106
103
- module . exports = Parser
107
+ module . exports = parser
0 commit comments