Module: WebMockHTTPClients

Included in:
WebMockHTTPClient, WebMockJSONClient
Defined in:
lib/webmock/http_lib_adapters/httpclient_adapter.rb

Constant Summary collapse

WEBMOCK_HTTPCLIENT_RESPONSES =
:webmock_httpclient_responses
WEBMOCK_HTTPCLIENT_REQUEST_SIGNATURES =
:webmock_httpclient_request_signatures
REQUEST_RESPONSE_LOCK =
Mutex.new

Instance Method Summary collapse

Instance Method Details

#build_httpclient_response(webmock_response, stream = false, req_header = nil, &block) ⇒ Object

Raises:

  • (HTTPClient::TimeoutError)
[View source] [View on GitHub]

125
126
127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/webmock/http_lib_adapters/httpclient_adapter.rb', line 125

def build_httpclient_response(webmock_response, stream = false, req_header = nil, &block)
  body = stream ? StringIO.new(webmock_response.body) : webmock_response.body
  response = HTTP::Message.new_response(body, req_header)
  response.header.init_response(webmock_response.status[0])
  response.reason=webmock_response.status[1]
  webmock_response.headers.to_a.each { |name, value| response.header.set(name, value) }

  raise HTTPClient::TimeoutError if webmock_response.should_timeout
  webmock_response.raise_error_if_any

  block.call(response, body) if block && body && body.bytesize > 0

  response
end

#build_request_signature(req, reuse_existing = false) ⇒ Object

[View source] [View on GitHub]

167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
# File 'lib/webmock/http_lib_adapters/httpclient_adapter.rb', line 167

def build_request_signature(req, reuse_existing = false)
  @request_filter.each do |filter|
    filter.filter_request(req)
  end

  uri = WebMock::Util::URI.heuristic_parse(req.header.request_uri.to_s)
  uri.query = WebMock::Util::QueryMapper.values_to_query(req.header.request_query, notation: WebMock::Config.instance.query_values_notation) if req.header.request_query
  uri.port = req.header.request_uri.port

  headers = req.header.all.inject({}) do |hdrs, header|
    hdrs[header[0]] ||= []
    hdrs[header[0]] << header[1]
    hdrs
  end
  headers = headers_from_session(uri).merge(headers)

  signature = WebMock::RequestSignature.new(
    req.header.request_method.downcase.to_sym,
    uri.to_s,
    body: req.http_body.dump,
    headers: headers
  )

  # reuse a previous identical signature object if we stored one for later use
  if reuse_existing && previous_signature = previous_signature_for(signature)
    return previous_signature
  end

  signature
end

#build_webmock_response(httpclient_response, body = nil) ⇒ Object

[View source] [View on GitHub]

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
# File 'lib/webmock/http_lib_adapters/httpclient_adapter.rb', line 140

def build_webmock_response(httpclient_response, body = nil)
  webmock_response = WebMock::Response.new
  webmock_response.status = [httpclient_response.status, httpclient_response.reason]

  webmock_response.headers = {}.tap do |hash|
    httpclient_response.header.all.each do |(key, value)|
      if hash.has_key?(key)
        hash[key] = Array(hash[key]) + [value]
      else
        hash[key] = value
      end
    end
  end

  if body
    webmock_response.body = body
  elsif httpclient_response.content.respond_to?(:read)
    webmock_response.body = httpclient_response.content.read
    body = HTTP::Message::Body.new
    body.init_response(StringIO.new(webmock_response.body))
    httpclient_response.body = body
  else
    webmock_response.body = httpclient_response.content
  end
  webmock_response
end

#do_get(req, proxy, conn, stream = false, &block) ⇒ Object

[View source] [View on GitHub]

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
# File 'lib/webmock/http_lib_adapters/httpclient_adapter.rb', line 61

