Skip to content

Commit

Permalink
Merge pull request ipfs/kubo#1544 from ipfs/fix/allowed-origins
Browse files Browse the repository at this point in the history
fix allowed origins to make webui work again

This commit was moved from ipfs/kubo@b19dd47
  • Loading branch information
jbenet committed Aug 2, 2015
2 parents 5012dee + 5d82470 commit e3ae41d
Show file tree
Hide file tree
Showing 8 changed files with 76 additions and 15 deletions.
46 changes: 45 additions & 1 deletion gateway/core/corehttp/commands.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package corehttp

import (
"net"
"net/http"
"os"
"strconv"
"strings"

cors "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/rs/cors"
Expand All @@ -28,6 +30,13 @@ or
ipfs daemon --api-http-header 'Access-Control-Allow-Origin: *'
`

var defaultLocalhostOrigins = []string{
"http://127.0.0.1:<port>",
"https://127.0.0.1:<port>",
"http://localhost:<port>",
"https://localhost:<port>",
}

func addCORSFromEnv(c *cmdsHttp.ServerConfig) {
origin := os.Getenv(originEnvKey)
if origin != "" {
Expand Down Expand Up @@ -57,8 +66,41 @@ func addHeadersFromConfig(c *cmdsHttp.ServerConfig, nc *config.Config) {
c.Headers = nc.API.HTTPHeaders
}

func addCORSDefaults(c *cmdsHttp.ServerConfig) {
// by default use localhost origins
if len(c.CORSOpts.AllowedOrigins) == 0 {
c.CORSOpts.AllowedOrigins = defaultLocalhostOrigins
}

// by default, use GET, PUT, POST
if len(c.CORSOpts.AllowedMethods) == 0 {
c.CORSOpts.AllowedMethods = []string{"GET", "POST", "PUT"}
}
}

func patchCORSVars(c *cmdsHttp.ServerConfig, addr net.Addr) {

// we have to grab the port from an addr, which may be an ip6 addr.
// TODO: this should take multiaddrs and derive port from there.
port := ""
if tcpaddr, ok := addr.(*net.TCPAddr); ok {
port = strconv.Itoa(tcpaddr.Port)
} else if udpaddr, ok := addr.(*net.UDPAddr); ok {
port = strconv.Itoa(udpaddr.Port)
}

// we're listening on tcp/udp with ports. ("udp!?" you say? yeah... it happens...)
for i, o := range c.CORSOpts.AllowedOrigins {
// TODO: allow replacing <host>. tricky, ip4 and ip6 and hostnames...
if port != "" {
o = strings.Replace(o, "<port>", port, -1)
}
c.CORSOpts.AllowedOrigins[i] = o
}
}

func CommandsOption(cctx commands.Context) ServeOption {
return func(n *core.IpfsNode, mux *http.ServeMux) (*http.ServeMux, error) {
return func(n *core.IpfsNode, l net.Listener, mux *http.ServeMux) (*http.ServeMux, error) {

cfg := &cmdsHttp.ServerConfig{
CORSOpts: &cors.Options{
Expand All @@ -68,6 +110,8 @@ func CommandsOption(cctx commands.Context) ServeOption {

addHeadersFromConfig(cfg, n.Repo.Config())
addCORSFromEnv(cfg)
addCORSDefaults(cfg)
patchCORSVars(cfg, l.Addr())

cmdHandler := cmdsHttp.NewHandler(cctx, corecommands.Root, cfg)
mux.Handle(cmdsHttp.ApiPath+"/", cmdHandler)
Expand Down
8 changes: 4 additions & 4 deletions gateway/core/corehttp/corehttp.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,16 @@ var log = eventlog.Logger("core/server")
// It returns the mux to expose to future options, which may be a new mux if it
// is interested in mediating requests to future options, or the same mux
// initially passed in if not.
type ServeOption func(*core.IpfsNode, *http.ServeMux) (*http.ServeMux, error)
type ServeOption func(*core.IpfsNode, net.Listener, *http.ServeMux) (*http.ServeMux, error)

// makeHandler turns a list of ServeOptions into a http.Handler that implements
// all of the given options, in order.
func makeHandler(n *core.IpfsNode, options ...ServeOption) (http.Handler, error) {
func makeHandler(n *core.IpfsNode, l net.Listener, options ...ServeOption) (http.Handler, error) {
topMux := http.NewServeMux()
mux := topMux
for _, option := range options {
var err error
mux, err = option(n, mux)
mux, err = option(n, l, mux)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -65,7 +65,7 @@ func ListenAndServe(n *core.IpfsNode, listeningMultiAddr string, options ...Serv
}

func Serve(node *core.IpfsNode, lis net.Listener, options ...ServeOption) error {
handler, err := makeHandler(node, options...)
handler, err := makeHandler(node, lis, options...)
if err != nil {
return err
}
Expand Down
5 changes: 3 additions & 2 deletions gateway/core/corehttp/gateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package corehttp

import (
"fmt"
"net"
"net/http"
"sync"

Expand All @@ -27,7 +28,7 @@ func NewGateway(conf GatewayConfig) *Gateway {
}

func (g *Gateway) ServeOption() ServeOption {
return func(n *core.IpfsNode, mux *http.ServeMux) (*http.ServeMux, error) {
return func(n *core.IpfsNode, _ net.Listener, mux *http.ServeMux) (*http.ServeMux, error) {
// pass user's HTTP headers
g.Config.Headers = n.Repo.Config().Gateway.HTTPHeaders

Expand All @@ -50,7 +51,7 @@ func GatewayOption(writable bool) ServeOption {
}

func VersionOption() ServeOption {
return func(n *core.IpfsNode, mux *http.ServeMux) (*http.ServeMux, error) {
return func(n *core.IpfsNode, _ net.Listener, mux *http.ServeMux) (*http.ServeMux, error) {
mux.HandleFunc("/version", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Client Version: %s\n", id.ClientVersion)
fmt.Fprintf(w, "Protocol Version: %s\n", id.IpfsVersion)
Expand Down
20 changes: 16 additions & 4 deletions gateway/core/corehttp/gateway_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,14 @@ func newNodeWithMockNamesys(t *testing.T, ns mockNamesys) *core.IpfsNode {
return n
}

type delegatedHandler struct {
http.Handler
}

func (dh *delegatedHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
dh.Handler.ServeHTTP(w, r)
}

func TestGatewayGet(t *testing.T) {
t.Skip("not sure whats going on here")
ns := mockNamesys{}
Expand All @@ -65,17 +73,21 @@ func TestGatewayGet(t *testing.T) {
}
ns["example.com"] = path.FromString("/ipfs/" + k)

h, err := makeHandler(n,
// need this variable here since we need to construct handler with
// listener, and server with handler. yay cycles.
dh := &delegatedHandler{}
ts := httptest.NewServer(dh)
defer ts.Close()

dh.Handler, err = makeHandler(n,
ts.Listener,
IPNSHostnameOption(),
GatewayOption(false),
)
if err != nil {
t.Fatal(err)
}

ts := httptest.NewServer(h)
defer ts.Close()

t.Log(ts.URL)
for _, test := range []struct {
host string
Expand Down
3 changes: 2 additions & 1 deletion gateway/core/corehttp/ipns_hostname.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package corehttp

import (
"net"
"net/http"
"strings"

Expand All @@ -13,7 +14,7 @@ import (
// an IPNS name.
// The rewritten request points at the resolved name on the gateway handler.
func IPNSHostnameOption() ServeOption {
return func(n *core.IpfsNode, mux *http.ServeMux) (*http.ServeMux, error) {
return func(n *core.IpfsNode, _ net.Listener, mux *http.ServeMux) (*http.ServeMux, error) {
childMux := http.NewServeMux()
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
ctx, cancel := context.WithCancel(n.Context())
Expand Down
3 changes: 2 additions & 1 deletion gateway/core/corehttp/logs.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package corehttp

import (
"io"
"net"
"net/http"

core "github.com/ipfs/go-ipfs/core"
Expand Down Expand Up @@ -36,7 +37,7 @@ func (w *writeErrNotifier) Write(b []byte) (int, error) {
}

func LogOption() ServeOption {
return func(n *core.IpfsNode, mux *http.ServeMux) (*http.ServeMux, error) {
return func(n *core.IpfsNode, _ net.Listener, mux *http.ServeMux) (*http.ServeMux, error) {
mux.HandleFunc("/logs", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(200)
wnf, errs := newWriteErrNotifier(w)
Expand Down
3 changes: 2 additions & 1 deletion gateway/core/corehttp/prometheus.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package corehttp

import (
"net"
"net/http"

prom "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/prometheus/client_golang/prometheus"
Expand All @@ -9,7 +10,7 @@ import (
)

func PrometheusOption(path string) ServeOption {
return func(n *core.IpfsNode, mux *http.ServeMux) (*http.ServeMux, error) {
return func(n *core.IpfsNode, _ net.Listener, mux *http.ServeMux) (*http.ServeMux, error) {
mux.Handle(path, prom.Handler())
return mux, nil
}
Expand Down
3 changes: 2 additions & 1 deletion gateway/core/corehttp/redirect.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
package corehttp

import (
"net"
"net/http"

core "github.com/ipfs/go-ipfs/core"
)

func RedirectOption(path string, redirect string) ServeOption {
handler := &redirectHandler{redirect}
return func(n *core.IpfsNode, mux *http.ServeMux) (*http.ServeMux, error) {
return func(n *core.IpfsNode, _ net.Listener, mux *http.ServeMux) (*http.ServeMux, error) {
mux.Handle("/"+path+"/", handler)
return mux, nil
}
Expand Down

0 comments on commit e3ae41d

Please sign in to comment.