response.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. package restful
  2. // Copyright 2013 Ernest Micklei. All rights reserved.
  3. // Use of this source code is governed by a license
  4. // that can be found in the LICENSE file.
  5. import (
  6. "bufio"
  7. "errors"
  8. "net"
  9. "net/http"
  10. )
  11. // DefaultResponseMimeType is DEPRECATED, use DefaultResponseContentType(mime)
  12. var DefaultResponseMimeType string
  13. //PrettyPrintResponses controls the indentation feature of XML and JSON serialization
  14. var PrettyPrintResponses = true
  15. // Response is a wrapper on the actual http ResponseWriter
  16. // It provides several convenience methods to prepare and write response content.
  17. type Response struct {
  18. http.ResponseWriter
  19. requestAccept string // mime-type what the Http Request says it wants to receive
  20. routeProduces []string // mime-types what the Route says it can produce
  21. statusCode int // HTTP status code that has been written explicitly (if zero then net/http has written 200)
  22. contentLength int // number of bytes written for the response body
  23. prettyPrint bool // controls the indentation feature of XML and JSON serialization. It is initialized using var PrettyPrintResponses.
  24. err error // err property is kept when WriteError is called
  25. hijacker http.Hijacker // if underlying ResponseWriter supports it
  26. }
  27. // NewResponse creates a new response based on a http ResponseWriter.
  28. func NewResponse(httpWriter http.ResponseWriter) *Response {
  29. hijacker, _ := httpWriter.(http.Hijacker)
  30. return &Response{ResponseWriter: httpWriter, routeProduces: []string{}, statusCode: http.StatusOK, prettyPrint: PrettyPrintResponses, hijacker: hijacker}
  31. }
  32. // DefaultResponseContentType set a default.
  33. // If Accept header matching fails, fall back to this type.
  34. // Valid values are restful.MIME_JSON and restful.MIME_XML
  35. // Example:
  36. // restful.DefaultResponseContentType(restful.MIME_JSON)
  37. func DefaultResponseContentType(mime string) {
  38. DefaultResponseMimeType = mime
  39. }
  40. // InternalServerError writes the StatusInternalServerError header.
  41. // DEPRECATED, use WriteErrorString(http.StatusInternalServerError,reason)
  42. func (r Response) InternalServerError() Response {
  43. r.WriteHeader(http.StatusInternalServerError)
  44. return r
  45. }
  46. // Hijack implements the http.Hijacker interface. This expands
  47. // the Response to fulfill http.Hijacker if the underlying
  48. // http.ResponseWriter supports it.
  49. func (r *Response) Hijack() (net.Conn, *bufio.ReadWriter, error) {
  50. if r.hijacker == nil {
  51. return nil, nil, errors.New("http.Hijacker not implemented by underlying http.ResponseWriter")
  52. }
  53. return r.hijacker.Hijack()
  54. }
  55. // PrettyPrint changes whether this response must produce pretty (line-by-line, indented) JSON or XML output.
  56. func (r *Response) PrettyPrint(bePretty bool) {
  57. r.prettyPrint = bePretty
  58. }
  59. // AddHeader is a shortcut for .Header().Add(header,value)
  60. func (r Response) AddHeader(header string, value string) Response {
  61. r.Header().Add(header, value)
  62. return r
  63. }
  64. // SetRequestAccepts tells the response what Mime-type(s) the HTTP request said it wants to accept. Exposed for testing.
  65. func (r *Response) SetRequestAccepts(mime string) {
  66. r.requestAccept = mime
  67. }
  68. // EntityWriter returns the registered EntityWriter that the entity (requested resource)
  69. // can write according to what the request wants (Accept) and what the Route can produce or what the restful defaults say.
  70. // If called before WriteEntity and WriteHeader then a false return value can be used to write a 406: Not Acceptable.
  71. func (r *Response) EntityWriter() (EntityReaderWriter, bool) {
  72. sorted := sortedMimes(r.requestAccept)
  73. for _, eachAccept := range sorted {
  74. for _, eachProduce := range r.routeProduces {
  75. if eachProduce == eachAccept.media {
  76. if w, ok := entityAccessRegistry.accessorAt(eachAccept.media); ok {
  77. return w, true
  78. }
  79. }
  80. }
  81. if eachAccept.media == "*/*" {
  82. for _, each := range r.routeProduces {
  83. if w, ok := entityAccessRegistry.accessorAt(each); ok {
  84. return w, true
  85. }
  86. }
  87. }
  88. }
  89. // if requestAccept is empty
  90. writer, ok := entityAccessRegistry.accessorAt(r.requestAccept)
  91. if !ok {
  92. // if not registered then fallback to the defaults (if set)
  93. if DefaultResponseMimeType == MIME_JSON {
  94. return entityAccessRegistry.accessorAt(MIME_JSON)
  95. }
  96. if DefaultResponseMimeType == MIME_XML {
  97. return entityAccessRegistry.accessorAt(MIME_XML)
  98. }
  99. if DefaultResponseMimeType == MIME_ZIP {
  100. return entityAccessRegistry.accessorAt(MIME_ZIP)
  101. }
  102. // Fallback to whatever the route says it can produce.
  103. // https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
  104. for _, each := range r.routeProduces {
  105. if w, ok := entityAccessRegistry.accessorAt(each); ok {
  106. return w, true
  107. }
  108. }
  109. if trace {
  110. traceLogger.Printf("no registered EntityReaderWriter found for %s", r.requestAccept)
  111. }
  112. }
  113. return writer, ok
  114. }
  115. // WriteEntity calls WriteHeaderAndEntity with Http Status OK (200)
  116. func (r *Response) WriteEntity(value interface{}) error {
  117. return r.WriteHeaderAndEntity(http.StatusOK, value)
  118. }
  119. // WriteHeaderAndEntity marshals the value using the representation denoted by the Accept Header and the registered EntityWriters.
  120. // If no Accept header is specified (or */*) then respond with the Content-Type as specified by the first in the Route.Produces.
  121. // If an Accept header is specified then respond with the Content-Type as specified by the first in the Route.Produces that is matched with the Accept header.
  122. // If the value is nil then no response is send except for the Http status. You may want to call WriteHeader(http.StatusNotFound) instead.
  123. // If there is no writer available that can represent the value in the requested MIME type then Http Status NotAcceptable is written.
  124. // Current implementation ignores any q-parameters in the Accept Header.
  125. // Returns an error if the value could not be written on the response.
  126. func (r *Response) WriteHeaderAndEntity(status int, value interface{}) error {
  127. writer, ok := r.EntityWriter()
  128. if !ok {
  129. r.WriteHeader(http.StatusNotAcceptable)
  130. return nil
  131. }
  132. return writer.Write(r, status, value)
  133. }
  134. // WriteAsXml is a convenience method for writing a value in xml (requires Xml tags on the value)
  135. // It uses the standard encoding/xml package for marshalling the value ; not using a registered EntityReaderWriter.
  136. func (r *Response) WriteAsXml(value interface{}) error {
  137. return writeXML(r, http.StatusOK, MIME_XML, value)
  138. }
  139. // WriteHeaderAndXml is a convenience method for writing a status and value in xml (requires Xml tags on the value)
  140. // It uses the standard encoding/xml package for marshalling the value ; not using a registered EntityReaderWriter.
  141. func (r *Response) WriteHeaderAndXml(status int, value interface{}) error {
  142. return writeXML(r, status, MIME_XML, value)
  143. }
  144. // WriteAsJson is a convenience method for writing a value in json.
  145. // It uses the standard encoding/json package for marshalling the value ; not using a registered EntityReaderWriter.
  146. func (r *Response) WriteAsJson(value interface{}) error {
  147. return writeJSON(r, http.StatusOK, MIME_JSON, value)
  148. }
  149. // WriteJson is a convenience method for writing a value in Json with a given Content-Type.
  150. // It uses the standard encoding/json package for marshalling the value ; not using a registered EntityReaderWriter.
  151. func (r *Response) WriteJson(value interface{}, contentType string) error {
  152. return writeJSON(r, http.StatusOK, contentType, value)
  153. }
  154. // WriteHeaderAndJson is a convenience method for writing the status and a value in Json with a given Content-Type.
  155. // It uses the standard encoding/json package for marshalling the value ; not using a registered EntityReaderWriter.
  156. func (r *Response) WriteHeaderAndJson(status int, value interface{}, contentType string) error {
  157. return writeJSON(r, status, contentType, value)
  158. }
  159. // WriteError writes the http status and the error string on the response. err can be nil.
  160. // Return an error if writing was not successful.
  161. func (r *Response) WriteError(httpStatus int, err error) (writeErr error) {
  162. r.err = err
  163. if err == nil {
  164. writeErr = r.WriteErrorString(httpStatus, "")
  165. } else {
  166. writeErr = r.WriteErrorString(httpStatus, err.Error())
  167. }
  168. return writeErr
  169. }
  170. // WriteServiceError is a convenience method for a responding with a status and a ServiceError
  171. func (r *Response) WriteServiceError(httpStatus int, err ServiceError) error {
  172. r.err = err
  173. return r.WriteHeaderAndEntity(httpStatus, err)
  174. }
  175. // WriteErrorString is a convenience method for an error status with the actual error
  176. func (r *Response) WriteErrorString(httpStatus int, errorReason string) error {
  177. if r.err == nil {
  178. // if not called from WriteError
  179. r.err = errors.New(errorReason)
  180. }
  181. r.WriteHeader(httpStatus)
  182. if _, err := r.Write([]byte(errorReason)); err != nil {
  183. return err
  184. }
  185. return nil
  186. }
  187. // Flush implements http.Flusher interface, which sends any buffered data to the client.
  188. func (r *Response) Flush() {
  189. if f, ok := r.ResponseWriter.(http.Flusher); ok {
  190. f.Flush()
  191. } else if trace {
  192. traceLogger.Printf("ResponseWriter %v doesn't support Flush", r)
  193. }
  194. }
  195. // WriteHeader is overridden to remember the Status Code that has been written.
  196. // Changes to the Header of the response have no effect after this.
  197. func (r *Response) WriteHeader(httpStatus int) {
  198. r.statusCode = httpStatus
  199. r.ResponseWriter.WriteHeader(httpStatus)
  200. }
  201. // StatusCode returns the code that has been written using WriteHeader.
  202. func (r Response) StatusCode() int {
  203. if 0 == r.statusCode {
  204. // no status code has been written yet; assume OK
  205. return http.StatusOK
  206. }
  207. return r.statusCode
  208. }
  209. // Write writes the data to the connection as part of an HTTP reply.
  210. // Write is part of http.ResponseWriter interface.
  211. func (r *Response) Write(bytes []byte) (int, error) {
  212. written, err := r.ResponseWriter.Write(bytes)
  213. r.contentLength += written
  214. return written, err
  215. }
  216. // ContentLength returns the number of bytes written for the response content.
  217. // Note that this value is only correct if all data is written through the Response using its Write* methods.
  218. // Data written directly using the underlying http.ResponseWriter is not accounted for.
  219. func (r Response) ContentLength() int {
  220. return r.contentLength
  221. }
  222. // CloseNotify is part of http.CloseNotifier interface
  223. func (r Response) CloseNotify() <-chan bool {
  224. return r.ResponseWriter.(http.CloseNotifier).CloseNotify()
  225. }
  226. // Error returns the err created by WriteError
  227. func (r Response) Error() error {
  228. return r.err
  229. }