Skip to content

Commit 12c6f74

Browse files
authored
Merge pull request #6 from jtgeibel/use-http-types
Bump to latest conduit alpha and use `http` types
2 parents f7f53b8 + aee68bf commit 12c6f74

File tree

7 files changed

+82
-193
lines changed

7 files changed

+82
-193
lines changed

Cargo.toml

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "conduit-hyper"
3-
version = "0.3.0-alpha.0"
3+
version = "0.3.0-alpha.1"
44
authors = ["Justin Geibel <[email protected]>"]
55
license = "MIT OR Apache-2.0"
66
description = "Host a conduit based web application on a hyper server"
@@ -9,16 +9,15 @@ readme = "README.md"
99
edition = "2018"
1010

1111
[dependencies]
12-
conduit = "0.9.0-alpha.0"
12+
conduit = "0.9.0-alpha.1"
1313
futures = "0.3"
1414
hyper = "0.13"
1515
http = "0.2"
1616
tracing = { version = "0.1", features = ["log"] }
17-
semver = "0.9" # Must match version in conduit
1817
tokio = { version = "0.2", features = ["blocking", "rt-threaded"] }
1918
tower-service = "0.3"
2019

2120
[dev-dependencies]
22-
conduit-router = "0.9.0-alpha.0"
21+
conduit-router = "0.9.0-alpha.1"
2322
env_logger = "0.7"
2423
tokio = { version = "0.2", features = ["macros"] }

examples/server.rs

Lines changed: 11 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
#![deny(clippy::all)]
22

3-
use conduit::{Handler, Request, Response};
3+
use conduit::{header, static_to_body, Handler, RequestExt, Response, ResponseResult};
44
use conduit_hyper::Server;
55
use conduit_router::RouteBuilder;
66

7-
use std::collections::HashMap;
8-
use std::io::{Cursor, Error};
7+
use std::io;
98
use std::thread::sleep;
109

1110
const MAX_THREADS: usize = 1;
@@ -28,29 +27,22 @@ fn build_conduit_handler() -> impl Handler {
2827
router
2928
}
3029

