Skip to content

Latest commit

 

History

History
68 lines (58 loc) · 2.25 KB

12-验证.md

File metadata and controls

68 lines (58 loc) · 2.25 KB

正如你可能观察到的,这个程序有严重的安全问题:一个用户可以随意提供路径在服务器上度/写。为缓解这个问题,我们可以写一个函数使用正则表达式校验标题。

首先,添加“regexp“到导入列表。然后我们可以创建全局变量来保存我们的验证表达式:

var validPath = regexp.MustCompile("^/(edit|save|view)/([a-zA-Z0-9]+)$")

这个regexp.MustCompile函数将解析并编译正则表达式,并返回一个不同于Compile的regexp.Regexp.MustCompile,如果表达式编译失败它将引起恐慌失败。

现在,让我们写一个函数,用validPath表达式验证路径并导出页面标题:

func getTitle(w http.ResponseWriter, r *http.Request) (string, error) {
    m := validPath.FindStringSubmatch(r.URL.Path)
    if m == nil {
        http.NotFound(w, r)
        return "", errors.New("Invalid Page Title")
    }
    return m[2], nil // The title is the second subexpression.
}

如果标题是有效的,它会顺便带着一个nil的错误值被返回。如果标题无效,此函数会将一个“404 Not Found“错误写入到HTTP连接,并向处理函数返回一个错误。为了创建一个新的错误,我们得导入errors包。

让我们在每个处理函数里放入一个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.Error(), http.StatusInternalServerError)
        return
    }
    http.Redirect(w, r, "/view/"+title, http.StatusFound)
}