yoyle439587298 0.13.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (91) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +10 -0
  3. data/.travis.yml +7 -0
  4. data/Gemfile +14 -0
  5. data/Guardfile +16 -0
  6. data/History +303 -0
  7. data/LICENSE +21 -0
  8. data/MIT-LICENSE +20 -0
  9. data/README.md +80 -0
  10. data/Rakefile +12 -0
  11. data/bin/httparty +117 -0
  12. data/cucumber.yml +1 -0
  13. data/examples/aaws.rb +32 -0
  14. data/examples/basic.rb +32 -0
  15. data/examples/crack.rb +19 -0
  16. data/examples/custom_parsers.rb +67 -0
  17. data/examples/delicious.rb +37 -0
  18. data/examples/google.rb +16 -0
  19. data/examples/headers_and_user_agents.rb +6 -0
  20. data/examples/nokogiri_html_parser.rb +22 -0
  21. data/examples/rubyurl.rb +14 -0
  22. data/examples/tripit_sign_in.rb +33 -0
  23. data/examples/twitter.rb +31 -0
  24. data/examples/whoismyrep.rb +10 -0
  25. data/features/basic_authentication.feature +20 -0
  26. data/features/command_line.feature +7 -0
  27. data/features/deals_with_http_error_codes.feature +26 -0
  28. data/features/digest_authentication.feature +20 -0
  29. data/features/handles_compressed_responses.feature +27 -0
  30. data/features/handles_multiple_formats.feature +57 -0
  31. data/features/steps/env.rb +22 -0
  32. data/features/steps/httparty_response_steps.rb +52 -0
  33. data/features/steps/httparty_steps.rb +35 -0
  34. data/features/steps/mongrel_helper.rb +94 -0
  35. data/features/steps/remote_service_steps.rb +74 -0
  36. data/features/supports_redirection.feature +22 -0
  37. data/features/supports_timeout_option.feature +13 -0
  38. data/httparty.gemspec +26 -0
  39. data/lib/httparty.rb +578 -0
  40. data/lib/httparty/connection_adapter.rb +176 -0
  41. data/lib/httparty/cookie_hash.rb +22 -0
  42. data/lib/httparty/core_extensions.rb +32 -0
  43. data/lib/httparty/exceptions.rb +29 -0
  44. data/lib/httparty/hash_conversions.rb +51 -0
  45. data/lib/httparty/logger/apache_logger.rb +22 -0
  46. data/lib/httparty/logger/curl_logger.rb +48 -0
  47. data/lib/httparty/logger/logger.rb +18 -0
  48. data/lib/httparty/module_inheritable_attributes.rb +56 -0
  49. data/lib/httparty/net_digest_auth.rb +84 -0
  50. data/lib/httparty/parser.rb +141 -0
  51. data/lib/httparty/request.rb +330 -0
  52. data/lib/httparty/response.rb +72 -0
  53. data/lib/httparty/response/headers.rb +31 -0
  54. data/lib/httparty/version.rb +3 -0
  55. data/script/release +42 -0
  56. data/spec/fixtures/delicious.xml +23 -0
  57. data/spec/fixtures/empty.xml +0 -0
  58. data/spec/fixtures/google.html +3 -0
  59. data/spec/fixtures/ssl/generate.sh +29 -0
  60. data/spec/fixtures/ssl/generated/1fe462c2.0 +16 -0
  61. data/spec/fixtures/ssl/generated/bogushost.crt +13 -0
  62. data/spec/fixtures/ssl/generated/ca.crt +16 -0
  63. data/spec/fixtures/ssl/generated/ca.key +15 -0
  64. data/spec/fixtures/ssl/generated/selfsigned.crt +14 -0
  65. data/spec/fixtures/ssl/generated/server.crt +13 -0
  66. data/spec/fixtures/ssl/generated/server.key +15 -0
  67. data/spec/fixtures/ssl/openssl-exts.cnf +9 -0
  68. data/spec/fixtures/twitter.csv +2 -0
  69. data/spec/fixtures/twitter.json +1 -0
  70. data/spec/fixtures/twitter.xml +403 -0
  71. data/spec/fixtures/undefined_method_add_node_for_nil.xml +2 -0
  72. data/spec/httparty/connection_adapter_spec.rb +298 -0
  73. data/spec/httparty/cookie_hash_spec.rb +83 -0
  74. data/spec/httparty/exception_spec.rb +23 -0
  75. data/spec/httparty/logger/apache_logger_spec.rb +26 -0
  76. data/spec/httparty/logger/curl_logger_spec.rb +18 -0
  77. data/spec/httparty/logger/logger_spec.rb +22 -0
  78. data/spec/httparty/net_digest_auth_spec.rb +152 -0
  79. data/spec/httparty/parser_spec.rb +165 -0
  80. data/spec/httparty/request_spec.rb +631 -0
  81. data/spec/httparty/response_spec.rb +221 -0
  82. data/spec/httparty/ssl_spec.rb +74 -0
  83. data/spec/httparty_spec.rb +764 -0
  84. data/spec/spec.opts +2 -0
  85. data/spec/spec_helper.rb +37 -0
  86. data/spec/support/ssl_test_helper.rb +47 -0
  87. data/spec/support/ssl_test_server.rb +80 -0
  88. data/spec/support/stub_response.rb +43 -0
  89. data/website/css/common.css +47 -0
  90. data/website/index.html +73 -0
  91. metadata +208 -0
