2
2
//!
3
3
//! Filters that extract a multipart body for a route.
4
4
5
- use std:: fmt;
6
5
use std:: future:: Future ;
7
- use std:: io:: { Cursor , Read } ;
8
6
use std:: pin:: Pin ;
9
7
use std:: task:: { Context , Poll } ;
8
+ use std:: { fmt, io} ;
10
9
11
10
use bytes:: { Buf , Bytes } ;
12
11
use futures_util:: { future, Stream } ;
13
12
use headers:: ContentType ;
13
+ use hyper:: Body ;
14
14
use mime:: Mime ;
15
- use multipart:: server:: Multipart ;
15
+ use multiparty:: headers:: Headers ;
16
+ use multiparty:: server:: owned_futures03:: { FormData as FormDataInner , Part as PartInner } ;
16
17
17
18
use crate :: filter:: { Filter , FilterBase , Internal } ;
18
19
use crate :: reject:: { self , Rejection } ;
@@ -32,17 +33,15 @@ pub struct FormOptions {
32
33
///
33
34
/// Extracted with a `warp::multipart::form` filter.
34
35
pub struct FormData {
35
- inner : Multipart < Cursor < :: bytes :: Bytes > > ,
36
+ inner : FormDataInner < BodyIoError > ,
36
37
}
37
38
38
39
/// A single "part" of a multipart/form-data body.
39
40
///
40
41
/// Yielded from the `FormData` stream.
41
42
pub struct Part {
42
- name : String ,
43
- filename : Option < String > ,
44
- content_type : Option < String > ,
45
- data : Option < Vec < u8 > > ,
43
+ headers : Headers ,
44
+ part : PartInner < BodyIoError > ,
46
45
}
47
46
48
47
/// Create a `Filter` to extract a `multipart/form-data` body from a request.
@@ -86,9 +85,12 @@ impl FilterBase for FormOptions {
86
85
87
86
let filt = super :: body:: content_length_limit ( self . max_length )
88
87
. and ( boundary)
89
- . and ( super :: body:: bytes ( ) )
90
- . map ( |boundary, body| FormData {
91
- inner : Multipart :: with_body ( Cursor :: new ( body) , boundary) ,
88
+ . and ( super :: body:: body ( ) )
89
+ . map ( |boundary : String , body| {
90
+ let body = BodyIoError ( body) ;
91
+ FormData {
92
+ inner : FormDataInner :: new ( body, & boundary) ,
93
+ }
92
94
} ) ;
93
95
94
96
let fut = filt. filter ( Internal ) ;
@@ -108,23 +110,18 @@ impl fmt::Debug for FormData {
108
110
impl Stream for FormData {
109
111
type Item = Result < Part , crate :: Error > ;
110
112
111
- fn poll_next ( mut self : Pin < & mut Self > , _cx : & mut Context < ' _ > ) -> Poll < Option < Self :: Item > > {
112
- match ( * self ) . inner . read_entry ( ) {
113
- Ok ( Some ( mut field) ) => {
114
- let mut data = Vec :: new ( ) ;
115
- field
116
- . data
117
- . read_to_end ( & mut data)
118
- . map_err ( crate :: Error :: new) ?;
119
- Poll :: Ready ( Some ( Ok ( Part {
120
- name : field. headers . name . to_string ( ) ,
121
- filename : field. headers . filename ,
122
- content_type : field. headers . content_type . map ( |m| m. to_string ( ) ) ,
123
- data : Some ( data) ,
124
- } ) ) )
113
+ fn poll_next ( mut self : Pin < & mut Self > , cx : & mut Context < ' _ > ) -> Poll < Option < Self :: Item > > {
114
+ match Pin :: new ( & mut self . inner ) . poll_next ( cx) {
115
+ Poll :: Pending => Poll :: Pending ,
116
+ Poll :: Ready ( Some ( Ok ( part) ) ) => {
117
+ let headers = match part. raw_headers ( ) . parse ( ) {
118
+ Ok ( headers) => headers,
119
+ Err ( err) => return Poll :: Ready ( Some ( Err ( crate :: Error :: new ( err) ) ) ) ,
120
+ } ;
121
+ Poll :: Ready ( Some ( Ok ( Part { part, headers } ) ) )
125
122
}
126
- Ok ( None ) => Poll :: Ready ( None ) ,
127
- Err ( e ) => Poll :: Ready ( Some ( Err ( crate :: Error :: new ( e ) ) ) ) ,
123
+ Poll :: Ready ( None ) => Poll :: Ready ( None ) ,
124
+ Poll :: Ready ( Some ( Err ( err ) ) ) => Poll :: Ready ( Some ( Err ( crate :: Error :: new ( err ) ) ) ) ,
128
125
}
129
126
}
130
127
}
@@ -134,44 +131,49 @@ impl Stream for FormData {
134
131
impl Part {
135
132
/// Get the name of this part.
136
133
pub fn name ( & self ) -> & str {
137
- & self . name
134
+ & self . headers . name
138
135
}
139
136
140
137
/// Get the filename of this part, if present.
141
138
pub fn filename ( & self ) -> Option < & str > {
142
- self . filename . as_deref ( )
139
+ self . headers . filename . as_deref ( )
143
140
}
144
141
145
142
/// Get the content-type of this part, if present.
146
143
pub fn content_type ( & self ) -> Option < & str > {
147
- self . content_type . as_deref ( )
144
+ self . headers . content_type . as_deref ( )
148
145
}
149
146
150
147
/// Asynchronously get some of the data for this `Part`.
151
148
pub async fn data ( & mut self ) -> Option < Result < impl Buf , crate :: Error > > {
152
- self . take_data ( )
149
+ future :: poll_fn ( |cx| self . poll_next ( cx ) ) . await
153
150
}
154
151
155
152
/// Convert this `Part` into a `Stream` of `Buf`s.
156
153
pub fn stream ( self ) -> impl Stream < Item = Result < impl Buf , crate :: Error > > {
157
154
PartStream ( self )
158
155
}
159
156
160
- fn take_data ( & mut self ) -> Option < Result < Bytes , crate :: Error > > {
161
- self . data . take ( ) . map ( |vec| Ok ( vec. into ( ) ) )
157
+ fn poll_next ( & mut self , cx : & mut Context < ' _ > ) -> Poll < Option < Result < Bytes , crate :: Error > > > {
158
+ match Pin :: new ( & mut self . part ) . poll_next ( cx) {
159
+ Poll :: Pending => Poll :: Pending ,
160
+ Poll :: Ready ( Some ( Ok ( bytes) ) ) => Poll :: Ready ( Some ( Ok ( bytes) ) ) ,
161
+ Poll :: Ready ( None ) => Poll :: Ready ( None ) ,
162
+ Poll :: Ready ( Some ( Err ( err) ) ) => Poll :: Ready ( Some ( Err ( crate :: Error :: new ( err) ) ) ) ,
163
+ }
162
164
}
163
165
}
164
166
165
167
impl fmt:: Debug for Part {
166
168
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
167
169
let mut builder = f. debug_struct ( "Part" ) ;
168
- builder. field ( "name" , & self . name ) ;
170
+ builder. field ( "name" , & self . headers . name ) ;
169
171
170
- if let Some ( ref filename) = self . filename {
172
+ if let Some ( ref filename) = self . headers . filename {
171
173
builder. field ( "filename" , filename) ;
172
174
}
173
175
174
- if let Some ( ref mime) = self . content_type {
176
+ if let Some ( ref mime) = self . headers . content_type {
175
177
builder. field ( "content_type" , mime) ;
176
178
}
177
179
@@ -184,7 +186,24 @@ struct PartStream(Part);
184
186
impl Stream for PartStream {
185
187
type Item = Result < Bytes , crate :: Error > ;
186
188
187
- fn poll_next ( mut self : Pin < & mut Self > , _cx : & mut Context < ' _ > ) -> Poll < Option < Self :: Item > > {
188
- Poll :: Ready ( self . 0 . take_data ( ) )
189
+ fn poll_next ( mut self : Pin < & mut Self > , cx : & mut Context < ' _ > ) -> Poll < Option < Self :: Item > > {
190
+ self . 0 . poll_next ( cx)
191
+ }
192
+ }
193
+
194
+ struct BodyIoError ( Body ) ;
195
+
196
+ impl Stream for BodyIoError {
197
+ type Item = io:: Result < Bytes > ;
198
+
199
+ fn poll_next ( mut self : Pin < & mut Self > , cx : & mut Context < ' _ > ) -> Poll < Option < Self :: Item > > {
200
+ match Pin :: new ( & mut self . 0 ) . poll_next ( cx) {
201
+ Poll :: Pending => Poll :: Pending ,
202
+ Poll :: Ready ( Some ( Ok ( bytes) ) ) => Poll :: Ready ( Some ( Ok ( bytes) ) ) ,
203
+ Poll :: Ready ( None ) => Poll :: Ready ( None ) ,
204
+ Poll :: Ready ( Some ( Err ( err) ) ) => {
205
+ Poll :: Ready ( Some ( Err ( io:: Error :: new ( io:: ErrorKind :: Other , err) ) ) )
206
+ }
207
+ }
189
208
}
190
209
}
0 commit comments