transport.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. package gock
  2. import (
  3. "errors"
  4. "net/http"
  5. "sync"
  6. )
  7. // var mutex *sync.Mutex = &sync.Mutex{}
  8. var (
  9. // DefaultTransport stores the default mock transport used by gock.
  10. DefaultTransport = NewTransport()
  11. // NativeTransport stores the native net/http default transport
  12. // in order to restore it when needed.
  13. NativeTransport = http.DefaultTransport
  14. )
  15. var (
  16. // ErrCannotMatch store the error returned in case of no matches.
  17. ErrCannotMatch = errors.New("gock: cannot match any request")
  18. )
  19. // Transport implements http.RoundTripper, which fulfills single http requests issued by
  20. // an http.Client.
  21. //
  22. // gock's Transport encapsulates a given or default http.Transport for further
  23. // delegation, if needed.
  24. type Transport struct {
  25. // mutex is used to make transport thread-safe of concurrent uses across goroutines.
  26. mutex sync.Mutex
  27. // Transport encapsulates the original http.RoundTripper transport interface for delegation.
  28. Transport http.RoundTripper
  29. }
  30. // NewTransport creates a new *Transport with no responders.
  31. func NewTransport() *Transport {
  32. return &Transport{Transport: NativeTransport}
  33. }
  34. // RoundTrip receives HTTP requests and routes them to the appropriate responder. It is required to
  35. // implement the http.RoundTripper interface. You will not interact with this directly, instead
  36. // the *http.Client you are using will call it for you.
  37. func (m *Transport) RoundTrip(req *http.Request) (*http.Response, error) {
  38. // Just act as a proxy if not intercepting
  39. if !Intercepting() {
  40. return m.Transport.RoundTrip(req)
  41. }
  42. m.mutex.Lock()
  43. defer Clean()
  44. var err error
  45. var res *http.Response
  46. // Match mock for the incoming http.Request
  47. mock, err := MatchMock(req)
  48. if err != nil {
  49. m.mutex.Unlock()
  50. return nil, err
  51. }
  52. // Verify if should use real networking
  53. networking := shouldUseNetwork(req, mock)
  54. if !networking && mock == nil {
  55. m.mutex.Unlock()
  56. trackUnmatchedRequest(req)
  57. return nil, ErrCannotMatch
  58. }
  59. // Ensure me unlock the mutex before building the response
  60. m.mutex.Unlock()
  61. // Perform real networking via original transport
  62. if networking {
  63. res, err = m.Transport.RoundTrip(req)
  64. // In no mock matched, continue with the response
  65. if err != nil || mock == nil {
  66. return res, err
  67. }
  68. }
  69. return Responder(req, mock.Response(), res)
  70. }
  71. // CancelRequest is a no-op function.
  72. func (m *Transport) CancelRequest(req *http.Request) {}
  73. func shouldUseNetwork(req *http.Request, mock Mock) bool {
  74. if mock != nil && mock.Response().UseNetwork {
  75. return true
  76. }
  77. if !config.Networking {
  78. return false
  79. }
  80. if len(config.NetworkingFilters) == 0 {
  81. return true
  82. }
  83. for _, filter := range config.NetworkingFilters {
  84. if !filter(req) {
  85. return false
  86. }
  87. }
  88. return true
  89. }