aboutsummaryrefslogtreecommitdiff
path: root/libgo/go/net/http/server.go
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/net/http/server.go')
-rw-r--r--libgo/go/net/http/server.go117
1 files changed, 62 insertions, 55 deletions
diff --git a/libgo/go/net/http/server.go b/libgo/go/net/http/server.go
index aaf7b68..77329b2 100644
--- a/libgo/go/net/http/server.go
+++ b/libgo/go/net/http/server.go
@@ -19,6 +19,7 @@ import (
"net"
"net/textproto"
"net/url"
+ urlpkg "net/url"
"os"
"path"
"runtime"
@@ -1384,7 +1385,12 @@ func (cw *chunkWriter) writeHeader(p []byte) {
if bodyAllowedForStatus(code) {
// If no content type, apply sniffing algorithm to body.
_, haveType := header["Content-Type"]
- if !haveType && !hasTE && len(p) > 0 {
+
+ // If the Content-Encoding was set and is non-blank,
+ // we shouldn't sniff the body. See Issue 31753.
+ ce := header.Get("Content-Encoding")
+ hasCE := len(ce) > 0
+ if !hasCE && !haveType && !hasTE && len(p) > 0 {
setHeader.contentType = DetectContentType(p)
}
} else {
@@ -1696,11 +1702,10 @@ func (c *conn) closeWriteAndWait() {
time.Sleep(rstAvoidanceDelay)
}
-// validNPN reports whether the proto is not a blacklisted Next
-// Protocol Negotiation protocol. Empty and built-in protocol types
-// are blacklisted and can't be overridden with alternate
-// implementations.
-func validNPN(proto string) bool {
+// validNextProto reports whether the proto is not a blacklisted ALPN
+// protocol name. Empty and built-in protocol types are blacklisted
+// and can't be overridden with alternate implementations.
+func validNextProto(proto string) bool {
switch proto {
case "", "http/1.1", "http/1.0":
return false
@@ -1799,9 +1804,9 @@ func (c *conn) serve(ctx context.Context) {
}
c.tlsState = new(tls.ConnectionState)
*c.tlsState = tlsConn.ConnectionState()
- if proto := c.tlsState.NegotiatedProtocol; validNPN(proto) {
+ if proto := c.tlsState.NegotiatedProtocol; validNextProto(proto) {
if fn := c.server.TLSNextProto[proto]; fn != nil {
- h := initNPNRequest{ctx, tlsConn, serverHandler{c.server}}
+ h := initALPNRequest{ctx, tlsConn, serverHandler{c.server}}
fn(c.server, tlsConn, h)
}
return
@@ -2066,8 +2071,7 @@ func StripPrefix(prefix string, h Handler) Handler {
// Setting the Content-Type header to any value, including nil,
// disables that behavior.
func Redirect(w ResponseWriter, r *Request, url string, code int) {
- // parseURL is just url.Parse (url is shadowed for godoc).
- if u, err := parseURL(url); err == nil {
+ if u, err := urlpkg.Parse(url); err == nil {
// If url was relative, make its path absolute by
// combining with request path.
// The client would probably do this for us,
@@ -2121,10 +2125,6 @@ func Redirect(w ResponseWriter, r *Request, url string, code int) {
}
}
-// parseURL is just url.Parse. It exists only so that url.Parse can be called
-// in places where url is shadowed for godoc. See https://golang.org/cl/49930.
-var parseURL = url.Parse
-
var htmlReplacer = strings.NewReplacer(
"&", "&",
"<", "&lt;",
@@ -2493,7 +2493,12 @@ func ServeTLS(l net.Listener, handler Handler, certFile, keyFile string) error {
// A Server defines parameters for running an HTTP server.
// The zero value for Server is a valid configuration.
type Server struct {
- Addr string // TCP address to listen on, ":http" if empty
+ // Addr optionally specifies the TCP address for the server to listen on,
+ // in the form "host:port". If empty, ":http" (port 80) is used.
+ // The service names are defined in RFC 6335 and assigned by IANA.
+ // See net.Dial for details of the address format.
+ Addr string
+
Handler Handler // handler to invoke, http.DefaultServeMux if nil
// TLSConfig optionally provides a TLS configuration for use
@@ -2542,7 +2547,7 @@ type Server struct {
MaxHeaderBytes int
// TLSNextProto optionally specifies a function to take over
- // ownership of the provided TLS connection when an NPN/ALPN
+ // ownership of the provided TLS connection when an ALPN
// protocol upgrade has occurred. The map key is the protocol
// name negotiated. The Handler argument should be used to
// handle HTTP requests and will initialize the Request's TLS
@@ -2692,7 +2697,7 @@ func (srv *Server) Shutdown(ctx context.Context) error {
// RegisterOnShutdown registers a function to call on Shutdown.
// This can be used to gracefully shutdown connections that have
-// undergone NPN/ALPN protocol upgrade or that have been hijacked.
+// undergone ALPN protocol upgrade or that have been hijacked.
// This function should start protocol-specific graceful shutdown,
// but should not wait for shutdown to complete.
func (srv *Server) RegisterOnShutdown(f func()) {
@@ -2886,8 +2891,6 @@ func (srv *Server) Serve(l net.Listener) error {
}
defer srv.trackListener(&l, false)
- var tempDelay time.Duration // how long to sleep on accept failure
-
baseCtx := context.Background()
if srv.BaseContext != nil {
baseCtx = srv.BaseContext(origListener)
@@ -2896,16 +2899,18 @@ func (srv *Server) Serve(l net.Listener) error {
}
}
+ var tempDelay time.Duration // how long to sleep on accept failure
+
ctx := context.WithValue(baseCtx, ServerContextKey, srv)
for {
- rw, e := l.Accept()
- if e != nil {
+ rw, err := l.Accept()
+ if err != nil {
select {
case <-srv.getDoneChan():
return ErrServerClosed
default:
}
- if ne, ok := e.(net.Error); ok && ne.Temporary() {
+ if ne, ok := err.(net.Error); ok && ne.Temporary() {
if tempDelay == 0 {
tempDelay = 5 * time.Millisecond
} else {
@@ -2914,22 +2919,23 @@ func (srv *Server) Serve(l net.Listener) error {
if max := 1 * time.Second; tempDelay > max {
tempDelay = max
}
- srv.logf("http: Accept error: %v; retrying in %v", e, tempDelay)
+ srv.logf("http: Accept error: %v; retrying in %v", err, tempDelay)
time.Sleep(tempDelay)
continue
}
- return e
+ return err
}
+ connCtx := ctx
if cc := srv.ConnContext; cc != nil {
- ctx = cc(ctx, rw)
- if ctx == nil {
+ connCtx = cc(connCtx, rw)
+ if connCtx == nil {
panic("ConnContext returned nil")
}
}
tempDelay = 0
c := srv.newConn(rw)
c.setState(c.rwc, StateNew) // before Serve can return
- go c.serve(ctx)
+ go c.serve(connCtx)
}
}
@@ -3160,7 +3166,7 @@ func (srv *Server) onceSetNextProtoDefaults_Serve() {
// configured otherwise. (by setting srv.TLSNextProto non-nil)
// It must only be called via srv.nextProtoOnce (use srv.setupHTTP2_*).
func (srv *Server) onceSetNextProtoDefaults() {
- if strings.Contains(os.Getenv("GODEBUG"), "http2server=0") {
+ if omitBundledHTTP2 || strings.Contains(os.Getenv("GODEBUG"), "http2server=0") {
return
}
// Enable HTTP/2 by default if the user hasn't otherwise
@@ -3182,8 +3188,8 @@ func (srv *Server) onceSetNextProtoDefaults() {
// After such a timeout, writes by h to its ResponseWriter will return
// ErrHandlerTimeout.
//
-// TimeoutHandler supports the Flusher and Pusher interfaces but does not
-// support the Hijacker interface.
+// TimeoutHandler supports the Pusher interface but does not support
+// the Hijacker or Flusher interfaces.
func TimeoutHandler(h Handler, dt time.Duration, msg string) Handler {
return &timeoutHandler{
handler: h,
@@ -3223,8 +3229,9 @@ func (h *timeoutHandler) ServeHTTP(w ResponseWriter, r *Request) {
r = r.WithContext(ctx)
done := make(chan struct{})
tw := &timeoutWriter{
- w: w,
- h: make(Header),
+ w: w,
+ h: make(Header),
+ req: r,
}
panicChan := make(chan interface{}, 1)
go func() {
@@ -3264,6 +3271,7 @@ type timeoutWriter struct {
w ResponseWriter
h Header
wbuf bytes.Buffer
+ req *Request
mu sync.Mutex
timedOut bool
@@ -3272,7 +3280,6 @@ type timeoutWriter struct {
}
var _ Pusher = (*timeoutWriter)(nil)
-var _ Flusher = (*timeoutWriter)(nil)
// Push implements the Pusher interface.
func (tw *timeoutWriter) Push(target string, opts *PushOptions) error {
@@ -3282,14 +3289,6 @@ func (tw *timeoutWriter) Push(target string, opts *PushOptions) error {
return ErrNotSupported
}
-// Flush implements the Flusher interface.
-func (tw *timeoutWriter) Flush() {
- f, ok := tw.w.(Flusher)
- if ok {
- f.Flush()
- }
-}
-
func (tw *timeoutWriter) Header() Header { return tw.h }
func (tw *timeoutWriter) Write(p []byte) (int, error) {
@@ -3299,24 +3298,32 @@ func (tw *timeoutWriter) Write(p []byte) (int, error) {
return 0, ErrHandlerTimeout
}
if !tw.wroteHeader {
- tw.writeHeader(StatusOK)
+ tw.writeHeaderLocked(StatusOK)
}
return tw.wbuf.Write(p)
}
-func (tw *timeoutWriter) WriteHeader(code int) {
+func (tw *timeoutWriter) writeHeaderLocked(code int) {
checkWriteHeaderCode(code)
- tw.mu.Lock()
- defer tw.mu.Unlock()
- if tw.timedOut || tw.wroteHeader {
+
+ switch {
+ case tw.timedOut:
return
+ case tw.wroteHeader:
+ if tw.req != nil {
+ caller := relevantCaller()
+ logf(tw.req, "http: superfluous response.WriteHeader call from %s (%s:%d)", caller.Function, path.Base(caller.File), caller.Line)
+ }
+ default:
+ tw.wroteHeader = true
+ tw.code = code
}
- tw.writeHeader(code)
}
-func (tw *timeoutWriter) writeHeader(code int) {
- tw.wroteHeader = true
- tw.code = code
+func (tw *timeoutWriter) WriteHeader(code int) {
+ tw.mu.Lock()
+ defer tw.mu.Unlock()
+ tw.writeHeaderLocked(code)
}
// onceCloseListener wraps a net.Listener, protecting it from
@@ -3350,10 +3357,10 @@ func (globalOptionsHandler) ServeHTTP(w ResponseWriter, r *Request) {
}
}
-// initNPNRequest is an HTTP handler that initializes certain
+// initALPNRequest is an HTTP handler that initializes certain
// uninitialized fields in its *Request. Such partially-initialized
-// Requests come from NPN protocol handlers.
-type initNPNRequest struct {
+// Requests come from ALPN protocol handlers.
+type initALPNRequest struct {
ctx context.Context
c *tls.Conn
h serverHandler
@@ -3363,9 +3370,9 @@ type initNPNRequest struct {
// recognized by x/net/http2 to pass down a context; the TLSNextProto
// API predates context support so we shoehorn through the only
// interface we have available.
-func (h initNPNRequest) BaseContext() context.Context { return h.ctx }
+func (h initALPNRequest) BaseContext() context.Context { return h.ctx }
-func (h initNPNRequest) ServeHTTP(rw ResponseWriter, req *Request) {
+func (h initALPNRequest) ServeHTTP(rw ResponseWriter, req *Request) {
if req.TLS == nil {
req.TLS = &tls.ConnectionState{}
*req.TLS = h.c.ConnectionState()