Results
package revel
type Result interface {
Apply(req *Request, resp *Response)
}
type ErrorResult struct {
RenderArgs map[string]interface{}
Error error
}
func (r ErrorResult) Apply(req *Request, resp *Response) {
format := req.Format
status := resp.Status
if status == 0 {
status = http.StatusInternalServerError
}
contentType := ContentTypeByFilename("xxx." + format)
if contentType == DefaultFileContentType {
contentType = "text/plain"
}
var err error
templatePath := fmt.Sprintf("errors/%d.%s", status, format)
tmpl, err := MainTemplateLoader.Template(templatePath)
showPlaintext := func(err error) {
PlaintextErrorResult{fmt.Errorf("Server Error:\n%s\n\n"+
"Additionally, an error occurred when rendering the error page:\n%s",
r.Error, err)}.Apply(req, resp)
}
if tmpl == nil {
if err == nil {
err = fmt.Errorf("Couldn't find template %s", templatePath)
}
showPlaintext(err)
return
}
var revelError *Error
switch e := r.Error.(type) {
case *Error:
revelError = e
case error:
revelError = &Error{
Title: "Server Error",
Description: e.Error(),
}
}
if revelError == nil {
panic("no error provided")
}
if r.RenderArgs == nil {
r.RenderArgs = make(map[string]interface{})
}
r.RenderArgs["RunMode"] = RunMode
r.RenderArgs["Error"] = revelError
r.RenderArgs["Router"] = MainRouter
var b bytes.Buffer
err = tmpl.Render(&b, r.RenderArgs)
if err != nil {
showPlaintext(err)
return
}
resp.WriteHeader(status, contentType)
b.WriteTo(resp.Out)
}
type PlaintextErrorResult struct {
Error error
}
func (r PlaintextErrorResult) Apply(req *Request, resp *Response) {
resp.WriteHeader(http.StatusInternalServerError, "text/plain; charset=utf-8")
resp.Out.Write([]byte(r.Error.Error()))
}
type RenderTemplateResult struct {
Template Template
RenderArgs map[string]interface{}
}
func (r *RenderTemplateResult) Apply(req *Request, resp *Response) {
defer func() {
if err := recover(); err != nil {
ERROR.Println(err)
PlaintextErrorResult{fmt.Errorf("Template Execution Panic in %s:\n%s",
r.Template.Name(), err)}.Apply(req, resp)
}
}()
chunked := Config.BoolDefault("results.chunked", false)
out := io.Writer(resp.Out)
if req.Method == "HEAD" {
out = ioutil.Discard
}
if chunked && !DevMode {
resp.WriteHeader(http.StatusOK, "text/html; charset=utf-8")
r.render(req, resp, out)
return
}
var b bytes.Buffer
r.render(req, resp, &b)
if !chunked {
resp.Out.Header().Set("Content-Length", strconv.Itoa(b.Len()))
}
resp.WriteHeader(http.StatusOK, "text/html; charset=utf-8")
b.WriteTo(out)
}
type RenderHtmlResult struct {
}
func (r RenderHtmlResult) Apply(req *Request, resp *Response) {
resp.WriteHeader(http.StatusOK, "text/html; charset=utf-8")
resp.Out.Write([]byte(r.html))
}
type RenderJsonResult struct {
}
func (r RenderJsonResult) Apply(req *Request, resp *Response) {
var b []byte
var err error
if Config.BoolDefault("results.pretty", false) {
b, err = json.MarshalIndent(r.obj, "", " ")
} else {
b, err = json.Marshal(r.obj)
}
if err != nil {
ErrorResult{Error: err}.Apply(req, resp)
return
}
if r.callback == "" {
resp.WriteHeader(http.StatusOK, "application/json; charset=utf-8")
resp.Out.Write(b)
return
}
resp.WriteHeader(http.StatusOK, "application/javascript; charset=utf-8")
resp.Out.Write([]byte(r.callback + "("))
resp.Out.Write(b)
resp.Out.Write([]byte(");"))
}
type RenderXmlResult struct {
}
func (r RenderXmlResult) Apply(req *Request, resp *Response) {
var b []byte
var err error
if Config.BoolDefault("results.pretty", false) {
b, err = xml.MarshalIndent(r.obj, "", " ")
} else {
b, err = xml.Marshal(r.obj)
}
if err != nil {
ErrorResult{Error: err}.Apply(req, resp)
return
}
resp.WriteHeader(http.StatusOK, "application/xml; charset=utf-8")
resp.Out.Write(b)
}
type RenderTextResult struct {
}
func (r RenderTextResult) Apply(req *Request, resp *Response) {
resp.WriteHeader(http.StatusOK, "text/plain; charset=utf-8")
resp.Out.Write([]byte(r.text))
}
type ContentDisposition string
var (
Attachment ContentDisposition = "attachment"
Inline ContentDisposition = "inline"
)
type BinaryResult struct {
Reader io.Reader
Name string
Length int64
Delivery ContentDisposition
ModTime time.Time
}
func (r *BinaryResult) Apply(req *Request, resp *Response) {
disposition := string(r.Delivery)
if r.Name != "" {
disposition += fmt.Sprintf("; filename=%s", r.Name)
}
resp.Out.Header().Set("Content-Disposition", disposition)
if rs, ok := r.Reader.(io.ReadSeeker); ok {
if resp.ContentType != "" {
resp.Out.Header().Set("Content-Type", resp.ContentType)
}
http.ServeContent(resp.Out, req.Request, r.Name, r.ModTime, rs)
} else {
if r.Length != -1 {
resp.Out.Header().Set("Content-Length", strconv.FormatInt(r.Length, 10))
}
resp.WriteHeader(http.StatusOK, ContentTypeByFilename(r.Name))
io.Copy(resp.Out, r.Reader)
}
if v, ok := r.Reader.(io.Closer); ok {
v.Close()
}
}
type RedirectToUrlResult struct {
}
func (r *RedirectToUrlResult) Apply(req *Request, resp *Response) {
resp.Out.Header().Set("Location", r.url)
resp.WriteHeader(http.StatusFound, "")
}
type RedirectToActionResult struct {
}
func (r *RedirectToActionResult) Apply(req *Request, resp *Response) {
url, err := getRedirectUrl(r.val)
if err != nil {
ERROR.Println("Couldn't resolve redirect:", err.Error())
ErrorResult{Error: err}.Apply(req, resp)
return
}
resp.Out.Header().Set("Location", url)
resp.WriteHeader(http.StatusFound, "")
}