dnclabs-httparty 0.6.1.2010090201

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. data/.gitignore +7 -0
  2. data/History +216 -0
  3. data/MIT-LICENSE +20 -0
  4. data/Manifest +47 -0
  5. data/README.rdoc +54 -0
  6. data/Rakefile +89 -0
  7. data/VERSION +1 -0
  8. data/bin/httparty +108 -0
  9. data/cucumber.yml +1 -0
  10. data/examples/aaws.rb +32 -0
  11. data/examples/basic.rb +11 -0
  12. data/examples/custom_parsers.rb +67 -0
  13. data/examples/delicious.rb +37 -0
  14. data/examples/google.rb +16 -0
  15. data/examples/rubyurl.rb +14 -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 +23 -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 +146 -0
  32. data/lib/httparty.rb +365 -0
  33. data/lib/httparty/cookie_hash.rb +22 -0
  34. data/lib/httparty/core_extensions.rb +31 -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 +35 -0
  38. data/lib/httparty/parser.rb +141 -0
  39. data/lib/httparty/request.rb +231 -0
  40. data/lib/httparty/response.rb +79 -0
  41. data/spec/fixtures/delicious.xml +23 -0
  42. data/spec/fixtures/empty.xml +0 -0
  43. data/spec/fixtures/google.html +3 -0
  44. data/spec/fixtures/ssl/generate.sh +29 -0
  45. data/spec/fixtures/ssl/generated/1fe462c2.0 +15 -0
  46. data/spec/fixtures/ssl/generated/bogushost.crt +13 -0
  47. data/spec/fixtures/ssl/generated/ca.crt +15 -0
  48. data/spec/fixtures/ssl/generated/ca.key +15 -0
  49. data/spec/fixtures/ssl/generated/selfsigned.crt +14 -0
  50. data/spec/fixtures/ssl/generated/server.crt +13 -0
  51. data/spec/fixtures/ssl/generated/server.key +15 -0
  52. data/spec/fixtures/ssl/openssl-exts.cnf +9 -0
  53. data/spec/fixtures/twitter.json +1 -0
  54. data/spec/fixtures/twitter.xml +403 -0
  55. data/spec/fixtures/undefined_method_add_node_for_nil.xml +2 -0
  56. data/spec/httparty/cookie_hash_spec.rb +71 -0
  57. data/spec/httparty/parser_spec.rb +155 -0
  58. data/spec/httparty/request_spec.rb +430 -0
  59. data/spec/httparty/response_spec.rb +188 -0
  60. data/spec/httparty/ssl_spec.rb +54 -0
  61. data/spec/httparty_spec.rb +570 -0
  62. data/spec/spec.opts +3 -0
  63. data/spec/spec_helper.rb +20 -0
  64. data/spec/support/ssl_test_helper.rb +25 -0
  65. data/spec/support/ssl_test_server.rb +69 -0
  66. data/spec/support/stub_response.rb +30 -0
  67. data/website/css/common.css +47 -0
  68. data/website/index.html +73 -0
  69. metadata +245 -0
