118 lines
2.0 KiB
Go
118 lines
2.0 KiB
Go
package headers
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
type Headers struct {
|
|
headers map[string]string
|
|
}
|
|
|
|
var rn = []byte("\r\n")
|
|
|
|
func isToken(str []byte) bool {
|
|
for _, ch := range str {
|
|
found := false
|
|
|
|
if ch >= 'A' && ch <= 'Z' ||
|
|
ch >= 'a' && ch <= 'z' ||
|
|
ch >= '0' && ch <= '9' {
|
|
found = true
|
|
}
|
|
|
|
switch ch {
|
|
case '!', '#', '$', '%', '&', '\'', '*', '+', '-', '.', '^', '_', '`', '|', '~':
|
|
found = true
|
|
}
|
|
|
|
if !found {
|
|
return false
|
|
}
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
func NewHeaders() *Headers {
|
|
return &Headers{map[string]string{}}
|
|
}
|
|
|
|
func parseHeader(fieldLine []byte) (string, string, error) {
|
|
parts := bytes.SplitN(fieldLine, []byte(":"), 2)
|
|
if len(parts) != 2 {
|
|
return "", "", fmt.Errorf("malformed header")
|
|
}
|
|
|
|
name := parts[0]
|
|
value := bytes.TrimSpace(parts[1])
|
|
|
|
if bytes.HasSuffix(name, []byte(" ")) {
|
|
return "", "", fmt.Errorf("malformed header")
|
|
}
|
|
|
|
return string(name), string(value), nil
|
|
}
|
|
|
|
func (h *Headers) Get(name string) (string, bool) {
|
|
v, ok := h.headers[strings.ToLower(name)]
|
|
return v, ok
|
|
}
|
|
|
|
func (h *Headers) Set(name, value string) {
|
|
name = strings.ToLower(name)
|
|
|
|
if v, ok := h.headers[name]; ok {
|
|
h.headers[name] = fmt.Sprintf("%s,%s", v, value)
|
|
} else {
|
|
h.headers[name] = value
|
|
}
|
|
}
|
|
func (h *Headers) Replace(name, value string) {
|
|
name = strings.ToLower(name)
|
|
h.headers[name] = value
|
|
}
|
|
|
|
func (h *Headers) Delete(name string) {
|
|
name = strings.ToLower(name)
|
|
delete(h.headers,name)
|
|
}
|
|
|
|
func (h *Headers) ForEach(cb func(n, v string)) {
|
|
for n, v := range h.headers {
|
|
cb(n, v)
|
|
}
|
|
}
|
|
|
|
func (h Headers) Parse(data []byte) (int, bool, error) {
|
|
read := 0
|
|
done := false
|
|
|
|
for {
|
|
idx := bytes.Index(data[read:], rn)
|
|
if idx == -1 {
|
|
break
|
|
}
|
|
|
|
if idx == 0 {
|
|
done = true
|
|
break
|
|
}
|
|
|
|
name, value, err := parseHeader(data[read : read+idx])
|
|
if err != nil {
|
|
return 0, false, err
|
|
}
|
|
|
|
if !isToken([]byte(name)) {
|
|
return 0, false, fmt.Errorf("malformed header")
|
|
}
|
|
|
|
read += idx + len(rn)
|
|
h.Set(name, value)
|
|
}
|
|
|
|
return read, done, nil
|
|
}
|