ws/internal/http/reader/reader.go

87 lines
1.4 KiB
Go

package reader
// DISCLAIMER
// ----------
// Some of the content of this file is inspired or copied from
// the golang standard library
import (
"fmt"
"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
func NewReader(r io.Reader) (reader *chunkReader) {
br, ok := r.(*bufio.Reader)
if !ok {
br = bufio.NewReader(r)
}
return &chunkReader{reader: br}
}
// 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
}
if len(line) > maxLineLength {
return nil, fmt.Errorf("HTTP line %d exceeded buffer size %d", len(line), maxLineLength)
}
/* (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'
}