1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
use crate::*;
pub fn mount_php(
extensions: &mut Extensions,
connection: Connection,
capture_fn: Option<impl Fn(&FatRequest, &Host) -> bool + Send + Sync + 'static>,
) {
extensions.add_prepare_fn(
Box::new(move |req, host| {
(!host.options.disable_fs && req.uri().path().ends_with(".php"))
|| (capture_fn.as_ref().map_or(false, |f| f(req, host)))
}),
prepare!(req, host, path, addr, move |connection: Connection| {
php(req, host, path, addr, *connection).await
}),
extensions::Id::new(-8, "PHP"),
);
}
fn php<'a>(
req: &'a mut FatRequest,
host: &'a Host,
path: Option<&'a Path>,
address: SocketAddr,
connection: Connection,
) -> RetFut<'a, FatResponse> {
box_fut!({
if let Some(path) = path {
if !path.exists() {
return default_error_response(StatusCode::NOT_FOUND, host, None).await;
}
let body = match req.body_mut().read_to_bytes().await {
Ok(body) => body,
Err(_) => {
return FatResponse::cache(
default_error(
StatusCode::BAD_REQUEST,
Some(host),
Some("failed to read body".as_bytes()),
)
.await,
)
}
};
let output = match fastcgi::from_prepare(req, &body, path, address, connection).await {
Ok(vec) => vec,
Err(err) => {
error!("FastCGI failed. {}", err);
return default_error_response(StatusCode::INTERNAL_SERVER_ERROR, host, None)
.await;
}
};
let output = Bytes::copy_from_slice(&output);
match async_bits::read::response_php(&output) {
Ok(response) => FatResponse::cache(response),
Err(err) => {
error!("failed to parse response; {}", err.as_str());
default_error_response(StatusCode::NOT_FOUND, host, None).await
}
}
} else {
error!("Path is none. This is a internal guarantee error.");
default_error_response(StatusCode::INTERNAL_SERVER_ERROR, host, None).await
}
})
}
#[cfg(test)]
mod tests {
use kvarn_testing::prelude::*;
#[tokio::test]
async fn no_fs() {
let server = ServerBuilder::from(crate::new())
.with_options(|options| {
options.disable_fs();
})
.run()
.await;
let response = server.get("index.php").send().await.unwrap();
assert_eq!(response.status(), StatusCode::NOT_FOUND);
}
}