MCPcopy Create free account
hub / github.com/imroc/req / ReadResponse

Method ReadResponse

internal/http3/stream.go:330–411  ·  view source on GitHub ↗

ReadResponse reads the HTTP response from the stream. It must be called after sending the request (using SendRequestHeader). It is invalid to call it more than once. It doesn't set Response.Request and Response.TLS. It is invalid to call it after Read has been called.

()

Source from the content-addressed store, hash-verified

328// It doesn't set Response.Request and Response.TLS.
329// It is invalid to call it after Read has been called.
330func (s *RequestStream) ReadResponse() (*http.Response, error) {
331 if !s.sentRequest {
332 return nil, errors.New("http3: invalid duplicate use of RequestStream.ReadResponse before SendRequestHeader")
333 }
334 frame, err := s.str.frameParser.ParseNext(s.str.qlogger)
335 if err != nil {
336 s.str.CancelRead(quic.StreamErrorCode(ErrCodeFrameError))
337 s.str.CancelWrite(quic.StreamErrorCode(ErrCodeFrameError))
338 return nil, fmt.Errorf("http3: parsing frame failed: %w", err)
339 }
340 hf, ok := frame.(*headersFrame)
341 if !ok {
342 s.str.conn.CloseWithError(quic.ApplicationErrorCode(ErrCodeFrameUnexpected), "expected first frame to be a HEADERS frame")
343 return nil, errors.New("http3: expected first frame to be a HEADERS frame")
344 }
345 if hf.Length > uint64(s.maxHeaderBytes) {
346 maybeQlogInvalidHeadersFrame(s.str.qlogger, s.str.StreamID(), hf.Length)
347 s.str.CancelRead(quic.StreamErrorCode(ErrCodeFrameError))
348 s.str.CancelWrite(quic.StreamErrorCode(ErrCodeFrameError))
349 return nil, fmt.Errorf("http3: HEADERS frame too large: %d bytes (max: %d)", hf.Length, s.maxHeaderBytes)
350 }
351 headerBlock := make([]byte, hf.Length)
352 if _, err := io.ReadFull(s.str.datagramStream, headerBlock); err != nil {
353 maybeQlogInvalidHeadersFrame(s.str.qlogger, s.str.StreamID(), hf.Length)
354 s.str.CancelRead(quic.StreamErrorCode(ErrCodeRequestIncomplete))
355 s.str.CancelWrite(quic.StreamErrorCode(ErrCodeRequestIncomplete))
356 return nil, fmt.Errorf("http3: failed to read response headers: %w", err)
357 }
358 decodeFn := s.decoder.Decode(headerBlock)
359 var hfs []qpack.HeaderField
360 if s.str.qlogger != nil {
361 hfs = make([]qpack.HeaderField, 0, 16)
362 }
363 res := s.response
364 ds := dump.GetResponseHeaderDumpers(s.ctx, s.Dump)
365 err = updateResponseFromHeaders(res, decodeFn, s.maxHeaderBytes, &hfs, ds)
366 if s.str.qlogger != nil {
367 qlogParsedHeadersFrame(s.str.qlogger, s.str.StreamID(), hf, hfs)
368 }
369 if err != nil {
370 errCode := ErrCodeMessageError
371 var qpackErr *qpackError
372 if errors.As(err, &qpackErr) {
373 errCode = ErrCodeQPACKDecompressionFailed
374 }
375 s.str.CancelRead(quic.StreamErrorCode(errCode))
376 s.str.CancelWrite(quic.StreamErrorCode(errCode))
377 return nil, fmt.Errorf("http3: invalid response: %w", err)
378 }
379
380 // Check that the server doesn't send more data in DATA frames than indicated by the Content-Length header (if set).
381 // See section 4.1.2 of RFC 9114.
382 respBody := newResponseBody(s.str, res.ContentLength, s.reqDone)
383
384 // Rules for when to set Content-Length are defined in https://tools.ietf.org/html/rfc7230#section-3.3.2.
385 isInformational := res.StatusCode >= 100 && res.StatusCode < 200
386 isNoContent := res.StatusCode == http.StatusNoContent
387 isSuccessfulConnect := s.isConnect && res.StatusCode >= 200 && res.StatusCode < 300

Callers 2

dialConnMethod · 0.80
doRequestMethod · 0.80

Calls 14

GetResponseHeaderDumpersFunction · 0.92
NewGzipReaderFunction · 0.92
NewCompressReaderFunction · 0.92
qlogParsedHeadersFrameFunction · 0.85
newResponseBodyFunction · 0.85
ParseNextMethod · 0.80
CancelReadMethod · 0.65
CancelWriteMethod · 0.65
ErrorfMethod · 0.65
StreamIDMethod · 0.65

Tested by

no test coverage detected