github.com/google/go-safeweb@v0.0.0-20231219055052-64d8cfc90fbb/safehttp/response.go (about)

     1  // Copyright 2020 Google LLC
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //	https://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package safehttp
    16  
    17  import (
    18  	"fmt"
    19  	"io"
    20  )
    21  
    22  // Response should encapsulate the data passed to the ResponseWriter to be
    23  // written by the Dispatcher. Any implementation of the interface should be
    24  // supported by the Dispatcher.
    25  type Response interface{}
    26  
    27  // ErrorResponse is an HTTP error response. The Dispatcher is responsible for
    28  // determining whether it is safe.
    29  type ErrorResponse interface {
    30  	Code() StatusCode
    31  }
    32  
    33  // JSONResponse should encapsulate a valid JSON object that will be serialised
    34  // and written to the http.ResponseWriter using a JSON encoder.
    35  type JSONResponse struct {
    36  	Data interface{}
    37  }
    38  
    39  // WriteJSON creates a JSONResponse from the data object and calls the Write
    40  // function of the ResponseWriter, passing the response. The data object should
    41  // be valid JSON, otherwise an error will occur.
    42  func WriteJSON(w ResponseWriter, data interface{}) Result {
    43  	return w.Write(JSONResponse{data})
    44  }
    45  
    46  // Template implements a template.
    47  type Template interface {
    48  	// Execute applies data to the template and then writes the result to
    49  	// the io.Writer.
    50  	//
    51  	// Execute returns an error if applying the data object to the
    52  	// Template fails or if an error occurs while writing the result to the
    53  	// io.Writer.
    54  	Execute(wr io.Writer, data interface{}) error
    55  
    56  	// ExecuteTemplate applies the named associated template to the specified data
    57  	// object and writes the output to the io.Writer.
    58  	//
    59  	// ExecuteTemplate returns an error if applying the data object to the
    60  	// Template fails or if an error occurs while writing the result to the
    61  	// io.Writer.
    62  	ExecuteTemplate(wr io.Writer, name string, data interface{}) error
    63  }
    64  
    65  // TemplateResponse bundles a Template with its data and names to function
    66  // mappings to be passed together to the commit phase.
    67  type TemplateResponse struct {
    68  	Template Template
    69  	Name     string
    70  	Data     interface{}
    71  	FuncMap  map[string]interface{}
    72  }
    73  
    74  // ExecuteTemplate creates a TemplateResponse from the provided Template and its
    75  // data and calls the Write function of the ResponseWriter, passing the
    76  // response.
    77  func ExecuteTemplate(w ResponseWriter, t Template, data interface{}) Result {
    78  	return ExecuteNamedTemplate(w, t, "", data)
    79  }
    80  
    81  // ExecuteNamedTemplate creates a TemplateResponse from the provided Template and its
    82  // data and calls the Write function of the ResponseWriter, passing the
    83  // response.
    84  // Leaving name empty is valid if the template does not have associated templates.
    85  func ExecuteNamedTemplate(w ResponseWriter, t Template, name string, data interface{}) Result {
    86  	return w.Write(&TemplateResponse{Template: t, Name: name, Data: data, FuncMap: nil})
    87  }
    88  
    89  // ExecuteTemplateWithFuncs creates a TemplateResponse from the provided
    90  // Template, its data and the name to function mappings and calls the Write
    91  // function of the ResponseWriter, passing the response.
    92  // Leaving name empty is valid if the template does not have associated templates.
    93  func ExecuteTemplateWithFuncs(w ResponseWriter, t Template, data interface{}, fm map[string]interface{}) Result {
    94  	return ExecuteNamedTemplateWithFuncs(w, t, "", data, fm)
    95  }
    96  
    97  // ExecuteNamedTemplateWithFuncs creates a TemplateResponse from the provided
    98  // Template, its data and the name to function mappings and calls the Write
    99  // function of the ResponseWriter, passing the response.
   100  // Leaving name empty is valid if the template does not have associated templates.
   101  func ExecuteNamedTemplateWithFuncs(w ResponseWriter, t Template, name string, data interface{}, fm map[string]interface{}) Result {
   102  	return w.Write(&TemplateResponse{Template: t, Name: name, Data: data, FuncMap: fm})
   103  }
   104  
   105  // NoContentResponse is used to write a "No Content" response.
   106  type NoContentResponse struct{}
   107  
   108  // RedirectResponse is used to generate redirect responses.
   109  type RedirectResponse struct {
   110  	// Code is the status to use for the redirect.
   111  	Code StatusCode
   112  	// Location is the value to use for the redirect Location.
   113  	Location string
   114  	// Request is the matching request for which this response is being written.
   115  	// It is used to build the redirect response.
   116  	Request *IncomingRequest
   117  }
   118  
   119  // Redirect creates a RedirectResponse and writes it to w.
   120  // If the given code is not a valid Redirect code this function will panic.
   121  func Redirect(w ResponseWriter, r *IncomingRequest, location string, code StatusCode) Result {
   122  	if code < 300 || code >= 400 {
   123  		panic(fmt.Sprintf("wrong method called: redirect with status %d", code))
   124  	}
   125  	return w.Write(RedirectResponse{Code: code, Location: location, Request: r})
   126  }