Static Website serving and listing
adds trailing slash redirection index.html return templated directory listing Signed off : Simon Kirkby <tigger@interthingy.com>
Simon Kirkby committed
Nov 20, 2014 at 21:20 UTC
32823d2085a53820cf1995a2075dd478d3e46371
2 files changed
+95
-4
cmd/ipfs/daemon.go
+3
-1
@@ -165,7 +165,9 @@ func listenAndServeAPI(node *core.IpfsNode, req cmds.Request, addr ma.Multiaddr)
165
cmdHandler := cmdsHttp.NewHandler(*req.Context(), commands.Root, origin)
166
mux.Handle(cmdsHttp.ApiPath+"/", cmdHandler)
167
168
- ifpsHandler := &ipfsHandler{node}
168
+ ifpsHandler := &ipfsHandler{node: node}
169
+ ifpsHandler.LoadTemplate()
170
+
171
mux.Handle("/ipfs/", ifpsHandler)
172
173
// if the server exits beforehand
cmd/ipfs/ipfsHandler.go
+92
-3
@@ -1,6 +1,7 @@
1
package main
2
3
import (
4
+ "html/template"
5
"io"
6
"net/http"
7
@@ -23,10 +24,29 @@ type ipfs interface {
24
NewDagReader(nd *dag.Node) (io.Reader, error)
25
}
26
27
+// shortcut for templating
28
+type H map[string]interface{}
29
+
30
+// struct for directory listing
31
+type directoryItem struct {
32
+ Size uint64
33
+ Name string
34
+}
35
+
36
// ipfsHandler is a HTTP handler that serves IPFS objects (accessible by default at /ipfs/<path>)
37
// (it serves requests like GET /ipfs/QmVRzPKPzNtSrEzBFm2UZfxmPAgnaLke4DMcerbsGGSaFe/link)
38
type ipfsHandler struct {
29
- node *core.IpfsNode
39
+ node *core.IpfsNode
40
+ dirList *template.Template
41
+}
42
+
43
+// Load the directroy list template
44
+func (i *ipfsHandler) LoadTemplate() {
45
+ t, err := template.New("dir").Parse(listingTemplate)
46
+ if err != nil {
47
+ log.Error(err)
48
+ }
49
+ i.dirList = t
50
}
51
52
func (i *ipfsHandler) ResolvePath(path string) (*dag.Node, error) {
@@ -65,14 +85,63 @@ func (i *ipfsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
85
}
86
87
dr, err := i.NewDagReader(nd)
88
+
89
if err != nil {
69
- // TODO: return json object containing the tree data if it's a directory (err == ErrIsDir)
90
+ if err == uio.ErrIsDir {
91
+ log.Debug("is directory %s", path)
92
+
93
+ if path[len(path)-1:] != "/" {
94
+ log.Debug("missing trailing slash redirect")
95
+ http.Redirect(w, r, "/ipfs/"+path+"/", 307)
96
+ return
97
+ }
98
+
99
+ // storage for directory listing
100
+ var dirListing []directoryItem
101
+ // loop through files
102
+ for _, link := range nd.Links {
103
+ if link.Name == "index.html" {
104
+ log.Debug("found index")
105
+ // return index page
106
+ nd, err := i.ResolvePath(path + "/index.html")
107
+ if err != nil {
108
+ w.WriteHeader(http.StatusInternalServerError)
109
+ w.Write([]byte(err.Error()))
110
+ log.Error("%s", err)
111
+ return
112
+ }
113
+ dr, err := i.NewDagReader(nd)
114
+ if err != nil {
115
+ w.WriteHeader(http.StatusInternalServerError)
116
+ w.Write([]byte(err.Error()))
117
+ log.Error("%s", err)
118
+ return
119
+ }
120
+ // write to request
121
+ io.Copy(w, dr)
122
+ return
123
+ }
124
+ dirListing = append(dirListing, directoryItem{link.Size, link.Name})
125
+ }
126
+ // template and return directory listing
127
+ //for i, j := range dirListing {
128
+ // log.Debug(i, ":", j.Size, " ", j.Name)
129
+ //}
130
+ err := i.dirList.Execute(w, H{"listing": dirListing, "path": path})
131
+ if err != nil {
132
+ w.WriteHeader(http.StatusInternalServerError)
133
+ w.Write([]byte(err.Error()))
134
+ log.Error("%s", err)
135
+ return
136
+ }
137
+ return
138
+ }
139
w.WriteHeader(http.StatusInternalServerError)
140
log.Error(err)
141
w.Write([]byte(err.Error()))
142
return
143
}
75
-
144
+ // data file
145
io.Copy(w, dr)
146
}
147
@@ -97,3 +166,23 @@ func (i *ipfsHandler) postHandler(w http.ResponseWriter, r *http.Request) {
166
w.WriteHeader(http.StatusCreated)
167
w.Write([]byte(mh.Multihash(k).B58String()))
168
}
169
+
170
+// Directory listing template
171
+var listingTemplate = `
172
+<!DOCTYPE html>
173
+<html>
174
+ <head>
175
+ <meta charset="utf-8" />
176
+ <title>{{ .path }}</title>
177
+ </head>
178
+ <body>
179
+ <h2>Index of {{ .path }}</h2>
180
+ <ul>
181
+ <li> <a href="./..">Parent</a></li>
182
+ {{ range $item := .listing }}
183
+ <li> <a href="./{{ $item.Name }}">{{ $item.Name }}</a> - {{ $item.Size }} bytes</li>
184
+ {{ end }}
185
+ </ul>
186
+ </body>
187
+</html>
188
+`