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
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
//! ureq is a minimal request library.
//!
//! The goals of this library are:
//!
//! * Minimal dependency tree
//! * Obvious API
//!
//! ```
//! // requires feature: `ureq = { version = "*", features = ["json"] }`
//! #[macro_use]
//! extern crate ureq;
//!
//! fn main() {
//!     // sync post request of some json.
//!     let resp = ureq::post("https://myapi.acme.com/ingest")
//!         .set("X-My-Header", "Secret")
//!         .send_json(json!({
//!             "name": "martin",
//!             "rust": true
//!         }));
//!
//!     // .ok() tells if response is 200-299.
//!     if resp.ok() {
//!       // ....
//!     }
//! }
//! ```
//!
//! # Plain requests
//!
//! Most standard methods (GET, POST, PUT etc), are supported as functions from the
//! top of the library ([`ureq::get`](fn.get.html), [`ureq::post`](fn.post.html),
//! [`ureq::put`](fn.put.html), etc).
//!
//! These top level http method functions create a [Request](struct.Request.html) instance
//! which follows a build pattern. The builders are finished using:
//!
//! * [`.call()`](struct.Request.html#method.call) without a request body.
//! * [`.send()`](struct.Request.html#method.send) with a request body as `Read`.
//! * [`.send_string()`](struct.Request.html#method.send_string) body as string.
//!
//! # JSON
//!
//! By enabling the `ureq = { version = "*", features = ["json"] }` feature,
//! the library supports serde json.
//!
//! * [`request.send_json()`](struct.Request.html#method.send_json) send body as serde json.
//! * [`response.into_json()`](struct.Response.html#method.into_json) transform response to json.
//!
//! # Agents
//!
//! To maintain a state, cookies, between requests, you use an [agent](struct.Agent.html).
//! Agents also follow the build pattern. Agents are created with
//! [`ureq::agent()`](struct.Agent.html).
//!
//! # Content-Length
//!
//! The library will set the content length on the request when using
//! [`.send_string()`](struct.Request.html#method.send_string) or
//! [`.send_json()`](struct.Request.html#method.send_json). In other cases the user
//! can optionally `request.set("Content-Length", 1234)`.
//!
//! For responses, if the `Content-Length` header is present, the methods that reads the
//! body (as string, json or read trait) are all limited to the length specified in the header.
//!
//! # Transfer-Encoding: chunked
//!
//! Dechunking is a response body is done automatically if the response headers contains
//! a `Transfer-Encoding` header.
//!
//! Sending a chunked request body is done by setting the header prior to sending a body.
//!
//! ```
//! let resp = ureq::post("http://my-server.com/ingest")
//!     .set("Transfer-Encoding", "chunked")
//!     .send_string("Hello world");
//! ```
//!
//! # Character encoding
//!
//! By enabling the `ureq = { version = "*", features = ["charset"] }` feature,
//! the library supports sending/receiving other character sets than `utf-8`.
//!
//! For [`response.into_string()`](struct.Response.html#method.into_string) we read the
//! header `Content-Type: text/plain; charset=iso-8859-1` and if it contains a charset
//! specification, we try to decode the body using that encoding. In the absence of, or failing
//! to interpret the charset, we fall back on `utf-8`.
//!
//! Similarly when using [`request.send_string()`](struct.Request.html#method.send_string),
//! we first check if the user has set a `; charset=<whatwg charset>` and attempt
//! to encode the request body using that.
//!
extern crate ascii;
extern crate base64;
extern crate chunked_transfer;
extern crate cookie;
#[macro_use]
extern crate lazy_static;
extern crate qstring;
extern crate url;

#[cfg(feature = "charset")]
extern crate encoding;
#[cfg(feature = "tls")]
extern crate native_tls;
#[cfg(feature = "json")]
extern crate serde_json;

mod agent;
mod body;
mod error;
mod header;
mod macros;
mod pool;
mod response;
mod stream;

#[cfg(feature = "json")]
mod serde_macros;

#[cfg(test)]
mod test;

pub use agent::{Agent, Request};
pub use error::Error;
pub use header::Header;
pub use response::Response;

// re-export
pub use cookie::Cookie;
#[cfg(feature = "json")]
pub use serde_json::{to_value as serde_to_value, Map as SerdeMap, Value as SerdeValue};

/// Agents are used to keep state between requests.
pub fn agent() -> Agent {
    Agent::new().build()
}

/// Make a request setting the HTTP method via a string.
///
/// ```
/// ureq::request("GET", "https://www.google.com").call();
/// ```
pub fn request<M, S>(method: M, path: S) -> Request
where
    M: Into<String>,
    S: Into<String>,
{
    Agent::new().request(method, path)
}

/// Make a GET request.
pub fn get<S>(path: S) -> Request
where
    S: Into<String>,
{
    request("GET", path)
}

/// Make a HEAD request.
pub fn head<S>(path: S) -> Request
where
    S: Into<String>,
{
    request("HEAD", path)
}

/// Make a POST request.
pub fn post<S>(path: S) -> Request
where
    S: Into<String>,
{
    request("POST", path)
}

/// Make a PUT request.
pub fn put<S>(path: S) -> Request
where
    S: Into<String>,
{
    request("PUT", path)
}

/// Make a DELETE request.
pub fn delete<S>(path: S) -> Request
where
    S: Into<String>,
{
    request("DELETE", path)
}

/// Make a TRACE request.
pub fn trace<S>(path: S) -> Request
where
    S: Into<String>,
{
    request("TRACE", path)
}

/// Make an OPTIONS request.
pub fn options<S>(path: S) -> Request
where
    S: Into<String>,
{
    request("OPTIONS", path)
}

/// Make an CONNECT request.
pub fn connect<S>(path: S) -> Request
where
    S: Into<String>,
{
    request("CONNECT", path)
}

/// Make an PATCH request.
pub fn patch<S>(path: S) -> Request
where
    S: Into<String>,
{
    request("PATCH", path)
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn connect_http_google() {
        let resp = get("http://www.google.com/").call();
        assert_eq!(
            "text/html; charset=ISO-8859-1",
            resp.header("content-type").unwrap()
        );
        assert_eq!("text/html", resp.content_type());
    }

    #[test]
    #[cfg(feature = "tls")]
    fn connect_https_google() {
        let resp = get("https://www.google.com/").call();
        assert_eq!(
            "text/html; charset=ISO-8859-1",
            resp.header("content-type").unwrap()
        );
        assert_eq!("text/html", resp.content_type());
    }
}