File: faraday.rb

package info (click to toggle)
ruby-vcr 6.0.0%2Breally5.0.0-5
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 1,320 kB
  • sloc: ruby: 8,456; sh: 177; makefile: 7
file content (122 lines) | stat: -rw-r--r-- 3,801 bytes parent folder | download | duplicates (3)
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
require 'faraday'
require 'vcr/util/version_checker'
require 'vcr/request_handler'

VCR::VersionChecker.new('Faraday', Faraday::VERSION, '0.7.0').check_version!

module VCR
  # Contains middlewares for use with different libraries.
  module Middleware
    # Faraday middleware that VCR uses to record and replay HTTP requests made through
    # Faraday.
    #
    # @note You can either insert this middleware into the Faraday middleware stack
    #  yourself or configure {VCR::Configuration#hook_into} to hook into `:faraday`.
    class Faraday
      include VCR::Deprecations::Middleware::Faraday

      # Constructs a new instance of the Faraday middleware.
      #
      # @param [#call] app the faraday app
      def initialize(app)
        super
        @app = app
      end

      # Handles the HTTP request being made through Faraday
      #
      # @param [Hash] env the Faraday request env hash
      def call(env)
        return @app.call(env) if VCR.library_hooks.disabled?(:faraday)
        RequestHandler.new(@app, env).handle
      end

      # @private
      class RequestHandler < ::VCR::RequestHandler
        attr_reader :app, :env
        def initialize(app, env)
          @app, @env = app, env
          @has_on_complete_hook = false
        end

        def handle
          # Faraday must be exlusive here in case another library hook is being used.
          # We don't want double recording/double playback.
          VCR.library_hooks.exclusive_hook = :faraday
          super
        ensure
          response = defined?(@vcr_response) ? @vcr_response : nil
          invoke_after_request_hook(response) unless delay_finishing?
        end

      private

        def delay_finishing?
          !!env[:parallel_manager] && @has_on_complete_hook
        end

        def vcr_request
          @vcr_request ||= VCR::Request.new \
            env[:method],
            env[:url].to_s,
            raw_body_from(env[:body]),
            env[:request_headers]
        end

        def raw_body_from(body)
          return body unless body.respond_to?(:read)

          body.read.tap do |b|
            body.rewind if body.respond_to?(:rewind)
          end
        end

        def response_for(response)
          # reason_phrase is a new addition to Faraday::Response,
          # so maintain backward compatibility
          reason = response.respond_to?(:reason_phrase) ? response.reason_phrase : nil

          VCR::Response.new(
            VCR::ResponseStatus.new(response.status, reason),
            response.headers,
            raw_body_from(response.body),
            nil
          )
        end

        def on_ignored_request
          response = app.call(env)
          @vcr_response = response_for(response)
          response
        end

        def on_stubbed_by_vcr_request
          headers = env[:response_headers] ||= ::Faraday::Utils::Headers.new
          headers.update stubbed_response.headers if stubbed_response.headers
          env.update :status => stubbed_response.status.code, :body => stubbed_response.body

          @vcr_response = stubbed_response

          faraday_response = ::Faraday::Response.new
          faraday_response.finish(env)
          env[:response] = faraday_response
        end

        def on_recordable_request
          @has_on_complete_hook = true
          response = app.call(env)
          response.on_complete do
            @vcr_response = response_for(response)
            VCR.record_http_interaction(VCR::HTTPInteraction.new(vcr_request, @vcr_response))
            invoke_after_request_hook(@vcr_response) if delay_finishing?
          end
        end

        def invoke_after_request_hook(response)
          super
          VCR.library_hooks.exclusive_hook = nil
        end
      end
    end
  end
end