Commit 0d676f3d authored by Andrew Gerrand's avatar Andrew Gerrand

doc/articles/wiki: fix path handling and clean up test process

Fixes #6525.

R=r
CC=golang-dev
https://golang.org/cl/14383043
parent 97958827
...@@ -4,17 +4,7 @@ ...@@ -4,17 +4,7 @@
all: index.html all: index.html
CLEANFILES:=srcextract.bin htmlify.bin get.bin CLEANFILES:=get.bin final-test.bin a.out
index.html: wiki.html srcextract.bin htmlify.bin
PATH=.:$$PATH awk '/^!/{system(substr($$0,2)); next} {print}' < wiki.html | tr -d '\r' > index.html
test: get.bin
bash ./test.sh
rm -f get.6 get.bin
%.bin: %.go
go build -o $@ $^
clean: clean:
rm -f $(CLEANFILES) rm -f $(CLEANFILES)
...@@ -83,17 +83,15 @@ func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) { ...@@ -83,17 +83,15 @@ func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) {
} }
} }
const lenPath = len("/view/") var validPath = regexp.MustCompile("^/(edit|save|view)/([a-zA-Z0-9]+)$")
var titleValidator = regexp.MustCompile("^[a-zA-Z0-9]+$") func getTitle(w http.ResponseWriter, r *http.Request) (string, error) {
m := validPath.FindStringSubmatch(r.URL.Path)
func getTitle(w http.ResponseWriter, r *http.Request) (title string, err error) { if m == nil {
title = r.URL.Path[lenPath:]
if !titleValidator.MatchString(title) {
http.NotFound(w, r) http.NotFound(w, r)
err = errors.New("Invalid Page Title") return "", errors.New("Invalid Page Title")
} }
return return m[2], nil // The title is the second subexpression.
} }
func main() { func main() {
......
...@@ -29,10 +29,8 @@ func loadPage(title string) (*Page, error) { ...@@ -29,10 +29,8 @@ func loadPage(title string) (*Page, error) {
return &Page{Title: title, Body: body}, nil return &Page{Title: title, Body: body}, nil
} }
const lenPath = len("/view/")
func editHandler(w http.ResponseWriter, r *http.Request) { func editHandler(w http.ResponseWriter, r *http.Request) {
title := r.URL.Path[lenPath:] title := r.URL.Path[len("/edit/"):]
p, err := loadPage(title) p, err := loadPage(title)
if err != nil { if err != nil {
p = &Page{Title: title} p = &Page{Title: title}
...@@ -42,7 +40,7 @@ func editHandler(w http.ResponseWriter, r *http.Request) { ...@@ -42,7 +40,7 @@ func editHandler(w http.ResponseWriter, r *http.Request) {
} }
func viewHandler(w http.ResponseWriter, r *http.Request) { func viewHandler(w http.ResponseWriter, r *http.Request) {
title := r.URL.Path[lenPath:] title := r.URL.Path[len("/view/"):]
p, _ := loadPage(title) p, _ := loadPage(title)
t, _ := template.ParseFiles("view.html") t, _ := template.ParseFiles("view.html")
t.Execute(w, p) t.Execute(w, p)
......
...@@ -70,18 +70,16 @@ func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) { ...@@ -70,18 +70,16 @@ func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) {
} }
} }
const lenPath = len("/view/") var validPath = regexp.MustCompile("^/(edit|save|view)/([a-zA-Z0-9]+)$")
var titleValidator = regexp.MustCompile("^[a-zA-Z0-9]+$")
func makeHandler(fn func(http.ResponseWriter, *http.Request, string)) http.HandlerFunc { func makeHandler(fn func(http.ResponseWriter, *http.Request, string)) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
title := r.URL.Path[lenPath:] m := validPath.FindStringSubmatch(r.URL.Path)
if !titleValidator.MatchString(title) { if m == nil {
http.NotFound(w, r) http.NotFound(w, r)
return return
} }
fn(w, r, title) fn(w, r, m[2])
} }
} }
......
...@@ -29,10 +29,8 @@ func loadPage(title string) (*Page, error) { ...@@ -29,10 +29,8 @@ func loadPage(title string) (*Page, error) {
return &Page{Title: title, Body: body}, nil return &Page{Title: title, Body: body}, nil
} }
const lenPath = len("/view/")
func editHandler(w http.ResponseWriter, r *http.Request) { func editHandler(w http.ResponseWriter, r *http.Request) {
title := r.URL.Path[lenPath:] title := r.URL.Path[len("/edit/"):]
p, err := loadPage(title) p, err := loadPage(title)
if err != nil { if err != nil {
p = &Page{Title: title} p = &Page{Title: title}
...@@ -41,13 +39,13 @@ func editHandler(w http.ResponseWriter, r *http.Request) { ...@@ -41,13 +39,13 @@ func editHandler(w http.ResponseWriter, r *http.Request) {
} }
func viewHandler(w http.ResponseWriter, r *http.Request) { func viewHandler(w http.ResponseWriter, r *http.Request) {
title := r.URL.Path[lenPath:] title := r.URL.Path[len("/view/"):]
p, _ := loadPage(title) p, _ := loadPage(title)
renderTemplate(w, "view", p) renderTemplate(w, "view", p)
} }
func saveHandler(w http.ResponseWriter, r *http.Request) { func saveHandler(w http.ResponseWriter, r *http.Request) {
title := r.URL.Path[lenPath:] title := r.URL.Path[len("/save/"):]
body := r.FormValue("body") body := r.FormValue("body")
p := &Page{Title: title, Body: []byte(body)} p := &Page{Title: title, Body: []byte(body)}
p.save() p.save()
......
...@@ -67,18 +67,16 @@ func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) { ...@@ -67,18 +67,16 @@ func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) {
} }
} }
const lenPath = len("/view/") var validPath = regexp.MustCompile("^/(edit|save|view)/([a-zA-Z0-9]+)$")
var titleValidator = regexp.MustCompile("^[a-zA-Z0-9]+$")
func makeHandler(fn func(http.ResponseWriter, *http.Request, string)) http.HandlerFunc { func makeHandler(fn func(http.ResponseWriter, *http.Request, string)) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
title := r.URL.Path[lenPath:] m := validPath.FindStringSubmatch(r.URL.Path)
if !titleValidator.MatchString(title) { if m == nil {
http.NotFound(w, r) http.NotFound(w, r)
return return
} }
fn(w, r, title) fn(w, r, m[2])
} }
} }
......
// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"io/ioutil"
"os"
"text/template"
)
func main() {
b, _ := ioutil.ReadAll(os.Stdin)
template.HTMLEscape(os.Stdout, b)
}
...@@ -260,18 +260,15 @@ Let's create a handler, <code>viewHandler</code> that will allow users to ...@@ -260,18 +260,15 @@ Let's create a handler, <code>viewHandler</code> that will allow users to
view a wiki page. It will handle URLs prefixed with "/view/". view a wiki page. It will handle URLs prefixed with "/view/".
</p> </p>
{{code "doc/articles/wiki/part2.go" `/^const lenPath/`}}
{{code "doc/articles/wiki/part2.go" `/^func viewHandler/` `/^}/`}} {{code "doc/articles/wiki/part2.go" `/^func viewHandler/` `/^}/`}}
<p> <p>
First, this function extracts the page title from <code>r.URL.Path</code>, First, this function extracts the page title from <code>r.URL.Path</code>,
the path component of the request URL. The global constant the path component of the request URL.
<code>lenPath</code> is the length of the leading <code>"/view/"</code> The <code>Path</code> is re-sliced with <code>[len("/view/"):]</code> to drop
component of the request path. the leading <code>"/view/"</code> component of the request path.
The <code>Path</code> is re-sliced with <code>[lenPath:]</code> to drop the This is because the path will invariably begin with <code>"/view/"</code>,
first 6 characters of the string. This is because the path will invariably which is not part of the page's title.
begin with <code>"/view/"</code>, which is not part of the page's title.
</p> </p>
<p> <p>
...@@ -431,6 +428,11 @@ to its own function: ...@@ -431,6 +428,11 @@ to its own function:
</p> </p>
{{code "doc/articles/wiki/final-template.go" `/^func renderTemplate/` `/^}/`}} {{code "doc/articles/wiki/final-template.go" `/^func renderTemplate/` `/^}/`}}
<p>
And modify the handlers to use that function:
</p>
{{code "doc/articles/wiki/final-template.go" `/^func viewHandler/` `/^}/`}} {{code "doc/articles/wiki/final-template.go" `/^func viewHandler/` `/^}/`}}
{{code "doc/articles/wiki/final-template.go" `/^func editHandler/` `/^}/`}} {{code "doc/articles/wiki/final-template.go" `/^func editHandler/` `/^}/`}}
...@@ -573,10 +575,11 @@ this, we can write a function to validate the title with a regular expression. ...@@ -573,10 +575,11 @@ this, we can write a function to validate the title with a regular expression.
<p> <p>
First, add <code>"regexp"</code> to the <code>import</code> list. First, add <code>"regexp"</code> to the <code>import</code> list.
Then we can create a global variable to store our validation regexp: Then we can create a global variable to store our validation
expression:
</p> </p>
{{code "doc/articles/wiki/final-noclosure.go" `/^var titleValidator/`}} {{code "doc/articles/wiki/final-noclosure.go" `/^var validPath/`}}
<p> <p>
The function <code>regexp.MustCompile</code> will parse and compile the The function <code>regexp.MustCompile</code> will parse and compile the
...@@ -587,9 +590,8 @@ an <code>error</code> as a second parameter. ...@@ -587,9 +590,8 @@ an <code>error</code> as a second parameter.
</p> </p>
<p> <p>
Now, let's write a function, <code>getTitle</code>, that extracts the title Now, let's write a function that uses the <code>validPath</code>
string from the request URL, and tests it against our expression to validate path and extract the page title:
<code>TitleValidator</code> expression:
</p> </p>
{{code "doc/articles/wiki/final-noclosure.go" `/func getTitle/` `/^}/`}} {{code "doc/articles/wiki/final-noclosure.go" `/func getTitle/` `/^}/`}}
......
...@@ -29,16 +29,14 @@ func loadPage(title string) (*Page, error) { ...@@ -29,16 +29,14 @@ func loadPage(title string) (*Page, error) {
return &Page{Title: title, Body: body}, nil return &Page{Title: title, Body: body}, nil
} }
const lenPath = len("/view/")
func viewHandler(w http.ResponseWriter, r *http.Request) { func viewHandler(w http.ResponseWriter, r *http.Request) {
title := r.URL.Path[lenPath:] title := r.URL.Path[len("/view/"):]
p, _ := loadPage(title) p, _ := loadPage(title)
fmt.Fprintf(w, "<h1>%s</h1><div>%s</div>", p.Title, p.Body) fmt.Fprintf(w, "<h1>%s</h1><div>%s</div>", p.Title, p.Body)
} }
func editHandler(w http.ResponseWriter, r *http.Request) { func editHandler(w http.ResponseWriter, r *http.Request) {
title := r.URL.Path[lenPath:] title := r.URL.Path[len("/edit/"):]
p, err := loadPage(title) p, err := loadPage(title)
if err != nil { if err != nil {
p = &Page{Title: title} p = &Page{Title: title}
......
...@@ -29,10 +29,8 @@ func loadPage(title string) (*Page, error) { ...@@ -29,10 +29,8 @@ func loadPage(title string) (*Page, error) {
return &Page{Title: title, Body: body}, nil return &Page{Title: title, Body: body}, nil
} }
const lenPath = len("/view/")
func viewHandler(w http.ResponseWriter, r *http.Request) { func viewHandler(w http.ResponseWriter, r *http.Request) {
title := r.URL.Path[lenPath:] title := r.URL.Path[len("/view/"):]
p, _ := loadPage(title) p, _ := loadPage(title)
fmt.Fprintf(w, "<h1>%s</h1><div>%s</div>", p.Title, p.Body) fmt.Fprintf(w, "<h1>%s</h1><div>%s</div>", p.Title, p.Body)
} }
......
...@@ -29,15 +29,13 @@ func loadPage(title string) (*Page, error) { ...@@ -29,15 +29,13 @@ func loadPage(title string) (*Page, error) {
return &Page{Title: title, Body: body}, nil return &Page{Title: title, Body: body}, nil
} }
const lenPath = len("/view/")
func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) { func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) {
t, _ := template.ParseFiles(tmpl + ".html") t, _ := template.ParseFiles(tmpl + ".html")
t.Execute(w, p) t.Execute(w, p)
} }
func viewHandler(w http.ResponseWriter, r *http.Request) { func viewHandler(w http.ResponseWriter, r *http.Request) {
title := r.URL.Path[lenPath:] title := r.URL.Path[len("/view/"):]
p, err := loadPage(title) p, err := loadPage(title)
if err != nil { if err != nil {
http.Redirect(w, r, "/edit/"+title, http.StatusFound) http.Redirect(w, r, "/edit/"+title, http.StatusFound)
...@@ -47,7 +45,7 @@ func viewHandler(w http.ResponseWriter, r *http.Request) { ...@@ -47,7 +45,7 @@ func viewHandler(w http.ResponseWriter, r *http.Request) {
} }
func editHandler(w http.ResponseWriter, r *http.Request) { func editHandler(w http.ResponseWriter, r *http.Request) {
title := r.URL.Path[lenPath:] title := r.URL.Path[len("/edit/"):]
p, err := loadPage(title) p, err := loadPage(title)
if err != nil { if err != nil {
p = &Page{Title: title} p = &Page{Title: title}
...@@ -56,7 +54,7 @@ func editHandler(w http.ResponseWriter, r *http.Request) { ...@@ -56,7 +54,7 @@ func editHandler(w http.ResponseWriter, r *http.Request) {
} }
func saveHandler(w http.ResponseWriter, r *http.Request) { func saveHandler(w http.ResponseWriter, r *http.Request) {
title := r.URL.Path[lenPath:] title := r.URL.Path[len("/save/"):]
body := r.FormValue("body") body := r.FormValue("body")
p := &Page{Title: title, Body: []byte(body)} p := &Page{Title: title, Body: []byte(body)}
err := p.save() err := p.save()
......
...@@ -29,21 +29,19 @@ func loadPage(title string) (*Page, error) { ...@@ -29,21 +29,19 @@ func loadPage(title string) (*Page, error) {
return &Page{Title: title, Body: body}, nil return &Page{Title: title, Body: body}, nil
} }
const lenPath = len("/view/")
func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) { func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) {
t, _ := template.ParseFiles(tmpl + ".html") t, _ := template.ParseFiles(tmpl + ".html")
t.Execute(w, p) t.Execute(w, p)
} }
func viewHandler(w http.ResponseWriter, r *http.Request) { func viewHandler(w http.ResponseWriter, r *http.Request) {
title := r.URL.Path[lenPath:] title := r.URL.Path[len("/view/"):]
p, _ := loadPage(title) p, _ := loadPage(title)
renderTemplate(w, "view", p) renderTemplate(w, "view", p)
} }
func editHandler(w http.ResponseWriter, r *http.Request) { func editHandler(w http.ResponseWriter, r *http.Request) {
title := r.URL.Path[lenPath:] title := r.URL.Path[len("/edit/"):]
p, err := loadPage(title) p, err := loadPage(title)
if err != nil { if err != nil {
p = &Page{Title: title} p = &Page{Title: title}
......
// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"bytes"
"flag"
"go/ast"
"go/parser"
"go/printer"
"go/token"
"log"
"os"
"text/template"
)
var (
srcFn = flag.String("src", "", "source filename")
getName = flag.String("name", "", "func/type name to output")
html = flag.Bool("html", true, "output HTML")
showPkg = flag.Bool("pkg", false, "show package in output")
)
func main() {
// handle input
flag.Parse()
if *srcFn == "" || *getName == "" {
flag.Usage()
os.Exit(2)
}
// load file
fs := token.NewFileSet()
file, err := parser.ParseFile(fs, *srcFn, nil, 0)
if err != nil {
log.Fatal(err)
}
// create filter
filter := func(name string) bool {
return name == *getName
}
// filter
if !ast.FilterFile(file, filter) {
os.Exit(1)
}
// print the AST
var b bytes.Buffer
printer.Fprint(&b, fs, file)
// drop package declaration
if !*showPkg {
for {
c, err := b.ReadByte()
if c == '\n' || err != nil {
break
}
}
}
// drop leading newlines
for {
b, err := b.ReadByte()
if err != nil {
break
}
if b != '\n' {
os.Stdout.Write([]byte{b})
break
}
}
// output
if *html {
template.HTMLEscape(os.Stdout, b.Bytes())
} else {
b.WriteTo(os.Stdout)
}
}
...@@ -7,10 +7,17 @@ set -e ...@@ -7,10 +7,17 @@ set -e
wiki_pid= wiki_pid=
cleanup() { cleanup() {
kill $wiki_pid kill $wiki_pid
rm -f test_*.out Test.txt final-test.bin final-test.go rm -f test_*.out Test.txt final-test.bin final-test.go a.out get.bin
} }
trap cleanup 0 INT trap cleanup 0 INT
# If called with -all, check that all code snippets compile.
if [ "$1" == "-all" ]; then
for fn in *.go; do
go build -o a.out $fn
done
fi
go build -o get.bin get.go go build -o get.bin get.go
addr=$(./get.bin -addr) addr=$(./get.bin -addr)
sed s/:8080/$addr/ < final.go > final-test.go sed s/:8080/$addr/ < final.go > final-test.go
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment