From 73353824e91c62623b6bc6c3681b6a6dfda9e484 Mon Sep 17 00:00:00 2001 From: Matt Bell <mappum@gmail.com> Date: Wed, 22 Oct 2014 15:26:18 -0700 Subject: [PATCH] server/http: Added HTTP API handler --- server/http/http.go | 94 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 88 insertions(+), 6 deletions(-) diff --git a/server/http/http.go b/server/http/http.go index 3c5992c6e..4b5a6ac3c 100644 --- a/server/http/http.go +++ b/server/http/http.go @@ -5,25 +5,35 @@ import ( "fmt" "io" "net/http" + "strings" "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/gorilla/mux" ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" manet "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr/net" mh "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multihash" + cmds "github.com/jbenet/go-ipfs/commands" core "github.com/jbenet/go-ipfs/core" + "github.com/jbenet/go-ipfs/core/commands" ) -type handler struct { +type objectHandler struct { ipfs } +type apiHandler struct{} + // Serve starts the http server func Serve(address ma.Multiaddr, node *core.IpfsNode) error { r := mux.NewRouter() - handler := &handler{&ipfsHandler{node}} - r.HandleFunc("/ipfs/", handler.postHandler).Methods("POST") - r.PathPrefix("/ipfs/").Handler(handler).Methods("GET") + objectHandler := &objectHandler{&ipfsHandler{node}} + apiHandler := &apiHandler{} + + r.PathPrefix("/api/v0/").Handler(apiHandler).Methods("GET", "POST") + + r.HandleFunc("/ipfs/", objectHandler.postHandler).Methods("POST") + r.PathPrefix("/ipfs/").Handler(objectHandler).Methods("GET") + http.Handle("/", r) _, host, err := manet.DialArgs(address) @@ -34,7 +44,7 @@ func Serve(address ma.Multiaddr, node *core.IpfsNode) error { return http.ListenAndServe(host, nil) } -func (i *handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { +func (i *objectHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { path := r.URL.Path[5:] nd, err := i.ResolvePath(path) @@ -55,7 +65,7 @@ func (i *handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { io.Copy(w, dr) } -func (i *handler) postHandler(w http.ResponseWriter, r *http.Request) { +func (i *objectHandler) postHandler(w http.ResponseWriter, r *http.Request) { nd, err := i.NewDagFromReader(r.Body) if err != nil { w.WriteHeader(http.StatusInternalServerError) @@ -74,3 +84,75 @@ func (i *handler) postHandler(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusCreated) w.Write([]byte(mh.Multihash(k).B58String())) } + +func (i *apiHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + path := strings.Split(r.URL.Path, "/")[3:] + opts := getOptions(r) + + // TODO: get args + + // ensure the requested command exists, otherwise 404 + _, err := commands.Root.Get(path) + if err != nil { + w.WriteHeader(http.StatusNotFound) + w.Write([]byte("404 page not found")) + return + } + + // build the Request and call the command + req := cmds.NewRequest(path, opts, nil, nil) + res := commands.Root.Call(req) + + // if response contains an error, write an HTTP error status code + if err = res.Error(); err != nil { + e := err.(cmds.Error) + + if e.Code == cmds.ErrClient { + w.WriteHeader(http.StatusBadRequest) + } else { + w.WriteHeader(http.StatusInternalServerError) + } + } + + val := res.Value() + + // if the output value is a io.Reader, stream its output in the request body + if stream, ok := val.(io.Reader); ok { + io.Copy(w, stream) + return + } + + // otherwise, marshall and output the response value or error + if val != nil || res.Error() != nil { + output, err := res.Marshal() + + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + fmt.Println(err) + return + } + + if output != nil { + w.Write(output) + } + } +} + +// getOptions returns the command options in the given HTTP request +// (from the querystring and request body) +func getOptions(r *http.Request) map[string]interface{} { + opts := make(map[string]interface{}) + + query := r.URL.Query() + for k, v := range query { + opts[k] = v[0] + } + + // TODO: get more options from request body (formdata, json, etc) + + if _, exists := opts[cmds.EncShort]; !exists { + opts[cmds.EncShort] = cmds.JSON + } + + return opts +} -- GitLab