@@ -0,0 +1,10 @@
1
+ dir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ require File.join(dir, 'httparty')
3
+ require 'pp'
4
+
5
+ class Rep
6
+ include HTTParty
7
+ end
8
+
9
+ pp Rep.get('http://whoismyrepresentative.com/getall_mems.php?zip=46544')
10
+ pp Rep.get('http://whoismyrepresentative.com/getall_mems.php', :query => {:zip => 46544})
@@ -0,0 +1,20 @@
1
+ Feature: Basic Authentication
2
+
3
+ As a developer
4
+ I want to be able to use a service that requires Basic Authentication
5
+ Because that is not an uncommon requirement
6
+
7
+ Scenario: Passing no credentials to a page requiring Basic Authentication
8
+ Given a restricted page at '/basic_auth.html'
9
+ When I call HTTParty#get with '/basic_auth.html'
10
+ Then it should return a response with a 401 response code
11
+
12
+ Scenario: Passing proper credentials to a page requiring Basic Authentication
13
+ Given a remote service that returns 'Authenticated Page'
14
+ And that service is accessed at the path '/basic_auth.html'
15
+ And that service is protected by Basic Authentication
16
+ And that service requires the username 'jcash' with the password 'maninblack'
17
+ When I call HTTParty#get with '/basic_auth.html' and a basic_auth hash:
18
+ | username | password |
19
+ | jcash | maninblack |
20
+ Then the return value should match 'Authenticated Page'
@@ -0,0 +1,7 @@
1
+ Feature: Command Line
2
+
3
+ As a developer
4
+ I want to be able to harness the power of HTTParty from the command line
5
+ Because that would make quick testing and debugging easy
6
+ And 'easy' is my middle name
7
+ And I'm kidding it's actually 'Danger'!
@@ -0,0 +1,26 @@
1
+ Feature: Deals with HTTP error codes
2
+
3
+ As a developer
4
+ I want to be informed of non-successful responses
5
+ Because sometimes thing explode
6
+ And I should probably know what happened
7
+
8
+ Scenario: A response of '404 - Not Found'
9
+ Given a remote service that returns a 404 status code
10
+ And that service is accessed at the path '/404_service.html'
11
+ When I call HTTParty#get with '/404_service.html'
12
+ Then it should return a response with a 404 response code
13
+
14
+ Scenario: A response of '500 - Internal Server Error'
15
+ Given a remote service that returns a 500 status code
16
+ And that service is accessed at the path '/500_service.html'
17
+ When I call HTTParty#get with '/500_service.html'
18
+ Then it should return a response with a 500 response code
19
+
20
+ Scenario: A non-successful response where I need the body
21
+ Given a remote service that returns a 400 status code
22
+ And the response from the service has a body of 'Bad response'
23
+ And that service is accessed at the path '/400_service.html'
24
+ When I call HTTParty#get with '/400_service.html'
25
+ Then it should return a response with a 400 response code
26
+ And the return value should match 'Bad response'
@@ -0,0 +1,20 @@
1
+ Feature: Digest Authentication
2
+
3
+ As a developer
4
+ I want to be able to use a service that requires Digest Authentication
5
+ Because that is not an uncommon requirement
6
+
7
+ Scenario: Passing no credentials to a page requiring Digest Authentication
8
+ Given a restricted page at '/digest_auth.html'
9
+ When I call HTTParty#get with '/digest_auth.html'
10
+ Then it should return a response with a 401 response code
11
+
12
+ Scenario: Passing proper credentials to a page requiring Digest Authentication
13
+ Given a remote service that returns 'Digest Authenticated Page'
14
+ And that service is accessed at the path '/digest_auth.html'
15
+ And that service is protected by Digest Authentication
16
+ And that service requires the username 'jcash' with the password 'maninblack'
17
+ When I call HTTParty#get with '/digest_auth.html' and a digest_auth hash:
18
+ | username | password |
19
+ | jcash | maninblack |
20
+ Then the return value should match 'Digest Authenticated Page'
@@ -0,0 +1,27 @@
1
+ Feature: Handles Compressed Responses
2
+
3
+ In order to save bandwidth
4
+ As a developer
5
+ I want to uncompress compressed responses
6
+
7
+ Scenario: Supports deflate encoding
8
+ Given a remote deflate service
9
+ And the response from the service has a body of '<h1>Some HTML</h1>'
10
+ And that service is accessed at the path '/deflate_service.html'
11
+ When I call HTTParty#get with '/deflate_service.html'
12
+ Then the return value should match '<h1>Some HTML</h1>'
13
+
14
+ Scenario: Supports gzip encoding
15
+ Given a remote gzip service
16
+ And the response from the service has a body of '<h1>Some HTML</h1>'
17
+ And that service is accessed at the path '/gzip_service.html'
18
+ When I call HTTParty#get with '/gzip_service.html'
19
+ Then the return value should match '<h1>Some HTML</h1>'
20
+
21
+ Scenario: Supports HEAD request with gzip encoding
22
+ Given a remote gzip service
23
+ And that service is accessed at the path '/gzip_head.gz.js'
24
+ When I call HTTParty#head with '/gzip_head.gz.js'
25
+ Then it should return a response with a 200 response code
26
+ Then it should return a response with a gzip content-encoding
27
+ Then it should return a response with a blank body
@@ -0,0 +1,57 @@
1
+ Feature: Handles Multiple Formats
2
+
3
+ As a developer
4
+ I want to be able to consume remote services of many different formats
5
+ And I want those formats to be automatically detected and handled
6
+ Because web services take many forms
7
+ And I don't want to have to do any extra work
8
+
9
+ Scenario: An HTML service
10
+ Given a remote service that returns '<h1>Some HTML</h1>'
11
+ And that service is accessed at the path '/html_service.html'
12
+ And the response from the service has a Content-Type of 'text/html'
13
+ When I call HTTParty#get with '/html_service.html'
14
+ Then it should return a String
15
+ And the return value should match '<h1>Some HTML</h1>'
16
+
17
+ Scenario: A CSV service
18
+ Given a remote service that returns:
19
+ """
20
+ "Last Name","Name"
21
+ "jennings","waylon"
22
+ "cash","johnny"
23
+ """
24
+ And that service is accessed at the path '/service.csv'
25
+ And the response from the service has a Content-Type of 'application/csv'
26
+ When I call HTTParty#get with '/service.csv'
27
+ Then it should return an Array equaling:
28
+ | Last Name | Name |
29
+ | jennings | waylon |
30
+ | cash | johnny |
31
+
32
+ Scenario: A JSON service
33
+ Given a remote service that returns '{ "jennings": "waylon", "cash": "johnny" }'
34
+ And that service is accessed at the path '/service.json'
35
+ And the response from the service has a Content-Type of 'application/json'
36
+ When I call HTTParty#get with '/service.json'
37
+ Then it should return a Hash equaling:
38
+ | key | value |
39
+ | jennings | waylon |
40
+ | cash | johnny |
41
+
42
+ Scenario: An XML Service
43
+ Given a remote service that returns '<singer>waylon jennings</singer>'
44
+ And that service is accessed at the path '/service.xml'
45
+ And the response from the service has a Content-Type of 'text/xml'
46
+ When I call HTTParty#get with '/service.xml'
47
+ Then it should return a Hash equaling:
48
+ | key | value |
49
+ | singer | waylon jennings |
50
+
51
+ Scenario: A Javascript remote file
52
+ Given a remote service that returns '$(function() { alert("hi"); });'
53
+ And that service is accessed at the path '/service.js'
54
+ And the response from the service has a Content-Type of 'application/javascript'
55
+ When I call HTTParty#get with '/service.js'
56
+ Then it should return a String
57
+ And the return value should match '$(function() { alert("hi"); });'
@@ -0,0 +1,22 @@
1
+ require 'mongrel'
2
+ require './lib/httparty'
3
+ require 'spec/expectations'
4
+
5
+ Before do
6
+ def new_port
7
+ server = TCPServer.new('0.0.0.0', nil)
8
+ port = server.addr[1]
9
+ ensure
10
+ server.close
11
+ end
12
+
13
+ port = ENV["HTTPARTY_PORT"] || new_port
14
+ @host_and_port = "0.0.0.0:#{port}"
15
+ @server = Mongrel::HttpServer.new("0.0.0.0", port)
16
+ @server.run
17
+ @request_options = {}
18
+ end
19
+
20
+ After do
21
+ @server.stop
22
+ end
@@ -0,0 +1,52 @@
1
+ # Not needed anymore in ruby 2.0, but needed to resolve constants
2
+ # in nested namespaces. This is taken from rails :)
3
+ def constantize(camel_cased_word)
4
+ names = camel_cased_word.split('::')
5
+ names.shift if names.empty? || names.first.empty?
6
+
7
+ constant = Object
8
+ names.each do |name|
9
+ constant = constant.const_defined?(name) ? constant.const_get(name) : constant.const_missing(name)
10
+ end
11
+ constant
12
+ end
13
+
14
+ Then /it should return an? (\w+)$/ do |class_string|
15
+ @response_from_httparty.should be_an_instance_of(class_string.class)
16
+ end
17
+
18
+ Then /the return value should match '(.*)'/ do |expected_text|
19
+ @response_from_httparty.should eql(expected_text)
20
+ end
21
+
22
+ Then /it should return a Hash equaling:/ do |hash_table|
23
+ @response_from_httparty.should be_an_instance_of(Hash)
24
+ @response_from_httparty.keys.length.should eql(hash_table.rows.length)
25
+ hash_table.hashes.each do |pair|
26
+ key, value = pair["key"], pair["value"]
27
+ @response_from_httparty.keys.should include(key)
28
+ @response_from_httparty[key].should eql(value)
29
+ end
30
+ end
31
+
32
+ Then /it should return an Array equaling:/ do |array|
33
+ @response_from_httparty.should be_an_instance_of(Array)
34
+ @response_from_httparty.should eql array.raw
35
+ end
36
+
37
+ Then /it should return a response with a (\d+) response code/ do |code|
38
+ @response_from_httparty.code.should eql(code.to_i)
39
+ end
40
+
41
+ Then /it should return a response with a (.*) content\-encoding$/ do |content_type|
42
+ @response_from_httparty.headers['content-encoding'].should eql('gzip')
43
+ end
44
+
45
+ Then /it should return a response with a blank body$/ do
46
+ @response_from_httparty.body.should be(nil)
47
+ end
48
+
49
+ Then /it should raise (?:an|a) ([\w:]+) exception/ do |exception|
50
+ @exception_from_httparty.should_not be_nil
51
+ @exception_from_httparty.should be_a constantize(exception)
52
+ end
@@ -0,0 +1,35 @@
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#head with '(.*)'$/ do |url|
14
+ begin
15
+ @response_from_httparty = HTTParty.head("http://#{@host_and_port}#{url}", @request_options)
16
+ rescue HTTParty::RedirectionTooDeep, Timeout::Error => e
17
+ @exception_from_httparty = e
18
+ end
19
+ end
20
+
21
+ When /I call HTTParty#get with '(.*)' and a basic_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
+ :basic_auth => { :username => h["username"], :password => h["password"] }
26
+ )
27
+ end
28
+
29
+ When /I call HTTParty#get with '(.*)' and a digest_auth hash:/ do |url, auth_table|
30
+ h = auth_table.hashes.first
31
+ @response_from_httparty = HTTParty.get(
32
+ "http://#{@host_and_port}#{url}",
33
+ :digest_auth => { :username => h["username"], :password => h["password"] }
34
+ )
35
+ 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
+ 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,74 @@
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:$/ do |response_body|
7
+ @handler = BasicMongrelHandler.new
8
+ @handler.response_body = response_body
9
+ end
10
+
11
+ Given /a remote service that returns a (\d+) status code/ do |code|
12
+ @handler = BasicMongrelHandler.new
13
+ @handler.response_code = code
14
+ end
15
+
16
+ Given /that service is accessed at the path '(.*)'/ do |path|
17
+ @server.register(path, @handler)
18
+ end
19
+
20
+ Given /^that service takes (\d+) seconds to generate a response$/ do |time|
21
+ @server_response_time = time.to_i
22
+ @handler.preprocessor = Proc.new { sleep time.to_i }
23
+ end
24
+
25
+ Given /^a remote deflate service$/ do
26
+ @handler = DeflateHandler.new
27
+ end
28
+
29
+ Given /^a remote gzip service$/ do
30
+ @handler = GzipHandler.new
31
+ end
32
+
33
+ Given /the response from the service has a Content-Type of '(.*)'/ do |content_type|
34
+ @handler.content_type = content_type
35
+ end
36
+
37
+ Given /the response from the service has a body of '(.*)'/ do |response_body|
38
+ @handler.response_body = response_body
39
+ end
40
+
41
+ Given /the url '(.*)' redirects to '(.*)'/ do |redirection_url, target_url|
42
+ @server.register redirection_url, new_mongrel_redirector(target_url)
43
+ end
44
+
45
+ Given /that service is protected by Basic Authentication/ do
46
+ @handler.extend BasicAuthentication
47
+ end
48
+
49
+ Given /that service is protected by Digest Authentication/ do
50
+ @handler.extend DigestAuthentication
51
+ end
52
+
53
+ Given /that service requires the username '(.*)' with the password '(.*)'/ do |username, password|
54
+ @handler.username = username
55
+ @handler.password = password
56
+ end
57
+
58
+ Given /a restricted page at '(.*)'/ do |url|
59
+ Given "a remote service that returns 'A response I will never see'"
60
+ And "that service is accessed at the path '#{url}'"
61
+ And "that service is protected by Basic Authentication"
62
+ And "that service requires the username 'something' with the password 'secret'"
63
+ end
64
+
65
+ # This joins the server thread, and halts cucumber, so you can actually hit the
66
+ # server with a browser. Runs until you kill it with Ctrl-c
67
+ Given /I want to hit this in a browser/ do
68
+ @server.acceptor.join
69
+ end
70
+
71
+ Then /I wait for the server to recover/ do
72
+ timeout = @request_options[:timeout] || 0
73
+ sleep @server_response_time - timeout
74
+ end