Merge branch '20647-cr-logs-preflight'
[arvados.git] / lib / controller / localdb / container_gateway.go
index 9526c01f8e66cefd2bcb44a662921011bf91a8d0..0b6a630faea3707a2fdf59164cf2f96e04750644 100644 (file)
@@ -183,6 +183,8 @@ func (conn *Conn) ContainerRequestLog(ctx context.Context, opts arvados.Containe
                                        // an attacker-in-the-middle.
                                        return httpserver.ErrorWithStatus(errors.New("bad X-Arvados-Authorization-Response header"), http.StatusBadGateway)
                                }
+                               resp.Header.Del("X-Arvados-Authorization-Response")
+                               preemptivelyDeduplicateHeaders(w.Header(), resp.Header)
                                return nil
                        },
                        ErrorHandler: func(w http.ResponseWriter, r *http.Request, err error) {
@@ -273,6 +275,10 @@ func (conn *Conn) serveContainerRequestLogViaKeepWeb(opts arvados.ContainerLogOp
                                r.Header.Set("X-Webdav-Source", "/log for container "+opts.Path[1:28]+"/")
                        }
                },
+               ModifyResponse: func(resp *http.Response) error {
+                       preemptivelyDeduplicateHeaders(w.Header(), resp.Header)
+                       return nil
+               },
        }
        if conn.cluster.TLS.Insecure {
                proxy.Transport = &http.Transport{
@@ -284,6 +290,31 @@ func (conn *Conn) serveContainerRequestLogViaKeepWeb(opts arvados.ContainerLogOp
        proxy.ServeHTTP(w, r)
 }
 
+// httputil.ReverseProxy uses (http.Header)Add() to copy headers from
+// the upstream Response to the downstream ResponseWriter. If headers
+// have already been set on the downstream ResponseWriter, Add() will
+// result in duplicate headers. For example, if we set CORS headers
+// and then use ReverseProxy with an upstream that also sets CORS
+// headers, our client will receive
+//
+//     Access-Control-Allow-Origin: *
+//     Access-Control-Allow-Origin: *
+//
+// ...which is incorrect.
+//
+// preemptivelyDeduplicateHeaders, when called from a ModifyResponse
+// hook, solves this by removing any conflicting headers from
+// ResponseWriter. This way, when ReverseProxy calls Add(), it will
+// assign the new values without causing duplicates.
+//
+// dst is the downstream ResponseWriter's Header(). src is the
+// upstream resp.Header.
+func preemptivelyDeduplicateHeaders(dst, src http.Header) {
+       for hdr := range src {
+               dst.Del(hdr)
+       }
+}
+
 // serveEmptyDir handles read-only webdav requests as if there was an
 // empty collection rooted at the given path. It's equivalent to
 // proxying to an empty collection in keep-web, but avoids the extra