// Send response body if header specifies chunked encoding. rdSize specifies // the size of each read on Reader, it should be set to be the buffer size of // the Reader, this parameter is added for testing. func sendBodyChunked(w io.Writer, r *bufio.Reader, rdSize int) (err error) { // debug.Println("Sending chunked body") for { var s []byte // Read chunk size line, ignore chunk extension if any. if s, err = r.PeekSlice('\n'); err != nil { errl.Println("peek chunk size:", err) return } smid := bytes.IndexByte(s, ';') if smid == -1 { smid = len(s) } else { // use error log to find usage of chunk extension errl.Printf("got chunk extension: %s\n", s) } var size int64 if size, err = ParseIntFromBytes(TrimSpace(s[:smid]), 16); err != nil { errl.Println("chunk size invalid:", err) return } /* if debug { // To debug getting malformed response status line with "0\r\n". if c, ok := w.(*clientConn); ok { debug.Printf("cli(%s) chunk size %d %#v\n", c.RemoteAddr(), size, string(s)) } } */ if size == 0 { r.Skip(len(s)) if err = skipCRLF(r); err != nil { return } if _, err = w.Write([]byte(chunkEnd)); err != nil { debug.Println("send chunk ending:", err) } return } // RFC 2616 19.3 only suggest tolerating single LF for // headers, not for chunked encoding. So assume the server will send // CRLF. If not, the following parse int may find errors. total := len(s) + int(size) + 2 // total data size for this chunk, including ending CRLF // PeekSlice will not advance reader, so we can just copy total sized data. if err = copyN(w, r, total, rdSize); err != nil { debug.Println("copy chunked data:", err) return } } }
// Send response body if header specifies chunked encoding. rdSize specifies // the size of each read on Reader, it should be set to be the buffer size of // the Reader, this parameter is added for testing. func sendBodyChunked(r *bufio.Reader, w io.Writer, rdSize int) (err error) { // debug.Println("Sending chunked body") for { var s []byte // Read chunk size line, ignore chunk extension if any. if s, err = r.PeekSlice('\n'); err != nil { errl.Println("peeking chunk size:", err) return } // debug.Printf("Chunk size line %s\n", s) smid := bytes.IndexByte(s, ';') if smid == -1 { smid = len(s) } var size int64 if size, err = ParseIntFromBytes(TrimSpace(s[:smid]), 16); err != nil { errl.Println("chunk size invalid:", err) return } // end of chunked data. As we remove trailer header in request sending // to server, there should be no trailer in response. // TODO: Is it possible for client request body to have trailers in it? if size == 0 { r.Skip(len(s)) skipCRLF(r) if _, err = w.Write([]byte(chunkEnd)); err != nil { debug.Println("sending chunk ending:", err) } return } // The spec section 19.3 only suggest toleranting single LF for // headers, not for chunked encoding. So assume the server will send // CRLF. If not, the following parse int may find errors. total := len(s) + int(size) + 2 // total data size for this chunk, including ending CRLF // PeekSlice will not advance reader, so we can just copy total sized data. if err = copyN(w, r, total, rdSize); err != nil { debug.Println("copying chunked data:", err) return } } return }