github.com/hbdrawn/golang@v0.0.0-20141214014649-6b835209aba2/doc/articles/wiki/final.go (about) 1 // Copyright 2010 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package main 6 7 import ( 8 "flag" 9 "html/template" 10 "io/ioutil" 11 "log" 12 "net" 13 "net/http" 14 "regexp" 15 ) 16 17 var ( 18 addr = flag.Bool("addr", false, "find open address and print to final-port.txt") 19 ) 20 21 type Page struct { 22 Title string 23 Body []byte 24 } 25 26 func (p *Page) save() error { 27 filename := p.Title + ".txt" 28 return ioutil.WriteFile(filename, p.Body, 0600) 29 } 30 31 func loadPage(title string) (*Page, error) { 32 filename := title + ".txt" 33 body, err := ioutil.ReadFile(filename) 34 if err != nil { 35 return nil, err 36 } 37 return &Page{Title: title, Body: body}, nil 38 } 39 40 func viewHandler(w http.ResponseWriter, r *http.Request, title string) { 41 p, err := loadPage(title) 42 if err != nil { 43 http.Redirect(w, r, "/edit/"+title, http.StatusFound) 44 return 45 } 46 renderTemplate(w, "view", p) 47 } 48 49 func editHandler(w http.ResponseWriter, r *http.Request, title string) { 50 p, err := loadPage(title) 51 if err != nil { 52 p = &Page{Title: title} 53 } 54 renderTemplate(w, "edit", p) 55 } 56 57 func saveHandler(w http.ResponseWriter, r *http.Request, title string) { 58 body := r.FormValue("body") 59 p := &Page{Title: title, Body: []byte(body)} 60 err := p.save() 61 if err != nil { 62 http.Error(w, err.Error(), http.StatusInternalServerError) 63 return 64 } 65 http.Redirect(w, r, "/view/"+title, http.StatusFound) 66 } 67 68 var templates = template.Must(template.ParseFiles("edit.html", "view.html")) 69 70 func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) { 71 err := templates.ExecuteTemplate(w, tmpl+".html", p) 72 if err != nil { 73 http.Error(w, err.Error(), http.StatusInternalServerError) 74 } 75 } 76 77 var validPath = regexp.MustCompile("^/(edit|save|view)/([a-zA-Z0-9]+)$") 78 79 func makeHandler(fn func(http.ResponseWriter, *http.Request, string)) http.HandlerFunc { 80 return func(w http.ResponseWriter, r *http.Request) { 81 m := validPath.FindStringSubmatch(r.URL.Path) 82 if m == nil { 83 http.NotFound(w, r) 84 return 85 } 86 fn(w, r, m[2]) 87 } 88 } 89 90 func main() { 91 flag.Parse() 92 http.HandleFunc("/view/", makeHandler(viewHandler)) 93 http.HandleFunc("/edit/", makeHandler(editHandler)) 94 http.HandleFunc("/save/", makeHandler(saveHandler)) 95 96 if *addr { 97 l, err := net.Listen("tcp", "127.0.0.1:0") 98 if err != nil { 99 log.Fatal(err) 100 } 101 err = ioutil.WriteFile("final-port.txt", []byte(l.Addr().String()), 0644) 102 if err != nil { 103 log.Fatal(err) 104 } 105 s := &http.Server{} 106 s.Serve(l) 107 return 108 } 109 110 http.ListenAndServe(":8080", nil) 111 }