server/http: Added HTTP API handler
Matt Bell committed
Oct 22, 2014 at 15:26 UTC
73353824e91c62623b6bc6c3681b6a6dfda9e484
1 file changed
+88
-6
server/http/http.go
+88
-6
@@ -5,25 +5,35 @@ import (
5
"fmt"
6
"io"
7
"net/http"
8
+ "strings"
9
10
"github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/gorilla/mux"
11
ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
12
manet "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr/net"
13
mh "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multihash"
14
15
+ cmds "github.com/jbenet/go-ipfs/commands"
16
core "github.com/jbenet/go-ipfs/core"
17
+ "github.com/jbenet/go-ipfs/core/commands"
18
)
19
17
-type handler struct {
20
+type objectHandler struct {
21
ipfs
22
}
23
24
+type apiHandler struct{}
25
+
26
// Serve starts the http server
27
func Serve(address ma.Multiaddr, node *core.IpfsNode) error {
28
r := mux.NewRouter()
24
- handler := &handler{&ipfsHandler{node}}
25
- r.HandleFunc("/ipfs/", handler.postHandler).Methods("POST")
26
- r.PathPrefix("/ipfs/").Handler(handler).Methods("GET")
29
+ objectHandler := &objectHandler{&ipfsHandler{node}}
30
+ apiHandler := &apiHandler{}
31
+
32
+ r.PathPrefix("/api/v0/").Handler(apiHandler).Methods("GET", "POST")
33
+
34
+ r.HandleFunc("/ipfs/", objectHandler.postHandler).Methods("POST")
35
+ r.PathPrefix("/ipfs/").Handler(objectHandler).Methods("GET")
36
+
37
http.Handle("/", r)
38
39
_, host, err := manet.DialArgs(address)
@@ -34,7 +44,7 @@ func Serve(address ma.Multiaddr, node *core.IpfsNode) error {
44
return http.ListenAndServe(host, nil)
45
}
46
37
-func (i *handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
47
+func (i *objectHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
48
path := r.URL.Path[5:]
49
50
nd, err := i.ResolvePath(path)
@@ -55,7 +65,7 @@ func (i *handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
65
io.Copy(w, dr)
66
}
67
58
-func (i *handler) postHandler(w http.ResponseWriter, r *http.Request) {
68
+func (i *objectHandler) postHandler(w http.ResponseWriter, r *http.Request) {
69
nd, err := i.NewDagFromReader(r.Body)
70
if err != nil {
71
w.WriteHeader(http.StatusInternalServerError)
@@ -74,3 +84,75 @@ func (i *handler) postHandler(w http.ResponseWriter, r *http.Request) {
84
w.WriteHeader(http.StatusCreated)
85
w.Write([]byte(mh.Multihash(k).B58String()))
86
}
87
+
88
+func (i *apiHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
89
+ path := strings.Split(r.URL.Path, "/")[3:]
90
+ opts := getOptions(r)
91
+
92
+ // TODO: get args
93
+
94
+ // ensure the requested command exists, otherwise 404
95
+ _, err := commands.Root.Get(path)
96
+ if err != nil {
97
+ w.WriteHeader(http.StatusNotFound)
98
+ w.Write([]byte("404 page not found"))
99
+ return
100
+ }
101
+
102
+ // build the Request and call the command
103
+ req := cmds.NewRequest(path, opts, nil, nil)
104
+ res := commands.Root.Call(req)
105
+
106
+ // if response contains an error, write an HTTP error status code
107
+ if err = res.Error(); err != nil {
108
+ e := err.(cmds.Error)
109
+
110
+ if e.Code == cmds.ErrClient {
111
+ w.WriteHeader(http.StatusBadRequest)
112
+ } else {
113
+ w.WriteHeader(http.StatusInternalServerError)
114
+ }
115
+ }
116
+
117
+ val := res.Value()
118
+
119
+ // if the output value is a io.Reader, stream its output in the request body
120
+ if stream, ok := val.(io.Reader); ok {
121
+ io.Copy(w, stream)
122
+ return
123
+ }
124
+
125
+ // otherwise, marshall and output the response value or error
126
+ if val != nil || res.Error() != nil {
127
+ output, err := res.Marshal()
128
+
129
+ if err != nil {
130
+ w.WriteHeader(http.StatusInternalServerError)
131
+ fmt.Println(err)
132
+ return
133
+ }
134
+
135
+ if output != nil {
136
+ w.Write(output)
137
+ }
138
+ }
139
+}
140
+
141
+// getOptions returns the command options in the given HTTP request
142
+// (from the querystring and request body)
143
+func getOptions(r *http.Request) map[string]interface{} {
144
+ opts := make(map[string]interface{})
145
+
146
+ query := r.URL.Query()
147
+ for k, v := range query {
148
+ opts[k] = v[0]
149
+ }
150
+
151
+ // TODO: get more options from request body (formdata, json, etc)
152
+
153
+ if _, exists := opts[cmds.EncShort]; !exists {
154
+ opts[cmds.EncShort] = cmds.JSON
155
+ }
156
+
157
+ return opts
158
+}