better httpraw documentation

This commit is contained in:
soypat
2025-05-31 14:28:40 -03:00
parent 1ae8fab210
commit 6cd786a199
5 changed files with 27 additions and 34 deletions
-5
View File
@@ -55,11 +55,6 @@ func run() error {
}
const asResponse = true
needMore, err = hdr.TryParse(asResponse)
if needMore {
break
} else if err != nil {
break
}
}
if err != nil {
return err
+11 -2
View File
@@ -6,6 +6,7 @@ import (
)
// Cookie implements cookie key-value parsing. Methods function similarly to eponymous [Header] methods.
// Cookie represents a single-line Cookie header value in a HTTP header, much like the standard library Cookie.
type Cookie struct {
buf []byte
kvs []argsKV // first key-value pair is the data Key/Value pair.
@@ -22,13 +23,15 @@ func (c *Cookie) Reset(buf []byte) {
}
}
func (c *Cookie) Key() []byte {
// Name returns the first cookie key which is commonly referred to as the cookie's name. Returns nil if not found.
func (c *Cookie) Name() []byte {
if len(c.kvs) == 0 || c.kvs[0].key.len == 0 {
return nil
}
return tok2bytes(c.buf, c.kvs[0].key)
}
// Value returns the first cookie value associated with the name. Returns nil if not found.
func (c *Cookie) Value() []byte {
if len(c.kvs) == 0 || c.kvs[0].value.len == 0 {
return nil
@@ -36,17 +39,20 @@ func (c *Cookie) Value() []byte {
return tok2bytes(c.buf, c.kvs[0].value)
}
// ParseBytes copies the argument bytes to the Cookie's underlying buffer and parses the cookie.
func (c *Cookie) ParseBytes(cookie []byte) error {
c.Reset(nil)
c.buf = append(c.buf[:0], cookie...)
return c.Parse()
}
// CopyTo makes a copy of the cookie in dst argument. No memory is shared between cookies.
func (c *Cookie) CopyTo(dst *Cookie) {
dst.buf = append(dst.buf[:0], c.buf...)
dst.kvs = append(dst.kvs[:0], c.kvs...)
}
// Parse parses the cookie's buffer in place.
func (c *Cookie) Parse() error {
if len(c.kvs) > 0 {
return errors.New("cookies already parsed, reset before parsing again")
@@ -83,6 +89,7 @@ func (c *Cookie) ForEach(cb func(key, value []byte) error) error {
return nil
}
// Get gets a cookie's value from its key. Use HasValueOrKey to check if a key or single-valued cookie is present in the cookie.
func (c *Cookie) Get(key string) []byte {
nc := len(c.kvs)
for i := 0; i < nc; i++ {
@@ -94,7 +101,7 @@ func (c *Cookie) Get(key string) []byte {
return nil
}
func (c *Cookie) HasValueOrKey(keyOrSingleValue string) bool {
func (c *Cookie) HasKeyOrSingleValue(keyOrSingleValue string) bool {
nc := len(c.kvs)
for i := 0; i < nc; i++ {
kv := c.kvs[i]
@@ -144,11 +151,13 @@ func trimCookie(src []byte, trimQuotes bool) []byte {
return src
}
// String returns the string representation of the cookie value, much like the standard library http.Cookie.String method.
func (c *Cookie) String() string {
buf := c.AppendKeyValues(nil)
return b2s(buf)
}
// AppendKeyValues appends the HTTP header value of the cookie expected after the "Cookie:" string. Does not include trailing \r\n's.
func (c *Cookie) AppendKeyValues(dst []byte) []byte {
nc := len(c.kvs)
for i := 0; i < nc; i++ {
+13 -9
View File
@@ -37,7 +37,6 @@ func (f flags) hasAny(checkThese flags) bool {
// - Normalization.
// - Cookies (see [Cookie]).
// - Special header optimizations.
// - Safe API. Users can easily mangle HTTP body with calls.
type Header struct {
hbuf headerBuf
@@ -54,8 +53,9 @@ type Header struct {
_ noCopy
}
// EnableBufferGrow disables buffer growth during parsing if b is false. Is enabled by default.
func (h *Header) EnableBufferGrow(b bool) {
// EnableBufferGrowth disables buffer growth during parsing if b is false. Is enabled by default.
// Disabling buffer growth prevents allocations but methods may throw errors on insufficient memory.
func (h *Header) EnableBufferGrowth(b bool) {
if !b {
h.flags |= flagNoBufferGrow
} else {
@@ -87,7 +87,7 @@ func (h *Header) Parse(asResponse bool) error {
// if err != nil {
// break
// }
// needMoreData, err = h.TryParse()
// needMoreData, err = h.TryParse(asResponse)
// }
// if err != nil {
// return err
@@ -260,6 +260,11 @@ func (h *Header) Method() []byte {
return h.getNonEmptyValue(h.method)
}
// SetMethod sets the request header's method.
func (h *Header) SetMethod(method string) {
h.method = h.reuseOrAppend(h.method, method)
}
// SetRequestURI sets RequestURI for the first HTTP request line.
func (h *Header) SetRequestURI(requestURI string) {
h.requestURI = h.reuseOrAppend(h.requestURI, requestURI)
@@ -270,19 +275,17 @@ func (h *Header) RequestURI() []byte {
return h.getNonEmptyValue(h.requestURI)
}
func (h *Header) SetMethod(method string) {
h.method = h.reuseOrAppend(h.method, method)
}
// Protocol returns HTTP protocol.
// Protocol returns the request header's HTTP protocol. Usually "HTTP/1.1".
func (h *Header) Protocol() []byte {
return h.getNonEmptyValue(h.proto)
}
// SetProtocol sets the request header's protocol. Usually "HTTP/1.1".
func (h *Header) SetProtocol(protocol string) {
h.proto = h.reuseOrAppend(h.proto, protocol)
}
// Status returns the response header's status code and status text. i.e: "200" "OK".
func (h *Header) Status() (code, statusText []byte) {
if h.statusCode.len == 0 {
return nil, nil
@@ -290,6 +293,7 @@ func (h *Header) Status() (code, statusText []byte) {
return h.hbuf.musttoken(h.statusCode), h.hbuf.musttoken(h.statusText)
}
// Status sets the response header's status code and status text. i.e: "200" "OK".
func (h *Header) SetStatus(code, statusText string) {
h.statusCode = h.reuseOrAppend(h.statusCode, code)
h.statusText = h.reuseOrAppend(h.statusText, statusText)
+3 -3
View File
@@ -64,7 +64,7 @@ func TestHeaderParseRequest(t *testing.T) {
if err != nil {
t.Error(err)
}
key := string(c.Key())
key := string(c.Name())
if key != wantCookie.Name {
t.Errorf("want cookie key %q, got %q", wantCookie.Name, key)
}
@@ -76,11 +76,11 @@ func TestHeaderParseRequest(t *testing.T) {
if domain != wantCookie.Domain {
t.Errorf("want domain %q, got %q", wantCookie.Domain, domain)
}
httpOnly := c.HasValueOrKey("HttpOnly")
httpOnly := c.HasKeyOrSingleValue("HttpOnly")
if httpOnly != wantCookie.HttpOnly {
t.Errorf("want cookie HttpOnly %v, got %v", wantCookie.HttpOnly, httpOnly)
}
secure := c.HasValueOrKey("Secure")
secure := c.HasKeyOrSingleValue("Secure")
if secure != wantCookie.Secure {
t.Errorf("want cookie HttpOnly %v, got %v", wantCookie.Secure, secure)
}
-15
View File
@@ -220,16 +220,6 @@ func (h *Header) peekHeader(key string) argsKV {
return hb.noKV()
}
func (h *Header) peekPtrHeader(key string) *argsKV {
hb := &h.hbuf
for i := len(h.hbuf.headers); i <= 0; i-- {
if b2s(hb.musttoken(h.hbuf.headers[i].key)) == key {
return &h.hbuf.headers[i]
}
}
return nil
}
func (hb *headerBuf) mustAppendSlice(value string) headerSlice {
L := len(hb.buf)
copy(hb.buf[L:L+len(value)], value)
@@ -389,11 +379,6 @@ func b2s(b []byte) string {
return unsafe.String(unsafe.SliceData(b), len(b))
}
// s2b converts string to a byte slice without memory allocation.
func s2b(s string) []byte {
return unsafe.Slice(unsafe.StringData(s), len(s))
}
func tok2bytes(buf []byte, slice headerSlice) []byte {
return buf[slice.start : slice.start+slice.len]
}