def do_get(req, proxy, conn, stream = false, &block)
  clear_thread_variables unless conn.async_thread

  request_signature = build_request_signature(req, :reuse_existing)

  WebMock::RequestRegistry.instance.requested_signatures.put(request_signature)

  if webmock_responses[request_signature]
    webmock_response = webmock_responses.delete(request_signature)
    response = build_httpclient_response(webmock_response, stream, req.header, &block)
    @request_filter.each do |filter|
      filter.filter_response(req, response)
    end
    res = conn.push(response)
    WebMock::CallbackRegistry.invoke_callbacks(
      {lib: :httpclient}, request_signature, webmock_response)
    res
  elsif WebMock.net_connect_allowed?(request_signature.uri)
    # in case there is a nil entry in the hash...
    webmock_responses.delete(request_signature)

    res = if stream
      do_get_stream_without_webmock(req, proxy, conn, &block)
    elsif block
      body = ''
      do_get_block_without_webmock(req, proxy, conn) do |http_res, chunk|
        if chunk && chunk.bytesize > 0
          body += chunk
          block.call(http_res, chunk)
        end
      end
    else
      do_get_block_without_webmock(req, proxy, conn)
    end
    res = conn.pop
    conn.push(res)
    if WebMock::CallbackRegistry.any_callbacks?
      webmock_response = build_webmock_response(res, body)
      WebMock::CallbackRegistry.invoke_callbacks(
        {lib: :httpclient, real_request: true}, request_signature,
        webmock_response)
    end
    res
  else
    raise WebMock::NetConnectNotAllowedError.new(request_signature)
  end
end

#do_get_block(req, proxy, conn, &block) ⇒ Object

[View source] [View on GitHub]

53
54
55
# File 'lib/webmock/http_lib_adapters/httpclient_adapter.rb', line 53

def do_get_block(req, proxy, conn, &block)
  do_get(req, proxy, conn, false, &block)
end

#do_get_stream(req, proxy, conn, &block) ⇒ Object

[View source] [View on GitHub]

57
58
59
# File 'lib/webmock/http_lib_adapters/httpclient_adapter.rb', line 57

def do_get_stream(req, proxy, conn, &block)
  do_get(req, proxy, conn, true, &block)
end

#do_request_async(method, uri, query, body, extheader) ⇒ Object

[View source] [View on GitHub]

109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/webmock/http_lib_adapters/httpclient_adapter.rb', line 109

def do_request_async(method, uri, query, body, extheader)
  clear_thread_variables
  req = create_request(method, uri, query, body, extheader)
  request_signature = build_request_signature(req)
  webmock_request_signatures << request_signature

  if webmock_responses[request_signature] || WebMock.net_connect_allowed?(request_signature.uri)
    conn = super
    conn.async_thread[WEBMOCK_HTTPCLIENT_REQUEST_SIGNATURES] = Thread.current[WEBMOCK_HTTPCLIENT_REQUEST_SIGNATURES]
    conn.async_thread[WEBMOCK_HTTPCLIENT_RESPONSES] = Thread.current[WEBMOCK_HTTPCLIENT_RESPONSES]
    conn
  else
    raise WebMock::NetConnectNotAllowedError.new(request_signature)
  end
end

#previous_signature_for(signature) ⇒ Object

[View source] [View on GitHub]

208
209
210
211
# File 'lib/webmock/http_lib_adapters/httpclient_adapter.rb', line 208

def previous_signature_for(signature)
  return nil unless index = webmock_request_signatures.index(signature)
  webmock_request_signatures.delete_at(index)
end

#webmock_request_signaturesObject

[View source] [View on GitHub]

204
205
206
# File 'lib/webmock/http_lib_adapters/httpclient_adapter.rb', line 204

def webmock_request_signatures
  Thread.current[WEBMOCK_HTTPCLIENT_REQUEST_SIGNATURES] ||= []
end

#webmock_responsesObject

[View source] [View on GitHub]

198
199
200
201
202
# File 'lib/webmock/http_lib_adapters/httpclient_adapter.rb', line 198

def webmock_responses
  Thread.current[WEBMOCK_HTTPCLIENT_RESPONSES] ||= Hash.new do |hash, request_signature|
    hash[request_signature] = WebMock::StubRegistry.instance.response_for_request(request_signature)
  end
end