httpserious 0.13.5.lstoll1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (100) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +11 -0
  3. data/.rubocop.yml +92 -0
  4. data/.rubocop_todo.yml +124 -0
  5. data/.simplecov +1 -0
  6. data/.travis.yml +7 -0
  7. data/CONTRIBUTING.md +23 -0
  8. data/Gemfile +19 -0
  9. data/Guardfile +16 -0
  10. data/History +370 -0
  11. data/MIT-LICENSE +20 -0
  12. data/README.md +78 -0
  13. data/Rakefile +10 -0
  14. data/bin/httparty +116 -0
  15. data/cucumber.yml +1 -0
  16. data/examples/README.md +67 -0
  17. data/examples/aaws.rb +32 -0
  18. data/examples/basic.rb +28 -0
  19. data/examples/crack.rb +19 -0
  20. data/examples/custom_parsers.rb +64 -0
  21. data/examples/delicious.rb +37 -0
  22. data/examples/google.rb +16 -0
  23. data/examples/headers_and_user_agents.rb +6 -0
  24. data/examples/logging.rb +36 -0
  25. data/examples/nokogiri_html_parser.rb +19 -0
  26. data/examples/rescue_json.rb +17 -0
  27. data/examples/rubyurl.rb +14 -0
  28. data/examples/stackexchange.rb +24 -0
  29. data/examples/tripit_sign_in.rb +33 -0
  30. data/examples/twitter.rb +31 -0
  31. data/examples/whoismyrep.rb +10 -0
  32. data/features/basic_authentication.feature +20 -0
  33. data/features/command_line.feature +90 -0
  34. data/features/deals_with_http_error_codes.feature +26 -0
  35. data/features/digest_authentication.feature +20 -0
  36. data/features/handles_compressed_responses.feature +27 -0
  37. data/features/handles_multiple_formats.feature +57 -0
  38. data/features/steps/env.rb +27 -0
  39. data/features/steps/httparty_response_steps.rb +52 -0
  40. data/features/steps/httparty_steps.rb +43 -0
  41. data/features/steps/mongrel_helper.rb +94 -0
  42. data/features/steps/remote_service_steps.rb +86 -0
  43. data/features/supports_read_timeout_option.feature +13 -0
  44. data/features/supports_redirection.feature +22 -0
  45. data/features/supports_timeout_option.feature +13 -0
  46. data/httparty.gemspec +28 -0
  47. data/httpserious.gemspec +25 -0
  48. data/lib/httparty.rb +612 -0
  49. data/lib/httparty/connection_adapter.rb +190 -0
  50. data/lib/httparty/cookie_hash.rb +21 -0
  51. data/lib/httparty/exceptions.rb +29 -0
  52. data/lib/httparty/hash_conversions.rb +49 -0
  53. data/lib/httparty/logger/apache_formatter.rb +22 -0
  54. data/lib/httparty/logger/curl_formatter.rb +48 -0
  55. data/lib/httparty/logger/logger.rb +26 -0
  56. data/lib/httparty/module_inheritable_attributes.rb +56 -0
  57. data/lib/httparty/net_digest_auth.rb +117 -0
  58. data/lib/httparty/parser.rb +141 -0
  59. data/lib/httparty/request.rb +361 -0
  60. data/lib/httparty/response.rb +77 -0
  61. data/lib/httparty/response/headers.rb +31 -0
  62. data/lib/httparty/version.rb +3 -0
  63. data/lib/httpserious.rb +1 -0
  64. data/script/release +42 -0
  65. data/spec/fixtures/delicious.xml +23 -0
  66. data/spec/fixtures/empty.xml +0 -0
  67. data/spec/fixtures/google.html +3 -0
  68. data/spec/fixtures/ssl/generate.sh +29 -0
  69. data/spec/fixtures/ssl/generated/1fe462c2.0 +16 -0
  70. data/spec/fixtures/ssl/generated/bogushost.crt +13 -0
  71. data/spec/fixtures/ssl/generated/ca.crt +16 -0
  72. data/spec/fixtures/ssl/generated/ca.key +15 -0
  73. data/spec/fixtures/ssl/generated/selfsigned.crt +14 -0
  74. data/spec/fixtures/ssl/generated/server.crt +13 -0
  75. data/spec/fixtures/ssl/generated/server.key +15 -0
  76. data/spec/fixtures/ssl/openssl-exts.cnf +9 -0
  77. data/spec/fixtures/twitter.csv +2 -0
  78. data/spec/fixtures/twitter.json +1 -0
  79. data/spec/fixtures/twitter.xml +403 -0
  80. data/spec/fixtures/undefined_method_add_node_for_nil.xml +2 -0
  81. data/spec/httparty/connection_adapter_spec.rb +468 -0
  82. data/spec/httparty/cookie_hash_spec.rb +83 -0
  83. data/spec/httparty/exception_spec.rb +38 -0
  84. data/spec/httparty/hash_conversions_spec.rb +41 -0
  85. data/spec/httparty/logger/apache_formatter_spec.rb +41 -0
  86. data/spec/httparty/logger/curl_formatter_spec.rb +18 -0
  87. data/spec/httparty/logger/logger_spec.rb +38 -0
  88. data/spec/httparty/net_digest_auth_spec.rb +191 -0
  89. data/spec/httparty/parser_spec.rb +167 -0
  90. data/spec/httparty/request_spec.rb +872 -0
  91. data/spec/httparty/response_spec.rb +241 -0
  92. data/spec/httparty/ssl_spec.rb +74 -0
  93. data/spec/httparty_spec.rb +823 -0
  94. data/spec/spec_helper.rb +59 -0
  95. data/spec/support/ssl_test_helper.rb +47 -0
  96. data/spec/support/ssl_test_server.rb +80 -0
  97. data/spec/support/stub_response.rb +43 -0
  98. data/website/css/common.css +47 -0
  99. data/website/index.html +73 -0
  100. metadata +219 -0
