-
Notifications
You must be signed in to change notification settings - Fork 15
/
Copy pathvcrtransport.go
165 lines (132 loc) · 5.59 KB
/
vcrtransport.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
package govcr
import (
"net/http"
"github.com/pkg/errors"
"github.com/seborama/govcr/v15/cassette"
"github.com/seborama/govcr/v15/cassette/track"
"github.com/seborama/govcr/v15/encryption"
govcrerr "github.com/seborama/govcr/v15/errors"
"github.com/seborama/govcr/v15/stats"
)
// vcrTransport is the heart of VCR. It implements
// http.RoundTripper that wraps over the default
// one provided by Go's http package or a custom one
// if provided when calling NewVCR.
type vcrTransport struct {
pcb *PrintedCircuitBoard
cassette *cassette.Cassette
transport http.RoundTripper
}
// RoundTrip is an implementation of http.RoundTripper.
// Note: by convention resp should be nil if an error occurs with HTTP.
func (t *vcrTransport) RoundTrip(httpRequest *http.Request) (*http.Response, error) {
if t.cassette == nil {
return nil, govcrerr.NewErrGoVCR("invalid VCR state: no cassette loaded")
}
httpRequestClone := track.CloneHTTPRequest(httpRequest)
// search for a matching track on cassette if liveOnly mode is not selected
trk, err := t.pcb.SeekTrack(t.cassette, httpRequestClone)
if err != nil {
return nil, errors.Wrap(err, "govcr failed to read matching track from cassette")
}
if trk != nil {
t.pcb.mutateTrackReplaying(trk)
httpResponse := trk.ToHTTPResponse()
httpError := trk.ToErr()
return httpResponse, httpError //nolint:wrapcheck
}
if t.pcb.httpMode == HTTPModeOffline {
return nil, errors.New("no track matched on cassette and offline mode is active")
}
httpResponse, reqErr := t.transport.RoundTrip(httpRequest)
if !t.pcb.readOnly {
trkResponse := track.ToResponse(httpResponse)
trkRequest := track.ToRequest(httpRequestClone)
newTrack := track.NewTrack(trkRequest, trkResponse, reqErr)
t.pcb.mutateTrackRecording(newTrack)
if err = cassette.AddTrackToCassette(t.cassette, newTrack); err != nil {
return nil, errors.Wrap(err, "govcr failed to add track to cassette")
}
}
return httpResponse, errors.WithStack(reqErr)
}
// NumberOfTracks returns the number of tracks contained in the cassette.
func (t *vcrTransport) NumberOfTracks() int32 {
return t.cassette.NumberOfTracks()
}
// SetRequestMatchers sets a new collection of RequestMatcher's to the VCR.
func (t *vcrTransport) SetRequestMatchers(reqMatchers ...RequestMatcher) {
t.pcb.SetRequestMatchers(reqMatchers...)
}
// AddRequestMatchers sets a new collection of RequestMatcher's to the VCR.
func (t *vcrTransport) AddRequestMatchers(reqMatchers ...RequestMatcher) {
t.pcb.AddRequestMatchers(reqMatchers...)
}
// SetReadOnlyMode sets the VCR to read-only mode (true) or to normal read-write (false).
func (t *vcrTransport) SetReadOnlyMode(state bool) {
t.pcb.SetReadOnlyMode(state)
}
// SetNormalMode sets the VCR to normal HTTP mode.
func (t *vcrTransport) SetNormalMode() {
t.pcb.SetNormalMode()
}
// SetOfflineMode sets the VCR to offline mode.
func (t *vcrTransport) SetOfflineMode() {
t.pcb.SetOfflineMode()
}
// SetLiveOnlyMode sets the VCR to live-only mode.
func (t *vcrTransport) SetLiveOnlyMode() {
t.pcb.SetLiveOnlyMode()
}
// SetCipher sets the cassette Cipher.
// This can be used to set a cipher when none is present (which already happens automatically
// when loading a cassette) or change the cipher when one is already present.
// The cassette is automatically saved with the new selected cipher.
func (t *vcrTransport) SetCipher(crypter CrypterProvider, keyFile string) error {
f := func(key []byte, nonceGenerator encryption.NonceGenerator) (*encryption.Crypter, error) {
// a "CrypterProvider" is a CrypterNonceProvider with a pre-defined / default nonceGenerator
return crypter(key)
}
return t.SetCipherCustomNonce(f, keyFile, nil)
}
// SetCipherCustomNonce sets the cassette Cipher.
// This can be used to set a cipher when none is present (which already happens automatically
// when loading a cassette) or change the cipher when one is already present.
// The cassette is automatically saved with the new selected cipher.
func (t *vcrTransport) SetCipherCustomNonce(crypter CrypterNonceProvider, keyFile string, nonceGenerator encryption.NonceGenerator) error {
cr, err := makeCrypter(crypter, keyFile, nonceGenerator)
if err != nil {
return err
}
return t.cassette.SetCrypter(cr)
}
// AddRecordingMutators adds a set of recording Track Mutator's to the VCR.
func (t *vcrTransport) AddRecordingMutators(trackMutators ...track.Mutator) {
t.pcb.AddRecordingMutators(trackMutators...)
}
// SetRecordingMutators replaces the set of recording Track Mutator's in the VCR.
func (t *vcrTransport) SetRecordingMutators(trackMutators ...track.Mutator) {
t.pcb.SetRecordingMutators(trackMutators...)
}
// ClearRecordingMutators clears the set of recording Track Mutator's from the VCR.
func (t *vcrTransport) ClearRecordingMutators() {
t.pcb.ClearRecordingMutators()
}
// AddReplayingMutators adds a set of replaying Track Mutator's to the VCR.
// Replaying happens AFTER the request has been matched. As such, while the track's Request
// could be mutated, it will have no effect.
// However, the Request data can be referenced as part of mutating the Response.
func (t *vcrTransport) AddReplayingMutators(mutators ...track.Mutator) {
t.pcb.AddReplayingMutators(mutators...)
}
// SetReplayingMutators replaces the set of replaying Track Mutator's in the VCR.
func (t *vcrTransport) SetReplayingMutators(trackMutators ...track.Mutator) {
t.pcb.SetReplayingMutators(trackMutators...)
}
// ClearReplayingMutators clears the set of replaying Track Mutator's from the VCR.
func (t *vcrTransport) ClearReplayingMutators() {
t.pcb.ClearReplayingMutators()
}
func (t *vcrTransport) stats() *stats.Stats {
return t.cassette.Stats()
}