MCPcopy
hub / github.com/keploy/keploy / readResponseV2

Method readResponseV2

pkg/agent/proxy/integrations/http/recordv2.go:257–356  ·  view source on GitHub ↗

readResponseV2 is the V2 counterpart of handleChunkedResponses. It consumes the remainder of an HTTP/1 response from stream, appending bytes to *finalResp, and returns the WrittenAt timestamp of the last chunk it consumed. It does NOT write to any client connection — the relay owns forwarding on the

(ctx context.Context, stream *fakeconn.FakeConn, finalResp *[]byte)

Source from the content-addressed store, hash-verified

255// "server closed after sending a full response" case; the caller
256// decides whether to emit a mock.
257func (h *HTTP) readResponseV2(ctx context.Context, stream *fakeconn.FakeConn, finalResp *[]byte) (time.Time, error) {
258 var lastWr time.Time
259
260 // 1. Complete headers.
261 for !hasCompleteHeaders(*finalResp) {
262 if err := ctx.Err(); err != nil {
263 return lastWr, err
264 }
265 chunk, err := stream.ReadChunk()
266 if err != nil {
267 return lastWr, err
268 }
269 if !chunk.WrittenAt.IsZero() {
270 lastWr = chunk.WrittenAt
271 }
272 if len(chunk.Bytes) == 0 {
273 return lastWr, io.EOF
274 }
275 *finalResp = append(*finalResp, chunk.Bytes...)
276 }
277
278 // 2. Parse headers for body framing.
279 contentLengthHeader, transferEncodingHeader := parseHeaders(*finalResp)
280
281 if contentLengthHeader != "" {
282 contentLength, err := strconv.Atoi(contentLengthHeader)
283 if err != nil {
284 return lastWr, fmt.Errorf("invalid content-length: %w", err)
285 }
286 headerEnd := bytes.Index(*finalResp, []byte("\r\n\r\n"))
287 if headerEnd < 0 {
288 return lastWr, fmt.Errorf("header terminator missing")
289 }
290 bodyLength := len(*finalResp) - headerEnd - 4
291 remaining := contentLength - bodyLength
292 for remaining > 0 {
293 if err := ctx.Err(); err != nil {
294 return lastWr, err
295 }
296 chunk, err := stream.ReadChunk()
297 if err != nil {
298 return lastWr, err
299 }
300 if !chunk.WrittenAt.IsZero() {
301 lastWr = chunk.WrittenAt
302 }
303 if len(chunk.Bytes) == 0 {
304 return lastWr, io.EOF
305 }
306 *finalResp = append(*finalResp, chunk.Bytes...)
307 remaining -= len(chunk.Bytes)
308 }
309 return lastWr, nil
310 }
311
312 if transferEncodingHeader != "" &&
313 strings.Contains(strings.ToLower(transferEncodingHeader), "chunked") {
314 // Chunked: read until we see the last-chunk terminator as a

Callers 1

recordV2Method · 0.95

Calls 4

hasCompleteHeadersFunction · 0.85
parseHeadersFunction · 0.85
ReadChunkMethod · 0.80
IsZeroMethod · 0.80

Tested by

no test coverage detected