httsoiree 0.13.1

Sign up to get free protection for your applications and to get access to all the features.
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