Copyright 2009 The Go Authors. All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.

package httputil

import (
	
	
	
	
	
	
	
	
	
	
)
drainBody reads all of b to memory and then returns two equivalent ReadClosers yielding the same bytes. It returns an error if the initial slurp of all bytes fails. It does not attempt to make the returned ReadClosers have identical error-matching behavior.
func ( io.ReadCloser) (,  io.ReadCloser,  error) {
No copying needed. Preserve the magic sentinel meaning of NoBody.
		return http.NoBody, http.NoBody, nil
	}
	var  bytes.Buffer
	if _,  = .ReadFrom();  != nil {
		return nil, , 
	}
	if  = .Close();  != nil {
		return nil, , 
	}
	return io.NopCloser(&), io.NopCloser(bytes.NewReader(.Bytes())), nil
}
dumpConn is a net.Conn which writes to Writer and reads from Reader
type dumpConn struct {
	io.Writer
	io.Reader
}

func ( *dumpConn) () error                       { return nil }
func ( *dumpConn) () net.Addr                { return nil }
func ( *dumpConn) () net.Addr               { return nil }
func ( *dumpConn) ( time.Time) error      { return nil }
func ( *dumpConn) ( time.Time) error  { return nil }
func ( *dumpConn) ( time.Time) error { return nil }

type neverEnding byte

func ( neverEnding) ( []byte) ( int,  error) {
	for  := range  {
		[] = byte()
	}
	return len(), nil
}
outGoingLength is a copy of the unexported (*http.Request).outgoingLength method.
func ( *http.Request) int64 {
	if .Body == nil || .Body == http.NoBody {
		return 0
	}
	if .ContentLength != 0 {
		return .ContentLength
	}
	return -1
}
DumpRequestOut is like DumpRequest but for outgoing client requests. It includes any headers that the standard http.Transport adds, such as User-Agent.
func ( *http.Request,  bool) ([]byte, error) {
	 := .Body
	 := false
	if ! {
		 := outgoingLength()
		if  != 0 {
			.Body = io.NopCloser(io.LimitReader(neverEnding('x'), ))
			 = true
		}
	} else {
		var  error
		, .Body,  = drainBody(.Body)
		if  != nil {
			return nil, 
		}
	}
Since we're using the actual Transport code to write the request, switch to http so the Transport doesn't try to do an SSL negotiation with our dumpConn and its bytes.Buffer & pipe. The wire format for https and http are the same, anyway.
	 := 
	if .URL.Scheme == "https" {
		 = new(http.Request)
		* = *
		.URL = new(url.URL)
		*.URL = *.URL
		.URL.Scheme = "http"
	}
Use the actual Transport code to record what we would send on the wire, but not using TCP. Use a Transport with a custom dialer that returns a fake net.Conn that waits for the full input (and recording it), and then responds with a dummy response.
	var  bytes.Buffer // records the output
	,  := io.Pipe()
	defer .Close()
	defer .Close()
	 := &delegateReader{c: make(chan io.Reader)}

	 := &http.Transport{
		Dial: func(,  string) (net.Conn, error) {
			return &dumpConn{io.MultiWriter(&, ), }, nil
		},
	}
	defer .CloseIdleConnections()
We need this channel to ensure that the reader goroutine exits if t.RoundTrip returns an error. See golang.org/issue/32571.
Wait for the request before replying with a dummy response:
	go func() {
		,  := http.ReadRequest(bufio.NewReader())
Ensure all the body is read; otherwise we'll get a partial dump.
			io.Copy(io.Discard, .Body)
			.Body.Close()
		}
		select {
		case .c <- strings.NewReader("HTTP/1.1 204 No Content\r\nConnection: close\r\n\r\n"):
Ensure delegateReader.Read doesn't block forever if we get an error.
			close(.c)
		}
	}()

	,  := .RoundTrip()

	.Body = 
	if  != nil {
		.Close()
		.err = 
		close()
		return nil, 
	}
	 := .Bytes()
If we used a dummy body above, remove it now. TODO: if the req.ContentLength is large, we allocate memory unnecessarily just to slice it off here. But this is just a debug function, so this is acceptable for now. We could discard the body earlier if this matters.
	if  {
		if  := bytes.Index(, []byte("\r\n\r\n"));  >= 0 {
			 = [:+4]
		}
	}
	return , nil
}
delegateReader is a reader that delegates to another reader, once it arrives on a channel.
type delegateReader struct {
	c   chan io.Reader
	err error     // only used if r is nil and c is closed.
	r   io.Reader // nil until received from c
}

