aboutsummaryrefslogtreecommitdiff
path: root/src/lib/http
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2009-04-07 00:40:07 -0700
committerRuss Cox <rsc@golang.org>2009-04-07 00:40:07 -0700
commit16b38b554fb4dae82923cb81a5c6a76ee2959d2f (patch)
treed99b97d1215df17d8a4f968eb03664bc6512dee7 /src/lib/http
parent640f3f25dcd238bfc6b4fd99b1808071cfa12888 (diff)
downloadgo-16b38b554fb4dae82923cb81a5c6a76ee2959d2f.tar.xz
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
Diffstat (limited to 'src/lib/http')
-rw-r--r--src/lib/http/server.go31
1 files changed, 30 insertions, 1 deletions
diff --git a/src/lib/http/server.go b/src/lib/http/server.go
index df2ce3698a..fa29e9bc1c 100644
--- a/src/lib/http/server.go
+++ b/src/lib/http/server.go
@@ -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;