httsoiree 0.13.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +10 -0
  3. data/.travis.yml +7 -0
  4. data/Gemfile +14 -0
  5. data/Guardfile +16 -0
  6. data/History +303 -0
  7. data/MIT-LICENSE +20 -0
  8. data/README.md +77 -0
  9. data/Rakefile +12 -0
  10. data/bin/httparty +117 -0
  11. data/cucumber.yml +1 -0
  12. data/examples/aaws.rb +32 -0
  13. data/examples/basic.rb +28 -0
  14. data/examples/crack.rb +19 -0
  15. data/examples/custom_parsers.rb +67 -0
  16. data/examples/delicious.rb +37 -0
  17. data/examples/google.rb +16 -0
  18. data/examples/headers_and_user_agents.rb +6 -0
  19. data/examples/logging.rb +38 -0
  20. data/examples/nokogiri_html_parser.rb +22 -0
  21. data/examples/rubyurl.rb +14 -0
  22. data/examples/stackexchange.rb +24 -0
  23. data/examples/tripit_sign_in.rb +33 -0
  24. data/examples/twitter.rb +31 -0
  25. data/examples/whoismyrep.rb +10 -0
  26. data/features/basic_authentication.feature +20 -0
  27. data/features/command_line.feature +7 -0
  28. data/features/deals_with_http_error_codes.feature +26 -0
  29. data/features/digest_authentication.feature +20 -0
  30. data/features/handles_compressed_responses.feature +27 -0
  31. data/features/handles_multiple_formats.feature +57 -0
  32. data/features/steps/env.rb +22 -0
  33. data/features/steps/httparty_response_steps.rb +52 -0
  34. data/features/steps/httparty_steps.rb +43 -0
  35. data/features/steps/mongrel_helper.rb +94 -0
  36. data/features/steps/remote_service_steps.rb +74 -0
  37. data/features/supports_read_timeout_option.feature +13 -0
  38. data/features/supports_redirection.feature +22 -0
  39. data/features/supports_timeout_option.feature +13 -0
  40. data/httparty.gemspec +25 -0
  41. data/lib/httparty/connection_adapter.rb +188 -0
  42. data/lib/httparty/cookie_hash.rb +22 -0
  43. data/lib/httparty/core_extensions.rb +32 -0
  44. data/lib/httparty/exceptions.rb +29 -0
  45. data/lib/httparty/hash_conversions.rb +51 -0
  46. data/lib/httparty/logger/apache_logger.rb +22 -0
  47. data/lib/httparty/logger/curl_logger.rb +48 -0
  48. data/lib/httparty/logger/logger.rb +18 -0
  49. data/lib/httparty/module_inheritable_attributes.rb +56 -0
  50. data/lib/httparty/net_digest_auth.rb +84 -0
  51. data/lib/httparty/parser.rb +141 -0
  52. data/lib/httparty/request.rb +339 -0
  53. data/lib/httparty/response/headers.rb +31 -0
  54. data/lib/httparty/response.rb +72 -0
  55. data/lib/httparty/version.rb +3 -0
  56. data/lib/httparty.rb +618 -0
  57. data/lib/httsoiree.rb +3 -0
  58. data/script/release +42 -0
  59. data/spec/fixtures/delicious.xml +23 -0
  60. data/spec/fixtures/empty.xml +0 -0
  61. data/spec/fixtures/google.html +3 -0
  62. data/spec/fixtures/ssl/generate.sh +29 -0
  63. data/spec/fixtures/ssl/generated/1fe462c2.0 +16 -0
  64. data/spec/fixtures/ssl/generated/bogushost.crt +13 -0
  65. data/spec/fixtures/ssl/generated/ca.crt +16 -0
  66. data/spec/fixtures/ssl/generated/ca.key +15 -0
  67. data/spec/fixtures/ssl/generated/selfsigned.crt +14 -0
  68. data/spec/fixtures/ssl/generated/server.crt +13 -0
  69. data/spec/fixtures/ssl/generated/server.key +15 -0
  70. data/spec/fixtures/ssl/openssl-exts.cnf +9 -0
  71. data/spec/fixtures/twitter.csv +2 -0
  72. data/spec/fixtures/twitter.json +1 -0
  73. data/spec/fixtures/twitter.xml +403 -0
  74. data/spec/fixtures/undefined_method_add_node_for_nil.xml +2 -0
  75. data/spec/httparty/connection_adapter_spec.rb +370 -0
  76. data/spec/httparty/cookie_hash_spec.rb +83 -0
  77. data/spec/httparty/exception_spec.rb +23 -0
  78. data/spec/httparty/logger/apache_logger_spec.rb +41 -0
  79. data/spec/httparty/logger/curl_logger_spec.rb +18 -0
  80. data/spec/httparty/logger/logger_spec.rb +22 -0
  81. data/spec/httparty/net_digest_auth_spec.rb +152 -0
  82. data/spec/httparty/parser_spec.rb +165 -0
  83. data/spec/httparty/request_spec.rb +774 -0
  84. data/spec/httparty/response_spec.rb +221 -0
  85. data/spec/httparty/ssl_spec.rb +74 -0
  86. data/spec/httparty_spec.rb +783 -0
  87. data/spec/spec.opts +2 -0
  88. data/spec/spec_helper.rb +37 -0
  89. data/spec/support/ssl_test_helper.rb +47 -0
  90. data/spec/support/ssl_test_server.rb +80 -0
  91. data/spec/support/stub_response.rb +43 -0
  92. data/website/css/common.css +47 -0
  93. data/website/index.html +73 -0
  94. metadata +215 -0
