@@ -236,13 +236,14 @@ where C: Connect + Sync + 'static,
|
|||||||
match req.version() {
|
match req.version() {
|
||||||
Version::HTTP_11 => (),
|
Version::HTTP_11 => (),
|
||||||
Version::HTTP_10 => if is_http_connect {
|
Version::HTTP_10 => if is_http_connect {
|
||||||
debug!("CONNECT is not allowed for HTTP/1.0");
|
warn!("CONNECT is not allowed for HTTP/1.0");
|
||||||
return ResponseFuture::new(Box::new(future::err(::Error::new_user_unsupported_request_method())));
|
return ResponseFuture::new(Box::new(future::err(::Error::new_user_unsupported_request_method())));
|
||||||
},
|
},
|
||||||
other => if self.config.ver != Ver::Http2 {
|
other_h2 @ Version::HTTP_2 => if self.config.ver != Ver::Http2 {
|
||||||
error!("Request has unsupported version \"{:?}\"", other);
|
return ResponseFuture::error_version(other_h2);
|
||||||
return ResponseFuture::new(Box::new(future::err(::Error::new_user_unsupported_version())));
|
},
|
||||||
}
|
// completely unsupported HTTP version (like HTTP/0.9)!
|
||||||
|
other => return ResponseFuture::error_version(other),
|
||||||
};
|
};
|
||||||
|
|
||||||
let domain = match extract_domain(req.uri_mut(), is_http_connect) {
|
let domain = match extract_domain(req.uri_mut(), is_http_connect) {
|
||||||
@@ -591,6 +592,11 @@ impl ResponseFuture {
|
|||||||
inner: fut,
|
inner: fut,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn error_version(ver: Version) -> Self {
|
||||||
|
warn!("Request has unsupported version \"{:?}\"", ver);
|
||||||
|
ResponseFuture::new(Box::new(future::err(::Error::new_user_unsupported_version())))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for ResponseFuture {
|
impl fmt::Debug for ResponseFuture {
|
||||||
|
|||||||
@@ -271,7 +271,7 @@ impl Http1Transaction for Server {
|
|||||||
warn!("response with HTTP2 version coerced to HTTP/1.1");
|
warn!("response with HTTP2 version coerced to HTTP/1.1");
|
||||||
extend(dst, b"HTTP/1.1 ");
|
extend(dst, b"HTTP/1.1 ");
|
||||||
},
|
},
|
||||||
_ => unreachable!(),
|
other => panic!("unexpected response version: {:?}", other),
|
||||||
}
|
}
|
||||||
|
|
||||||
extend(dst, msg.head.subject.as_str().as_bytes());
|
extend(dst, msg.head.subject.as_str().as_bytes());
|
||||||
@@ -667,7 +667,11 @@ impl Http1Transaction for Client {
|
|||||||
match msg.head.version {
|
match msg.head.version {
|
||||||
Version::HTTP_10 => extend(dst, b"HTTP/1.0"),
|
Version::HTTP_10 => extend(dst, b"HTTP/1.0"),
|
||||||
Version::HTTP_11 => extend(dst, b"HTTP/1.1"),
|
Version::HTTP_11 => extend(dst, b"HTTP/1.1"),
|
||||||
_ => unreachable!(),
|
Version::HTTP_2 => {
|
||||||
|
warn!("request with HTTP2 version coerced to HTTP/1.1");
|
||||||
|
extend(dst, b"HTTP/1.1");
|
||||||
|
},
|
||||||
|
other => panic!("unexpected request version: {:?}", other),
|
||||||
}
|
}
|
||||||
extend(dst, b"\r\n");
|
extend(dst, b"\r\n");
|
||||||
|
|
||||||
|
|||||||
@@ -39,13 +39,6 @@ macro_rules! test {
|
|||||||
request: {$(
|
request: {$(
|
||||||
$c_req_prop:ident: $c_req_val: tt,
|
$c_req_prop:ident: $c_req_val: tt,
|
||||||
)*},
|
)*},
|
||||||
/*
|
|
||||||
method: $client_method:ident,
|
|
||||||
url: $client_url:expr,
|
|
||||||
headers: { $($request_header_name:expr => $request_header_val:expr,)* },
|
|
||||||
body: $request_body:expr,
|
|
||||||
},
|
|
||||||
*/
|
|
||||||
|
|
||||||
response:
|
response:
|
||||||
status: $client_status:ident,
|
status: $client_status:ident,
|
||||||
@@ -299,6 +292,10 @@ macro_rules! __client_req_prop {
|
|||||||
$req_builder.method(Method::$method);
|
$req_builder.method(Method::$method);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
($req_builder:ident, $body:ident, $addr:ident, version: $version:ident) => ({
|
||||||
|
$req_builder.version(hyper::Version::$version);
|
||||||
|
});
|
||||||
|
|
||||||
($req_builder:ident, $body:ident, $addr:ident, url: $url:expr) => ({
|
($req_builder:ident, $body:ident, $addr:ident, url: $url:expr) => ({
|
||||||
$req_builder.uri(format!($url, addr=$addr));
|
$req_builder.uri(format!($url, addr=$addr));
|
||||||
});
|
});
|
||||||
@@ -724,6 +721,38 @@ test! {
|
|||||||
body: None,
|
body: None,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test! {
|
||||||
|
name: client_h1_rejects_http2,
|
||||||
|
|
||||||
|
server:
|
||||||
|
expected: "won't get here {addr}",
|
||||||
|
reply: "won't reply",
|
||||||
|
|
||||||
|
client:
|
||||||
|
request: {
|
||||||
|
method: GET,
|
||||||
|
url: "http://{addr}/",
|
||||||
|
version: HTTP_2,
|
||||||
|
},
|
||||||
|
error: |err| err.to_string() == "request has unsupported HTTP version",
|
||||||
|
}
|
||||||
|
|
||||||
|
test! {
|
||||||
|
name: client_always_rejects_http09,
|
||||||
|
|
||||||
|
server:
|
||||||
|
expected: "won't get here {addr}",
|
||||||
|
reply: "won't reply",
|
||||||
|
|
||||||
|
client:
|
||||||
|
request: {
|
||||||
|
method: GET,
|
||||||
|
url: "http://{addr}/",
|
||||||
|
version: HTTP_09,
|
||||||
|
},
|
||||||
|
error: |err| err.to_string() == "request has unsupported HTTP version",
|
||||||
|
}
|
||||||
|
|
||||||
mod dispatch_impl {
|
mod dispatch_impl {
|
||||||
use super::*;
|
use super::*;
|
||||||
use std::io::{self, Read, Write};
|
use std::io::{self, Read, Write};
|
||||||
@@ -1804,6 +1833,52 @@ mod conn {
|
|||||||
rt.block_on(res.join(rx).map(|r| r.0)).unwrap();
|
rt.block_on(res.join(rx).map(|r| r.0)).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn http1_conn_coerces_http2_request() {
|
||||||
|
let server = TcpListener::bind("127.0.0.1:0").unwrap();
|
||||||
|
let addr = server.local_addr().unwrap();
|
||||||
|
let mut rt = Runtime::new().unwrap();
|
||||||
|
|
||||||
|
let (tx1, rx1) = oneshot::channel();
|
||||||
|
|
||||||
|
thread::spawn(move || {
|
||||||
|
let mut sock = server.accept().unwrap().0;
|
||||||
|
sock.set_read_timeout(Some(Duration::from_secs(5))).unwrap();
|
||||||
|
sock.set_write_timeout(Some(Duration::from_secs(5))).unwrap();
|
||||||
|
let mut buf = [0; 4096];
|
||||||
|
let n = sock.read(&mut buf).expect("read 1");
|
||||||
|
|
||||||
|
// Not HTTP/2, nor panicked
|
||||||
|
let expected = "GET /a HTTP/1.1\r\n\r\n";
|
||||||
|
assert_eq!(s(&buf[..n]), expected);
|
||||||
|
|
||||||
|
sock.write_all(b"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n").unwrap();
|
||||||
|
let _ = tx1.send(());
|
||||||
|
});
|
||||||
|
|
||||||
|
let tcp = rt.block_on(tcp_connect(&addr)).unwrap();
|
||||||
|
|
||||||
|
let (mut client, conn) = rt.block_on(conn::handshake(tcp)).unwrap();
|
||||||
|
|
||||||
|
rt.spawn(conn.map(|_| ()).map_err(|e| panic!("conn error: {}", e)));
|
||||||
|
|
||||||
|
let req = Request::builder()
|
||||||
|
.uri("/a")
|
||||||
|
.version(hyper::Version::HTTP_2)
|
||||||
|
.body(Default::default())
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let res = client.send_request(req).and_then(move |res| {
|
||||||
|
assert_eq!(res.status(), hyper::StatusCode::OK);
|
||||||
|
res.into_body().concat2()
|
||||||
|
});
|
||||||
|
let rx = rx1.expect("thread panicked");
|
||||||
|
|
||||||
|
let timeout = Delay::new(Duration::from_millis(200));
|
||||||
|
let rx = rx.and_then(move |_| timeout.expect("timeout"));
|
||||||
|
rt.block_on(res.join(rx).map(|r| r.0)).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn pipeline() {
|
fn pipeline() {
|
||||||
let server = TcpListener::bind("127.0.0.1:0").unwrap();
|
let server = TcpListener::bind("127.0.0.1:0").unwrap();
|
||||||
|
|||||||
Reference in New Issue
Block a user