summaryrefslogtreecommitdiff
path: root/src/pkg/http/server.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/http/server.go')
-rw-r--r--src/pkg/http/server.go72
1 files changed, 43 insertions, 29 deletions
diff --git a/src/pkg/http/server.go b/src/pkg/http/server.go
index b8783da28..6672c494b 100644
--- a/src/pkg/http/server.go
+++ b/src/pkg/http/server.go
@@ -181,7 +181,9 @@ func (c *conn) readRequest() (w *response, err os.Error) {
w.SetHeader("Content-Type", "text/html; charset=utf-8")
w.SetHeader("Date", time.UTC().Format(TimeFormat))
- if req.ProtoAtLeast(1, 1) {
+ if req.Method == "HEAD" {
+ // do nothing
+ } else if req.ProtoAtLeast(1, 1) {
// HTTP/1.1 or greater: use chunked transfer encoding
// to avoid closing the connection at EOF.
w.chunking = true
@@ -227,6 +229,10 @@ func (w *response) WriteHeader(code int) {
w.header["Transfer-Encoding"] = "", false
w.chunking = false
}
+ // Cannot use Content-Length with non-identity Transfer-Encoding.
+ if w.chunking {
+ w.header["Content-Length"] = "", false
+ }
if !w.req.ProtoAtLeast(1, 0) {
return
}
@@ -268,7 +274,7 @@ func (w *response) Write(data []byte) (n int, err os.Error) {
return 0, nil
}
- if w.status == StatusNotModified {
+ if w.status == StatusNotModified || w.req.Method == "HEAD" {
// Must not have body.
return 0, ErrBodyNotAllowed
}
@@ -495,11 +501,11 @@ func Redirect(w ResponseWriter, r *Request, url string, code int) {
// RFC2616 recommends that a short note "SHOULD" be included in the
// response because older user agents may not understand 301/307.
- note := "<a href=\"" + htmlEscape(url) + "\">" + statusText[code] + "</a>.\n"
- if r.Method == "POST" {
- note = ""
+ // Shouldn't send the response for POST or HEAD; that leaves GET.
+ if r.Method == "GET" {
+ note := "<a href=\"" + htmlEscape(url) + "\">" + statusText[code] + "</a>.\n"
+ fmt.Fprintln(w, note)
}
- fmt.Fprintln(w, note)
}
func htmlEscape(s string) string {
@@ -533,9 +539,8 @@ func RedirectHandler(url string, code int) Handler {
// patterns and calls the handler for the pattern that
// most closely matches the URL.
//
-// Patterns named fixed paths, like "/favicon.ico",
-// or subtrees, like "/images/" (note the trailing slash).
-// Patterns must begin with /.
+// Patterns named fixed, rooted paths, like "/favicon.ico",
+// or rooted subtrees, like "/images/" (note the trailing slash).
// Longer patterns take precedence over shorter ones, so that
// if there are handlers registered for both "/images/"
// and "/images/thumbnails/", the latter handler will be
@@ -543,11 +548,11 @@ func RedirectHandler(url string, code int) Handler {
// former will receiver requests for any other paths in the
// "/images/" subtree.
//
-// In the future, the pattern syntax may be relaxed to allow
-// an optional host-name at the beginning of the pattern,
-// so that a handler might register for the two patterns
-// "/codesearch" and "codesearch.google.com/"
-// without taking over requests for http://www.google.com/.
+// Patterns may optionally begin with a host name, restricting matches to
+// URLs on that host only. Host-specific patterns take precedence over
+// general patterns, so that a handler might register for the two patterns
+// "/codesearch" and "codesearch.google.com/" without also taking over
+// requests for "http://www.google.com/".
//
// ServeMux also takes care of sanitizing the URL request path,
// redirecting any request containing . or .. elements to an
@@ -592,21 +597,13 @@ func cleanPath(p string) string {
return np
}
-// ServeHTTP dispatches the request to the handler whose
-// pattern most closely matches the request URL.
-func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) {
- // Clean path to canonical form and redirect.
- if p := cleanPath(r.URL.Path); p != r.URL.Path {
- w.SetHeader("Location", p)
- w.WriteHeader(StatusMovedPermanently)
- return
- }
-
- // Most-specific (longest) pattern wins.
+// Find a handler on a handler map given a path string
+// Most-specific (longest) pattern wins
+func (mux *ServeMux) match(path string) Handler {
var h Handler
var n = 0
for k, v := range mux.m {
- if !pathMatch(k, r.URL.Path) {
+ if !pathMatch(k, path) {
continue
}
if h == nil || len(k) > n {
@@ -614,6 +611,23 @@ func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) {
h = v
}
}
+ 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) {
+ // Clean path to canonical form and redirect.
+ if p := cleanPath(r.URL.Path); p != r.URL.Path {
+ w.SetHeader("Location", p)
+ 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()
}
@@ -622,7 +636,7 @@ func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) {
// Handle registers the handler for the given pattern.
func (mux *ServeMux) Handle(pattern string, handler Handler) {
- if pattern == "" || pattern[0] != '/' {
+ if pattern == "" {
panic("http: invalid pattern " + pattern)
}
@@ -697,7 +711,7 @@ func Serve(l net.Listener, handler Handler) os.Error {
// http.HandleFunc("/hello", HelloServer)
// err := http.ListenAndServe(":12345", nil)
// if err != nil {
-// log.Exit("ListenAndServe: ", err.String())
+// log.Fatal("ListenAndServe: ", err.String())
// }
// }
func ListenAndServe(addr string, handler Handler) os.Error {
@@ -731,7 +745,7 @@ func ListenAndServe(addr string, handler Handler) os.Error {
// log.Printf("About to listen on 10443. Go to https://127.0.0.1:10443/")
// err := http.ListenAndServeTLS(":10443", "cert.pem", "key.pem", nil)
// if err != nil {
-// log.Exit(err)
+// log.Fatal(err)
// }
// }
//