dump.go 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  1. // Copyright 2009 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package httputil
  5. import (
  6. "bufio"
  7. "bytes"
  8. "errors"
  9. "fmt"
  10. "io"
  11. "net"
  12. "net/http"
  13. "net/url"
  14. "strings"
  15. "time"
  16. )
  17. // drainBody reads all of b to memory and then returns two equivalent
  18. // ReadClosers yielding the same bytes.
  19. //
  20. // It returns an error if the initial slurp of all bytes fails. It does not attempt
  21. // to make the returned ReadClosers have identical error-matching behavior.
  22. func drainBody(b io.ReadCloser) (r1, r2 io.ReadCloser, err error) {
  23. if b == nil || b == http.NoBody {
  24. // No copying needed. Preserve the magic sentinel meaning of NoBody.
  25. return http.NoBody, http.NoBody, nil
  26. }
  27. var buf bytes.Buffer
  28. if _, err = buf.ReadFrom(b); err != nil {
  29. return nil, b, err
  30. }
  31. if err = b.Close(); err != nil {
  32. return nil, b, err
  33. }
  34. return io.NopCloser(&buf), io.NopCloser(bytes.NewReader(buf.Bytes())), nil
  35. }
  36. // dumpConn is a net.Conn which writes to Writer and reads from Reader
  37. type dumpConn struct {
  38. io.Writer
  39. io.Reader
  40. }
  41. func (c *dumpConn) Close() error { return nil }
  42. func (c *dumpConn) LocalAddr() net.Addr { return nil }
  43. func (c *dumpConn) RemoteAddr() net.Addr { return nil }
  44. func (c *dumpConn) SetDeadline(t time.Time) error { return nil }
  45. func (c *dumpConn) SetReadDeadline(t time.Time) error { return nil }
  46. func (c *dumpConn) SetWriteDeadline(t time.Time) error { return nil }
  47. type neverEnding byte
  48. func (b neverEnding) Read(p []byte) (n int, err error) {
  49. for i := range p {
  50. p[i] = byte(b)
  51. }
  52. return len(p), nil
  53. }
  54. // outGoingLength is a copy of the unexported
  55. // (*http.Request).outgoingLength method.
  56. func outgoingLength(req *http.Request) int64 {
  57. if req.Body == nil || req.Body == http.NoBody {
  58. return 0
  59. }
  60. if req.ContentLength != 0 {
  61. return req.ContentLength
  62. }
  63. return -1
  64. }
  65. // DumpRequestOut is like DumpRequest but for outgoing client requests. It
  66. // includes any headers that the standard http.Transport adds, such as
  67. // User-Agent.
  68. func DumpRequestOut(req *http.Request, body bool) ([]byte, error) {
  69. save := req.Body
  70. dummyBody := false
  71. if !body {
  72. contentLength := outgoingLength(req)
  73. if contentLength != 0 {
  74. req.Body = io.NopCloser(io.LimitReader(neverEnding('x'), contentLength))
  75. dummyBody = true
  76. }
  77. } else {
  78. var err error
  79. save, req.Body, err = drainBody(req.Body)
  80. if err != nil {
  81. return nil, err
  82. }
  83. }
  84. // Since we're using the actual Transport code to write the request,
  85. // switch to http so the Transport doesn't try to do an SSL
  86. // negotiation with our dumpConn and its bytes.Buffer & pipe.
  87. // The wire format for https and http are the same, anyway.
  88. reqSend := req
  89. if req.URL.Scheme == "https" {
  90. reqSend = new(http.Request)
  91. *reqSend = *req
  92. reqSend.URL = new(url.URL)
  93. *reqSend.URL = *req.URL
  94. reqSend.URL.Scheme = "http"
  95. }
  96. // Use the actual Transport code to record what we would send
  97. // on the wire, but not using TCP. Use a Transport with a
  98. // custom dialer that returns a fake net.Conn that waits
  99. // for the full input (and recording it), and then responds
  100. // with a dummy response.
  101. var buf bytes.Buffer // records the output
  102. pr, pw := io.Pipe()
  103. defer pr.Close()
  104. defer pw.Close()
  105. dr := &delegateReader{c: make(chan io.Reader)}
  106. t := &http.Transport{
  107. Dial: func(net, addr string) (net.Conn, error) {
  108. return &dumpConn{io.MultiWriter(&buf, pw), dr}, nil
  109. },
  110. }
  111. defer t.CloseIdleConnections()
  112. // We need this channel to ensure that the reader
  113. // goroutine exits if t.RoundTrip returns an error.
  114. // See golang.org/issue/32571.
  115. quitReadCh := make(chan struct{})
  116. // Wait for the request before replying with a dummy response:
  117. go func() {
  118. req, err := http.ReadRequest(bufio.NewReader(pr))
  119. if err == nil {
  120. // Ensure all the body is read; otherwise
  121. // we'll get a partial dump.
  122. io.Copy(io.Discard, req.Body)
  123. req.Body.Close()
  124. }
  125. select {
  126. case dr.c <- strings.NewReader("HTTP/1.1 204 No Content\r\nConnection: close\r\n\r\n"):
  127. case <-quitReadCh:
  128. // Ensure delegateReader.Read doesn't block forever if we get an error.
  129. close(dr.c)
  130. }
  131. }()
  132. _, err := t.RoundTrip(reqSend)
  133. req.Body = save
  134. if err != nil {
  135. pw.Close()
  136. dr.err = err
  137. close(quitReadCh)
  138. return nil, err
  139. }
  140. dump := buf.Bytes()
  141. // If we used a dummy body above, remove it now.
  142. // TODO: if the req.ContentLength is large, we allocate memory
  143. // unnecessarily just to slice it off here. But this is just
  144. // a debug function, so this is acceptable for now. We could
  145. // discard the body earlier if this matters.
  146. if dummyBody {
  147. if i := bytes.Index(dump, []byte("\r\n\r\n")); i >= 0 {
  148. dump = dump[:i+4]
  149. }
  150. }
  151. return dump, nil
  152. }
  153. // delegateReader is a reader that delegates to another reader,
  154. // once it arrives on a channel.
  155. type delegateReader struct {
  156. c chan io.Reader
  157. err error // only used if r is nil and c is closed.
  158. r io.Reader // nil until received from c
  159. }
  160. func (r *delegateReader) Read(p []byte) (int, error) {
  161. if r.r == nil {
  162. var ok bool
  163. if r.r, ok = <-r.c; !ok {
  164. return 0, r.err
  165. }
  166. }
  167. return r.r.Read(p)
  168. }
  169. // Return value if nonempty, def otherwise.
  170. func valueOrDefault(value, def string) string {
  171. if value != "" {
  172. return value
  173. }
  174. return def
  175. }
  176. var reqWriteExcludeHeaderDump = map[string]bool{
  177. "Host": true, // not in Header map anyway
  178. "Transfer-Encoding": true,
  179. "Trailer": true,
  180. }
  181. // DumpRequest returns the given request in its HTTP/1.x wire
  182. // representation. It should only be used by servers to debug client
  183. // requests. The returned representation is an approximation only;
  184. // some details of the initial request are lost while parsing it into
  185. // an http.Request. In particular, the order and case of header field
  186. // names are lost. The order of values in multi-valued headers is kept
  187. // intact. HTTP/2 requests are dumped in HTTP/1.x form, not in their
  188. // original binary representations.
  189. //
  190. // If body is true, DumpRequest also returns the body. To do so, it
  191. // consumes req.Body and then replaces it with a new io.ReadCloser
  192. // that yields the same bytes. If DumpRequest returns an error,
  193. // the state of req is undefined.
  194. //
  195. // The documentation for http.Request.Write details which fields
  196. // of req are included in the dump.
  197. func DumpRequest(req *http.Request, body bool) ([]byte, error) {
  198. var err error
  199. save := req.Body
  200. if !body || req.Body == nil {
  201. req.Body = nil
  202. } else {
  203. save, req.Body, err = drainBody(req.Body)
  204. if err != nil {
  205. return nil, err
  206. }
  207. }
  208. var b bytes.Buffer
  209. // By default, print out the unmodified req.RequestURI, which
  210. // is always set for incoming server requests. But because we
  211. // previously used req.URL.RequestURI and the docs weren't
  212. // always so clear about when to use DumpRequest vs
  213. // DumpRequestOut, fall back to the old way if the caller
  214. // provides a non-server Request.
  215. reqURI := req.RequestURI
  216. if reqURI == "" {
  217. reqURI = req.URL.RequestURI()
  218. }
  219. fmt.Fprintf(&b, "%s %s HTTP/%d.%d\r\n", valueOrDefault(req.Method, "GET"),
  220. reqURI, req.ProtoMajor, req.ProtoMinor)
  221. absRequestURI := strings.HasPrefix(req.RequestURI, "http://") || strings.HasPrefix(req.RequestURI, "https://")
  222. if !absRequestURI {
  223. host := req.Host
  224. if host == "" && req.URL != nil {
  225. host = req.URL.Host
  226. }
  227. if host != "" {
  228. fmt.Fprintf(&b, "Host: %s\r\n", host)
  229. }
  230. }
  231. chunked := len(req.TransferEncoding) > 0 && req.TransferEncoding[0] == "chunked"
  232. if len(req.TransferEncoding) > 0 {
  233. fmt.Fprintf(&b, "Transfer-Encoding: %s\r\n", strings.Join(req.TransferEncoding, ","))
  234. }
  235. if req.Close {
  236. fmt.Fprintf(&b, "Connection: close\r\n")
  237. }
  238. err = req.Header.WriteSubset(&b, reqWriteExcludeHeaderDump)
  239. if err != nil {
  240. return nil, err
  241. }
  242. io.WriteString(&b, "\r\n")
  243. if req.Body != nil {
  244. var dest io.Writer = &b
  245. if chunked {
  246. dest = NewChunkedWriter(dest)
  247. }
  248. _, err = io.Copy(dest, req.Body)
  249. if chunked {
  250. dest.(io.Closer).Close()
  251. io.WriteString(&b, "\r\n")
  252. }
  253. }
  254. req.Body = save
  255. if err != nil {
  256. return nil, err
  257. }
  258. return b.Bytes(), nil
  259. }
  260. // errNoBody is a sentinel error value used by failureToReadBody so we
  261. // can detect that the lack of body was intentional.
  262. var errNoBody = errors.New("sentinel error value")
  263. // failureToReadBody is an io.ReadCloser that just returns errNoBody on
  264. // Read. It's swapped in when we don't actually want to consume
  265. // the body, but need a non-nil one, and want to distinguish the
  266. // error from reading the dummy body.
  267. type failureToReadBody struct{}
  268. func (failureToReadBody) Read([]byte) (int, error) { return 0, errNoBody }
  269. func (failureToReadBody) Close() error { return nil }
  270. // emptyBody is an instance of empty reader.
  271. var emptyBody = io.NopCloser(strings.NewReader(""))
  272. // DumpResponse is like DumpRequest but dumps a response.
  273. func DumpResponse(resp *http.Response, body bool) ([]byte, error) {
  274. var b bytes.Buffer
  275. var err error
  276. save := resp.Body
  277. savecl := resp.ContentLength
  278. if !body {
  279. // For content length of zero. Make sure the body is an empty
  280. // reader, instead of returning error through failureToReadBody{}.
  281. if resp.ContentLength == 0 {
  282. resp.Body = emptyBody
  283. } else {
  284. resp.Body = failureToReadBody{}
  285. }
  286. } else if resp.Body == nil {
  287. resp.Body = emptyBody
  288. } else {
  289. save, resp.Body, err = drainBody(resp.Body)
  290. if err != nil {
  291. return nil, err
  292. }
  293. }
  294. err = resp.Write(&b)
  295. if err == errNoBody {
  296. err = nil
  297. }
  298. resp.Body = save
  299. resp.ContentLength = savecl
  300. if err != nil {
  301. return nil, err
  302. }
  303. return b.Bytes(), nil
  304. }