func (inbound *Inbound) error(title, outbound string, err error, t0 time.Time) error { if urlErr, ok := err.(*url.Error); ok { return inbound.error(title, outbound, urlErr.Err, t0) } else if netErr, ok := err.(*net.OpError); ok { if errno, ok := netErr.Err.(syscall.Errno); ok && errno == syscall.ECONNREFUSED { klog.KPrintf(klog.Keyf("%s.%s.%s.timeout", inbound.Name, outbound, title), "%T -> %v", err, err) inbound.record(outbound, Event{Timeout: true, Latency: time.Since(t0)}) return err } return inbound.error(title, outbound, netErr.Err, t0) } switch err.Error() { // Prevents spamming the logs with closed connections even though they were // not properly closed. case "EOF": inbound.record(outbound, Event{Error: true, Latency: time.Since(t0)}) return err // I hate this but net and net/http provides no useful errors or indicators // that a request ended up in a timeout. Furthermore, most of the errors are // either not exported or are just randomly created as string. In other // words, this is a crappy interface that needs to be fixed bad. case "use of closed network connection": // net.errClosing fallthrough case "net/http: transport closed before response was received": fallthrough case "net/http: request canceled while waiting for connection": klog.KPrintf(klog.Keyf("%s.%s.%s.timeout", inbound.Name, outbound, title), "%T -> %v", err, err) inbound.record(outbound, Event{Timeout: true, Latency: time.Since(t0)}) return err } klog.KPrintf(klog.Keyf("%s.%s.%s.error", inbound.Name, outbound, title), "%T -> %v", err, err) inbound.record(outbound, Event{Error: true, Latency: time.Since(t0)}) return err }
// NewInboundServer creates and starts a new HTTP server associated with the // given Inbound. func NewInboundServer(inbound *Inbound) (*InboundServer, error) { server := new(InboundServer) if err := inbound.Validate(); err != nil { return nil, err } inbound.Init() server.setInbound(inbound) listener, err := net.Listen("tcp", inbound.Listen) if err != nil { klog.KPrintf(klog.Keyf("%s.listen", inbound.Name), "unable to listen on %s: %s", inbound.Listen, err) return nil, err } server.listener = listener go func() { err := http.Serve(tcpKeepAliveListener{listener.(*net.TCPListener)}, server) klog.KPrintf(klog.Keyf("%s.close", server.getInbound().Name), "server closed with: %s", err) }() return server, nil }