package http import ( "bufio" "errors" "io" "strconv" "strings" ) func ReadResponse(r io.Reader) (*Response, error) { b := bufio.NewReader(r) if _, err := b.ReadString(' '); err != nil { return nil, errors.New("read httpVersion") } statusCode, err := b.ReadString(' ') if err != nil { return nil, errors.New("read statusCode") } statusCode = statusCode[:len(statusCode)-1] if _, err := b.ReadString('\r'); err != nil { return nil, errors.New("read statusName") } if _, err := b.ReadString('\n'); err != nil { return nil, errors.New("read LF") } headerStr := "" contentLengthStr := "" headers := []Header{} for { headerStr, err = b.ReadString('\n') if err != nil { return nil, errors.New("read header") } if headerStr == "\r\n" { break } arr := strings.Split(headerStr, ": ") value := strings.TrimSpace(arr[1]) header := Header{Name: arr[0], Value: value} if header.Name == "Content-Length" { contentLengthStr = header.Value } headers = append(headers, header) } length, err := strconv.Atoi(contentLengthStr) if err != nil { return nil, errors.New("read Content-Length") } body := make([]byte, 0, length) for i := 0; i < length; i++ { r, err := b.ReadByte() if err != nil { return nil, errors.New("read body") } body = append(body, r) } return &Response{ StatusCode: statusCode, Headers: headers, Body: body, }, nil }