func newTextprotoReader(br *bufio.Reader) *textprotoport.Reader { if v := textprotoReaderPool.Get(); v != nil { tr := v.(*textprotoport.Reader) tr.R = br return tr } return textprotoport.NewReader(br) }
// ReadResponse reads and returns an HTTP response from r. // The req parameter optionally specifies the Request that corresponds // to this Response. If nil, a GET request is assumed. // Clients must call resp.Body.Close when finished reading resp.Body. // After that call, clients can inspect resp.Trailer to find key/value // pairs included in the response trailer. func ReadResponse(r *bufio.Reader, req *Request) (*Response, error) { tp := textprotoport.NewReader(r) resp := &Response{ Request: req, } // Parse the first line of the response. line, err := tp.ReadLine() resp.StatusLine = line if err != nil { if err == io.EOF { err = io.ErrUnexpectedEOF } return nil, err } f := strings.SplitN(line, " ", 3) if len(f) < 2 { return nil, &badStringError{"malformed HTTP response", line} } reasonPhrase := "" if len(f) > 2 { reasonPhrase = f[2] } if len(f[1]) != 3 { return nil, &badStringError{"malformed HTTP status code", f[1]} } resp.StatusCode, err = strconv.Atoi(f[1]) if err != nil || resp.StatusCode < 0 { return nil, &badStringError{"malformed HTTP status code", f[1]} } resp.Status = f[1] + " " + reasonPhrase resp.Proto = f[0] var ok bool if resp.ProtoMajor, resp.ProtoMinor, ok = ParseHTTPVersion(resp.Proto); !ok { return nil, &badStringError{"malformed HTTP version", resp.Proto} } // Parse the response headers. mimeHeader, rawHeaders, err := tp.ReadMIMEHeader() if err != nil { if err == io.EOF { err = io.ErrUnexpectedEOF } return nil, err } resp.Header = Header(mimeHeader) resp.RawHeaders = rawHeaders fixPragmaCacheControl(resp.Header) err = readTransfer(resp, r) if err != nil { return nil, err } return resp, nil }