|
|
@ -37,35 +37,31 @@ func (t *Templates) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddy |
|
|
|
buf.Reset() |
|
|
|
defer bufPool.Put(buf) |
|
|
|
|
|
|
|
wb := &responseBuffer{ |
|
|
|
ResponseWriterWrapper: &caddyhttp.ResponseWriterWrapper{ResponseWriter: w}, |
|
|
|
buf: buf, |
|
|
|
} |
|
|
|
rr := caddyhttp.NewResponseRecorder(w, buf) |
|
|
|
|
|
|
|
err := next.ServeHTTP(wb, r) |
|
|
|
err := next.ServeHTTP(rr, r) |
|
|
|
if err != nil { |
|
|
|
return err |
|
|
|
} |
|
|
|
|
|
|
|
err = t.executeTemplate(wb, r) |
|
|
|
err = t.executeTemplate(rr, r) |
|
|
|
if err != nil { |
|
|
|
return err |
|
|
|
} |
|
|
|
|
|
|
|
w.Header().Set("Content-Length", strconv.Itoa(wb.buf.Len())) |
|
|
|
w.Header().Set("Content-Length", strconv.Itoa(buf.Len())) |
|
|
|
w.Header().Del("Accept-Ranges") // we don't know ranges for dynamically-created content
|
|
|
|
w.Header().Del("Etag") // don't know a way to quickly generate etag for dynamic content
|
|
|
|
w.Header().Del("Last-Modified") // useless for dynamic content since it's always changing
|
|
|
|
|
|
|
|
w.WriteHeader(wb.statusCode) |
|
|
|
io.Copy(w, wb.buf) |
|
|
|
w.WriteHeader(rr.Status()) |
|
|
|
io.Copy(w, buf) |
|
|
|
|
|
|
|
return nil |
|
|
|
} |
|
|
|
|
|
|
|
// executeTemplate executes the template contianed
|
|
|
|
// in wb.buf and replaces it with the results.
|
|
|
|
func (t *Templates) executeTemplate(wb *responseBuffer, r *http.Request) error { |
|
|
|
// executeTemplate executes the template contained in wb.buf and replaces it with the results.
|
|
|
|
func (t *Templates) executeTemplate(rr caddyhttp.ResponseRecorder, r *http.Request) error { |
|
|
|
var fs http.FileSystem |
|
|
|
if t.FileRoot != "" { |
|
|
|
fs = http.Dir(t.FileRoot) |
|
|
@ -74,11 +70,11 @@ func (t *Templates) executeTemplate(wb *responseBuffer, r *http.Request) error { |
|
|
|
ctx := &templateContext{ |
|
|
|
Root: fs, |
|
|
|
Req: r, |
|
|
|
RespHeader: tplWrappedHeader{wb.Header()}, |
|
|
|
RespHeader: tplWrappedHeader{rr.Header()}, |
|
|
|
config: t, |
|
|
|
} |
|
|
|
|
|
|
|
err := ctx.executeTemplateInBuffer(r.URL.Path, wb.buf) |
|
|
|
err := ctx.executeTemplateInBuffer(r.URL.Path, rr.Buffer()) |
|
|
|
if err != nil { |
|
|
|
return caddyhttp.Error(http.StatusInternalServerError, err) |
|
|
|
} |
|
|
@ -86,29 +82,8 @@ func (t *Templates) executeTemplate(wb *responseBuffer, r *http.Request) error { |
|
|
|
return nil |
|
|
|
} |
|
|
|
|
|
|
|
// responseBuffer buffers the response so that it can be
|
|
|
|
// executed as a template.
|
|
|
|
type responseBuffer struct { |
|
|
|
*caddyhttp.ResponseWriterWrapper |
|
|
|
wroteHeader bool |
|
|
|
statusCode int |
|
|
|
buf *bytes.Buffer |
|
|
|
} |
|
|
|
|
|
|
|
func (rb *responseBuffer) WriteHeader(statusCode int) { |
|
|
|
if rb.wroteHeader { |
|
|
|
return |
|
|
|
} |
|
|
|
rb.statusCode = statusCode |
|
|
|
rb.wroteHeader = true |
|
|
|
} |
|
|
|
|
|
|
|
func (rb *responseBuffer) Write(data []byte) (int, error) { |
|
|
|
rb.WriteHeader(http.StatusOK) |
|
|
|
return rb.buf.Write(data) |
|
|
|
} |
|
|
|
|
|
|
|
// virtualResponseWriter is used in virtualized HTTP requests.
|
|
|
|
// virtualResponseWriter is used in virtualized HTTP requests
|
|
|
|
// that templates may execute.
|
|
|
|
type virtualResponseWriter struct { |
|
|
|
status int |
|
|
|
header http.Header |
|
|
@ -131,5 +106,4 @@ func (vrw *virtualResponseWriter) Write(data []byte) (int, error) { |
|
|
|
var ( |
|
|
|
_ caddy.Validator = (*Templates)(nil) |
|
|
|
_ caddyhttp.MiddlewareHandler = (*Templates)(nil) |
|
|
|
_ caddyhttp.HTTPInterfaces = (*responseBuffer)(nil) |
|
|
|
) |
|
|
|