yoyle439587298 0.13.0
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.
- checksums.yaml +7 -0
- data/.gitignore +10 -0
- data/.travis.yml +7 -0
- data/Gemfile +14 -0
- data/Guardfile +16 -0
- data/History +303 -0
- data/LICENSE +21 -0
- data/MIT-LICENSE +20 -0
- data/README.md +80 -0
- data/Rakefile +12 -0
- data/bin/httparty +117 -0
- data/cucumber.yml +1 -0
- data/examples/aaws.rb +32 -0
- data/examples/basic.rb +32 -0
- data/examples/crack.rb +19 -0
- data/examples/custom_parsers.rb +67 -0
- data/examples/delicious.rb +37 -0
- data/examples/google.rb +16 -0
- data/examples/headers_and_user_agents.rb +6 -0
- data/examples/nokogiri_html_parser.rb +22 -0
- data/examples/rubyurl.rb +14 -0
- data/examples/tripit_sign_in.rb +33 -0
- data/examples/twitter.rb +31 -0
- data/examples/whoismyrep.rb +10 -0
- data/features/basic_authentication.feature +20 -0
- data/features/command_line.feature +7 -0
- data/features/deals_with_http_error_codes.feature +26 -0
- data/features/digest_authentication.feature +20 -0
- data/features/handles_compressed_responses.feature +27 -0
- data/features/handles_multiple_formats.feature +57 -0
- data/features/steps/env.rb +22 -0
- data/features/steps/httparty_response_steps.rb +52 -0
- data/features/steps/httparty_steps.rb +35 -0
- data/features/steps/mongrel_helper.rb +94 -0
- data/features/steps/remote_service_steps.rb +74 -0
- data/features/supports_redirection.feature +22 -0
- data/features/supports_timeout_option.feature +13 -0
- data/httparty.gemspec +26 -0
- data/lib/httparty.rb +578 -0
- data/lib/httparty/connection_adapter.rb +176 -0
- data/lib/httparty/cookie_hash.rb +22 -0
- data/lib/httparty/core_extensions.rb +32 -0
- data/lib/httparty/exceptions.rb +29 -0
- data/lib/httparty/hash_conversions.rb +51 -0
- data/lib/httparty/logger/apache_logger.rb +22 -0
- data/lib/httparty/logger/curl_logger.rb +48 -0
- data/lib/httparty/logger/logger.rb +18 -0
- data/lib/httparty/module_inheritable_attributes.rb +56 -0
- data/lib/httparty/net_digest_auth.rb +84 -0
- data/lib/httparty/parser.rb +141 -0
- data/lib/httparty/request.rb +330 -0
- data/lib/httparty/response.rb +72 -0
- data/lib/httparty/response/headers.rb +31 -0
- data/lib/httparty/version.rb +3 -0
- data/script/release +42 -0
- data/spec/fixtures/delicious.xml +23 -0
- data/spec/fixtures/empty.xml +0 -0
- data/spec/fixtures/google.html +3 -0
- data/spec/fixtures/ssl/generate.sh +29 -0
- data/spec/fixtures/ssl/generated/1fe462c2.0 +16 -0
- data/spec/fixtures/ssl/generated/bogushost.crt +13 -0
- data/spec/fixtures/ssl/generated/ca.crt +16 -0
- data/spec/fixtures/ssl/generated/ca.key +15 -0
- data/spec/fixtures/ssl/generated/selfsigned.crt +14 -0
- data/spec/fixtures/ssl/generated/server.crt +13 -0
- data/spec/fixtures/ssl/generated/server.key +15 -0
- data/spec/fixtures/ssl/openssl-exts.cnf +9 -0
- data/spec/fixtures/twitter.csv +2 -0
- data/spec/fixtures/twitter.json +1 -0
- data/spec/fixtures/twitter.xml +403 -0
- data/spec/fixtures/undefined_method_add_node_for_nil.xml +2 -0
- data/spec/httparty/connection_adapter_spec.rb +298 -0
- data/spec/httparty/cookie_hash_spec.rb +83 -0
- data/spec/httparty/exception_spec.rb +23 -0
- data/spec/httparty/logger/apache_logger_spec.rb +26 -0
- data/spec/httparty/logger/curl_logger_spec.rb +18 -0
- data/spec/httparty/logger/logger_spec.rb +22 -0
- data/spec/httparty/net_digest_auth_spec.rb +152 -0
- data/spec/httparty/parser_spec.rb +165 -0
- data/spec/httparty/request_spec.rb +631 -0
- data/spec/httparty/response_spec.rb +221 -0
- data/spec/httparty/ssl_spec.rb +74 -0
- data/spec/httparty_spec.rb +764 -0
- data/spec/spec.opts +2 -0
- data/spec/spec_helper.rb +37 -0
- data/spec/support/ssl_test_helper.rb +47 -0
- data/spec/support/ssl_test_server.rb +80 -0
- data/spec/support/stub_response.rb +43 -0
- data/website/css/common.css +47 -0
- data/website/index.html +73 -0
- metadata +208 -0
@@ -0,0 +1,22 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'spec_helper'))
|
2
|
+
|
3
|
+
describe HTTParty::Logger do
|
4
|
+
describe ".build" do
|
5
|
+
subject { HTTParty::Logger }
|
6
|
+
|
7
|
+
it "defaults level to :info" do
|
8
|
+
logger_double = double()
|
9
|
+
subject.build(logger_double, nil, nil).level.should == :info
|
10
|
+
end
|
11
|
+
|
12
|
+
it "defaults format to :apache" do
|
13
|
+
logger_double = double()
|
14
|
+
subject.build(logger_double, nil, nil).should be_an_instance_of(HTTParty::Logger::ApacheLogger)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "builds :curl style logger" do
|
18
|
+
logger_double = double()
|
19
|
+
subject.build(logger_double, nil, :curl).should be_an_instance_of(HTTParty::Logger::CurlLogger)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,152 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
|
2
|
+
|
3
|
+
describe Net::HTTPHeader::DigestAuthenticator do
|
4
|
+
def setup_digest(response)
|
5
|
+
digest = Net::HTTPHeader::DigestAuthenticator.new("Mufasa",
|
6
|
+
"Circle Of Life", "GET", "/dir/index.html", response)
|
7
|
+
digest.stub(:random).and_return("deadbeef")
|
8
|
+
Digest::MD5.stub(:hexdigest) { |str| "md5(#{str})" }
|
9
|
+
digest
|
10
|
+
end
|
11
|
+
|
12
|
+
def authorization_header
|
13
|
+
@digest.authorization_header.join(", ")
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
context "with an opaque value in the response header" do
|
18
|
+
before do
|
19
|
+
@digest = setup_digest({
|
20
|
+
'www-authenticate' => 'Digest realm="myhost@testrealm.com", opaque="solid"'
|
21
|
+
})
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should set opaque" do
|
25
|
+
authorization_header.should include(%Q(opaque="solid"))
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
context "without an opaque valid in the response header" do
|
30
|
+
before do
|
31
|
+
@digest = setup_digest({
|
32
|
+
'www-authenticate' => 'Digest realm="myhost@testrealm.com"'
|
33
|
+
})
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should not set opaque" do
|
37
|
+
authorization_header.should_not include(%Q(opaque=))
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context "with specified quality of protection (qop)" do
|
42
|
+
before do
|
43
|
+
@digest = setup_digest({
|
44
|
+
'www-authenticate' => 'Digest realm="myhost@testrealm.com", nonce="NONCE", qop="auth"',
|
45
|
+
})
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should set prefix" do
|
49
|
+
authorization_header.should =~ /^Digest /
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should set username" do
|
53
|
+
authorization_header.should include(%Q(username="Mufasa"))
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should set digest-uri" do
|
57
|
+
authorization_header.should include(%Q(uri="/dir/index.html"))
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should set qop" do
|
61
|
+
authorization_header.should include(%Q(qop="auth"))
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should set cnonce" do
|
65
|
+
authorization_header.should include(%Q(cnonce="md5(deadbeef)"))
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should set nonce-count" do
|
69
|
+
authorization_header.should include(%Q(nc=00000001))
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should set response" do
|
73
|
+
request_digest = "md5(md5(Mufasa:myhost@testrealm.com:Circle Of Life):NONCE:00000001:md5(deadbeef):auth:md5(GET:/dir/index.html))"
|
74
|
+
authorization_header.should include(%Q(response="#{request_digest}"))
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
|
79
|
+
context "with unspecified quality of protection (qop)" do
|
80
|
+
before do
|
81
|
+
@digest = setup_digest({
|
82
|
+
'www-authenticate' => 'Digest realm="myhost@testrealm.com", nonce="NONCE"',
|
83
|
+
})
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should set prefix" do
|
87
|
+
authorization_header.should =~ /^Digest /
|
88
|
+
end
|
89
|
+
|
90
|
+
it "should set username" do
|
91
|
+
authorization_header.should include(%Q(username="Mufasa"))
|
92
|
+
end
|
93
|
+
|
94
|
+
it "should set digest-uri" do
|
95
|
+
authorization_header.should include(%Q(uri="/dir/index.html"))
|
96
|
+
end
|
97
|
+
|
98
|
+
it "should not set qop" do
|
99
|
+
authorization_header.should_not include(%Q(qop=))
|
100
|
+
end
|
101
|
+
|
102
|
+
it "should not set cnonce" do
|
103
|
+
authorization_header.should_not include(%Q(cnonce=))
|
104
|
+
end
|
105
|
+
|
106
|
+
it "should not set nonce-count" do
|
107
|
+
authorization_header.should_not include(%Q(nc=))
|
108
|
+
end
|
109
|
+
|
110
|
+
it "should set response" do
|
111
|
+
request_digest = "md5(md5(Mufasa:myhost@testrealm.com:Circle Of Life):NONCE:md5(GET:/dir/index.html))"
|
112
|
+
authorization_header.should include(%Q(response="#{request_digest}"))
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
context "with multiple authenticate headers" do
|
117
|
+
before do
|
118
|
+
@digest = setup_digest({
|
119
|
+
'www-authenticate' => 'NTLM, Digest realm="myhost@testrealm.com", nonce="NONCE", qop="auth"',
|
120
|
+
})
|
121
|
+
end
|
122
|
+
|
123
|
+
it "should set prefix" do
|
124
|
+
authorization_header.should =~ /^Digest /
|
125
|
+
end
|
126
|
+
|
127
|
+
it "should set username" do
|
128
|
+
authorization_header.should include(%Q(username="Mufasa"))
|
129
|
+
end
|
130
|
+
|
131
|
+
it "should set digest-uri" do
|
132
|
+
authorization_header.should include(%Q(uri="/dir/index.html"))
|
133
|
+
end
|
134
|
+
|
135
|
+
it "should set qop" do
|
136
|
+
authorization_header.should include(%Q(qop="auth"))
|
137
|
+
end
|
138
|
+
|
139
|
+
it "should set cnonce" do
|
140
|
+
authorization_header.should include(%Q(cnonce="md5(deadbeef)"))
|
141
|
+
end
|
142
|
+
|
143
|
+
it "should set nonce-count" do
|
144
|
+
authorization_header.should include(%Q(nc=00000001))
|
145
|
+
end
|
146
|
+
|
147
|
+
it "should set response" do
|
148
|
+
request_digest = "md5(md5(Mufasa:myhost@testrealm.com:Circle Of Life):NONCE:00000001:md5(deadbeef):auth:md5(GET:/dir/index.html))"
|
149
|
+
authorization_header.should include(%Q(response="#{request_digest}"))
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
@@ -0,0 +1,165 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
|
2
|
+
|
3
|
+
describe HTTParty::Parser do
|
4
|
+
describe ".SupportedFormats" do
|
5
|
+
it "returns a hash" do
|
6
|
+
HTTParty::Parser::SupportedFormats.should be_instance_of(Hash)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
describe ".call" do
|
11
|
+
it "generates an HTTParty::Parser instance with the given body and format" do
|
12
|
+
HTTParty::Parser.should_receive(:new).with('body', :plain).and_return(stub(:parse => nil))
|
13
|
+
HTTParty::Parser.call('body', :plain)
|
14
|
+
end
|
15
|
+
|
16
|
+
it "calls #parse on the parser" do
|
17
|
+
parser = mock('Parser')
|
18
|
+
parser.should_receive(:parse)
|
19
|
+
HTTParty::Parser.stub(:new => parser)
|
20
|
+
parser = HTTParty::Parser.call('body', :plain)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe ".formats" do
|
25
|
+
it "returns the SupportedFormats constant" do
|
26
|
+
HTTParty::Parser.formats.should == HTTParty::Parser::SupportedFormats
|
27
|
+
end
|
28
|
+
|
29
|
+
it "returns the SupportedFormats constant for subclasses" do
|
30
|
+
class MyParser < HTTParty::Parser
|
31
|
+
SupportedFormats = {"application/atom+xml" => :atom}
|
32
|
+
end
|
33
|
+
MyParser.formats.should == {"application/atom+xml" => :atom}
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe ".format_from_mimetype" do
|
38
|
+
it "returns a symbol representing the format mimetype" do
|
39
|
+
HTTParty::Parser.format_from_mimetype("text/plain").should == :plain
|
40
|
+
end
|
41
|
+
|
42
|
+
it "returns nil when the mimetype is not supported" do
|
43
|
+
HTTParty::Parser.format_from_mimetype("application/atom+xml").should be_nil
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe ".supported_formats" do
|
48
|
+
it "returns a unique set of supported formats represented by symbols" do
|
49
|
+
HTTParty::Parser.supported_formats.should == HTTParty::Parser::SupportedFormats.values.uniq
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe ".supports_format?" do
|
54
|
+
it "returns true for a supported format" do
|
55
|
+
HTTParty::Parser.stub(:supported_formats => [:json])
|
56
|
+
HTTParty::Parser.supports_format?(:json).should be_true
|
57
|
+
end
|
58
|
+
|
59
|
+
it "returns false for an unsupported format" do
|
60
|
+
HTTParty::Parser.stub(:supported_formats => [])
|
61
|
+
HTTParty::Parser.supports_format?(:json).should be_false
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe "#parse" do
|
66
|
+
before do
|
67
|
+
@parser = HTTParty::Parser.new('body', :json)
|
68
|
+
end
|
69
|
+
|
70
|
+
it "attempts to parse supported formats" do
|
71
|
+
@parser.stub(:supports_format? => true)
|
72
|
+
@parser.should_receive(:parse_supported_format)
|
73
|
+
@parser.parse
|
74
|
+
end
|
75
|
+
|
76
|
+
it "returns the unparsed body when the format is unsupported" do
|
77
|
+
@parser.stub(:supports_format? => false)
|
78
|
+
@parser.parse.should == @parser.body
|
79
|
+
end
|
80
|
+
|
81
|
+
it "returns nil for an empty body" do
|
82
|
+
@parser.stub(:body => '')
|
83
|
+
@parser.parse.should be_nil
|
84
|
+
end
|
85
|
+
|
86
|
+
it "returns nil for a nil body" do
|
87
|
+
@parser.stub(:body => nil)
|
88
|
+
@parser.parse.should be_nil
|
89
|
+
end
|
90
|
+
|
91
|
+
it "returns nil for a 'null' body" do
|
92
|
+
@parser.stub(:body => "null")
|
93
|
+
@parser.parse.should be_nil
|
94
|
+
end
|
95
|
+
|
96
|
+
it "returns nil for a body with spaces only" do
|
97
|
+
@parser.stub(:body => " ")
|
98
|
+
@parser.parse.should be_nil
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
describe "#supports_format?" do
|
103
|
+
it "utilizes the class method to determine if the format is supported" do
|
104
|
+
HTTParty::Parser.should_receive(:supports_format?).with(:json)
|
105
|
+
parser = HTTParty::Parser.new('body', :json)
|
106
|
+
parser.send(:supports_format?)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
describe "#parse_supported_format" do
|
111
|
+
it "calls the parser for the given format" do
|
112
|
+
parser = HTTParty::Parser.new('body', :json)
|
113
|
+
parser.should_receive(:json)
|
114
|
+
parser.send(:parse_supported_format)
|
115
|
+
end
|
116
|
+
|
117
|
+
context "when a parsing method does not exist for the given format" do
|
118
|
+
it "raises an exception" do
|
119
|
+
parser = HTTParty::Parser.new('body', :atom)
|
120
|
+
expect do
|
121
|
+
parser.send(:parse_supported_format)
|
122
|
+
end.to raise_error(NotImplementedError, "HTTParty::Parser has not implemented a parsing method for the :atom format.")
|
123
|
+
end
|
124
|
+
|
125
|
+
it "raises a useful exception message for subclasses" do
|
126
|
+
atom_parser = Class.new(HTTParty::Parser) do
|
127
|
+
def self.name; 'AtomParser'; end
|
128
|
+
end
|
129
|
+
parser = atom_parser.new 'body', :atom
|
130
|
+
expect do
|
131
|
+
parser.send(:parse_supported_format)
|
132
|
+
end.to raise_error(NotImplementedError, "AtomParser has not implemented a parsing method for the :atom format.")
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
context "parsers" do
|
138
|
+
subject do
|
139
|
+
HTTParty::Parser.new('body', nil)
|
140
|
+
end
|
141
|
+
|
142
|
+
it "parses xml with MultiXml" do
|
143
|
+
MultiXml.should_receive(:parse).with('body')
|
144
|
+
subject.send(:xml)
|
145
|
+
end
|
146
|
+
|
147
|
+
it "parses json with JSON" do
|
148
|
+
JSON.should_receive(:load).with('body', nil)
|
149
|
+
subject.send(:json)
|
150
|
+
end
|
151
|
+
|
152
|
+
it "parses html by simply returning the body" do
|
153
|
+
subject.send(:html).should == 'body'
|
154
|
+
end
|
155
|
+
|
156
|
+
it "parses plain text by simply returning the body" do
|
157
|
+
subject.send(:plain).should == 'body'
|
158
|
+
end
|
159
|
+
|
160
|
+
it "parses csv with CSV" do
|
161
|
+
CSV.should_receive(:parse).with('body')
|
162
|
+
subject.send(:csv)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
@@ -0,0 +1,631 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
|
2
|
+
|
3
|
+
describe HTTParty::Request do
|
4
|
+
before do
|
5
|
+
@request = HTTParty::Request.new(Net::HTTP::Get, 'http://api.foo.com/v1', :format => :xml)
|
6
|
+
end
|
7
|
+
|
8
|
+
describe "::NON_RAILS_QUERY_STRING_NORMALIZER" do
|
9
|
+
let(:normalizer) { HTTParty::Request::NON_RAILS_QUERY_STRING_NORMALIZER }
|
10
|
+
|
11
|
+
it "doesn't modify strings" do
|
12
|
+
query_string = normalizer["foo=bar&foo=baz"]
|
13
|
+
URI.unescape(query_string).should == "foo=bar&foo=baz"
|
14
|
+
end
|
15
|
+
|
16
|
+
context "when the query is an array" do
|
17
|
+
|
18
|
+
it "doesn't include brackets" do
|
19
|
+
query_string = normalizer[{:page => 1, :foo => %w(bar baz)}]
|
20
|
+
URI.unescape(query_string).should == "foo=bar&foo=baz&page=1"
|
21
|
+
end
|
22
|
+
|
23
|
+
it "URI encodes array values" do
|
24
|
+
query_string = normalizer[{:people => ["Otis Redding", "Bob Marley", "Tim & Jon"], :page => 1, :xyzzy => 3}]
|
25
|
+
query_string.should == "page=1&people=Otis%20Redding&people=Bob%20Marley&people=Tim%20%26%20Jon&xyzzy=3"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
context "when the query is a hash" do
|
30
|
+
it "correctly handles nil values" do
|
31
|
+
query_string = normalizer[{:page => 1, :per_page => nil}]
|
32
|
+
query_string.should == "page=1&per_page"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe "initialization" do
|
38
|
+
it "sets parser to HTTParty::Parser" do
|
39
|
+
request = HTTParty::Request.new(Net::HTTP::Get, 'http://google.com')
|
40
|
+
request.parser.should == HTTParty::Parser
|
41
|
+
end
|
42
|
+
|
43
|
+
it "sets parser to the optional parser" do
|
44
|
+
my_parser = lambda {}
|
45
|
+
request = HTTParty::Request.new(Net::HTTP::Get, 'http://google.com', :parser => my_parser)
|
46
|
+
request.parser.should == my_parser
|
47
|
+
end
|
48
|
+
|
49
|
+
it "sets connection_adapter to HTTPParty::ConnectionAdapter" do
|
50
|
+
request = HTTParty::Request.new(Net::HTTP::Get, 'http://google.com')
|
51
|
+
request.connection_adapter.should == HTTParty::ConnectionAdapter
|
52
|
+
end
|
53
|
+
|
54
|
+
it "sets connection_adapter to the optional connection_adapter" do
|
55
|
+
my_adapter = lambda {}
|
56
|
+
request = HTTParty::Request.new(Net::HTTP::Get, 'http://google.com', :connection_adapter => my_adapter)
|
57
|
+
request.connection_adapter.should == my_adapter
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
describe "#format" do
|
62
|
+
context "request yet to be made" do
|
63
|
+
it "returns format option" do
|
64
|
+
request = HTTParty::Request.new 'get', '/', :format => :xml
|
65
|
+
request.format.should == :xml
|
66
|
+
end
|
67
|
+
|
68
|
+
it "returns nil format" do
|
69
|
+
request = HTTParty::Request.new 'get', '/'
|
70
|
+
request.format.should be_nil
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
context "request has been made" do
|
75
|
+
it "returns format option" do
|
76
|
+
request = HTTParty::Request.new 'get', '/', :format => :xml
|
77
|
+
request.last_response = stub
|
78
|
+
request.format.should == :xml
|
79
|
+
end
|
80
|
+
|
81
|
+
it "returns the content-type from the last response when the option is not set" do
|
82
|
+
request = HTTParty::Request.new 'get', '/'
|
83
|
+
response = stub
|
84
|
+
response.should_receive(:[]).with('content-type').and_return('text/json')
|
85
|
+
request.last_response = response
|
86
|
+
request.format.should == :json
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
|
92
|
+
context "options" do
|
93
|
+
it "should use basic auth when configured" do
|
94
|
+
@request.options[:basic_auth] = {:username => 'foobar', :password => 'secret'}
|
95
|
+
@request.send(:setup_raw_request)
|
96
|
+
@request.instance_variable_get(:@raw_request)['authorization'].should_not be_nil
|
97
|
+
end
|
98
|
+
|
99
|
+
it "should use digest auth when configured" do
|
100
|
+
FakeWeb.register_uri(:get, "http://api.foo.com/v1",
|
101
|
+
:www_authenticate => 'Digest realm="Log Viewer", qop="auth", nonce="2CA0EC6B0E126C4800E56BA0C0003D3C", opaque="5ccc069c403ebaf9f0171e9517f40e41", stale=false')
|
102
|
+
|
103
|
+
@request.options[:digest_auth] = {:username => 'foobar', :password => 'secret'}
|
104
|
+
@request.send(:setup_raw_request)
|
105
|
+
|
106
|
+
raw_request = @request.instance_variable_get(:@raw_request)
|
107
|
+
raw_request.instance_variable_get(:@header)['Authorization'].should_not be_nil
|
108
|
+
end
|
109
|
+
|
110
|
+
it "should use the right http method for digest authentication" do
|
111
|
+
@post_request = HTTParty::Request.new(Net::HTTP::Post, 'http://api.foo.com/v1', :format => :xml)
|
112
|
+
FakeWeb.register_uri(:post, "http://api.foo.com/v1", {})
|
113
|
+
|
114
|
+
http = @post_request.send(:http)
|
115
|
+
@post_request.should_receive(:http).and_return(http)
|
116
|
+
http.should_not_receive(:head).and_return({'www-authenticate' => nil})
|
117
|
+
@post_request.options[:digest_auth] = {:username => 'foobar', :password => 'secret'}
|
118
|
+
@post_request.send(:setup_raw_request)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
describe "#uri" do
|
123
|
+
context "query strings" do
|
124
|
+
it "does not add an empty query string when default_params are blank" do
|
125
|
+
@request.options[:default_params] = {}
|
126
|
+
@request.uri.query.should be_nil
|
127
|
+
end
|
128
|
+
|
129
|
+
it "respects the query string normalization proc" do
|
130
|
+
empty_proc = lambda {|qs| ""}
|
131
|
+
@request.options[:query_string_normalizer] = empty_proc
|
132
|
+
@request.options[:query] = {:foo => :bar}
|
133
|
+
URI.unescape(@request.uri.query).should == ""
|
134
|
+
end
|
135
|
+
|
136
|
+
it "does not append an ampersand when queries are embedded in paths" do
|
137
|
+
@request.path = "/path?a=1"
|
138
|
+
@request.options[:query] = {}
|
139
|
+
@request.uri.query.should == "a=1"
|
140
|
+
end
|
141
|
+
|
142
|
+
it "does not duplicate query string parameters when uri is called twice" do
|
143
|
+
@request.options[:query] = {:foo => :bar}
|
144
|
+
@request.uri
|
145
|
+
@request.uri.query.should == "foo=bar"
|
146
|
+
end
|
147
|
+
|
148
|
+
context "when representing an array" do
|
149
|
+
it "returns a Rails style query string" do
|
150
|
+
@request.options[:query] = {:foo => %w(bar baz)}
|
151
|
+
URI.unescape(@request.uri.query).should == "foo[]=bar&foo[]=baz"
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
describe "#setup_raw_request" do
|
159
|
+
context "when query_string_normalizer is set" do
|
160
|
+
it "sets the body to the return value of the proc" do
|
161
|
+
@request.options[:query_string_normalizer] = HTTParty::Request::NON_RAILS_QUERY_STRING_NORMALIZER
|
162
|
+
@request.options[:body] = {:page => 1, :foo => %w(bar baz)}
|
163
|
+
@request.send(:setup_raw_request)
|
164
|
+
body = @request.instance_variable_get(:@raw_request).body
|
165
|
+
URI.unescape(body).should == "foo=bar&foo=baz&page=1"
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
describe 'http' do
|
171
|
+
it "should get a connection from the connection_adapter" do
|
172
|
+
http = Net::HTTP.new('google.com')
|
173
|
+
adapter = mock('adapter')
|
174
|
+
request = HTTParty::Request.new(Net::HTTP::Get, 'https://api.foo.com/v1:443', :connection_adapter => adapter)
|
175
|
+
adapter.should_receive(:call).with(request.uri, request.options).and_return(http)
|
176
|
+
request.send(:http).should be http
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
describe '#format_from_mimetype' do
|
181
|
+
it 'should handle text/xml' do
|
182
|
+
["text/xml", "text/xml; charset=iso8859-1"].each do |ct|
|
183
|
+
@request.send(:format_from_mimetype, ct).should == :xml
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
it 'should handle application/xml' do
|
188
|
+
["application/xml", "application/xml; charset=iso8859-1"].each do |ct|
|
189
|
+
@request.send(:format_from_mimetype, ct).should == :xml
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
it 'should handle text/json' do
|
194
|
+
["text/json", "text/json; charset=iso8859-1"].each do |ct|
|
195
|
+
@request.send(:format_from_mimetype, ct).should == :json
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
it 'should handle application/json' do
|
200
|
+
["application/json", "application/json; charset=iso8859-1"].each do |ct|
|
201
|
+
@request.send(:format_from_mimetype, ct).should == :json
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
it 'should handle text/csv' do
|
206
|
+
["text/csv", "text/csv; charset=iso8859-1"].each do |ct|
|
207
|
+
@request.send(:format_from_mimetype, ct).should == :csv
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
it 'should handle application/csv' do
|
212
|
+
["application/csv", "application/csv; charset=iso8859-1"].each do |ct|
|
213
|
+
@request.send(:format_from_mimetype, ct).should == :csv
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
it 'should handle text/comma-separated-values' do
|
218
|
+
["text/comma-separated-values", "text/comma-separated-values; charset=iso8859-1"].each do |ct|
|
219
|
+
@request.send(:format_from_mimetype, ct).should == :csv
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
it 'should handle text/javascript' do
|
224
|
+
["text/javascript", "text/javascript; charset=iso8859-1"].each do |ct|
|
225
|
+
@request.send(:format_from_mimetype, ct).should == :plain
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
it 'should handle application/javascript' do
|
230
|
+
["application/javascript", "application/javascript; charset=iso8859-1"].each do |ct|
|
231
|
+
@request.send(:format_from_mimetype, ct).should == :plain
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
it "returns nil for an unrecognized mimetype" do
|
236
|
+
@request.send(:format_from_mimetype, "application/atom+xml").should be_nil
|
237
|
+
end
|
238
|
+
|
239
|
+
it "returns nil when using a default parser" do
|
240
|
+
@request.options[:parser] = lambda {}
|
241
|
+
@request.send(:format_from_mimetype, "text/json").should be_nil
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
describe 'parsing responses' do
|
246
|
+
it 'should handle xml automatically' do
|
247
|
+
xml = %q[<books><book><id>1234</id><name>Foo Bar!</name></book></books>]
|
248
|
+
@request.options[:format] = :xml
|
249
|
+
@request.send(:parse_response, xml).should == {'books' => {'book' => {'id' => '1234', 'name' => 'Foo Bar!'}}}
|
250
|
+
end
|
251
|
+
|
252
|
+
it 'should handle csv automatically' do
|
253
|
+
csv=[%q["id","Name"],%q["1234","Foo Bar!"]].join("\n")
|
254
|
+
@request.options[:format] = :csv
|
255
|
+
@request.send(:parse_response, csv).should == [["id","Name"],["1234","Foo Bar!"]]
|
256
|
+
end
|
257
|
+
|
258
|
+
it 'should handle json automatically' do
|
259
|
+
json = %q[{"books": {"book": {"name": "Foo Bar!", "id": "1234"}}}]
|
260
|
+
@request.options[:format] = :json
|
261
|
+
@request.send(:parse_response, json).should == {'books' => {'book' => {'id' => '1234', 'name' => 'Foo Bar!'}}}
|
262
|
+
end
|
263
|
+
|
264
|
+
it "should include any HTTP headers in the returned response" do
|
265
|
+
@request.options[:format] = :html
|
266
|
+
response = stub_response "Content"
|
267
|
+
response.initialize_http_header("key" => "value")
|
268
|
+
|
269
|
+
@request.perform.headers.should == { "key" => ["value"] }
|
270
|
+
end
|
271
|
+
|
272
|
+
if "".respond_to?(:encoding)
|
273
|
+
|
274
|
+
it "should process charset in content type properly" do
|
275
|
+
response = stub_response "Content"
|
276
|
+
response.initialize_http_header("Content-Type" => "text/plain;charset = utf-8")
|
277
|
+
resp = @request.perform
|
278
|
+
resp.body.encoding.should == Encoding.find("UTF-8")
|
279
|
+
end
|
280
|
+
|
281
|
+
it "should process charset in content type properly if it has a different case" do
|
282
|
+
response = stub_response "Content"
|
283
|
+
response.initialize_http_header("Content-Type" => "text/plain;CHARSET = utf-8")
|
284
|
+
resp = @request.perform
|
285
|
+
resp.body.encoding.should == Encoding.find("UTF-8")
|
286
|
+
end
|
287
|
+
|
288
|
+
it "should process quoted charset in content type properly" do
|
289
|
+
response = stub_response "Content"
|
290
|
+
response.initialize_http_header("Content-Type" => "text/plain;charset = \"utf-8\"")
|
291
|
+
resp = @request.perform
|
292
|
+
resp.body.encoding.should == Encoding.find("UTF-8")
|
293
|
+
end
|
294
|
+
|
295
|
+
it "should process utf-16 charset with little endian bom correctly" do
|
296
|
+
@request.options[:assume_utf16_is_big_endian] = true
|
297
|
+
|
298
|
+
response = stub_response "\xFF\xFEC\x00o\x00n\x00t\x00e\x00n\x00t\x00"
|
299
|
+
response.initialize_http_header("Content-Type" => "text/plain;charset = utf-16")
|
300
|
+
resp = @request.perform
|
301
|
+
resp.body.encoding.should == Encoding.find("UTF-16LE")
|
302
|
+
end
|
303
|
+
|
304
|
+
it "should process utf-16 charset with big endian bom correctly" do
|
305
|
+
@request.options[:assume_utf16_is_big_endian] = false
|
306
|
+
|
307
|
+
response = stub_response "\xFE\xFF\x00C\x00o\x00n\x00t\x00e\x00n\x00t"
|
308
|
+
response.initialize_http_header("Content-Type" => "text/plain;charset = utf-16")
|
309
|
+
resp = @request.perform
|
310
|
+
resp.body.encoding.should == Encoding.find("UTF-16BE")
|
311
|
+
end
|
312
|
+
|
313
|
+
it "should assume utf-16 little endian if options has been chosen" do
|
314
|
+
@request.options[:assume_utf16_is_big_endian] = false
|
315
|
+
|
316
|
+
response = stub_response "C\x00o\x00n\x00t\x00e\x00n\x00t\x00"
|
317
|
+
response.initialize_http_header("Content-Type" => "text/plain;charset = utf-16")
|
318
|
+
resp = @request.perform
|
319
|
+
resp.body.encoding.should == Encoding.find("UTF-16LE")
|
320
|
+
end
|
321
|
+
|
322
|
+
|
323
|
+
it "should perform no encoding if the charset is not available" do
|
324
|
+
|
325
|
+
response = stub_response "Content"
|
326
|
+
response.initialize_http_header("Content-Type" => "text/plain;charset = utf-lols")
|
327
|
+
resp = @request.perform
|
328
|
+
resp.body.should == "Content"
|
329
|
+
resp.body.encoding.should == "Content".encoding
|
330
|
+
end
|
331
|
+
|
332
|
+
it "should perform no encoding if the content type is specified but no charset is specified" do
|
333
|
+
|
334
|
+
response = stub_response "Content"
|
335
|
+
response.initialize_http_header("Content-Type" => "text/plain")
|
336
|
+
resp = @request.perform
|
337
|
+
resp.body.should == "Content"
|
338
|
+
resp.body.encoding.should == "Content".encoding
|
339
|
+
end
|
340
|
+
end
|
341
|
+
|
342
|
+
|
343
|
+
describe 'with non-200 responses' do
|
344
|
+
context "3xx responses" do
|
345
|
+
it 'returns a valid object for 304 not modified' do
|
346
|
+
stub_response '', 304
|
347
|
+
resp = @request.perform
|
348
|
+
resp.code.should == 304
|
349
|
+
resp.body.should == ''
|
350
|
+
resp.should be_nil
|
351
|
+
end
|
352
|
+
|
353
|
+
it "redirects if a 300 contains a location header" do
|
354
|
+
redirect = stub_response '', 300
|
355
|
+
redirect['location'] = 'http://foo.com/foo'
|
356
|
+
ok = stub_response('<hash><foo>bar</foo></hash>', 200)
|
357
|
+
@http.stub!(:request).and_return(redirect, ok)
|
358
|
+
response = @request.perform
|
359
|
+
response.request.base_uri.to_s.should == "http://foo.com"
|
360
|
+
response.request.path.to_s.should == "http://foo.com/foo"
|
361
|
+
response.request.uri.request_uri.should == "/foo"
|
362
|
+
response.request.uri.to_s.should == "http://foo.com/foo"
|
363
|
+
response.should == {"hash" => {"foo" => "bar"}}
|
364
|
+
end
|
365
|
+
|
366
|
+
it "calls block given to perform with each redirect" do
|
367
|
+
@request = HTTParty::Request.new(Net::HTTP::Get, 'http://test.com/redirect', :format => :xml)
|
368
|
+
FakeWeb.register_uri(:get, "http://test.com/redirect", :status => [300, "REDIRECT"], :location => "http://api.foo.com/v2")
|
369
|
+
FakeWeb.register_uri(:get, "http://api.foo.com/v2", :body => "<hash><foo>bar</foo></hash>")
|
370
|
+
body = ""
|
371
|
+
response = @request.perform { |chunk| body += chunk }
|
372
|
+
body.length.should == 27
|
373
|
+
end
|
374
|
+
|
375
|
+
it "redirects if a 300 contains a relative location header" do
|
376
|
+
redirect = stub_response '', 300
|
377
|
+
redirect['location'] = '/foo/bar'
|
378
|
+
ok = stub_response('<hash><foo>bar</foo></hash>', 200)
|
379
|
+
@http.stub!(:request).and_return(redirect, ok)
|
380
|
+
response = @request.perform
|
381
|
+
response.request.base_uri.to_s.should == "http://api.foo.com"
|
382
|
+
response.request.path.to_s.should == "/foo/bar"
|
383
|
+
response.request.uri.request_uri.should == "/foo/bar"
|
384
|
+
response.request.uri.to_s.should == "http://api.foo.com/foo/bar"
|
385
|
+
response.should == {"hash" => {"foo" => "bar"}}
|
386
|
+
end
|
387
|
+
|
388
|
+
it "handles multiple redirects and relative location headers on different hosts" do
|
389
|
+
@request = HTTParty::Request.new(Net::HTTP::Get, 'http://test.com/redirect', :format => :xml)
|
390
|
+
FakeWeb.register_uri(:get, "http://test.com/redirect", :status => [300, "REDIRECT"], :location => "http://api.foo.com/v2")
|
391
|
+
FakeWeb.register_uri(:get, "http://api.foo.com/v2", :status => [300, "REDIRECT"], :location => "/v3")
|
392
|
+
FakeWeb.register_uri(:get, "http://api.foo.com/v3", :body => "<hash><foo>bar</foo></hash>")
|
393
|
+
response = @request.perform
|
394
|
+
response.request.base_uri.to_s.should == "http://api.foo.com"
|
395
|
+
response.request.path.to_s.should == "/v3"
|
396
|
+
response.request.uri.request_uri.should == "/v3"
|
397
|
+
response.request.uri.to_s.should == "http://api.foo.com/v3"
|
398
|
+
response.should == {"hash" => {"foo" => "bar"}}
|
399
|
+
end
|
400
|
+
|
401
|
+
it "returns the HTTParty::Response when the 300 does not contain a location header" do
|
402
|
+
stub_response '', 300
|
403
|
+
HTTParty::Response.should === @request.perform
|
404
|
+
end
|
405
|
+
end
|
406
|
+
|
407
|
+
it 'should return a valid object for 4xx response' do
|
408
|
+
stub_response '<foo><bar>yes</bar></foo>', 401
|
409
|
+
resp = @request.perform
|
410
|
+
resp.code.should == 401
|
411
|
+
resp.body.should == "<foo><bar>yes</bar></foo>"
|
412
|
+
resp['foo']['bar'].should == "yes"
|
413
|
+
end
|
414
|
+
|
415
|
+
it 'should return a valid object for 5xx response' do
|
416
|
+
stub_response '<foo><bar>error</bar></foo>', 500
|
417
|
+
resp = @request.perform
|
418
|
+
resp.code.should == 500
|
419
|
+
resp.body.should == "<foo><bar>error</bar></foo>"
|
420
|
+
resp['foo']['bar'].should == "error"
|
421
|
+
end
|
422
|
+
|
423
|
+
it "parses response lazily so codes can be checked prior" do
|
424
|
+
stub_response 'not xml', 500
|
425
|
+
@request.options[:format] = :xml
|
426
|
+
lambda {
|
427
|
+
response = @request.perform
|
428
|
+
response.code.should == 500
|
429
|
+
response.body.should == 'not xml'
|
430
|
+
}.should_not raise_error
|
431
|
+
end
|
432
|
+
end
|
433
|
+
end
|
434
|
+
|
435
|
+
it "should not attempt to parse empty responses" do
|
436
|
+
[204, 304].each do |code|
|
437
|
+
stub_response "", code
|
438
|
+
|
439
|
+
@request.options[:format] = :xml
|
440
|
+
@request.perform.should be_nil
|
441
|
+
end
|
442
|
+
end
|
443
|
+
|
444
|
+
it "should not fail for missing mime type" do
|
445
|
+
stub_response "Content for you"
|
446
|
+
@request.options[:format] = :html
|
447
|
+
@request.perform.should == 'Content for you'
|
448
|
+
end
|
449
|
+
|
450
|
+
describe "a request that redirects" do
|
451
|
+
before(:each) do
|
452
|
+
@redirect = stub_response("", 302)
|
453
|
+
@redirect['location'] = '/foo'
|
454
|
+
|
455
|
+
@ok = stub_response('<hash><foo>bar</foo></hash>', 200)
|
456
|
+
end
|
457
|
+
|
458
|
+
describe "once" do
|
459
|
+
before(:each) do
|
460
|
+
@http.stub!(:request).and_return(@redirect, @ok)
|
461
|
+
end
|
462
|
+
|
463
|
+
it "should be handled by GET transparently" do
|
464
|
+
@request.perform.should == {"hash" => {"foo" => "bar"}}
|
465
|
+
end
|
466
|
+
|
467
|
+
it "should be handled by POST transparently" do
|
468
|
+
@request.http_method = Net::HTTP::Post
|
469
|
+
@request.perform.should == {"hash" => {"foo" => "bar"}}
|
470
|
+
end
|
471
|
+
|
472
|
+
it "should be handled by DELETE transparently" do
|
473
|
+
@request.http_method = Net::HTTP::Delete
|
474
|
+
@request.perform.should == {"hash" => {"foo" => "bar"}}
|
475
|
+
end
|
476
|
+
|
477
|
+
it "should be handled by MOVE transparently" do
|
478
|
+
@request.http_method = Net::HTTP::Move
|
479
|
+
@request.perform.should == {"hash" => {"foo" => "bar"}}
|
480
|
+
end
|
481
|
+
|
482
|
+
it "should be handled by COPY transparently" do
|
483
|
+
@request.http_method = Net::HTTP::Copy
|
484
|
+
@request.perform.should == {"hash" => {"foo" => "bar"}}
|
485
|
+
end
|
486
|
+
|
487
|
+
it "should be handled by PATCH transparently" do
|
488
|
+
@request.http_method = Net::HTTP::Patch
|
489
|
+
@request.perform.should == {"hash" => {"foo" => "bar"}}
|
490
|
+
end
|
491
|
+
|
492
|
+
it "should be handled by PUT transparently" do
|
493
|
+
@request.http_method = Net::HTTP::Put
|
494
|
+
@request.perform.should == {"hash" => {"foo" => "bar"}}
|
495
|
+
end
|
496
|
+
|
497
|
+
it "should be handled by HEAD transparently" do
|
498
|
+
@request.http_method = Net::HTTP::Head
|
499
|
+
@request.perform.should == {"hash" => {"foo" => "bar"}}
|
500
|
+
end
|
501
|
+
|
502
|
+
it "should be handled by OPTIONS transparently" do
|
503
|
+
@request.http_method = Net::HTTP::Options
|
504
|
+
@request.perform.should == {"hash" => {"foo" => "bar"}}
|
505
|
+
end
|
506
|
+
|
507
|
+
it "should keep track of cookies between redirects" do
|
508
|
+
@redirect['Set-Cookie'] = 'foo=bar; name=value; HTTPOnly'
|
509
|
+
@request.perform
|
510
|
+
@request.options[:headers]['Cookie'].should match(/foo=bar/)
|
511
|
+
@request.options[:headers]['Cookie'].should match(/name=value/)
|
512
|
+
end
|
513
|
+
|
514
|
+
it 'should update cookies with rediects' do
|
515
|
+
@request.options[:headers] = {'Cookie'=> 'foo=bar;'}
|
516
|
+
@redirect['Set-Cookie'] = 'foo=tar;'
|
517
|
+
@request.perform
|
518
|
+
@request.options[:headers]['Cookie'].should match(/foo=tar/)
|
519
|
+
end
|
520
|
+
|
521
|
+
it 'should keep cookies between rediects' do
|
522
|
+
@request.options[:headers] = {'Cookie'=> 'keep=me'}
|
523
|
+
@redirect['Set-Cookie'] = 'foo=tar;'
|
524
|
+
@request.perform
|
525
|
+
@request.options[:headers]['Cookie'].should match(/keep=me/)
|
526
|
+
end
|
527
|
+
|
528
|
+
it "should handle multiple Set-Cookie headers between redirects" do
|
529
|
+
@redirect.add_field 'set-cookie', 'foo=bar; name=value; HTTPOnly'
|
530
|
+
@redirect.add_field 'set-cookie', 'one=1; two=2; HTTPOnly'
|
531
|
+
@request.perform
|
532
|
+
@request.options[:headers]['Cookie'].should match(/foo=bar/)
|
533
|
+
@request.options[:headers]['Cookie'].should match(/name=value/)
|
534
|
+
@request.options[:headers]['Cookie'].should match(/one=1/)
|
535
|
+
@request.options[:headers]['Cookie'].should match(/two=2/)
|
536
|
+
end
|
537
|
+
|
538
|
+
it 'should make resulting request a get request if it not already' do
|
539
|
+
@request.http_method = Net::HTTP::Delete
|
540
|
+
@request.perform.should == {"hash" => {"foo" => "bar"}}
|
541
|
+
@request.http_method.should == Net::HTTP::Get
|
542
|
+
end
|
543
|
+
|
544
|
+
it 'should not make resulting request a get request if options[:maintain_method_across_redirects] is true' do
|
545
|
+
@request.options[:maintain_method_across_redirects] = true
|
546
|
+
@request.http_method = Net::HTTP::Delete
|
547
|
+
@request.perform.should == {"hash" => {"foo" => "bar"}}
|
548
|
+
@request.http_method.should == Net::HTTP::Delete
|
549
|
+
end
|
550
|
+
|
551
|
+
it 'should log the redirection' do
|
552
|
+
logger_double = double
|
553
|
+
logger_double.should_receive(:info).twice
|
554
|
+
@request.options[:logger] = logger_double
|
555
|
+
@request.perform
|
556
|
+
end
|
557
|
+
end
|
558
|
+
|
559
|
+
describe "infinitely" do
|
560
|
+
before(:each) do
|
561
|
+
@http.stub!(:request).and_return(@redirect)
|
562
|
+
end
|
563
|
+
|
564
|
+
it "should raise an exception" do
|
565
|
+
lambda { @request.perform }.should raise_error(HTTParty::RedirectionTooDeep)
|
566
|
+
end
|
567
|
+
end
|
568
|
+
end
|
569
|
+
|
570
|
+
describe "#handle_deflation" do
|
571
|
+
context "context-encoding" do
|
572
|
+
before do
|
573
|
+
@request.options[:format] = :html
|
574
|
+
@last_response = mock()
|
575
|
+
@last_response.stub!(:body).and_return('')
|
576
|
+
end
|
577
|
+
|
578
|
+
it "should inflate the gzipped body with content-encoding: gzip" do
|
579
|
+
@last_response.stub!(:[]).with("content-encoding").and_return("gzip")
|
580
|
+
@request.stub!(:last_response).and_return(@last_response)
|
581
|
+
Zlib::GzipReader.should_receive(:new).and_return(StringIO.new(''))
|
582
|
+
@request.last_response.should_receive(:delete).with('content-encoding')
|
583
|
+
@request.send(:handle_deflation)
|
584
|
+
end
|
585
|
+
|
586
|
+
it "should inflate the gzipped body with content-encoding: x-gzip" do
|
587
|
+
@last_response.stub!(:[]).with("content-encoding").and_return("x-gzip")
|
588
|
+
@request.stub!(:last_response).and_return(@last_response)
|
589
|
+
Zlib::GzipReader.should_receive(:new).and_return(StringIO.new(''))
|
590
|
+
@request.last_response.should_receive(:delete).with('content-encoding')
|
591
|
+
@request.send(:handle_deflation)
|
592
|
+
end
|
593
|
+
|
594
|
+
it "should inflate the deflated body" do
|
595
|
+
@last_response.stub!(:[]).with("content-encoding").and_return("deflate")
|
596
|
+
@request.stub!(:last_response).and_return(@last_response)
|
597
|
+
Zlib::Inflate.should_receive(:inflate).and_return('')
|
598
|
+
@request.last_response.should_receive(:delete).with('content-encoding')
|
599
|
+
@request.send(:handle_deflation)
|
600
|
+
end
|
601
|
+
end
|
602
|
+
end
|
603
|
+
|
604
|
+
context "with POST http method" do
|
605
|
+
it "should raise argument error if query is not a hash" do
|
606
|
+
lambda {
|
607
|
+
HTTParty::Request.new(Net::HTTP::Post, 'http://api.foo.com/v1', :format => :xml, :query => 'astring').perform
|
608
|
+
}.should raise_error(ArgumentError)
|
609
|
+
end
|
610
|
+
end
|
611
|
+
|
612
|
+
describe "argument validation" do
|
613
|
+
it "should raise argument error if basic_auth and digest_auth are both present" do
|
614
|
+
lambda {
|
615
|
+
HTTParty::Request.new(Net::HTTP::Post, 'http://api.foo.com/v1', :basic_auth => {}, :digest_auth => {}).perform
|
616
|
+
}.should raise_error(ArgumentError, "only one authentication method, :basic_auth or :digest_auth may be used at a time")
|
617
|
+
end
|
618
|
+
|
619
|
+
it "should raise argument error if basic_auth is not a hash" do
|
620
|
+
lambda {
|
621
|
+
HTTParty::Request.new(Net::HTTP::Post, 'http://api.foo.com/v1', :basic_auth => ["foo", "bar"]).perform
|
622
|
+
}.should raise_error(ArgumentError, ":basic_auth must be a hash")
|
623
|
+
end
|
624
|
+
|
625
|
+
it "should raise argument error if digest_auth is not a hash" do
|
626
|
+
lambda {
|
627
|
+
HTTParty::Request.new(Net::HTTP::Post, 'http://api.foo.com/v1', :digest_auth => ["foo", "bar"]).perform
|
628
|
+
}.should raise_error(ArgumentError, ":digest_auth must be a hash")
|
629
|
+
end
|
630
|
+
end
|
631
|
+
end
|