package httpheadimport ()// Version contains protocol major and minor version.typeVersionstruct { Major int Minor int}// RequestLine contains parameters parsed from the first request line.typeRequestLinestruct { Method []byte URI []byte Version Version}// ResponseLine contains parameters parsed from the first response line.typeResponseLinestruct { Version Version Status int Reason []byte}// SplitRequestLine splits given slice of bytes into three chunks without// parsing.func ( []byte) (, , []byte) {returnsplit3(, ' ')}// ParseRequestLine parses http request line like "GET / HTTP/1.0".func ( []byte) ( RequestLine, bool) {varintfor = 0; < len(); ++ { := []if !OctetTypes[].IsToken() {if > 0 && == ' ' {break }return } }if == len() {return }var []byte .Method = [:] .URI, = split2([+1:], ' ')iflen(.URI) == 0 {return }if , , := ParseVersion(); { .Version.Major = .Version.Minor = return , true }return , false}// SplitResponseLine splits given slice of bytes into three chunks without// parsing.func ( []byte) (, , []byte) {returnsplit3(, ' ')}// ParseResponseLine parses first response line into ResponseLine struct.func ( []byte) ( ResponseLine, bool) {var ( []byte []byte ) , , .Reason = split3(, ' ')if , , := ParseVersion(); { .Version.Major = .Version.Minor = } else {return , false }if , := IntFromASCII(); { .Status = } else {return , false }// TODO(gobwas): parse here r.Reason fot TEXT rule: // TEXT = <any OCTET except CTLs, // but including LWS>return , true}var ( httpVersion10 = []byte("HTTP/1.0") httpVersion11 = []byte("HTTP/1.1") httpVersionPrefix = []byte("HTTP/"))// ParseVersion parses major and minor version of HTTP protocol.// It returns parsed values and true if parse is ok.func ( []byte) (, int, bool) {switch {casebytes.Equal(, httpVersion11):return1, 1, truecasebytes.Equal(, httpVersion10):return1, 0, truecaselen() < 8:returncase !bytes.Equal([:5], httpVersionPrefix):return } = [5:] := bytes.IndexByte(, '.')if == -1 {return } , = IntFromASCII([:])if ! {return } , = IntFromASCII([+1:])if ! {return }return , , true}// ReadLine reads line from br. It reads until '\n' and returns bytes without// '\n' or '\r\n' at the end.// It returns err if and only if line does not end in '\n'. Note that read// bytes returned in any case of error.//// It is much like the textproto/Reader.ReadLine() except the thing that it// returns raw bytes, instead of string. That is, it avoids copying bytes read// from br.//// textproto/Reader.ReadLineBytes() is also makes copy of resulting bytes to be// safe with future I/O operations on br.//// We could control I/O operations on br and do not need to make additional// copy for safety.func ( *bufio.Reader) ([]byte, error) {var []bytefor { , := .ReadSlice('\n')if == bufio.ErrBufferFull {// Copy bytes because next read will discard them. = append(, ...)continue }// Avoid copy of single read.if == nil { = } else { = append(, ...) }if != nil {return , }// Size of line is at least 1. // In other case bufio.ReadSlice() returns error. := len()// Cut '\n' or '\r\n'.if > 1 && [-2] == '\r' { = [:-2] } else { = [:-1] }return , nil }}// ParseHeaderLine parses HTTP header as key-value pair. It returns parsed// values and true if parse is ok.func ( []byte) (, []byte, bool) { := bytes.IndexByte(, ':')if == -1 {return } = trim([:])for , := range {if !OctetTypes[].IsToken() {returnnil, nil, false } } = trim([+1:])return , , true}// IntFromASCII converts ascii encoded decimal numeric value from HTTP entities// to an integer.func ( []byte) ( int, bool) {// ASCII numbers all start with the high-order bits 0011. // If you see that, and the next bits are 0-9 (0000 - 1001) you can grab those // bits and interpret them directly as an integer.varintif = len(); < 1 {return0, false }for := 0; < ; ++ {if []&0xf0 != 0x30 {return0, false } += int([]&0xf) * pow(10, --1) }return , true}const ( toLower = 'a' - 'A'// for use with OR. toUpper = ^byte(toLower) // for use with AND.)// CanonicalizeHeaderKey is like standard textproto/CanonicalMIMEHeaderKey,// except that it operates with slice of bytes and modifies it inplace without// copying.func ( []byte) { := truefor , := range {if && 'a' <= && <= 'z' { [] &= toUpper } elseif ! && 'A' <= && <= 'Z' { [] |= toLower } = == '-' }}// pow for integers implementation.// See Donald Knuth, The Art of Computer Programming, Volume 2, Section 4.6.3func pow(, int) int { := 1for > 0 {if &1 != 0 { *= } >>= 1 *= }return}func split3( []byte, byte) (, , []byte) { := bytes.IndexByte(, ) := bytes.IndexByte([+1:], )if == -1 || == -1 {return , nil, nil } += + 1return [:], [+1 : ], [+1:]}func split2( []byte, byte) (, []byte) { := bytes.IndexByte(, )if == -1 {return , nil }return [:], [+1:]}func trim( []byte) []byte {var , intfor = 0; < len() && ([] == ' ' || [] == '\t'); { ++ }for = len(); > && ([-1] == ' ' || [-1] == '\t'); { -- }return [:]}
The pages are generated with Goldsv0.8.2. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.