v0.26.0
This commit is contained in:
1 parent
d168ee2afa
commit
ddc5c6593f
70 files changed
+2293
-594
No files matched your search
@@ -2,11 +2,11 @@ use super::{
|
||||
config::{CompiledPhp, FastCgiEndpoint, MAX_HEADER_VALUE_BYTES},
|
||||
filesystem::path_components,
|
||||
htaccess,
|
||||
response::{builtin_error_response, status_response},
|
||||
request::server_protocol,
|
||||
response::{builtin_error_response, status_response},
|
||||
CompiledService, RequestContext,
|
||||
};
|
||||
use anyhow::{Context, ensure, Result};
|
||||
use anyhow::{ensure, Context, Result};
|
||||
use axum::{body::Body, response::Response};
|
||||
use bytes::Bytes;
|
||||
use futures_util::stream;
|
||||
@@ -38,9 +38,7 @@ impl<T> FastCgiIo for T where T: AsyncRead + AsyncWrite + Unpin + Send {}
|
||||
async fn connect_fastcgi(endpoint: &FastCgiEndpoint) -> io::Result<Box<dyn FastCgiIo>> {
|
||||
match endpoint {
|
||||
#[cfg(unix)]
|
||||
FastCgiEndpoint::Unix(path) => {
|
||||
Ok(Box::new(tokio::net::UnixStream::connect(path).await?))
|
||||
}
|
||||
FastCgiEndpoint::Unix(path) => Ok(Box::new(tokio::net::UnixStream::connect(path).await?)),
|
||||
FastCgiEndpoint::Tcp(address) => {
|
||||
Ok(Box::new(tokio::net::TcpStream::connect(address).await?))
|
||||
}
|
||||
@@ -95,7 +93,6 @@ fn encode_fcgi_param(target: &mut Vec<u8>, name: &str, value: &str) -> io::Resul
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
fn fastcgi_header_param(name: &HeaderName) -> Option<String> {
|
||||
let lower = name.as_str();
|
||||
if matches!(
|
||||
@@ -147,32 +144,45 @@ pub(super) fn fastcgi_params(
|
||||
params.insert("QUERY_STRING".into(), query.unwrap_or("").into());
|
||||
params.insert("REQUEST_URI".into(), request_uri.into());
|
||||
params.insert("DOCUMENT_ROOT".into(), document_root);
|
||||
params.insert("SERVER_PROTOCOL".into(), server_protocol(context.version).into());
|
||||
params.insert(
|
||||
"SERVER_PROTOCOL".into(),
|
||||
server_protocol(context.version).into(),
|
||||
);
|
||||
params.insert("SERVER_NAME".into(), context.server_name.clone());
|
||||
params.insert("SERVER_PORT".into(), context.server_port.to_string());
|
||||
params.insert("REMOTE_ADDR".into(), context.client_ip.to_string());
|
||||
if let Some(port) = context.client_port {
|
||||
params.insert("REMOTE_PORT".into(), port.to_string());
|
||||
}
|
||||
params.insert("HTTPS".into(), if context.tls { "on" } else { "off" }.into());
|
||||
params.insert(
|
||||
"HTTPS".into(),
|
||||
if context.tls { "on" } else { "off" }.into(),
|
||||
);
|
||||
params.insert("GATEWAY_INTERFACE".into(), "CGI/1.1".into());
|
||||
params.insert("SERVER_SOFTWARE".into(), "RustProxy/0.25.7".into());
|
||||
params.insert("SERVER_SOFTWARE".into(), "RustProxy/0.26.0".into());
|
||||
params.insert("REDIRECT_STATUS".into(), "200".into());
|
||||
if let Some(value) = headers.get(CONTENT_TYPE).and_then(|value| value.to_str().ok()) {
|
||||
if let Some(value) = headers
|
||||
.get(CONTENT_TYPE)
|
||||
.and_then(|value| value.to_str().ok())
|
||||
{
|
||||
params.insert("CONTENT_TYPE".into(), value.into());
|
||||
}
|
||||
if let Some(value) = headers.get(CONTENT_LENGTH).and_then(|value| value.to_str().ok()) {
|
||||
if let Some(value) = headers
|
||||
.get(CONTENT_LENGTH)
|
||||
.and_then(|value| value.to_str().ok())
|
||||
{
|
||||
params.insert("CONTENT_LENGTH".into(), value.into());
|
||||
}
|
||||
for (name, value) in headers {
|
||||
// HTTP_PROXY is a well-known CGI/FastCGI injection vector (httpoxy).
|
||||
// This must never depend on the optional Web Service hardening switch.
|
||||
if name.as_str() == "proxy"
|
||||
|| (!php.pass_authorization && name.as_str() == "authorization")
|
||||
if name.as_str() == "proxy" || (!php.pass_authorization && name.as_str() == "authorization")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
let Some(param) = fastcgi_header_param(name) else { continue };
|
||||
let Some(param) = fastcgi_header_param(name) else {
|
||||
continue;
|
||||
};
|
||||
let Ok(value) = value.to_str() else { continue };
|
||||
if value.len() > MAX_HEADER_VALUE_BYTES {
|
||||
continue;
|
||||
@@ -224,7 +234,8 @@ pub(super) async fn read_fcgi_record(
|
||||
tokio::time::timeout_at(deadline, io.read_exact(&mut header))
|
||||
.await
|
||||
.map_err(|_| io::Error::new(io::ErrorKind::TimedOut, "FastCGI response timeout"))??;
|
||||
if header[0] != FCGI_VERSION_1 || u16::from_be_bytes([header[2], header[3]]) != FCGI_REQUEST_ID {
|
||||
if header[0] != FCGI_VERSION_1 || u16::from_be_bytes([header[2], header[3]]) != FCGI_REQUEST_ID
|
||||
{
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidData,
|
||||
"invalid FastCGI record header",
|
||||
@@ -325,7 +336,10 @@ async fn drain_fastcgi_body(
|
||||
loop {
|
||||
match read_fcgi_record(io.as_mut(), deadline).await {
|
||||
Ok((FCGI_STDOUT, content)) => {
|
||||
if send_body && !content.is_empty() && tx.send(Ok(Bytes::from(content))).await.is_err() {
|
||||
if send_body
|
||||
&& !content.is_empty()
|
||||
&& tx.send(Ok(Bytes::from(content))).await.is_err()
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,7 +85,8 @@ pub(super) async fn file_response(
|
||||
if let Some(range) = range {
|
||||
response.headers_mut().insert(
|
||||
CONTENT_RANGE,
|
||||
HeaderValue::from_str(&format!("bytes {}-{}/{length}", range.start, range.end)).unwrap(),
|
||||
HeaderValue::from_str(&format!("bytes {}-{}/{length}", range.start, range.end))
|
||||
.unwrap(),
|
||||
);
|
||||
}
|
||||
add_validators(&mut response, etag.as_deref(), modified);
|
||||
@@ -173,14 +174,18 @@ pub(super) fn directory_listing(path: &str, entries: &[DirectoryEntry]) -> Vec<u
|
||||
}
|
||||
let href = html_escape(&href);
|
||||
let slash = if entry.directory { "/" } else { "" };
|
||||
let class = if entry.directory { "entry directory" } else { "entry file" };
|
||||
let class = if entry.directory {
|
||||
"entry directory"
|
||||
} else {
|
||||
"entry file"
|
||||
};
|
||||
let kind = if entry.directory { "Directory" } else { "File" };
|
||||
let type_label = if entry.directory { "DIR" } else { "FILE" };
|
||||
html.push_str(&format!(
|
||||
"<a class=\"{class}\" href=\"{href}\"><span class=\"type\">{type_label}</span><span class=\"name\">{label}{slash}</span><span class=\"kind\">{kind}</span></a>"
|
||||
));
|
||||
}
|
||||
html.push_str(r#"</div></section><footer class="page-footer"><span>RustProxy <b>0.25.7</b></span><span>Web Server · Directory listing</span></footer></main></body></html>"#);
|
||||
html.push_str(r#"</div></section><footer class="page-footer"><span>RustProxy <b>0.26.0</b></span><span>Web Server · Directory listing</span></footer></main></body></html>"#);
|
||||
html.into_bytes()
|
||||
}
|
||||
|
||||
|
||||
@@ -202,7 +202,7 @@ async fn empty_index_can_go_directly_to_directory_listing() {
|
||||
let body = std::str::from_utf8(&body).unwrap();
|
||||
assert!(body.contains("file.txt"));
|
||||
assert!(body.contains("DIRECTORY LISTING"));
|
||||
assert!(body.contains("RustProxy <b>0.25.7</b>"));
|
||||
assert!(body.contains("RustProxy <b>0.26.0</b>"));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
||||
Reference in new issue
Block a user