Repository: actix/actix-web
File: actix-files/src/service.rs (Rust)

Code before:
impl Service<ServiceRequest> for FilesService {
    type Response = ServiceResponse;
    type Error = Error;
    type Future = LocalBoxFuture<'static, Result<ServiceResponse, Error>>;

    actix_service::always_ready!();

    fn call(&self, req: ServiceRequest) -> Self::Future {
        let is_method_valid = if let Some(guard) = &self.guards {
            // execute user defined guards
            (**guard).check(req.head())
        } else {
            // default behavior
            matches!(*req.method(), Method::HEAD | Method::GET)
        };

        if !is_method_valid {
            return Box::pin(ok(req.into_response(
                actix_web::HttpResponse::MethodNotAllowed()
                    .insert_header(header::ContentType(mime::TEXT_PLAIN_UTF_8))
                    .body("Request did not meet this resource's requirements."),
            )));
        }

        let path_decoded =
            percent_encoding::percent_decode_str(req.match_info().path()).decode_utf8_lossy();

        let real_path = match PathBufWrap::parse_path(&path_decoded, self.hidden_files) {
            Ok(item) => item,
            Err(e) => return Box::pin(ok(req.error_response(e))),
        };

        if let Some(filter) = &self.path_filter {
            if !filter(real_path.as_ref(), req.head()) {
                if let Some(ref default) = self.default {
                    return Box::pin(default.call(req));
                } else {
                    return Box::pin(ok(
                        req.into_response(actix_web::HttpResponse::NotFound().finish())
                    ));
                }
            }
        }

        // full file path
        let path = self.directory.join(&real_path);
        if let Err(err) = path.canonicalize() {
            return Box::pin(self.handle_err(err, req));
        }

        if path.is_dir() {

Review comment (bug):
This is a potential security problem. Would prefer a failed decode to return a 400 response.

Code after:
        log::debug!("error handling {}: {}", req.path(), err);

        if let Some(ref default) = self.default {
            default.call(req).await
        } else {
            Ok(req.error_response(err))
        }
    }

    fn serve_named_file(
        &self,
        req: ServiceRequest,
        mut named_file: NamedFile,
    ) -> ServiceResponse {
        if let Some(ref mime_override) = self.mime_override {
            let new_disposition = mime_override(&named_file.content_type.type_());
            named_file.content_disposition.disposition = new_disposition;
        }
        named_file.flags = self.file_flags;

        let (req, _) = req.into_parts();
        let res = named_file.into_response(&req);
        ServiceResponse::new(req, res)
    }

    fn show_index(&self, req: ServiceRequest, path: PathBuf) -> ServiceResponse {
        let dir = Directory::new(self.directory.clone(), path);

        let (req, _) = req.into_parts();

        (self.renderer)(&dir, &req).unwrap_or_else(|e| ServiceResponse::from_err(e, req))
    }
}

impl fmt::Debug for FilesService {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str("FilesService")
    }
}

impl Service<ServiceRequest> for FilesService {
    type Response = ServiceResponse<BoxBody>;
    type Error = Error;
    type Future = LocalBoxFuture<'static, Result<Self::Response, Self::Error>>;

    actix_service::always_ready!();

    fn call(&self, req: ServiceRequest) -> Self::Future {
        let is_method_valid = if let Some(guard) = &self.guards {
            // execute user defined guards
            (**guard).check(&req.guard_ctx())