Skip to content

⚡ Bolt: Optimize security headers middleware with caching#205

Draft
EffortlessSteven wants to merge 1 commit intomainfrom
bolt-optimize-security-headers-8874080653256103478
Draft

⚡ Bolt: Optimize security headers middleware with caching#205
EffortlessSteven wants to merge 1 commit intomainfrom
bolt-optimize-security-headers-8874080653256103478

Conversation

@EffortlessSteven
Copy link
Member

This PR optimizes the security headers middleware by caching the parsed HeaderValue instances. Previously, the middleware parsed the configuration strings into HeaderValue on every request, which involves validation overhead. By parsing them once during initialization and storing them in an Arc<CachedSecurityHeaders>, we reduce the CPU cost of applying security headers. The original parsing logic is retained as a fallback.


PR created automatically by Jules for task 8874080653256103478 started by @EffortlessSteven

Pre-computes and caches `HeaderValue` instances in `SecurityHeadersConfig` to avoid parsing strings on every request. This improves middleware performance by eliminating repeated validation and allocation of header values.

- Adds `CachedSecurityHeaders` struct to store pre-parsed headers
- Adds `cached_headers` field to `SecurityHeadersConfig`
- Initializes cache in `from_sources` and `Default`
- Updates `apply_headers` to use the cache fast path
Copilot AI review requested due to automatic review settings February 16, 2026 08:03
@google-labs-jules
Copy link

👋 Jules, reporting for duty! I'm here to lend a hand with this pull request.

When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down.

I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job!

For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

@coderabbitai
Copy link

coderabbitai bot commented Feb 16, 2026

Walkthrough

Implements a header value caching optimization for security headers middleware. Introduces a CachedSecurityHeaders structure to store pre-computed HeaderValue instances and extends SecurityHeadersConfig with cache initialization and usage, reducing per-request parsing overhead.

Changes

Cohort / File(s) Summary
Documentation
.Jules/bolt.md
Dated entry documenting the optimization approach of pre-computing and caching constant HeaderValue instances via Arc in middleware to avoid repeated parsing per request.
Security Headers Caching Implementation
crates/app-http/src/middleware/security_headers.rs
Introduces CachedSecurityHeaders struct for storing optional HeaderValue entries. Extends SecurityHeadersConfig with cached_headers field and init_cache() method. Updates initialization paths to populate cache and modifies apply_headers flow to use cached headers when available with fallback to existing parsing path.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 Headers hop faster, pre-parsed with delight,
Arc shares the burden, no parsing each night,
The cache initialization sparkles so bright,
Fast paths and fallbacks keep everything right,
Performance leaps forward—pure optimization might! ✨


Note

🎁 Summarized by CodeRabbit Free

Your organization is on the Free plan. CodeRabbit will generate a high-level summary and a walkthrough for each pull request. For a comprehensive line-by-line review, please upgrade your subscription to CodeRabbit Pro by visiting https://app.coderabbit.ai/login.

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist
Copy link

Summary of Changes

Hello @EffortlessSteven, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces a significant performance improvement to the security headers middleware. By pre-parsing and caching the HeaderValue instances for static security header configurations, the system avoids redundant and CPU-intensive string parsing and validation on each incoming request. This change aims to reduce the computational load and improve the efficiency of applying security policies, ensuring that security measures are applied with minimal performance impact.

Highlights

  • Performance Optimization: The security headers middleware has been optimized to cache parsed HeaderValue instances, significantly reducing CPU overhead by avoiding repetitive parsing and validation on every request.
  • New Data Structure: A new CachedSecurityHeaders struct was introduced to store pre-computed HeaderValue instances for all configurable security headers.
  • Caching Mechanism: The SecurityHeadersConfig now includes an Arc<CachedSecurityHeaders> to hold and share the pre-parsed header values across requests, initialized during configuration loading.
  • Middleware Logic Update: The apply_headers method in the security headers middleware now prioritizes using the cached HeaderValue instances, falling back to on-the-fly parsing only if caching failed or was not initialized.
Changelog
  • .Jules/bolt.md
    • Added a new learning note documenting the benefits of pre-computing and caching constant HeaderValue instances to avoid parsing overhead.
  • crates/app-http/src/middleware/security_headers.rs
    • Introduced CachedSecurityHeaders struct to store pre-parsed HeaderValue instances for all security headers.
    • Added cached_headers field (an Option<Arc<CachedSecurityHeaders>>) to SecurityHeadersConfig to hold the cached values, marked with #[serde(skip)].
    • Implemented init_cache method within SecurityHeadersConfig to parse all configured header strings into HeaderValue and store them in the cached_headers field.
    • Modified Default::default() and SecurityHeadersConfig::from_sources to call init_cache upon configuration creation, ensuring headers are parsed once.
    • Updated the apply_headers method to first attempt to use the cached_headers for setting response headers, falling back to the original parsing logic if no cached values are available.
Activity
  • No human activity has occurred on this pull request yet.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

