1 // Copyright 2016 `multipart` Crate Developers
2 //
3 // Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
4 // http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
5 // http://opensource.org/licenses/MIT>, at your option. This file may not be
6 // copied, modified, or distributed except according to those terms.
7 //! The server-side abstraction for multipart requests. Enabled with the `server` feature.
8 //!
9 //! Use this when you are implementing an HTTP server and want to
10 //! to accept, parse, and serve HTTP `multipart/form-data` requests (file uploads).
11 //!
12 //! See the `Multipart` struct for more info.
13
14 pub extern crate buf_redux;
15 extern crate httparse;
16 extern crate twoway;
17
18 use std::borrow::Borrow;
19 use std::io::prelude::*;
20 use std::io;
21
22 use self::boundary::BoundaryReader;
23
24 use self::field::PrivReadEntry;
25
26 pub use self::field::{FieldHeaders, MultipartField, MultipartData, ReadEntry, ReadEntryResult};
27
28 use self::save::SaveBuilder;
29
30 pub use self::save::{Entries, SaveResult, SavedField};
31
32 macro_rules! try_opt (
33 ($expr:expr) => (
34 match $expr {
35 Some(val) => val,
36 None => return None,
37 }
38 );
39 ($expr:expr, $before_ret:expr) => (
40 match $expr {
41 Some(val) => val,
42 None => {
43 $before_ret;
44 return None;
45 }
46 }
47 )
48 );
49
50 macro_rules! try_read_entry {
51 ($self_:expr; $try:expr) => (
52 match $try {
53 Ok(res) => res,
54 Err(err) => return ::server::ReadEntryResult::Error($self_, err),
55 }
56 )
57 }
58
59 mod boundary;
60 mod field;
61
62 #[cfg(feature = "hyper")]
63 pub mod hyper;
64
65 #[cfg(feature = "iron")]
66 pub mod iron;
67
68 #[cfg(feature = "tiny_http")]
69 pub mod tiny_http;
70
71 #[cfg(feature = "nickel")]
72 pub mod nickel;
73
74 pub mod save;
75
76 /// The server-side implementation of `multipart/form-data` requests.
77 ///
78 /// Implements `Borrow<R>` to allow access to the request body, if desired.
79 pub struct Multipart<R> {
80 reader: BoundaryReader<R>,
81 }
82
83 impl Multipart<()> {
84 /// If the given `HttpRequest` is a multipart/form-data POST request,
85 /// return the request body wrapped in the multipart reader. Otherwise,
86 /// returns the original request.
from_request<R: HttpRequest>(req: R) -> Result<Multipart<R::Body>, R>87 pub fn from_request<R: HttpRequest>(req: R) -> Result<Multipart<R::Body>, R> {
88 //FIXME: move `map` expr to `Some` arm when nonlexical borrow scopes land.
89 let boundary = match req.multipart_boundary().map(String::from) {
90 Some(boundary) => boundary,
91 None => return Err(req),
92 };
93
94 Ok(Multipart::with_body(req.body(), boundary))
95 }
96 }
97
98 impl<R: Read> Multipart<R> {
99 /// Construct a new `Multipart` with the given body reader and boundary.
100 ///
101 /// ## Note: `boundary`
102 /// This will prepend the requisite `--` to the boundary string as documented in
103 /// [IETF RFC 1341, Section 7.2.1: "Multipart: the common syntax"][rfc1341-7.2.1].
104 /// Simply pass the value of the `boundary` key from the `Content-Type` header in the
105 /// request (or use `Multipart::from_request()`, if supported).
106 ///
107 /// [rfc1341-7.2.1]: https://tools.ietf.org/html/rfc1341#page-30
with_body<Bnd: Into<String>>(body: R, boundary: Bnd) -> Self108 pub fn with_body<Bnd: Into<String>>(body: R, boundary: Bnd) -> Self {
109 let boundary = boundary.into();
110
111 info!("Multipart::with_boundary(_, {:?})", boundary);
112
113 Multipart {
114 reader: BoundaryReader::from_reader(body, boundary),
115 }
116 }
117
118 /// Read the next entry from this multipart request, returning a struct with the field's name and
119 /// data. See `MultipartField` for more info.
120 ///
121 /// ## Warning: Risk of Data Loss
122 /// If the previously returned entry had contents of type `MultipartField::File`,
123 /// calling this again will discard any unread contents of that entry.
read_entry(&mut self) -> io::Result<Option<MultipartField<&mut Self>>>124 pub fn read_entry(&mut self) -> io::Result<Option<MultipartField<&mut Self>>> {
125 self.read_entry_mut().into_result()
126 }
127
128 /// Read the next entry from this multipart request, returning a struct with the field's name and
129 /// data. See `MultipartField` for more info.
into_entry(self) -> ReadEntryResult<Self>130 pub fn into_entry(self) -> ReadEntryResult<Self> {
131 self.read_entry()
132 }
133
134 /// Call `f` for each entry in the multipart request.
135 ///
136 /// This is a substitute for Rust not supporting streaming iterators (where the return value
137 /// from `next()` borrows the iterator for a bound lifetime).
138 ///
139 /// Returns `Ok(())` when all fields have been read, or the first error.
foreach_entry<F>(&mut self, mut foreach: F) -> io::Result<()> where F: FnMut(MultipartField<&mut Self>)140 pub fn foreach_entry<F>(&mut self, mut foreach: F) -> io::Result<()> where F: FnMut(MultipartField<&mut Self>) {
141 loop {
142 match self.read_entry() {
143 Ok(Some(field)) => foreach(field),
144 Ok(None) => return Ok(()),
145 Err(err) => return Err(err),
146 }
147 }
148 }
149
150 /// Get a builder type for saving the files in this request to the filesystem.
151 ///
152 /// See [`SaveBuilder`](save/struct.SaveBuilder.html) for more information.
save(&mut self) -> SaveBuilder<&mut Self>153 pub fn save(&mut self) -> SaveBuilder<&mut Self> {
154 SaveBuilder::new(self)
155 }
156 }
157
158 impl<R> Borrow<R> for Multipart<R> {
borrow(&self) -> &R159 fn borrow(&self) -> &R {
160 self.reader.borrow()
161 }
162 }
163
164 impl<R: Read> PrivReadEntry for Multipart<R> {
165 type Source = BoundaryReader<R>;
166
source_mut(&mut self) -> &mut BoundaryReader<R>167 fn source_mut(&mut self) -> &mut BoundaryReader<R> {
168 &mut self.reader
169 }
170
set_min_buf_size(&mut self, min_buf_size: usize)171 fn set_min_buf_size(&mut self, min_buf_size: usize) {
172 self.reader.set_min_buf_size(min_buf_size)
173 }
174
175 /// Consume the next boundary.
176 /// Returns `true` if a field should follow this boundary, `false` otherwise.
consume_boundary(&mut self) -> io::Result<bool>177 fn consume_boundary(&mut self) -> io::Result<bool> {
178 debug!("Consume boundary!");
179 self.reader.consume_boundary()
180 }
181 }
182
183 /// A server-side HTTP request that may or may not be multipart.
184 ///
185 /// May be implemented by mutable references if providing the request or body by-value is
186 /// undesirable.
187 pub trait HttpRequest {
188 /// The body of this request.
189 type Body: Read;
190 /// Get the boundary string of this request if it is a POST request
191 /// with the `Content-Type` header set to `multipart/form-data`.
192 ///
193 /// The boundary string should be supplied as an extra value of the `Content-Type` header, e.g.
194 /// `Content-Type: multipart/form-data; boundary={boundary}`.
multipart_boundary(&self) -> Option<&str>195 fn multipart_boundary(&self) -> Option<&str>;
196
197 /// Return the request body for reading.
body(self) -> Self::Body198 fn body(self) -> Self::Body;
199 }
200
201 #[test]
issue_104()202 fn issue_104() {
203 ::init_log();
204
205 use std::io::Cursor;
206
207 let body = "\
208 POST /test.html HTTP/1.1\r\n\
209 Host: example.org\r\n\
210 Content-Type: multipart/form-data;boundary=\"boundary\"\r\n\r\n\
211 Content-Disposition: form-data; name=\"field1\"\r\n\r\n\
212 value1\r\n\
213 Content-Disposition: form-data; name=\"field2\"; filename=\"example.txt\"\r\n\r\n\
214 value2 ";
215
216 let request = Cursor::new(body);
217
218 let mut multipart = Multipart::with_body(request, "boundary");
219 multipart.foreach_entry(|_field| {/* Do nothing */}).unwrap_err();
220 }
221
222 #[test]
issue_114()223 fn issue_114() {
224 ::init_log();
225
226 fn consume_all<R: BufRead>(mut rdr: R) {
227 loop {
228 let consume = rdr.fill_buf().unwrap().len();
229 if consume == 0 { return; }
230 rdr.consume(consume);
231 }
232 }
233
234 use std::io::Cursor;
235
236 let body = "\
237 --------------------------c616e5fded96a3c7\r\n\
238 Content-Disposition: form-data; name=\"key1\"\r\n\r\n\
239 v1,\r\n\
240 --------------------------c616e5fded96a3c7\r\n\
241 Content-Disposition: form-data; name=\"key2\"\r\n\r\n\
242 v2,\r\n\
243 --------------------------c616e5fded96a3c7\r\n\
244 Content-Disposition: form-data; name=\"key3\"\r\n\r\n\
245 v3\r\n\
246 --------------------------c616e5fded96a3c7--\r\n";
247
248 let request = Cursor::new(body);
249 let mut multipart = Multipart::with_body(request, "------------------------c616e5fded96a3c7");
250
251 // one error if you do nothing
252 multipart.foreach_entry(|_entry| { /* do nothing */}).unwrap();
253
254 // a different error if you skip the first field
255 multipart.foreach_entry(|entry| if *entry.headers.name != *"key1" { consume_all(entry.data); })
256 .unwrap();
257
258
259 multipart.foreach_entry(|_entry| () /* match entry.headers.name.as_str() {
260 "file" => {
261 let mut vec = Vec::new();
262 entry.data.read_to_end(&mut vec).expect("can't read");
263 // message.file = String::from_utf8(vec).ok();
264 println!("key file got");
265 }
266
267 "key1" => {
268 let mut vec = Vec::new();
269 entry.data.read_to_end(&mut vec).expect("can't read");
270 // message.key1 = String::from_utf8(vec).ok();
271 println!("key1 got");
272 }
273
274 "key2" => {
275 let mut vec = Vec::new();
276 entry.data.read_to_end(&mut vec).expect("can't read");
277 // message.key2 = String::from_utf8(vec).ok();
278 println!("key2 got");
279 }
280
281 _ => {
282 // as multipart has a bug https://github.com/abonander/multipart/issues/114
283 // we manually do read_to_end here
284 //let mut _vec = Vec::new();
285 //entry.data.read_to_end(&mut _vec).expect("can't read");
286 println!("key neglected");
287 }
288 }*/)
289 .expect("Unable to iterate multipart?")
290 }
291