HTTP and Listener improvements and bugfixes (#17)

* listener revamp

* improvements to conn lifetimes
This commit is contained in:
Pat Whittingslow
2026-01-11 10:29:16 -03:00
committed by GitHub
parent be194ad7ea
commit 151133dfb4
8 changed files with 145 additions and 77 deletions
+25 -3
View File
@@ -111,6 +111,11 @@ func (h *Header) TryParse(asResponse bool) (needMoreData bool, err error) {
return err == errNeedMore, err
}
// ParsingSuccess returns true if TryParse was successful, that is to say it returned needMoreData==false and err==nil.
func (h *Header) ParsingSuccess() bool {
return h.flags.hasAny(flagDoneParsingHeader)
}
// ReadFromLimited reads at most maxBytesToRead from reader and appends them to underlying buffer.
// Used to accumulate HTTP header for later parsing with [Header.TryParse].
// If read is successful (read length>0) and reader returns [io.EOF] then ReadFromLimited will return a nil error.
@@ -157,6 +162,14 @@ func (h *Header) ReadFromBytes(b []byte) (int, error) {
return len(b), nil
}
// BufferReceived returns the amoung of bytes read during calls to Read* methods.
func (h *Header) BufferReceived() int {
if h.flags.hasAny(flagMangledBuffer | flagOOMReached) {
return 0
}
return len(h.hbuf.buf)
}
// BufferParsed returns the amount of bytes parsed during a call to Parse* methods.
// If the Parse* method completed without error then BufferParsed returns the header's length including the final "\r\n\r\n" text.
// BufferParsed returns 0 if the buffer is invalid/mangled or if no header data has been parsed succesfully.
@@ -321,11 +334,15 @@ func (h *Header) getNonEmptyValue(s headerSlice) []byte {
// AppendRequest appends the request header representation to the buffer and returns the result.
func (h *Header) AppendRequest(dst []byte) ([]byte, error) {
proto := h.Protocol()
if h.flags.hasAny(flagOOMReached) {
return dst, errOOM
} else if h.requestURI.len == 0 || h.proto.len == 0 || h.method.len == 0 {
return dst, errors.New("need method/protocol/request URI to create request header")
} else if h.requestURI.len == 0 || h.method.len == 0 {
return dst, errors.New("need method/request URI to create request header")
} else if len(proto) == 0 {
return dst, errNoProto
}
method := h.Method()
if len(method) == 0 {
dst = append(dst, methodGet...)
@@ -333,7 +350,6 @@ func (h *Header) AppendRequest(dst []byte) ([]byte, error) {
dst = append(dst, method...)
}
uri := h.RequestURI()
proto := h.Protocol()
dst = append(dst, ' ')
dst = append(dst, uri...)
@@ -348,12 +364,18 @@ func (h *Header) AppendRequest(dst []byte) ([]byte, error) {
// AppendResponse appends the response header representation to the buffer and returns the result.
func (h *Header) AppendResponse(dst []byte) ([]byte, error) {
proto := h.Protocol()
if h.flags.hasAny(flagOOMReached) {
return dst, errOOM
} else if h.statusCode.len == 0 || h.statusText.len == 0 {
return dst, errors.New("invalid status code or text")
} else if len(proto) == 0 {
return dst, errNoProto
}
code, text := h.Status()
dst = append(dst, proto...)
dst = append(dst, ' ')
dst = append(dst, code...)
dst = append(dst, ' ')
dst = append(dst, text...)
+2 -1
View File
@@ -8,6 +8,7 @@ import (
)
var (
errNoProto = errors.New("missing protocol, HTTP/0.9 unsupported")
errNeedMore = errors.New("need more data: cannot find trailing lf")
errUnparsed = errors.New("need to finish parsing")
errInvalidName = errors.New("invalid header name")
@@ -250,7 +251,7 @@ func (h *Header) appendSlice(value string) headerSlice {
h.flags |= flagOOMReached
return headerSlice{}
}
h.hbuf.buf = slices.Grow(h.hbuf.buf, len(value))
h.hbuf.buf = slices.Grow(h.hbuf.buf, len(value)+1) // Grow 1 beyond due to slice validity.
}
h.flags |= flagMangledBuffer
return h.hbuf.mustAppendSlice(value)