Skip to content

Commit

Permalink
waiProxy: Remove Content-Length for Encoded Responses
Browse files Browse the repository at this point in the history
This is a proper fix to #45.

In previous merge request (#45), for HTTP/2 connections, Content-Length
header is retained in order to avoid problems with Docker client rejecting
chunked encoding responses from Docker registry.

However, this approach failed when the upstream response was encoded
(e.g. with 'Content-Encoding: gzip' in header). The retained
'Content-Length' header then mismatched the actual content size after
decoding.

To fix this, we now strip the Content-Length header if Content-Encoding
header is present, along with our existing checks for cases where chunked
encoding is not used (HTTP/2 and HEAD requests).
  • Loading branch information
bjin committed Jun 6, 2024
1 parent 4e076eb commit 4aa43a2
Show file tree
Hide file tree
Showing 3 changed files with 11 additions and 5 deletions.
4 changes: 4 additions & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@

## 0.6.0.3

* Fix a regression introduced in 0.6.0.2: wrong 'Content-Length' header is preserved for responses with encoded content. [#47](https://github.com/fpco/http-reverse-proxy/pull/47)

## 0.6.0.2

* Fix docker registry reverse proxying by preserving the 'Content-Length' response header to HTTP/2 and HEAD requests. [#45](https://github.com/fpco/http-reverse-proxy/pull/45)
Expand Down
10 changes: 6 additions & 4 deletions Network/HTTP/ReverseProxy.hs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ import Data.Functor.Identity (Identity (..))
import Data.IORef
import Data.List.NonEmpty (NonEmpty (..))
import qualified Data.List.NonEmpty as NE
import Data.Maybe (fromMaybe, listToMaybe)
import Data.Maybe (fromMaybe, isNothing, listToMaybe)
import Data.Monoid (mappend, mconcat, (<>))
import Data.Set (Set)
import qualified Data.Set as Set
Expand Down Expand Up @@ -426,12 +426,14 @@ waiProxyToSettings getDest wps' manager req0 sendResponse = do
(awaitForever (\bs -> yield (Chunk $ fromByteString bs) >> yield Flush))
(wpsProcessBody wps req $ const () <$> res)
src = bodyReaderSource $ HC.responseBody res
noChunked = HT.httpMajor (WAI.httpVersion req) >= 2 || WAI.requestMethod req == HT.methodHead
headers = HC.responseHeaders res
notEncoded = isNothing (lookup "content-encoding" headers)
notChunked = HT.httpMajor (WAI.httpVersion req) >= 2 || WAI.requestMethod req == HT.methodHead
sendResponse $ WAI.responseStream
(HC.responseStatus res)
(filter (\(key, v) -> not (key `Set.member` strippedHeaders) ||
key == "content-length" && (noChunked || v == "0"))
(HC.responseHeaders res))
key == "content-length" && (notEncoded && notChunked || v == "0"))
headers)
(\sendChunk flush -> runConduit $ src .| conduit .| CL.mapM_ (\mb ->
case mb of
Flush -> flush
Expand Down
2 changes: 1 addition & 1 deletion http-reverse-proxy.cabal
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: http-reverse-proxy
version: 0.6.0.2
version: 0.6.0.3
synopsis: Reverse proxy HTTP requests, either over raw sockets or with WAI
description: Provides a simple means of reverse-proxying HTTP requests. The raw approach uses the same technique as leveraged by keter, whereas the WAI approach performs full request/response parsing via WAI and http-conduit.
homepage: https://github.com/fpco/http-reverse-proxy
Expand Down

0 comments on commit 4aa43a2

Please sign in to comment.