@@ -0,0 +1,56 @@
1
+ module HTTParty
2
+ module ModuleInheritableAttributes #:nodoc:
3
+ def self.included(base)
4
+ base.extend(ClassMethods)
5
+ end
6
+
7
+ # borrowed from Rails 3.2 ActiveSupport
8
+ def self.hash_deep_dup(hash)
9
+ duplicate = hash.dup
10
+
11
+ duplicate.each_pair do |key, value|
12
+ duplicate[key] = if value.is_a?(Hash)
13
+ hash_deep_dup(value)
14
+ elsif value.is_a?(Proc)
15
+ duplicate[key] = value.dup
16
+ else
17
+ value
18
+ end
19
+ end
20
+
21
+ duplicate
22
+ end
23
+
24
+ module ClassMethods #:nodoc:
25
+ def mattr_inheritable(*args)
26
+ @mattr_inheritable_attrs ||= [:mattr_inheritable_attrs]
27
+ @mattr_inheritable_attrs += args
28
+
29
+ args.each do |arg|
30
+ module_eval %(class << self; attr_accessor :#{arg} end)
31
+ end
32
+
33
+ @mattr_inheritable_attrs
34
+ end
35
+
36
+ def inherited(subclass)
37
+ super
38
+ @mattr_inheritable_attrs.each do |inheritable_attribute|
39
+ ivar = "@#{inheritable_attribute}"
40
+ subclass.instance_variable_set(ivar, instance_variable_get(ivar).clone)
41
+
42
+ if instance_variable_get(ivar).respond_to?(:merge)
43
+ method = <<-EOM
44
+ def self.#{inheritable_attribute}
45
+ duplicate = ModuleInheritableAttributes.hash_deep_dup(#{ivar})
46
+ #{ivar} = superclass.#{inheritable_attribute}.merge(duplicate)
47
+ end
48
+ EOM
49
+
50
+ subclass.class_eval method
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,84 @@
1
+ require 'digest/md5'
2
+ require 'net/http'
3
+
4
+ module Net
5
+ module HTTPHeader
6
+ def digest_auth(username, password, response)
7
+ @header['Authorization'] = DigestAuthenticator.new(username, password,
8
+ @method, @path, response).authorization_header
9
+ end
10
+
11
+
12
+ class DigestAuthenticator
13
+ def initialize(username, password, method, path, response_header)
14
+ @username = username
15
+ @password = password
16
+ @method = method
17
+ @path = path
18
+ @response = parse(response_header)
19
+ end
20
+
21
+ def authorization_header
22
+ @cnonce = md5(random)
23
+ header = [
24
+ %Q(Digest username="#{@username}"),
25
+ %Q(realm="#{@response['realm']}"),
26
+ %Q(nonce="#{@response['nonce']}"),
27
+ %Q(uri="#{@path}"),
28
+ %Q(response="#{request_digest}"),
29
+ ]
30
+
31
+ if qop_present?
32
+ fields = [
33
+ %Q(cnonce="#{@cnonce}"),
34
+ %Q(qop="#{@response['qop']}"),
35
+ %Q(nc=00000001)
36
+ ]
37
+ fields.each { |field| header << field }
38
+ end
39
+
40
+ header << %Q(opaque="#{@response['opaque']}") if opaque_present?
41
+ header
42
+ end
43
+
44
+ private
45
+
46
+ def parse(response_header)
47
+ response_header['www-authenticate'] =~ /Digest (.*)/
48
+ params = {}
49
+ $1.gsub(/(\w+)="(.*?)"/) { params[$1] = $2 }
50
+ params
51
+ end
52
+
53
+ def opaque_present?
54
+ @response.has_key?('opaque') and not @response['opaque'].empty?
55
+ end
56
+
57
+ def qop_present?
58
+ @response.has_key?('qop') and not @response['qop'].empty?
59
+ end
60
+
61
+ def random
62
+ "%x" % (Time.now.to_i + rand(65535))
63
+ end
64
+
65
+ def request_digest
66
+ a = [md5(a1), @response['nonce'], md5(a2)]
67
+ a.insert(2, "00000001", @cnonce, @response['qop']) if qop_present?
68
+ md5(a.join(":"))
69
+ end
70
+
71
+ def md5(str)
72
+ Digest::MD5.hexdigest(str)
73
+ end
74
+
75
+ def a1
76
+ [@username, @response['realm'], @password].join(":")
77
+ end
78
+
79
+ def a2
80
+ [@method, @path].join(":")
81
+ end
82
+ end
83
+ end
84
+ 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.load(body, nil)
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,339 @@
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 = [URI::HTTP, URI::HTTPS, URI::Generic]
16
+
17
+ NON_RAILS_QUERY_STRING_NORMALIZER = Proc.new 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}=#{URI.encode(v.to_s, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))}"}
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.path = path
35
+ self.options = {
36
+ limit: o.delete(:no_follow) ? 1 : 5,
37
+ assume_utf16_is_big_endian: true,
38
+ default_params: {},
39
+ follow_redirects: true,
40
+ parser: Parser,
41
+ connection_adapter: ConnectionAdapter
42
+ }.merge(o)
43
+ end
44
+
45
+ def path=(uri)
46
+ @path = URI(uri)
47
+ end
48
+
49
+ def request_uri(uri)
50
+ if uri.respond_to? :request_uri
51
+ uri.request_uri
52
+ else
53
+ uri.path
54
+ end
55
+ end
56
+
57
+ def uri
58
+ new_uri = path.relative? ? URI.parse("#{base_uri}#{path}") : path.clone
59
+
60
+ # avoid double query string on redirects [#12]
61
+ unless redirect
62
+ new_uri.query = query_string(new_uri)
63
+ end
64
+
65
+ unless SupportedURISchemes.include? new_uri.class
66
+ raise UnsupportedURIScheme, "'#{new_uri}' Must be HTTP, HTTPS or Generic"
67
+ end
68
+
69
+ @last_uri = new_uri
70
+ end
71
+
72
+ def base_uri
73
+ redirect ? "#{@last_uri.scheme}://#{@last_uri.host}" : options[:base_uri]
74
+ end
75
+
76
+ def format
77
+ options[:format] || (format_from_mimetype(last_response['content-type']) if last_response)
78
+ end
79
+
80
+ def parser
81
+ options[:parser]
82
+ end
83
+
84
+ def connection_adapter
85
+ options[:connection_adapter]
86
+ end
87
+
88
+ def perform(&block)
89
+ validate
90
+ setup_raw_request
91
+ chunked_body = nil
92
+
93
+ self.last_response = http.request(@raw_request) do |http_response|
94
+ if block
95
+ chunks = []
96
+
97
+ http_response.read_body do |fragment|
98
+ chunks << fragment
99
+ block.call(fragment)
100
+ end
101
+
102
+ chunked_body = chunks.join
103
+ end
104
+ end
105
+
106
+ handle_deflation unless http_method == Net::HTTP::Head
107
+ handle_response(chunked_body, &block)
108
+ end
109
+
110
+ def raw_body
111
+ @raw_request.body
112
+ end
113
+
114
+ private
115
+
116
+ def http
117
+ connection_adapter.call(uri, options)
118
+ end
119
+
120
+ def body
121
+ options[:body].respond_to?(:to_hash) ? normalize_query(options[:body]) : options[:body]
122
+ end
123
+
124
+ def credentials
125
+ (options[:basic_auth] || options[:digest_auth]).to_hash
126
+ end
127
+
128
+ def username
129
+ credentials[:username]
130
+ end
131
+
132
+ def password
133
+ credentials[:password]
134
+ end
135
+
136
+ def normalize_query(query)
137
+ if query_string_normalizer
138
+ query_string_normalizer.call(query)
139
+ else
140
+ HashConversions.to_params(query)
141
+ end
142
+ end
143
+
144
+ def query_string_normalizer
145
+ options[:query_string_normalizer]
146
+ end
147
+
148
+ def setup_raw_request
149
+ @raw_request = http_method.new(request_uri(uri))
150
+ @raw_request.body = body if body
151
+ @raw_request.body_stream = options[:body_stream] if options[:body_stream]
152
+ @raw_request.initialize_http_header(options[:headers].to_hash) if options[:headers].respond_to?(:to_hash)
153
+ @raw_request.basic_auth(username, password) if options[:basic_auth]
154
+ setup_digest_auth if options[:digest_auth]
155
+ end
156
+
157
+ def setup_digest_auth
158
+ auth_request = http_method.new(uri.request_uri)
159
+ auth_request.initialize_http_header(options[:headers].to_hash) if options[:headers].respond_to?(:to_hash)
160
+ res = http.request(auth_request)
161
+
162
+ if res['www-authenticate'] != nil && res['www-authenticate'].length > 0
163
+ @raw_request.digest_auth(username, password, res)
164
+ end
165
+ end
166
+
167
+ def query_string(uri)
168
+ query_string_parts = []
169
+ query_string_parts << uri.query unless uri.query.nil?
170
+
171
+ if options[:query].respond_to?(:to_hash)
172
+ query_string_parts << normalize_query(options[:default_params].merge(options[:query].to_hash))
173
+ else
174
+ query_string_parts << normalize_query(options[:default_params]) unless options[:default_params].empty?
175
+ query_string_parts << options[:query] unless options[:query].nil?
176
+ end
177
+
178
+ query_string_parts.reject!(&:empty?) unless query_string_parts == [""]
179
+ query_string_parts.size > 0 ? query_string_parts.join('&') : nil
180
+ end
181
+
182
+ def get_charset
183
+ content_type = last_response["content-type"]
184
+ if content_type.nil?
185
+ return nil
186
+ end
187
+
188
+ if content_type =~ /;\s*charset\s*=\s*([^=,;"\s]+)/i
189
+ return $1
190
+ end
191
+
192
+ if content_type =~ /;\s*charset\s*=\s*"((\\.|[^\\"])+)"/i
193
+ return $1.gsub(/\\(.)/, '\1')
194
+ end
195
+
196
+ nil
197
+ end
198
+
199
+ def encode_with_ruby_encoding(body, charset)
200
+ begin
201
+ encoding = Encoding.find(charset)
202
+ body.force_encoding(encoding)
203
+ rescue
204
+ body
205
+ end
206
+ end
207
+
208
+ def assume_utf16_is_big_endian
209
+ options[:assume_utf16_is_big_endian]
210
+ end
211
+
212
+ def encode_utf_16(body)
213
+ if body.bytesize >= 2
214
+ if body.getbyte(0) == 0xFF && body.getbyte(1) == 0xFE
215
+ return body.force_encoding("UTF-16LE")
216
+ elsif body.getbyte(0) == 0xFE && body.getbyte(1) == 0xFF
217
+ return body.force_encoding("UTF-16BE")
218
+ end
219
+ end
220
+
221
+ if assume_utf16_is_big_endian
222
+ body.force_encoding("UTF-16BE")
223
+ else
224
+ body.force_encoding("UTF-16LE")
225
+ end
226
+
227
+ end
228
+
229
+ def _encode_body(body)
230
+ charset = get_charset
231
+
232
+ if charset.nil?
233
+ return body
234
+ end
235
+
236
+ if "utf-16".casecmp(charset) == 0
237
+ encode_utf_16(body)
238
+ else
239
+ encode_with_ruby_encoding(body, charset)
240
+ end
241
+ end
242
+
243
+ def encode_body(body)
244
+ if "".respond_to?(:encoding)
245
+ _encode_body(body)
246
+ else
247
+ body
248
+ end
249
+ end
250
+
251
+ def handle_response(body, &block)
252
+ if response_redirects?
253
+ options[:limit] -= 1
254
+ if options[:logger]
255
+ logger = HTTParty::Logger.build(options[:logger], options[:log_level], options[:log_format])
256
+ logger.format(self, last_response)
257
+ end
258
+ self.path = last_response['location']
259
+ self.redirect = true
260
+ if last_response.class == Net::HTTPSeeOther
261
+ unless options[:maintain_method_across_redirects] and options[:resend_on_redirect]
262
+ self.http_method = Net::HTTP::Get
263
+ end
264
+ else
265
+ unless options[:maintain_method_across_redirects]
266
+ self.http_method = Net::HTTP::Get
267
+ end
268
+ end
269
+ capture_cookies(last_response)
270
+ perform(&block)
271
+ else
272
+ body = body || last_response.body
273
+ body = encode_body(body)
274
+ Response.new(self, last_response, lambda { parse_response(body) }, body: body)
275
+ end
276
+ end
277
+
278
+ # Inspired by Ruby 1.9
279
+ def handle_deflation
280
+ case last_response["content-encoding"]
281
+ when "gzip", "x-gzip"
282
+ body_io = StringIO.new(last_response.body)
283
+ last_response.body.replace Zlib::GzipReader.new(body_io).read
284
+ last_response.delete('content-encoding')
285
+ when "deflate"
286
+ last_response.body.replace Zlib::Inflate.inflate(last_response.body)
287
+ last_response.delete('content-encoding')
288
+ end
289
+ end
290
+
291
+ def response_redirects?
292
+ case last_response
293
+ when Net::HTTPMultipleChoice, # 300
294
+ Net::HTTPMovedPermanently, # 301
295
+ Net::HTTPFound, # 302
296
+ Net::HTTPSeeOther, # 303
297
+ Net::HTTPUseProxy, # 305
298
+ Net::HTTPTemporaryRedirect
299
+ options[:follow_redirects] && last_response.key?('location')
300
+ end
301
+ end
302
+
303
+ def parse_response(body)
304
+ parser.call(body, format)
305
+ end
306
+
307
+ def capture_cookies(response)
308
+ return unless response['Set-Cookie']
309
+ cookies_hash = HTTParty::CookieHash.new()
310
+ cookies_hash.add_cookies(options[:headers].to_hash['Cookie']) if options[:headers] && options[:headers].to_hash['Cookie']
311
+ response.get_fields('Set-Cookie').each { |cookie| cookies_hash.add_cookies(cookie) }
312
+ options[:headers] ||= {}
313
+ options[:headers]['Cookie'] = cookies_hash.to_cookie_string
314
+ end
315
+
316
+ # Uses the HTTP Content-Type header to determine the format of the
317
+ # response It compares the MIME type returned to the types stored in the
318
+ # SupportedFormats hash
319
+ def format_from_mimetype(mimetype)
320
+ if mimetype && parser.respond_to?(:format_from_mimetype)
321
+ parser.format_from_mimetype(mimetype)
322
+ end
323
+ end
324
+
325
+ def validate
326
+ raise HTTParty::RedirectionTooDeep.new(last_response), 'HTTP redirects too deep' if options[:limit].to_i <= 0
327
+ raise ArgumentError, 'only get, post, patch, put, delete, head, and options methods are supported' unless SupportedHTTPMethods.include?(http_method)
328
+ raise ArgumentError, ':headers must be a hash' if options[:headers] && !options[:headers].respond_to?(:to_hash)
329
+ raise ArgumentError, 'only one authentication method, :basic_auth or :digest_auth may be used at a time' if options[:basic_auth] && options[:digest_auth]
330
+ raise ArgumentError, ':basic_auth must be a hash' if options[:basic_auth] && !options[:basic_auth].respond_to?(:to_hash)
331
+ raise ArgumentError, ':digest_auth must be a hash' if options[:digest_auth] && !options[:digest_auth].respond_to?(:to_hash)
332
+ raise ArgumentError, ':query must be hash if using HTTP Post' if post? && !options[:query].nil? && !options[:query].respond_to?(:to_hash)
333
+ end
334
+
335
+ def post?
336
+ Net::HTTP::Post == http_method
337
+ end
338
+ end
339
+ end
@@ -0,0 +1,31 @@
1
+ module HTTParty
2
+ class Response #:nodoc:
3
+ class Headers
4
+ include ::Net::HTTPHeader
5
+
6
+ def initialize(header = {})
7
+ @header = header
8
+ end
9
+
10
+ def ==(other)
11
+ @header == other
12
+ end
13
+
14
+ def inspect
15
+ @header.inspect
16
+ end
17
+
18
+ def method_missing(name, *args, &block)
19
+ if @header.respond_to?(name)
20
+ @header.send(name, *args, &block)
21
+ else
22
+ super
23
+ end
24
+ end
25
+
26
+ def respond_to?(method, include_all = false)
27
+ super || @header.respond_to?(method, include_all)
28
+ end
29
+ end
30
+ end
31
+ end