func (rp *Response) hasBody(method string) bool {
	if method == "HEAD" || rp.Status == 304 || rp.Status == 204 ||
		rp.Status < 200 {
		return false
	}
	return true
}
If an http response may have message body
package main
import (
	"bytes"
	"errors"
	"fmt"
	"github.com/cyfdecyf/bufio"
	"net"
	"strconv"
	"strings"
	"time"
)
const CRLF = "\r\n"
const (
	statusCodeContinue = 100
)
const (
	statusBadReq         = "400 Bad Request"
	statusForbidden      = "403 Forbidden"
	statusExpectFailed   = "417 Expectation Failed"
	statusRequestTimeout = "408 Request Timeout"
)
var CustomHttpErr = errors.New("CustomHttpErr")
type Header struct {
	ContLen             int64
	KeepAlive           time.Duration
	ProxyAuthorization  string
	Chunking            bool
	Trailer             bool
	ConnectionKeepAlive bool
	ExpectContinue      bool
	Host                string
}
type rqState byte
const (
	rsCreated  rqState = iota
	rsSent              
	rsRecvBody          
	rsDone
)
type Request struct {
	Method  string
	URL     *URL
	raw     *bytes.Buffer  
	rawByte []byte         
	reqLnStart int  
	headStart  int  
	bodyStart  int  
	Header
	isConnect bool
	partial   bool  
	state     rqState
	tryCnt    byte
}
var zeroRequest = Request{Header: Header{ConnectionKeepAlive: true}}
func (r *Request) reset() {
	b := r.rawByte
	raw := r.raw
	*r = zeroRequest  
	if raw != nil {
		raw.Reset()
		r.rawByte = b
		r.raw = raw
	} else {
		r.rawByte = httpBuf.Get()
		r.raw = bytes.NewBuffer(r.rawByte[:0])  
	}
}
func (r *Request) String() (s string) {
	return fmt.Sprintf("%s %s%s", r.Method, r.URL.HostPort, r.URL.Path)
}
func (r *Request) Verbose() []byte {
	var rqbyte []byte
	if r.isConnect {
		rqbyte = r.rawBeforeBody()
	} else {
		rqbyte = r.raw.Bytes()
	}
	return rqbyte
}
func (r *Request) hasBody() bool {
	return r.Chunking || r.ContLen > 0
}
func (r *Request) isRetry() bool {
	return r.tryCnt > 1
}
func (r *Request) tryOnce() {
	r.tryCnt++
}
func (r *Request) tooManyRetry() bool {
	return r.tryCnt > 3
}
func (r *Request) responseNotSent() bool {
	return r.state <= rsSent
}
func (r *Request) hasSent() bool {
	return r.state >= rsSent
}
func (r *Request) releaseBuf() {
	if r.raw != nil {
		httpBuf.Put(r.rawByte)
		r.rawByte = nil
		r.raw = nil
	}
}
func (r *Request) rawRequest() []byte {
	return r.raw.Bytes()[r.reqLnStart:]
}
func (r *Request) rawBeforeBody() []byte {
	return r.raw.Bytes()[:r.bodyStart]
}
func (r *Request) rawHeaderBody() []byte {
	return r.raw.Bytes()[r.headStart:]
}
func (r *Request) rawBody() []byte {
	return r.raw.Bytes()[r.bodyStart:]
}
func (r *Request) proxyRequestLine() []byte {
	return r.raw.Bytes()[0:r.reqLnStart]
}
func (r *Request) genRequestLine() {
	r.raw.WriteString(r.Method + " ")
	if len(r.URL.Path) == 0 {
		r.raw.WriteString("/")
	} else {
		r.raw.WriteString(r.URL.Path)
	}
	r.raw.WriteString(" HTTP/1.1\r\n")
}
type Response struct {
	Status int
	Reason []byte
	Header
	raw     *bytes.Buffer
	rawByte []byte
}
var zeroResponse = Response{Header: Header{ConnectionKeepAlive: true}}
func (rp *Response) reset() {
	b := rp.rawByte
	raw := rp.raw
	*rp = zeroResponse
	if raw != nil {
		raw.Reset()
		rp.rawByte = b
		rp.raw = raw
	} else {
		rp.rawByte = httpBuf.Get()
		rp.raw = bytes.NewBuffer(rp.rawByte[:0])
	}
}
func (rp *Response) releaseBuf() {
	if rp.raw != nil {
		httpBuf.Put(rp.rawByte)
		rp.rawByte = nil
		rp.raw = nil
	}
}
func (rp *Response) rawResponse() []byte {
	return rp.raw.Bytes()
}
func (rp *Response) genStatusLine() {
	rp.raw.Write([]byte("HTTP/1.1 "))
	rp.raw.WriteString(strconv.Itoa(rp.Status))
	if len(rp.Reason) != 0 {
		rp.raw.WriteByte(' ')
		rp.raw.Write(rp.Reason)
	}
	rp.raw.Write([]byte(CRLF))
	return
}
func (rp *Response) String() string {
	return fmt.Sprintf("%d %s", rp.Status, rp.Reason)
}
func (rp *Response) Verbose() []byte {
	return rp.raw.Bytes()
}
type URL struct {
	HostPort string  
	Host     string  
	Port     string
	Domain   string
	Path     string
}
func (url *URL) String() string {
	return url.HostPort + url.Path
}
func (url *URL) ParseHostPort(hostPort string) {
	if hostPort == "" {
		return
	}
	host, port, err := net.SplitHostPort(hostPort)
	if err != nil {
		host = hostPort
		port = "80"
		hostPort = net.JoinHostPort(hostPort, port)
	}
	url.Host = host
	url.Port = port
	url.HostPort = hostPort
	url.Domain = host2Domain(host)
}
func ParseRequestURI(rawurl string) (*URL, error) {
	return ParseRequestURIBytes([]byte(rawurl))
}
func ParseRequestURIBytes(rawurl []byte) (*URL, error) {
	if rawurl[0] == '/' {
		return &URL{Path: string(rawurl)}, nil
	}
	var rest, scheme []byte
	id := bytes.Index(rawurl, []byte("://"))
	if id == -1 {
		rest = rawurl
		scheme = []byte("http")  
	} else {
		scheme = rawurl[:id]
		ASCIIToLowerInplace(scheme)  
		if !bytes.Equal(scheme, []byte("http")) && !bytes.Equal(scheme, []byte("https")) {
			errl.Printf("%s protocol not supported\n", scheme)
			return nil, errors.New("protocol not supported")
		}
		rest = rawurl[id+3:]
	}
	var hostport, host, port, path string
	id = bytes.IndexByte(rest, '/')
	if id == -1 {
		hostport = string(rest)
	} else {
		hostport = string(rest[:id])
		path = string(rest[id:])
	}
	host, port, err := net.SplitHostPort(hostport)
	if err != nil {  
		host = hostport
		if len(scheme) == 4 {
			hostport = net.JoinHostPort(host, "80")
			port = "80"
		} else {
			hostport = net.JoinHostPort(host, "443")
			port = "443"
		}
	}
        host = strings.TrimSuffix(strings.TrimPrefix(host, "[::ffff:"), "]")
        hostport = net.JoinHostPort(host, port)
	return &URL{hostport, host, port, host2Domain(host), path}, nil
}
const (
	headerConnection         = "connection"
	headerContentLength      = "content-length"
	headerExpect             = "expect"
	headerHost               = "host"
	headerKeepAlive          = "keep-alive"
	headerProxyAuthenticate  = "proxy-authenticate"
	headerProxyAuthorization = "proxy-authorization"
	headerProxyConnection    = "proxy-connection"
	headerReferer            = "referer"
	headerTE                 = "te"
	headerTrailer            = "trailer"
	headerTransferEncoding   = "transfer-encoding"
	headerUpgrade            = "upgrade"
	fullHeaderConnectionKeepAlive = "Connection: keep-alive\r\n"
	fullHeaderConnectionClose     = "Connection: close\r\n"
	fullHeaderTransferEncoding    = "Transfer-Encoding: chunked\r\n"
)
var headerParser = map[string]HeaderParserFunc{
	headerConnection:         (*Header).parseConnection,
	headerContentLength:      (*Header).parseContentLength,
	headerExpect:             (*Header).parseExpect,
	headerHost:               (*Header).parseHost,
	headerKeepAlive:          (*Header).parseKeepAlive,
	headerProxyAuthorization: (*Header).parseProxyAuthorization,
	headerProxyConnection:    (*Header).parseConnection,
	headerTransferEncoding:   (*Header).parseTransferEncoding,
	headerTrailer:            (*Header).parseTrailer,
}
var hopByHopHeader = map[string]bool{
	headerConnection:         true,
	headerKeepAlive:          true,
	headerProxyAuthorization: true,
	headerProxyConnection:    true,
	headerTE:                 true,
	headerTrailer:            true,
	headerTransferEncoding:   true,
	headerUpgrade:            true,
}
type HeaderParserFunc func(*Header, []byte) error
func (h *Header) parseConnection(s []byte) error {
	ASCIIToLowerInplace(s)
	h.ConnectionKeepAlive = !bytes.Contains(s, []byte("close"))
	return nil
}
func (h *Header) parseContentLength(s []byte) (err error) {
	h.ContLen, err = ParseIntFromBytes(s, 10)
	return err
}
func (h *Header) parseHost(s []byte) (err error) {
	if h.Host == "" {
		h.Host = string(s)
	}
	return
}
func (h *Header) parseKeepAlive(s []byte) (err error) {
	ASCIIToLowerInplace(s)
	id := bytes.Index(s, []byte("timeout="))
	if id != -1 {
		id += len("timeout=")
		end := id
		for ; end < len(s) && IsDigit(s[end]); end++ {
		}
		delta, err := ParseIntFromBytes(s[id:end], 10)
		if err != nil {
			return err  
		}
		h.KeepAlive = time.Second * time.Duration(delta)
	}
	return nil
}
func (h *Header) parseProxyAuthorization(s []byte) error {
	h.ProxyAuthorization = string(s)
	return nil
}
func (h *Header) parseTransferEncoding(s []byte) error {
	ASCIIToLowerInplace(s)
	h.Chunking = bytes.Contains(s, []byte("chunked"))
	if !h.Chunking && !bytes.Contains(s, []byte("identity")) {
		return fmt.Errorf("invalid transfer encoding: %s", s)
	}
	return nil
}
func (h *Header) parseTrailer(s []byte) error {
	errl.Printf("got Trailer header: %s\n", s)
	if len(s) != 0 {
		h.Trailer = true
	}
	return nil
}
func (h *Header) parseExpect(s []byte) error {
	ASCIIToLowerInplace(s)
	errl.Printf("Expect header: %s\n", s)  
	h.ExpectContinue = true
	return nil
}
func splitHeader(s []byte) (name, val []byte, err error) {
	i := bytes.IndexByte(s, ':')
	if i < 0 {
		return nil, nil, fmt.Errorf("malformed header: %#v", string(s))
	}
	return ASCIIToLower(s[:i]), TrimSpace(s[i+1:]), nil
}
func readContinuedLineSlice(r *bufio.Reader) ([]byte, error) {
	isspace := func(b byte) bool {
		return b == ' ' || b == '\t'
	}
	line, err := r.ReadSlice('\n')
	if err != nil {
		return nil, err
	}
	trimmed := TrimSpace(line)
	if len(trimmed) == 0 {
		if len(line) > 2 {
			return nil, fmt.Errorf("malformed end of headers, len: %d, %#v", len(line), string(line))
		}
		return nil, nil
	}
	if isspace(line[0]) {
		return nil, fmt.Errorf("malformed header, start with space: %#v", string(line))
	}
	if r.Buffered() > 0 {
		peek, err := r.Peek(1)
		if err == nil && !isspace(peek[0]) {
			return line, nil
		}
	}
	var buf []byte
	buf = append(buf, trimmed...)
	for skipSpace(r) > 0 {
		line, err := r.ReadSlice('\n')
		if err != nil {
			break
		}
		buf = append(buf, ' ')
		buf = append(buf, TrimTrailingSpace(line)...)
	}
	buf = append(buf, '\r', '\n')
	return buf, nil
}
func skipSpace(r *bufio.Reader) int {
	n := 0
	for {
		c, err := r.ReadByte()
		if err != nil {
			break
		}
		if c != ' ' && c != '\t' {
			r.UnreadByte()
			break
		}
		n++
	}
	return n
}
func (h *Header) parseHeader(reader *bufio.Reader, raw *bytes.Buffer, url *URL) (err error) {
	h.ContLen = -1
	for {
		var line, name, val []byte
		if line, err = readContinuedLineSlice(reader); err != nil || len(line) == 0 {
			return
		}
		if name, val, err = splitHeader(line); err != nil {
			errl.Printf("split header %v\nline: %s\nraw header:\n%s\n", err, line, raw.Bytes())
			return
		}
		kn := string(name)
		if parseFunc, ok := headerParser[kn]; ok {
			if len(val) == 0 {
				continue
			}
			if err = parseFunc(h, val); err != nil {
				errl.Printf("parse header %v\nline: %s\nraw header:\n%s\n", err, line, raw.Bytes())
				return
			}
		}
		if hopByHopHeader[kn] {
			continue
		}
		raw.Write(line)
	}
}
func parseRequest(c *clientConn, r *Request) (err error) {
	var s []byte
	reader := c.bufRd
	c.setReadTimeout("parseRequest")
	if s, err = reader.ReadSlice('\n'); err != nil {
		if isErrTimeout(err) {
			return errClientTimeout
		}
		return err
	}
	c.unsetReadTimeout("parseRequest")
	r.reset()
	if config.saveReqLine {
		r.raw.Write(s)
		r.reqLnStart = len(s)
	}
	var f [][]byte
	if f = FieldsN(s, 3); len(f) != 3 {
		return fmt.Errorf("malformed request line: %#v", string(s))
	}
	ASCIIToUpperInplace(f[0])
	r.Method = string(f[0])
	r.URL, err = ParseRequestURIBytes(f[1])
	if err != nil {
		return
	}
	r.Header.Host = r.URL.HostPort  
	if r.Method == "CONNECT" {
		r.isConnect = true
		if bool(dbgRq) && verbose && !config.saveReqLine {
			r.raw.Write(s)
		}
	} else {
		r.genRequestLine()
	}
	r.headStart = r.raw.Len()
	if err = r.parseHeader(reader, r.raw, r.URL); err != nil {
		errl.Printf("parse request header: %v %s\n%s", err, r, r.Verbose())
		return err
	}
	if r.Chunking {
		r.raw.WriteString(fullHeaderTransferEncoding)
	}
	if r.ConnectionKeepAlive {
		r.raw.WriteString(fullHeaderConnectionKeepAlive)
	} else {
		r.raw.WriteString(fullHeaderConnectionClose)
	}
	r.raw.WriteString(CRLF)
	r.bodyStart = r.raw.Len()
	return
}