From 4699d6be18bbbcdfee10322e96528a5850a396ee Mon Sep 17 00:00:00 2001 From: Fernandez Ludovic Date: Thu, 29 Jun 2017 16:41:44 +0200 Subject: [PATCH] Fix proxying of unannounced trailers --- glide.lock | 6 +-- glide.yaml | 2 +- vendor/github.com/vulcand/oxy/forward/fwd.go | 46 +++++++++++++++----- 3 files changed, 39 insertions(+), 15 deletions(-) diff --git a/glide.lock b/glide.lock index f35a851c0..f8442e172 100644 --- a/glide.lock +++ b/glide.lock @@ -1,5 +1,5 @@ -hash: 9a62fe4058ef43ed185d96638322dd3d44ae21f7f65fae14c4c6d404876c2872 -updated: 2017-06-28T15:47:14.848940186+02:00 +hash: cebc972cf87c4b0a8f86801f38750c51b09c8dee3bf62bb48f8eaa6ab7946352 +updated: 2017-06-29T16:47:14.848940186+02:00 imports: - name: cloud.google.com/go version: 2e6a95edb1071d750f6d7db777bf66cd2997af6c @@ -409,7 +409,7 @@ imports: - name: github.com/vdemeester/docker-events version: be74d4929ec1ad118df54349fda4b0cba60f849b - name: github.com/vulcand/oxy - version: ad5bdb606fa9c64db267f0e43d63834908bdb05e + version: 7da864c1d53bd58165435bb78bbf8c01f01c8f4a repo: https://github.com/containous/oxy.git vcs: git subpackages: diff --git a/glide.yaml b/glide.yaml index b6323c01f..fc582e5e3 100644 --- a/glide.yaml +++ b/glide.yaml @@ -8,7 +8,7 @@ import: - package: github.com/cenk/backoff - package: github.com/containous/flaeg - package: github.com/vulcand/oxy - version: ad5bdb606fa9c64db267f0e43d63834908bdb05e + version: 7da864c1d53bd58165435bb78bbf8c01f01c8f4a repo: https://github.com/containous/oxy.git vcs: git subpackages: diff --git a/vendor/github.com/vulcand/oxy/forward/fwd.go b/vendor/github.com/vulcand/oxy/forward/fwd.go index 1e0cc74e6..28cb1e1c8 100644 --- a/vendor/github.com/vulcand/oxy/forward/fwd.go +++ b/vendor/github.com/vulcand/oxy/forward/fwd.go @@ -159,7 +159,9 @@ func (f *Forwarder) ServeHTTP(w http.ResponseWriter, req *http.Request) { // serveHTTP forwards HTTP traffic using the configured transport func (f *httpForwarder) serveHTTP(w http.ResponseWriter, req *http.Request, ctx *handlerContext) { start := time.Now().UTC() + response, err := f.roundTripper.RoundTrip(f.copyRequest(req, req.URL)) + if err != nil { ctx.log.Errorf("Error forwarding to %v, err: %v", req.URL, err) ctx.errHandler.ServeHTTP(w, req, err) @@ -169,6 +171,16 @@ func (f *httpForwarder) serveHTTP(w http.ResponseWriter, req *http.Request, ctx utils.CopyHeaders(w.Header(), response.Header) // Remove hop-by-hop headers. utils.RemoveHeaders(w.Header(), HopHeaders...) + + announcedTrailerKeyCount := len(response.Trailer) + if announcedTrailerKeyCount > 0 { + trailerKeys := make([]string, 0, announcedTrailerKeyCount) + for k := range response.Trailer { + trailerKeys = append(trailerKeys, k) + } + w.Header().Add("Trailer", strings.Join(trailerKeys, ", ")) + } + w.WriteHeader(response.StatusCode) stream := f.streamResponse @@ -179,6 +191,20 @@ func (f *httpForwarder) serveHTTP(w http.ResponseWriter, req *http.Request, ctx } } written, err := io.Copy(newResponseFlusher(w, stream), response.Body) + if err != nil { + ctx.log.Errorf("Error copying upstream response body: %v", err) + ctx.errHandler.ServeHTTP(w, req, err) + return + } + + defer response.Body.Close() + + forceSetTrailers := len(response.Trailer) != announcedTrailerKeyCount + shallowCopyTrailers(w.Header(), response.Trailer, forceSetTrailers) + + if written != 0 { + w.Header().Set(ContentLength, strconv.FormatInt(written, 10)) + } if req.TLS != nil { ctx.log.Infof("Round trip: %v, code: %v, duration: %v tls:version: %x, tls:resume:%t, tls:csuite:%x, tls:server:%v", @@ -192,17 +218,6 @@ func (f *httpForwarder) serveHTTP(w http.ResponseWriter, req *http.Request, ctx req.URL, response.StatusCode, time.Now().UTC().Sub(start)) } - defer response.Body.Close() - - if err != nil { - ctx.log.Errorf("Error copying upstream response Body: %v", err) - ctx.errHandler.ServeHTTP(w, req, err) - return - } - - if written != 0 { - w.Header().Set(ContentLength, strconv.FormatInt(written, 10)) - } } // copyRequest makes a copy of the specified request to be sent using the configured @@ -364,3 +379,12 @@ func isWebsocketRequest(req *http.Request) bool { } return containsHeader(Connection, "upgrade") && containsHeader(Upgrade, "websocket") } + +func shallowCopyTrailers(dstHeader, srcTrailer http.Header, forceSetTrailers bool) { + for k, vv := range srcTrailer { + if forceSetTrailers { + k = http.TrailerPrefix + k + } + dstHeader[k] = vv + } +}