diff --git a/gateway/core/corehttp/commands.go b/gateway/core/corehttp/commands.go index f3e5c8a45..0a65fcc3a 100644 --- a/gateway/core/corehttp/commands.go +++ b/gateway/core/corehttp/commands.go @@ -3,22 +3,73 @@ package corehttp import ( "net/http" "os" + "strings" + + cors "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/rs/cors" commands "github.com/ipfs/go-ipfs/commands" cmdsHttp "github.com/ipfs/go-ipfs/commands/http" core "github.com/ipfs/go-ipfs/core" corecommands "github.com/ipfs/go-ipfs/core/commands" + config "github.com/ipfs/go-ipfs/repo/config" ) -const ( - // TODO rename - originEnvKey = "API_ORIGIN" -) +const originEnvKey = "API_ORIGIN" +const originEnvKeyDeprecate = `You are using the ` + originEnvKey + `ENV Variable. +This functionality is deprecated, and will be removed in future versions. +Instead, try either adding headers to the config, or passing them via +cli arguments: + + ipfs config API.HTTPHeaders 'Access-Control-Allow-Origin' '*' + ipfs daemon + +or + + ipfs daemon --api-http-header 'Access-Control-Allow-Origin: *' +` + +func addCORSFromEnv(c *cmdsHttp.ServerConfig) { + origin := os.Getenv(originEnvKey) + if origin != "" { + log.Warning(originEnvKeyDeprecate) + if c.CORSOpts == nil { + c.CORSOpts.AllowedOrigins = []string{origin} + } + c.CORSOpts.AllowedOrigins = append(c.CORSOpts.AllowedOrigins, origin) + } +} + +func addHeadersFromConfig(c *cmdsHttp.ServerConfig, nc *config.Config) { + log.Info("Using API.HTTPHeaders:", nc.API.HTTPHeaders) + + if acao := nc.API.HTTPHeaders[cmdsHttp.ACAOrigin]; acao != nil { + c.CORSOpts.AllowedOrigins = acao + } + if acam := nc.API.HTTPHeaders[cmdsHttp.ACAMethods]; acam != nil { + c.CORSOpts.AllowedMethods = acam + } + if acac := nc.API.HTTPHeaders[cmdsHttp.ACACredentials]; acac != nil { + for _, v := range acac { + c.CORSOpts.AllowCredentials = (strings.ToLower(v) == "true") + } + } + + c.Headers = nc.API.HTTPHeaders +} func CommandsOption(cctx commands.Context) ServeOption { return func(n *core.IpfsNode, mux *http.ServeMux) (*http.ServeMux, error) { - origin := os.Getenv(originEnvKey) - cmdHandler := cmdsHttp.NewHandler(cctx, corecommands.Root, origin) + + cfg := &cmdsHttp.ServerConfig{ + CORSOpts: &cors.Options{ + AllowedMethods: []string{"GET", "POST", "PUT"}, + }, + } + + addHeadersFromConfig(cfg, n.Repo.Config()) + addCORSFromEnv(cfg) + + cmdHandler := cmdsHttp.NewHandler(cctx, corecommands.Root, cfg) mux.Handle(cmdsHttp.ApiPath+"/", cmdHandler) return mux, nil } diff --git a/gateway/core/corehttp/gateway.go b/gateway/core/corehttp/gateway.go index 0a84178b8..f70a1d11f 100644 --- a/gateway/core/corehttp/gateway.go +++ b/gateway/core/corehttp/gateway.go @@ -15,6 +15,7 @@ type Gateway struct { } type GatewayConfig struct { + Headers map[string][]string BlockList *BlockList Writable bool } @@ -27,6 +28,9 @@ func NewGateway(conf GatewayConfig) *Gateway { func (g *Gateway) ServeOption() ServeOption { return func(n *core.IpfsNode, mux *http.ServeMux) (*http.ServeMux, error) { + // pass user's HTTP headers + g.Config.Headers = n.Repo.Config().Gateway.HTTPHeaders + gateway, err := newGatewayHandler(n, g.Config) if err != nil { return nil, err diff --git a/gateway/core/corehttp/gateway_handler.go b/gateway/core/corehttp/gateway_handler.go index 6ea7b906f..671a1c5e8 100644 --- a/gateway/core/corehttp/gateway_handler.go +++ b/gateway/core/corehttp/gateway_handler.go @@ -106,6 +106,7 @@ func (i *gatewayHandler) getOrHeadHandler(w http.ResponseWriter, r *http.Request return } + i.addUserHeaders(w) // ok, _now_ write user's headers. w.Header().Set("X-IPFS-Path", urlPath) // Suborigin header, sandboxes apps from each other in the browser (even @@ -229,6 +230,7 @@ func (i *gatewayHandler) postHandler(w http.ResponseWriter, r *http.Request) { return } + i.addUserHeaders(w) // ok, _now_ write user's headers. w.Header().Set("IPFS-Hash", k.String()) http.Redirect(w, r, ipfsPathPrefix+k.String(), http.StatusCreated) } @@ -242,6 +244,7 @@ func (i *gatewayHandler) putEmptyDirHandler(w http.ResponseWriter, r *http.Reque return } + i.addUserHeaders(w) // ok, _now_ write user's headers. w.Header().Set("IPFS-Hash", key.String()) http.Redirect(w, r, ipfsPathPrefix+key.String()+"/", http.StatusCreated) } @@ -340,6 +343,7 @@ func (i *gatewayHandler) putHandler(w http.ResponseWriter, r *http.Request) { return } + i.addUserHeaders(w) // ok, _now_ write user's headers. w.Header().Set("IPFS-Hash", key.String()) http.Redirect(w, r, ipfsPathPrefix+key.String()+"/"+strings.Join(components, "/"), http.StatusCreated) } @@ -411,10 +415,17 @@ func (i *gatewayHandler) deleteHandler(w http.ResponseWriter, r *http.Request) { return } + i.addUserHeaders(w) // ok, _now_ write user's headers. w.Header().Set("IPFS-Hash", key.String()) http.Redirect(w, r, ipfsPathPrefix+key.String()+"/"+strings.Join(components[:len(components)-1], "/"), http.StatusCreated) } +func (i *gatewayHandler) addUserHeaders(w http.ResponseWriter) { + for k, v := range i.config.Headers { + w.Header()[k] = v + } +} + func webError(w http.ResponseWriter, message string, err error, defaultCode int) { if _, ok := err.(path.ErrNoLink); ok { webErrorWithCode(w, message, err, http.StatusNotFound)