mirror of
https://github.com/ipfs/kubo.git
synced 2025-08-06 19:44:01 +08:00
91 lines
2.0 KiB
Go
91 lines
2.0 KiB
Go
package http
|
|
|
|
import (
|
|
"errors"
|
|
"io"
|
|
"net/http"
|
|
|
|
cmds "github.com/jbenet/go-ipfs/commands"
|
|
u "github.com/jbenet/go-ipfs/util"
|
|
)
|
|
|
|
var log = u.Logger("commands/http")
|
|
|
|
type Handler struct {
|
|
ctx cmds.Context
|
|
root *cmds.Command
|
|
}
|
|
|
|
var ErrNotFound = errors.New("404 page not found")
|
|
|
|
const (
|
|
streamHeader = "X-Stream-Output"
|
|
contentTypeHeader = "Content-Type"
|
|
)
|
|
|
|
var mimeTypes = map[string]string{
|
|
cmds.JSON: "application/json",
|
|
cmds.XML: "application/xml",
|
|
cmds.Text: "text/plain",
|
|
}
|
|
|
|
func NewHandler(ctx cmds.Context, root *cmds.Command) *Handler {
|
|
return &Handler{ctx, root}
|
|
}
|
|
|
|
func (i Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
log.Debug("Incoming API request: ", r.URL)
|
|
|
|
req, err := Parse(r, i.root)
|
|
if err != nil {
|
|
if err == ErrNotFound {
|
|
w.WriteHeader(http.StatusNotFound)
|
|
} else {
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
}
|
|
w.Write([]byte(err.Error()))
|
|
return
|
|
}
|
|
req.SetContext(i.ctx)
|
|
|
|
// call the command
|
|
res := i.root.Call(req)
|
|
|
|
// set the Content-Type based on res output
|
|
if _, ok := res.Output().(io.Reader); ok {
|
|
// we don't set the Content-Type for streams, so that browsers can MIME-sniff the type themselves
|
|
// we set this header so clients have a way to know this is an output stream
|
|
// (not marshalled command output)
|
|
// TODO: set a specific Content-Type if the command response needs it to be a certain type
|
|
w.Header().Set(streamHeader, "1")
|
|
|
|
} else {
|
|
enc, found, err := req.Option(cmds.EncShort).String()
|
|
if err != nil || !found {
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
return
|
|
}
|
|
mime := mimeTypes[enc]
|
|
w.Header().Set(contentTypeHeader, mime)
|
|
}
|
|
|
|
// if response contains an error, write an HTTP error status code
|
|
if e := res.Error(); e != nil {
|
|
if e.Code == cmds.ErrClient {
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
} else {
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
}
|
|
}
|
|
|
|
out, err := res.Reader()
|
|
if err != nil {
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
w.Header().Set(contentTypeHeader, "text/plain")
|
|
w.Write([]byte(err.Error()))
|
|
return
|
|
}
|
|
|
|
io.Copy(w, out)
|
|
}
|