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 588900b
Showing 1 changed file with 6 additions and 4 deletions.
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

0 comments on commit 588900b

Please sign in to comment.