The pull request effectively optimizes the security headers middleware by introducing a caching mechanism for HeaderValue instances. This change correctly addresses the performance overhead of repeatedly parsing header strings on every request, leading to improved CPU efficiency. The implementation correctly handles initialization in both Default and from_sources methods, and includes a robust fallback to the original parsing logic if cached headers are not available. The addition of #[serde(skip)] for cached_headers is also appropriate.

Comment on lines +317 to +346
if let Some(val) = &cached.content_security_policy {
response.headers_mut().insert("Content-Security-Policy", val.clone());
}
if let Some(val) = &cached.x_frame_options {
response.headers_mut().insert("X-Frame-Options", val.clone());
}
if let Some(val) = &cached.x_content_type_options {
response.headers_mut().insert("X-Content-Type-Options", val.clone());
}
if let Some(val) = &cached.x_xss_protection {
response.headers_mut().insert("X-XSS-Protection", val.clone());
}
if let Some(val) = &cached.strict_transport_security {
response.headers_mut().insert("Strict-Transport-Security", val.clone());
}
if let Some(val) = &cached.referrer_policy {
response.headers_mut().insert("Referrer-Policy", val.clone());
}
if let Some(val) = &cached.permissions_policy {
response.headers_mut().insert("Permissions-Policy", val.clone());
}
if let Some(val) = &cached.cross_origin_embedder_policy {
response.headers_mut().insert("Cross-Origin-Embedder-Policy", val.clone());
}
if let Some(val) = &cached.cross_origin_opener_policy {
response.headers_mut().insert("Cross-Origin-Opener-Policy", val.clone());
}
if let Some(val) = &cached.cross_origin_resource_policy {
response.headers_mut().insert("Cross-Origin-Resource-Policy", val.clone());
}

Choose a reason for hiding this comment

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

medium

The apply_headers method contains a significant amount of repetitive code for inserting each header. This pattern can be refactored into a helper function to improve readability and reduce duplication. A similar helper could also be beneficial for the init_cache method to abstract away the HeaderValue::from_str calls, especially for Option<String> versus String fields, making the code more concise and less prone to copy-paste errors.

            insert_header_if_some(response, "Content-Security-Policy", &cached.content_security_policy);
            insert_header_if_some(response, "X-Frame-Options", &cached.x_frame_options);
            insert_header_if_some(response, "X-Content-Type-Options", &cached.x_content_type_options);
            insert_header_if_some(response, "X-XSS-Protection", &cached.x_xss_protection);
            insert_header_if_some(response, "Strict-Transport-Security", &cached.strict_transport_security);
            insert_header_if_some(response, "Referrer-Policy", &cached.referrer_policy);
            insert_header_if_some(response, "Permissions-Policy", &cached.permissions_policy);
            insert_header_if_some(response, "Cross-Origin-Embedder-Policy", &cached.cross_origin_embedder_policy);
            insert_header_if_some(response, "Cross-Origin-Opener-Policy", &cached.cross_origin_opener_policy);
            insert_header_if_some(response, "Cross-Origin-Resource-Policy", &cached.cross_origin_resource_policy);
            return;
        }

        // Helper function to insert a header if its value is Some
        fn insert_header_if_some(
            response: &mut Response,
            header_name: &str,
            header_value: &Option<HeaderValue>,
        ) {
            if let Some(val) = header_value {
                response.headers_mut().insert(header_name, val.clone());
            }
        }

        // Fallback to parsing (slow path, should only happen if not initialized)

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR optimizes the security headers middleware by pre-computing and caching parsed HeaderValue instances at configuration initialization time, eliminating the need to parse header values on every HTTP request. The optimization uses an Arc<CachedSecurityHeaders> structure to share the cached values efficiently across requests, while maintaining a fallback path for compatibility.

Changes:

  • Added CachedSecurityHeaders struct to hold pre-parsed HeaderValue instances for all security headers
  • Added cached_headers field to SecurityHeadersConfig with #[serde(skip)] to prevent serialization
  • Modified Default::default() and from_sources() to call init_cache() after construction
  • Implemented fast path in apply_headers() that uses cached values when available
  • Added .Jules/bolt.md documentation to record this optimization pattern

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
crates/app-http/src/middleware/security_headers.rs Adds header value caching infrastructure and fast path for applying headers using cached values
.Jules/bolt.md Documents the learning about pre-computing HeaderValue instances for static configuration

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +100 to +127
let cached = CachedSecurityHeaders {
content_security_policy: self
.content_security_policy
.as_ref()
.and_then(|s| HeaderValue::from_str(s).ok()),
x_frame_options: HeaderValue::from_str(&self.x_frame_options).ok(),
x_content_type_options: HeaderValue::from_str(&self.x_content_type_options).ok(),
x_xss_protection: HeaderValue::from_str(&self.x_xss_protection).ok(),
strict_transport_security: self
.strict_transport_security
.as_ref()
.and_then(|s| HeaderValue::from_str(s).ok()),
referrer_policy: HeaderValue::from_str(&self.referrer_policy).ok(),
permissions_policy: self
.permissions_policy
.as_ref()
.and_then(|s| HeaderValue::from_str(s).ok()),
cross_origin_embedder_policy: self
.cross_origin_embedder_policy
.as_ref()
.and_then(|s| HeaderValue::from_str(s).ok()),
cross_origin_opener_policy: self
.cross_origin_opener_policy
.as_ref()
.and_then(|s| HeaderValue::from_str(s).ok()),
cross_origin_resource_policy: HeaderValue::from_str(&self.cross_origin_resource_policy)
.ok(),
};
Copy link

