2018-04-24 21:10:01 +00:00
|
|
|
package reader
|
|
|
|
|
|
|
|
// DISCLAIMER
|
|
|
|
// ----------
|
|
|
|
// Some of the content of this file is inspired or copied from
|
|
|
|
// the golang standard library
|
|
|
|
|
|
|
|
import (
|
2018-04-26 08:24:00 +00:00
|
|
|
"fmt"
|
2018-04-24 21:10:01 +00:00
|
|
|
"io"
|
|
|
|
"bufio"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Maximum line length
|
|
|
|
var maxLineLength = 4096
|
|
|
|
|
|
|
|
// Chunk reader
|
|
|
|
type chunkReader struct {
|
|
|
|
reader *bufio.Reader // the reader
|
|
|
|
isEnded bool // If we are done (2 consecutive CRLF)
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// New creates a new reader
|
2018-04-25 13:55:32 +00:00
|
|
|
func NewReader(r io.Reader) (reader *chunkReader) {
|
2018-04-24 21:10:01 +00:00
|
|
|
|
|
|
|
br, ok := r.(*bufio.Reader)
|
|
|
|
if !ok {
|
2018-04-25 13:55:32 +00:00
|
|
|
br = bufio.NewReader(r)
|
2018-04-24 21:10:01 +00:00
|
|
|
}
|
|
|
|
|
2018-04-25 13:55:32 +00:00
|
|
|
return &chunkReader{reader: br}
|
2018-04-24 21:10:01 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Read reads a chunk, err is io.EOF when done
|
|
|
|
func (r *chunkReader) Read() ([]byte, error){
|
|
|
|
|
|
|
|
/* (1) If already ended */
|
|
|
|
if r.isEnded {
|
|
|
|
return nil, io.EOF
|
|
|
|
}
|
|
|
|
|
|
|
|
/* (2) Read line */
|
|
|
|
var line []byte
|
|
|
|
line, err := r.reader.ReadSlice('\n')
|
|
|
|
|
|
|
|
/* (3) manage errors */
|
|
|
|
if err == io.EOF {
|
|
|
|
err = io.ErrUnexpectedEOF
|
|
|
|
}
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2018-04-26 08:24:00 +00:00
|
|
|
if len(line) > maxLineLength {
|
|
|
|
return nil, fmt.Errorf("HTTP line %d exceeded buffer size %d", len(line), maxLineLength)
|
|
|
|
}
|
|
|
|
|
2018-04-24 21:10:01 +00:00
|
|
|
/* (4) Trim */
|
|
|
|
line = removeTrailingSpace(line)
|
|
|
|
|
|
|
|
/* (5) Manage ending line */
|
|
|
|
if len(line) == 0 {
|
|
|
|
r.isEnded = true
|
|
|
|
return line, io.EOF
|
|
|
|
}
|
|
|
|
|
|
|
|
return line, nil
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func removeTrailingSpace(b []byte) []byte{
|
|
|
|
for len(b) > 0 && isASCIISpace(b[len(b)-1]) {
|
|
|
|
b = b[:len(b)-1]
|
|
|
|
}
|
|
|
|
return b
|
|
|
|
}
|
|
|
|
|
|
|
|
func isASCIISpace(b byte) bool {
|
|
|
|
return b == ' ' || b == '\t' || b == '\r' || b =='\n'
|
|
|
|
}
|