package http import ( "bufio" "errors" "fmt" "io" "strconv" "strings" ) func ReadResponse(r io.Reader) (*Response, error) { b := bufio.NewReader(r) protocol, err := b.ReadString(' ') if err != nil { return nil, errors.New("read protocol") } protocol = protocol[:len(protocol)-1] statusCode, err := b.ReadString(' ') if err != nil { return nil, errors.New("read statusCode") } statusCode = statusCode[:len(statusCode)-1] statusMessage, err := b.ReadString('\r') if err != nil { return nil, errors.New("read statusMessage") } statusMessage = statusMessage[:len(statusMessage)-1] 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{ Protocol: protocol, StatusCode: statusCode, StatusMessage: statusMessage, Headers: headers, Body: body, }, nil } func ReadResponseDebugWrap(r io.Reader, f func(r io.Reader) (*Response, error)) (*Response, error) { resp, err := f(r) if err != nil { return nil, err } fmt.Println("----- Debug Info -----") fmt.Printf("%s %s %s\n", resp.Protocol, resp.StatusCode, resp.StatusMessage) for _, header := range resp.Headers { fmt.Printf("%s: %s\n", header.Name, header.Value) } if len(resp.Body) > 0 { fmt.Println(string(resp.Body)) } fmt.Println("----- Debug End Info -----") return resp, nil }