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 const asResponse = true
needMore, err = hdr.TryParse(asResponse) needMore, err = hdr.TryParse(asResponse)
if needMore {
break
} else if err != nil {
break
}
} }
if err != nil { if err != nil {
return err 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 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 { type Cookie struct {
buf []byte buf []byte
kvs []argsKV // first key-value pair is the data Key/Value pair. 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 { if len(c.kvs) == 0 || c.kvs[0].key.len == 0 {
return nil return nil
} }
return tok2bytes(c.buf, c.kvs[0].key) 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 { func (c *Cookie) Value() []byte {
if len(c.kvs) == 0 || c.kvs[0].value.len == 0 { if len(c.kvs) == 0 || c.kvs[0].value.len == 0 {
return nil return nil
@@ -36,17 +39,20 @@ func (c *Cookie) Value() []byte {
return tok2bytes(c.buf, c.kvs[0].value) 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 { func (c *Cookie) ParseBytes(cookie []byte) error {
c.Reset(nil) c.Reset(nil)
c.buf = append(c.buf[:0], cookie...) c.buf = append(c.buf[:0], cookie...)
return c.Parse() 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) { func (c *Cookie) CopyTo(dst *Cookie) {
dst.buf = append(dst.buf[:0], c.buf...) dst.buf = append(dst.buf[:0], c.buf...)
dst.kvs = append(dst.kvs[:0], c.kvs...) dst.kvs = append(dst.kvs[:0], c.kvs...)
} }
// Parse parses the cookie's buffer in place.
func (c *Cookie) Parse() error { func (c *Cookie) Parse() error {
if len(c.kvs) > 0 { if len(c.kvs) > 0 {
return errors.New("cookies already parsed, reset before parsing again") 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 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 { func (c *Cookie) Get(key string) []byte {
nc := len(c.kvs) nc := len(c.kvs)
for i := 0; i < nc; i++ { for i := 0; i < nc; i++ {
@@ -94,7 +101,7 @@ func (c *Cookie) Get(key string) []byte {
return nil return nil
} }
func (c *Cookie) HasValueOrKey(keyOrSingleValue string) bool { func (c *Cookie) HasKeyOrSingleValue(keyOrSingleValue string) bool {
nc := len(c.kvs) nc := len(c.kvs)
for i := 0; i < nc; i++ { for i := 0; i < nc; i++ {
kv := c.kvs[i] kv := c.kvs[i]
@@ -144,11 +151,13 @@ func trimCookie(src []byte, trimQuotes bool) []byte {
return src 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 { func (c *Cookie) String() string {
buf := c.AppendKeyValues(nil) buf := c.AppendKeyValues(nil)
return b2s(buf) 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 { func (c *Cookie) AppendKeyValues(dst []byte) []byte {
nc := len(c.kvs) nc := len(c.kvs)
for i := 0; i < nc; i++ { for i := 0; i < nc; i++ {
+13 -9
View File
@@ -37,7 +37,6 @@ func (f flags) hasAny(checkThese flags) bool {
// - Normalization. // - Normalization.
// - Cookies (see [Cookie]). // - Cookies (see [Cookie]).
// - Special header optimizations. // - Special header optimizations.
// - Safe API. Users can easily mangle HTTP body with calls.
type Header struct { type Header struct {
hbuf headerBuf hbuf headerBuf
@@ -54,8 +53,9 @@ type Header struct {
_ noCopy _ noCopy
} }
// EnableBufferGrow disables buffer growth during parsing if b is false. Is enabled by default. // EnableBufferGrowth disables buffer growth during parsing if b is false. Is enabled by default.
func (h *Header) EnableBufferGrow(b bool) { // Disabling buffer growth prevents allocations but methods may throw errors on insufficient memory.
func (h *Header) EnableBufferGrowth(b bool) {
if !b { if !b {
h.flags |= flagNoBufferGrow h.flags |= flagNoBufferGrow
} else { } else {
@@ -87,7 +87,7 @@ func (h *Header) Parse(asResponse bool) error {
// if err != nil { // if err != nil {
// break // break
// } // }
// needMoreData, err = h.TryParse() // needMoreData, err = h.TryParse(asResponse)
// } // }
// if err != nil { // if err != nil {
// return err // return err
@@ -260,6 +260,11 @@ func (h *Header) Method() []byte {
return h.getNonEmptyValue(h.method) 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. // SetRequestURI sets RequestURI for the first HTTP request line.
func (h *Header) SetRequestURI(requestURI string) { func (h *Header) SetRequestURI(requestURI string) {
h.requestURI = h.reuseOrAppend(h.requestURI, requestURI) h.requestURI = h.reuseOrAppend(h.requestURI, requestURI)
@@ -270,19 +275,17 @@ func (h *Header) RequestURI() []byte {
return h.getNonEmptyValue(h.requestURI) return h.getNonEmptyValue(h.requestURI)
} }
func (h *Header) SetMethod(method string) { // Protocol returns the request header's HTTP protocol. Usually "HTTP/1.1".
h.method = h.reuseOrAppend(h.method, method)
}
// Protocol returns HTTP protocol.
func (h *Header) Protocol() []byte { func (h *Header) Protocol() []byte {
return h.getNonEmptyValue(h.proto) return h.getNonEmptyValue(h.proto)
} }
// SetProtocol sets the request header's protocol. Usually "HTTP/1.1".
func (h *Header) SetProtocol(protocol string) { func (h *Header) SetProtocol(protocol string) {
h.proto = h.reuseOrAppend(h.proto, protocol) 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) { func (h *Header) Status() (code, statusText []byte) {
if h.statusCode.len == 0 { if h.statusCode.len == 0 {
return nil, nil 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) 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) { func (h *Header) SetStatus(code, statusText string) {
h.statusCode = h.reuseOrAppend(h.statusCode, code) h.statusCode = h.reuseOrAppend(h.statusCode, code)
h.statusText = h.reuseOrAppend(h.statusText, statusText) h.statusText = h.reuseOrAppend(h.statusText, statusText)
+3 -3
View File
@@ -64,7 +64,7 @@ func TestHeaderParseRequest(t *testing.T) {
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
key := string(c.Key()) key := string(c.Name())
if key != wantCookie.Name { if key != wantCookie.Name {
t.Errorf("want cookie key %q, got %q", wantCookie.Name, key) t.Errorf("want cookie key %q, got %q", wantCookie.Name, key)
} }
@@ -76,11 +76,11 @@ func TestHeaderParseRequest(t *testing.T) {
if domain != wantCookie.Domain { if domain != wantCookie.Domain {
t.Errorf("want domain %q, got %q", wantCookie.Domain, domain) t.Errorf("want domain %q, got %q", wantCookie.Domain, domain)
} }
httpOnly := c.HasValueOrKey("HttpOnly") httpOnly := c.HasKeyOrSingleValue("HttpOnly")
if httpOnly != wantCookie.HttpOnly { if httpOnly != wantCookie.HttpOnly {
t.Errorf("want cookie HttpOnly %v, got %v", wantCookie.HttpOnly, httpOnly) t.Errorf("want cookie HttpOnly %v, got %v", wantCookie.HttpOnly, httpOnly)
} }
secure := c.HasValueOrKey("Secure") secure := c.HasKeyOrSingleValue("Secure")
if secure != wantCookie.Secure { if secure != wantCookie.Secure {
t.Errorf("want cookie HttpOnly %v, got %v", wantCookie.Secure, 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() 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 { func (hb *headerBuf) mustAppendSlice(value string) headerSlice {
L := len(hb.buf) L := len(hb.buf)
copy(hb.buf[L:L+len(value)], value) 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)) 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 { func tok2bytes(buf []byte, slice headerSlice) []byte {
return buf[slice.start : slice.start+slice.len] return buf[slice.start : slice.start+slice.len]
} }