func objectMarshaler(res cmds.Response) (io.Reader, error) { o, ok := res.Output().(*Object) if !ok { return nil, u.ErrCast() } return strings.NewReader(o.Hash + "\n"), nil }
// KeyListTextMarshaler outputs a KeyList as plaintext, one key per line func KeyListTextMarshaler(res cmds.Response) (io.Reader, error) { output := res.Output().(*KeyList) buf := new(bytes.Buffer) for _, key := range output.Keys { buf.WriteString(key.B58String() + "\n") } return buf, nil }
func bootstrapMarshaler(res cmds.Response) (io.Reader, error) { v, ok := res.Output().(*BootstrapOutput) if !ok { return nil, u.ErrCast() } buf := new(bytes.Buffer) err := bootstrapWritePeers(buf, "", v.Peers) return buf, err }
func stringListMarshaler(res cmds.Response) (io.Reader, error) { list, ok := res.Output().(*stringList) if !ok { return nil, errors.New("failed to cast []string") } buf := new(bytes.Buffer) for _, s := range list.Strings { buf.WriteString(s) buf.WriteString("\n") } return buf, nil }
func MessageTextMarshaler(res cmds.Response) (io.Reader, error) { return strings.NewReader(res.Output().(*MessageOutput).Message), nil }
func sendResponse(w http.ResponseWriter, r *http.Request, res cmds.Response, req cmds.Request) { mime, err := guessMimeType(res) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } status := http.StatusOK // if response contains an error, write an HTTP error status code if e := res.Error(); e != nil { if e.Code == cmds.ErrClient { status = http.StatusBadRequest } else { status = http.StatusInternalServerError } // NOTE: The error will actually be written out by the reader below } out, err := res.Reader() if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } h := w.Header() // Set up our potential trailer h.Set("Trailer", StreamErrHeader) if res.Length() > 0 { h.Set(contentLengthHeader, strconv.FormatUint(res.Length(), 10)) } 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) mime = "" h.Set(streamHeader, "1") } // if output is a channel and user requested streaming channels, // use chunk copier for the output _, isChan := res.Output().(chan interface{}) if !isChan { _, isChan = res.Output().(<-chan interface{}) } if isChan { h.Set(channelHeader, "1") } if mime != "" { h.Set(contentTypeHeader, mime) } h.Set(transferEncodingHeader, "chunked") if r.Method == "HEAD" { // after all the headers. return } w.WriteHeader(status) _, err = io.Copy(w, out) if err != nil { log.Error("err: ", err) w.Header().Set(StreamErrHeader, sanitizedErrStr(err)) } }
func sendResponse(w http.ResponseWriter, r *http.Request, res cmds.Response, req cmds.Request) { mime, err := guessMimeType(res) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } status := http.StatusOK // if response contains an error, write an HTTP error status code if e := res.Error(); e != nil { if e.Code == cmds.ErrClient { status = http.StatusBadRequest } else { status = http.StatusInternalServerError } // NOTE: The error will actually be written out by the reader below } out, err := res.Reader() if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } h := w.Header() // Set up our potential trailer h.Set("Trailer", StreamErrHeader) if res.Length() > 0 { h.Set(contentLengthHeader, strconv.FormatUint(res.Length(), 10)) } if _, ok := res.Output().(io.Reader); ok { // set streams output type to text to avoid issues with browsers rendering // html pages on priveleged api ports mime = "text/plain" h.Set(streamHeader, "1") } // if output is a channel and user requested streaming channels, // use chunk copier for the output _, isChan := res.Output().(chan interface{}) if !isChan { _, isChan = res.Output().(<-chan interface{}) } if isChan { h.Set(channelHeader, "1") } // catch-all, set to text as default if mime == "" { mime = "text/plain" } h.Set(contentTypeHeader, mime) h.Set(transferEncodingHeader, "chunked") // set 'allowed' headers h.Set("Access-Control-Allow-Headers", "X-Stream-Output, X-Chunked-Output") // expose those headers h.Set("Access-Control-Expose-Headers", "X-Stream-Output, X-Chunked-Output") if r.Method == "HEAD" { // after all the headers. return } w.WriteHeader(status) err = flushCopy(w, out) if err != nil { log.Error("err: ", err) w.Header().Set(StreamErrHeader, sanitizedErrStr(err)) } }
func sendResponse(w http.ResponseWriter, req cmds.Request, res cmds.Response) { mime, err := guessMimeType(res) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } status := http.StatusOK // if response contains an error, write an HTTP error status code if e := res.Error(); e != nil { if e.Code == cmds.ErrClient { status = http.StatusBadRequest } else { status = http.StatusInternalServerError } // NOTE: The error will actually be written out by the reader below } out, err := res.Reader() if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } h := w.Header() if res.Length() > 0 { h.Set(contentLengthHeader, strconv.FormatUint(res.Length(), 10)) } 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) mime = "" h.Set(streamHeader, "1") } // if output is a channel and user requested streaming channels, // use chunk copier for the output _, isChan := res.Output().(chan interface{}) if !isChan { _, isChan = res.Output().(<-chan interface{}) } streamChans, _, _ := req.Option("stream-channels").Bool() if isChan { h.Set(channelHeader, "1") if streamChans { // streaming output from a channel will always be json objects mime = applicationJson } } if mime != "" { h.Set(contentTypeHeader, mime) } h.Set(transferEncodingHeader, "chunked") if err := writeResponse(status, w, out); err != nil { log.Error("error while writing stream", err) } }