File: typhoeus.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 (149 lines) | stat: -rw-r--r-- 5,036 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
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
require 'vcr/util/version_checker'
require 'vcr/request_handler'
require 'typhoeus'

if Float(Typhoeus::VERSION[/^\d+\.\d+/]) < 0.5
  require 'vcr/library_hooks/typhoeus_0.4'
else
  VCR::VersionChecker.new('Typhoeus', Typhoeus::VERSION, '0.5.0').check_version!

  module VCR
    class LibraryHooks
      # @private
      module Typhoeus
        # @private
        class RequestHandler < ::VCR::RequestHandler
          attr_reader :request
          def initialize(request)
            @request = request
            request.block_connection = false if VCR.turned_on?
          end

          def vcr_request
            @vcr_request ||= VCR::Request.new \
              request.options.fetch(:method, :get),
              request.url,
              request_body,
              request.options.fetch(:headers, {})
          end

        private

          def externally_stubbed?
            ::Typhoeus::Expectation.find_by(request)
          end

          def set_typed_request_for_after_hook(*args)
            super
            request.instance_variable_set(:@__typed_vcr_request, @after_hook_typed_request)
          end

          def on_unhandled_request
            invoke_after_request_hook(nil)
            super
          end

          def on_stubbed_by_vcr_request
            response = ::Typhoeus::Response.new \
              :http_version   => stubbed_response.http_version,
              :code           => stubbed_response.status.code,
              :status_message => stubbed_response.status.message,
              :headers        => stubbed_response_headers,
              :body           => stubbed_response.body,
              :effective_url  => stubbed_response.adapter_metadata.fetch('effective_url', request.url),
              :mock           => true

            first_header_line = "HTTP/#{stubbed_response.http_version} #{response.code} #{response.status_message}\r\n"
            response.instance_variable_set(:@first_header_line, first_header_line)
            response.instance_variable_get(:@options)[:response_headers] =
              first_header_line + response.headers.map { |k,v| "#{k}: #{v}"}.join("\r\n")

            response
          end

          def stubbed_response_headers
            @stubbed_response_headers ||= {}.tap do |hash|
              stubbed_response.headers.each do |key, values|
                hash[key] = values.size == 1 ? values.first : values
              end if stubbed_response.headers
            end
          end

          if ::Typhoeus::Request.method_defined?(:encoded_body)
            def request_body
              request.encoded_body
            end
          else
            def request_body
              request.options.fetch(:body, "")
            end
          end
        end

        # @private
        class << self
          def vcr_response_from(response)
            VCR::Response.new \
              VCR::ResponseStatus.new(response.code, response.status_message),
              response.headers,
              response.body,
              response.http_version,
              { "effective_url" => response.effective_url }
          end

          def collect_chunks(request)
            chunks = ''
            request.on_body.unshift(
              Proc.new do |body, response|
                chunks += body
                request.instance_variable_set(:@chunked_body, chunks)
              end
            )
          end

          def restore_body_from_chunks(response, request)
            response.options[:response_body] = request.instance_variable_get(:@chunked_body)
          end
        end

        ::Typhoeus.on_complete do |response|
          request = response.request

          restore_body_from_chunks(response, request) if request.streaming?

          unless VCR.library_hooks.disabled?(:typhoeus)
            vcr_response = vcr_response_from(response)
            typed_vcr_request = request.send(:remove_instance_variable, :@__typed_vcr_request)

            unless request.response.mock
              http_interaction = VCR::HTTPInteraction.new(typed_vcr_request, vcr_response)
              VCR.record_http_interaction(http_interaction)
            end

            VCR.configuration.invoke_hook(:after_http_request, typed_vcr_request, vcr_response)
          end
        end

        ::Typhoeus.before do |request|
          collect_chunks(request) if request.streaming?
          if response = VCR::LibraryHooks::Typhoeus::RequestHandler.new(request).handle
            request.on_headers.each { |cb| cb.call(response) }
            request.on_body.each { |cb| cb.call(response.body, response) }
            request.finish(response)
          else
            true
          end
        end
      end
    end
  end
end

VCR.configuration.after_library_hooks_loaded do
  # ensure WebMock's Typhoeus adapter does not conflict with us here
  # (i.e. to double record requests or whatever).
  if defined?(WebMock::HttpLibAdapters::TyphoeusAdapter)
    WebMock::HttpLibAdapters::TyphoeusAdapter.disable!
  end
end