7.12. 验证
你可能已经发现,程序中有一个严重的安全漏洞:用户可以提供任意的路径在服务器上执行读写操作。为了消除这个问题,我们使用正则表达式验证页面的标题。
首先,添加"regexp"到导入列表。然后创建一个全局变量存储我们的验证正则表达式:
函数regexp.MustCompile解析并且编译正则表达式,返回一个regexp.Regexp对象。和template.MustParseFile类似,当表达式编译错误时,MustCompile抛出一个错误,而Compile在它的第二个返回参数中返回一个os.Error。
现在,我们编写一个函数,它从请求URL解析中解析页面标题,并且使用titleValidator进行验证:
func getTitle(w http.ResponseWriter, r *http.Request) (title string, err os.Error) {
title = r.URL.Path[lenPath:]
if !titleValidator.MatchString(title) {
http.NotFound(w, r)
err = os.NewError("Invalid Page Title")
}
return
}
如果标题有效,它返回一个nil错误值。如果无效,它写"404 Not Found"错误到HTTP连接中,并且返回一个错误对象。
修改所有的处理函数,使用getTitle获取页面标题:
func viewHandler(w http.ResponseWriter, r *http.Request) {
title, err := getTitle(w, r)
if err != nil {
return
}
p, err := loadPage(title)
if err != nil {
http.Redirect(w, r, "/edit/"+title, http.StatusFound)
return
}
renderTemplate(w, "view", p)
}
func editHandler(w http.ResponseWriter, r *http.Request) {
title, err := getTitle(w, r)
if err != nil {
return
}
p, err := loadPage(title)
if err != nil {
p = &page{title: title}
}
renderTemplate(w, "edit", p)
}
func saveHandler(w http.ResponseWriter, r *http.Request) {
title, err := getTitle(w, r)
if err != nil {
return
}
body := r.FormValue("body")
p := &page{title: title, body: []byte(body)}
err = p.save()
if err != nil {
http.Error(w, err.String(), http.StatusInternalServerError)
return
}
http.Redirect(w, r, "/view/"+title, http.StatusFound)
}