1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798 |
- package conn
- import (
- "bufio"
- "bytes"
- "fmt"
- "io"
- "math/rand"
- "net"
- "net/http"
- "ngrok"
- )
- type Conn interface {
- net.Conn
- ngrok.Logger
- Id() string
- }
- type loggedConn struct {
- net.Conn
- ngrok.Logger
- id int32
- typ string
- }
- func NewLogged(conn net.Conn, typ string) *loggedConn {
- c := &loggedConn{conn, ngrok.NewPrefixLogger(), rand.Int31(), typ}
- c.AddLogPrefix(c.Id())
- c.Info("New connection from %v", conn.RemoteAddr())
- return c
- }
- func (c *loggedConn) Close() error {
- c.Debug("Closing")
- return c.Conn.Close()
- }
- func (c *loggedConn) Id() string {
- return fmt.Sprintf("%s:%x", c.typ, c.id)
- }
- func Join(c Conn, c2 Conn) (int64, int64) {
- done := make(chan error)
- pipe := func(to Conn, from Conn, bytesCopied *int64) {
- var err error
- *bytesCopied, err = io.Copy(to, from)
- if err != nil {
- from.Warn("Copied %d bytes to %s before failing with error %v", *bytesCopied, to.Id(), err)
- done <- err
- } else {
- from.Debug("Copied %d bytes from to %s", *bytesCopied, to.Id())
- done <- nil
- }
- }
- var fromBytes, toBytes int64
- go pipe(c, c2, &fromBytes)
- go pipe(c2, c, &toBytes)
- c.Info("Joined with connection %s", c2.Id())
- <-done
- c.Close()
- c2.Close()
- <-done
- return fromBytes, toBytes
- }
- type loggedHttpConn struct {
- *loggedConn
- reqBuf *bytes.Buffer
- }
- func NewHttp(conn net.Conn, typ string) *loggedHttpConn {
- return &loggedHttpConn{
- NewLogged(conn, typ),
- bytes.NewBuffer(make([]byte, 0, 1024)),
- }
- }
- func (c *loggedHttpConn) ReadRequest() (*http.Request, error) {
- r := io.TeeReader(c.loggedConn, c.reqBuf)
- return http.ReadRequest(bufio.NewReader(r))
- }
- func (c *loggedConn) ReadFrom(r io.Reader) (n int64, err error) {
- // special case when we're reading from an http request where
- // we had to parse the request and consume bytes from the socket
- // and store them in a temporary request buffer
- if httpConn, ok := r.(*loggedHttpConn); ok {
- if n, err = httpConn.reqBuf.WriteTo(c); err != nil {
- return
- }
- }
- nCopied, err := io.Copy(c.Conn, r)
- n += nCopied
- return
- }
|