Copilot AI Feb 16, 2026

Choose a reason for hiding this comment

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

The init_cache() method silently ignores parse errors using .ok(). If any of the configured header values are invalid and fail to parse, they will be silently skipped without any warning or error. This could lead to a security misconfiguration going unnoticed.

Consider logging a warning when header parsing fails during initialization, so operators are aware that their security headers configuration has invalid values. For example:

  • Log when HeaderValue::from_str() returns an error
  • Include which header failed and what the invalid value was

Copilot uses AI. Check for mistakes.
Comment on lines +318 to +345
response.headers_mut().insert("Content-Security-Policy", val.clone());
}
if let Some(val) = &cached.x_frame_options {
response.headers_mut().insert("X-Frame-Options", val.clone());
}
if let Some(val) = &cached.x_content_type_options {
response.headers_mut().insert("X-Content-Type-Options", val.clone());
}
if let Some(val) = &cached.x_xss_protection {
response.headers_mut().insert("X-XSS-Protection", val.clone());
}
if let Some(val) = &cached.strict_transport_security {
response.headers_mut().insert("Strict-Transport-Security", val.clone());
}
if let Some(val) = &cached.referrer_policy {
response.headers_mut().insert("Referrer-Policy", val.clone());
}
if let Some(val) = &cached.permissions_policy {
response.headers_mut().insert("Permissions-Policy", val.clone());
}
if let Some(val) = &cached.cross_origin_embedder_policy {
response.headers_mut().insert("Cross-Origin-Embedder-Policy", val.clone());
}
if let Some(val) = &cached.cross_origin_opener_policy {
response.headers_mut().insert("Cross-Origin-Opener-Policy", val.clone());
}
if let Some(val) = &cached.cross_origin_resource_policy {
response.headers_mut().insert("Cross-Origin-Resource-Policy", val.clone());
Copy link

Copilot AI Feb 16, 2026

Choose a reason for hiding this comment

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

The header names are being inserted as string literals instead of using HeaderName constants. For consistency with the rest of the codebase (see cors.rs which uses header::ACCESS_CONTROL_ALLOW_ORIGIN), these should use HeaderName constants or HeaderName::from_static(). This would also avoid the runtime parsing overhead of converting strings to header names on every request.

While most of these security headers don't have constants in the standard http crate, you should use HeaderName::from_static() for all of them to be consistent with how other parts of the codebase handle custom headers (e.g., request_id.rs uses HeaderName::from_static("x-request-id")).

Copilot uses AI. Check for mistakes.
Comment on lines +317 to +345
if let Some(val) = &cached.content_security_policy {
response.headers_mut().insert("Content-Security-Policy", val.clone());
}
if let Some(val) = &cached.x_frame_options {
response.headers_mut().insert("X-Frame-Options", val.clone());
}
if let Some(val) = &cached.x_content_type_options {
response.headers_mut().insert("X-Content-Type-Options", val.clone());
}
if let Some(val) = &cached.x_xss_protection {
response.headers_mut().insert("X-XSS-Protection", val.clone());
}
if let Some(val) = &cached.strict_transport_security {
response.headers_mut().insert("Strict-Transport-Security", val.clone());
}
if let Some(val) = &cached.referrer_policy {
response.headers_mut().insert("Referrer-Policy", val.clone());
}
if let Some(val) = &cached.permissions_policy {
response.headers_mut().insert("Permissions-Policy", val.clone());
}
if let Some(val) = &cached.cross_origin_embedder_policy {
response.headers_mut().insert("Cross-Origin-Embedder-Policy", val.clone());
}
if let Some(val) = &cached.cross_origin_opener_policy {
response.headers_mut().insert("Cross-Origin-Opener-Policy", val.clone());
}
if let Some(val) = &cached.cross_origin_resource_policy {
response.headers_mut().insert("Cross-Origin-Resource-Policy", val.clone());
Copy link

Copilot AI Feb 16, 2026

Choose a reason for hiding this comment

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

The cached HeaderValues are being cloned on every request with val.clone(). Since HeaderValue implements Clone cheaply (it uses Arc internally for the value data), this is acceptable but not optimal. However, to truly minimize overhead, consider storing the header name-value pairs together in the cache so you can insert them without any cloning at all. Alternatively, document that the clone is cheap due to Arc to clarify this is intentional.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants