-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'tower' into in-memory-backend
- Loading branch information
Showing
24 changed files
with
543 additions
and
49 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
use async_trait::async_trait; | ||
use hitbox::cache::{Extractor, KeyPart, KeyParts}; | ||
use http::HeaderValue; | ||
|
||
use crate::CacheableHttpRequest; | ||
|
||
pub struct Header<E> { | ||
inner: E, | ||
name: String, | ||
} | ||
|
||
pub trait HeaderExtractor: Sized { | ||
fn header(self, name: String) -> Header<Self>; | ||
} | ||
|
||
impl<E> HeaderExtractor for E | ||
where | ||
E: Extractor, | ||
{ | ||
fn header(self, name: String) -> Header<Self> { | ||
Header { inner: self, name } | ||
} | ||
} | ||
|
||
#[async_trait] | ||
impl<ReqBody, E> Extractor for Header<E> | ||
where | ||
ReqBody: Send + 'static, | ||
E: Extractor<Subject = CacheableHttpRequest<ReqBody>> + Send + Sync, | ||
{ | ||
type Subject = E::Subject; | ||
|
||
async fn get(&self, subject: Self::Subject) -> KeyParts<Self::Subject> { | ||
let value = subject | ||
.parts() | ||
.headers | ||
.get(self.name.as_str()) | ||
.map(HeaderValue::to_str) | ||
.transpose() | ||
.ok() | ||
.flatten() | ||
.map(str::to_string); | ||
let mut parts = self.inner.get(subject).await; | ||
parts.push(KeyPart { | ||
key: self.name.clone(), | ||
value, | ||
}); | ||
parts | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
use async_trait::async_trait; | ||
use hitbox::cache::{Extractor, KeyPart, KeyParts}; | ||
use http::HeaderValue; | ||
|
||
use crate::CacheableHttpRequest; | ||
|
||
pub struct Method<E> { | ||
inner: E, | ||
} | ||
|
||
pub trait MethodExtractor: Sized { | ||
fn method(self) -> Method<Self>; | ||
} | ||
|
||
impl<E> MethodExtractor for E | ||
where | ||
E: Extractor, | ||
{ | ||
fn method(self) -> Method<Self> { | ||
Method { inner: self } | ||
} | ||
} | ||
|
||
#[async_trait] | ||
impl<ReqBody, E> Extractor for Method<E> | ||
where | ||
ReqBody: Send + 'static, | ||
E: Extractor<Subject = CacheableHttpRequest<ReqBody>> + Send + Sync, | ||
{ | ||
type Subject = E::Subject; | ||
|
||
async fn get(&self, subject: Self::Subject) -> KeyParts<Self::Subject> { | ||
let method = subject.parts().method.to_string(); | ||
let mut parts = self.inner.get(subject).await; | ||
parts.push(KeyPart { | ||
key: "method".to_owned(), | ||
value: Some(method), | ||
}); | ||
parts | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
use std::marker::PhantomData; | ||
|
||
use async_trait::async_trait; | ||
use hitbox::cache::{Extractor, KeyPart, KeyParts}; | ||
|
||
use crate::CacheableHttpRequest; | ||
|
||
pub mod header; | ||
pub mod method; | ||
pub mod path; | ||
pub mod query; | ||
|
||
pub struct NeutralExtractor<ReqBody> { | ||
_res: PhantomData<fn(ReqBody) -> ReqBody>, | ||
} | ||
|
||
impl<ResBody> NeutralExtractor<ResBody> { | ||
pub fn new() -> Self { | ||
NeutralExtractor { _res: PhantomData } | ||
} | ||
} | ||
|
||
#[async_trait] | ||
impl<ResBody> Extractor for NeutralExtractor<ResBody> | ||
where | ||
ResBody: Send + 'static, | ||
{ | ||
type Subject = CacheableHttpRequest<ResBody>; | ||
|
||
async fn get(&self, subject: Self::Subject) -> KeyParts<Self::Subject> { | ||
KeyParts { | ||
subject, | ||
parts: Vec::new(), | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
use actix_router::{ResourceDef, ResourcePath}; | ||
use async_trait::async_trait; | ||
use hitbox::cache::{CacheableRequest, Extractor, KeyPart, KeyParts}; | ||
use http::HeaderValue; | ||
|
||
use crate::CacheableHttpRequest; | ||
|
||
pub struct Path<E> { | ||
inner: E, | ||
resource: ResourceDef, | ||
} | ||
|
||
pub trait PathExtractor: Sized { | ||
fn path(self, resource: &str) -> Path<Self>; | ||
} | ||
|
||
impl<E> PathExtractor for E | ||
where | ||
E: Extractor, | ||
{ | ||
fn path(self, resource: &str) -> Path<Self> { | ||
Path { | ||
inner: self, | ||
resource: ResourceDef::try_from(resource).unwrap(), | ||
} | ||
} | ||
} | ||
|
||
#[async_trait] | ||
impl<ReqBody, E> Extractor for Path<E> | ||
where | ||
ReqBody: Send + 'static, | ||
E: Extractor<Subject = CacheableHttpRequest<ReqBody>> + Send + Sync, | ||
{ | ||
type Subject = E::Subject; | ||
|
||
async fn get(&self, subject: Self::Subject) -> KeyParts<Self::Subject> { | ||
let mut path = actix_router::Path::new(subject.parts().uri.path()); | ||
self.resource.capture_match_info(&mut path); | ||
let mut matched_parts = path | ||
.iter() | ||
.map(|(key, value)| KeyPart { | ||
key: key.to_owned(), | ||
value: Some(value.to_owned()), | ||
}) | ||
.collect::<Vec<_>>(); | ||
let mut parts = self.inner.get(subject).await; | ||
parts.append(&mut matched_parts); | ||
parts | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
use async_trait::async_trait; | ||
use hitbox::cache::{Extractor, KeyPart, KeyParts}; | ||
|
||
use crate::CacheableHttpRequest; | ||
|
||
pub struct Query<E> { | ||
inner: E, | ||
name: String, | ||
} | ||
|
||
pub trait QueryExtractor: Sized { | ||
fn query(self, name: String) -> Query<Self>; | ||
} | ||
|
||
impl<E> QueryExtractor for E | ||
where | ||
E: Extractor, | ||
{ | ||
fn query(self, name: String) -> Query<Self> { | ||
Query { inner: self, name } | ||
} | ||
} | ||
|
||
#[async_trait] | ||
impl<ReqBody, E> Extractor for Query<E> | ||
where | ||
ReqBody: Send + 'static, | ||
E: Extractor<Subject = CacheableHttpRequest<ReqBody>> + Send + Sync, | ||
{ | ||
type Subject = E::Subject; | ||
|
||
async fn get(&self, subject: Self::Subject) -> KeyParts<Self::Subject> { | ||
let values = subject | ||
.parts() | ||
.uri | ||
.query() | ||
.map(crate::query::parse) | ||
.map(|m| m.get(&self.name).map(crate::query::Value::inner)) | ||
.flatten() | ||
.unwrap_or_default(); | ||
let mut parts = self.inner.get(subject).await; | ||
for value in values { | ||
parts.push(KeyPart { | ||
key: self.name.clone(), | ||
value: Some(value), | ||
}); | ||
} | ||
parts | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,7 @@ | ||
mod body; | ||
pub mod extractors; | ||
pub mod predicates; | ||
mod query; | ||
mod request; | ||
mod response; | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
use serde::Deserialize; | ||
use std::collections::HashMap; | ||
|
||
#[derive(Debug, Deserialize, PartialEq, Eq)] | ||
#[serde(untagged)] | ||
pub enum Value { | ||
Scalar(String), | ||
Array(Vec<String>), | ||
} | ||
|
||
impl Value { | ||
pub fn inner(&self) -> Vec<String> { | ||
match self { | ||
Value::Scalar(value) => vec![value.to_owned()], | ||
Value::Array(values) => values.to_owned(), | ||
} | ||
} | ||
} | ||
|
||
pub fn parse(value: &str) -> HashMap<String, Value> { | ||
serde_qs::from_str(value).expect("Unreachable branch reached") | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::*; | ||
|
||
#[test] | ||
fn test_parse_valid_one() { | ||
let hash_map = parse("key=value"); | ||
let value = hash_map.get("key").unwrap(); | ||
assert_eq!(value.inner(), vec!["value"]); | ||
} | ||
|
||
#[test] | ||
fn test_parse_valid_multiple() { | ||
let hash_map = parse("key-one=value-one&key-two=value-two&key-three=value-three"); | ||
let value = hash_map.get("key-one").unwrap(); | ||
assert_eq!(value.inner(), vec!["value-one"]); | ||
let value = hash_map.get("key-two").unwrap(); | ||
assert_eq!(value.inner(), vec!["value-two"]); | ||
let value = hash_map.get("key-three").unwrap(); | ||
assert_eq!(value.inner(), vec!["value-three"]); | ||
} | ||
|
||
#[test] | ||
fn test_parse_not_valid() { | ||
let hash_map = parse(" wrong "); | ||
assert_eq!(hash_map.len(), 1); | ||
} | ||
} |
Oops, something went wrong.