httparty 0.13.7 → 0.20.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of httparty might be problematic. Click here for more details.

Files changed (101) hide show
  1. checksums.yaml +5 -5
  2. data/.editorconfig +18 -0
  3. data/.github/workflows/ci.yml +23 -0
  4. data/.gitignore +2 -0
  5. data/.rubocop_todo.yml +1 -1
  6. data/{History → Changelog.md} +220 -59
  7. data/Gemfile +8 -3
  8. data/README.md +8 -7
  9. data/bin/httparty +3 -1
  10. data/docs/README.md +171 -0
  11. data/examples/README.md +34 -12
  12. data/examples/aaws.rb +7 -3
  13. data/examples/body_stream.rb +14 -0
  14. data/examples/crack.rb +1 -1
  15. data/examples/custom_parsers.rb +5 -1
  16. data/examples/delicious.rb +4 -4
  17. data/examples/headers_and_user_agents.rb +7 -3
  18. data/examples/idn.rb +10 -0
  19. data/examples/logging.rb +4 -4
  20. data/examples/microsoft_graph.rb +52 -0
  21. data/examples/multipart.rb +22 -0
  22. data/examples/peer_cert.rb +9 -0
  23. data/examples/stackexchange.rb +1 -1
  24. data/examples/stream_download.rb +26 -0
  25. data/examples/tripit_sign_in.rb +17 -6
  26. data/examples/twitter.rb +2 -2
  27. data/examples/whoismyrep.rb +1 -1
  28. data/httparty.gemspec +7 -5
  29. data/lib/httparty/connection_adapter.rb +86 -20
  30. data/lib/httparty/cookie_hash.rb +10 -8
  31. data/lib/httparty/decompressor.rb +92 -0
  32. data/lib/httparty/exceptions.rb +8 -2
  33. data/lib/httparty/hash_conversions.rb +30 -8
  34. data/lib/httparty/headers_processor.rb +32 -0
  35. data/lib/httparty/logger/apache_formatter.rb +31 -6
  36. data/lib/httparty/logger/curl_formatter.rb +68 -23
  37. data/lib/httparty/logger/logger.rb +5 -1
  38. data/lib/httparty/logger/logstash_formatter.rb +61 -0
  39. data/lib/httparty/module_inheritable_attributes.rb +6 -4
  40. data/lib/httparty/net_digest_auth.rb +23 -21
  41. data/lib/httparty/parser.rb +25 -14
  42. data/lib/httparty/request/body.rb +98 -0
  43. data/lib/httparty/request/multipart_boundary.rb +13 -0
  44. data/lib/httparty/request.rb +156 -106
  45. data/lib/httparty/response/headers.rb +23 -19
  46. data/lib/httparty/response.rb +92 -13
  47. data/lib/httparty/response_fragment.rb +21 -0
  48. data/lib/httparty/text_encoder.rb +72 -0
  49. data/lib/httparty/utils.rb +13 -0
  50. data/lib/httparty/version.rb +3 -1
  51. data/lib/httparty.rb +98 -34
  52. data/website/css/common.css +1 -1
  53. metadata +34 -113
  54. data/.travis.yml +0 -7
  55. data/features/basic_authentication.feature +0 -20
  56. data/features/command_line.feature +0 -95
  57. data/features/deals_with_http_error_codes.feature +0 -26
  58. data/features/digest_authentication.feature +0 -30
  59. data/features/handles_compressed_responses.feature +0 -27
  60. data/features/handles_multiple_formats.feature +0 -57
  61. data/features/steps/env.rb +0 -27
  62. data/features/steps/httparty_response_steps.rb +0 -52
  63. data/features/steps/httparty_steps.rb +0 -43
  64. data/features/steps/mongrel_helper.rb +0 -127
  65. data/features/steps/remote_service_steps.rb +0 -90
  66. data/features/supports_read_timeout_option.feature +0 -13
  67. data/features/supports_redirection.feature +0 -22
  68. data/features/supports_timeout_option.feature +0 -13
  69. data/spec/fixtures/delicious.xml +0 -23
  70. data/spec/fixtures/empty.xml +0 -0
  71. data/spec/fixtures/google.html +0 -3
  72. data/spec/fixtures/ssl/generate.sh +0 -29
  73. data/spec/fixtures/ssl/generated/1fe462c2.0 +0 -16
  74. data/spec/fixtures/ssl/generated/bogushost.crt +0 -13
  75. data/spec/fixtures/ssl/generated/ca.crt +0 -16
  76. data/spec/fixtures/ssl/generated/ca.key +0 -15
  77. data/spec/fixtures/ssl/generated/selfsigned.crt +0 -14
  78. data/spec/fixtures/ssl/generated/server.crt +0 -13
  79. data/spec/fixtures/ssl/generated/server.key +0 -15
  80. data/spec/fixtures/ssl/openssl-exts.cnf +0 -9
  81. data/spec/fixtures/twitter.csv +0 -2
  82. data/spec/fixtures/twitter.json +0 -1
  83. data/spec/fixtures/twitter.xml +0 -403
  84. data/spec/fixtures/undefined_method_add_node_for_nil.xml +0 -2
  85. data/spec/httparty/connection_adapter_spec.rb +0 -468
  86. data/spec/httparty/cookie_hash_spec.rb +0 -83
  87. data/spec/httparty/exception_spec.rb +0 -38
  88. data/spec/httparty/hash_conversions_spec.rb +0 -41
  89. data/spec/httparty/logger/apache_formatter_spec.rb +0 -41
  90. data/spec/httparty/logger/curl_formatter_spec.rb +0 -18
  91. data/spec/httparty/logger/logger_spec.rb +0 -38
  92. data/spec/httparty/net_digest_auth_spec.rb +0 -230
  93. data/spec/httparty/parser_spec.rb +0 -173
  94. data/spec/httparty/request_spec.rb +0 -1073
  95. data/spec/httparty/response_spec.rb +0 -241
  96. data/spec/httparty/ssl_spec.rb +0 -74
  97. data/spec/httparty_spec.rb +0 -850
  98. data/spec/spec_helper.rb +0 -59
  99. data/spec/support/ssl_test_helper.rb +0 -47
  100. data/spec/support/ssl_test_server.rb +0 -80
  101. data/spec/support/stub_response.rb +0 -49