func ( *delegateReader) ( []byte) (int, error) {
	if .r == nil {
		var  bool
		if .r,  = <-.c; ! {
			return 0, .err
		}
	}
	return .r.Read()
}
Return value if nonempty, def otherwise.
func (,  string) string {
	if  != "" {
		return 
	}
	return 
}

var reqWriteExcludeHeaderDump = map[string]bool{
	"Host":              true, // not in Header map anyway
	"Transfer-Encoding": true,
	"Trailer":           true,
}
DumpRequest returns the given request in its HTTP/1.x wire representation. It should only be used by servers to debug client requests. The returned representation is an approximation only; some details of the initial request are lost while parsing it into an http.Request. In particular, the order and case of header field names are lost. The order of values in multi-valued headers is kept intact. HTTP/2 requests are dumped in HTTP/1.x form, not in their original binary representations. If body is true, DumpRequest also returns the body. To do so, it consumes req.Body and then replaces it with a new io.ReadCloser that yields the same bytes. If DumpRequest returns an error, the state of req is undefined. The documentation for http.Request.Write details which fields of req are included in the dump.
func ( *http.Request,  bool) ([]byte, error) {
	var  error
	 := .Body
	if ! || .Body == nil {
		.Body = nil
	} else {
		, .Body,  = drainBody(.Body)
		if  != nil {
			return nil, 
		}
	}

	var  bytes.Buffer
By default, print out the unmodified req.RequestURI, which is always set for incoming server requests. But because we previously used req.URL.RequestURI and the docs weren't always so clear about when to use DumpRequest vs DumpRequestOut, fall back to the old way if the caller provides a non-server Request.
	 := .RequestURI
	if  == "" {
		 = .URL.RequestURI()
	}

	fmt.Fprintf(&, "%s %s HTTP/%d.%d\r\n", valueOrDefault(.Method, "GET"),
		, .ProtoMajor, .ProtoMinor)

	 := strings.HasPrefix(.RequestURI, "http://") || strings.HasPrefix(.RequestURI, "https://")
	if ! {
		 := .Host
		if  == "" && .URL != nil {
			 = .URL.Host
		}
		if  != "" {
			fmt.Fprintf(&, "Host: %s\r\n", )
		}
	}

	 := len(.TransferEncoding) > 0 && .TransferEncoding[0] == "chunked"
	if len(.TransferEncoding) > 0 {
		fmt.Fprintf(&, "Transfer-Encoding: %s\r\n", strings.Join(.TransferEncoding, ","))
	}
	if .Close {
		fmt.Fprintf(&, "Connection: close\r\n")
	}

	 = .Header.WriteSubset(&, reqWriteExcludeHeaderDump)
	if  != nil {
		return nil, 
	}

	io.WriteString(&, "\r\n")

	if .Body != nil {
		var  io.Writer = &
		if  {
			 = NewChunkedWriter()
		}
		_,  = io.Copy(, .Body)
		if  {
			.(io.Closer).Close()
			io.WriteString(&, "\r\n")
		}
	}

	.Body = 
	if  != nil {
		return nil, 
	}
	return .Bytes(), nil
}
errNoBody is a sentinel error value used by failureToReadBody so we can detect that the lack of body was intentional.
var errNoBody = errors.New("sentinel error value")
failureToReadBody is a io.ReadCloser that just returns errNoBody on Read. It's swapped in when we don't actually want to consume the body, but need a non-nil one, and want to distinguish the error from reading the dummy body.
type failureToReadBody struct{}

func (failureToReadBody) ([]byte) (int, error) { return 0, errNoBody }
func (failureToReadBody) () error             { return nil }
emptyBody is an instance of empty reader.
DumpResponse is like DumpRequest but dumps a response.
func ( *http.Response,  bool) ([]byte, error) {
	var  bytes.Buffer
	var  error
	 := .Body
	 := .ContentLength

For content length of zero. Make sure the body is an empty reader, instead of returning error through failureToReadBody{}.
		if .ContentLength == 0 {
			.Body = emptyBody
		} else {
			.Body = failureToReadBody{}
		}
	} else if .Body == nil {
		.Body = emptyBody
	} else {
		, .Body,  = drainBody(.Body)
		if  != nil {
			return nil, 
		}
	}
	 = .Write(&)
	if  == errNoBody {
		 = nil
	}
	.Body = 
	.ContentLength = 
	if  != nil {
		return nil, 
	}
	return .Bytes(), nil