Skip to content

Add custom response header hook - #110

Open
vibhor-aggr wants to merge 2 commits into
koajs:masterfrom
vibhor-aggr:feat/custom-response-headers
Open

vibhor-aggr wants to merge 2 commits into
koajs:masterfrom
vibhor-aggr:feat/custom-response-headers

Conversation

@vibhor-aggr

@vibhor-aggr vibhor-aggr commented Jun 17, 2026 •

Copy link
Copy Markdown

Closes #102.

This adds an optional setHeaders(ctx, file) hook that runs after the built-in static headers have been applied for a matched file. It lets applications add or override custom response headers while preserving the existing buffered, streamed, cache, and gzip behavior.

Verification:

  • ./node_modules/.bin/mocha --grep "custom headers"
  • npm test
  • git diff --check

Summary by Sourcery

Add a configurable hook to customize response headers for static file responses.

New Features:

  • Introduce an optional options.setHeaders(ctx, file) hook to allow custom response headers on cached static file responses.

Documentation:

  • Document the new options.setHeaders hook in the README with its purpose and signature.

Tests:

  • Add tests verifying custom headers are applied for both streamed and buffered static file responses.

Summary by CodeRabbit

  • New Features
    • Added an optional setHeaders(ctx, file) hook for staticCache, enabling custom response headers per matched cached file.
  • Documentation
    • Updated the README API documentation to describe the new setHeaders option and its parameters.
  • Tests
    • Added coverage to confirm setHeaders is invoked for both streamed and buffered responses, and that it also runs during conditional requests resulting in 304.

@coderabbitai

coderabbitai Bot commented Jun 17, 2026 •

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 2199c84e-20df-4d86-8a6b-4e03f6b9b79a

📥 Commits

Reviewing files that changed from the base of the PR and between b57dc74 and b91c0d6.

📒 Files selected for processing (2)
  • index.js
  • test/index.js
✅ Files skipped from review due to trivial changes (1)
  • test/index.js
🚧 Files skipped from review as they are similar to previous changes (1)
  • index.js

📝 Walkthrough

Walkthrough

The PR adds an optional setHeaders callback to koa-static-cache. The middleware reads options.setHeaders during initialization, then calls setHeaders(ctx, file) after setting lastModified and etag and before the HEAD early-return. The README documents the new option, and tests cover streamed responses, buffered responses, and a 304 conditional request path.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: adding a custom response header hook.
Linked Issues check ✅ Passed The PR implements the requested callback-style response header customization for the static-cache middleware.
Out of Scope Changes check ✅ Passed The changes stay focused on the header hook, its documentation, and tests, with no unrelated additions.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@sourcery-ai

sourcery-ai Bot commented Jun 17, 2026

Copy link
Copy Markdown

Reviewer's Guide

Adds an optional setHeaders(ctx, file) hook to the staticCache middleware that runs after standard static headers are applied, along with tests and README documentation demonstrating custom headers for both streamed and buffered files.

Sequence diagram for staticCache setHeaders hook

sequenceDiagram
  participant Client
  participant Koa as KoaApp
  participant staticCache
  participant ctx
  Client->>Koa: HTTP request
  Koa->>staticCache: staticCache(ctx, next)
  staticCache->>ctx: set(cache-control)
  staticCache->>ctx: set(content-md5)
  alt options.setHeaders is provided
    staticCache->>staticCache: setHeaders(ctx, file)
  end
  ctx-->>Client: HTTP response with headers
Loading

File-Level Changes

Change Details Files
Add optional setHeaders(ctx, file) hook to staticCache to allow custom response headers after built-in headers are set.
  • Derive a setHeaders function from options.setHeaders only when it is a function, otherwise default to null.
  • Invoke setHeaders(ctx, file) after setting cache-control and content-md5 headers, so custom logic can add or override headers while preserving existing behavior.
index.js
Add tests verifying custom headers behavior for streamed and buffered files using the new setHeaders hook.
  • Add a test that configures staticCache with setHeaders and filter, then asserts a custom X-Static-Cache header and inspects the provided file metadata for streamed responses.
  • Add a test that enables buffer mode, uses setHeaders to set an X-Static-Length header, and asserts both the header value and presence of the in-memory file buffer.
test/index.js
Document the new setHeaders option in the README.
  • Extend the options list with a description of options.setHeaders as an optional function (ctx, file) hook for setting custom response headers on matched files.
README.md

Assessment against linked issues

