Skip to content

Invalid status codes returned from reverse_proxy when used with replace-response #6144

@ImpostorKeanu

Description

@ImpostorKeanu

I've been using the replace-response module alongside reverse_proxy recently and observed incorrect status codes being returned from the proxy, e.g., the origin responded with a 404 and the proxy responds with a 200.

flowchart
UA --> |Request| reverse_proxy --> |Request| Origin
Origin --> |404 Origin Response| reverse_proxy --> |200 Proxy Response| UA
Loading

After a bit of debugging, it looks like the call to copyResponse results in a flush action here, which causes a 200 status code to be written after http.ResponseController.Flush unwraps and writes to the replace-response's replaceWriter caddyhttp.responseRecorder.

edit: I mistakenly thought I had streaming enabled, which is why I originally referenced replaceWriter.

A potential fix would be to check for an Unwrap method on the response writer alongside the base one in reverseproxy.go. I've tested this locally but I'm not sure if it's the best solution. I'm also not entirely sure if this is even considered a bug. I know that flush_interval is available as a configuration and I haven't tested if it solves the issue, but it definitely was not an obvious solution to the behavior if it is.

edit: Setting flush_interval does not seem to correct the issue.

type unwrapper interface {
  Unwrap() http.ResponseWriter
}

func (h *Handler) finalizeResponse {
  //...
  // Line 955
  rw.WriteHeader(res.StatusCode)
  
  // Unwrap and write non-200 status code
  if rw, ok := rw.(unwrapper); res.StatusCode != http.StatusOK && ok {
	rw.Unwrap().WriteHeader(res.StatusCode)
  }

  if h.VerboseLogs {
	logger.Debug("wrote header")
  }

  err := h.copyResponse(rw, res.Body, h.flushInterval(req, res), logger)
  //...
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions