tee.go 1.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. package conn
  2. import (
  3. "bufio"
  4. "io"
  5. )
  6. // conn.Tee is a wraps a conn.Conn
  7. // causing all writes/reads to be tee'd just
  8. // like the unix command such that all data that
  9. // is read and written to the connection through its
  10. // interfaces will also be copied into two dedicated pipes
  11. // used for consuming a copy of the data stream
  12. //
  13. // this is useful for introspecting the traffic flowing
  14. // over a connection without having to tamper with the actual
  15. // code that reads and writes over the connection
  16. //
  17. // NB: the data is Tee'd into a shared-memory io.Pipe which
  18. // has a limited (and small) buffer. If you are not consuming from
  19. // the ReadBuffer() and WriteBuffer(), you are going to block
  20. // your application's real traffic from flowing over the connection
  21. type Tee struct {
  22. rd io.Reader
  23. wr io.Writer
  24. readPipe struct {
  25. rd *io.PipeReader
  26. wr *io.PipeWriter
  27. }
  28. writePipe struct {
  29. rd *io.PipeReader
  30. wr *io.PipeWriter
  31. }
  32. Conn
  33. }
  34. func NewTee(conn Conn) *Tee {
  35. c := &Tee{
  36. rd: nil,
  37. wr: nil,
  38. Conn: conn,
  39. }
  40. c.readPipe.rd, c.readPipe.wr = io.Pipe()
  41. c.writePipe.rd, c.writePipe.wr = io.Pipe()
  42. c.rd = io.TeeReader(c.Conn, c.readPipe.wr)
  43. c.wr = io.MultiWriter(c.Conn, c.writePipe.wr)
  44. return c
  45. }
  46. func (c *Tee) ReadBuffer() *bufio.Reader {
  47. return bufio.NewReader(c.readPipe.rd)
  48. }
  49. func (c *Tee) WriteBuffer() *bufio.Reader {
  50. return bufio.NewReader(c.writePipe.rd)
  51. }
  52. func (c *Tee) Read(b []byte) (n int, err error) {
  53. return c.rd.Read(b)
  54. }
  55. func (c *Tee) ReadFrom(r io.Reader) (n int64, err error) {
  56. return io.Copy(c.wr, r)
  57. }
  58. func (c *Tee) Write(b []byte) (n int, err error) {
  59. return c.wr.Write(b)
  60. }