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
6 changes: 6 additions & 0 deletions internal/constants/global.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,9 @@ const (
InternalCacheErrCode = "i-x-ct-code"
InternalUpstreamAddr = "i-x-ups-addr"
)

// define flag constants
const (
FlagOn = "1" // gateway control flag ON
FlagOff = "0" // gateway control flag OFF
Comment on lines +22 to +23
Copy link

Copilot AI Feb 4, 2026

Choose a reason for hiding this comment

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

FlagOn / FlagOff are very generic exported names in a shared constants package, which makes it unclear what they apply to and increases the chance of future collisions/ambiguity. Consider using more specific names (e.g., GatewayFlagOn/GatewayFlagOff or ControlFlagOn/ControlFlagOff, or even feature-scoped constants like CacheErrCodeFlagOn).

Suggested change
FlagOn = "1" // gateway control flag ON
FlagOff = "0" // gateway control flag OFF
// GatewayControlFlagOn represents the "ON" value for gateway control flags.
GatewayControlFlagOn = "1"
// GatewayControlFlagOff represents the "OFF" value for gateway control flags.
GatewayControlFlagOff = "0"
// Deprecated: use GatewayControlFlagOn instead.
FlagOn = GatewayControlFlagOn
// Deprecated: use GatewayControlFlagOff instead.
FlagOff = GatewayControlFlagOff

Copilot uses AI. Check for mistakes.
)
22 changes: 15 additions & 7 deletions server/middleware/caching/caching.go
Original file line number Diff line number Diff line change
Expand Up @@ -387,13 +387,21 @@ func (c *Caching) doProxy(req *http.Request, subRequest bool) (*http.Response, e
c.md.Size = respRange.ObjSize

// error code cache feature.
if statusCode >= http.StatusBadRequest &&
resp.Header.Get(constants.InternalCacheErrCode) != "1" {
c.cacheable = false // 禁止缓存错误码缓存

copiedHeaders := make(http.Header)
xhttp.CopyHeader(copiedHeaders, resp.Header)
c.md.Headers = copiedHeaders
if statusCode >= http.StatusBadRequest {

// Caching is disabled
// restoring the default behavior for error codes.
if resp.Header.Get(constants.InternalCacheErrCode) != constants.FlagOn {
c.cacheable = false

copiedHeaders := make(http.Header)
xhttp.CopyHeader(copiedHeaders, resp.Header)
c.md.Headers = copiedHeaders
} else {
// Caching is allowed (or rather, not disabled),
// and the proxy error is suppressed
proxyErr = nil
Copy link

Copilot AI Feb 4, 2026

Choose a reason for hiding this comment

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

When InternalCacheErrCode == FlagOn, this branch suppresses proxyErr but does not update c.md.Headers. For subRequest == true and c.fileChanged == false, the later header sync (if c.fileChanged || !subRequest) will be skipped, so the metadata can keep stale/empty headers while c.md.Code is set to an error. That can cause cached error responses to be served with incorrect headers/content-length.

Consider always copying resp.Header into c.md.Headers when caching an error response is allowed (ideally replacing the map to avoid stale keys), even for sub-requests.

Suggested change
proxyErr = nil
proxyErr = nil
// Ensure metadata headers are updated for cached error responses.
copiedHeaders := make(http.Header)
xhttp.CopyHeader(copiedHeaders, resp.Header)
c.md.Headers = copiedHeaders

Copilot uses AI. Check for mistakes.
}
}

// `cacheable` means can write to cache storage
Expand Down
Loading