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>
Jeromy committed
Aug 28, 2015 at 13:02 UTC
e89f7b8ded9b56d14fca5a1dc2906b8ecbe02a8b
4 files changed
+21
-79
.travis.yml
+1
-2
@@ -7,8 +7,7 @@ os:
7
language: go
8
9
go:
10
-# - 1.3
11
- - 1.4
10
+ - 1.5.1
11
12
env:
13
- TEST_NO_FUSE=1 TEST_VERBOSE=1 TEST_SUITE=test_go_expensive
cmd/ipfs/go_req.go
new
+3
@@ -0,0 +1,3 @@
1
+// +build !go1.5
2
+
3
+`IPFS needs to be built with go version 1.5 or greater`
commands/http/handler.go
+8
-75
@@ -1,7 +1,6 @@
1
package http
2
3
import (
4
- "bufio"
4
"errors"
5
"fmt"
6
"io"
@@ -205,6 +204,10 @@ func sendResponse(w http.ResponseWriter, r *http.Request, res cmds.Response, req
204
}
205
206
h := w.Header()
207
+
208
+ // Set up our potential trailer
209
+ h.Set("Trailer", StreamErrHeader)
210
+
211
if res.Length() > 0 {
212
h.Set(contentLengthHeader, strconv.FormatUint(res.Length(), 10))
213
}
@@ -237,82 +240,12 @@ func sendResponse(w http.ResponseWriter, r *http.Request, res cmds.Response, req
240
return
241
}
242
240
- if err := writeResponse(status, w, out); err != nil {
241
- if strings.Contains(err.Error(), "broken pipe") {
242
- log.Info("client disconnect while writing stream ", err)
243
- return
244
- }
245
-
246
- log.Error("error while writing stream ", err)
247
- }
248
-}
249
-
250
-// Copies from an io.Reader to a http.ResponseWriter.
251
-// Flushes chunks over HTTP stream as they are read (if supported by transport).
252
-func writeResponse(status int, w http.ResponseWriter, out io.Reader) error {
253
- // hijack the connection so we can write our own chunked output and trailers
254
- hijacker, ok := w.(http.Hijacker)
255
- if !ok {
256
- log.Error("Failed to create hijacker! cannot continue!")
257
- return errors.New("Could not create hijacker")
258
- }
259
- conn, writer, err := hijacker.Hijack()
243
+ w.WriteHeader(status)
244
+ _, err = io.Copy(w, out)
245
if err != nil {
261
- return err
262
- }
263
- defer conn.Close()
264
-
265
- // write status
266
- writer.WriteString(fmt.Sprintf("HTTP/1.1 %d %s\r\n", status, http.StatusText(status)))
267
-
268
- // Write out headers
269
- w.Header().Write(writer)
270
-
271
- // end of headers
272
- writer.WriteString("\r\n")
273
-
274
- // write body
275
- streamErr := writeChunks(out, writer)
276
-
277
- // close body
278
- writer.WriteString("0\r\n")
279
-
280
- // if there was a stream error, write out an error trailer. hopefully
281
- // the client will pick it up!
282
- if streamErr != nil {
283
- writer.WriteString(StreamErrHeader + ": " + sanitizedErrStr(streamErr) + "\r\n")
284
- }
285
- writer.WriteString("\r\n") // close response
286
- writer.Flush()
287
- return streamErr
288
-}
289
-
290
-func writeChunks(r io.Reader, w *bufio.ReadWriter) error {
291
- buf := make([]byte, 32*1024)
292
- for {
293
- n, err := r.Read(buf)
294
-
295
- if n > 0 {
296
- length := fmt.Sprintf("%x\r\n", n)
297
- w.WriteString(length)
298
-
299
- _, err := w.Write(buf[0:n])
300
- if err != nil {
301
- return err
302
- }
303
-
304
- w.WriteString("\r\n")
305
- w.Flush()
306
- }
307
-
308
- if err != nil && err != io.EOF {
309
- return err
310
- }
311
- if err == io.EOF {
312
- break
313
- }
246
+ log.Error("err: ", err)
247
+ w.Header().Set(StreamErrHeader, sanitizedErrStr(err))
248
}
315
- return nil
249
}
250
251
func sanitizedErrStr(err error) string {
test/sharness/t0230-channel-streaming-http-content-type.sh
+9
-2
@@ -22,11 +22,14 @@ test_ls_cmd() {
22
test_expect_success "Text encoded channel-streaming command output looks good" '
23
printf "HTTP/1.1 200 OK\r\n" >expected_output &&
24
printf "Content-Type: text/plain\r\n" >>expected_output &&
25
+ printf "Trailer: X-Stream-Error\r\n" >>expected_output &&
26
printf "Transfer-Encoding: chunked\r\n" >>expected_output &&
27
printf "X-Chunked-Output: 1\r\n" >>expected_output &&
28
+ printf "Transfer-Encoding: chunked\r\n" >>expected_output &&
29
printf "\r\n" >>expected_output &&
30
echo QmRmPLc1FsPAn8F8F9DQDEYADNX5ER2sgqiokEvqnYknVW >>expected_output &&
29
- test_cmp expected_output actual_output
31
+ cat actual_output | grep -vE Date > cleaned_output &&
32
+ test_cmp expected_output cleaned_output
33
'
34
35
test_expect_success "JSON encoded channel-streaming command succeeds" '
@@ -39,8 +42,10 @@ test_ls_cmd() {
42
test_expect_success "JSON encoded channel-streaming command output looks good" '
43
printf "HTTP/1.1 200 OK\r\n" >expected_output &&
44
printf "Content-Type: application/json\r\n" >>expected_output &&
45
+ printf "Trailer: X-Stream-Error\r\n" >>expected_output &&
46
printf "Transfer-Encoding: chunked\r\n" >>expected_output &&
47
printf "X-Chunked-Output: 1\r\n" >>expected_output &&
48
+ printf "Transfer-Encoding: chunked\r\n" >>expected_output &&
49
printf "\r\n" >>expected_output &&
50
cat <<-\EOF >>expected_output &&
51
{
@@ -48,8 +53,10 @@ test_ls_cmd() {
53
"Err": ""
54
}
55
EOF
56
+ printf "\n" >> expected_output &&
57
perl -pi -e '"'"'chomp if eof'"'"' expected_output &&
52
- test_cmp expected_output actual_output
58
+ cat actual_output | grep -vE Date > cleaned_output &&
59
+ test_cmp expected_output cleaned_output
60
'
61
}
62