httparty2 0.7.10

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 (71) hide show
  1. data/.gitignore +9 -0
  2. data/Gemfile +6 -0
  3. data/History +253 -0
  4. data/MIT-LICENSE +20 -0
  5. data/README.rdoc +54 -0
  6. data/Rakefile +13 -0
  7. data/bin/httparty +108 -0
  8. data/cucumber.yml +1 -0
  9. data/examples/aaws.rb +32 -0
  10. data/examples/basic.rb +32 -0
  11. data/examples/custom_parsers.rb +67 -0
  12. data/examples/delicious.rb +37 -0
  13. data/examples/google.rb +16 -0
  14. data/examples/rubyurl.rb +14 -0
  15. data/examples/tripit_sign_in.rb +33 -0
  16. data/examples/twitter.rb +31 -0
  17. data/examples/whoismyrep.rb +10 -0
  18. data/features/basic_authentication.feature +20 -0
  19. data/features/command_line.feature +7 -0
  20. data/features/deals_with_http_error_codes.feature +26 -0
  21. data/features/digest_authentication.feature +20 -0
  22. data/features/handles_compressed_responses.feature +19 -0
  23. data/features/handles_multiple_formats.feature +34 -0
  24. data/features/steps/env.rb +22 -0
  25. data/features/steps/httparty_response_steps.rb +26 -0
  26. data/features/steps/httparty_steps.rb +27 -0
  27. data/features/steps/mongrel_helper.rb +94 -0
  28. data/features/steps/remote_service_steps.rb +69 -0
  29. data/features/supports_redirection.feature +22 -0
  30. data/features/supports_timeout_option.feature +13 -0
  31. data/httparty.gemspec +31 -0
  32. data/lib/httparty.rb +455 -0
  33. data/lib/httparty/cookie_hash.rb +22 -0
  34. data/lib/httparty/core_extensions.rb +9 -0
  35. data/lib/httparty/exceptions.rb +26 -0
  36. data/lib/httparty/module_inheritable_attributes.rb +34 -0
  37. data/lib/httparty/net_digest_auth.rb +71 -0
  38. data/lib/httparty/parser.rb +140 -0
  39. data/lib/httparty/request.rb +252 -0
  40. data/lib/httparty/response.rb +85 -0
  41. data/lib/httparty/version.rb +3 -0
  42. data/spec/fixtures/delicious.xml +23 -0
  43. data/spec/fixtures/empty.xml +0 -0
  44. data/spec/fixtures/google.html +3 -0
  45. data/spec/fixtures/ssl/generate.sh +29 -0
  46. data/spec/fixtures/ssl/generated/1fe462c2.0 +16 -0
  47. data/spec/fixtures/ssl/generated/bogushost.crt +13 -0
  48. data/spec/fixtures/ssl/generated/ca.crt +16 -0
  49. data/spec/fixtures/ssl/generated/ca.key +15 -0
  50. data/spec/fixtures/ssl/generated/selfsigned.crt +14 -0
  51. data/spec/fixtures/ssl/generated/server.crt +13 -0
  52. data/spec/fixtures/ssl/generated/server.key +15 -0
  53. data/spec/fixtures/ssl/openssl-exts.cnf +9 -0
  54. data/spec/fixtures/twitter.json +1 -0
  55. data/spec/fixtures/twitter.xml +403 -0
  56. data/spec/fixtures/undefined_method_add_node_for_nil.xml +2 -0
  57. data/spec/httparty/cookie_hash_spec.rb +71 -0
  58. data/spec/httparty/net_digest_auth_spec.rb +93 -0
  59. data/spec/httparty/parser_spec.rb +155 -0
  60. data/spec/httparty/request_spec.rb +496 -0
  61. data/spec/httparty/response_spec.rb +193 -0
  62. data/spec/httparty/ssl_spec.rb +54 -0
  63. data/spec/httparty_spec.rb +621 -0
  64. data/spec/spec.opts +3 -0
  65. data/spec/spec_helper.rb +23 -0
  66. data/spec/support/ssl_test_helper.rb +25 -0
  67. data/spec/support/ssl_test_server.rb +69 -0
  68. data/spec/support/stub_response.rb +30 -0
  69. data/website/css/common.css +47 -0
  70. data/website/index.html +73 -0
  71. metadata +206 -0
