From 49c15c550e652826642d2370695015615825bba5 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Fri, 4 Jan 2019 11:18:24 -0800 Subject: [PATCH 1/3] api: let the CORs library handle CORs headers License: MIT Signed-off-by: Steven Allen This commit was moved from ipfs/kubo@543be29796eee1e72280d22ddde12b57ef5c7ad7 --- gateway/core/corehttp/commands.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/gateway/core/corehttp/commands.go b/gateway/core/corehttp/commands.go index 99d3b3eff..aa2f51065 100644 --- a/gateway/core/corehttp/commands.go +++ b/gateway/core/corehttp/commands.go @@ -67,12 +67,17 @@ func addHeadersFromConfig(c *cmdsHttp.ServerConfig, nc *config.Config) { } } - c.Headers = make(map[string][]string, len(nc.API.HTTPHeaders)) + c.Headers = make(map[string][]string, len(nc.API.HTTPHeaders)+1) // Copy these because the config is shared and this function is called // in multiple places concurrently. Updating these in-place *is* racy. for h, v := range nc.API.HTTPHeaders { - c.Headers[h] = v + switch h { + case cmdsHttp.ACAOrigin, cmdsHttp.ACAMethods, cmdsHttp.ACACredentials: + // these are handled by the CORs library. + default: + c.Headers[h] = v + } } c.Headers["Server"] = []string{"go-ipfs/" + version.CurrentVersionNumber} } From faf068b9b758b9ae1daf522792cb8c2935470b93 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Fri, 4 Jan 2019 12:08:57 -0800 Subject: [PATCH 2/3] gateway: fix CORs headers fixes #5138 -- always add user-agent to access-control-allow-headers. fixes #5888 -- same with content-type. fixes #5892 -- extend user-provided headers instead of overriding them. License: MIT Signed-off-by: Steven Allen This commit was moved from ipfs/kubo@82629c00ec12e376e26b28d3551395d5e2dfb85c --- gateway/core/corehttp/gateway.go | 58 +++++++++++++++++++++++- gateway/core/corehttp/gateway_handler.go | 13 ------ 2 files changed, 57 insertions(+), 14 deletions(-) diff --git a/gateway/core/corehttp/gateway.go b/gateway/core/corehttp/gateway.go index 52560750a..ae3e035d8 100644 --- a/gateway/core/corehttp/gateway.go +++ b/gateway/core/corehttp/gateway.go @@ -4,6 +4,7 @@ import ( "fmt" "net" "net/http" + "sort" version "github.com/ipfs/go-ipfs" core "github.com/ipfs/go-ipfs/core" @@ -18,6 +19,26 @@ type GatewayConfig struct { PathPrefixes []string } +// A helper function to clean up a set of headers: +// 1. Canonicalizes. +// 2. Deduplicates. +// 3. Sorts. +func cleanHeaderSet(headers []string) []string { + // Deduplicate and canonicalize. + m := make(map[string]struct{}, len(headers)) + for _, h := range headers { + m[http.CanonicalHeaderKey(h)] = struct{}{} + } + result := make([]string, 0, len(m)) + for k := range m { + result = append(result, k) + } + + // Sort + sort.Strings(result) + return result +} + func GatewayOption(writable bool, paths ...string) ServeOption { return func(n *core.IpfsNode, _ net.Listener, mux *http.ServeMux) (*http.ServeMux, error) { cfg, err := n.Repo.Config() @@ -30,8 +51,43 @@ func GatewayOption(writable bool, paths ...string) ServeOption { return nil, err } + headers := make(map[string][]string, len(cfg.Gateway.HTTPHeaders)) + for h, v := range cfg.Gateway.HTTPHeaders { + headers[h] = v + } + + // Hard-coded headers. + const ACAHeadersName = "Access-Control-Allow-Headers" + const ACEHeadersName = "Access-Control-Expose-Headers" + const ACAOriginName = "Access-Control-Allow-Origin" + const ACAMethodsName = "Access-Control-Allow-Methods" + + if _, ok := headers[ACAOriginName]; !ok { + // Default to *all* + headers[ACAOriginName] = []string{"*"} + } + if _, ok := headers[ACAMethodsName]; !ok { + // Default to GET + headers[ACAMethodsName] = []string{"GET"} + } + + headers[ACAHeadersName] = cleanHeaderSet( + append([]string{ + "Content-Type", + "User-Agent", + "Range", + "X-Requested-With", + }, headers[ACAHeadersName]...)) + + headers[ACEHeadersName] = cleanHeaderSet( + append([]string{ + "Content-Range", + "X-Chunked-Output", + "X-Stream-Output", + }, headers[ACEHeadersName]...)) + gateway := newGatewayHandler(n, GatewayConfig{ - Headers: cfg.Gateway.HTTPHeaders, + Headers: headers, Writable: writable, PathPrefixes: cfg.Gateway.PathPrefixes, }, api) diff --git a/gateway/core/corehttp/gateway_handler.go b/gateway/core/corehttp/gateway_handler.go index 553ebdcf8..bb6ff51c4 100644 --- a/gateway/core/corehttp/gateway_handler.go +++ b/gateway/core/corehttp/gateway_handler.go @@ -184,19 +184,6 @@ func (i *gatewayHandler) getOrHeadHandler(ctx context.Context, w http.ResponseWr w.Header().Set("X-IPFS-Path", urlPath) w.Header().Set("Etag", etag) - // set 'allowed' headers - // & expose those headers - var allowedHeadersArr = []string{ - "Content-Range", - "X-Chunked-Output", - "X-Stream-Output", - } - - var allowedHeaders = strings.Join(allowedHeadersArr, ", ") - - w.Header().Set("Access-Control-Allow-Headers", allowedHeaders) - w.Header().Set("Access-Control-Expose-Headers", allowedHeaders) - // Suborigin header, sandboxes apps from each other in the browser (even // though they are served from the same gateway domain). // From f23457c632a4a63197db9c4a240410610ea53b45 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Fri, 4 Jan 2019 13:00:31 -0800 Subject: [PATCH 3/3] gateway, api: canonicalize headers from user config License: MIT Signed-off-by: Steven Allen This commit was moved from ipfs/kubo@4bbf4cc9a08a55f1e0f69447a06179f2106e48c0 --- gateway/core/corehttp/commands.go | 1 + gateway/core/corehttp/gateway.go | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/gateway/core/corehttp/commands.go b/gateway/core/corehttp/commands.go index aa2f51065..3b2a971b9 100644 --- a/gateway/core/corehttp/commands.go +++ b/gateway/core/corehttp/commands.go @@ -72,6 +72,7 @@ func addHeadersFromConfig(c *cmdsHttp.ServerConfig, nc *config.Config) { // Copy these because the config is shared and this function is called // in multiple places concurrently. Updating these in-place *is* racy. for h, v := range nc.API.HTTPHeaders { + h = http.CanonicalHeaderKey(h) switch h { case cmdsHttp.ACAOrigin, cmdsHttp.ACAMethods, cmdsHttp.ACACredentials: // these are handled by the CORs library. diff --git a/gateway/core/corehttp/gateway.go b/gateway/core/corehttp/gateway.go index ae3e035d8..044144a76 100644 --- a/gateway/core/corehttp/gateway.go +++ b/gateway/core/corehttp/gateway.go @@ -53,7 +53,7 @@ func GatewayOption(writable bool, paths ...string) ServeOption { headers := make(map[string][]string, len(cfg.Gateway.HTTPHeaders)) for h, v := range cfg.Gateway.HTTPHeaders { - headers[h] = v + headers[http.CanonicalHeaderKey(h)] = v } // Hard-coded headers.