Closes #1000 BREAKING CHANGE: The name of `RequestUri` has changed to `Uri`. It is no longer an `enum`, but an opaque struct with getter methods.
235 lines
6.9 KiB
Rust
235 lines
6.9 KiB
Rust
use std::fmt;
|
|
|
|
use Url;
|
|
|
|
use header::Headers;
|
|
use http::{Body, RequestHead};
|
|
use method::Method;
|
|
use uri::Uri;
|
|
use version::HttpVersion;
|
|
|
|
/// A client request to a remote server.
|
|
pub struct Request {
|
|
method: Method,
|
|
url: Url,
|
|
version: HttpVersion,
|
|
headers: Headers,
|
|
body: Option<Body>,
|
|
}
|
|
|
|
impl Request {
|
|
/// Construct a new Request.
|
|
#[inline]
|
|
pub fn new(method: Method, url: Url) -> Request {
|
|
Request {
|
|
method: method,
|
|
url: url,
|
|
version: HttpVersion::default(),
|
|
headers: Headers::new(),
|
|
body: None,
|
|
}
|
|
}
|
|
|
|
/// Read the Request Url.
|
|
#[inline]
|
|
pub fn url(&self) -> &Url { &self.url }
|
|
|
|
/// Readthe Request Version.
|
|
#[inline]
|
|
pub fn version(&self) -> &HttpVersion { &self.version }
|
|
|
|
/// Read the Request headers.
|
|
#[inline]
|
|
pub fn headers(&self) -> &Headers { &self.headers }
|
|
|
|
/// Read the Request method.
|
|
#[inline]
|
|
pub fn method(&self) -> &Method { &self.method }
|
|
|
|
/// Set the Method of this request.
|
|
#[inline]
|
|
pub fn set_method(&mut self, method: Method) { self.method = method; }
|
|
|
|
/// Get a mutable reference to the Request headers.
|
|
#[inline]
|
|
pub fn headers_mut(&mut self) -> &mut Headers { &mut self.headers }
|
|
|
|
/// Set the `Url` of this request.
|
|
#[inline]
|
|
pub fn set_url(&mut self, url: Url) { self.url = url; }
|
|
|
|
/// Set the `HttpVersion` of this request.
|
|
#[inline]
|
|
pub fn set_version(&mut self, version: HttpVersion) { self.version = version; }
|
|
|
|
/// Set the body of the request.
|
|
#[inline]
|
|
pub fn set_body<T: Into<Body>>(&mut self, body: T) { self.body = Some(body.into()); }
|
|
}
|
|
|
|
impl fmt::Debug for Request {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
f.debug_struct("Request")
|
|
.field("method", &self.method)
|
|
.field("url", &self.url)
|
|
.field("version", &self.version)
|
|
.field("headers", &self.headers)
|
|
.finish()
|
|
}
|
|
}
|
|
|
|
pub fn split(req: Request) -> (RequestHead, Option<Body>) {
|
|
let uri = Uri::new(&req.url[::url::Position::BeforePath..::url::Position::AfterQuery]).expect("url is uri");
|
|
let head = RequestHead {
|
|
subject: ::http::RequestLine(req.method, uri),
|
|
headers: req.headers,
|
|
version: req.version,
|
|
};
|
|
(head, req.body)
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
/*
|
|
use std::io::Write;
|
|
use std::str::from_utf8;
|
|
use url::Url;
|
|
use method::Method::{Get, Head, Post};
|
|
use mock::{MockStream, MockConnector};
|
|
use net::Fresh;
|
|
use header::{ContentLength,TransferEncoding,Encoding};
|
|
use url::form_urlencoded;
|
|
use super::Request;
|
|
use http::h1::Http11Message;
|
|
|
|
fn run_request(req: Request<Fresh>) -> Vec<u8> {
|
|
let req = req.start().unwrap();
|
|
let message = req.message;
|
|
let mut message = message.downcast::<Http11Message>().ok().unwrap();
|
|
message.flush_outgoing().unwrap();
|
|
let stream = *message
|
|
.into_inner().downcast::<MockStream>().ok().unwrap();
|
|
stream.write
|
|
}
|
|
|
|
fn assert_no_body(s: &str) {
|
|
assert!(!s.contains("Content-Length:"));
|
|
assert!(!s.contains("Transfer-Encoding:"));
|
|
}
|
|
|
|
#[test]
|
|
fn test_get_empty_body() {
|
|
let req = Request::with_connector(
|
|
Get, Url::parse("http://example.dom").unwrap(), &mut MockConnector
|
|
).unwrap();
|
|
let bytes = run_request(req);
|
|
let s = from_utf8(&bytes[..]).unwrap();
|
|
assert_no_body(s);
|
|
}
|
|
|
|
#[test]
|
|
fn test_head_empty_body() {
|
|
let req = Request::with_connector(
|
|
Head, Url::parse("http://example.dom").unwrap(), &mut MockConnector
|
|
).unwrap();
|
|
let bytes = run_request(req);
|
|
let s = from_utf8(&bytes[..]).unwrap();
|
|
assert_no_body(s);
|
|
}
|
|
|
|
#[test]
|
|
fn test_url_query() {
|
|
let url = Url::parse("http://example.dom?q=value").unwrap();
|
|
let req = Request::with_connector(
|
|
Get, url, &mut MockConnector
|
|
).unwrap();
|
|
let bytes = run_request(req);
|
|
let s = from_utf8(&bytes[..]).unwrap();
|
|
assert!(s.contains("?q=value"));
|
|
}
|
|
|
|
#[test]
|
|
fn test_post_content_length() {
|
|
let url = Url::parse("http://example.dom").unwrap();
|
|
let mut req = Request::with_connector(
|
|
Post, url, &mut MockConnector
|
|
).unwrap();
|
|
let mut body = String::new();
|
|
form_urlencoded::Serializer::new(&mut body).append_pair("q", "value");
|
|
req.headers_mut().set(ContentLength(body.len() as u64));
|
|
let bytes = run_request(req);
|
|
let s = from_utf8(&bytes[..]).unwrap();
|
|
assert!(s.contains("Content-Length:"));
|
|
}
|
|
|
|
#[test]
|
|
fn test_post_chunked() {
|
|
let url = Url::parse("http://example.dom").unwrap();
|
|
let req = Request::with_connector(
|
|
Post, url, &mut MockConnector
|
|
).unwrap();
|
|
let bytes = run_request(req);
|
|
let s = from_utf8(&bytes[..]).unwrap();
|
|
assert!(!s.contains("Content-Length:"));
|
|
}
|
|
|
|
#[test]
|
|
fn test_host_header() {
|
|
let url = Url::parse("http://example.dom").unwrap();
|
|
let req = Request::with_connector(
|
|
Get, url, &mut MockConnector
|
|
).unwrap();
|
|
let bytes = run_request(req);
|
|
let s = from_utf8(&bytes[..]).unwrap();
|
|
assert!(s.contains("Host: example.dom"));
|
|
}
|
|
|
|
#[test]
|
|
fn test_proxy() {
|
|
let url = Url::parse("http://example.dom").unwrap();
|
|
let mut req = Request::with_connector(
|
|
Get, url, &mut MockConnector
|
|
).unwrap();
|
|
req.message.set_proxied(true);
|
|
let bytes = run_request(req);
|
|
let s = from_utf8(&bytes[..]).unwrap();
|
|
let request_line = "GET http://example.dom/ HTTP/1.1";
|
|
assert_eq!(&s[..request_line.len()], request_line);
|
|
assert!(s.contains("Host: example.dom"));
|
|
}
|
|
|
|
#[test]
|
|
fn test_post_chunked_with_encoding() {
|
|
let url = Url::parse("http://example.dom").unwrap();
|
|
let mut req = Request::with_connector(
|
|
Post, url, &mut MockConnector
|
|
).unwrap();
|
|
req.headers_mut().set(TransferEncoding(vec![Encoding::Chunked]));
|
|
let bytes = run_request(req);
|
|
let s = from_utf8(&bytes[..]).unwrap();
|
|
assert!(!s.contains("Content-Length:"));
|
|
assert!(s.contains("Transfer-Encoding:"));
|
|
}
|
|
|
|
#[test]
|
|
fn test_write_error_closes() {
|
|
let url = Url::parse("http://hyper.rs").unwrap();
|
|
let req = Request::with_connector(
|
|
Get, url, &mut MockConnector
|
|
).unwrap();
|
|
let mut req = req.start().unwrap();
|
|
|
|
req.message.downcast_mut::<Http11Message>().unwrap()
|
|
.get_mut().downcast_mut::<MockStream>().unwrap()
|
|
.error_on_write = true;
|
|
|
|
req.write(b"foo").unwrap();
|
|
assert!(req.flush().is_err());
|
|
|
|
assert!(req.message.downcast_ref::<Http11Message>().unwrap()
|
|
.get_ref().downcast_ref::<MockStream>().unwrap()
|
|
.is_closed);
|
|
}
|
|
*/
|
|
}
|