recorder_test.go 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. // Remove me when https://github.com/golang/go/pull/56151 will be merged
  2. // Copyright 2011 The Go Authors. All rights reserved.
  3. // Use of this source code is governed by a BSD-style
  4. // license that can be found in the LICENSE file.
  5. package frankenphp_test
  6. import (
  7. "bytes"
  8. "fmt"
  9. "io"
  10. "net/http"
  11. "net/http/httptrace"
  12. "net/textproto"
  13. "strconv"
  14. "strings"
  15. "golang.org/x/net/http/httpguts"
  16. )
  17. // ResponseRecorder is an implementation of http.ResponseWriter that
  18. // records its mutations for later inspection in tests.
  19. type ResponseRecorder struct {
  20. // Code is the HTTP response code set by WriteHeader.
  21. //
  22. // Note that if a Handler never calls WriteHeader or Write,
  23. // this might end up being 0, rather than the implicit
  24. // http.StatusOK. To get the implicit value, use the Result
  25. // method.
  26. Code int
  27. // HeaderMap contains the headers explicitly set by the Handler.
  28. // It is an internal detail.
  29. //
  30. // Deprecated: HeaderMap exists for historical compatibility
  31. // and should not be used. To access the headers returned by a handler,
  32. // use the Response.Header map as returned by the Result method.
  33. HeaderMap http.Header
  34. // Body is the buffer to which the Handler's Write calls are sent.
  35. // If nil, the Writes are silently discarded.
  36. Body *bytes.Buffer
  37. // Flushed is whether the Handler called Flush.
  38. Flushed bool
  39. // ClientTrace is used to trace 1XX responses
  40. ClientTrace *httptrace.ClientTrace
  41. result *http.Response // cache of Result's return value
  42. snapHeader http.Header // snapshot of HeaderMap at first Write
  43. wroteHeader bool
  44. }
  45. // NewRecorder returns an initialized ResponseRecorder.
  46. func NewRecorder() *ResponseRecorder {
  47. return &ResponseRecorder{
  48. HeaderMap: make(http.Header),
  49. Body: new(bytes.Buffer),
  50. Code: 200,
  51. }
  52. }
  53. // DefaultRemoteAddr is the default remote address to return in RemoteAddr if
  54. // an explicit DefaultRemoteAddr isn't set on ResponseRecorder.
  55. const DefaultRemoteAddr = "1.2.3.4"
  56. // Header implements http.ResponseWriter. It returns the response
  57. // headers to mutate within a handler. To test the headers that were
  58. // written after a handler completes, use the Result method and see
  59. // the returned Response value's Header.
  60. func (rw *ResponseRecorder) Header() http.Header {
  61. m := rw.HeaderMap
  62. if m == nil {
  63. m = make(http.Header)
  64. rw.HeaderMap = m
  65. }
  66. return m
  67. }
  68. // writeHeader writes a header if it was not written yet and
  69. // detects Content-Type if needed.
  70. //
  71. // bytes or str are the beginning of the response body.
  72. // We pass both to avoid unnecessarily generate garbage
  73. // in rw.WriteString which was created for performance reasons.
  74. // Non-nil bytes win.
  75. func (rw *ResponseRecorder) writeHeader(b []byte, str string) {
  76. if rw.wroteHeader {
  77. return
  78. }
  79. if len(str) > 512 {
  80. str = str[:512]
  81. }
  82. m := rw.Header()
  83. _, hasType := m["Content-Type"]
  84. hasTE := m.Get("Transfer-Encoding") != ""
  85. if !hasType && !hasTE {
  86. if b == nil {
  87. b = []byte(str)
  88. }
  89. m.Set("Content-Type", http.DetectContentType(b))
  90. }
  91. rw.WriteHeader(200)
  92. }
  93. // Write implements http.ResponseWriter. The data in buf is written to
  94. // rw.Body, if not nil.
  95. func (rw *ResponseRecorder) Write(buf []byte) (int, error) {
  96. rw.writeHeader(buf, "")
  97. if rw.Body != nil {
  98. rw.Body.Write(buf)
  99. }
  100. return len(buf), nil
  101. }
  102. // WriteString implements io.StringWriter. The data in str is written
  103. // to rw.Body, if not nil.
  104. func (rw *ResponseRecorder) WriteString(str string) (int, error) {
  105. rw.writeHeader(nil, str)
  106. if rw.Body != nil {
  107. rw.Body.WriteString(str)
  108. }
  109. return len(str), nil
  110. }
  111. func checkWriteHeaderCode(code int) {
  112. // Issue 22880: require valid WriteHeader status codes.
  113. // For now we only enforce that it's three digits.
  114. // In the future we might block things over 599 (600 and above aren't defined
  115. // at https://httpwg.org/specs/rfc7231.html#status.codes)
  116. // and we might block under 200 (once we have more mature 1xx support).
  117. // But for now any three digits.
  118. //
  119. // We used to send "HTTP/1.1 000 0" on the wire in responses but there's
  120. // no equivalent bogus thing we can realistically send in HTTP/2,
  121. // so we'll consistently panic instead and help people find their bugs
  122. // early. (We can't return an error from WriteHeader even if we wanted to.)
  123. if code < 100 || code > 999 {
  124. panic(fmt.Sprintf("invalid WriteHeader code %v", code))
  125. }
  126. }
  127. // WriteHeader implements http.ResponseWriter.
  128. func (rw *ResponseRecorder) WriteHeader(code int) {
  129. if rw.wroteHeader {
  130. return
  131. }
  132. checkWriteHeaderCode(code)
  133. if rw.ClientTrace != nil && code >= 100 && code < 200 {
  134. if code == 100 {
  135. rw.ClientTrace.Got100Continue()
  136. }
  137. // treat 101 as a terminal status, see issue 26161
  138. if code != http.StatusSwitchingProtocols {
  139. if err := rw.ClientTrace.Got1xxResponse(code, textproto.MIMEHeader(rw.HeaderMap)); err != nil {
  140. panic(err)
  141. }
  142. return
  143. }
  144. }
  145. rw.Code = code
  146. rw.wroteHeader = true
  147. if rw.HeaderMap == nil {
  148. rw.HeaderMap = make(http.Header)
  149. }
  150. rw.snapHeader = rw.HeaderMap.Clone()
  151. }
  152. // Flush implements http.Flusher. To test whether Flush was
  153. // called, see rw.Flushed.
  154. func (rw *ResponseRecorder) Flush() {
  155. if !rw.wroteHeader {
  156. rw.WriteHeader(200)
  157. }
  158. rw.Flushed = true
  159. }
  160. // Result returns the response generated by the handler.
  161. //
  162. // The returned Response will have at least its StatusCode,
  163. // Header, Body, and optionally Trailer populated.
  164. // More fields may be populated in the future, so callers should
  165. // not DeepEqual the result in tests.
  166. //
  167. // The Response.Header is a snapshot of the headers at the time of the
  168. // first write call, or at the time of this call, if the handler never
  169. // did a write.
  170. //
  171. // The Response.Body is guaranteed to be non-nil and Body.Read call is
  172. // guaranteed to not return any error other than io.EOF.
  173. //
  174. // Result must only be called after the handler has finished running.
  175. func (rw *ResponseRecorder) Result() *http.Response {
  176. if rw.result != nil {
  177. return rw.result
  178. }
  179. if rw.snapHeader == nil {
  180. rw.snapHeader = rw.HeaderMap.Clone()
  181. }
  182. res := &http.Response{
  183. Proto: "HTTP/1.1",
  184. ProtoMajor: 1,
  185. ProtoMinor: 1,
  186. StatusCode: rw.Code,
  187. Header: rw.snapHeader,
  188. }
  189. rw.result = res
  190. if res.StatusCode == 0 {
  191. res.StatusCode = 200
  192. }
  193. res.Status = fmt.Sprintf("%03d %s", res.StatusCode, http.StatusText(res.StatusCode))
  194. if rw.Body != nil {
  195. res.Body = io.NopCloser(bytes.NewReader(rw.Body.Bytes()))
  196. } else {
  197. res.Body = http.NoBody
  198. }
  199. res.ContentLength = parseContentLength(res.Header.Get("Content-Length"))
  200. if trailers, ok := rw.snapHeader["Trailer"]; ok {
  201. res.Trailer = make(http.Header, len(trailers))
  202. for _, k := range trailers {
  203. for _, k := range strings.Split(k, ",") {
  204. k = http.CanonicalHeaderKey(textproto.TrimString(k))
  205. if !httpguts.ValidTrailerHeader(k) {
  206. // Ignore since forbidden by RFC 7230, section 4.1.2.
  207. continue
  208. }
  209. vv, ok := rw.HeaderMap[k]
  210. if !ok {
  211. continue
  212. }
  213. vv2 := make([]string, len(vv))
  214. copy(vv2, vv)
  215. res.Trailer[k] = vv2
  216. }
  217. }
  218. }
  219. for k, vv := range rw.HeaderMap {
  220. if !strings.HasPrefix(k, http.TrailerPrefix) {
  221. continue
  222. }
  223. if res.Trailer == nil {
  224. res.Trailer = make(http.Header)
  225. }
  226. for _, v := range vv {
  227. res.Trailer.Add(strings.TrimPrefix(k, http.TrailerPrefix), v)
  228. }
  229. }
  230. return res
  231. }
  232. // parseContentLength trims whitespace from s and returns -1 if no value
  233. // is set, or the value if it's >= 0.
  234. //
  235. // This a modified version of same function found in net/http/transfer.go. This
  236. // one just ignores an invalid header.
  237. func parseContentLength(cl string) int64 {
  238. cl = textproto.TrimString(cl)
  239. if cl == "" {
  240. return -1
  241. }
  242. n, err := strconv.ParseUint(cl, 10, 63)
  243. if err != nil {
  244. return -1
  245. }
  246. return int64(n)
  247. }