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.
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