data/bin/httparty CHANGED
@@ -103,9 +103,11 @@ else
103
103
  when :json
104
104
  begin
105
105
  require 'json'
106
- puts JSON.pretty_generate(response)
106
+ puts JSON.pretty_generate(response.parsed_response)
107
107
  rescue LoadError
108
108
  puts YAML.dump(response)
109
+ rescue JSON::JSONError
110
+ puts response.inspect
109
111
  end
110
112
  when :xml
111
113
  require 'rexml/document'
data/docs/README.md ADDED
@@ -0,0 +1,171 @@
1
+ # httparty
2
+
3
+ Makes http fun again!
4
+
5
+ ## Table of contents
6
+ - [Parsing JSON](#parsing-json)
7
+ - [Working with SSL](#working-with-ssl)
8
+
9
+ ## Parsing JSON
10
+ If the response Content Type is `application/json`, HTTParty will parse the response and return Ruby objects such as a hash or array. The default behavior for parsing JSON will return keys as strings. This can be supressed with the `format` option. To get hash keys as symbols:
11
+
12
+ ```ruby
13
+ response = HTTParty.get('http://example.com', format: :plain)
14
+ JSON.parse response, symbolize_names: true
15
+ ```
16
+
17
+ ## Working with SSL
18
+
19
+ You can use this guide to work with SSL certificates.
20
+
21
+ #### Using `pem` option
22
+
23
+ ```ruby
24
+ # Use this example if you are using a pem file
25
+
26
+ class Client
27
+ include HTTParty
28
+
29
+ base_uri "https://example.com"
30
+ pem File.read("#{File.expand_path('.')}/path/to/certs/cert.pem"), "123456"
31
+ end
32
+ ```
33
+
34
+ #### Using `pkcs12` option
35
+
36
+ ```ruby
37
+ # Use this example if you are using a pkcs12 file
38
+
39
+ class Client
40
+ include HTTParty
41
+
42
+ base_uri "https://example.com"
43
+ pkcs12 File.read("#{File.expand_path('.')}/path/to/certs/cert.p12"), "123456"
44
+ end
45
+ ```
46
+
47
+ #### Using `ssl_ca_file` option
48
+
49
+ ```ruby
50
+ # Use this example if you are using a pkcs12 file
51
+
52
+ class Client
53
+ include HTTParty
54
+
55
+ base_uri "https://example.com"
56
+ ssl_ca_file "#{File.expand_path('.')}/path/to/certs/cert.pem"
57
+ end
58
+ ```
59
+
60
+ #### Using `ssl_ca_path` option
61
+
62
+ ```ruby
63
+ # Use this example if you are using a pkcs12 file
64
+
65
+ class Client
66
+ include HTTParty
67
+
68
+ base_uri "https://example.com"
69
+ ssl_ca_path '/path/to/certs'
70
+ end
71
+ ```
72
+
73
+ You can also include all of these options with the call:
74
+
75
+ ```ruby
76
+ class Client
77
+ include HTTParty
78
+
79
+ base_uri "https://example.com"
80
+
81
+ def self.fetch
82
+ get("/resources", pem: File.read("#{File.expand_path('.')}/path/to/certs/cert.pem"), pem_password: "123456")
83
+ end
84
+ end
85
+ ```
86
+
87
+ ### Avoid SSL verification
88
+
89
+ In some cases you may want to skip SSL verification, because the entity that issued the certificate is not a valid one, but you still want to work with it. You can achieve this through:
90
+
91
+ ```ruby
92
+ # Skips SSL certificate verification
93
+
94
+ class Client
95
+ include HTTParty
96
+
97
+ base_uri "https://example.com"
98
+ pem File.read("#{File.expand_path('.')}/path/to/certs/cert.pem"), "123456"
99
+
100
+ def self.fetch
101
+ get("/resources", verify: false)
102
+ # You can also use something like:
103
+ # get("resources", verify_peer: false)
104
+ end
105
+ end
106
+ ```
107
+
108
+ ### HTTP Compression
109
+
110
+ The `Accept-Encoding` request header and `Content-Encoding` response header
111
+ are used to control compression (gzip, etc.) over the wire. Refer to
112
+ [RFC-2616](https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html) for details.
113
+ (For clarity: these headers are **not** used for character encoding i.e. `utf-8`
114
+ which is specified in the `Accept` and `Content-Type` headers.)
115
+
116
+ Unless you have specific requirements otherwise, we recommend to **not** set
117
+ set the `Accept-Encoding` header on HTTParty requests. In this case, `Net::HTTP`
118
+ will set a sensible default compression scheme and automatically decompress the response.
119
+
120
+ If you explicitly set `Accept-Encoding`, there be dragons:
121
+
122
+ * If the HTTP response `Content-Encoding` received on the wire is `gzip` or `deflate`,
123
+ `Net::HTTP` will automatically decompress it, and will omit `Content-Encoding`
124
+ from your `HTTParty::Response` headers.
125
+
126
+ * For encodings `br` (Brotli) or `compress` (LZW), HTTParty will automatically
127
+ decompress if you include the `brotli` or `ruby-lzws` gems respectively into your project.
128
+ **Warning:** Support for these encodings is experimental and not fully battle-tested.
129
+ Similar to above, if decompression succeeds, `Content-Encoding` will be omitted
130
+ from your `HTTParty::Response` headers.
131
+
132
+ * For other encodings, `HTTParty::Response#body` will return the raw uncompressed byte string,
133
+ and you'll need to inspect the `Content-Encoding` response header and decompress it yourself.
134
+ In this case, `HTTParty::Response#parsed_response` will be `nil`.
135
+
136
+ * Lastly, you may use the `skip_decompression` option to disable all automatic decompression
137
+ and always get `HTTParty::Response#body` in its raw form along with the `Content-Encoding` header.
138
+
139
+ ```ruby
140
+ # Accept-Encoding=gzip,deflate can be safely assumed to be auto-decompressed
141
+
142
+ res = HTTParty.get('https://example.com/test.json', headers: { 'Accept-Encoding' => 'gzip,deflate,identity' })
143
+ JSON.parse(res.body) # safe
144
+
145
+
146
+ # Accept-Encoding=br,compress requires third-party gems
147
+
148
+ require 'brotli'
149
+ require 'lzws'
150
+ res = HTTParty.get('https://example.com/test.json', headers: { 'Accept-Encoding' => 'br,compress' })
151
+ JSON.parse(res.body)
152
+
153
+
154
+ # Accept-Encoding=* may return unhandled Content-Encoding
155
+
156
+ res = HTTParty.get('https://example.com/test.json', headers: { 'Accept-Encoding' => '*' })
157
+ encoding = res.headers['Content-Encoding']
158
+ if encoding
159
+ JSON.parse(your_decompression_handling(res.body, encoding))
160
+ else
161
+ # Content-Encoding not present implies decompressed
162
+ JSON.parse(res.body)
163
+ end
164
+
165
+
166
+ # Gimme the raw data!
167
+
168
+ res = HTTParty.get('https://example.com/test.json', skip_decompression: true)
169
+ encoding = res.headers['Content-Encoding']
170
+ JSON.parse(your_decompression_handling(res.body, encoding))
171
+ ```
data/examples/README.md CHANGED
@@ -13,22 +13,22 @@
13
13
  * Creates a custom parser for XML using crack gem
14
14
  * Uses `get` request
15
15
 
16
- * [Create HTML Nokogiri parser](nokogiri_html_parser.rb)
16
+ * [Create HTML Nokogiri parser](nokogiri_html_parser.rb)
17
17
  * Adds Html as a format
18
18
  * passed the body of request to Nokogiri
19
-
19
+
20
20
  * [More Custom Parsers](custom_parsers.rb)
21
21
  * Create an additional parser for atom or make it the ONLY parser
22
-
22
+
23
23
  * [Basic Auth, Delicious](delicious.rb)
24
24
  * Basic Auth, shows how to merge those into options
25
25
  * Uses `get` requests
26
-
26
+
27
27
  * [Passing Headers, User Agent](headers_and_user_agents.rb)
28
28
  * Use the class method of Httparty
29
29
  * Pass the User-Agent in the headers
30
30
  * Uses `get` requests
31
-
31
+
32
32
  * [Basic Post Request](basic.rb)
33
33
  * Httparty included into poro class
34
34
  * Uses `post` requests
@@ -36,7 +36,7 @@
36
36
  * [Access Rubyurl Shortener](rubyurl.rb)
37
37
  * Httparty included into poro class
38
38
  * Uses `post` requests
39
-
39
+
40
40
  * [Add a custom log file](logging.rb)
41
41
  * create a log file and have httparty log requests
42
42
 
@@ -44,24 +44,46 @@
44
44
  * Httparty included into poro class
45
45
  * Creates methods for different endpoints
46
46
  * Uses `get` requests
47
-
47
+
48
48
  * [Accessing Tripit](tripit_sign_in.rb)
49
49
  * Httparty included into poro class
50
50
  * Example of using `debug_output` to see headers/urls passed
51
51
  * Getting and using Cookies
52
52
  * Uses `get` requests
53
-
53
+
54
54
  * [Accessing Twitter](twitter.rb)
55
55
  * Httparty included into poro class
56
56
  * Basic Auth
57
- * Loads settings from a config file
57
+ * Loads settings from a config file
58
58
  * Uses `get` requests
59
59
  * Uses `post` requests
60
-
60
+
61
61
  * [Accessing WhoIsMyRep](whoismyrep.rb)
62
62
  * Httparty included into poro class
63
- * Uses `get` requests
63
+ * Uses `get` requests
64
64
  * Two ways to pass params to get, inline on the url or in query hash
65
65
 
66
66
  * [Rescue Json Error](rescue_json.rb)
67
- * Rescue errors due to parsing response
67
+ * Rescue errors due to parsing response
68
+
69
+ * [Download file using stream mode](stream_download.rb)
70
+ * Uses `get` requests
71
+ * Uses `stream_body` mode
72
+ * Download file without using the memory
73
+
74
+ * [Microsoft graph](microsoft_graph.rb)
75
+ * Basic Auth
76
+ * Uses `post` requests
77
+ * Uses multipart
78
+
79
+ * [Multipart](multipart.rb)
80
+ * Multipart data upload _(with and without file)_
81
+
82
+ * [Uploading File](body_stream.rb)
83
+ * Uses `body_stream` to upload file
84
+
85
+ * [Accessing x509 Peer Certificate](peer_cert.rb)
86
+ * Provides access to the server's TLS certificate
87
+
88
+ * [Accessing IDNs](idn.rb)
89
+ * Uses a `get` request with an International domain names, which are Urls with emojis and non-ASCII characters such as accented letters.
data/examples/aaws.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  require 'rubygems'
2
2
  require 'active_support'
3
+ require 'active_support/core_ext/hash'
4
+ require 'active_support/core_ext/string'
3
5
 
4
6
  dir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
5
7
  require File.join(dir, 'httparty')
@@ -13,14 +15,16 @@ module AAWS
13
15
  default_params Service: 'AWSECommerceService', Operation: 'ItemSearch', SearchIndex: 'Books'
14
16
 
15
17
  def initialize(key)
16
- self.class.default_params AWSAccessKeyId: key
18
+ @auth = { AWSAccessKeyId: key }
17
19
  end
18
20
 
19
21
  def search(options = {})
20
22
  raise ArgumentError, 'You must search for something' if options[:query].blank?
21
23
 
22
24
  # amazon uses nasty camelized query params
23
- options[:query] = options[:query].inject({}) { |h, q| h[q[0].to_s.camelize] = q[1]; h }
25
+ options[:query] = options[:query]
26
+ .reverse_merge(@auth)
27
+ .transform_keys { |k| k.to_s.camelize }
24
28
 
25
29
  # make a request and return the items (NOTE: this doesn't handle errors at this point)
26
30
  self.class.get('/onca/xml', options)['ItemSearchResponse']['Items']
@@ -29,4 +33,4 @@ module AAWS
29
33
  end
30
34
 
31
35
  aaws = AAWS::Book.new(config[:access_key])
32
- pp aaws.search(query: {title: 'Ruby On Rails'})
36
+ pp aaws.search(query: { title: 'Ruby On Rails' })
@@ -0,0 +1,14 @@
1
+ # To upload file to a server use :body_stream
2
+
3
+ HTTParty.put(
4
+ 'http://localhost:3000/train',
5
+ body_stream: File.open('sample_configs/config_train_server_md.yml', 'r')
6
+ )
7
+
8
+
9
+ # Actually, it works with any IO object
10
+
11
+ HTTParty.put(
12
+ 'http://localhost:3000/train',
13
+ body_stream: StringIO.new('foo')
14
+ )
data/examples/crack.rb CHANGED
@@ -16,4 +16,4 @@ class Rep
16
16
  end
17
17
 
18
18
  pp Rep.get('http://whoismyrepresentative.com/getall_mems.php?zip=46544')
19
- pp Rep.get('http://whoismyrepresentative.com/getall_mems.php', query: {zip: 46544})
19
+ pp Rep.get('http://whoismyrepresentative.com/getall_mems.php', query: { zip: 46544 })
@@ -1,3 +1,7 @@
1
+ dir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ require File.join(dir, 'httparty')
3
+ require 'pp'
4
+
1
5
  class ParseAtom
2
6
  include HTTParty
3
7
 
@@ -21,7 +25,7 @@ class OnlyParseAtom
21
25
 
22
26
  # Only support Atom
23
27
  class Parser::OnlyAtom < HTTParty::Parser
24
- SupportedFormats = {"application/atom+xml" => :atom}
28
+ SupportedFormats = { "application/atom+xml" => :atom }
25
29
 
26
30
  protected
27
31
 
@@ -8,7 +8,7 @@ class Delicious
8
8
  base_uri 'https://api.del.icio.us/v1'
9
9
 
10
10
  def initialize(u, p)
11
- @auth = {username: u, password: p}
11
+ @auth = { username: u, password: p }
12
12
  end
13
13
 
14
14
  # query params that filter the posts are:
@@ -17,7 +17,7 @@ class Delicious
17
17
  # url (optional). Filter by this url.
18
18
  # ie: posts(query: {tag: 'ruby'})
19
19
  def posts(options = {})
20
- options.merge!({basic_auth: @auth})
20
+ options.merge!({ basic_auth: @auth })
21
21
  self.class.get('/posts/get', options)
22
22
  end
23
23
 
@@ -25,13 +25,13 @@ class Delicious
25
25
  # tag (optional). Filter by this tag.
26
26
  # count (optional). Number of items to retrieve (Default:15, Maximum:100).
27
27
  def recent(options = {})
28
- options.merge!({basic_auth: @auth})
28
+ options.merge!({ basic_auth: @auth })
29
29
  self.class.get('/posts/recent', options)
30
30
  end
31
31
  end
32
32
 
33
33
  delicious = Delicious.new(config['username'], config['password'])
34
- pp delicious.posts(query: {tag: 'ruby'})
34
+ pp delicious.posts(query: { tag: 'ruby' })
35
35
  pp delicious.recent
36
36
 
37
37
  delicious.recent['posts']['post'].each { |post| puts post['href'] }
@@ -1,6 +1,10 @@
1
1
  # To send custom user agents to identify your application to a web service (or mask as a specific browser for testing), send "User-Agent" as a hash to headers as shown below.
2
2
 
3
- require 'httparty'
3
+ dir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
4
+ require File.join(dir, 'httparty')
5
+ require 'pp'
4
6
 
5
- APPLICATION_NAME = "Httparty"
6
- response = HTTParty.get('http://example.com', headers: {"User-Agent" => APPLICATION_NAME})
7
+ response = HTTParty.get('http://example.com', {
8
+ headers: {"User-Agent" => "Httparty"},
9
+ debug_output: STDOUT, # To show that User-Agent is Httparty
10
+ })
data/examples/idn.rb ADDED
@@ -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 Idn
6
+ include HTTParty
7
+ uri_adapter Addressable::URI
8
+ end
9
+
10
+ pp Idn.get("https://i❤️.ws/emojidomain/💎?format=json")
data/examples/logging.rb CHANGED
@@ -3,7 +3,7 @@ require File.join(dir, 'httparty')
3
3
  require 'logger'
4
4
  require 'pp'
5
5
 
6
- my_logger = Logger.new "httparty.log"
6
+ my_logger = Logger.new STDOUT
7
7
 
8
8
  my_logger.info "Logging can be used on the main HTTParty class. It logs redirects too."
9
9
  HTTParty.get "http://google.com", logger: my_logger
@@ -14,7 +14,7 @@ my_logger.info "It can be used also on a custom class."
14
14
 
15
15
  class Google
16
16
  include HTTParty
17
- logger ::Logger.new "httparty.log"
17
+ logger ::Logger.new STDOUT
18
18
  end
19
19
 
20
20
  Google.get "http://google.com"
@@ -22,7 +22,7 @@ Google.get "http://google.com"
22
22
  my_logger.info '*' * 70
23
23
 
24
24
  my_logger.info "The default formatter is :apache. The :curl formatter can also be used."
25
- my_logger.info "You can tell wich method to call on the logger too. It is info by default."
25
+ my_logger.info "You can tell which method to call on the logger too. It is info by default."
26
26
  HTTParty.get "http://google.com", logger: my_logger, log_level: :debug, log_format: :curl
27
27
 
28
28
  my_logger.info '*' * 70
@@ -30,7 +30,7 @@ my_logger.info '*' * 70
30
30
  my_logger.info "These configs are also available on custom classes."
31
31
  class Google
32
32
  include HTTParty
33
- logger ::Logger.new("httparty.log"), :debug, :curl
33
+ logger ::Logger.new(STDOUT), :debug, :curl
34
34
  end
35
35
 
36
36
  Google.get "http://google.com"
@@ -0,0 +1,52 @@
1
+ require 'httparty'
2
+
3
+ class MicrosoftGraph
4
+ MS_BASE_URL = "https://login.microsoftonline.com".freeze
5
+ TOKEN_REQUEST_PATH = "oauth2/v2.0/token".freeze
6
+
7
+ def initialize(tenant_id)
8
+ @tenant_id = tenant_id
9
+ end
10
+
11
+ # Make a request to the Microsoft Graph API, for instance https://graph.microsoft.com/v1.0/users
12
+ def request(url)
13
+ return false unless (token = bearer_token)
14
+
15
+ response = HTTParty.get(
16
+ url,
17
+ headers: {
18
+ Authorization: "Bearer #{token}"
19
+ }
20
+ )
21
+
22
+ return false unless response.code == 200
23
+
24
+ return JSON.parse(response.body)
25
+ end
26
+
27
+ private
28
+
29
+ # A post to the Microsoft Graph to get a bearer token for the specified tenant. In this example
30
+ # our Rails application has already been given permission to request these tokens by the admin of
31
+ # the specified tenant_id.
32
+ #
33
+ # See here for more information https://developer.microsoft.com/en-us/graph/docs/concepts/auth_v2_service
34
+ #
35
+ # This request also makes use of the multipart/form-data post body.
36
+ def bearer_token
37
+ response = HTTParty.post(
38
+ "#{MS_BASE_URL}/#{@tenant_id}/#{TOKEN_REQUEST_PATH}",
39
+ multipart: true,
40
+ body: {
41
+ client_id: Rails.application.credentials[Rails.env.to_sym][:microsoft_client_id],
42
+ client_secret: Rails.application.credentials[Rails.env.to_sym][:microsoft_client_secret],
43
+ scope: 'https://graph.microsoft.com/.default',
44
+ grant_type: 'client_credentials'
45
+ }
46
+ )
47
+
48
+ return false unless response.code == 200
49
+
50
+ JSON.parse(response.body)['access_token']
51
+ end
52
+ end
@@ -0,0 +1,22 @@
1
+ # If you are uploading file in params, multipart will used as content-type automatically
2
+
3
+ HTTParty.post(
4
+ 'http://localhost:3000/user',
5
+ body: {
6
+ name: 'Foo Bar',
7
+ email: 'example@email.com',
8
+ avatar: File.open('/full/path/to/avatar.jpg')
9
+ }
10
+ )
11
+
12
+
13
+ # However, you can force it yourself
14
+
15
+ HTTParty.post(
16
+ 'http://localhost:3000/user',
17
+ multipart: true,
18
+ body: {
19
+ name: 'Foo Bar',
20
+ email: 'example@email.com'
21
+ }
22
+ )
@@ -0,0 +1,9 @@
1
+ dir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ require File.join(dir, 'httparty')
3
+
4
+ peer_cert = nil
5
+ HTTParty.get("https://www.example.com") do |fragment|
6
+ peer_cert ||= fragment.connection.peer_cert
7
+ end
8
+
9
+ puts "The server's certificate expires #{peer_cert.not_after}"
@@ -7,7 +7,7 @@ class StackExchange
7
7
  base_uri 'api.stackexchange.com'
8
8
 
9
9
  def initialize(service, page)
10
- @options = { query: {site: service, page: page} }
10
+ @options = { query: { site: service, page: page } }
11
11
  end
12
12
 
13
13
  def questions
@@ -0,0 +1,26 @@
1
+ dir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ require File.join(dir, 'httparty')
3
+ require 'pp'
4
+
5
+ # download file linux-4.6.4.tar.xz without using the memory
6
+ response = nil
7
+ filename = "linux-4.6.4.tar.xz"
8
+ url = "https://cdn.kernel.org/pub/linux/kernel/v4.x/#{filename}"
9
+
10
+ File.open(filename, "w") do |file|
11
+ response = HTTParty.get(url, stream_body: true) do |fragment|
12
+ if [301, 302].include?(fragment.code)
13
+ print "skip writing for redirect"
14
+ elsif fragment.code == 200
15
+ print "."
16
+ file.write(fragment)
17
+ else
18
+ raise StandardError, "Non-success status code while streaming #{fragment.code}"
19
+ end
20
+ end
21
+ end
22
+ puts
23
+
24
+ pp "Success: #{response.success?}"
25
+ pp File.stat(filename).inspect
26
+ File.unlink(filename)
@@ -3,30 +3,41 @@ require File.join(dir, 'httparty')
3
3
 
4
4
  class TripIt
5
5
  include HTTParty
6
- base_uri 'http://www.tripit.com'
6
+ base_uri 'https://www.tripit.com'
7
7
  debug_output
8
8
 
9
9
  def initialize(email, password)
10
10
  @email = email
11
- response = self.class.get('/account/login')
12
- response = self.class.post(
11
+ get_response = self.class.get('/account/login')
12
+ get_response_cookie = parse_cookie(get_response.headers['Set-Cookie'])
13
+
14
+ post_response = self.class.post(
13
15
  '/account/login',
14
16
  body: {
15
17
  login_email_address: email,
16
18
  login_password: password
17
19
  },
18
- headers: {'Cookie' => response.headers['Set-Cookie']}
20
+ headers: {'Cookie' => get_response_cookie.to_cookie_string }
19
21
  )
20
- @cookie = response.request.options[:headers]['Cookie']
22
+
23
+ @cookie = parse_cookie(post_response.headers['Set-Cookie'])
21
24
  end
22
25
 
23
26
  def account_settings
24
- self.class.get('/account/edit', headers: {'Cookie' => @cookie})
27
+ self.class.get('/account/edit', headers: { 'Cookie' => @cookie.to_cookie_string })
25
28
  end
26
29
 
27
30
  def logged_in?
28
31
  account_settings.include? "You're logged in as #{@email}"
29
32
  end
33
+
34
+ private
35
+
36
+ def parse_cookie(resp)
37
+ cookie_hash = CookieHash.new
38
+ resp.get_fields('Set-Cookie').each { |c| cookie_hash.add_cookies(c) }
39
+ cookie_hash
40
+ end
30
41
  end
31
42
 
32
43
  tripit = TripIt.new('email', 'password')
data/examples/twitter.rb CHANGED
@@ -14,12 +14,12 @@ class Twitter
14
14
  # which can be :friends, :user or :public
15
15
  # options[:query] can be things like since, since_id, count, etc.
16
16
  def timeline(which = :friends, options = {})
17
- options.merge!({basic_auth: @auth})
17
+ options.merge!({ basic_auth: @auth })
18
18
  self.class.get("/statuses/#{which}_timeline.json", options)
19
19
  end
20
20
 
21
21
  def post(text)
22
- options = { query: {status: text}, basic_auth: @auth }
22
+ options = { query: { status: text }, basic_auth: @auth }
23
23
  self.class.post('/statuses/update.json', options)
24
24
  end
25
25
  end
@@ -7,4 +7,4 @@ class Rep
7
7
  end
8
8
 
9
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})
10
+ pp Rep.get('http://whoismyrepresentative.com/getall_mems.php', query: { zip: 46544 })
data/httparty.gemspec CHANGED
@@ -9,20 +9,22 @@ Gem::Specification.new do |s|
9
9
  s.licenses = ['MIT']
10
10
  s.authors = ["John Nunemaker", "Sandro Turriate"]
11
11
  s.email = ["nunemaker@gmail.com"]
12
- s.homepage = "http://jnunemaker.github.com/httparty"
12
+ s.homepage = "https://github.com/jnunemaker/httparty"
13
13
  s.summary = 'Makes http fun! Also, makes consuming restful web services dead easy.'
14
14
  s.description = 'Makes http fun! Also, makes consuming restful web services dead easy.'
15
15
 
16
- s.required_ruby_version = '>= 1.9.3'
16
+ s.required_ruby_version = '>= 2.3.0'
17
17
 
18
- s.add_dependency 'json', "~> 1.8"
19
18
  s.add_dependency 'multi_xml', ">= 0.5.2"
19
+ s.add_dependency('mime-types', "~> 3.0")
20
20
 
21
21
  # If this line is removed, all hard partying will cease.
22
22
  s.post_install_message = "When you HTTParty, you must party hard!"
23
23
 
24
- s.files = `git ls-files`.split("\n")
25
- s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
24
+ all_files = `git ls-files`.split("\n")
25
+ test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
26
+
27
+ s.files = all_files - test_files
26
28
  s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
27
29
  s.require_paths = ["lib"]
28
30
  end