1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
// Copyright 2016 `multipart` Crate Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
//! Client-side integration with [Hyper](https://github.com/hyperium/hyper). 
//! Enabled with the `hyper` feature (on by default).
//!
//! Contains `impl HttpRequest for Request<Fresh>` and `impl HttpStream for Request<Streaming>`.
//!
//! Also see: [`lazy::Multipart::client_request()`](../lazy/struct.Multipart.html#method.client_request)
//! and [`lazy::Multipart::client_request_mut()`](../lazy/struct.Multipart.html#method.client_request_mut)
//! (adaptors for `hyper::client::RequestBuilder`).
use hyper::client::request::Request;
use hyper::client::response::Response;
use hyper::header::{ContentType, ContentLength};
use hyper::method::Method;
use hyper::net::{Fresh, Streaming};

use hyper::Error as HyperError;

use mime::{Mime, TopLevel, SubLevel, Attr, Value};

use super::{HttpRequest, HttpStream};

/// ####Feature: `hyper`
impl HttpRequest for Request<Fresh> {
    type Stream = Request<Streaming>;
    type Error = HyperError;

    /// #Panics
    /// If `self.method() != Method::Post`.
    fn apply_headers(&mut self, boundary: &str, content_len: Option<u64>) -> bool {
        if self.method() != Method::Post {
            error!(
                "Expected Hyper request method to be `Post`, was actually `{:?}`",
                self.method()
            );

            return false;
        }

        let headers = self.headers_mut();

        headers.set(ContentType(multipart_mime(boundary)));

        if let Some(size) = content_len {
            headers.set(ContentLength(size));   
        }

        debug!("Hyper headers: {}", headers); 

        true
    }

    fn open_stream(self) -> Result<Self::Stream, Self::Error> {
        self.start()
    }
} 

/// ####Feature: `hyper`
impl HttpStream for Request<Streaming> {
    type Request = Request<Fresh>;
    type Response = Response;
    type Error = HyperError;

    fn finish(self) -> Result<Self::Response, Self::Error> {
        self.send()
    }
}

/// Create a `Content-Type: multipart/form-data;boundary={bound}`
pub fn content_type(bound: &str) -> ContentType {
    ContentType(multipart_mime(bound))
}

fn multipart_mime(bound: &str) -> Mime {
    Mime(
        TopLevel::Multipart, SubLevel::Ext("form-data".into()),
        vec![(Attr::Ext("boundary".into()), Value::Ext(bound.into()))]
    )         
}