1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
|
package page
import (
"bytes"
"net/http"
"path/filepath"
"strings"
)
func getURLPath(r *http.Request) string {
u := r.URL.Path
if u == "/" {
u = "/index"
}
return u
}
// Render5xx is automatically called if any render fails,
// additionally you can call it for your own uses. It will
// try to use the 5xx template but will fall back to a plain
// page if that fails.
func Render5xx(w http.ResponseWriter, r *http.Request,
vars map[string]interface{}, statusCode int) {
u := getURLPath(r)
Logger.Printf("%s %s %d %s",
r.RemoteAddr,
r.Method,
statusCode,
u)
p := NewPage(TemplateDirectory + "/5xx")
buf := &bytes.Buffer{}
err := p.Render(buf)
if err != nil {
Logger.Printf("%s %s path: %s while trying 5xx: %s",
r.RemoteAddr,
r.Method,
u,
err)
http.Error(w, "Internal server error", statusCode)
return
}
w.WriteHeader(statusCode)
_, _ = w.Write(buf.Bytes())
Logger.Printf("%s %s %d %s", r.RemoteAddr, r.Method, statusCode, u)
}
// Render4xx is mostly used to render a 404 page, pulls from 404 template.
// automatically called by Render if a page is missing.
func Render4xx(w http.ResponseWriter, r *http.Request,
vars map[string]interface{}, statusCode int) {
u := getURLPath(r)
Logger.Printf("%s %s %d %s",
r.RemoteAddr,
r.Method,
statusCode,
u)
p := NewPage(TemplateDirectory + "/4xx")
buf := &bytes.Buffer{}
err := p.Render(buf)
if err != nil {
Logger.Printf("%s %s path: %s while trying 404: %s",
r.RemoteAddr,
r.Method,
u,
err)
Render5xx(w, r, vars, http.StatusInternalServerError)
return
}
w.WriteHeader(statusCode)
_, err = w.Write(buf.Bytes())
if err != nil {
Render5xx(w, r, nil, http.StatusInternalServerError)
return
}
Logger.Printf("%s %s %d %s", r.RemoteAddr, r.Method, statusCode, u)
}
// Render is a lower level option, allowing you to specify local
// variables and the status code in which to return.
func Render(w http.ResponseWriter, r *http.Request,
path string, vars map[string]interface{}, statusCode int) {
u := getURLPath(r)
u = filepath.Join(".", u)
// Sepcifically use the specified path for the page
p := NewPage(path)
if vars != nil {
p.Vars = vars
}
buf := &bytes.Buffer{}
err := p.Render(buf)
if err != nil {
if strings.HasSuffix(err.Error(), "no such file or directory") {
Render4xx(w, r, vars, http.StatusNotFound)
return
}
Logger.Printf("%s %s path: %s rendering encountered: %s",
r.RemoteAddr,
r.Method,
u,
err)
Render5xx(w, r, vars, http.StatusInternalServerError)
return
}
w.WriteHeader(statusCode)
_, err = w.Write(buf.Bytes())
if err != nil {
Logger.Printf("%s %s %d %s: while writing buf: %s",
r.RemoteAddr,
r.Method,
statusCode,
u,
err)
Render5xx(w, r, nil, http.StatusInternalServerError)
return
}
Logger.Printf("%s %s %d %s", r.RemoteAddr, r.Method, statusCode, u)
}
// RenderWithVars allows you to specify a specific page and whether or not
// you wish to override vars. If left nil they will not be overridden.
// Also see RenderForPath if you don't need to override them.
func RenderWithVars(w http.ResponseWriter, r *http.Request,
path string, vars map[string]interface{}) {
Render(w, r, path, vars, http.StatusOK)
}
// RenderForPath takes the path to a page and finish up the rendering
// Allowing you to place logic on what page is rendered by your handlers.
func RenderForPath(w http.ResponseWriter, r *http.Request, path string) {
RenderWithVars(w, r, path, nil)
}
|