Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(291)

Delta Between Two Patch Sets: doc/codelab/wiki/index.html

Issue 5307066: code review 5307066: non-pkg: gofix -r error (Closed)
Left Patch Set: Created 13 years, 4 months ago
Right Patch Set: diff -r 586479483dd6 https://go.googlecode.com/hg/ Created 13 years, 4 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Right: Side by side diff | Download
« no previous file with change/comment | « doc/codelab/wiki/get.go ('k') | doc/codelab/wiki/notemplate.go » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
(no file at all)
1 <!-- Codelab: Writing Web Applications --> 1 <!-- Codelab: Writing Web Applications -->
2 <h2>Introduction</h2> 2 <h2>Introduction</h2>
3 3
4 <p> 4 <p>
5 Covered in this codelab: 5 Covered in this codelab:
6 </p> 6 </p>
7 <ul> 7 <ul>
8 <li>Creating a data structure with load and save methods</li> 8 <li>Creating a data structure with load and save methods</li>
9 <li>Using the <code>http</code> package to build web applications 9 <li>Using the <code>http</code> package to build web applications
10 <li>Using the <code>template</code> package to process HTML templates</li> 10 <li>Using the <code>template</code> package to process HTML templates</li>
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
91 libraries we will use, as you'll see below. 91 libraries we will use, as you'll see below.
92 </p> 92 </p>
93 93
94 <p> 94 <p>
95 The <code>Page</code> struct describes how page data will be stored in memory.· 95 The <code>Page</code> struct describes how page data will be stored in memory.·
96 But what about persistent storage? We can address that by creating a· 96 But what about persistent storage? We can address that by creating a·
97 <code>save</code> method on <code>Page</code>: 97 <code>save</code> method on <code>Page</code>:
98 </p> 98 </p>
99 99
100 <pre> 100 <pre>
101 func (p *Page) save() os.Error { 101 func (p *Page) save() error {
102 filename := p.Title + &#34;.txt&#34; 102 filename := p.Title + &#34;.txt&#34;
103 return ioutil.WriteFile(filename, p.Body, 0600) 103 return ioutil.WriteFile(filename, p.Body, 0600)
104 } 104 }
105 </pre> 105 </pre>
106 106
107 <p> 107 <p>
108 This method's signature reads: "This is a method named <code>save</code> that 108 This method's signature reads: "This is a method named <code>save</code> that
109 takes as its receiver <code>p</code>, a pointer to <code>Page</code> . It takes 109 takes as its receiver <code>p</code>, a pointer to <code>Page</code> . It takes
110 no parameters, and returns a value of type <code>os.Error</code>."· 110 no parameters, and returns a value of type <code>os.Error</code>."·
111 </p> 111 </p>
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
158 error return value (in essence, assigning the value to nothing).· 158 error return value (in essence, assigning the value to nothing).·
159 </p> 159 </p>
160 160
161 <p> 161 <p>
162 But what happens if <code>ReadFile</code> encounters an error? For example, 162 But what happens if <code>ReadFile</code> encounters an error? For example,
163 the file might not exist. We should not ignore such errors. Let's modify the 163 the file might not exist. We should not ignore such errors. Let's modify the
164 function to return <code>*Page</code> and <code>os.Error</code>. 164 function to return <code>*Page</code> and <code>os.Error</code>.
165 </p> 165 </p>
166 166
167 <pre> 167 <pre>
168 func loadPage(title string) (*Page, os.Error) { 168 func loadPage(title string) (*Page, error) {
169 filename := title + &#34;.txt&#34; 169 filename := title + &#34;.txt&#34;
170 body, err := ioutil.ReadFile(filename) 170 body, err := ioutil.ReadFile(filename)
171 if err != nil { 171 if err != nil {
172 return nil, err 172 return nil, err
173 } 173 }
174 return &amp;Page{Title: title, Body: body}, nil 174 return &amp;Page{Title: title, Body: body}, nil
175 } 175 }
176 </pre> 176 </pre>
177 177
178 <p> 178 <p>
(...skipping 459 matching lines...) Expand 10 before | Expand all | Expand 10 after
638 </p> 638 </p>
639 639
640 <p> 640 <p>
641 First, let's handle the errors in <code>renderTemplate</code>: 641 First, let's handle the errors in <code>renderTemplate</code>:
642 </p> 642 </p>
643 643
644 <pre> 644 <pre>
645 func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) { 645 func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) {
646 t, err := template.ParseFile(tmpl+&#34;.html&#34;, nil) 646 t, err := template.ParseFile(tmpl+&#34;.html&#34;, nil)
647 if err != nil { 647 if err != nil {
648 » » http.Error(w, err.String(), http.StatusInternalServerError) 648 » » http.Error(w, err.Error(), http.StatusInternalServerError)
649 return 649 return
650 } 650 }
651 err = t.Execute(w, p) 651 err = t.Execute(w, p)
652 if err != nil { 652 if err != nil {
653 » » http.Error(w, err.String(), http.StatusInternalServerError) 653 » » http.Error(w, err.Error(), http.StatusInternalServerError)
654 } 654 }
655 } 655 }
656 </pre> 656 </pre>
657 657
658 <p> 658 <p>
659 The <code>http.Error</code> function sends a specified HTTP response code· 659 The <code>http.Error</code> function sends a specified HTTP response code·
660 (in this case "Internal Server Error") and error message. 660 (in this case "Internal Server Error") and error message.
661 Already the decision to put this in a separate function is paying off. 661 Already the decision to put this in a separate function is paying off.
662 </p> 662 </p>
663 663
664 <p> 664 <p>
665 Now let's fix up <code>saveHandler</code>: 665 Now let's fix up <code>saveHandler</code>:
666 </p> 666 </p>
667 667
668 <pre> 668 <pre>
669 func saveHandler(w http.ResponseWriter, r *http.Request) { 669 func saveHandler(w http.ResponseWriter, r *http.Request) {
670 title, err := getTitle(w, r) 670 title, err := getTitle(w, r)
671 if err != nil { 671 if err != nil {
672 return 672 return
673 } 673 }
674 body := r.FormValue(&#34;body&#34;) 674 body := r.FormValue(&#34;body&#34;)
675 p := &amp;Page{Title: title, Body: []byte(body)} 675 p := &amp;Page{Title: title, Body: []byte(body)}
676 err = p.save() 676 err = p.save()
677 if err != nil { 677 if err != nil {
678 » » http.Error(w, err.String(), http.StatusInternalServerError) 678 » » http.Error(w, err.Error(), http.StatusInternalServerError)
679 return 679 return
680 } 680 }
681 http.Redirect(w, r, &#34;/view/&#34;+title, http.StatusFound) 681 http.Redirect(w, r, &#34;/view/&#34;+title, http.StatusFound)
682 } 682 }
683 </pre> 683 </pre>
684 684
685 <p> 685 <p>
686 Any errors that occur during <code>p.save()</code> will be reported· 686 Any errors that occur during <code>p.save()</code> will be reported·
687 to the user. 687 to the user.
688 </p> 688 </p>
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
734 734
735 <p> 735 <p>
736 We then modify our <code>renderTemplate</code> function to call· 736 We then modify our <code>renderTemplate</code> function to call·
737 the <code>Execute</code> method on the appropriate <code>Template</code> from· 737 the <code>Execute</code> method on the appropriate <code>Template</code> from·
738 <code>templates</code>: 738 <code>templates</code>:
739 739
740 <pre> 740 <pre>
741 func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) { 741 func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) {
742 err := templates[tmpl].Execute(w, p) 742 err := templates[tmpl].Execute(w, p)
743 if err != nil { 743 if err != nil {
744 » » http.Error(w, err.String(), http.StatusInternalServerError) 744 » » http.Error(w, err.Error(), http.StatusInternalServerError)
745 } 745 }
746 } 746 }
747 </pre> 747 </pre>
748 748
749 <h2>Validation</h2> 749 <h2>Validation</h2>
750 750
751 <p> 751 <p>
752 As you may have observed, this program has a serious security flaw: a user 752 As you may have observed, this program has a serious security flaw: a user
753 can supply an arbitrary path to be read/written on the server. To mitigate 753 can supply an arbitrary path to be read/written on the server. To mitigate
754 this, we can write a function to validate the title with a regular expression. 754 this, we can write a function to validate the title with a regular expression.
(...skipping 15 matching lines...) Expand all
770 panic if the expression compilation fails, while <code>Compile</code> returns 770 panic if the expression compilation fails, while <code>Compile</code> returns
771 an <code>os.Error</code> as a second parameter.· 771 an <code>os.Error</code> as a second parameter.·
772 </p> 772 </p>
773 773
774 <p> 774 <p>
775 Now, let's write a function that extracts the title string from the request· 775 Now, let's write a function that extracts the title string from the request·
776 URL, and tests it against our <code>TitleValidator</code> expression: 776 URL, and tests it against our <code>TitleValidator</code> expression:
777 </p> 777 </p>
778 778
779 <pre> 779 <pre>
780 func getTitle(w http.ResponseWriter, r *http.Request) (title string, err os.Erro r) { 780 func getTitle(w http.ResponseWriter, r *http.Request) (title string, err error) {
781 title = r.URL.Path[lenPath:] 781 title = r.URL.Path[lenPath:]
782 if !titleValidator.MatchString(title) { 782 if !titleValidator.MatchString(title) {
783 http.NotFound(w, r) 783 http.NotFound(w, r)
784 » » err = os.NewError(&#34;Invalid Page Title&#34;) 784 » » err = errors.New(&#34;Invalid Page Title&#34;)
785 } 785 }
786 return 786 return
787 } 787 }
788 </pre> 788 </pre>
789 789
790 <p> 790 <p>
791 If the title is valid, it will be returned along with a <code>nil</code> 791 If the title is valid, it will be returned along with a <code>nil</code>
792 error value. If the title is invalid, the function will write a· 792 error value. If the title is invalid, the function will write a·
793 "404 Not Found" error to the HTTP connection, and return an error to the· 793 "404 Not Found" error to the HTTP connection, and return an error to the·
794 handler.· 794 handler.·
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
826 826
827 func saveHandler(w http.ResponseWriter, r *http.Request) { 827 func saveHandler(w http.ResponseWriter, r *http.Request) {
828 title, err := getTitle(w, r) 828 title, err := getTitle(w, r)
829 if err != nil { 829 if err != nil {
830 return 830 return
831 } 831 }
832 body := r.FormValue(&#34;body&#34;) 832 body := r.FormValue(&#34;body&#34;)
833 p := &amp;Page{Title: title, Body: []byte(body)} 833 p := &amp;Page{Title: title, Body: []byte(body)}
834 err = p.save() 834 err = p.save()
835 if err != nil { 835 if err != nil {
836 » » http.Error(w, err.String(), http.StatusInternalServerError) 836 » » http.Error(w, err.Error(), http.StatusInternalServerError)
837 return 837 return
838 } 838 }
839 http.Redirect(w, r, &#34;/view/&#34;+title, http.StatusFound) 839 http.Redirect(w, r, &#34;/view/&#34;+title, http.StatusFound)
840 } 840 }
841 </pre> 841 </pre>
842 842
843 <h2>Introducing Function Literals and Closures</h2> 843 <h2>Introducing Function Literals and Closures</h2>
844 844
845 <p> 845 <p>
846 Catching the error condition in each handler introduces a lot of repeated code. 846 Catching the error condition in each handler introduces a lot of repeated code.
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
951 p = &amp;Page{Title: title} 951 p = &amp;Page{Title: title}
952 } 952 }
953 renderTemplate(w, &#34;edit&#34;, p) 953 renderTemplate(w, &#34;edit&#34;, p)
954 } 954 }
955 955
956 func saveHandler(w http.ResponseWriter, r *http.Request, title string) { 956 func saveHandler(w http.ResponseWriter, r *http.Request, title string) {
957 body := r.FormValue(&#34;body&#34;) 957 body := r.FormValue(&#34;body&#34;)
958 p := &amp;Page{Title: title, Body: []byte(body)} 958 p := &amp;Page{Title: title, Body: []byte(body)}
959 err := p.save() 959 err := p.save()
960 if err != nil { 960 if err != nil {
961 » » http.Error(w, err.String(), http.StatusInternalServerError) 961 » » http.Error(w, err.Error(), http.StatusInternalServerError)
962 return 962 return
963 } 963 }
964 http.Redirect(w, r, &#34;/view/&#34;+title, http.StatusFound) 964 http.Redirect(w, r, &#34;/view/&#34;+title, http.StatusFound)
965 } 965 }
966 </pre> 966 </pre>
967 967
968 <h2>Try it out!</h2> 968 <h2>Try it out!</h2>
969 969
970 <p> 970 <p>
971 <a href="final.go">Click here to view the final code listing.</a> 971 <a href="final.go">Click here to view the final code listing.</a>
(...skipping 26 matching lines...) Expand all
998 <li>Add a handler to make the web root redirect to· 998 <li>Add a handler to make the web root redirect to·
999 <code>/view/FrontPage</code>.</li> 999 <code>/view/FrontPage</code>.</li>
1000 <li>Spruce up the page templates by making them valid HTML and adding some 1000 <li>Spruce up the page templates by making them valid HTML and adding some
1001 CSS rules.</li> 1001 CSS rules.</li>
1002 <li>Implement inter-page linking by converting instances of· 1002 <li>Implement inter-page linking by converting instances of·
1003 <code>[PageName]</code> to <br> 1003 <code>[PageName]</code> to <br>
1004 <code>&lt;a href="/view/PageName"&gt;PageName&lt;/a&gt;</code>. 1004 <code>&lt;a href="/view/PageName"&gt;PageName&lt;/a&gt;</code>.
1005 (hint: you could use <code>regexp.ReplaceAllFunc</code> to do this) 1005 (hint: you could use <code>regexp.ReplaceAllFunc</code> to do this)
1006 </li> 1006 </li>
1007 </ul> 1007 </ul>
LEFTRIGHT

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b