github.com/zignig/go-ipfs@v0.0.0-20141111235910-c9e5fdf55a52/commands/http/handler.go (about) 1 package http 2 3 import ( 4 "errors" 5 "io" 6 "net/http" 7 8 cmds "github.com/jbenet/go-ipfs/commands" 9 u "github.com/jbenet/go-ipfs/util" 10 ) 11 12 var log = u.Logger("commands/http") 13 14 type Handler struct { 15 ctx cmds.Context 16 root *cmds.Command 17 } 18 19 var ErrNotFound = errors.New("404 page not found") 20 21 const streamHeader = "X-Stream-Output" 22 23 var mimeTypes = map[string]string{ 24 cmds.JSON: "application/json", 25 cmds.XML: "application/xml", 26 cmds.Text: "text/plain", 27 } 28 29 func NewHandler(ctx cmds.Context, root *cmds.Command) *Handler { 30 return &Handler{ctx, root} 31 } 32 33 func (i Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { 34 log.Debug("Incoming API request: ", r.URL) 35 36 req, err := Parse(r, i.root) 37 if err != nil { 38 if err == ErrNotFound { 39 w.WriteHeader(http.StatusNotFound) 40 } else { 41 w.WriteHeader(http.StatusBadRequest) 42 } 43 w.Write([]byte(err.Error())) 44 return 45 } 46 req.SetContext(i.ctx) 47 48 // call the command 49 res := i.root.Call(req) 50 51 // set the Content-Type based on res output 52 if _, ok := res.Output().(io.Reader); ok { 53 // we don't set the Content-Type for streams, so that browsers can MIME-sniff the type themselves 54 // we set this header so clients have a way to know this is an output stream 55 // (not marshalled command output) 56 // TODO: set a specific Content-Type if the command response needs it to be a certain type 57 w.Header().Set(streamHeader, "1") 58 59 } else { 60 enc, err := req.Option(cmds.EncShort).String() 61 if err != nil || len(enc) == 0 { 62 w.WriteHeader(http.StatusInternalServerError) 63 return 64 } 65 mime := mimeTypes[enc] 66 w.Header().Set("Content-Type", mime) 67 } 68 69 // if response contains an error, write an HTTP error status code 70 if e := res.Error(); e != nil { 71 if e.Code == cmds.ErrClient { 72 w.WriteHeader(http.StatusBadRequest) 73 } else { 74 w.WriteHeader(http.StatusInternalServerError) 75 } 76 } 77 78 out, err := res.Reader() 79 if err != nil { 80 w.WriteHeader(http.StatusInternalServerError) 81 w.Header().Set("Content-Type", "text/plain") 82 w.Write([]byte(err.Error())) 83 return 84 } 85 86 io.Copy(w, out) 87 }