mirror of
https://github.com/ipfs/kubo.git
synced 2025-06-27 07:57:30 +08:00
use go's built in handling of trailers and dont do custom chunking
License: MIT Signed-off-by: Jeromy <jeromyj@gmail.com> use go1.5 syntax to ensure builds on older versions fail License: MIT Signed-off-by: Jeromy <jeromyj@gmail.com> fix t0230 License: MIT Signed-off-by: Jeromy <jeromyj@gmail.com>
This commit is contained in:
@ -7,8 +7,7 @@ os:
|
|||||||
language: go
|
language: go
|
||||||
|
|
||||||
go:
|
go:
|
||||||
# - 1.3
|
- 1.5.1
|
||||||
- 1.4
|
|
||||||
|
|
||||||
env:
|
env:
|
||||||
- TEST_NO_FUSE=1 TEST_VERBOSE=1 TEST_SUITE=test_go_expensive
|
- TEST_NO_FUSE=1 TEST_VERBOSE=1 TEST_SUITE=test_go_expensive
|
||||||
|
3
cmd/ipfs/go_req.go
Normal file
3
cmd/ipfs/go_req.go
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
// +build !go1.5
|
||||||
|
|
||||||
|
`IPFS needs to be built with go version 1.5 or greater`
|
@ -1,7 +1,6 @@
|
|||||||
package http
|
package http
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
@ -205,6 +204,10 @@ func sendResponse(w http.ResponseWriter, r *http.Request, res cmds.Response, req
|
|||||||
}
|
}
|
||||||
|
|
||||||
h := w.Header()
|
h := w.Header()
|
||||||
|
|
||||||
|
// Set up our potential trailer
|
||||||
|
h.Set("Trailer", StreamErrHeader)
|
||||||
|
|
||||||
if res.Length() > 0 {
|
if res.Length() > 0 {
|
||||||
h.Set(contentLengthHeader, strconv.FormatUint(res.Length(), 10))
|
h.Set(contentLengthHeader, strconv.FormatUint(res.Length(), 10))
|
||||||
}
|
}
|
||||||
@ -237,82 +240,12 @@ func sendResponse(w http.ResponseWriter, r *http.Request, res cmds.Response, req
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := writeResponse(status, w, out); err != nil {
|
w.WriteHeader(status)
|
||||||
if strings.Contains(err.Error(), "broken pipe") {
|
_, err = io.Copy(w, out)
|
||||||
log.Info("client disconnect while writing stream ", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Error("error while writing stream ", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copies from an io.Reader to a http.ResponseWriter.
|
|
||||||
// Flushes chunks over HTTP stream as they are read (if supported by transport).
|
|
||||||
func writeResponse(status int, w http.ResponseWriter, out io.Reader) error {
|
|
||||||
// hijack the connection so we can write our own chunked output and trailers
|
|
||||||
hijacker, ok := w.(http.Hijacker)
|
|
||||||
if !ok {
|
|
||||||
log.Error("Failed to create hijacker! cannot continue!")
|
|
||||||
return errors.New("Could not create hijacker")
|
|
||||||
}
|
|
||||||
conn, writer, err := hijacker.Hijack()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
log.Error("err: ", err)
|
||||||
|
w.Header().Set(StreamErrHeader, sanitizedErrStr(err))
|
||||||
}
|
}
|
||||||
defer conn.Close()
|
|
||||||
|
|
||||||
// write status
|
|
||||||
writer.WriteString(fmt.Sprintf("HTTP/1.1 %d %s\r\n", status, http.StatusText(status)))
|
|
||||||
|
|
||||||
// Write out headers
|
|
||||||
w.Header().Write(writer)
|
|
||||||
|
|
||||||
// end of headers
|
|
||||||
writer.WriteString("\r\n")
|
|
||||||
|
|
||||||
// write body
|
|
||||||
streamErr := writeChunks(out, writer)
|
|
||||||
|
|
||||||
// close body
|
|
||||||
writer.WriteString("0\r\n")
|
|
||||||
|
|
||||||
// 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(streamErr) + "\r\n")
|
|
||||||
}
|
|
||||||
writer.WriteString("\r\n") // close response
|
|
||||||
writer.Flush()
|
|
||||||
return streamErr
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeChunks(r io.Reader, w *bufio.ReadWriter) error {
|
|
||||||
buf := make([]byte, 32*1024)
|
|
||||||
for {
|
|
||||||
n, err := r.Read(buf)
|
|
||||||
|
|
||||||
if n > 0 {
|
|
||||||
length := fmt.Sprintf("%x\r\n", n)
|
|
||||||
w.WriteString(length)
|
|
||||||
|
|
||||||
_, err := w.Write(buf[0:n])
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
w.WriteString("\r\n")
|
|
||||||
w.Flush()
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil && err != io.EOF {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err == io.EOF {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func sanitizedErrStr(err error) string {
|
func sanitizedErrStr(err error) string {
|
||||||
|
@ -22,11 +22,14 @@ test_ls_cmd() {
|
|||||||
test_expect_success "Text encoded channel-streaming command output looks good" '
|
test_expect_success "Text encoded channel-streaming command output looks good" '
|
||||||
printf "HTTP/1.1 200 OK\r\n" >expected_output &&
|
printf "HTTP/1.1 200 OK\r\n" >expected_output &&
|
||||||
printf "Content-Type: text/plain\r\n" >>expected_output &&
|
printf "Content-Type: text/plain\r\n" >>expected_output &&
|
||||||
|
printf "Trailer: X-Stream-Error\r\n" >>expected_output &&
|
||||||
printf "Transfer-Encoding: chunked\r\n" >>expected_output &&
|
printf "Transfer-Encoding: chunked\r\n" >>expected_output &&
|
||||||
printf "X-Chunked-Output: 1\r\n" >>expected_output &&
|
printf "X-Chunked-Output: 1\r\n" >>expected_output &&
|
||||||
|
printf "Transfer-Encoding: chunked\r\n" >>expected_output &&
|
||||||
printf "\r\n" >>expected_output &&
|
printf "\r\n" >>expected_output &&
|
||||||
echo QmRmPLc1FsPAn8F8F9DQDEYADNX5ER2sgqiokEvqnYknVW >>expected_output &&
|
echo QmRmPLc1FsPAn8F8F9DQDEYADNX5ER2sgqiokEvqnYknVW >>expected_output &&
|
||||||
test_cmp expected_output actual_output
|
cat actual_output | grep -vE Date > cleaned_output &&
|
||||||
|
test_cmp expected_output cleaned_output
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success "JSON encoded channel-streaming command succeeds" '
|
test_expect_success "JSON encoded channel-streaming command succeeds" '
|
||||||
@ -39,8 +42,10 @@ test_ls_cmd() {
|
|||||||
test_expect_success "JSON encoded channel-streaming command output looks good" '
|
test_expect_success "JSON encoded channel-streaming command output looks good" '
|
||||||
printf "HTTP/1.1 200 OK\r\n" >expected_output &&
|
printf "HTTP/1.1 200 OK\r\n" >expected_output &&
|
||||||
printf "Content-Type: application/json\r\n" >>expected_output &&
|
printf "Content-Type: application/json\r\n" >>expected_output &&
|
||||||
|
printf "Trailer: X-Stream-Error\r\n" >>expected_output &&
|
||||||
printf "Transfer-Encoding: chunked\r\n" >>expected_output &&
|
printf "Transfer-Encoding: chunked\r\n" >>expected_output &&
|
||||||
printf "X-Chunked-Output: 1\r\n" >>expected_output &&
|
printf "X-Chunked-Output: 1\r\n" >>expected_output &&
|
||||||
|
printf "Transfer-Encoding: chunked\r\n" >>expected_output &&
|
||||||
printf "\r\n" >>expected_output &&
|
printf "\r\n" >>expected_output &&
|
||||||
cat <<-\EOF >>expected_output &&
|
cat <<-\EOF >>expected_output &&
|
||||||
{
|
{
|
||||||
@ -48,8 +53,10 @@ test_ls_cmd() {
|
|||||||
"Err": ""
|
"Err": ""
|
||||||
}
|
}
|
||||||
EOF
|
EOF
|
||||||
|
printf "\n" >> expected_output &&
|
||||||
perl -pi -e '"'"'chomp if eof'"'"' expected_output &&
|
perl -pi -e '"'"'chomp if eof'"'"' expected_output &&
|
||||||
test_cmp expected_output actual_output
|
cat actual_output | grep -vE Date > cleaned_output &&
|
||||||
|
test_cmp expected_output cleaned_output
|
||||||
'
|
'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user