@cryptotaxi247 / kubo / commits / 82629c00e

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 <steven@stebalien.com>

Steven Allen committed Jan 4, 2019 at 12:08 UTC 82629c00ec12e376e26b28d3551395d5e2dfb85c
2 files changed +57 -14
core/corehttp/gateway.go
+57 -1
@@ -4,6 +4,7 @@ import (
4 "fmt"
5 "net"
6 "net/http"
7 + "sort"
8
9 version "github.com/ipfs/go-ipfs"
10 core "github.com/ipfs/go-ipfs/core"
@@ -18,6 +19,26 @@ type GatewayConfig struct {
19 PathPrefixes []string
20 }
21
22 +// A helper function to clean up a set of headers:
23 +// 1. Canonicalizes.
24 +// 2. Deduplicates.
25 +// 3. Sorts.
26 +func cleanHeaderSet(headers []string) []string {
27 + // Deduplicate and canonicalize.
28 + m := make(map[string]struct{}, len(headers))
29 + for _, h := range headers {
30 + m[http.CanonicalHeaderKey(h)] = struct{}{}
31 + }
32 + result := make([]string, 0, len(m))
33 + for k := range m {
34 + result = append(result, k)
35 + }
36 +
37 + // Sort
38 + sort.Strings(result)
39 + return result
40 +}
41 +
42 func GatewayOption(writable bool, paths ...string) ServeOption {
43 return func(n *core.IpfsNode, _ net.Listener, mux *http.ServeMux) (*http.ServeMux, error) {
44 cfg, err := n.Repo.Config()
@@ -30,8 +51,43 @@ func GatewayOption(writable bool, paths ...string) ServeOption {
51 return nil, err
52 }
53
54 + headers := make(map[string][]string, len(cfg.Gateway.HTTPHeaders))
55 + for h, v := range cfg.Gateway.HTTPHeaders {
56 + headers[h] = v
57 + }
58 +
59 + // Hard-coded headers.
60 + const ACAHeadersName = "Access-Control-Allow-Headers"
61 + const ACEHeadersName = "Access-Control-Expose-Headers"
62 + const ACAOriginName = "Access-Control-Allow-Origin"
63 + const ACAMethodsName = "Access-Control-Allow-Methods"
64 +
65 + if _, ok := headers[ACAOriginName]; !ok {
66 + // Default to *all*
67 + headers[ACAOriginName] = []string{"*"}
68 + }
69 + if _, ok := headers[ACAMethodsName]; !ok {
70 + // Default to GET
71 + headers[ACAMethodsName] = []string{"GET"}
72 + }
73 +
74 + headers[ACAHeadersName] = cleanHeaderSet(
75 + append([]string{
76 + "Content-Type",
77 + "User-Agent",
78 + "Range",
79 + "X-Requested-With",
80 + }, headers[ACAHeadersName]...))
81 +
82 + headers[ACEHeadersName] = cleanHeaderSet(
83 + append([]string{
84 + "Content-Range",
85 + "X-Chunked-Output",
86 + "X-Stream-Output",
87 + }, headers[ACEHeadersName]...))
88 +
89 gateway := newGatewayHandler(n, GatewayConfig{
34 - Headers: cfg.Gateway.HTTPHeaders,
90 + Headers: headers,
91 Writable: writable,
92 PathPrefixes: cfg.Gateway.PathPrefixes,
93 }, api)
core/corehttp/gateway_handler.go
-13
@@ -184,19 +184,6 @@ func (i *gatewayHandler) getOrHeadHandler(ctx context.Context, w http.ResponseWr
184 w.Header().Set("X-IPFS-Path", urlPath)
185 w.Header().Set("Etag", etag)
186
187 - // set 'allowed' headers
188 - // & expose those headers
189 - var allowedHeadersArr = []string{
190 - "Content-Range",
191 - "X-Chunked-Output",
192 - "X-Stream-Output",
193 - }
194 -
195 - var allowedHeaders = strings.Join(allowedHeadersArr, ", ")
196 -
197 - w.Header().Set("Access-Control-Allow-Headers", allowedHeaders)
198 - w.Header().Set("Access-Control-Expose-Headers", allowedHeaders)
199 -
187 // Suborigin header, sandboxes apps from each other in the browser (even
188 // though they are served from the same gateway domain).
189 //