Пример #1
0
func tcpShim(inbound, outbound *net.TCPConn, connEvent *events.Connection, eh events.Handler) error {
	eh.Connection(connEvent)
	ch := make(chan error, 1)
	go func() {
		var err error
		defer func() { ch <- err }()
		_, err = io.Copy(inbound, outbound)
		outbound.CloseRead()
		inbound.CloseWrite()
	}()

	_, err1 := io.Copy(outbound, inbound)
	inbound.CloseRead()
	outbound.CloseWrite()

	err2 := <-ch
	inbound.Close()
	outbound.Close()

	if err1 != nil {
		return err1
	} else {
		return err2
	}
}
Пример #2
0
func httpShim(inbound, outbound *net.TCPConn, connEvent *events.Connection, eh events.Handler) error {
	eh.Connection(connEvent)
	defer inbound.Close()
	defer outbound.Close()

	// Request handling and response handling take place in
	// separate goroutines.  This is not to support pipelining
	// (although it could easily be extended to do so).  Rather,
	// it is to support cases where the server produces a response
	// before the client is done sending the request (e.g. when
	// the server produces an error response before reading the
	// whole request).

	type request struct {
		req      *http.Request
		tReadReq time.Time
		err      error
	}

	reqCh := make(chan request)
	doneCh := make(chan struct{})
	defer close(doneCh)

	passReq := func(req request) bool {
		select {
		case reqCh <- req:
			return true
		case <-doneCh:
			return false
		}
	}

	// The request handler loop
	go func() {
		reqrd := bufio.NewReader(inbound)
		for {
			// XXX timeout on no request
			req, err := http.ReadRequest(reqrd)
			if err != nil {
				if err == io.EOF {
					close(reqCh)
					return
				}

				passReq(request{err: err})
				return
			}

			if !passReq(request{req: req, tReadReq: time.Now()}) {
				return
			}

			err = req.Write(outbound)
			if err != nil {
				passReq(request{err: err})
				return
			}
		}
	}()

	// The response handler loop
	resprd := bufio.NewReader(outbound)
	for {
		req, ok := <-reqCh
		if !ok {
			return nil
		}

		if req.err != nil {
			return req.err
		}

		resp, err := http.ReadResponse(resprd, req.req)
		tReadResponse := time.Now()
		if err != nil {
			return err
		}

		err = resp.Write(inbound)
		tWroteResponse := time.Now()
		if err != nil {
			return err
		}

		eh.HttpExchange(&events.HttpExchange{
			Connection: connEvent,
			Request:    req.req,
			Response:   resp,
			RoundTrip:  tReadResponse.Sub(req.tReadReq),
			TotalTime:  tWroteResponse.Sub(req.tReadReq),
		})
	}
}