Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 17 additions & 16 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ members = [
]

[workspace.package]
version = "0.1.194"
version = "0.1.195"
Copy link

Copilot AI Jan 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The workspace/package version here is 0.1.195, but the PR description and release notes text refer to v0.1.200. To avoid confusion when publishing and tagging, please align this version number with the version referenced in the release notes (or adjust the notes if 0.1.195 is the intended release).

Copilot uses AI. Check for mistakes.
edition = "2021"
authors = ["RustAPI Contributors"]
license = "MIT OR Apache-2.0"
Expand Down Expand Up @@ -120,3 +120,4 @@ rustls-pemfile = "2.2"
rcgen = "0.13"



2 changes: 2 additions & 0 deletions crates/rustapi-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ h3-quinn = { version = "0.0.10", optional = true }
rustls = { workspace = true, optional = true }
rustls-pemfile = { workspace = true, optional = true }
rcgen = { workspace = true, optional = true }
chrono = "0.4.43"

[dev-dependencies]
tokio = { workspace = true, features = ["macros", "rt-multi-thread"] }
Expand All @@ -98,3 +99,4 @@ http3 = ["dep:quinn", "dep:h3", "dep:h3-quinn", "dep:rustls", "dep:rustls-pemfil
http3-dev = ["http3", "dep:rcgen"]



64 changes: 62 additions & 2 deletions crates/rustapi-core/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ pub struct RustApi {
interceptors: InterceptorChain,
#[cfg(feature = "http3")]
http3_config: Option<crate::http3::Http3Config>,
status_config: Option<crate::status::StatusConfig>,
}

impl RustApi {
Expand Down Expand Up @@ -61,6 +62,7 @@ impl RustApi {
interceptors: InterceptorChain::new(),
#[cfg(feature = "http3")]
http3_config: None,
status_config: None,
}
}

Expand Down Expand Up @@ -869,6 +871,54 @@ impl RustApi {
.route(path, docs_router)
}

/// Enable automatic status page with default configuration
pub fn status_page(self) -> Self {
self.status_page_with_config(crate::status::StatusConfig::default())
}

/// Enable automatic status page with custom configuration
pub fn status_page_with_config(mut self, config: crate::status::StatusConfig) -> Self {
self.status_config = Some(config);
self
}
Comment on lines +874 to +883
Copy link

Copilot AI Jan 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Enabling the status page here unconditionally exposes a /status (or configured) endpoint with detailed per-route metrics and uptime, and there is no authentication or feature gating around it. For production deployments, this can leak internal routing and performance information; it would be safer to either (a) document clearly that this should be disabled or protected in production, or (b) provide a way to plug this endpoint behind existing auth/guard middleware.

Copilot uses AI. Check for mistakes.
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot open a new pull request to apply changes based on this feedback


// Helper to apply status page logic (monitor, layer, route)
fn apply_status_page(&mut self) {
if let Some(config) = &self.status_config {
let monitor = std::sync::Arc::new(crate::status::StatusMonitor::new());

// 1. Add middleware layer
self.layers
.push(Box::new(crate::status::StatusLayer::new(monitor.clone())));

// 2. Add status route
use crate::router::MethodRouter;
use std::collections::HashMap;

let monitor = monitor.clone();
let config = config.clone();
let path = config.path.clone(); // Clone path before moving config

let handler: crate::handler::BoxedHandler = std::sync::Arc::new(move |_| {
let monitor = monitor.clone();
let config = config.clone();
Box::pin(async move {
crate::status::status_handler(monitor, config)
.await
.into_response()
})
});

let mut handlers = HashMap::new();
handlers.insert(http::Method::GET, handler);
let method_router = MethodRouter::from_boxed(handlers);

// We need to take the router out to call route() which consumes it
let router = std::mem::take(&mut self.router);
self.router = router.route(&path, method_router);
}
}

/// Run the server
///
/// # Example
Expand All @@ -880,6 +930,9 @@ impl RustApi {
/// .await
/// ```
pub async fn run(mut self, addr: &str) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
// Apply status page if configured
self.apply_status_page();

// Apply body limit layer if configured (should be first in the chain)
if let Some(limit) = self.body_limit {
// Prepend body limit layer so it's the first to process requests
Expand All @@ -899,9 +952,10 @@ impl RustApi {
where
F: std::future::Future<Output = ()> + Send + 'static,
{
// Apply body limit layer if configured (should be first in the chain)
// Apply status page if configured
self.apply_status_page();

if let Some(limit) = self.body_limit {
// Prepend body limit layer so it's the first to process requests
self.layers.prepend(Box::new(BodyLimitLayer::new(limit)));
}

Expand Down Expand Up @@ -944,6 +998,9 @@ impl RustApi {
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
use std::sync::Arc;

// Apply status page if configured
self.apply_status_page();

// Apply body limit layer if configured
if let Some(limit) = self.body_limit {
self.layers.prepend(Box::new(BodyLimitLayer::new(limit)));
Expand Down Expand Up @@ -980,6 +1037,9 @@ impl RustApi {
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
use std::sync::Arc;

// Apply status page if configured
self.apply_status_page();

// Apply body limit layer if configured
if let Some(limit) = self.body_limit {
self.layers.prepend(Box::new(BodyLimitLayer::new(limit)));
Expand Down
1 change: 1 addition & 0 deletions crates/rustapi-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ mod router;
mod server;
pub mod sse;
pub mod static_files;
pub mod status;
pub mod stream;
pub mod typed_path;
pub mod validation;
Expand Down
Loading
Loading