// TODO(bradfitz): move common stuff here. The other files have accumulated
// generic http stuff in random places.
+
+// contextKey is a value for use with context.WithValue. It's used as
+// a pointer so it fits in an interface{} without allocation.
+type contextKey struct {
+ name string
+}
+
+func (k *contextKey) String() string { return "net/http context value " + k.name }
}
}
+func TestServerContext_ServerContextKey(t *testing.T) {
+ defer afterTest(t)
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ ctx := r.Context()
+ got := ctx.Value(ServerContextKey)
+ if _, ok := got.(*Server); !ok {
+ t.Errorf("context value = %T; want *http.Server")
+ }
+ }))
+ defer ts.Close()
+ res, err := Get(ts.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+ res.Body.Close()
+}
+
func BenchmarkClientServer(b *testing.B) {
b.ReportAllocs()
b.StopTimer()
CloseNotify() <-chan bool
}
+var (
+ // ServerContextKey is a context key. It can be used in HTTP
+ // handlers with context.WithValue to access the server that
+ // started the handler. The associated value will be of
+ // type *Server.
+ ServerContextKey = &contextKey{"http-server"}
+)
+
// A conn represents the server side of an HTTP connection.
type conn struct {
// server is the server on which the connection arrived.
func (e badRequestError) Error() string { return "Bad Request: " + string(e) }
// Serve a new connection.
-func (c *conn) serve() {
+func (c *conn) serve(ctx context.Context) {
c.remoteAddr = c.rwc.RemoteAddr().String()
defer func() {
if err := recover(); err != nil {
c.bufr = newBufioReader(c.r)
c.bufw = newBufioWriterSize(checkConnErrorWriter{c}, 4<<10)
- // TODO: allow changing base context? can't imagine concrete
- // use cases yet.
- baseCtx := context.Background()
- ctx, cancelCtx := context.WithCancel(baseCtx)
+ ctx, cancelCtx := context.WithCancel(ctx)
defer cancelCtx()
for {
if err := srv.setupHTTP2(); err != nil {
return err
}
+ // TODO: allow changing base context? can't imagine concrete
+ // use cases yet.
+ baseCtx := context.Background()
+ ctx := context.WithValue(baseCtx, ServerContextKey, srv)
for {
rw, e := l.Accept()
if e != nil {
tempDelay = 0
c := srv.newConn(rw)
c.setState(c.rwc, StateNew) // before Serve can return
- go c.serve()
+ go c.serve(ctx)
}
}