@@ -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
+ instance_eval &preprocessor if preprocessor
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 as 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
data/httparty.gemspec ADDED
@@ -0,0 +1,146 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{httparty}
8
+ s.version = "0.6.1.hmac"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["John Nunemaker", "Sandro Turriate"]
12
+ s.date = %q{2010-08-12}
13
+ s.default_executable = %q{httparty}
14
+ s.description = %q{Makes http fun! Also, makes consuming restful web services dead easy.}
15
+ s.email = %q{nunemaker@gmail.com}
16
+ s.executables = ["httparty"]
17
+ s.extra_rdoc_files = [
18
+ "README.rdoc"
19
+ ]
20
+ s.files = [
21
+ ".gitignore",
22
+ "History",
23
+ "MIT-LICENSE",
24
+ "Manifest",
25
+ "README.rdoc",
26
+ "Rakefile",
27
+ "VERSION",
28
+ "bin/httparty",
29
+ "cucumber.yml",
30
+ "examples/aaws.rb",
31
+ "examples/basic.rb",
32
+ "examples/custom_parsers.rb",
33
+ "examples/delicious.rb",
34
+ "examples/google.rb",
35
+ "examples/rubyurl.rb",
36
+ "examples/twitter.rb",
37
+ "examples/whoismyrep.rb",
38
+ "features/basic_authentication.feature",
39
+ "features/command_line.feature",
40
+ "features/deals_with_http_error_codes.feature",
41
+ "features/digest_authentication.feature",
42
+ "features/handles_compressed_responses.feature",
43
+ "features/handles_multiple_formats.feature",
44
+ "features/steps/env.rb",
45
+ "features/steps/httparty_response_steps.rb",
46
+ "features/steps/httparty_steps.rb",
47
+ "features/steps/mongrel_helper.rb",
48
+ "features/steps/remote_service_steps.rb",
49
+ "features/supports_redirection.feature",
50
+ "features/supports_timeout_option.feature",
51
+ "httparty.gemspec",
52
+ "lib/httparty.rb",
53
+ "lib/httparty/cookie_hash.rb",
54
+ "lib/httparty/core_extensions.rb",
55
+ "lib/httparty/exceptions.rb",
56
+ "lib/httparty/module_inheritable_attributes.rb",
57
+ "lib/httparty/net_digest_auth.rb",
58
+ "lib/httparty/parser.rb",
59
+ "lib/httparty/request.rb",
60
+ "lib/httparty/response.rb",
61
+ "spec/fixtures/delicious.xml",
62
+ "spec/fixtures/empty.xml",
63
+ "spec/fixtures/google.html",
64
+ "spec/fixtures/ssl/generate.sh",
65
+ "spec/fixtures/ssl/generated/1fe462c2.0",
66
+ "spec/fixtures/ssl/generated/bogushost.crt",
67
+ "spec/fixtures/ssl/generated/ca.crt",
68
+ "spec/fixtures/ssl/generated/ca.key",
69
+ "spec/fixtures/ssl/generated/selfsigned.crt",
70
+ "spec/fixtures/ssl/generated/server.crt",
71
+ "spec/fixtures/ssl/generated/server.key",
72
+ "spec/fixtures/ssl/openssl-exts.cnf",
73
+ "spec/fixtures/twitter.json",
74
+ "spec/fixtures/twitter.xml",
75
+ "spec/fixtures/undefined_method_add_node_for_nil.xml",
76
+ "spec/httparty/cookie_hash_spec.rb",
77
+ "spec/httparty/parser_spec.rb",
78
+ "spec/httparty/request_spec.rb",
79
+ "spec/httparty/response_spec.rb",
80
+ "spec/httparty/ssl_spec.rb",
81
+ "spec/httparty_spec.rb",
82
+ "spec/spec.opts",
83
+ "spec/spec_helper.rb",
84
+ "spec/support/ssl_test_helper.rb",
85
+ "spec/support/ssl_test_server.rb",
86
+ "spec/support/stub_response.rb",
87
+ "website/css/common.css",
88
+ "website/index.html"
89
+ ]
90
+ s.homepage = %q{http://httparty.rubyforge.org}
91
+ s.post_install_message = %q{When you HTTParty, you must party hard!}
92
+ s.rdoc_options = ["--charset=UTF-8"]
93
+ s.require_paths = ["lib"]
94
+ s.rubyforge_project = %q{httparty}
95
+ s.rubygems_version = %q{1.3.7}
96
+ s.summary = %q{Makes http fun! Also, makes consuming restful web services dead easy.}
97
+ s.test_files = [
98
+ "spec/httparty/cookie_hash_spec.rb",
99
+ "spec/httparty/parser_spec.rb",
100
+ "spec/httparty/request_spec.rb",
101
+ "spec/httparty/response_spec.rb",
102
+ "spec/httparty/ssl_spec.rb",
103
+ "spec/httparty_spec.rb",
104
+ "spec/spec_helper.rb",
105
+ "spec/support/ssl_test_helper.rb",
106
+ "spec/support/ssl_test_server.rb",
107
+ "spec/support/stub_response.rb",
108
+ "examples/aaws.rb",
109
+ "examples/basic.rb",
110
+ "examples/custom_parsers.rb",
111
+ "examples/delicious.rb",
112
+ "examples/google.rb",
113
+ "examples/rubyurl.rb",
114
+ "examples/twitter.rb",
115
+ "examples/whoismyrep.rb"
116
+ ]
117
+
118
+ if s.respond_to? :specification_version then
119
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
120
+ s.specification_version = 3
121
+
122
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
123
+ s.add_runtime_dependency(%q<crack>, ["= 0.1.8"])
124
+ s.add_development_dependency(%q<activesupport>, ["~> 2.3"])
125
+ s.add_development_dependency(%q<cucumber>, ["~> 0.7"])
126
+ s.add_development_dependency(%q<fakeweb>, ["~> 1.2"])
127
+ s.add_development_dependency(%q<mongrel>, ["~> 1.1"])
128
+ s.add_development_dependency(%q<rspec>, ["~> 1.3"])
129
+ else
130
+ s.add_dependency(%q<crack>, ["= 0.1.8"])
131
+ s.add_dependency(%q<activesupport>, ["~> 2.3"])
132
+ s.add_dependency(%q<cucumber>, ["~> 0.7"])
133
+ s.add_dependency(%q<fakeweb>, ["~> 1.2"])
134
+ s.add_dependency(%q<mongrel>, ["~> 1.1"])
135
+ s.add_dependency(%q<rspec>, ["~> 1.3"])
136
+ end
137
+ else
138
+ s.add_dependency(%q<crack>, ["= 0.1.8"])
139
+ s.add_dependency(%q<activesupport>, ["~> 2.3"])
140
+ s.add_dependency(%q<cucumber>, ["~> 0.7"])
141
+ s.add_dependency(%q<fakeweb>, ["~> 1.2"])
142
+ s.add_dependency(%q<mongrel>, ["~> 1.1"])
143
+ s.add_dependency(%q<rspec>, ["~> 1.3"])
144
+ end
145
+ end
146
+
data/lib/httparty.rb ADDED
@@ -0,0 +1,365 @@
1
+ require 'pathname'
2
+ require 'net/http'
3
+ require 'net/https'
4
+ require 'uri'
5
+ require 'zlib'
6
+ require 'crack'
7
+
8
+ dir = Pathname(__FILE__).dirname.expand_path
9
+
10
+ require dir + 'httparty/module_inheritable_attributes'
11
+ require dir + 'httparty/cookie_hash'
12
+ require dir + 'httparty/net_digest_auth'
13
+
14
+ module HTTParty
15
+ VERSION = "0.6.1".freeze
16
+ CRACK_DEPENDENCY = "0.1.8".freeze
17
+
18
+ module AllowedFormatsDeprecation
19
+ def const_missing(const)
20
+ if const.to_s =~ /AllowedFormats$/
21
+ Kernel.warn("Deprecated: Use HTTParty::Parser::SupportedFormats")
22
+ HTTParty::Parser::SupportedFormats
23
+ else
24
+ super
25
+ end
26
+ end
27
+ end
28
+
29
+ extend AllowedFormatsDeprecation
30
+
31
+ def self.included(base)
32
+ base.extend ClassMethods
33
+ base.send :include, HTTParty::ModuleInheritableAttributes
34
+ base.send(:mattr_inheritable, :default_options)
35
+ base.send(:mattr_inheritable, :default_cookies)
36
+ base.instance_variable_set("@default_options", {})
37
+ base.instance_variable_set("@default_cookies", CookieHash.new)
38
+ end
39
+
40
+ module ClassMethods
41
+ extend AllowedFormatsDeprecation
42
+
43
+ # Allows setting http proxy information to be used
44
+ #
45
+ # class Foo
46
+ # include HTTParty
47
+ # http_proxy 'http://foo.com', 80
48
+ # end
49
+ def http_proxy(addr=nil, port = nil)
50
+ default_options[:http_proxyaddr] = addr
51
+ default_options[:http_proxyport] = port
52
+ end
53
+
54
+ # Allows setting a base uri to be used for each request.
55
+ # Will normalize uri to include http, etc.
56
+ #
57
+ # class Foo
58
+ # include HTTParty
59
+ # base_uri 'twitter.com'
60
+ # end
61
+ def base_uri(uri=nil)
62
+ return default_options[:base_uri] unless uri
63
+ default_options[:base_uri] = HTTParty.normalize_base_uri(uri)
64
+ end
65
+
66
+ # Allows setting basic authentication username and password.
67
+ #
68
+ # class Foo
69
+ # include HTTParty
70
+ # basic_auth 'username', 'password'
71
+ # end
72
+ def basic_auth(u, p)
73
+ default_options[:basic_auth] = {:username => u, :password => p}
74
+ end
75
+
76
+ # Allows setting digest authentication username and password.
77
+ #
78
+ # class Foo
79
+ # include HTTParty
80
+ # digest_auth 'username', 'password'
81
+ # end
82
+ def digest_auth(u, p)
83
+ default_options[:digest_auth] = {:username => u, :password => p}
84
+ end
85
+
86
+ # Allows setting default parameters to be appended to each request.
87
+ # Great for api keys and such.
88
+ #
89
+ # class Foo
90
+ # include HTTParty
91
+ # default_params :api_key => 'secret', :another => 'foo'
92
+ # end
93
+ def default_params(h={})
94
+ raise ArgumentError, 'Default params must be a hash' unless h.is_a?(Hash)
95
+ default_options[:default_params] ||= {}
96
+ default_options[:default_params].merge!(h)
97
+ end
98
+
99
+ # Allows setting a default timeout for all HTTP calls
100
+ # Timeout is specified in seconds.
101
+ #
102
+ # class Foo
103
+ # include HTTParty
104
+ # default_timeout 10
105
+ # end
106
+ def default_timeout(t)
107
+ raise ArgumentError, 'Timeout must be an integer' unless t && t.is_a?(Integer)
108
+ default_options[:timeout] = t
109
+ end
110
+
111
+ # Set an output stream for debugging, defaults to $stderr.
112
+ # The output stream is passed on to Net::HTTP#set_debug_output.
113
+ #
114
+ # class Foo
115
+ # include HTTParty
116
+ # debug_output $stderr
117
+ # end
118
+ def debug_output(stream = $stderr)
119
+ default_options[:debug_output] = stream
120
+ end
121
+
122
+ # Allows setting HTTP headers to be used for each request.
123
+ #
124
+ # class Foo
125
+ # include HTTParty
126
+ # headers 'Accept' => 'text/html'
127
+ # end
128
+ def headers(h={})
129
+ raise ArgumentError, 'Headers must be a hash' unless h.is_a?(Hash)
130
+ default_options[:headers] ||= {}
131
+ default_options[:headers].merge!(h)
132
+ end
133
+
134
+ def cookies(h={})
135
+ raise ArgumentError, 'Cookies must be a hash' unless h.is_a?(Hash)
136
+ default_cookies.add_cookies(h)
137
+ end
138
+
139
+ # Allows setting the format with which to parse.
140
+ # Must be one of the allowed formats ie: json, xml
141
+ #
142
+ # class Foo
143
+ # include HTTParty
144
+ # format :json
145
+ # end
146
+ def format(f = nil)
147
+ if f.nil?
148
+ default_options[:format]
149
+ else
150
+ parser(Parser) if parser.nil?
151
+ default_options[:format] = f
152
+ validate_format
153
+ end
154
+ end
155
+
156
+ # Declare whether or not to follow redirects. When true, an
157
+ # {HTTParty::RedirectionTooDeep} error will raise upon encountering a
158
+ # redirect. You can then gain access to the response object via
159
+ # HTTParty::RedirectionTooDeep#response.
160
+ #
161
+ # @see HTTParty::ResponseError#response
162
+ #
163
+ # @example
164
+ # class Foo
165
+ # include HTTParty
166
+ # base_uri 'http://google.com'
167
+ # no_follow true
168
+ # end
169
+ #
170
+ # begin
171
+ # Foo.get('/')
172
+ # rescue HTTParty::RedirectionTooDeep => e
173
+ # puts e.response.body
174
+ # end
175
+ def no_follow(value = false)
176
+ default_options[:no_follow] = value
177
+ end
178
+
179
+ # Declare that you wish to maintain the chosen HTTP method across redirects.
180
+ # The default behavior is to follow redirects via the GET method.
181
+ # If you wish to maintain the original method, you can set this option to true.
182
+ #
183
+ # @example
184
+ # class Foo
185
+ # include HTTParty
186
+ # base_uri 'http://google.com'
187
+ # maintain_method_across_redirects true
188
+ # end
189
+
190
+ def maintain_method_across_redirects(value = true)
191
+ default_options[:maintain_method_across_redirects] = value
192
+ end
193
+
194
+ # Allows setting a PEM file to be used
195
+ #
196
+ # class Foo
197
+ # include HTTParty
198
+ # pem File.read('/home/user/my.pem')
199
+ # end
200
+ def pem(pem_contents)
201
+ default_options[:pem] = pem_contents
202
+ end
203
+
204
+ # Allows setting an OpenSSL certificate authority file
205
+ #
206
+ # class Foo
207
+ # include HTTParty
208
+ # ssl_ca_file '/etc/ssl/certs/ca-certificates.crt'
209
+ # end
210
+ def ssl_ca_file(path)
211
+ default_options[:ssl_ca_file] = path
212
+ end
213
+
214
+ # Allows setting an OpenSSL certificate authority path (directory)
215
+ #
216
+ # class Foo
217
+ # include HTTParty
218
+ # ssl_ca_path '/etc/ssl/certs/'
219
+ # end
220
+ def ssl_ca_path(path)
221
+ default_options[:ssl_ca_path] = path
222
+ end
223
+
224
+ # Allows setting a custom parser for the response.
225
+ #
226
+ # class Foo
227
+ # include HTTParty
228
+ # parser Proc.new {|data| ...}
229
+ # end
230
+ def parser(custom_parser = nil)
231
+ if custom_parser.nil?
232
+ default_options[:parser]
233
+ else
234
+ default_options[:parser] = custom_parser
235
+ validate_format
236
+ end
237
+ end
238
+
239
+ # Allows making a get request to a url.
240
+ #
241
+ # class Foo
242
+ # include HTTParty
243
+ # end
244
+ #
245
+ # # Simple get with full url
246
+ # Foo.get('http://foo.com/resource.json')
247
+ #
248
+ # # Simple get with full url and query parameters
249
+ # # ie: http://foo.com/resource.json?limit=10
250
+ # Foo.get('http://foo.com/resource.json', :query => {:limit => 10})
251
+ def get(path, options={})
252
+ perform_request Net::HTTP::Get, path, options
253
+ end
254
+
255
+ # Allows making a post request to a url.
256
+ #
257
+ # class Foo
258
+ # include HTTParty
259
+ # end
260
+ #
261
+ # # Simple post with full url and setting the body
262
+ # Foo.post('http://foo.com/resources', :body => {:bar => 'baz'})
263
+ #
264
+ # # Simple post with full url using :query option,
265
+ # # which gets set as form data on the request.
266
+ # Foo.post('http://foo.com/resources', :query => {:bar => 'baz'})
267
+ def post(path, options={})
268
+ perform_request Net::HTTP::Post, path, options
269
+ end
270
+
271
+ # Perform a PUT request to a path
272
+ def put(path, options={})
273
+ perform_request Net::HTTP::Put, path, options
274
+ end
275
+
276
+ # Perform a DELETE request to a path
277
+ def delete(path, options={})
278
+ perform_request Net::HTTP::Delete, path, options
279
+ end
280
+
281
+ # Perform a HEAD request to a path
282
+ def head(path, options={})
283
+ perform_request Net::HTTP::Head, path, options
284
+ end
285
+
286
+ # Perform an OPTIONS request to a path
287
+ def options(path, options={})
288
+ perform_request Net::HTTP::Options, path, options
289
+ end
290
+
291
+ def default_options #:nodoc:
292
+ @default_options
293
+ end
294
+
295
+ private
296
+
297
+ def perform_request(http_method, path, options) #:nodoc:
298
+ options = default_options.dup.merge(options)
299
+ process_cookies(options)
300
+ Request.new(http_method, path, options).perform
301
+ end
302
+
303
+ def process_cookies(options) #:nodoc:
304
+ return unless options[:cookies] || default_cookies.any?
305
+ options[:headers] ||= headers.dup
306
+ options[:headers]["cookie"] = cookies.merge(options.delete(:cookies) || {}).to_cookie_string
307
+ end
308
+
309
+ def validate_format
310
+ if format && parser.respond_to?(:supports_format?) && !parser.supports_format?(format)
311
+ raise UnsupportedFormat, "'#{format.inspect}' Must be one of: #{parser.supported_formats.map{|f| f.to_s}.sort.join(', ')}"
312
+ end
313
+ end
314
+ end
315
+
316
+ def self.normalize_base_uri(url) #:nodoc:
317
+ normalized_url = url.dup
318
+ use_ssl = (normalized_url =~ /^https/) || normalized_url.include?(':443')
319
+ ends_with_slash = normalized_url =~ /\/$/
320
+
321
+ normalized_url.chop! if ends_with_slash
322
+ normalized_url.gsub!(/^https?:\/\//i, '')
323
+
324
+ "http#{'s' if use_ssl}://#{normalized_url}"
325
+ end
326
+
327
+ class Basement #:nodoc:
328
+ include HTTParty
329
+ end
330
+
331
+ def self.get(*args)
332
+ Basement.get(*args)
333
+ end
334
+
335
+ def self.post(*args)
336
+ Basement.post(*args)
337
+ end
338
+
339
+ def self.put(*args)
340
+ Basement.put(*args)
341
+ end
342
+
343
+ def self.delete(*args)
344
+ Basement.delete(*args)
345
+ end
346
+
347
+ def self.head(*args)
348
+ Basement.head(*args)
349
+ end
350
+
351
+ def self.options(*args)
352
+ Basement.options(*args)
353
+ end
354
+
355
+ end
356
+
357
+ require dir + 'httparty/core_extensions'
358
+ require dir + 'httparty/exceptions'
359
+ require dir + 'httparty/parser'
360
+ require dir + 'httparty/request'
361
+ require dir + 'httparty/response'
362
+
363
+ if Crack::VERSION != HTTParty::CRACK_DEPENDENCY
364
+ warn "warning: HTTParty depends on version #{HTTParty::CRACK_DEPENDENCY} of crack, not #{Crack::VERSION}."
365
+ end