31-
fn endpoint(_: &mut dyn Request) -> Result<Response, Error> {
32-
let body = "Hello world!";
30+
fn endpoint(_: &mut dyn RequestExt) -> ResponseResult<http::Error> {
31+
let body = b"Hello world!";
3332

3433
sleep(std::time::Duration::from_secs(2));
3534

36-
let mut headers = HashMap::new();
37-
headers.insert(
38-
"Content-Type".to_string(),
39-
vec!["text/plain; charset=utf-8".to_string()],
40-
);
41-
headers.insert("Content-Length".to_string(), vec![body.len().to_string()]);
42-
Ok(Response {
43-
status: (200, "OK"),
44-
headers,
45-
body: Box::new(Cursor::new(body)),
46-
})
35+
Response::builder()
36+
.header(header::CONTENT_TYPE, "text/plain; charset=utf-8")
37+
.header(header::CONTENT_LENGTH, body.len())
38+
.body(static_to_body(body))
4739
}
4840

49-
fn panic(_: &mut dyn Request) -> Result<Response, Error> {
41+
fn panic(_: &mut dyn RequestExt) -> ResponseResult<http::Error> {
5042
// For now, connection is immediately closed
5143
panic!("message");
5244
}
5345

54-
fn error(_: &mut dyn Request) -> Result<Response, Error> {
55-
Err(Error::new(std::io::ErrorKind::Other, "io error, oops"))
46+
fn error(_: &mut dyn RequestExt) -> ResponseResult<io::Error> {
47+
Err(io::Error::new(io::ErrorKind::Other, "io error, oops"))
5648
}

src/adaptor.rs

Lines changed: 9 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,9 @@ use std::io::{Cursor, Read};
1313
use std::net::SocketAddr;
1414
use std::path::{Component, Path, PathBuf};
1515

16-
use conduit::{Extensions, Headers, Host, Method, Request, Scheme};
17-
use http::{request::Parts as HttpParts, HeaderMap};
18-
use hyper::{body::Bytes, Method as HyperMethod, Version as HttpVersion};
19-
use semver::Version;
16+
use conduit::{Extensions, HeaderMap, Host, Method, RequestExt, Scheme, Version};
17+
use http::request::Parts as HttpParts;
18+
use hyper::body::Bytes;
2019

2120
/// Owned data consumed by the background thread
2221
///
@@ -52,44 +51,6 @@ impl Parts {
5251
}
5352
}
5453

55-
impl Headers for Parts {
56-
/// Find all values associated with a header, or None.
57-
///
58-
/// If the value of a header is not valid UTF-8, that value
59-
/// is replaced with the emtpy string.
60-
fn find(&self, key: &str) -> Option<Vec<&str>> {
61-
let values = self
62-
.headers()
63-
.get_all(key)
64-
.iter()
65-
.map(|v| v.to_str().unwrap_or(""))
66-
.collect::<Vec<_>>();
67-
68-
if values.is_empty() {
69-
None
70-
} else {
71-
Some(values)
72-
}
73-
}
74-
75-
fn has(&self, key: &str) -> bool {
76-
self.headers().contains_key(key)
77-
}
78-
79-
/// Returns a representation of all headers
80-
fn all(&self) -> Vec<(&str, Vec<&str>)> {
81-
let mut all = Vec::new();
82-
for key in self.headers().keys() {
83-
let key = key.as_str();
84-
let values = self
85-
.find(key)
86-
.expect("all keys should have at least one value");
87-
all.push((key, values));
88-
}
89-
all
90-
}
91-
}
92-
9354
pub(crate) struct ConduitRequest {
9455
parts: Parts,
9556
path: String,
@@ -141,44 +102,22 @@ impl ConduitRequest {
141102
}
142103
}
143104

144-
impl Request for ConduitRequest {
105+
impl RequestExt for ConduitRequest {
145106
fn http_version(&self) -> Version {
146-
match self.parts().version {
147-
HttpVersion::HTTP_09 => version(0, 9),
148-
HttpVersion::HTTP_10 => version(1, 0),
149-
HttpVersion::HTTP_11 => version(1, 1),
150-
HttpVersion::HTTP_2 => version(2, 0),
151-
HttpVersion::HTTP_3 => version(3, 0),
152-
_ => version(0, 0),
153-
}
107+
self.parts().version
154108
}
155109

156-
fn conduit_version(&self) -> Version {
157-
version(0, 1)
158-
}
159-
160-
fn method(&self) -> Method {
161-
match self.parts().method {
162-
HyperMethod::CONNECT => Method::Connect,
163-
HyperMethod::DELETE => Method::Delete,
164-
HyperMethod::GET => Method::Get,
165-
HyperMethod::HEAD => Method::Head,
166-
HyperMethod::OPTIONS => Method::Options,
167-
HyperMethod::PATCH => Method::Patch,
168-
HyperMethod::POST => Method::Post,
169-
HyperMethod::PUT => Method::Put,
170-
HyperMethod::TRACE => Method::Trace,
171-
_ => Method::Other(self.parts().method.to_string()),
172-
}
110+
fn method(&self) -> &Method {
111+
&self.parts().method
173112
}
174113

175114
/// Always returns Http
176115
fn scheme(&self) -> Scheme {
177116
Scheme::Http
178117
}
179118

180-
fn headers(&self) -> &dyn Headers {
181-
&self.parts
119+
fn headers(&self) -> &HeaderMap {
120+
&self.parts.headers()
182121
}
183122

184123
/// Returns the length of the buffered body
@@ -228,13 +167,3 @@ impl Request for ConduitRequest {
228167
&mut self.body
229168
}
230169
}
231-
232-
fn version(major: u64, minor: u64) -> Version {
233-
Version {
234-
major,
235-
minor,
236-
patch: 0,
237-
pre: vec![],
238-
build: vec![],
239-
}
240-
}

src/lib.rs

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -35,16 +35,12 @@
3535
//! }
3636
//! #
3737
//! # use std::{error, io};
38-
//! # use conduit::{Request, Response};
38+
//! # use conduit::{box_error, static_to_body, Response, RequestExt, HandlerResult};
3939
//! #
4040
//! # struct Endpoint();
4141
//! # impl Handler for Endpoint {
42-
//! # fn call(&self, _: &mut dyn Request) -> Result<Response, Box<dyn error::Error + Send>> {
43-
//! # Ok(Response {
44-
//! # status: (200, "OK"),
45-
//! # headers: Default::default(),
46-
//! # body: Box::new(io::Cursor::new("")),
47-
//! # })
42+
//! # fn call(&self, _: &mut dyn RequestExt) -> HandlerResult {
43+
//! # Response::builder().body(static_to_body(b"")).map_err(box_error)
4844
//! # }
4945
//! # }
5046
//! ```
@@ -55,8 +51,7 @@ mod service;
5551
#[cfg(test)]
5652
mod tests;
5753

58-
// Consumers of this library need access to this particular version of `semver`
59-
pub use semver;
60-
6154
pub use server::Server;
6255
pub use service::{BlockingHandler, Service};
56+
57+
type HyperResponse = hyper::Response<hyper::Body>;

src/service.rs

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,17 +23,12 @@ impl Service {
2323
/// ```no_run
2424
/// # use std::sync::Arc;
2525
/// # use conduit_hyper::{BlockingHandler, Service};
26-
/// # use std::{error, io};
27-
/// # use conduit::{Handler, Request, Response};
26+
/// # use conduit::{box_error, static_to_body, Handler, HandlerResult, RequestExt, Response};
2827
/// #
2928
/// # struct Endpoint();
3029
/// # impl Handler for Endpoint {
31-
/// # fn call(&self, _: &mut dyn Request) -> Result<Response, Box<dyn error::Error + Send>> {
32-
/// # Ok(Response {
33-
/// # status: (200, "OK"),
34-
/// # headers: Default::default(),
35-
/// # body: Box::new(io::Cursor::new("")),
36-
/// # })
30+
/// # fn call(&self, _: &mut dyn RequestExt) -> HandlerResult {
31+
/// # Response::builder().body(static_to_body(b"")).map_err(box_error)
3732
/// # }
3833
/// # }
3934
/// # let app = Endpoint();

src/service/blocking_handler.rs

Lines changed: 17 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,27 @@
11
use crate::adaptor::{ConduitRequest, RequestInfo};
22
use crate::service::ServiceError;
3+
use crate::HyperResponse;
34

45
use std::net::SocketAddr;
5-
use std::sync::{atomic::Ordering, Arc};
6+
use std::sync::{
7+
atomic::{AtomicUsize, Ordering},
8+
Arc,
9+
};
610

7-
use hyper::{Body, Request, Response, StatusCode};
11+
use conduit::Handler;
12+
use hyper::{Body, Request, Response};
813
use tracing::error;
914

10-
use std::sync::atomic::AtomicUsize;
15+
type ConduitResponse = Response<conduit::Body>;
1116

1217
#[derive(Debug)]
13-
pub struct BlockingHandler<H: conduit::Handler> {
18+
pub struct BlockingHandler<H: Handler> {
1419
thread_count: AtomicUsize,
1520
max_thread_count: usize,
1621
handler: Arc<H>,
1722
}
1823

19-
impl<H: conduit::Handler> BlockingHandler<H> {
24+
impl<H: Handler> BlockingHandler<H> {
2025
pub fn new(handler: H, max_thread_count: usize) -> Self {
2126
Self {
2227
thread_count: AtomicUsize::new(0),
@@ -30,7 +35,7 @@ impl<H: conduit::Handler> BlockingHandler<H> {
3035
self: Arc<Self>,
3136
request: Request<Body>,
3237
remote_addr: SocketAddr,
33-
) -> Result<Response<Body>, ServiceError> {
38+
) -> Result<HyperResponse, ServiceError> {
3439
let (parts, body) = request.into_parts();
3540

3641
let full_body = hyper::body::to_bytes(body).await?;
@@ -58,32 +63,18 @@ impl<H: conduit::Handler> BlockingHandler<H> {
5863
}
5964

6065
/// Builds a `hyper::Response` given a `conduit:Response`
61-
fn good_response(mut response: conduit::Response) -> Response<Body> {
66+
fn good_response(mut response: ConduitResponse) -> HyperResponse {
6267
let mut body = Vec::new();
63-
if response.body.write_body(&mut body).is_err() {
68+
if response.body_mut().write_body(&mut body).is_err() {
6469
return server_error_response("Error writing body");
6570
}
6671

67-
let mut builder = Response::builder();
68-
let status = match StatusCode::from_u16(response.status.0 as u16) {
69-
Ok(s) => s,
70-
Err(e) => return server_error_response(&e.to_string()),
71-
};
72-
73-
for (key, values) in response.headers {
74-
for value in values {
75-
builder = builder.header(key.as_str(), value.as_str());
76-
}
77-
}
78-
79-
builder
80-
.status(status)
81-
.body(body.into())
82-
.unwrap_or_else(|e| server_error_response(&e.to_string()))
72+
let (parts, _) = response.into_parts();
73+
Response::from_parts(parts, body.into())
8374
}
8475

8576
/// Logs an error message and returns a generic status 500 response
86-
fn server_error_response(message: &str) -> Response<Body> {
77+
fn server_error_response(message: &str) -> HyperResponse {
8778
error!("Internal Server Error: {}", message);
8879
let body = Body::from("Internal Server Error");
8980
Response::builder()
@@ -93,7 +84,7 @@ fn server_error_response(message: &str) -> Response<Body> {
9384
}
9485

9586
/// Logs an error message and returns a 503 status saying the service is over capacity
96-
fn over_capacity_error_response() -> Response<Body> {
87+
fn over_capacity_error_response() -> HyperResponse {
9788
const RETRY_AFTER: u32 = 2;
9889
error!("Server Capacity Exceeded");
9990
let body = Body::from(format!(

0 commit comments

Comments
 (0)