summaryrefslogtreecommitdiff
path: root/src/pkg/net/http/httputil/dump.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/net/http/httputil/dump.go')
-rw-r--r--src/pkg/net/http/httputil/dump.go276
1 files changed, 0 insertions, 276 deletions
diff --git a/src/pkg/net/http/httputil/dump.go b/src/pkg/net/http/httputil/dump.go
deleted file mode 100644
index 2a7a413d0..000000000
--- a/src/pkg/net/http/httputil/dump.go
+++ /dev/null
@@ -1,276 +0,0 @@
-// 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 (
- "bufio"
- "bytes"
- "errors"
- "fmt"
- "io"
- "io/ioutil"
- "net"
- "net/http"
- "net/url"
- "strings"
- "time"
-)
-
-// One of the copies, say from b to r2, could be avoided by using a more
-// elaborate trick where the other copy is made during Request/Response.Write.
-// This would complicate things too much, given that these functions are for
-// debugging only.
-func drainBody(b io.ReadCloser) (r1, r2 io.ReadCloser, err error) {
- var buf bytes.Buffer
- if _, err = buf.ReadFrom(b); err != nil {
- return nil, nil, err
- }
- if err = b.Close(); err != nil {
- return nil, nil, err
- }
- return ioutil.NopCloser(&buf), ioutil.NopCloser(bytes.NewReader(buf.Bytes())), nil
-}
-
-// dumpConn is a net.Conn which writes to Writer and reads from Reader
-type dumpConn struct {
- io.Writer
- io.Reader
-}
-
-func (c *dumpConn) Close() error { return nil }
-func (c *dumpConn) LocalAddr() net.Addr { return nil }
-func (c *dumpConn) RemoteAddr() net.Addr { return nil }
-func (c *dumpConn) SetDeadline(t time.Time) error { return nil }
-func (c *dumpConn) SetReadDeadline(t time.Time) error { return nil }
-func (c *dumpConn) SetWriteDeadline(t time.Time) error { return nil }
-
-type neverEnding byte
-
-func (b neverEnding) Read(p []byte) (n int, err error) {
- for i := range p {
- p[i] = byte(b)
- }
- return len(p), nil
-}
-
-// DumpRequestOut is like DumpRequest but includes
-// headers that the standard http.Transport adds,
-// such as User-Agent.
-func DumpRequestOut(req *http.Request, body bool) ([]byte, error) {
- save := req.Body
- dummyBody := false
- if !body || req.Body == nil {
- req.Body = nil
- if req.ContentLength != 0 {
- req.Body = ioutil.NopCloser(io.LimitReader(neverEnding('x'), req.ContentLength))
- dummyBody = true
- }
- } else {
- var err error
- save, req.Body, err = drainBody(req.Body)
- if err != nil {
- return nil, err
- }
- }
-
- // 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.
- reqSend := req
- if req.URL.Scheme == "https" {
- reqSend = new(http.Request)
- *reqSend = *req
- reqSend.URL = new(url.URL)
- *reqSend.URL = *req.URL
- reqSend.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 buf bytes.Buffer // records the output
- pr, pw := io.Pipe()
- dr := &delegateReader{c: make(chan io.Reader)}
- // Wait for the request before replying with a dummy response:
- go func() {
- http.ReadRequest(bufio.NewReader(pr))
- dr.c <- strings.NewReader("HTTP/1.1 204 No Content\r\n\r\n")
- }()
-
- t := &http.Transport{
- Dial: func(net, addr string) (net.Conn, error) {
- return &dumpConn{io.MultiWriter(&buf, pw), dr}, nil
- },
- }
- defer t.CloseIdleConnections()
-
- _, err := t.RoundTrip(reqSend)
-
- req.Body = save
- if err != nil {
- return nil, err
- }
- dump := buf.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 dummyBody {
- if i := bytes.Index(dump, []byte("\r\n\r\n")); i >= 0 {
- dump = dump[:i+4]
- }
- }
- return dump, nil
-}
-
-// delegateReader is a reader that delegates to another reader,
-// once it arrives on a channel.
-type delegateReader struct {
- c chan io.Reader
- r io.Reader // nil until received from c
-}
-
-func (r *delegateReader) Read(p []byte) (int, error) {
- if r.r == nil {
- r.r = <-r.c
- }
- return r.r.Read(p)
-}
-
-// Return value if nonempty, def otherwise.
-func valueOrDefault(value, def string) string {
- if value != "" {
- return value
- }
- return def
-}
-
-var reqWriteExcludeHeaderDump = map[string]bool{
- "Host": true, // not in Header map anyway
- "Content-Length": true,
- "Transfer-Encoding": true,
- "Trailer": true,
-}
-
-// dumpAsReceived writes req to w in the form as it was received, or
-// at least as accurately as possible from the information retained in
-// the request.
-func dumpAsReceived(req *http.Request, w io.Writer) error {
- return nil
-}
-
-// DumpRequest returns the as-received wire representation of req,
-// optionally including the request body, for debugging.
-// DumpRequest is semantically a no-op, but in order to
-// dump the body, it reads the body data into memory and
-// changes req.Body to refer to the in-memory copy.
-// The documentation for http.Request.Write details which fields
-// of req are used.
-func DumpRequest(req *http.Request, body bool) (dump []byte, err error) {
- save := req.Body
- if !body || req.Body == nil {
- req.Body = nil
- } else {
- save, req.Body, err = drainBody(req.Body)
- if err != nil {
- return
- }
- }
-
- var b bytes.Buffer
-
- fmt.Fprintf(&b, "%s %s HTTP/%d.%d\r\n", valueOrDefault(req.Method, "GET"),
- req.URL.RequestURI(), req.ProtoMajor, req.ProtoMinor)
-
- host := req.Host
- if host == "" && req.URL != nil {
- host = req.URL.Host
- }
- if host != "" {
- fmt.Fprintf(&b, "Host: %s\r\n", host)
- }
-
- chunked := len(req.TransferEncoding) > 0 && req.TransferEncoding[0] == "chunked"
- if len(req.TransferEncoding) > 0 {
- fmt.Fprintf(&b, "Transfer-Encoding: %s\r\n", strings.Join(req.TransferEncoding, ","))
- }
- if req.Close {
- fmt.Fprintf(&b, "Connection: close\r\n")
- }
-
- err = req.Header.WriteSubset(&b, reqWriteExcludeHeaderDump)
- if err != nil {
- return
- }
-
- io.WriteString(&b, "\r\n")
-
- if req.Body != nil {
- var dest io.Writer = &b
- if chunked {
- dest = NewChunkedWriter(dest)
- }
- _, err = io.Copy(dest, req.Body)
- if chunked {
- dest.(io.Closer).Close()
- io.WriteString(&b, "\r\n")
- }
- }
-
- req.Body = save
- if err != nil {
- return
- }
- dump = b.Bytes()
- return
-}
-
-// 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) Read([]byte) (int, error) { return 0, errNoBody }
-func (failureToReadBody) Close() error { return nil }
-
-var emptyBody = ioutil.NopCloser(strings.NewReader(""))
-
-// DumpResponse is like DumpRequest but dumps a response.
-func DumpResponse(resp *http.Response, body bool) (dump []byte, err error) {
- var b bytes.Buffer
- save := resp.Body
- savecl := resp.ContentLength
-
- if !body {
- resp.Body = failureToReadBody{}
- } else if resp.Body == nil {
- resp.Body = emptyBody
- } else {
- save, resp.Body, err = drainBody(resp.Body)
- if err != nil {
- return
- }
- }
- err = resp.Write(&b)
- if err == errNoBody {
- err = nil
- }
- resp.Body = save
- resp.ContentLength = savecl
- if err != nil {
- return nil, err
- }
- return b.Bytes(), nil
-}