Skip to content

Commit 91d35eb

Browse files
committed
chore: more work, improved inner ergonomics, added error types
Signed-off-by: Martin <martin@hotmail.com.br>
1 parent 06d36fe commit 91d35eb

File tree

2 files changed

+71
-68
lines changed

2 files changed

+71
-68
lines changed

src/errors.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use actix_web::http::StatusCode;
2+
use actix_web::{HttpResponse, ResponseError};
13
use thiserror::Error;
24

35
#[derive(Debug, Error)]
@@ -8,3 +10,14 @@ pub enum PrerenderError {
810
#[error(transparent)]
911
ReqwestError(#[from] reqwest::Error),
1012
}
13+
14+
impl ResponseError for PrerenderError {
15+
fn status_code(&self) -> StatusCode {
16+
StatusCode::BAD_REQUEST
17+
}
18+
19+
fn error_response(&self) -> HttpResponse {
20+
let res = HttpResponse::with_body(self.status_code(), self.to_string());
21+
res.map_into_boxed_body()
22+
}
23+
}

src/middleware.rs

Lines changed: 58 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
1-
use crate::errors::PrerenderError;
2-
use crate::{IGNORED_EXTENSIONS, USER_AGENTS};
31
use actix_service::{Service, Transform};
42
use actix_utils::future;
53
use actix_utils::future::Ready;
64
use actix_web::body::BoxBody;
7-
85
use actix_web::dev::{ServiceRequest, ServiceResponse};
96
use actix_web::http::header::HeaderMap;
107
use actix_web::http::uri::PathAndQuery;
@@ -13,48 +10,59 @@ use actix_web::{Error, HttpResponse};
1310
use futures_util::future::LocalBoxFuture;
1411
use futures_util::TryFutureExt;
1512
use reqwest::Client;
13+
use std::rc::Rc;
1614
use url::Url;
1715

16+
use crate::errors::PrerenderError;
17+
use crate::{IGNORED_EXTENSIONS, USER_AGENTS};
18+
1819
#[derive(Debug, Clone)]
1920
pub struct Prerender {
20-
prerender_service_url: Url,
21-
inner_client: Client,
21+
inner: Rc<Inner>,
2222
}
2323

2424
#[derive(Debug, Clone)]
2525
pub struct Inner {
2626
prerender_service_url: Url,
2727
inner_client: Client,
28+
prerender_token: String,
2829
}
2930

3031
impl Prerender {}
3132

32-
#[derive(Debug)]
33+
#[derive(Debug, Clone)]
3334
pub struct PrerenderBuilder {}
3435

3536
impl PrerenderBuilder {
36-
pub fn use_prerender_io(mut self) -> Prerender {
37-
Prerender {
37+
pub fn use_prerender_io(self, token: String) -> Prerender {
38+
let inner = Inner {
3839
prerender_service_url: prerender_url(),
39-
inner_client: Default::default(),
40-
}
40+
inner_client: Client::default(),
41+
prerender_token: token,
42+
};
43+
44+
Prerender { inner: Rc::new(inner) }
4145
}
4246

4347
pub fn use_custom_prerender_url(
44-
mut self,
48+
self,
4549
prerender_service_url: &str,
50+
token: String,
4651
) -> Result<Prerender, PrerenderError> {
47-
let result = Url::parse(prerender_service_url).map_err(|_| PrerenderError::InvalidUrl)?;
52+
let prerender_service_url = Url::parse(prerender_service_url).map_err(|_| PrerenderError::InvalidUrl)?;
4853

49-
Ok(Prerender {
50-
prerender_service_url: result,
51-
inner_client: Default::default(),
52-
})
54+
let inner = Inner {
55+
prerender_service_url,
56+
inner_client: Client::default(),
57+
prerender_token: token,
58+
};
59+
60+
Ok(Prerender { inner: Rc::new(inner) })
5361
}
5462
}
5563

5664
impl Prerender {
57-
pub fn builder() -> PrerenderBuilder {
65+
pub const fn builder() -> PrerenderBuilder {
5866
PrerenderBuilder {}
5967
}
6068
}
@@ -98,11 +106,7 @@ pub(crate) fn should_prerender(req: &ServiceRequest) -> bool {
98106
// check for ignored extensions
99107
let is_ignored_extension_url = req.uri().path_and_query().map_or_else(
100108
|| false,
101-
|path_query| {
102-
IGNORED_EXTENSIONS
103-
.iter()
104-
.any(|ext| path_query.as_str().contains(ext))
105-
},
109+
|path_query| IGNORED_EXTENSIONS.iter().any(|ext| path_query.as_str().contains(ext)),
106110
);
107111
if is_ignored_extension_url {
108112
return false;
@@ -114,44 +118,28 @@ pub(crate) fn should_prerender(req: &ServiceRequest) -> bool {
114118
#[derive(Debug)]
115119
pub struct PrerenderMiddleware<S> {
116120
pub(crate) service: S,
117-
prerender_service_url: Url,
118-
inner_client: Client,
121+
inner: Rc<Inner>,
119122
}
120123

121124
impl<S> PrerenderMiddleware<S> {
122-
pub fn prepare_build_api_url(&self, req: &ServiceRequest) -> String {
125+
pub fn prepare_build_api_url(service_url: &Url, req: &ServiceRequest) -> String {
123126
let req_uri = req.uri();
124127
let req_headers = req.headers();
125128

126-
// TODO: this.host?
127129
let host = req
128130
.uri()
129131
.host()
130-
.or_else(|| {
131-
req_headers
132-
.get("X-Forwarded-Host")
133-
.and_then(|hdr| hdr.to_str().ok())
134-
})
135-
.or_else(|| {
136-
req_headers
137-
.get(header::HOST)
138-
.and_then(|hdr| hdr.to_str().ok())
139-
})
132+
.or_else(|| req_headers.get("X-Forwarded-Host").and_then(|hdr| hdr.to_str().ok()))
133+
.or_else(|| req_headers.get(header::HOST).and_then(|hdr| hdr.to_str().ok()))
140134
.unwrap();
141135

142136
let scheme = req.uri().scheme_str().unwrap_or("http");
143137
let url_path_query = req_uri.path_and_query().map(PathAndQuery::as_str).unwrap();
144138

145-
format!(
146-
"{}{}://{}{}",
147-
self.prerender_service_url, scheme, host, url_path_query
148-
)
139+
format!("{}{}://{}{}", service_url, scheme, host, url_path_query)
149140
}
150141

151-
pub async fn get_rendered_response(
152-
&self,
153-
req: ServiceRequest,
154-
) -> Result<ServiceResponse, PrerenderError> {
142+
pub async fn get_rendered_response(inner: &Inner, req: ServiceRequest) -> Result<ServiceResponse, PrerenderError> {
155143
let mut prerender_request_headers = HeaderMap::new();
156144
let forward_headers = true;
157145

@@ -161,19 +149,20 @@ impl<S> PrerenderMiddleware<S> {
161149
}
162150

163151
prerender_request_headers.append(header::ACCEPT_ENCODING, "gzip".parse().unwrap());
152+
prerender_request_headers.append(
153+
"X-Prerender-Token".parse().unwrap(),
154+
inner.prerender_token.parse().unwrap(),
155+
);
164156

165-
// TODO: accept `X-Prerender-Token`
166-
// prerender_request_headers.insert("X-Prerender-Token", pre_render_token);
167-
168-
let url_to_request = self.prepare_build_api_url(&req);
169-
let prerender_response = self
157+
let url_to_request = Self::prepare_build_api_url(&inner.prerender_service_url, &req);
158+
let prerender_response = inner
170159
.inner_client
171160
.get(url_to_request)
172161
.send()
173-
.and_then(|a| a.bytes())
162+
.and_then(|resp| resp.bytes())
174163
.await?;
175164

176-
let http_response = HttpResponse::Ok().body(prerender_response);
165+
let http_response = HttpResponse::Ok().content_type("text/html").body(prerender_response);
177166
Ok(req.into_response(http_response))
178167
}
179168
}
@@ -196,8 +185,8 @@ where
196185
return Box::pin(async move { fut.await });
197186
}
198187

199-
// let response = self.get_rendered_response(req).await.map_err(|e| );
200-
todo!()
188+
let inner = Rc::clone(&self.inner);
189+
Box::pin(async move { Self::get_rendered_response(&inner, req).await.map_err(Into::into) })
201190
}
202191
}
203192

@@ -215,27 +204,28 @@ where
215204
fn new_transform(&self, service: S) -> Self::Future {
216205
future::ok(PrerenderMiddleware {
217206
service,
218-
prerender_service_url: self.prerender_service_url.clone(),
219-
inner_client: self.inner_client.clone(),
207+
inner: Rc::clone(&self.inner),
220208
})
221209
}
222210
}
223211

224212
#[cfg(test)]
225213
mod tests {
226-
use crate::middleware::{prerender_url, should_prerender, Prerender, PrerenderMiddleware};
227-
use actix_service::Transform;
214+
228215
use actix_web::http::header;
229216
use actix_web::middleware::Compat;
230217
use actix_web::test::TestRequest;
231-
use actix_web::{test, App};
218+
use actix_web::App;
219+
220+
use crate::middleware::{prerender_url, should_prerender, Prerender, PrerenderMiddleware};
232221

233-
fn init_logger() {
222+
fn _init_logger() {
234223
let _ = env_logger::builder().is_test(true).try_init();
235224
}
236225

237-
fn compat_compat() {
238-
let _ = App::new().wrap(Compat::new(Prerender::builder().use_prerender_io()));
226+
#[actix_web::test]
227+
async fn compat_compat() {
228+
App::new().wrap(Compat::new(Prerender::builder().use_prerender_io("".to_string())));
239229
}
240230

241231
#[actix_web::test]
@@ -292,8 +282,8 @@ mod tests {
292282
assert!(!render);
293283
}
294284

295-
fn create_middleware() -> Prerender {
296-
Prerender::builder().use_prerender_io()
285+
fn _create_middleware() -> Prerender {
286+
Prerender::builder().use_prerender_io("".to_string())
297287
}
298288

299289
#[actix_web::test]
@@ -308,13 +298,13 @@ mod tests {
308298
.uri(req_url)
309299
.to_srv_request();
310300

311-
let middleware = create_middleware()
312-
.new_transform(test::ok_service())
313-
.into_inner()
314-
.unwrap();
301+
// let middleware = create_middleware()
302+
// .new_transform(test::ok_service())
303+
// .into_inner()
304+
// .unwrap();
315305

316306
assert_eq!(
317-
middleware.prepare_build_api_url(&req),
307+
PrerenderMiddleware::<()>::prepare_build_api_url(&prerender_url(), &req),
318308
format!("{}{}", prerender_url(), req_url)
319309
);
320310
}

0 commit comments

Comments
 (0)