diff options
Diffstat (limited to 'src/pkg/net/http/server.go')
-rw-r--r-- | src/pkg/net/http/server.go | 93 |
1 files changed, 67 insertions, 26 deletions
diff --git a/src/pkg/net/http/server.go b/src/pkg/net/http/server.go index bad3bcb28..fa0df54a2 100644 --- a/src/pkg/net/http/server.go +++ b/src/pkg/net/http/server.go @@ -12,7 +12,6 @@ package http import ( "bufio" "bytes" - "crypto/rand" "crypto/tls" "errors" "fmt" @@ -59,7 +58,9 @@ type ResponseWriter interface { // Write writes the data to the connection as part of an HTTP reply. // If WriteHeader has not yet been called, Write calls WriteHeader(http.StatusOK) - // before writing the data. + // before writing the data. If the Header does not contain a + // Content-Type line, Write adds a Content-Type set to the result of passing + // the initial 512 bytes of written data to DetectContentType. Write([]byte) (int, error) // WriteHeader sends an HTTP response header with status code. @@ -341,7 +342,7 @@ func (w *response) WriteHeader(code int) { } } else { // If no content type, apply sniffing algorithm to body. - if w.header.Get("Content-Type") == "" { + if w.header.Get("Content-Type") == "" && w.req.Method != "HEAD" { w.needSniff = true } } @@ -833,11 +834,17 @@ func RedirectHandler(url string, code int) Handler { // redirecting any request containing . or .. elements to an // equivalent .- and ..-free URL. type ServeMux struct { - m map[string]Handler + mu sync.RWMutex + m map[string]muxEntry +} + +type muxEntry struct { + explicit bool + h Handler } // NewServeMux allocates and returns a new ServeMux. -func NewServeMux() *ServeMux { return &ServeMux{make(map[string]Handler)} } +func NewServeMux() *ServeMux { return &ServeMux{m: make(map[string]muxEntry)} } // DefaultServeMux is the default ServeMux used by Serve. var DefaultServeMux = NewServeMux() @@ -883,12 +890,28 @@ func (mux *ServeMux) match(path string) Handler { } if h == nil || len(k) > n { n = len(k) - h = v + h = v.h } } return h } +// handler returns the handler to use for the request r. +func (mux *ServeMux) handler(r *Request) Handler { + mux.mu.RLock() + defer mux.mu.RUnlock() + + // Host-specific pattern takes precedence over generic ones + h := mux.match(r.Host + r.URL.Path) + if h == nil { + h = mux.match(r.URL.Path) + } + if h == nil { + h = NotFoundHandler() + } + return h +} + // ServeHTTP dispatches the request to the handler whose // pattern most closely matches the request URL. func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) { @@ -898,30 +921,33 @@ func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) { w.WriteHeader(StatusMovedPermanently) return } - // Host-specific pattern takes precedence over generic ones - h := mux.match(r.Host + r.URL.Path) - if h == nil { - h = mux.match(r.URL.Path) - } - if h == nil { - h = NotFoundHandler() - } - h.ServeHTTP(w, r) + mux.handler(r).ServeHTTP(w, r) } // Handle registers the handler for the given pattern. +// If a handler already exists for pattern, Handle panics. func (mux *ServeMux) Handle(pattern string, handler Handler) { + mux.mu.Lock() + defer mux.mu.Unlock() + if pattern == "" { panic("http: invalid pattern " + pattern) } + if handler == nil { + panic("http: nil handler") + } + if mux.m[pattern].explicit { + panic("http: multiple registrations for " + pattern) + } - mux.m[pattern] = handler + mux.m[pattern] = muxEntry{explicit: true, h: handler} // Helpful behavior: - // If pattern is /tree/, insert permanent redirect for /tree. + // If pattern is /tree/, insert an implicit permanent redirect for /tree. + // It can be overridden by an explicit registration. n := len(pattern) - if n > 0 && pattern[n-1] == '/' { - mux.m[pattern[0:n-1]] = RedirectHandler(pattern, StatusMovedPermanently) + if n > 0 && pattern[n-1] == '/' && !mux.m[pattern[0:n-1]].explicit { + mux.m[pattern[0:n-1]] = muxEntry{h: RedirectHandler(pattern, StatusMovedPermanently)} } } @@ -958,6 +984,7 @@ type Server struct { ReadTimeout time.Duration // maximum duration before timing out read of the request WriteTimeout time.Duration // maximum duration before timing out write of the response MaxHeaderBytes int // maximum size of request headers, DefaultMaxHeaderBytes if 0 + TLSConfig *tls.Config // optional TLS config, used by ListenAndServeTLS } // ListenAndServe listens on the TCP network address srv.Addr and then @@ -980,15 +1007,26 @@ func (srv *Server) ListenAndServe() error { // then call srv.Handler to reply to them. func (srv *Server) Serve(l net.Listener) error { defer l.Close() + var tempDelay time.Duration // how long to sleep on accept failure for { rw, e := l.Accept() if e != nil { if ne, ok := e.(net.Error); ok && ne.Temporary() { - log.Printf("http: Accept error: %v", e) + if tempDelay == 0 { + tempDelay = 5 * time.Millisecond + } else { + tempDelay *= 2 + } + if max := 1 * time.Second; tempDelay > max { + tempDelay = max + } + log.Printf("http: Accept error: %v; retrying in %v", e, tempDelay) + time.Sleep(tempDelay) continue } return e } + tempDelay = 0 if srv.ReadTimeout != 0 { rw.SetReadDeadline(time.Now().Add(srv.ReadTimeout)) } @@ -1078,14 +1116,17 @@ func ListenAndServeTLS(addr string, certFile string, keyFile string, handler Han // of the server's certificate followed by the CA's certificate. // // If srv.Addr is blank, ":https" is used. -func (s *Server) ListenAndServeTLS(certFile, keyFile string) error { - addr := s.Addr +func (srv *Server) ListenAndServeTLS(certFile, keyFile string) error { + addr := srv.Addr if addr == "" { addr = ":https" } - config := &tls.Config{ - Rand: rand.Reader, - NextProtos: []string{"http/1.1"}, + config := &tls.Config{} + if srv.TLSConfig != nil { + *config = *srv.TLSConfig + } + if config.NextProtos == nil { + config.NextProtos = []string{"http/1.1"} } var err error @@ -1101,7 +1142,7 @@ func (s *Server) ListenAndServeTLS(certFile, keyFile string) error { } tlsListener := tls.NewListener(conn, config) - return s.Serve(tlsListener) + return srv.Serve(tlsListener) } // TimeoutHandler returns a Handler that runs h with the given time limit. |