make Location translate relative path to absolute

(HTTP requires absolute in protocol).

add URL tests

R=r
DELTA=243  (242 added, 0 deleted, 1 changed)
OCL=27472
CL=27523
This commit is contained in:
Russ Cox 2009-04-15 18:40:55 -07:00
parent 17c290ffb9
commit cff99ba167
3 changed files with 244 additions and 1 deletions

View file

@ -269,6 +269,49 @@ func NotFoundHandler() Handler {
// Redirect replies to the request with a redirect to url,
// which may be a path relative to the request path.
func Redirect(c *Conn, url string) {
u, err := ParseURL(url);
if err != nil {
// TODO report internal error instead?
c.SetHeader("Location", url);
c.WriteHeader(StatusMovedPermanently);
}
// If url was relative, make absolute by
// combining with request path.
// The browser would probably do this for us,
// but doing it ourselves is more reliable.
// NOTE(rsc): RFC 2616 says that the Location
// line must be an absolute URI, like
// "http://www.google.com/redirect/",
// not a path like "/redirect/".
// Unfortunately, we don't know what to
// put in the host name section to get the
// client to connect to us again, so we can't
// know the right absolute URI to send back.
// Because of this problem, no one pays attention
// to the RFC; they all send back just a new path.
// So do we.
oldpath := c.Req.Url.Path;
if oldpath == "" { // should not happen, but avoid a crash if it does
oldpath = "/"
}
if u.Scheme == "" {
// no leading http://server
if url == "" || url[0] != '/' {
// make relative path absolute
olddir, oldfile := path.Split(oldpath);
url = olddir + url;
}
// clean up but preserve trailing slash
trailing := url[len(url) - 1] == '/';
url = path.Clean(url);
if trailing && url[len(url) - 1] != '/' {
url += "/";
}
}
c.SetHeader("Location", url);
c.WriteHeader(StatusMovedPermanently);
}