multipart/server/
mod.rs

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
14pub extern crate buf_redux;
15extern crate httparse;
16extern crate twoway;
17
18use std::borrow::Borrow;
19use std::io::prelude::*;
20use std::io;
21
22use self::boundary::BoundaryReader;
23
24use self::field::PrivReadEntry;
25
26pub use self::field::{FieldHeaders, MultipartField, MultipartData, ReadEntry, ReadEntryResult};
27
28use self::save::SaveBuilder;
29
30pub use self::save::{Entries, SaveResult, SavedField};
31
32macro_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
50macro_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
59mod boundary;
60mod field;
61
62#[cfg(feature = "hyper")]
63pub mod hyper;
64
65#[cfg(feature = "iron")]
66pub mod iron;
67
68#[cfg(feature = "tiny_http")]
69pub mod tiny_http;
70
71#[cfg(feature = "nickel")]
72pub mod nickel;
73
74pub 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.
79pub struct Multipart<R> {
80    reader: BoundaryReader<R>,
81}
82
83impl 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.
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
98impl<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
108    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.
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.
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.
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.
153    pub fn save(&mut self) -> SaveBuilder<&mut Self> {
154        SaveBuilder::new(self)
155    }
156}
157
158impl<R> Borrow<R> for Multipart<R> {
159    fn borrow(&self) -> &R {
160        self.reader.borrow()
161    }
162}
163
164impl<R: Read> PrivReadEntry for Multipart<R> {
165    type Source = BoundaryReader<R>;
166
167    fn source_mut(&mut self) -> &mut BoundaryReader<R> {
168        &mut self.reader
169    }
170
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.
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.
187pub 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}`.
195    fn multipart_boundary(&self) -> Option<&str>;
196
197    /// Return the request body for reading.
198    fn body(self) -> Self::Body;
199}
200
201#[test]
202fn 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]
223fn 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}