Example #1
0
func trimWSRight(p []byte) []byte {
	var i int
	for i = len(p); i > 0; i-- {
		if !web.IsSpaceByte(p[i-1]) {
			break
		}
	}
	return p[0:i]
}
Example #2
0
func parseHeader(b *bufio.Reader) (header web.StringsMap, err os.Error) {

	const (
		// Max size for header line
		maxLineSize = 4096
		// Max size for header value
		maxValueSize = 4096
		// Maximum number of headers
		maxHeaderCount = 256
	)

	header = make(web.StringsMap)
	lastKey := ""
	headerCount := 0

	for {
		p, err := b.ReadSlice('\n')
		if err != nil {
			if err == bufio.ErrBufferFull {
				err = ErrLineTooLong
			} else if err == os.EOF {
				err = io.ErrUnexpectedEOF
			}
			return nil, err
		}

		// remove line terminator
		if len(p) >= 2 && p[len(p)-2] == '\r' {
			// \r\n
			p = p[0 : len(p)-2]
		} else {
			// \n
			p = p[0 : len(p)-1]
		}

		// End of headers?
		if len(p) == 0 {
			break
		}

		// Don't allow huge header lines.
		if len(p) > maxLineSize {
			return nil, ErrLineTooLong
		}

		if web.IsSpaceByte(p[0]) {

			if lastKey == "" {
				return nil, ErrBadHeaderLine
			}

			p = trimWSLeft(trimWSRight(p))

			if len(p) > 0 {
				values := header[lastKey]
				value := values[len(values)-1]
				value = value + " " + string(p)
				if len(value) > maxValueSize {
					return nil, ErrHeaderTooLong
				}
				values[len(values)-1] = value
			}

		} else {

			// New header
			headerCount = headerCount + 1
			if headerCount > maxHeaderCount {
				return nil, ErrHeadersTooLong
			}

			// Key
			i := skipBytes(p, web.IsTokenByte)
			if i < 1 {
				return nil, ErrBadHeaderLine
			}
			key := web.HeaderNameBytes(p[0:i])
			p = p[i:]
			lastKey = key

			p = trimWSLeft(p)

			// Colon
			if p[0] != ':' {
				return nil, ErrBadHeaderLine
			}
			p = p[1:]

			// Value
			p = trimWSLeft(p)
			value := string(trimWSRight(p))
			header.Append(key, value)
		}
	}
	return header, nil
}