@@ -156,63 +156,20 @@ func (r *RenderTemplateResult) Apply(req *Request, resp *Response) {
156
156
// error pages distorted by HTML already written)
157
157
if chunked && ! DevMode {
158
158
resp .WriteHeader (http .StatusOK , "text/html; charset=utf-8" )
159
- r .render (req , resp , out )
159
+ if err := r .renderOutput (out ); err != nil {
160
+ r .renderError (err ,req ,resp )
161
+ }
160
162
return
161
163
}
162
164
163
165
// Render the template into a temporary buffer, to see if there was an error
164
166
// rendering the template. If not, then copy it into the response buffer.
165
167
// Otherwise, template render errors may result in unpredictable HTML (and
166
168
// would carry a 200 status code)
167
- var b bytes.Buffer
168
- r .render (req , resp , & b )
169
-
170
- // Trimming the HTML will do the following:
171
- // * Remove all leading & trailing whitespace on every line
172
- // * Remove all empty lines
173
- // * Attempt to keep formatting inside <pre></pre> tags
174
- //
175
- // This is safe unless white-space: pre; is used in css for formatting.
176
- // Since there is no way to detect that, you will have to keep trimming off in these cases.
177
- if Config .BoolDefault ("results.trim.html" , false ) {
178
- var b2 bytes.Buffer
179
- // Allocate length of original buffer, so we can write everything without allocating again
180
- b2 .Grow (b .Len ())
181
- insidePre := false
182
- for {
183
- text , err := b .ReadString ('\n' )
184
- // Convert to lower case for finding <pre> tags.
185
- tl := strings .ToLower (text )
186
- if strings .Contains (tl , "<pre>" ) {
187
- insidePre = true
188
- }
189
- // Trim if not inside a <pre> statement
190
- if ! insidePre {
191
- // Cut trailing/leading whitespace
192
- text = strings .Trim (text , " \t \r \n " )
193
- if len (text ) > 0 {
194
- if _ , err = b2 .WriteString (text ); err != nil {
195
- resultsLog .Error ("Apply: " , "error" , err )
196
- }
197
- if _ , err = b2 .WriteString ("\n " ); err != nil {
198
- resultsLog .Error ("Apply: " , "error" , err )
199
- }
200
- }
201
- } else {
202
- if _ , err = b2 .WriteString (text ); err != nil {
203
- resultsLog .Error ("Apply: " , "error" , err )
204
- }
205
- }
206
- if strings .Contains (tl , "</pre>" ) {
207
- insidePre = false
208
- }
209
- // We are finished
210
- if err != nil {
211
- break
212
- }
213
- }
214
- // Replace the buffer
215
- b = b2
169
+ b , err := r .ToBytes ()
170
+ if err != nil {
171
+ r .renderError (err ,req ,resp )
172
+ return
216
173
}
217
174
218
175
if ! chunked {
@@ -224,12 +181,85 @@ func (r *RenderTemplateResult) Apply(req *Request, resp *Response) {
224
181
}
225
182
}
226
183
227
- func (r * RenderTemplateResult ) render (req * Request , resp * Response , wr io.Writer ) {
228
- err := r .Template .Render (wr , r .ViewArgs )
229
- if err == nil {
230
- return
184
+ // Return a byte array and or an error object if the template failed to render
185
+ func (r * RenderTemplateResult ) ToBytes () (b * bytes.Buffer ,err error ) {
186
+ defer func () {
187
+ if rerr := recover (); rerr != nil {
188
+ resultsLog .Error ("ApplyBytes: panic recovery" , "recover-error" , rerr )
189
+ err = fmt .Errorf ("Template Execution Panic in %s:\n %s" , r .Template .Name (), rerr )
190
+ }
191
+ }()
192
+ b = & bytes.Buffer {}
193
+ if err = r .renderOutput (b ); err == nil {
194
+ if Config .BoolDefault ("results.trim.html" , false ) {
195
+ b = r .compressHtml (b )
196
+ }
197
+ }
198
+ return
199
+ }
200
+
201
+ // Output the template to the writer, catch any panics and return as an error
202
+ func (r * RenderTemplateResult ) renderOutput (wr io.Writer ) (err error ) {
203
+ defer func () {
204
+ if rerr := recover (); rerr != nil {
205
+ resultsLog .Error ("ApplyBytes: panic recovery" , "recover-error" , rerr )
206
+ err = fmt .Errorf ("Template Execution Panic in %s:\n %s" , r .Template .Name (), rerr )
207
+ }
208
+ }()
209
+ err = r .Template .Render (wr , r .ViewArgs )
210
+ return
211
+ }
212
+
213
+ // Trimming the HTML will do the following:
214
+ // * Remove all leading & trailing whitespace on every line
215
+ // * Remove all empty lines
216
+ // * Attempt to keep formatting inside <pre></pre> tags
217
+ //
218
+ // This is safe unless white-space: pre; is used in css for formatting.
219
+ // Since there is no way to detect that, you will have to keep trimming off in these cases.
220
+ func (r * RenderTemplateResult ) compressHtml (b * bytes.Buffer ) (b2 * bytes.Buffer ) {
221
+
222
+ // Allocate length of original buffer, so we can write everything without allocating again
223
+ b2 .Grow (b .Len ())
224
+ insidePre := false
225
+ for {
226
+ text , err := b .ReadString ('\n' )
227
+ // Convert to lower case for finding <pre> tags.
228
+ tl := strings .ToLower (text )
229
+ if strings .Contains (tl , "<pre>" ) {
230
+ insidePre = true
231
+ }
232
+ // Trim if not inside a <pre> statement
233
+ if ! insidePre {
234
+ // Cut trailing/leading whitespace
235
+ text = strings .Trim (text , " \t \r \n " )
236
+ if len (text ) > 0 {
237
+ if _ , err = b2 .WriteString (text ); err != nil {
238
+ resultsLog .Error ("Apply: " , "error" , err )
239
+ }
240
+ if _ , err = b2 .WriteString ("\n " ); err != nil {
241
+ resultsLog .Error ("Apply: " , "error" , err )
242
+ }
243
+ }
244
+ } else {
245
+ if _ , err = b2 .WriteString (text ); err != nil {
246
+ resultsLog .Error ("Apply: " , "error" , err )
247
+ }
248
+ }
249
+ if strings .Contains (tl , "</pre>" ) {
250
+ insidePre = false
251
+ }
252
+ // We are finished
253
+ if err != nil {
254
+ break
255
+ }
231
256
}
232
257
258
+ return
259
+ }
260
+
261
+ // Render the error in the response
262
+ func (r * RenderTemplateResult ) renderError (err error ,req * Request , resp * Response ) {
233
263
var templateContent []string
234
264
templateName , line , description := ParseTemplateError (err )
235
265
if templateName == "" {
0 commit comments