We're almost done parsing the request! (Which, frankly, is the hardest part of an HTTP server imo.)
Remember, an HTTP-message has this format:
HTTP-message = start-line CRLF
*( field-line CRLF )
CRLF
[ message-body ]
Our current code parses the
start-line (request line for requests)field-line (headers)CRLF between headers and the bodyLet's tackle the [ message-body ]: but beware, it still has an edge case...

According to RFC9110 8.6:
A user agent SHOULD send Content-Length in a request...
And "should" has a specific meaning in RFCs per RFC2119:
This word, or the adjective "RECOMMENDED", mean that there may exist valid reasons in particular circumstances to ignore a particular item, but the full implications must be understood and carefully weighed before choosing a different course.
All this to say, for our implementation we're going to assume that if there is no Content-Length header, there is no body present. This is a safe assumption for our purposes, though it might not be true in all cases in the wild.
In the request package, update your (r *Request) parse method to parse the body in addition to the request line.
// Test: Standard Body
reader := &chunkReader{
data: "POST /submit HTTP/1.1\r\n" +
"Host: localhost:42069\r\n" +
"Content-Length: 13\r\n" +
"\r\n" +
"hello world!\n",
numBytesPerRead: 3,
}
r, err := RequestFromReader(reader)
require.NoError(t, err)
require.NotNil(t, r)
assert.Equal(t, "hello world!\n", string(r.Body))
// Test: Body shorter than reported content length
reader = &chunkReader{
data: "POST /submit HTTP/1.1\r\n" +
"Host: localhost:42069\r\n" +
"Content-Length: 20\r\n" +
"\r\n" +
"partial content",
numBytesPerRead: 3,
}
r, err = RequestFromReader(reader)
require.Error(t, err)
Run and submit the CLI tests.