responder.go 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. package gock
  2. import (
  3. "bytes"
  4. "io"
  5. "net/http"
  6. "strconv"
  7. "time"
  8. )
  9. // Responder builds a mock http.Response based on the given Response mock.
  10. func Responder(req *http.Request, mock *Response, res *http.Response) (*http.Response, error) {
  11. // If error present, reply it
  12. err := mock.Error
  13. if err != nil {
  14. return nil, err
  15. }
  16. if res == nil {
  17. res = createResponse(req)
  18. }
  19. // Apply response filter
  20. for _, filter := range mock.Filters {
  21. if !filter(res) {
  22. return res, nil
  23. }
  24. }
  25. // Define mock status code
  26. if mock.StatusCode != 0 {
  27. res.Status = strconv.Itoa(mock.StatusCode) + " " + http.StatusText(mock.StatusCode)
  28. res.StatusCode = mock.StatusCode
  29. }
  30. // Define headers by merging fields
  31. res.Header = mergeHeaders(res, mock)
  32. // Define mock body, if present
  33. if len(mock.BodyBuffer) > 0 {
  34. res.ContentLength = int64(len(mock.BodyBuffer))
  35. res.Body = createReadCloser(mock.BodyBuffer)
  36. }
  37. // Apply response mappers
  38. for _, mapper := range mock.Mappers {
  39. if tres := mapper(res); tres != nil {
  40. res = tres
  41. }
  42. }
  43. // Sleep to simulate delay, if necessary
  44. if mock.ResponseDelay > 0 {
  45. time.Sleep(mock.ResponseDelay)
  46. }
  47. return res, err
  48. }
  49. // createResponse creates a new http.Response with default fields.
  50. func createResponse(req *http.Request) *http.Response {
  51. return &http.Response{
  52. ProtoMajor: 1,
  53. ProtoMinor: 1,
  54. Proto: "HTTP/1.1",
  55. Request: req,
  56. Header: make(http.Header),
  57. Body: createReadCloser([]byte{}),
  58. }
  59. }
  60. // mergeHeaders copies the mock headers.
  61. func mergeHeaders(res *http.Response, mres *Response) http.Header {
  62. for key := range mres.Header {
  63. res.Header.Set(key, mres.Header.Get(key))
  64. }
  65. return res.Header
  66. }
  67. // createReadCloser creates an io.ReadCloser from a byte slice that is suitable for use as an
  68. // http response body.
  69. func createReadCloser(body []byte) io.ReadCloser {
  70. return &dummyReadCloser{body: bytes.NewReader(body)}
  71. }
  72. // dummyReadCloser is used internally as io.ReadCloser capable interface for bodies.
  73. type dummyReadCloser struct {
  74. body io.ReadSeeker
  75. }
  76. // Read implements the required method by io.ReadClose interface.
  77. func (d *dummyReadCloser) Read(p []byte) (n int, err error) {
  78. n, err = d.body.Read(p)
  79. if err == io.EOF {
  80. d.body.Seek(0, 0)
  81. }
  82. return n, err
  83. }
  84. // Close implements a no-op required method by io.ReadClose interface.
  85. func (d *dummyReadCloser) Close() error {
  86. return nil
  87. }