Issue Objective Addressed Explanation
#102 Add an option/callback to the middleware that allows users to set custom HTTP response headers for matched static files. ✅
#102 Document the new callback option for customizing HTTP response headers. ✅

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Hey - I've reviewed your changes and they look great!


Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
index.js (1)

99-105: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

setHeaders is skipped for conditional 304 responses.

For matched files with If-None-Match/If-Modified-Since, the early return at Line 99 bypasses the hook, so custom security headers are never applied on fresh-cache hits.

Suggested fix
-    if (ctx.fresh) return ctx.status = 304
+    if (ctx.fresh) {
+      if (setHeaders) setHeaders(ctx, file)
+      ctx.status = 304
+      return
+    }

     ctx.type = file.type
     ctx.length = file.zipBuffer ? file.zipBuffer.length : file.length
     ctx.set('cache-control', file.cacheControl || 'public, max-age=' + file.maxAge)
     if (file.md5) ctx.set('content-md5', file.md5)
     if (setHeaders) setHeaders(ctx, file)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@index.js` around lines 99 - 105, The setHeaders callback is being invoked
after the early return statement for fresh resources, causing it to be skipped
when ctx.fresh is true and a 304 status is returned. Move the setHeaders
invocation (the line with "if (setHeaders) setHeaders(ctx, file)") to execute
before the fresh resource check at the beginning of this block so that custom
headers are applied for both fresh-cache hits and regular responses.
🧹 Nitpick comments (1)
test/index.js (1)

253-304: ⚡ Quick win

Add a conditional-request regression test for setHeaders.

Current tests only validate 200 responses, so they won’t catch callback behavior on fresh-cache (304) requests.

Suggested test addition
+  it('should set custom headers for conditional requests', function (done) {
+    var app = new Koa()
+    app.use(staticCache(path.join(__dirname, '..'), {
+      setHeaders: function (ctx) {
+        ctx.set('X-Static-Conditional', '1')
+      },
+      filter(file) {
+        return !file.includes('node_modules')
+      }
+    }))
+
+    request(app.listen())
+    .get('/index.js')
+    .expect(200)
+    .expect('X-Static-Conditional', '1')
+    .end(function (err, res) {
+      if (err) return done(err)
+      request(app.listen())
+      .get('/index.js')
+      .set('If-None-Match', res.headers.etag)
+      .expect(304)
+      .expect('X-Static-Conditional', '1', done)
+    })
+  })
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/index.js` around lines 253 - 304, Add a new test case that validates the
setHeaders callback behavior for conditional requests returning 304 Not Modified
responses. Create a test similar to the existing streamed and buffered file
header tests, but make two consecutive requests to the same file where the
second request includes conditional headers (If-None-Match or If-Modified-Since)
to trigger a 304 response. Verify that the setHeaders callback is still invoked
during the 304 response and that the seenFile object is properly populated,
ensuring the callback works correctly for both fresh (200) and cached (304)
responses.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@index.js`:
- Around line 99-105: The setHeaders callback is being invoked after the early
return statement for fresh resources, causing it to be skipped when ctx.fresh is
true and a 304 status is returned. Move the setHeaders invocation (the line with
"if (setHeaders) setHeaders(ctx, file)") to execute before the fresh resource
check at the beginning of this block so that custom headers are applied for both
fresh-cache hits and regular responses.

---

Nitpick comments:
In `@test/index.js`:
- Around line 253-304: Add a new test case that validates the setHeaders
callback behavior for conditional requests returning 304 Not Modified responses.
Create a test similar to the existing streamed and buffered file header tests,
but make two consecutive requests to the same file where the second request
includes conditional headers (If-None-Match or If-Modified-Since) to trigger a
304 response. Verify that the setHeaders callback is still invoked during the
304 response and that the seenFile object is properly populated, ensuring the
callback works correctly for both fresh (200) and cached (304) responses.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 4b564def-5fe6-4650-853e-afb949eb21d4

📥 Commits

Reviewing files that changed from the base of the PR and between 182f260 and b57dc74.

📒 Files selected for processing (3)
  • README.md
  • index.js
  • test/index.js

@vibhor-aggr

Copy link
Copy Markdown
Author

Addressed the 304 path by running setHeaders(ctx, file) before the freshness return, so conditional cache hits receive the custom headers too. Added a regression test that performs an initial 200 request, follows with If-None-Match, verifies the 304 response carries the custom header, and confirms the callback still receives file metadata.

Local verification: focused custom-header Mocha tests passed, exact npm test passed on retry with 40 passing tests, and git diff --check master..HEAD passed.

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.

I need some callback function like setHeader to custom http response header

1 participant