refactor(http): merge Request and Response from server and client
Request and Response are now visible from:
- hyper::{Request, Response}
- hyper::server::{Request, Response}
- hyper::client::{Request, Response}
They truly exist in the http module, but are re-exported to reduce the number of breaking changes.
request::new and response::new were renamed to ::from_wire to reduce confusion with Request::new
and Response::new. See issue #1126
Request now has an optional Body, because not all requests have bodies.
Use body_ref() to determine if a body exists.
Use body() to take the body, or construct one if no body exists.
Closes #1155
BREAKING CHANGE: Response::body() now consumes the response
This commit is contained in:
@@ -22,19 +22,19 @@ pub use tokio_service::Service;
|
||||
|
||||
use header::{Headers, Host};
|
||||
use http::{self, TokioBody};
|
||||
use http::response;
|
||||
use http::request;
|
||||
use method::Method;
|
||||
use self::pool::{Pool, Pooled};
|
||||
use uri::{self, Uri};
|
||||
|
||||
pub use http::response::Response;
|
||||
pub use http::request::Request;
|
||||
pub use self::connect::{HttpConnector, Connect};
|
||||
pub use self::request::Request;
|
||||
pub use self::response::Response;
|
||||
|
||||
mod connect;
|
||||
mod dns;
|
||||
mod pool;
|
||||
mod request;
|
||||
mod response;
|
||||
|
||||
/// A Client to make outgoing HTTP requests.
|
||||
// If the Connector is clone, then the Client can be clone easily.
|
||||
@@ -198,8 +198,8 @@ where C: Connect,
|
||||
});
|
||||
FutureResponse(Box::new(req.map(|msg| {
|
||||
match msg {
|
||||
Message::WithoutBody(head) => response::new(head, None),
|
||||
Message::WithBody(head, body) => response::new(head, Some(body.into())),
|
||||
Message::WithoutBody(head) => response::from_wire(head, None),
|
||||
Message::WithBody(head, body) => response::from_wire(head, Some(body.into())),
|
||||
}
|
||||
})))
|
||||
}
|
||||
|
||||
@@ -1,216 +0,0 @@
|
||||
use std::fmt;
|
||||
|
||||
use header::Headers;
|
||||
use http::{Body, RequestHead};
|
||||
use method::Method;
|
||||
use uri::{self, Uri};
|
||||
use version::HttpVersion;
|
||||
|
||||
/// A client request to a remote server.
|
||||
pub struct Request<B = Body> {
|
||||
method: Method,
|
||||
uri: Uri,
|
||||
version: HttpVersion,
|
||||
headers: Headers,
|
||||
body: Option<B>,
|
||||
is_proxy: bool,
|
||||
}
|
||||
|
||||
impl<B> Request<B> {
|
||||
/// Construct a new Request.
|
||||
#[inline]
|
||||
pub fn new(method: Method, uri: Uri) -> Request<B> {
|
||||
Request {
|
||||
method: method,
|
||||
uri: uri,
|
||||
version: HttpVersion::default(),
|
||||
headers: Headers::new(),
|
||||
body: None,
|
||||
is_proxy: false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Read the Request Uri.
|
||||
#[inline]
|
||||
pub fn uri(&self) -> &Uri { &self.uri }
|
||||
|
||||
/// Read the 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 }
|
||||
|
||||
/// Read the Request body.
|
||||
#[inline]
|
||||
pub fn body(&self) -> Option<&B> { self.body.as_ref() }
|
||||
|
||||
/// 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 `Uri` of this request.
|
||||
#[inline]
|
||||
pub fn set_uri(&mut self, uri: Uri) { self.uri = uri; }
|
||||
|
||||
/// 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<B>>(&mut self, body: T) { self.body = Some(body.into()); }
|
||||
|
||||
/// Set that the URI should use the absolute form.
|
||||
///
|
||||
/// This is only needed when talking to HTTP/1 proxies to URLs not
|
||||
/// protected by TLS.
|
||||
#[inline]
|
||||
pub fn set_proxy(&mut self, is_proxy: bool) { self.is_proxy = is_proxy; }
|
||||
}
|
||||
|
||||
impl<B> fmt::Debug for Request<B> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_struct("Request")
|
||||
.field("method", &self.method)
|
||||
.field("uri", &self.uri)
|
||||
.field("version", &self.version)
|
||||
.field("headers", &self.headers)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn split<B>(req: Request<B>) -> (RequestHead, Option<B>) {
|
||||
let uri = if req.is_proxy {
|
||||
req.uri
|
||||
} else {
|
||||
uri::origin_form(&req.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;
|
||||
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"));
|
||||
}
|
||||
*/
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
use std::fmt;
|
||||
|
||||
use header;
|
||||
use http::{self, RawStatus, Body};
|
||||
use status;
|
||||
use version;
|
||||
|
||||
pub fn new(incoming: http::ResponseHead, body: Option<Body>) -> Response {
|
||||
trace!("Response::new");
|
||||
let status = status::StatusCode::from_u16(incoming.subject.0);
|
||||
debug!("version={:?}, status={:?}", incoming.version, status);
|
||||
debug!("headers={:?}", incoming.headers);
|
||||
|
||||
Response {
|
||||
status: status,
|
||||
version: incoming.version,
|
||||
headers: incoming.headers,
|
||||
status_raw: incoming.subject,
|
||||
body: body,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// A response for a client request to a remote server.
|
||||
pub struct Response {
|
||||
status: status::StatusCode,
|
||||
headers: header::Headers,
|
||||
version: version::HttpVersion,
|
||||
status_raw: RawStatus,
|
||||
body: Option<Body>,
|
||||
}
|
||||
|
||||
impl Response {
|
||||
/// Get the headers from the server.
|
||||
#[inline]
|
||||
pub fn headers(&self) -> &header::Headers { &self.headers }
|
||||
|
||||
/// Get the status from the server.
|
||||
#[inline]
|
||||
pub fn status(&self) -> status::StatusCode { self.status }
|
||||
|
||||
/// Get the raw status code and reason.
|
||||
#[inline]
|
||||
pub fn status_raw(&self) -> &RawStatus { &self.status_raw }
|
||||
|
||||
/// Get the HTTP version of this response from the server.
|
||||
#[inline]
|
||||
pub fn version(&self) -> version::HttpVersion { self.version }
|
||||
|
||||
/// Take the `Body` of this response.
|
||||
#[inline]
|
||||
pub fn body(mut self) -> Body {
|
||||
self.body.take().unwrap_or(Body::empty())
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Response {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_struct("Response")
|
||||
.field("status", &self.status)
|
||||
.field("version", &self.version)
|
||||
.field("headers", &self.headers)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user