readRequestV2 is the V2 counterpart of HandleChunkedRequests. It consumes the remainder of an HTTP/1 request from stream, appending bytes to *finalReq. Unlike HandleChunkedRequests it uses ReadChunk so we pull exactly one tee'd chunk at a time and never over-read past the end of the current request
(ctx context.Context, stream *fakeconn.FakeConn, finalReq *[]byte)
| 170 | // Returns io.EOF if stream closes before the body is fully consumed. |
| 171 | // Returns a decode error for malformed Content-Length / body framing. |
| 172 | func (h *HTTP) readRequestV2(ctx context.Context, stream *fakeconn.FakeConn, finalReq *[]byte) error { |
| 173 | // 1. Complete headers. |
| 174 | for !hasCompleteHeaders(*finalReq) { |
| 175 | if err := ctx.Err(); err != nil { |
| 176 | return err |
| 177 | } |
| 178 | chunk, err := stream.ReadChunk() |
| 179 | if err != nil { |
| 180 | return err |
| 181 | } |
| 182 | if len(chunk.Bytes) == 0 { |
| 183 | return io.EOF |
| 184 | } |
| 185 | *finalReq = append(*finalReq, chunk.Bytes...) |
| 186 | } |
| 187 | |
| 188 | contentLengthHeader, transferEncodingHeader := parseHeaders(*finalReq) |
| 189 | |
| 190 | if contentLengthHeader != "" { |
| 191 | contentLength, err := strconv.Atoi(contentLengthHeader) |
| 192 | if err != nil { |
| 193 | return fmt.Errorf("invalid content-length: %w", err) |
| 194 | } |
| 195 | headerEnd := bytes.Index(*finalReq, []byte("\r\n\r\n")) |
| 196 | if headerEnd < 0 { |
| 197 | return fmt.Errorf("header terminator missing") |
| 198 | } |
| 199 | bodyLength := len(*finalReq) - headerEnd - 4 |
| 200 | remaining := contentLength - bodyLength |
| 201 | for remaining > 0 { |
| 202 | if err := ctx.Err(); err != nil { |
| 203 | return err |
| 204 | } |
| 205 | chunk, err := stream.ReadChunk() |
| 206 | if err != nil { |
| 207 | return err |
| 208 | } |
| 209 | if len(chunk.Bytes) == 0 { |
| 210 | return io.EOF |
| 211 | } |
| 212 | *finalReq = append(*finalReq, chunk.Bytes...) |
| 213 | remaining -= len(chunk.Bytes) |
| 214 | } |
| 215 | return nil |
| 216 | } |
| 217 | |
| 218 | if transferEncodingHeader != "" && |
| 219 | strings.Contains(strings.ToLower(transferEncodingHeader), "chunked") { |
| 220 | for !bytes.HasSuffix(*finalReq, chunkedTerminator) { |
| 221 | if err := ctx.Err(); err != nil { |
| 222 | return err |
| 223 | } |
| 224 | chunk, err := stream.ReadChunk() |
| 225 | if err != nil { |
| 226 | return err |
| 227 | } |
| 228 | if len(chunk.Bytes) == 0 { |
| 229 | return io.EOF |
no test coverage detected