You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

123 lines
3.9 KiB

  1. // Copyright 2018 Google LLC
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. // +build go1.8
  15. // Package httpreplay provides an API for recording and replaying traffic
  16. // from HTTP-based Google API clients.
  17. //
  18. // To record:
  19. // 1. Call NewRecorder to get a Recorder.
  20. // 2. Use its Client method to obtain an HTTP client to use when making API calls.
  21. // 3. Close the Recorder when you're done. That will save the
  22. // log of interactions to the file you provided to NewRecorder.
  23. //
  24. // To replay:
  25. // 1. Call NewReplayer with the same filename you used to record to get a Replayer.
  26. // 2. Call its Client method and use the client to make the same API calls.
  27. // You will get back the recorded responses.
  28. // 3. Close the Replayer when you're done.
  29. //
  30. // This package is EXPERIMENTAL and is subject to change or removal without notice.
  31. // It requires Go version 1.8 or higher.
  32. package httpreplay
  33. // TODO(jba): add examples.
  34. import (
  35. "net/http"
  36. "cloud.google.com/go/httpreplay/internal/proxy"
  37. "golang.org/x/net/context"
  38. "google.golang.org/api/option"
  39. htransport "google.golang.org/api/transport/http"
  40. )
  41. // A Recorder records HTTP interactions.
  42. type Recorder struct {
  43. filename string
  44. proxy *proxy.Proxy
  45. }
  46. // NewRecorder creates a recorder that writes to filename. The file will
  47. // also store initial state that can be retrieved to configure replay.
  48. //
  49. // You must call Close on the Recorder to ensure that all data is written.
  50. func NewRecorder(filename string, initial []byte) (*Recorder, error) {
  51. p, err := proxy.ForRecording(filename, 0)
  52. if err != nil {
  53. return nil, err
  54. }
  55. p.Initial = initial
  56. return &Recorder{proxy: p}, nil
  57. }
  58. // Client returns an http.Client to be used for recording. Provide authentication options
  59. // like option.WithTokenSource as you normally would, or omit them to use Application Default
  60. // Credentials.
  61. func (r *Recorder) Client(ctx context.Context, opts ...option.ClientOption) (*http.Client, error) {
  62. return proxyClient(ctx, r.proxy, opts...)
  63. }
  64. func proxyClient(ctx context.Context, p *proxy.Proxy, opts ...option.ClientOption) (*http.Client, error) {
  65. trans, err := htransport.NewTransport(ctx, p.Transport(), opts...)
  66. if err != nil {
  67. return nil, err
  68. }
  69. return &http.Client{Transport: trans}, nil
  70. }
  71. // Close closes the Recorder and saves the log file.
  72. func (r *Recorder) Close() error {
  73. return r.proxy.Close()
  74. }
  75. // A Replayer replays previously recorded HTTP interactions.
  76. type Replayer struct {
  77. proxy *proxy.Proxy
  78. }
  79. // NewReplayer creates a replayer that reads from filename.
  80. func NewReplayer(filename string) (*Replayer, error) {
  81. p, err := proxy.ForReplaying(filename, 0)
  82. if err != nil {
  83. return nil, err
  84. }
  85. return &Replayer{proxy: p}, nil
  86. }
  87. // Client returns an HTTP client for replaying. The client does not need to be
  88. // configured with credentials for authenticating to a server, since it never
  89. // contacts a real backend.
  90. func (r *Replayer) Client(ctx context.Context) (*http.Client, error) {
  91. return proxyClient(ctx, r.proxy, option.WithoutAuthentication())
  92. }
  93. // Initial returns the initial state saved by the Recorder.
  94. func (r *Replayer) Initial() []byte {
  95. return r.proxy.Initial
  96. }
  97. // Close closes the replayer.
  98. func (r *Replayer) Close() error {
  99. return r.proxy.Close()
  100. }
  101. // DebugHeaders helps to determine whether a header should be ignored.
  102. // When true, if requests have the same method, URL and body but differ
  103. // in a header, the first mismatched header is logged.
  104. func DebugHeaders() {
  105. proxy.DebugHeaders = true
  106. }