aboutsummaryrefslogtreecommitdiff
path: root/src/pkg/net/http/server.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/net/http/server.go')
-rw-r--r--src/pkg/net/http/server.go67
1 files changed, 67 insertions, 0 deletions
diff --git a/src/pkg/net/http/server.go b/src/pkg/net/http/server.go
index fea1898fd7..8ca48ab3ce 100644
--- a/src/pkg/net/http/server.go
+++ b/src/pkg/net/http/server.go
@@ -1079,8 +1079,16 @@ func validNPN(proto string) bool {
return true
}
+func (c *conn) setState(nc net.Conn, state ConnState) {
+ if hook := c.server.ConnState; hook != nil {
+ hook(nc, state)
+ }
+}
+
// Serve a new connection.
func (c *conn) serve() {
+ origConn := c.rwc // copy it before it's set nil on Close or Hijack
+ c.setState(origConn, StateNew)
defer func() {
if err := recover(); err != nil {
const size = 64 << 10
@@ -1090,6 +1098,7 @@ func (c *conn) serve() {
}
if !c.hijacked() {
c.close()
+ c.setState(origConn, StateClosed)
}
}()
@@ -1116,6 +1125,10 @@ func (c *conn) serve() {
for {
w, err := c.readRequest()
+ // TODO(bradfitz): could push this StateActive
+ // earlier, but in practice header will be all in one
+ // packet/Read:
+ c.setState(c.rwc, StateActive)
if err != nil {
if err == errTooLarge {
// Their HTTP client may or may not be
@@ -1161,6 +1174,7 @@ func (c *conn) serve() {
// in parallel even if their responses need to be serialized.
serverHandler{c.server}.ServeHTTP(w, w.req)
if c.hijacked() {
+ c.setState(origConn, StateHijacked)
return
}
w.finishRequest()
@@ -1170,6 +1184,7 @@ func (c *conn) serve() {
}
break
}
+ c.setState(c.rwc, StateIdle)
}
}
@@ -1580,6 +1595,58 @@ type Server struct {
// and RemoteAddr if not already set. The connection is
// automatically closed when the function returns.
TLSNextProto map[string]func(*Server, *tls.Conn, Handler)
+
+ // ConnState specifies an optional callback function that is
+ // called when a client connection changes state. See the
+ // ConnState type and associated constants for details.
+ ConnState func(net.Conn, ConnState)
+}
+
+// A ConnState represents the state of a client connection to a server.
+// It's used by the optional Server.ConnState hook.
+type ConnState int
+
+const (
+ // StateNew represents a new connection that is expected to
+ // send a request immediately. Connections begin at this
+ // state and then transition to either StateActive or
+ // StateClosed.
+ StateNew ConnState = iota
+
+ // StateActive represents a connection that has read 1 or more
+ // bytes of a request. The Server.ConnState hook for
+ // StateActive fires before the request has entered a handler
+ // and doesn't fire again until the request has been
+ // handled. After the request is handled, the state
+ // transitions to StateClosed, StateHijacked, or StateIdle.
+ StateActive
+
+ // StateIdle represents a connection that has finished
+ // handling a request and is in the keep-alive state, waiting
+ // for a new request. Connections transition from StateIdle
+ // to either StateActive or StateClosed.
+ StateIdle
+
+ // StateHijacked represents a hijacked connection.
+ // This is a terminal state. It does not transition to StateClosed.
+ StateHijacked
+
+ // StateClosed represents a closed connection.
+ // This is a terminal state. Hijacked connections do not
+ // transition to StateClosed.
+ StateClosed
+)
+
+var stateName = map[ConnState]string{
+ StateNew: "new",
+ StateActive: "active",
+ StateIdle: "idle",
+ StateHijacked: "hijacked",
+ StateClosed: "closed",
+}
+
+func (c ConnState) String() string {
+ return stateName[c]
}
// serverHandler delegates to either the server's Handler or