@@ -0,0 +1,117 @@
1
+ require 'digest/md5'
2
+ require 'net/http'
3
+
4
+ module Net
5
+ module HTTPHeader
6
+ def digest_auth(username, password, response)
7
+ authenticator = DigestAuthenticator.new(
8
+ username,
9
+ password,
10
+ @method,
11
+ @path,
12
+ response
13
+ )
14
+
15
+ @header['Authorization'] = authenticator.authorization_header
16
+ @header['cookie'] = append_cookies(authenticator) if response['Set-Cookie']
17
+ end
18
+
19
+ def append_cookies(authenticator)
20
+ cookies = @header['cookie'] ? @header['cookie'] : []
21
+ cookies.concat(authenticator.cookie_header)
22
+ end
23
+
24
+ class DigestAuthenticator
25
+ def initialize(username, password, method, path, response_header)
26
+ @username = username
27
+ @password = password
28
+ @method = method
29
+ @path = path
30
+ @response = parse(response_header)
31
+ @cookies = parse_cookies(response_header)
32
+ end
33
+
34
+ def authorization_header
35
+ @cnonce = md5(random)
36
+ header = [
37
+ %(Digest username="#{@username}"),
38
+ %(realm="#{@response['realm']}"),
39
+ %(nonce="#{@response['nonce']}"),
40
+ %(uri="#{@path}"),
41
+ %(response="#{request_digest}")
42
+ ]
43
+
44
+ if qop_present?
45
+ fields = [
46
+ %(cnonce="#{@cnonce}"),
47
+ %(qop="#{@response['qop']}"),
48
+ "nc=00000001"
49
+ ]
50
+ fields.each { |field| header << field }
51
+ end
52
+
53
+ header << %(opaque="#{@response['opaque']}") if opaque_present?
54
+ header
55
+ end
56
+
57
+ def cookie_header
58
+ @cookies
59
+ end
60
+
61
+ private
62
+
63
+ def parse(response_header)
64
+ header = response_header['www-authenticate']
65
+ .gsub(/qop=(auth(?:-int)?)/, 'qop="\\1"')
66
+
67
+ header =~ /Digest (.*)/
68
+ params = {}
69
+ $1.gsub(/(\w+)="(.*?)"/) { params[$1] = $2 }
70
+ params
71
+ end
72
+
73
+ def parse_cookies(response_header)
74
+ return [] unless response_header['Set-Cookie']
75
+
76
+ cookies = response_header['Set-Cookie'].split('; ')
77
+
78
+ cookies.reduce([]) do |ret, cookie|
79
+ ret << cookie
80
+ ret
81
+ end
82
+
83
+ cookies
84
+ end
85
+
86
+ def opaque_present?
87
+ @response.key?('opaque') && !@response['opaque'].empty?
88
+ end
89
+
90
+ def qop_present?
91
+ @response.key?('qop') && !@response['qop'].empty?
92
+ end
93
+
94
+ def random
95
+ format "%x", (Time.now.to_i + rand(65535))
96
+ end
97
+
98
+ def request_digest
99
+ a = [md5(a1), @response['nonce'], md5(a2)]
100
+ a.insert(2, "00000001", @cnonce, @response['qop']) if qop_present?
101
+ md5(a.join(":"))
102
+ end
103
+
104
+ def md5(str)
105
+ Digest::MD5.hexdigest(str)
106
+ end
107
+
108
+ def a1
109
+ [@username, @response['realm'], @password].join(":")
110
+ end
111
+
112
+ def a2
113
+ [@method, @path].join(":")
114
+ end
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,141 @@
1
+ module HTTParty
2
+ # The default parser used by HTTParty, supports xml, json, html, csv and
3
+ # plain text.
4
+ #
5
+ # == Custom Parsers
6
+ #
7
+ # If you'd like to do your own custom parsing, subclassing HTTParty::Parser
8
+ # will make that process much easier. There are a few different ways you can
9
+ # utilize HTTParty::Parser as a superclass.
10
+ #
11
+ # @example Intercept the parsing for all formats
12
+ # class SimpleParser < HTTParty::Parser
13
+ # def parse
14
+ # perform_parsing
15
+ # end
16
+ # end
17
+ #
18
+ # @example Add the atom format and parsing method to the default parser
19
+ # class AtomParsingIncluded < HTTParty::Parser
20
+ # SupportedFormats.merge!(
21
+ # {"application/atom+xml" => :atom}
22
+ # )
23
+ #
24
+ # def atom
25
+ # perform_atom_parsing
26
+ # end
27
+ # end
28
+ #
29
+ # @example Only support the atom format
30
+ # class ParseOnlyAtom < HTTParty::Parser
31
+ # SupportedFormats = {"application/atom+xml" => :atom}
32
+ #
33
+ # def atom
34
+ # perform_atom_parsing
35
+ # end
36
+ # end
37
+ #
38
+ # @abstract Read the Custom Parsers section for more information.
39
+ class Parser
40
+ SupportedFormats = {
41
+ 'text/xml' => :xml,
42
+ 'application/xml' => :xml,
43
+ 'application/json' => :json,
44
+ 'text/json' => :json,
45
+ 'application/javascript' => :plain,
46
+ 'text/javascript' => :plain,
47
+ 'text/html' => :html,
48
+ 'text/plain' => :plain,
49
+ 'text/csv' => :csv,
50
+ 'application/csv' => :csv,
51
+ 'text/comma-separated-values' => :csv
52
+ }
53
+
54
+ # The response body of the request
55
+ # @return [String]
56
+ attr_reader :body
57
+
58
+ # The intended parsing format for the request
59
+ # @return [Symbol] e.g. :json
60
+ attr_reader :format
61
+
62
+ # Instantiate the parser and call {#parse}.
63
+ # @param [String] body the response body
64
+ # @param [Symbol] format the response format
65
+ # @return parsed response
66
+ def self.call(body, format)
67
+ new(body, format).parse
68
+ end
69
+
70
+ # @return [Hash] the SupportedFormats hash
71
+ def self.formats
72
+ const_get(:SupportedFormats)
73
+ end
74
+
75
+ # @param [String] mimetype response MIME type
76
+ # @return [Symbol]
77
+ # @return [nil] mime type not supported
78
+ def self.format_from_mimetype(mimetype)
79
+ formats[formats.keys.detect {|k| mimetype.include?(k)}]
80
+ end
81
+
82
+ # @return [Array<Symbol>] list of supported formats
83
+ def self.supported_formats
84
+ formats.values.uniq
85
+ end
86
+
87
+ # @param [Symbol] format e.g. :json, :xml
88
+ # @return [Boolean]
89
+ def self.supports_format?(format)
90
+ supported_formats.include?(format)
91
+ end
92
+
93
+ def initialize(body, format)
94
+ @body = body
95
+ @format = format
96
+ end
97
+
98
+ # @return [Object] the parsed body
99
+ # @return [nil] when the response body is nil, an empty string, spaces only or "null"
100
+ def parse
101
+ return nil if body.nil? || body.strip.empty? || body == "null"
102
+ if supports_format?
103
+ parse_supported_format
104
+ else
105
+ body
106
+ end
107
+ end
108
+
109
+ protected
110
+
111
+ def xml
112
+ MultiXml.parse(body)
113
+ end
114
+
115
+ def json
116
+ JSON.parse(body, :quirks_mode => true, :allow_nan => true)
117
+ end
118
+
119
+ def csv
120
+ CSV.parse(body)
121
+ end
122
+
123
+ def html
124
+ body
125
+ end
126
+
127
+ def plain
128
+ body
129
+ end
130
+
131
+ def supports_format?
132
+ self.class.supports_format?(format)
133
+ end
134
+
135
+ def parse_supported_format
136
+ send(format)
137
+ rescue NoMethodError => e
138
+ raise NotImplementedError, "#{self.class.name} has not implemented a parsing method for the #{format.inspect} format.", e.backtrace
139
+ end
140
+ end
141
+ end
@@ -0,0 +1,361 @@
1
+ module HTTParty
2
+ class Request #:nodoc:
3
+ SupportedHTTPMethods = [
4
+ Net::HTTP::Get,
5
+ Net::HTTP::Post,
6
+ Net::HTTP::Patch,
7
+ Net::HTTP::Put,
8
+ Net::HTTP::Delete,
9
+ Net::HTTP::Head,
10
+ Net::HTTP::Options,
11
+ Net::HTTP::Move,
12
+ Net::HTTP::Copy
13
+ ]
14
+
15
+ SupportedURISchemes = ['http', 'https', 'webcal', nil]
16
+
17
+ NON_RAILS_QUERY_STRING_NORMALIZER = proc do |query|
18
+ Array(query).sort_by { |a| a[0].to_s }.map do |key, value|
19
+ if value.nil?
20
+ key.to_s
21
+ elsif value.respond_to?(:to_ary)
22
+ value.to_ary.map {|v| "#{key}=#{ERB::Util.url_encode(v.to_s)}"}
23
+ else
24
+ HashConversions.to_params(key => value)
25
+ end
26
+ end.flatten.join('&')
27
+ end
28
+
29
+ attr_accessor :http_method, :options, :last_response, :redirect, :last_uri
30
+ attr_reader :path
31
+
32
+ def initialize(http_method, path, o = {})
33
+ self.http_method = http_method
34
+ self.options = {
35
+ limit: o.delete(:no_follow) ? 1 : 5,
36
+ assume_utf16_is_big_endian: true,
37
+ default_params: {},
38
+ follow_redirects: true,
39
+ parser: Parser,
40
+ uri_adapter: URI,
41
+ connection_adapter: ConnectionAdapter
42
+ }.merge(o)
43
+ self.path = path
44
+ set_basic_auth_from_uri
45
+ end
46
+
47
+ def path=(uri)
48
+ uri_adapter = options[:uri_adapter]
49
+
50
+ @path = if uri.is_a?(uri_adapter)
51
+ uri
52
+ elsif String.try_convert(uri)
53
+ uri_adapter.parse uri
54
+ else
55
+ raise ArgumentError,
56
+ "bad argument (expected #{uri_adapter} object or URI string)"
57
+ end
58
+ end
59
+
60
+ def request_uri(uri)
61
+ if uri.respond_to? :request_uri
62
+ uri.request_uri
63
+ else
64
+ uri.path
65
+ end
66
+ end
67
+
68
+ def uri
69
+ if redirect && path.relative? && path.path[0] != "/"
70
+ last_uri_host = @last_uri.path.gsub(/[^\/]+$/, "")
71
+
72
+ path.path = "/#{path.path}" if last_uri_host[-1] != "/"
73
+ path.path = last_uri_host + path.path
74
+ end
75
+
76
+ new_uri = path.relative? ? options[:uri_adapter].parse("#{base_uri}#{path}") : path.clone
77
+
78
+ # avoid double query string on redirects [#12]
79
+ unless redirect
80
+ new_uri.query = query_string(new_uri)
81
+ end
82
+
83
+ unless SupportedURISchemes.include? new_uri.scheme
84
+ raise UnsupportedURIScheme, "'#{new_uri}' Must be HTTP, HTTPS or Generic"
85
+ end
86
+
87
+ @last_uri = new_uri
88
+ end
89
+
90
+ def base_uri
91
+ redirect ? "#{@last_uri.scheme}://#{@last_uri.host}" : options[:base_uri]
92
+ end
93
+
94
+ def format
95
+ options[:format] || (format_from_mimetype(last_response['content-type']) if last_response)
96
+ end
97
+
98
+ def parser
99
+ options[:parser]
100
+ end
101
+
102
+ def connection_adapter
103
+ options[:connection_adapter]
104
+ end
105
+
106
+ def perform(&block)
107
+ validate
108
+ setup_raw_request
109
+ chunked_body = nil
110
+
111
+ self.last_response = http.request(@raw_request) do |http_response|
112
+ if block
113
+ chunks = []
114
+
115
+ http_response.read_body do |fragment|
116
+ chunks << fragment unless options[:stream_body]
117
+ block.call(fragment)
118
+ end
119
+
120
+ chunked_body = chunks.join
121
+ end
122
+ end
123
+
124
+ handle_deflation unless http_method == Net::HTTP::Head
125
+ handle_response(chunked_body, &block)
126
+ end
127
+
128
+ def raw_body
129
+ @raw_request.body
130
+ end
131
+
132
+ private
133
+
134
+ def http
135
+ connection_adapter.call(uri, options)
136
+ end
137
+
138
+ def body
139
+ options[:body].respond_to?(:to_hash) ? normalize_query(options[:body]) : options[:body]
140
+ end
141
+
142
+ def credentials
143
+ (options[:basic_auth] || options[:digest_auth]).to_hash
144
+ end
145
+
146
+ def username
147
+ credentials[:username]
148
+ end
149
+
150
+ def password
151
+ credentials[:password]
152
+ end
153
+
154
+ def normalize_query(query)
155
+ if query_string_normalizer
156
+ query_string_normalizer.call(query)
157
+ else
158
+ HashConversions.to_params(query)
159
+ end
160
+ end
161
+
162
+ def query_string_normalizer
163
+ options[:query_string_normalizer]
164
+ end
165
+
166
+ def setup_raw_request
167
+ @raw_request = http_method.new(request_uri(uri))
168
+ @raw_request.body = body if body
169
+ @raw_request.body_stream = options[:body_stream] if options[:body_stream]
170
+ @raw_request.initialize_http_header(options[:headers].to_hash) if options[:headers].respond_to?(:to_hash)
171
+ @raw_request.basic_auth(username, password) if options[:basic_auth]
172
+ setup_digest_auth if options[:digest_auth]
173
+ end
174
+
175
+ def setup_digest_auth
176
+ auth_request = http_method.new(uri.request_uri)
177
+ auth_request.initialize_http_header(options[:headers].to_hash) if options[:headers].respond_to?(:to_hash)
178
+ res = http.request(auth_request)
179
+
180
+ if !res['www-authenticate'].nil? && res['www-authenticate'].length > 0
181
+ @raw_request.digest_auth(username, password, res)
182
+ end
183
+ end
184
+
185
+ def query_string(uri)
186
+ query_string_parts = []
187
+ query_string_parts << uri.query unless uri.query.nil?
188
+
189
+ if options[:query].respond_to?(:to_hash)
190
+ query_string_parts << normalize_query(options[:default_params].merge(options[:query].to_hash))
191
+ else
192
+ query_string_parts << normalize_query(options[:default_params]) unless options[:default_params].empty?
193
+ query_string_parts << options[:query] unless options[:query].nil?
194
+ end
195
+
196
+ query_string_parts.reject!(&:empty?) unless query_string_parts == [""]
197
+ query_string_parts.size > 0 ? query_string_parts.join('&') : nil
198
+ end
199
+
200
+ def get_charset
201
+ content_type = last_response["content-type"]
202
+ if content_type.nil?
203
+ return nil
204
+ end
205
+
206
+ if content_type =~ /;\s*charset\s*=\s*([^=,;"\s]+)/i
207
+ return $1
208
+ end
209
+
210
+ if content_type =~ /;\s*charset\s*=\s*"((\\.|[^\\"])+)"/i
211
+ return $1.gsub(/\\(.)/, '\1')
212
+ end
213
+
214
+ nil
215
+ end
216
+
217
+ def encode_with_ruby_encoding(body, charset)
218
+ encoding = Encoding.find(charset)
219
+ body.force_encoding(encoding)
220
+ rescue
221
+ body
222
+ end
223
+
224
+ def assume_utf16_is_big_endian
225
+ options[:assume_utf16_is_big_endian]
226
+ end
227
+
228
+ def encode_utf_16(body)
229
+ if body.bytesize >= 2
230
+ if body.getbyte(0) == 0xFF && body.getbyte(1) == 0xFE
231
+ return body.force_encoding("UTF-16LE")
232
+ elsif body.getbyte(0) == 0xFE && body.getbyte(1) == 0xFF
233
+ return body.force_encoding("UTF-16BE")
234
+ end
235
+ end
236
+
237
+ if assume_utf16_is_big_endian
238
+ body.force_encoding("UTF-16BE")
239
+ else
240
+ body.force_encoding("UTF-16LE")
241
+ end
242
+ end
243
+
244
+ def _encode_body(body)
245
+ charset = get_charset
246
+
247
+ if charset.nil?
248
+ return body
249
+ end
250
+
251
+ if "utf-16".casecmp(charset) == 0
252
+ encode_utf_16(body)
253
+ else
254
+ encode_with_ruby_encoding(body, charset)
255
+ end
256
+ end
257
+
258
+ def encode_body(body)
259
+ if "".respond_to?(:encoding)
260
+ _encode_body(body)
261
+ else
262
+ body
263
+ end
264
+ end
265
+
266
+ def handle_response(body, &block)
267
+ if response_redirects?
268
+ options[:limit] -= 1
269
+ if options[:logger]
270
+ logger = HTTParty::Logger.build(options[:logger], options[:log_level], options[:log_format])
271
+ logger.format(self, last_response)
272
+ end
273
+ self.path = last_response['location']
274
+ self.redirect = true
275
+ if last_response.class == Net::HTTPSeeOther
276
+ unless options[:maintain_method_across_redirects] && options[:resend_on_redirect]
277
+ self.http_method = Net::HTTP::Get
278
+ end
279
+ else
280
+ unless options[:maintain_method_across_redirects]
281
+ self.http_method = Net::HTTP::Get
282
+ end
283
+ end
284
+ capture_cookies(last_response)
285
+ perform(&block)
286
+ else
287
+ body ||= last_response.body
288
+ body = encode_body(body)
289
+ Response.new(self, last_response, lambda { parse_response(body) }, body: body)
290
+ end
291
+ end
292
+
293
+ # Inspired by Ruby 1.9
294
+ def handle_deflation
295
+ case last_response["content-encoding"]
296
+ when "gzip", "x-gzip"
297
+ body_io = StringIO.new(last_response.body)
298
+ last_response.body.replace Zlib::GzipReader.new(body_io).read
299
+ last_response.delete('content-encoding')
300
+ when "deflate"
301
+ last_response.body.replace Zlib::Inflate.inflate(last_response.body)
302
+ last_response.delete('content-encoding')
303
+ end
304
+ end
305
+
306
+ def response_redirects?
307
+ case last_response
308
+ when Net::HTTPMultipleChoice, # 300
309
+ Net::HTTPMovedPermanently, # 301
310
+ Net::HTTPFound, # 302
311
+ Net::HTTPSeeOther, # 303
312
+ Net::HTTPUseProxy, # 305
313
+ Net::HTTPTemporaryRedirect
314
+ options[:follow_redirects] && last_response.key?('location')
315
+ end
316
+ end
317
+
318
+ def parse_response(body)
319
+ parser.call(body, format)
320
+ end
321
+
322
+ def capture_cookies(response)
323
+ return unless response['Set-Cookie']
324
+ cookies_hash = HTTParty::CookieHash.new
325
+ cookies_hash.add_cookies(options[:headers].to_hash['Cookie']) if options[:headers] && options[:headers].to_hash['Cookie']
326
+ response.get_fields('Set-Cookie').each { |cookie| cookies_hash.add_cookies(cookie) }
327
+ options[:headers] ||= {}
328
+ options[:headers]['Cookie'] = cookies_hash.to_cookie_string
329
+ end
330
+
331
+ # Uses the HTTP Content-Type header to determine the format of the
332
+ # response It compares the MIME type returned to the types stored in the
333
+ # SupportedFormats hash
334
+ def format_from_mimetype(mimetype)
335
+ if mimetype && parser.respond_to?(:format_from_mimetype)
336
+ parser.format_from_mimetype(mimetype)
337
+ end
338
+ end
339
+
340
+ def validate
341
+ raise HTTParty::RedirectionTooDeep.new(last_response), 'HTTP redirects too deep' if options[:limit].to_i <= 0
342
+ raise ArgumentError, 'only get, post, patch, put, delete, head, and options methods are supported' unless SupportedHTTPMethods.include?(http_method)
343
+ raise ArgumentError, ':headers must be a hash' if options[:headers] && !options[:headers].respond_to?(:to_hash)
344
+ raise ArgumentError, 'only one authentication method, :basic_auth or :digest_auth may be used at a time' if options[:basic_auth] && options[:digest_auth]
345
+ raise ArgumentError, ':basic_auth must be a hash' if options[:basic_auth] && !options[:basic_auth].respond_to?(:to_hash)
346
+ raise ArgumentError, ':digest_auth must be a hash' if options[:digest_auth] && !options[:digest_auth].respond_to?(:to_hash)
347
+ raise ArgumentError, ':query must be hash if using HTTP Post' if post? && !options[:query].nil? && !options[:query].respond_to?(:to_hash)
348
+ end
349
+
350
+ def post?
351
+ Net::HTTP::Post == http_method
352
+ end
353
+
354
+ def set_basic_auth_from_uri
355
+ if path.userinfo
356
+ username, password = path.userinfo.split(':')
357
+ options[:basic_auth] = {username: username, password: password}
358
+ end
359
+ end
360
+ end
361
+ end