mirror of
https://github.com/ipfs/kubo.git
synced 2025-06-30 01:52:26 +08:00
cmds/http/handler: set stream error trailer
stream output might break. in these cases we need to notify the client. this is after a 200 response has been sent. We do this by setting a special trailer (header after the body): X-Stream-Error: <error cause> This is similar to what's done by systems like gRPC. This still needs to be read + handled on the other side. License: MIT Signed-off-by: Juan Batiz-Benet <juan@benet.ai>
This commit is contained in:
@ -32,6 +32,7 @@ type Handler struct {
|
|||||||
var ErrNotFound = errors.New("404 page not found")
|
var ErrNotFound = errors.New("404 page not found")
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
StreamErrHeader = "X-Stream-Error"
|
||||||
streamHeader = "X-Stream-Output"
|
streamHeader = "X-Stream-Output"
|
||||||
channelHeader = "X-Chunked-Output"
|
channelHeader = "X-Chunked-Output"
|
||||||
contentTypeHeader = "Content-Type"
|
contentTypeHeader = "Content-Type"
|
||||||
@ -213,8 +214,8 @@ func copyChunks(contentType string, w http.ResponseWriter, out io.Reader) error
|
|||||||
writer.WriteString(transferEncodingHeader + ": chunked\r\n")
|
writer.WriteString(transferEncodingHeader + ": chunked\r\n")
|
||||||
writer.WriteString(channelHeader + ": 1\r\n\r\n")
|
writer.WriteString(channelHeader + ": 1\r\n\r\n")
|
||||||
|
|
||||||
|
writeChunks := func() error {
|
||||||
buf := make([]byte, 32*1024)
|
buf := make([]byte, 32*1024)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
n, err := out.Read(buf)
|
n, err := out.Read(buf)
|
||||||
|
|
||||||
@ -238,13 +239,29 @@ func copyChunks(contentType string, w http.ResponseWriter, out io.Reader) error
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
writer.WriteString("0\r\n\r\n")
|
|
||||||
writer.Flush()
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
streamErr := writeChunks()
|
||||||
|
writer.WriteString("0\r\n") // close body
|
||||||
|
|
||||||
|
// if there was a stream error, write out an error trailer. hopefully
|
||||||
|
// the client will pick it up!
|
||||||
|
if streamErr != nil {
|
||||||
|
writer.WriteString(StreamErrHeader + ": " + sanitizedErrStr(err) + "\r\n")
|
||||||
|
}
|
||||||
|
writer.WriteString("\r\n") // close response
|
||||||
|
writer.Flush()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func sanitizedErrStr(err error) string {
|
||||||
|
s := err.Error()
|
||||||
|
s = strings.Split(s, "\n")[0]
|
||||||
|
s = strings.Split(s, "\r")[0]
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
type flushResponse struct {
|
type flushResponse struct {
|
||||||
W http.ResponseWriter
|
W http.ResponseWriter
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user