@cryptotaxi247 / kubo / commits / 73353824e

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 +}