From 8603e8294f08d61433e7a9e8747f218f45b8a8d4 Mon Sep 17 00:00:00 2001 From: Matt Bell Date: Wed, 10 Dec 2014 00:50:02 -0800 Subject: [PATCH 01/11] config: Added a gateway server address --- config/config.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/config/config.go b/config/config.go index 3aca889ef..d33e4d36d 100644 --- a/config/config.go +++ b/config/config.go @@ -40,8 +40,9 @@ type Datastore struct { // Addresses stores the (string) multiaddr addresses for the node. type Addresses struct { - Swarm []string // addresses for the swarm network - API string // address for the local API (RPC) + Swarm []string // addresses for the swarm network + API string // address for the local API (RPC) + Gateway string // address to listen on for IPFS HTTP object gateway } // Mounts stores the (string) mount points From 9119435cb68cc8ff37bf8a29cc2b280a4802eb2d Mon Sep 17 00:00:00 2001 From: Matt Bell Date: Wed, 10 Dec 2014 00:58:18 -0800 Subject: [PATCH 02/11] cmd/ipfs: Added gateway server to daemon --- cmd/ipfs/daemon.go | 54 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 51 insertions(+), 3 deletions(-) diff --git a/cmd/ipfs/daemon.go b/cmd/ipfs/daemon.go index e0a6663cf..30f98f3f1 100644 --- a/cmd/ipfs/daemon.go +++ b/cmd/ipfs/daemon.go @@ -108,6 +108,13 @@ func daemonFunc(req cmds.Request) (interface{}, error) { return nil, err } + // ignore error for gateway address + // if there is an error (invalid address), then don't run the gateway + gatewayMaddr, _ := ma.NewMultiaddr(cfg.Addresses.Gateway) + if gatewayMaddr == nil { + fmt.Println("Invalid gateway address, not running gateway") + } + // mount if the user provided the --mount flag mount, _, err := req.Option(mountKwd).Bool() if err != nil { @@ -138,11 +145,14 @@ func daemonFunc(req cmds.Request) (interface{}, error) { fmt.Printf("IPNS mounted at: %s\n", nsdir) } + if gatewayMaddr != nil { + listenAndServeGateway(node, gatewayMaddr) + } + return nil, listenAndServeAPI(node, req, apiMaddr) } func listenAndServeAPI(node *core.IpfsNode, req cmds.Request, addr ma.Multiaddr) error { - _, host, err := manet.DialArgs(addr) if err != nil { return err @@ -163,7 +173,7 @@ func listenAndServeAPI(node *core.IpfsNode, req cmds.Request, addr ma.Multiaddr) serverExited := make(chan struct{}) go func() { - fmt.Printf("daemon listening on %s\n", addr) + fmt.Printf("API server listening on %s\n", addr) serverError = server.ListenAndServe(host, mux) close(serverExited) }() @@ -176,9 +186,47 @@ func listenAndServeAPI(node *core.IpfsNode, req cmds.Request, addr ma.Multiaddr) case <-node.Closing(): log.Infof("daemon at %s terminating...", addr) server.Shutdown <- true - <-serverExited // now, DO wait until server exits + <-serverExited // now, DO wait until server exit } log.Infof("daemon at %s terminated", addr) return serverError } + +func listenAndServeGateway(node *core.IpfsNode, addr ma.Multiaddr) error { + _, host, err := manet.DialArgs(addr) + if err != nil { + return err + } + + server := manners.NewServer() + mux := http.NewServeMux() + ifpsHandler := &ipfsHandler{node} + mux.Handle("/ipfs/", ifpsHandler) + + done := make(chan struct{}, 1) + defer func() { + done <- struct{}{} + }() + + // go wait until the node dies + go func() { + select { + case <-node.Closed(): + case <-done: + return + } + + log.Infof("terminating gateway at %s...", addr) + server.Shutdown <- true + }() + + fmt.Printf("Gateway listening on %s\n", addr) + go func() { + if err := server.ListenAndServe(host, mux); err != nil { + log.Error(err) + } + }() + + return nil +} From 32823d2085a53820cf1995a2075dd478d3e46371 Mon Sep 17 00:00:00 2001 From: Simon Kirkby Date: Thu, 20 Nov 2014 21:20:40 +0800 Subject: [PATCH 03/11] Static Website serving and listing adds trailing slash redirection index.html return templated directory listing Signed off : Simon Kirkby --- cmd/ipfs/daemon.go | 4 +- cmd/ipfs/ipfsHandler.go | 95 +++++++++++++++++++++++++++++++++++++++-- 2 files changed, 95 insertions(+), 4 deletions(-) diff --git a/cmd/ipfs/daemon.go b/cmd/ipfs/daemon.go index 30f98f3f1..6674b9d2f 100644 --- a/cmd/ipfs/daemon.go +++ b/cmd/ipfs/daemon.go @@ -165,7 +165,9 @@ func listenAndServeAPI(node *core.IpfsNode, req cmds.Request, addr ma.Multiaddr) cmdHandler := cmdsHttp.NewHandler(*req.Context(), commands.Root, origin) mux.Handle(cmdsHttp.ApiPath+"/", cmdHandler) - ifpsHandler := &ipfsHandler{node} + ifpsHandler := &ipfsHandler{node: node} + ifpsHandler.LoadTemplate() + mux.Handle("/ipfs/", ifpsHandler) // if the server exits beforehand diff --git a/cmd/ipfs/ipfsHandler.go b/cmd/ipfs/ipfsHandler.go index 623531239..2a10aea67 100644 --- a/cmd/ipfs/ipfsHandler.go +++ b/cmd/ipfs/ipfsHandler.go @@ -1,6 +1,7 @@ package main import ( + "html/template" "io" "net/http" @@ -23,10 +24,29 @@ type ipfs interface { NewDagReader(nd *dag.Node) (io.Reader, error) } +// shortcut for templating +type H map[string]interface{} + +// struct for directory listing +type directoryItem struct { + Size uint64 + Name string +} + // ipfsHandler is a HTTP handler that serves IPFS objects (accessible by default at /ipfs/) // (it serves requests like GET /ipfs/QmVRzPKPzNtSrEzBFm2UZfxmPAgnaLke4DMcerbsGGSaFe/link) type ipfsHandler struct { - node *core.IpfsNode + node *core.IpfsNode + dirList *template.Template +} + +// Load the directroy list template +func (i *ipfsHandler) LoadTemplate() { + t, err := template.New("dir").Parse(listingTemplate) + if err != nil { + log.Error(err) + } + i.dirList = t } func (i *ipfsHandler) ResolvePath(path string) (*dag.Node, error) { @@ -65,14 +85,63 @@ func (i *ipfsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { } dr, err := i.NewDagReader(nd) + if err != nil { - // TODO: return json object containing the tree data if it's a directory (err == ErrIsDir) + if err == uio.ErrIsDir { + log.Debug("is directory %s", path) + + if path[len(path)-1:] != "/" { + log.Debug("missing trailing slash redirect") + http.Redirect(w, r, "/ipfs/"+path+"/", 307) + return + } + + // storage for directory listing + var dirListing []directoryItem + // loop through files + for _, link := range nd.Links { + if link.Name == "index.html" { + log.Debug("found index") + // return index page + nd, err := i.ResolvePath(path + "/index.html") + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(err.Error())) + log.Error("%s", err) + return + } + dr, err := i.NewDagReader(nd) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(err.Error())) + log.Error("%s", err) + return + } + // write to request + io.Copy(w, dr) + return + } + dirListing = append(dirListing, directoryItem{link.Size, link.Name}) + } + // template and return directory listing + //for i, j := range dirListing { + // log.Debug(i, ":", j.Size, " ", j.Name) + //} + err := i.dirList.Execute(w, H{"listing": dirListing, "path": path}) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(err.Error())) + log.Error("%s", err) + return + } + return + } w.WriteHeader(http.StatusInternalServerError) log.Error(err) w.Write([]byte(err.Error())) return } - + // data file io.Copy(w, dr) } @@ -97,3 +166,23 @@ func (i *ipfsHandler) postHandler(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusCreated) w.Write([]byte(mh.Multihash(k).B58String())) } + +// Directory listing template +var listingTemplate = ` + + + + + {{ .path }} + + +

Index of {{ .path }}

+ + + +` From 64cb1b6bf835717372d619f4c67d52fe0175ec1a Mon Sep 17 00:00:00 2001 From: Simon Kirkby Date: Mon, 24 Nov 2014 21:10:42 +0800 Subject: [PATCH 04/11] CR updates replaced H moved internal errors into function. Signed-off-by: Simon Kirkby --- cmd/ipfs/ipfsHandler.go | 35 ++++++++++++++++------------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/cmd/ipfs/ipfsHandler.go b/cmd/ipfs/ipfsHandler.go index 2a10aea67..199a65ce2 100644 --- a/cmd/ipfs/ipfsHandler.go +++ b/cmd/ipfs/ipfsHandler.go @@ -25,7 +25,7 @@ type ipfs interface { } // shortcut for templating -type H map[string]interface{} +type webHandler map[string]interface{} // struct for directory listing type directoryItem struct { @@ -91,7 +91,7 @@ func (i *ipfsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { log.Debug("is directory %s", path) if path[len(path)-1:] != "/" { - log.Debug("missing trailing slash redirect") + log.Debug("missing trailing slash, redirect") http.Redirect(w, r, "/ipfs/"+path+"/", 307) return } @@ -105,16 +105,12 @@ func (i *ipfsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { // return index page nd, err := i.ResolvePath(path + "/index.html") if err != nil { - w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(err.Error())) - log.Error("%s", err) + internalWebError(w, err) return } dr, err := i.NewDagReader(nd) if err != nil { - w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(err.Error())) - log.Error("%s", err) + internalWebError(w, err) return } // write to request @@ -124,24 +120,18 @@ func (i *ipfsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { dirListing = append(dirListing, directoryItem{link.Size, link.Name}) } // template and return directory listing - //for i, j := range dirListing { - // log.Debug(i, ":", j.Size, " ", j.Name) - //} - err := i.dirList.Execute(w, H{"listing": dirListing, "path": path}) + err := i.dirList.Execute(w, webHandler{"listing": dirListing, "path": path}) if err != nil { - w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(err.Error())) - log.Error("%s", err) + internalWebError(w, err) return } return } - w.WriteHeader(http.StatusInternalServerError) - log.Error(err) - w.Write([]byte(err.Error())) + // not a directory and still an error + internalWebError(w, err) return } - // data file + // return data file io.Copy(w, dr) } @@ -167,6 +157,13 @@ func (i *ipfsHandler) postHandler(w http.ResponseWriter, r *http.Request) { w.Write([]byte(mh.Multihash(k).B58String())) } +// return a 500 error and log +func internalWebError(w http.ResponseWriter, err error) { + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(err.Error())) + log.Error("%s", err) +} + // Directory listing template var listingTemplate = ` From cb84a376bd5e2a9a1e1c320631505c5f0f1650b6 Mon Sep 17 00:00:00 2001 From: Matt Bell Date: Fri, 12 Dec 2014 20:50:02 -0800 Subject: [PATCH 05/11] cmd/ipfs: Added an ipfsHandler constructor --- cmd/ipfs/daemon.go | 11 ++++++++--- cmd/ipfs/ipfsHandler.go | 22 +++++++++++++++++----- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/cmd/ipfs/daemon.go b/cmd/ipfs/daemon.go index 6674b9d2f..ee816a800 100644 --- a/cmd/ipfs/daemon.go +++ b/cmd/ipfs/daemon.go @@ -165,8 +165,10 @@ func listenAndServeAPI(node *core.IpfsNode, req cmds.Request, addr ma.Multiaddr) cmdHandler := cmdsHttp.NewHandler(*req.Context(), commands.Root, origin) mux.Handle(cmdsHttp.ApiPath+"/", cmdHandler) - ifpsHandler := &ipfsHandler{node: node} - ifpsHandler.LoadTemplate() + ifpsHandler, err := NewIpfsHandler(node) + if err != nil { + return err + } mux.Handle("/ipfs/", ifpsHandler) @@ -203,7 +205,10 @@ func listenAndServeGateway(node *core.IpfsNode, addr ma.Multiaddr) error { server := manners.NewServer() mux := http.NewServeMux() - ifpsHandler := &ipfsHandler{node} + ifpsHandler, err := NewIpfsHandler(node) + if err != nil { + return err + } mux.Handle("/ipfs/", ifpsHandler) done := make(chan struct{}, 1) diff --git a/cmd/ipfs/ipfsHandler.go b/cmd/ipfs/ipfsHandler.go index 199a65ce2..bd9ea8ef2 100644 --- a/cmd/ipfs/ipfsHandler.go +++ b/cmd/ipfs/ipfsHandler.go @@ -40,13 +40,25 @@ type ipfsHandler struct { dirList *template.Template } +func NewIpfsHandler(node *core.IpfsNode) (*ipfsHandler, error) { + i := &ipfsHandler{ + node: node, + } + err := i.loadTemplate() + if err != nil { + return nil, err + } + return i, nil +} + // Load the directroy list template -func (i *ipfsHandler) LoadTemplate() { +func (i *ipfsHandler) loadTemplate() error { t, err := template.New("dir").Parse(listingTemplate) if err != nil { - log.Error(err) + return err } i.dirList = t + return nil } func (i *ipfsHandler) ResolvePath(path string) (*dag.Node, error) { @@ -175,9 +187,9 @@ var listingTemplate = `

Index of {{ .path }}

From e25b08231c0d63860c702dd42922a17603bbc5e9 Mon Sep 17 00:00:00 2001 From: Matt Bell Date: Fri, 12 Dec 2014 20:52:46 -0800 Subject: [PATCH 06/11] cmd/ipfs: Renamed 'ipfsHandler' to 'gatewayHandler' --- cmd/ipfs/daemon.go | 9 +++---- .../{ipfsHandler.go => gatewayHandler.go} | 24 +++++++++---------- 2 files changed, 17 insertions(+), 16 deletions(-) rename cmd/ipfs/{ipfsHandler.go => gatewayHandler.go} (84%) diff --git a/cmd/ipfs/daemon.go b/cmd/ipfs/daemon.go index ee816a800..c2bb740bb 100644 --- a/cmd/ipfs/daemon.go +++ b/cmd/ipfs/daemon.go @@ -165,12 +165,12 @@ func listenAndServeAPI(node *core.IpfsNode, req cmds.Request, addr ma.Multiaddr) cmdHandler := cmdsHttp.NewHandler(*req.Context(), commands.Root, origin) mux.Handle(cmdsHttp.ApiPath+"/", cmdHandler) - ifpsHandler, err := NewIpfsHandler(node) + gateway, err := NewGatewayHandler(node) if err != nil { return err } - mux.Handle("/ipfs/", ifpsHandler) + mux.Handle("/ipfs/", gateway) // if the server exits beforehand var serverError error @@ -197,6 +197,7 @@ func listenAndServeAPI(node *core.IpfsNode, req cmds.Request, addr ma.Multiaddr) return serverError } +// the gateway also listens on its own address:port in addition to the API listener func listenAndServeGateway(node *core.IpfsNode, addr ma.Multiaddr) error { _, host, err := manet.DialArgs(addr) if err != nil { @@ -205,11 +206,11 @@ func listenAndServeGateway(node *core.IpfsNode, addr ma.Multiaddr) error { server := manners.NewServer() mux := http.NewServeMux() - ifpsHandler, err := NewIpfsHandler(node) + gateway, err := NewGatewayHandler(node) if err != nil { return err } - mux.Handle("/ipfs/", ifpsHandler) + mux.Handle("/ipfs/", gateway) done := make(chan struct{}, 1) defer func() { diff --git a/cmd/ipfs/ipfsHandler.go b/cmd/ipfs/gatewayHandler.go similarity index 84% rename from cmd/ipfs/ipfsHandler.go rename to cmd/ipfs/gatewayHandler.go index bd9ea8ef2..e1bc0cb42 100644 --- a/cmd/ipfs/ipfsHandler.go +++ b/cmd/ipfs/gatewayHandler.go @@ -17,7 +17,7 @@ import ( u "github.com/jbenet/go-ipfs/util" ) -type ipfs interface { +type gateway interface { ResolvePath(string) (*dag.Node, error) NewDagFromReader(io.Reader) (*dag.Node, error) AddNodeToDAG(nd *dag.Node) (u.Key, error) @@ -33,15 +33,15 @@ type directoryItem struct { Name string } -// ipfsHandler is a HTTP handler that serves IPFS objects (accessible by default at /ipfs/) +// gatewayHandler is a HTTP handler that serves IPFS objects (accessible by default at /ipfs/) // (it serves requests like GET /ipfs/QmVRzPKPzNtSrEzBFm2UZfxmPAgnaLke4DMcerbsGGSaFe/link) -type ipfsHandler struct { +type gatewayHandler struct { node *core.IpfsNode dirList *template.Template } -func NewIpfsHandler(node *core.IpfsNode) (*ipfsHandler, error) { - i := &ipfsHandler{ +func NewGatewayHandler(node *core.IpfsNode) (*gatewayHandler, error) { + i := &gatewayHandler{ node: node, } err := i.loadTemplate() @@ -52,7 +52,7 @@ func NewIpfsHandler(node *core.IpfsNode) (*ipfsHandler, error) { } // Load the directroy list template -func (i *ipfsHandler) loadTemplate() error { +func (i *gatewayHandler) loadTemplate() error { t, err := template.New("dir").Parse(listingTemplate) if err != nil { return err @@ -61,24 +61,24 @@ func (i *ipfsHandler) loadTemplate() error { return nil } -func (i *ipfsHandler) ResolvePath(path string) (*dag.Node, error) { +func (i *gatewayHandler) ResolvePath(path string) (*dag.Node, error) { return i.node.Resolver.ResolvePath(path) } -func (i *ipfsHandler) NewDagFromReader(r io.Reader) (*dag.Node, error) { +func (i *gatewayHandler) NewDagFromReader(r io.Reader) (*dag.Node, error) { return importer.BuildDagFromReader( r, i.node.DAG, i.node.Pinning.GetManual(), chunk.DefaultSplitter) } -func (i *ipfsHandler) AddNodeToDAG(nd *dag.Node) (u.Key, error) { +func (i *gatewayHandler) AddNodeToDAG(nd *dag.Node) (u.Key, error) { return i.node.DAG.Add(nd) } -func (i *ipfsHandler) NewDagReader(nd *dag.Node) (io.Reader, error) { +func (i *gatewayHandler) NewDagReader(nd *dag.Node) (io.Reader, error) { return uio.NewDagReader(nd, i.node.DAG) } -func (i *ipfsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { +func (i *gatewayHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { path := r.URL.Path[5:] nd, err := i.ResolvePath(path) @@ -147,7 +147,7 @@ func (i *ipfsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { io.Copy(w, dr) } -func (i *ipfsHandler) postHandler(w http.ResponseWriter, r *http.Request) { +func (i *gatewayHandler) postHandler(w http.ResponseWriter, r *http.Request) { nd, err := i.NewDagFromReader(r.Body) if err != nil { w.WriteHeader(http.StatusInternalServerError) From b5300f1d2747136d8d6a95bd34a0623571647886 Mon Sep 17 00:00:00 2001 From: Matt Bell Date: Sun, 11 Jan 2015 21:47:00 -0800 Subject: [PATCH 07/11] cmd/ipfs: Added gateway MIME type resolution --- cmd/ipfs/gatewayHandler.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/cmd/ipfs/gatewayHandler.go b/cmd/ipfs/gatewayHandler.go index e1bc0cb42..c79dccb18 100644 --- a/cmd/ipfs/gatewayHandler.go +++ b/cmd/ipfs/gatewayHandler.go @@ -3,7 +3,9 @@ package main import ( "html/template" "io" + "mime" "net/http" + "strings" "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context" mh "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multihash" @@ -96,6 +98,15 @@ func (i *gatewayHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { return } + extensionIndex := strings.LastIndex(path, ".") + if extensionIndex != -1 { + extension := path[extensionIndex:] + mimeType := mime.TypeByExtension(extension) + if len(mimeType) > 0 { + w.Header().Add("Content-Type", mimeType) + } + } + dr, err := i.NewDagReader(nd) if err != nil { From f39f3fe43256f6fc2c5659a359bd0426e1bbdb7a Mon Sep 17 00:00:00 2001 From: Matt Bell Date: Sun, 11 Jan 2015 22:01:53 -0800 Subject: [PATCH 08/11] cmd/ipfs: Redirect requests to /webui to webui app --- cmd/ipfs/daemon.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/cmd/ipfs/daemon.go b/cmd/ipfs/daemon.go index c2bb740bb..9999cb9f6 100644 --- a/cmd/ipfs/daemon.go +++ b/cmd/ipfs/daemon.go @@ -24,7 +24,10 @@ const ( ipnsMountKwd = "mount-ipns" // apiAddrKwd = "address-api" // swarmAddrKwd = "address-swarm" + originEnvKey = "API_ORIGIN" + + webuiPath = "/ipfs/QmTWvqK9dYvqjAMAcCeUun8b45Fwu7wPhEN9B9TsGbkXfJ" ) var daemonCmd = &cmds.Command{ @@ -171,6 +174,7 @@ func listenAndServeAPI(node *core.IpfsNode, req cmds.Request, addr ma.Multiaddr) } mux.Handle("/ipfs/", gateway) + mux.Handle("/webui/", &redirectHandler{webuiPath}) // if the server exits beforehand var serverError error @@ -238,3 +242,11 @@ func listenAndServeGateway(node *core.IpfsNode, addr ma.Multiaddr) error { return nil } + +type redirectHandler struct { + path string +} + +func (i *redirectHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + http.Redirect(w, r, i.path, 302) +} From ed41ac27fd76efd85619737de0b2e19e21149629 Mon Sep 17 00:00:00 2001 From: Juan Batiz-Benet Date: Sun, 11 Jan 2015 23:44:05 -0800 Subject: [PATCH 09/11] daemon: refactor common parts of serve funcs --- cmd/ipfs/daemon.go | 82 ++++++++++++----------------------- test/sharness/lib/test-lib.sh | 2 +- 2 files changed, 28 insertions(+), 56 deletions(-) diff --git a/cmd/ipfs/daemon.go b/cmd/ipfs/daemon.go index 9999cb9f6..af0b3a8d7 100644 --- a/cmd/ipfs/daemon.go +++ b/cmd/ipfs/daemon.go @@ -156,32 +156,46 @@ func daemonFunc(req cmds.Request) (interface{}, error) { } func listenAndServeAPI(node *core.IpfsNode, req cmds.Request, addr ma.Multiaddr) error { - _, host, err := manet.DialArgs(addr) - if err != nil { - return err - } - origin := os.Getenv(originEnvKey) - - server := manners.NewServer() - mux := http.NewServeMux() cmdHandler := cmdsHttp.NewHandler(*req.Context(), commands.Root, origin) - mux.Handle(cmdsHttp.ApiPath+"/", cmdHandler) - gateway, err := NewGatewayHandler(node) if err != nil { return err } + mux := http.NewServeMux() + mux.Handle(cmdsHttp.ApiPath+"/", cmdHandler) mux.Handle("/ipfs/", gateway) mux.Handle("/webui/", &redirectHandler{webuiPath}) + return listenAndServe("API", node, addr, mux) +} + +// the gateway also listens on its own address:port in addition to the API listener +func listenAndServeGateway(node *core.IpfsNode, addr ma.Multiaddr) error { + gateway, err := NewGatewayHandler(node) + if err != nil { + return err + } + + mux := http.NewServeMux() + mux.Handle("/ipfs/", gateway) + return listenAndServe("gateway", node, addr, mux) +} + +func listenAndServe(name string, node *core.IpfsNode, addr ma.Multiaddr, mux *http.ServeMux) error { + _, host, err := manet.DialArgs(addr) + if err != nil { + return err + } + + server := manners.NewServer() // if the server exits beforehand var serverError error serverExited := make(chan struct{}) go func() { - fmt.Printf("API server listening on %s\n", addr) + fmt.Printf("%s server listening on %s\n", name, addr) serverError = server.ListenAndServe(host, mux) close(serverExited) }() @@ -192,57 +206,15 @@ func listenAndServeAPI(node *core.IpfsNode, req cmds.Request, addr ma.Multiaddr) // if node being closed before server exits, close server case <-node.Closing(): - log.Infof("daemon at %s terminating...", addr) + log.Infof("server at %s terminating...", addr) server.Shutdown <- true <-serverExited // now, DO wait until server exit } - log.Infof("daemon at %s terminated", addr) + log.Infof("server at %s terminated", addr) return serverError } -// the gateway also listens on its own address:port in addition to the API listener -func listenAndServeGateway(node *core.IpfsNode, addr ma.Multiaddr) error { - _, host, err := manet.DialArgs(addr) - if err != nil { - return err - } - - server := manners.NewServer() - mux := http.NewServeMux() - gateway, err := NewGatewayHandler(node) - if err != nil { - return err - } - mux.Handle("/ipfs/", gateway) - - done := make(chan struct{}, 1) - defer func() { - done <- struct{}{} - }() - - // go wait until the node dies - go func() { - select { - case <-node.Closed(): - case <-done: - return - } - - log.Infof("terminating gateway at %s...", addr) - server.Shutdown <- true - }() - - fmt.Printf("Gateway listening on %s\n", addr) - go func() { - if err := server.ListenAndServe(host, mux); err != nil { - log.Error(err) - } - }() - - return nil -} - type redirectHandler struct { path string } diff --git a/test/sharness/lib/test-lib.sh b/test/sharness/lib/test-lib.sh index 968627be5..43bd1397d 100644 --- a/test/sharness/lib/test-lib.sh +++ b/test/sharness/lib/test-lib.sh @@ -88,7 +88,7 @@ test_launch_ipfs_daemon() { test_expect_success FUSE "'ipfs daemon' output looks good" ' IPFS_PID=$! && - echo "daemon listening on /ip4/127.0.0.1/tcp/5001" >expected && + echo "API server listening on /ip4/127.0.0.1/tcp/5001" >expected && test_cmp_repeat_10_sec expected actual || fsh cat daemon_err ' From f215eee3edc92d04a95cdb21886a79a3ce763639 Mon Sep 17 00:00:00 2001 From: Juan Batiz-Benet Date: Sun, 11 Jan 2015 23:44:34 -0800 Subject: [PATCH 10/11] gateway: cleaned up ServeHTTP func --- cmd/ipfs/gatewayHandler.go | 92 +++++++++++++++++++------------------- 1 file changed, 47 insertions(+), 45 deletions(-) diff --git a/cmd/ipfs/gatewayHandler.go b/cmd/ipfs/gatewayHandler.go index c79dccb18..26422902a 100644 --- a/cmd/ipfs/gatewayHandler.go +++ b/cmd/ipfs/gatewayHandler.go @@ -82,6 +82,7 @@ func (i *gatewayHandler) NewDagReader(nd *dag.Node) (io.Reader, error) { func (i *gatewayHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { path := r.URL.Path[5:] + log := log.Prefix("serving %s", path) nd, err := i.ResolvePath(path) if err != nil { @@ -108,54 +109,55 @@ func (i *gatewayHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { } dr, err := i.NewDagReader(nd) + if err == nil { + io.Copy(w, dr) + return + } - if err != nil { - if err == uio.ErrIsDir { - log.Debug("is directory %s", path) - - if path[len(path)-1:] != "/" { - log.Debug("missing trailing slash, redirect") - http.Redirect(w, r, "/ipfs/"+path+"/", 307) - return - } - - // storage for directory listing - var dirListing []directoryItem - // loop through files - for _, link := range nd.Links { - if link.Name == "index.html" { - log.Debug("found index") - // return index page - nd, err := i.ResolvePath(path + "/index.html") - if err != nil { - internalWebError(w, err) - return - } - dr, err := i.NewDagReader(nd) - if err != nil { - internalWebError(w, err) - return - } - // write to request - io.Copy(w, dr) - return - } - dirListing = append(dirListing, directoryItem{link.Size, link.Name}) - } - // template and return directory listing - err := i.dirList.Execute(w, webHandler{"listing": dirListing, "path": path}) - if err != nil { - internalWebError(w, err) - return - } - return - } + if err != uio.ErrIsDir { // not a directory and still an error internalWebError(w, err) return } - // return data file - io.Copy(w, dr) + + log.Debug("listing directory") + if path[len(path)-1:] != "/" { + log.Debug("missing trailing slash, redirect") + http.Redirect(w, r, "/ipfs/"+path+"/", 307) + return + } + + // storage for directory listing + var dirListing []directoryItem + // loop through files + for _, link := range nd.Links { + if link.Name != "index.html" { + dirListing = append(dirListing, directoryItem{link.Size, link.Name}) + continue + } + + log.Debug("found index") + // return index page instead. + nd, err := i.ResolvePath(path + "/index.html") + if err != nil { + internalWebError(w, err) + return + } + dr, err := i.NewDagReader(nd) + if err != nil { + internalWebError(w, err) + return + } + // write to request + io.Copy(w, dr) + } + + // template and return directory listing + hndlr := webHandler{"listing": dirListing, "path": path} + if err := i.dirList.Execute(w, hndlr); err != nil { + internalWebError(w, err) + return + } } func (i *gatewayHandler) postHandler(w http.ResponseWriter, r *http.Request) { @@ -198,9 +200,9 @@ var listingTemplate = `

Index of {{ .path }}

From 2c83cd5627c4abd26c11938eec9590df52cabb51 Mon Sep 17 00:00:00 2001 From: Juan Batiz-Benet Date: Mon, 12 Jan 2015 01:05:15 -0800 Subject: [PATCH 11/11] daemon: only try gateway addr if there --- cmd/ipfs/daemon.go | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/cmd/ipfs/daemon.go b/cmd/ipfs/daemon.go index af0b3a8d7..bbf880f4d 100644 --- a/cmd/ipfs/daemon.go +++ b/cmd/ipfs/daemon.go @@ -111,11 +111,14 @@ func daemonFunc(req cmds.Request) (interface{}, error) { return nil, err } - // ignore error for gateway address - // if there is an error (invalid address), then don't run the gateway - gatewayMaddr, _ := ma.NewMultiaddr(cfg.Addresses.Gateway) - if gatewayMaddr == nil { - fmt.Println("Invalid gateway address, not running gateway") + var gatewayMaddr ma.Multiaddr + if len(cfg.Addresses.Gateway) > 0 { + // ignore error for gateway address + // if there is an error (invalid address), then don't run the gateway + gatewayMaddr, _ = ma.NewMultiaddr(cfg.Addresses.Gateway) + if gatewayMaddr == nil { + log.Errorf("Invalid gateway address: %s", cfg.Addresses.Gateway) + } } // mount if the user provided the --mount flag