http: add StripPrefix handler wrapper

R=rsc
CC=golang-dev
https://golang.org/cl/4626067
diff --git a/src/pkg/http/fs.go b/src/pkg/http/fs.go
index 5651298..866abe6 100644
--- a/src/pkg/http/fs.go
+++ b/src/pkg/http/fs.go
@@ -192,23 +192,19 @@
 }
 
 type fileHandler struct {
-	root   string
-	prefix string
+	root string
 }
 
 // FileServer returns a handler that serves HTTP requests
 // with the contents of the file system rooted at root.
 // It strips prefix from the incoming requests before
 // looking up the file name in the file system.
-func FileServer(root, prefix string) Handler { return &fileHandler{root, prefix} }
+func FileServer(root, prefix string) Handler {
+	return StripPrefix(prefix, &fileHandler{root})
+}
 
 func (f *fileHandler) ServeHTTP(w ResponseWriter, r *Request) {
 	path := r.URL.Path
-	if !strings.HasPrefix(path, f.prefix) {
-		NotFound(w, r)
-		return
-	}
-	path = path[len(f.prefix):]
 	serveFile(w, r, filepath.Join(f.root, filepath.FromSlash(path)), true)
 }
 
diff --git a/src/pkg/http/serve_test.go b/src/pkg/http/serve_test.go
index 207646f..a6a566a 100644
--- a/src/pkg/http/serve_test.go
+++ b/src/pkg/http/serve_test.go
@@ -798,6 +798,30 @@
 	}
 }
 
+func TestStripPrefix(t *testing.T) {
+	h := HandlerFunc(func(w ResponseWriter, r *Request) {
+		w.Header().Set("X-Path", r.URL.Path)
+	})
+	ts := httptest.NewServer(StripPrefix("/foo", h))
+	defer ts.Close()
+
+	res, err := Get(ts.URL + "/foo/bar")
+	if err != nil {
+		t.Fatal(err)
+	}
+	if g, e := res.Header.Get("X-Path"), "/bar"; g != e {
+		t.Errorf("test 1: got %s, want %s", g, e)
+	}
+
+	res, err = Get(ts.URL + "/bar")
+	if err != nil {
+		t.Fatal(err)
+	}
+	if g, e := res.StatusCode, 404; g != e {
+		t.Errorf("test 2: got status %v, want %v", g, e)
+	}
+}
+
 type errorListener struct {
 	errs []os.Error
 }
diff --git a/src/pkg/http/server.go b/src/pkg/http/server.go
index 03b9cd8..1e06c24 100644
--- a/src/pkg/http/server.go
+++ b/src/pkg/http/server.go
@@ -592,6 +592,22 @@
 // that replies to each request with a ``404 page not found'' reply.
 func NotFoundHandler() Handler { return HandlerFunc(NotFound) }
 
+// StripPrefix returns a handler that serves HTTP requests
+// by removing the given prefix from the request URL's Path
+// and invoking the handler h. StripPrefix handles a
+// request for a path that doesn't begin with prefix by
+// replying with an HTTP 404 not found error.
+func StripPrefix(prefix string, h Handler) Handler {
+	return HandlerFunc(func(w ResponseWriter, r *Request) {
+		if !strings.HasPrefix(r.URL.Path, prefix) {
+			NotFound(w, r)
+			return
+		}
+		r.URL.Path = r.URL.Path[len(prefix):]
+		h.ServeHTTP(w, r)
+	})
+}
+
 // Redirect replies to the request with a redirect to url,
 // which may be a path relative to the request path.
 func Redirect(w ResponseWriter, r *Request, url string, code int) {