add path.Clean and other utilities.

use path.Clean in web server to sanitize URLs.

http://triv/go/../../../etc/passwd

no longer serves the password file.
it redirects to

http://triv/etc/passwd

which then gets a 404.

R=r
DELTA=288  (286 added, 0 deleted, 2 changed)
OCL=27142
CL=27152
This commit is contained in:
Russ Cox 2009-04-07 00:40:07 -07:00
parent 640f3f25dc
commit 16b38b554f
4 changed files with 290 additions and 2 deletions

View file

@ -19,6 +19,7 @@ import (
"log";
"net";
"os";
"path";
"strconv";
)
@ -209,7 +210,7 @@ func (c *Conn) serve() {
}
// HTTP cannot have multiple simultaneous active requests.
// Until the server replies to this request, it can't read another,
// so we might as well run the handler in this thread.
// so we might as well run the handler in this goroutine.
c.handler.ServeHTTP(c, req);
if c.hijacked {
return;
@ -300,6 +301,10 @@ func RedirectHandler(url string) Handler {
// so that a handler might register for the two patterns
// "/codesearch" and "codesearch.google.com/"
// without 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
// equivalent .- and ..-free URL.
type ServeMux struct {
m map[string] Handler
}
@ -325,9 +330,33 @@ func pathMatch(pattern, path string) bool {
return len(path) >= n && path[0:n] == pattern;
}
// Return the canonical path for p, eliminating . and .. elements.
func cleanPath(p string) string {
if p == "" {
return "/";
}
if p[0] != '/' {
p = "/" + p;
}
np := path.Clean(p);
// path.Clean removes trailing slash except for root;
// put the trailing slash back if necessary.
if p[len(p)-1] == '/' && np != "/" {
np += "/";
}
return np;
}
// ServeHTTP dispatches the request to the handler whose
// pattern most closely matches the request URL.
func (mux *ServeMux) ServeHTTP(c *Conn, req *Request) {
// Clean path to canonical form and redirect.
if p := cleanPath(req.Url.Path); p != req.Url.Path {
c.SetHeader("Location", p);
c.WriteHeader(StatusMovedPermanently);
return;
}
// Most-specific (longest) pattern wins.
var h Handler;
var n = 0;