We've got the request line, now it's time to parse the request headers.
Now, when we say "headers" it's important to note that the RFC doesn't call them that.... The RFC uses the term field-line, but it's basically the same thing. From 5. Field Syntax
Each field line consists of a case-insensitive field name followed by a colon (
":"), optional leading whitespace, the field line value, and optional trailing whitespace.
field-line = field-name ":" OWS field-value OWS
One important point to note: there can be an unlimited amount of whitespace before and after the field-value (Header value). However, when parsing a field-name, there must be no spaces betwixt the colon and the field-name. In other words, these are valid:
'Host: localhost:42069'
' Host: localhost:42069 '
But this is not:
Host : localhost:42069
I made it a separate package because we'll use the headers package both for parsing requests and for sending responses. This is a stylistic choice rather than a Design (with A Capital D™) choice.
type Headers map[string]string
func (h Headers) Parse(data []byte) (n int, done bool, err error)
// Test: Valid single header
headers := NewHeaders()
data := []byte("Host: localhost:42069\r\n\r\n")
n, done, err := headers.Parse(data)
require.NoError(t, err)
require.NotNil(t, headers)
assert.Equal(t, "localhost:42069", headers["Host"])
assert.Equal(t, 23, n)
assert.False(t, done)
// Test: Invalid spacing header
headers = NewHeaders()
data = []byte(" Host : localhost:42069 \r\n\r\n")
n, done, err = headers.Parse(data)
require.Error(t, err)
assert.Equal(t, 0, n)
assert.False(t, done)
Run and submit the CLI tests.