@@ -0,0 +1,26 @@
1
+ Then /it should return an? (\w+)$/ do |class_string|
2
+ @response_from_httparty.should be_an_instance_of(class_string.class)
3
+ end
4
+
5
+ Then /the return value should match '(.*)'/ do |expected_text|
6
+ @response_from_httparty.should eql(expected_text)
7
+ end
8
+
9
+ Then /it should return a Hash equaling:/ do |hash_table|
10
+ @response_from_httparty.should be_an_instance_of(Hash)
11
+ @response_from_httparty.keys.length.should eql(hash_table.rows.length)
12
+ hash_table.hashes.each do |pair|
13
+ key, value = pair["key"], pair["value"]
14
+ @response_from_httparty.keys.should include(key)
15
+ @response_from_httparty[key].should eql(value)
16
+ end
17
+ end
18
+
19
+ Then /it should return a response with a (\d+) response code/ do |code|
20
+ @response_from_httparty.code.should eql(code.to_i)
21
+ end
22
+
23
+ Then /it should raise (?:an|a) ([\w:]+) exception/ do |exception|
24
+ @exception_from_httparty.should_not be_nil
25
+ @exception_from_httparty.class.name.should eql(exception)
26
+ end
@@ -0,0 +1,27 @@
1
+ When /^I set my HTTParty timeout option to (\d+)$/ do |timeout|
2
+ @request_options[:timeout] = timeout.to_i
3
+ end
4
+
5
+ When /I call HTTParty#get with '(.*)'$/ do |url|
6
+ begin
7
+ @response_from_httparty = HTTParty.get("http://#{@host_and_port}#{url}", @request_options)
8
+ rescue HTTParty::RedirectionTooDeep, Timeout::Error => e
9
+ @exception_from_httparty = e
10
+ end
11
+ end
12
+
13
+ When /I call HTTParty#get with '(.*)' and a basic_auth hash:/ do |url, auth_table|
14
+ h = auth_table.hashes.first
15
+ @response_from_httparty = HTTParty.get(
16
+ "http://#{@host_and_port}#{url}",
17
+ :basic_auth => { :username => h["username"], :password => h["password"] }
18
+ )
19
+ end
20
+
21
+ When /I call HTTParty#get with '(.*)' and a digest_auth hash:/ do |url, auth_table|
22
+ h = auth_table.hashes.first
23
+ @response_from_httparty = HTTParty.get(
24
+ "http://#{@host_and_port}#{url}",
25
+ :digest_auth => { :username => h["username"], :password => h["password"] }
26
+ )
27
+ end
@@ -0,0 +1,94 @@
1
+ require 'base64'
2
+ class BasicMongrelHandler < Mongrel::HttpHandler
3
+ attr_accessor :content_type, :custom_headers, :response_body, :response_code, :preprocessor, :username, :password
4
+
5
+ def initialize
6
+ @content_type = "text/html"
7
+ @response_body = ""
8
+ @response_code = 200
9
+ @custom_headers = {}
10
+ end
11
+
12
+ def process(request, response)
13
+ preprocessor.call if preprocessor.is_a? Proc
14
+ reply_with(response, response_code, response_body)
15
+ end
16
+
17
+ def reply_with(response, code, response_body)
18
+ response.start(code) do |head, body|
19
+ head["Content-Type"] = content_type
20
+ custom_headers.each { |k,v| head[k] = v }
21
+ body.write(response_body)
22
+ end
23
+ end
24
+ end
25
+
26
+ class DeflateHandler < BasicMongrelHandler
27
+ def process(request, response)
28
+ response.start do |head, body|
29
+ head['Content-Encoding'] = 'deflate'
30
+ body.write Zlib::Deflate.deflate(response_body)
31
+ end
32
+ end
33
+ end
34
+
35
+ class GzipHandler < BasicMongrelHandler
36
+ def process(request, response)
37
+ response.start do |head, body|
38
+ head['Content-Encoding'] = 'gzip'
39
+ body.write gzip(response_body)
40
+ end
41
+ end
42
+
43
+ protected
44
+
45
+ def gzip(string)
46
+ sio = StringIO.new('', 'r+')
47
+ gz = Zlib::GzipWriter.new sio
48
+ gz.write string
49
+ gz.finish
50
+ sio.rewind
51
+ sio.read
52
+ end
53
+ end
54
+
55
+ module BasicAuthentication
56
+ def self.extended(base)
57
+ base.custom_headers["WWW-Authenticate"] = 'Basic Realm="Super Secret Page"'
58
+ end
59
+
60
+ def process(request, response)
61
+ if authorized?(request)
62
+ super
63
+ else
64
+ reply_with(response, 401, "Incorrect. You have 20 seconds to comply.")
65
+ end
66
+ end
67
+
68
+ def authorized?(request)
69
+ request.params["HTTP_AUTHORIZATION"] == "Basic " + Base64.encode64("#{@username}:#{@password}").strip
70
+ end
71
+ end
72
+
73
+ module DigestAuthentication
74
+ def self.extended(base)
75
+ base.custom_headers["WWW-Authenticate"] = 'Digest realm="testrealm@host.com",qop="auth,auth-int",nonce="nonce",opaque="opaque"'
76
+ end
77
+
78
+ def process(request, response)
79
+ if authorized?(request)
80
+ super
81
+ else
82
+ reply_with(response, 401, "Incorrect. You have 20 seconds to comply.")
83
+ end
84
+ end
85
+
86
+ def authorized?(request)
87
+ request.params["HTTP_AUTHORIZATION"] =~ /Digest.*uri=/
88
+ end
89
+ end
90
+
91
+ def new_mongrel_redirector(target_url, relative_path = false)
92
+ target_url = "http://#{@host_and_port}#{target_url}" unless relative_path
93
+ Mongrel::RedirectHandler.new(target_url)
94
+ end
@@ -0,0 +1,69 @@
1
+ Given /a remote service that returns '(.*)'/ do |response_body|
2
+ @handler = BasicMongrelHandler.new
3
+ Given "the response from the service has a body of '#{response_body}'"
4
+ end
5
+
6
+ Given /a remote service that returns a (\d+) status code/ do |code|
7
+ @handler = BasicMongrelHandler.new
8
+ @handler.response_code = code
9
+ end
10
+
11
+ Given /that service is accessed at the path '(.*)'/ do |path|
12
+ @server.register(path, @handler)
13
+ end
14
+
15
+ Given /^that service takes (\d+) seconds to generate a response$/ do |time|
16
+ @server_response_time = time.to_i
17
+ @handler.preprocessor = lambda { sleep time.to_i }
18
+ end
19
+
20
+ Given /^a remote deflate service$/ do
21
+ @handler = DeflateHandler.new
22
+ end
23
+
24
+ Given /^a remote gzip service$/ do
25
+ @handler = GzipHandler.new
26
+ end
27
+
28
+ Given /the response from the service has a Content-Type of '(.*)'/ do |content_type|
29
+ @handler.content_type = content_type
30
+ end
31
+
32
+ Given /the response from the service has a body of '(.*)'/ do |response_body|
33
+ @handler.response_body = response_body
34
+ end
35
+
36
+ Given /the url '(.*)' redirects to '(.*)'/ do |redirection_url, target_url|
37
+ @server.register redirection_url, new_mongrel_redirector(target_url)
38
+ end
39
+
40
+ Given /that service is protected by Basic Authentication/ do
41
+ @handler.extend BasicAuthentication
42
+ end
43
+
44
+ Given /that service is protected by Digest Authentication/ do
45
+ @handler.extend DigestAuthentication
46
+ end
47
+
48
+ Given /that service requires the username '(.*)' with the password '(.*)'/ do |username, password|
49
+ @handler.username = username
50
+ @handler.password = password
51
+ end
52
+
53
+ Given /a restricted page at '(.*)'/ do |url|
54
+ Given "a remote service that returns 'A response I will never see'"
55
+ And "that service is accessed at the path '#{url}'"
56
+ And "that service is protected by Basic Authentication"
57
+ And "that service requires the username 'something' with the password 'secret'"
58
+ end
59
+
60
+ # This joins the server thread, and halts cucumber, so you can actually hit the
61
+ # server with a browser. Runs until you kill it with Ctrl-c
62
+ Given /I want to hit this in a browser/ do
63
+ @server.acceptor.join
64
+ end
65
+
66
+ Then /I wait for the server to recover/ do
67
+ timeout = @request_options[:timeout] || 0
68
+ sleep @server_response_time - timeout
69
+ end
@@ -0,0 +1,22 @@
1
+ Feature: Supports Redirection
2
+
3
+ As a developer
4
+ I want to work with services that may redirect me
5
+ And I want it to follow a reasonable number of redirects
6
+ Because sometimes web services do that
7
+
8
+ Scenario: A service that redirects once
9
+ Given a remote service that returns 'Service Response'
10
+ And that service is accessed at the path '/landing_service.html'
11
+ And the url '/redirector.html' redirects to '/landing_service.html'
12
+ When I call HTTParty#get with '/redirector.html'
13
+ Then the return value should match 'Service Response'
14
+
15
+ # TODO: Look in to why this actually fails...
16
+ Scenario: A service that redirects to a relative URL
17
+
18
+ Scenario: A service that redirects infinitely
19
+ Given the url '/first.html' redirects to '/second.html'
20
+ And the url '/second.html' redirects to '/first.html'
21
+ When I call HTTParty#get with '/first.html'
22
+ Then it should raise an HTTParty::RedirectionTooDeep exception
@@ -0,0 +1,13 @@
1
+ Feature: Supports the timeout option
2
+ In order to handle inappropriately slow response times
3
+ As a developer
4
+ I want my request to raise an exception after my specified timeout has elapsed
5
+
6
+ Scenario: A long running response
7
+ Given a remote service that returns '<h1>Some HTML</h1>'
8
+ And that service is accessed at the path '/long_running_service.html'
9
+ And that service takes 2 seconds to generate a response
10
+ When I set my HTTParty timeout option to 1
11
+ And I call HTTParty#get with '/long_running_service.html'
12
+ Then it should raise a Timeout::Error exception
13
+ And I wait for the server to recover
@@ -0,0 +1,31 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "httparty/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "httparty2"
7
+ s.version = HTTParty::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Anderson De Andrade", "John Nunemaker", "Sandro Turriate"]
10
+ s.email = ["adeandradeds@gmail.com"]
11
+ s.homepage = "https://github.com/adeandrade/httparty"
12
+ s.summary = %q{Makes http fun! Also, makes consuming restful web services dead easy.}
13
+ s.description = %q{Makes http fun! Also, makes consuming restful web services dead easy.}
14
+
15
+ s.add_dependency "activesupport", "~> 3.0"
16
+ s.add_dependency "multi_json", "~> 1.0"
17
+ s.add_dependency "multi_xml", "~> 0.2"
18
+
19
+ s.add_development_dependency "activesupport", "~> 3.0"
20
+ s.add_development_dependency "cucumber", "~> 1.0"
21
+ s.add_development_dependency "fakeweb", "~> 1.2"
22
+ s.add_development_dependency "rspec", "~> 2.6"
23
+ s.add_development_dependency "mongrel", "= 1.2.0.pre2"
24
+
25
+ s.post_install_message = "When you HTTParty, you must party hard!"
26
+
27
+ s.files = `git ls-files`.split("\n")
28
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
29
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
30
+ s.require_paths = ["lib"]
31
+ end
@@ -0,0 +1,455 @@
1
+ require 'pathname'
2
+ require 'net/http'
3
+ require 'net/https'
4
+ require 'uri'
5
+ require 'zlib'
6
+ require 'active_support/core_ext/object/blank'
7
+ require 'active_support/core_ext/object/to_param'
8
+ require 'active_support/core_ext/object/to_query'
9
+ require 'multi_json'
10
+ require 'multi_xml'
11
+
12
+ require 'httparty/module_inheritable_attributes'
13
+ require 'httparty/cookie_hash'
14
+ require 'httparty/net_digest_auth'
15
+ require 'httparty/version'
16
+
17
+ # @see HTTParty::ClassMethods
18
+ module HTTParty
19
+ module AllowedFormatsDeprecation
20
+ def const_missing(const)
21
+ if const.to_s =~ /AllowedFormats$/
22
+ Kernel.warn("Deprecated: Use HTTParty::Parser::SupportedFormats")
23
+ HTTParty::Parser::SupportedFormats
24
+ else
25
+ super
26
+ end
27
+ end
28
+ end
29
+
30
+ extend AllowedFormatsDeprecation
31
+
32
+ def self.included(base)
33
+ base.extend ClassMethods
34
+ base.send :include, HTTParty::ModuleInheritableAttributes
35
+ base.send(:mattr_inheritable, :default_options)
36
+ base.send(:mattr_inheritable, :default_cookies)
37
+ base.instance_variable_set("@default_options", {})
38
+ base.instance_variable_set("@default_cookies", CookieHash.new)
39
+ end
40
+
41
+ # == Common Request Options
42
+ # Request methods (get, post, put, delete, head, options) all take a common set of options. These are:
43
+ #
44
+ # [:+body+:] Body of the request. If passed a Hash, will try to normalize it first, by default passing it to ActiveSupport::to_params. Any other kind of object will get used as-is.
45
+ # [:+http_proxyaddr+:] Address of proxy server to use.
46
+ # [:+http_proxyport+:] Port of proxy server to use.
47
+ # [:+limit+:] Maximum number of redirects to follow. Takes precedences over :+no_follow+.
48
+ # [:+query+:] Query string, or a Hash representing it. Normalized according to the same rules as :+body+. If you specify this on a POST, you must use a Hash. See also HTTParty::ClassMethods.default_params.
49
+ # [:+timeout+:] Timeout for opening connection and reading data.
50
+ #
51
+ # There are also another set of options with names corresponding to various class methods. The methods in question are those that let you set a class-wide default, and the options override the defaults on a request-by-request basis. Those options are:
52
+ # * :+base_uri+: see HTTParty::ClassMethods.base_uri.
53
+ # * :+basic_auth+: see HTTParty::ClassMethods.basic_auth. Only one of :+basic_auth+ and :+digest_auth+ can be used at a time; if you try using both, you'll get an ArgumentError.
54
+ # * :+debug_output+: see HTTParty::ClassMethods.debug_output.
55
+ # * :+digest_auth+: see HTTParty::ClassMethods.digest_auth. Only one of :+basic_auth+ and :+digest_auth+ can be used at a time; if you try using both, you'll get an ArgumentError.
56
+ # * :+format+: see HTTParty::ClassMethods.format.
57
+ # * :+headers+: see HTTParty::ClassMethods.headers. Must be a Hash.
58
+ # * :+maintain_method_across_redirects+: see HTTParty::ClassMethods.maintain_method_across_redirects.
59
+ # * :+no_follow+: see HTTParty::ClassMethods.no_follow.
60
+ # * :+parser+: see HTTParty::ClassMethods.parser.
61
+ # * :+pem+: see HTTParty::ClassMethods.pem.
62
+ # * :+query_string_normalizer+: see HTTParty::ClassMethods.query_string_normalizer
63
+ # * :+ssl_ca_file+: see HTTParty::ClassMethods.ssl_ca_file.
64
+
65
+ module ClassMethods
66
+
67
+ extend AllowedFormatsDeprecation
68
+
69
+ # Allows setting http proxy information to be used
70
+ #
71
+ # class Foo
72
+ # include HTTParty
73
+ # http_proxy 'http://foo.com', 80
74
+ # end
75
+ def http_proxy(addr=nil, port = nil)
76
+ default_options[:http_proxyaddr] = addr
77
+ default_options[:http_proxyport] = port
78
+ end
79
+
80
+ # Allows setting a base uri to be used for each request.
81
+ # Will normalize uri to include http, etc.
82
+ #
83
+ # class Foo
84
+ # include HTTParty
85
+ # base_uri 'twitter.com'
86
+ # end
87
+ def base_uri(uri=nil)
88
+ return default_options[:base_uri] unless uri
89
+ default_options[:base_uri] = HTTParty.normalize_base_uri(uri)
90
+ end
91
+
92
+ # Allows setting basic authentication username and password.
93
+ #
94
+ # class Foo
95
+ # include HTTParty
96
+ # basic_auth 'username', 'password'
97
+ # end
98
+ def basic_auth(u, p)
99
+ default_options[:basic_auth] = {:username => u, :password => p}
100
+ end
101
+
102
+ # Allows setting digest authentication username and password.
103
+ #
104
+ # class Foo
105
+ # include HTTParty
106
+ # digest_auth 'username', 'password'
107
+ # end
108
+ def digest_auth(u, p)
109
+ default_options[:digest_auth] = {:username => u, :password => p}
110
+ end
111
+
112
+ # Do not send rails style query strings.
113
+ # Specically, don't use bracket notation when sending an array
114
+ #
115
+ # For a query:
116
+ # get '/', :query => {:selected_ids => [1,2,3]}
117
+ #
118
+ # The default query string looks like this:
119
+ # /?selected_ids[]=1&selected_ids[]=2&selected_ids[]=3
120
+ #
121
+ # Call `disable_rails_query_string_format` to transform the query string
122
+ # into:
123
+ # /?selected_ids=1&selected_ids=2&selected_ids=3
124
+ #
125
+ # @example
126
+ # class Foo
127
+ # include HTTParty
128
+ # disable_rails_query_string_format
129
+ # end
130
+ def disable_rails_query_string_format
131
+ query_string_normalizer Request::NON_RAILS_QUERY_STRING_NORMALIZER
132
+ end
133
+
134
+ # Allows setting default parameters to be appended to each request.
135
+ # Great for api keys and such.
136
+ #
137
+ # class Foo
138
+ # include HTTParty
139
+ # default_params :api_key => 'secret', :another => 'foo'
140
+ # end
141
+ def default_params(h={})
142
+ raise ArgumentError, 'Default params must be a hash' unless h.is_a?(Hash)
143
+ default_options[:default_params] ||= {}
144
+ default_options[:default_params].merge!(h)
145
+ end
146
+
147
+ # Allows setting a default timeout for all HTTP calls
148
+ # Timeout is specified in seconds.
149
+ #
150
+ # class Foo
151
+ # include HTTParty
152
+ # default_timeout 10
153
+ # end
154
+ def default_timeout(t)
155
+ raise ArgumentError, 'Timeout must be an integer or float' unless t && (t.is_a?(Integer) || t.is_a?(Float))
156
+ default_options[:timeout] = t
157
+ end
158
+
159
+ # Set an output stream for debugging, defaults to $stderr.
160
+ # The output stream is passed on to Net::HTTP#set_debug_output.
161
+ #
162
+ # class Foo
163
+ # include HTTParty
164
+ # debug_output $stderr
165
+ # end
166
+ def debug_output(stream = $stderr)
167
+ default_options[:debug_output] = stream
168
+ end
169
+
170
+ # Allows setting HTTP headers to be used for each request.
171
+ #
172
+ # class Foo
173
+ # include HTTParty
174
+ # headers 'Accept' => 'text/html'
175
+ # end
176
+ def headers(h={})
177
+ raise ArgumentError, 'Headers must be a hash' unless h.is_a?(Hash)
178
+ default_options[:headers] ||= {}
179
+ default_options[:headers].merge!(h)
180
+ end
181
+
182
+ def cookies(h={})
183
+ raise ArgumentError, 'Cookies must be a hash' unless h.is_a?(Hash)
184
+ default_cookies.add_cookies(h)
185
+ end
186
+
187
+ # Proceed to the location header when an HTTP response dictates a redirect.
188
+ # Redirects are always followed by default.
189
+ #
190
+ # @example
191
+ # class Foo
192
+ # include HTTParty
193
+ # base_uri 'http://google.com'
194
+ # follow_redirects true
195
+ # end
196
+ def follow_redirects(value = true)
197
+ default_options[:follow_redirects] = value
198
+ end
199
+
200
+ # Allows setting the format with which to parse.
201
+ # Must be one of the allowed formats ie: json, xml
202
+ #
203
+ # class Foo
204
+ # include HTTParty
205
+ # format :json
206
+ # end
207
+ def format(f = nil)
208
+ if f.nil?
209
+ default_options[:format]
210
+ else
211
+ parser(Parser) if parser.nil?
212
+ default_options[:format] = f
213
+ validate_format
214
+ end
215
+ end
216
+
217
+ # Declare whether or not to follow redirects. When true, an
218
+ # {HTTParty::RedirectionTooDeep} error will raise upon encountering a
219
+ # redirect. You can then gain access to the response object via
220
+ # HTTParty::RedirectionTooDeep#response.
221
+ #
222
+ # @see HTTParty::ResponseError#response
223
+ #
224
+ # @example
225
+ # class Foo
226
+ # include HTTParty
227
+ # base_uri 'http://google.com'
228
+ # no_follow true
229
+ # end
230
+ #
231
+ # begin
232
+ # Foo.get('/')
233
+ # rescue HTTParty::RedirectionTooDeep => e
234
+ # puts e.response.body
235
+ # end
236
+ def no_follow(value = false)
237
+ default_options[:no_follow] = value
238
+ end
239
+
240
+ # Declare that you wish to maintain the chosen HTTP method across redirects.
241
+ # The default behavior is to follow redirects via the GET method.
242
+ # If you wish to maintain the original method, you can set this option to true.
243
+ #
244
+ # @example
245
+ # class Foo
246
+ # include HTTParty
247
+ # base_uri 'http://google.com'
248
+ # maintain_method_across_redirects true
249
+ # end
250
+
251
+ def maintain_method_across_redirects(value = true)
252
+ default_options[:maintain_method_across_redirects] = value
253
+ end
254
+
255
+ # Allows setting a PEM file to be used
256
+ #
257
+ # class Foo
258
+ # include HTTParty
259
+ # pem File.read('/home/user/my.pem'), "optional password"
260
+ # end
261
+ def pem(pem_contents, password=nil)
262
+ default_options[:pem] = pem_contents
263
+ default_options[:pem_password] = password
264
+ end
265
+
266
+ # Override the way query strings are normalized.
267
+ # Helpful for overriding the default rails normalization of Array queries.
268
+ #
269
+ # For a query:
270
+ # get '/', :query => {:selected_ids => [1,2,3]}
271
+ #
272
+ # The default query string normalizer returns:
273
+ # /?selected_ids[]=1&selected_ids[]=2&selected_ids[]=3
274
+ #
275
+ # Let's change it to this:
276
+ # /?selected_ids=1&selected_ids=2&selected_ids=3
277
+ #
278
+ # Pass a Proc to the query normalizer which accepts the yielded query.
279
+ #
280
+ # @example Modifying Array query strings
281
+ # class ServiceWrapper
282
+ # include HTTParty
283
+ #
284
+ # query_string_normalizer proc { |query|
285
+ # query.map do |key, value|
286
+ # value.map {|v| "#{key}=#{v}"}
287
+ # end.join('&')
288
+ # }
289
+ # end
290
+ #
291
+ # @param [Proc] normalizer custom query string normalizer.
292
+ # @yield [Hash, String] query string
293
+ # @yieldreturn [Array] an array that will later be joined with '&'
294
+ def query_string_normalizer(normalizer)
295
+ default_options[:query_string_normalizer] = normalizer
296
+ end
297
+
298
+ # Allows setting an OpenSSL certificate authority file
299
+ #
300
+ # class Foo
301
+ # include HTTParty
302
+ # ssl_ca_file '/etc/ssl/certs/ca-certificates.crt'
303
+ # end
304
+ def ssl_ca_file(path)
305
+ default_options[:ssl_ca_file] = path
306
+ end
307
+
308
+ # Allows setting an OpenSSL certificate authority path (directory)
309
+ #
310
+ # class Foo
311
+ # include HTTParty
312
+ # ssl_ca_path '/etc/ssl/certs/'
313
+ # end
314
+ def ssl_ca_path(path)
315
+ default_options[:ssl_ca_path] = path
316
+ end
317
+
318
+ # Allows setting a custom parser for the response.
319
+ #
320
+ # class Foo
321
+ # include HTTParty
322
+ # parser Proc.new {|data| ...}
323
+ # end
324
+ def parser(custom_parser = nil)
325
+ if custom_parser.nil?
326
+ default_options[:parser]
327
+ else
328
+ default_options[:parser] = custom_parser
329
+ validate_format
330
+ end
331
+ end
332
+
333
+ # Allows making a get request to a url.
334
+ #
335
+ # class Foo
336
+ # include HTTParty
337
+ # end
338
+ #
339
+ # # Simple get with full url
340
+ # Foo.get('http://foo.com/resource.json')
341
+ #
342
+ # # Simple get with full url and query parameters
343
+ # # ie: http://foo.com/resource.json?limit=10
344
+ # Foo.get('http://foo.com/resource.json', :query => {:limit => 10})
345
+ def get(path, options={})
346
+ perform_request Net::HTTP::Get, path, options
347
+ end
348
+
349
+ # Allows making a post request to a url.
350
+ #
351
+ # class Foo
352
+ # include HTTParty
353
+ # end
354
+ #
355
+ # # Simple post with full url and setting the body
356
+ # Foo.post('http://foo.com/resources', :body => {:bar => 'baz'})
357
+ #
358
+ # # Simple post with full url using :query option,
359
+ # # which gets set as form data on the request.
360
+ # Foo.post('http://foo.com/resources', :query => {:bar => 'baz'})
361
+ def post(path, options={})
362
+ perform_request Net::HTTP::Post, path, options
363
+ end
364
+
365
+ # Perform a PUT request to a path
366
+ def put(path, options={})
367
+ perform_request Net::HTTP::Put, path, options
368
+ end
369
+
370
+ # Perform a DELETE request to a path
371
+ def delete(path, options={})
372
+ perform_request Net::HTTP::Delete, path, options
373
+ end
374
+
375
+ # Perform a HEAD request to a path
376
+ def head(path, options={})
377
+ perform_request Net::HTTP::Head, path, options
378
+ end
379
+
380
+ # Perform an OPTIONS request to a path
381
+ def options(path, options={})
382
+ perform_request Net::HTTP::Options, path, options
383
+ end
384
+
385
+ def default_options #:nodoc:
386
+ @default_options
387
+ end
388
+
389
+ private
390
+
391
+ def perform_request(http_method, path, options) #:nodoc:
392
+ options = default_options.dup.merge(options)
393
+ process_cookies(options)
394
+ Request.new(http_method, path, options).perform
395
+ end
396
+
397
+ def process_cookies(options) #:nodoc:
398
+ return unless options[:cookies] || default_cookies.any?
399
+ options[:headers] ||= headers.dup
400
+ options[:headers]["cookie"] = cookies.merge(options.delete(:cookies) || {}).to_cookie_string
401
+ end
402
+
403
+ def validate_format
404
+ if format && parser.respond_to?(:supports_format?) && !parser.supports_format?(format)
405
+ raise UnsupportedFormat, "'#{format.inspect}' Must be one of: #{parser.supported_formats.map{|f| f.to_s}.sort.join(', ')}"
406
+ end
407
+ end
408
+ end
409
+
410
+ def self.normalize_base_uri(url) #:nodoc:
411
+ normalized_url = url.dup
412
+ use_ssl = (normalized_url =~ /^https/) || normalized_url.include?(':443')
413
+ ends_with_slash = normalized_url =~ /\/$/
414
+
415
+ normalized_url.chop! if ends_with_slash
416
+ normalized_url.gsub!(/^https?:\/\//i, '')
417
+
418
+ "http#{'s' if use_ssl}://#{normalized_url}"
419
+ end
420
+
421
+ class Basement #:nodoc:
422
+ include HTTParty
423
+ end
424
+
425
+ def self.get(*args)
426
+ Basement.get(*args)
427
+ end
428
+
429
+ def self.post(*args)
430
+ Basement.post(*args)
431
+ end
432
+
433
+ def self.put(*args)
434
+ Basement.put(*args)
435
+ end
436
+
437
+ def self.delete(*args)
438
+ Basement.delete(*args)
439
+ end
440
+
441
+ def self.head(*args)
442
+ Basement.head(*args)
443
+ end
444
+
445
+ def self.options(*args)
446
+ Basement.options(*args)
447
+ end
448
+
449
+ end
450
+
451
+ require 'httparty/core_extensions'
452
+ require 'httparty/exceptions'
453
+ require 'httparty/parser'
454
+ require 'httparty/request'
455
+ require 'httparty/response'