From 7048d507ce1db4afd2af4aa82a6be51edcd3d7f2 Mon Sep 17 00:00:00 2001 From: Drew Bednar Date: Sun, 23 Jun 2024 09:06:02 -0400 Subject: [PATCH] Finished tutorial --- go-web-app/.gitignore | 3 +- go-web-app/gowiki/TestPage.txt | 2 +- go-web-app/gowiki/test.txt | 1 - go-web-app/gowiki/wiki.go | 83 ++++++++++++++++++++++++++++------ 4 files changed, 72 insertions(+), 17 deletions(-) diff --git a/go-web-app/.gitignore b/go-web-app/.gitignore index c4ad3b3..bcc6ba6 100644 --- a/go-web-app/.gitignore +++ b/go-web-app/.gitignore @@ -1 +1,2 @@ -gowiki/wiki \ No newline at end of file +gowiki/wiki +gowiki/*.txt \ No newline at end of file diff --git a/go-web-app/gowiki/TestPage.txt b/go-web-app/gowiki/TestPage.txt index 95b6a38..a5331a9 100644 --- a/go-web-app/gowiki/TestPage.txt +++ b/go-web-app/gowiki/TestPage.txt @@ -1 +1 @@ -This is a test page. \ No newline at end of file +This is my fixed test page \ No newline at end of file diff --git a/go-web-app/gowiki/test.txt b/go-web-app/gowiki/test.txt index 9fc0ab5..e69de29 100644 --- a/go-web-app/gowiki/test.txt +++ b/go-web-app/gowiki/test.txt @@ -1 +0,0 @@ -This is a page \ No newline at end of file diff --git a/go-web-app/gowiki/wiki.go b/go-web-app/gowiki/wiki.go index c8d752e..ad269b3 100644 --- a/go-web-app/gowiki/wiki.go +++ b/go-web-app/gowiki/wiki.go @@ -5,8 +5,15 @@ import ( "log" "net/http" "os" + "regexp" ) +// Template caching +var templates = template.Must(template.ParseFiles("edit.html", "view.html")) + +// Validation to prevent abitrary paths +var validPath = regexp.MustCompile("^/(edit|save|view)/([a-zA-Z0-9]+)$") + // A wiki consists of a series of interconnected pages, each of which has a title and a body type Page struct { Title string @@ -20,6 +27,17 @@ func (p *Page) save() error { return os.WriteFile(filename, p.Body, 0600) } +// Not neccessary after makeHandler implemented this. + +// 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 +// } + // loadPage loads a Page from disk. // It takes the title of the page as an argument, reads the corresponding // file, and returns a pointer to a Page struct containing the title and body. @@ -35,20 +53,41 @@ func loadPage(title string) (*Page, error) { } func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) { - t, err := template.ParseFiles(tmpl + ".html") + // In efficient. No cacheing + // t, err := template.ParseFiles(tmpl + ".html") + // if err != nil { + // http.Error(w, err.Error(), http.StatusInternalServerError) + // return + // } + // err = t.Execute(w, p) + + //With caching + err := templates.ExecuteTemplate(w, tmpl+".html", p) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) - return } - err = t.Execute(w, p) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) +} + +// Wraps a handler function, includes validation checks on titles +func makeHandler(fn func(http.ResponseWriter, *http.Request, string)) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + m := validPath.FindStringSubmatch(r.URL.Path) + if m == nil { + http.NotFound(w, r) + return + } + fn(w, r, m[2]) } } -func viewHandler(w http.ResponseWriter, r *http.Request) { +func viewHandler(w http.ResponseWriter, r *http.Request, title string) { // html := "

%s

%s
" - title := r.URL.Path[len("/view/"):] + // title := r.URL.Path[len("/view/"):] + // Not neccesary after makeHandler was implemented + // title, err := getTitle(w, r) + // if err != nil { + // return + // } page, err := loadPage(title) // fmt.Fprintf(w, html, page.Title, page.Body) // t, _ := template.ParseFiles("view.html") @@ -62,8 +101,13 @@ func viewHandler(w http.ResponseWriter, r *http.Request) { renderTemplate(w, "view", page) } -func editHandler(w http.ResponseWriter, r *http.Request) { - title := r.URL.Path[len("/edit/"):] +func editHandler(w http.ResponseWriter, r *http.Request, title string) { + // title := r.URL.Path[len("/edit/"):] + // Not neccesary after makeHandler was implemented + // title, err := getTitle(w, r) + // if err != nil { + // return + // } page, err := loadPage(title) if err != nil { page = &Page{Title: title} @@ -82,11 +126,17 @@ func editHandler(w http.ResponseWriter, r *http.Request) { renderTemplate(w, "edit", page) } -func saveHandler(w http.ResponseWriter, r *http.Request) { - title := r.URL.Path[len("/save/"):] +func saveHandler(w http.ResponseWriter, r *http.Request, title string) { + // title := r.URL.Path[len("/save/"):] + // Not neccesary after makeHandler was implemented + // 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 @@ -95,9 +145,14 @@ func saveHandler(w http.ResponseWriter, r *http.Request) { } func main() { - http.HandleFunc("/view/", viewHandler) - http.HandleFunc("/edit/", editHandler) - http.HandleFunc("/save/", saveHandler) + log.Printf("%s\n", templates.DefinedTemplates()) + // Using function literal and closures to handle not found + // http.HandleFunc("/view/", viewHandler) + // http.HandleFunc("/edit/", editHandler) + // http.HandleFunc("/save/", saveHandler) + http.HandleFunc("/view/", makeHandler(viewHandler)) + http.HandleFunc("/edit/", makeHandler(editHandler)) + http.HandleFunc("/save/", makeHandler(saveHandler)) log.Println("Serving on: http://0.0.0.0:5001") log.Fatal(http.ListenAndServe(":5001", nil))