Skip to content

Commit

Permalink
gateway: fix CORs headers
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Stebalien committed Jan 4, 2019
1 parent 543be29 commit ad6373e
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 14 deletions.
57 changes: 56 additions & 1 deletion core/corehttp/gateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"
"net"
"net/http"
"sort"

version "github.com/ipfs/go-ipfs"
core "github.com/ipfs/go-ipfs/core"
Expand All @@ -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()
Expand All @@ -30,8 +51,42 @@ 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-Range",
"Content-Type",
"User-Agent",
"X-Requested-With",
}, headers[ACAHeadersName]...))

headers[ACEHeadersName] = cleanHeaderSet(
append([]string{
"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)
Expand Down
13 changes: 0 additions & 13 deletions core/corehttp/gateway_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -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).
//
Expand Down

0 comments on commit ad6373e

Please sign in to comment.