http-request 1.1.6 → 1.1.8

Sign up to get free protection for your applications and to get access to all the features.
data/lib/http-request.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require 'net/http'
2
+ require 'net/https'
2
3
  require 'addressable/uri'
3
4
 
4
5
  module HttpRequest
@@ -13,6 +14,28 @@ module HttpRequest
13
14
  client.open(url)
14
15
  client
15
16
  end
17
+
18
+ def config(options={})
19
+ # Connection defaults
20
+ @config ||= {
21
+ :user_agent => "HttpRequest v#{HttpRequest::VERSION}",
22
+ :max_retries => 3,
23
+ :timeout => 30, # default seconds to timeout a request
24
+ :auto_redirect => true,
25
+ :max_redirects => 3,
26
+ :keep_alive => true
27
+ }
28
+ @config.tap {|config| config.merge(options) }
29
+ end
30
+
31
+ # Short-hand methods, auto-create a client object
32
+ [:get, :post, :put, :delete, :head].each do |verb|
33
+ define_method(verb) do |*args|
34
+ url, headers, body = args
35
+ @client ||= open(url)
36
+ @client.send verb, *args
37
+ end
38
+ end
16
39
  end
17
40
 
18
41
  require 'http-request/version'
@@ -13,7 +13,7 @@ module HttpRequest
13
13
  end
14
14
 
15
15
  def initialize(options={})
16
- @options = options # Connection options
16
+ @options = HttpRequest.config.merge(options) # Connection options
17
17
  @connections = []
18
18
  end
19
19
 
@@ -47,14 +47,38 @@ module HttpRequest
47
47
  [:get, :post, :put, :delete, :head].each do |verb|
48
48
  define_method(verb) do |*args|
49
49
  url, headers, body = args
50
- url ||= open_url
51
50
  request(verb, url, headers || {}, body)
52
51
  end
53
52
  end
54
53
 
55
54
  def request(method, url, headers={}, body=nil)
55
+ url ||= open_url
56
+ # TODO: raise an exception if the url is invalid...
57
+ # ie. nil or something else...
56
58
  conn = open(url)
57
- conn.send method, url, headers, body
59
+ raw_response = conn.send(method, url, headers, body)
60
+
61
+ response = Response.new(raw_response, url)
62
+
63
+ # TODO: .. max retries.. keeping track of state..
64
+ # is can create a bunch of connections in this process...
65
+ # but how do we manage that plus the idea of threads..?
66
+ # each thread has their own Client object.. which is a good thing..
67
+
68
+ if options[:auto_redirect] != false && raw_response.kind_of?(Net::HTTPRedirection) && !response.header['location'].nil?
69
+ # TODO: .. count max redirects...
70
+ new_location = response.header['location']
71
+
72
+ if new_location =~ /^http/i
73
+ request(method, new_location, headers, body)
74
+ else
75
+ absolute_url = uri(url).join(new_location).to_s
76
+ request(method, absolute_url, headers, body)
77
+ end
78
+ else
79
+ # reset redirect_count ..
80
+ response
81
+ end
58
82
  end
59
83
 
60
84
  def connection(url)
@@ -62,7 +86,11 @@ module HttpRequest
62
86
  end
63
87
 
64
88
  def server_id(url)
65
- Addressable::URI.parse(url).origin
89
+ uri(url).normalized_site
90
+ end
91
+
92
+ def uri(url)
93
+ Addressable::URI.parse(url)
66
94
  end
67
95
 
68
96
  private
@@ -1,15 +1,16 @@
1
1
  module HttpRequest
2
2
  class Connection
3
3
  attr_reader :uri, :http
4
- attr_accessor :user_agent, :max_retries, :timeout, :auto_redirect, :keep_alive
4
+ attr_accessor :user_agent, :max_retries, :timeout, :auto_redirect, :max_redirects, :keep_alive
5
5
 
6
6
  def initialize(url, options={})
7
- # Defaults
8
- @user_agent = options[:user_agent] || "HttpRequest v#{HttpRequest::VERSION}"
9
- @max_retries = options[:max_retries] || 3
10
- @timeout = options[:timeout] || 30 # 30 second timeout by default
11
- @auto_redirect = options[:auto_redirect].nil? ? true : options[:auto_redirect]
12
- @keep_alive = options[:keep_alive].nil? ? true : options[:keep_alive]
7
+ # Connection settings
8
+ @user_agent = options[:user_agent] || HttpRequest.config[:user_agent]
9
+ @max_retries = options[:max_retries] || HttpRequest.config[:max_retries]
10
+ @timeout = options[:timeout] || HttpRequest.config[:timeout]
11
+ @auto_redirect = options[:auto_redirect] || HttpRequest.config[:auto_redirect]
12
+ @max_redirects = options[:max_redirects] || HttpRequest.config[:max_redirects]
13
+ @keep_alive = options[:keep_alive] || HttpRequest.config[:keep_alive]
13
14
 
14
15
  # Let's do this
15
16
  @uri = parse_uri(url)
@@ -17,9 +18,17 @@ module HttpRequest
17
18
  end
18
19
 
19
20
  def open
21
+ uri.port ||= 443 if ssl?
22
+
20
23
  @http = Net::HTTP.new(uri.host, uri.port)
21
24
  http.open_timeout = timeout
22
25
  http.read_timeout = timeout
26
+
27
+ if ssl?
28
+ http.use_ssl = true
29
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
30
+ end
31
+
23
32
  http.start
24
33
 
25
34
  if socket && socket.respond_to?(:io) && Socket.const_defined?(:TCP_NODELAY)
@@ -27,6 +36,10 @@ module HttpRequest
27
36
  end
28
37
  end
29
38
 
39
+ def ssl?
40
+ uri.normalized_scheme == "https"
41
+ end
42
+
30
43
  def close
31
44
  http.finish if http
32
45
  end
@@ -45,7 +58,7 @@ module HttpRequest
45
58
  end
46
59
 
47
60
  def server_id
48
- uri.origin
61
+ uri.normalized_site
49
62
  end
50
63
 
51
64
  [:get, :post, :put, :delete, :head].each do |verb|
@@ -66,7 +79,7 @@ module HttpRequest
66
79
  else
67
80
  # Update the path and query
68
81
  # Note: also normalize the path in case its malformed.. dum dums
69
- uri.join! parse_uri(path.gsub('//','/')).request_uri
82
+ uri.join! parse_uri(path.to_s.gsub('//','/')).request_uri
70
83
  end
71
84
 
72
85
  # Open the connection if its closed or hasn't been started..
@@ -85,49 +98,28 @@ module HttpRequest
85
98
  # Make the HTTP request
86
99
  retries = max_retries
87
100
  begin
88
- raw_response = http.request(req)
101
+ response = http.request(req)
89
102
  rescue EOFError, Errno::EPIPE
90
103
  # Something happened to our connection, lets try this again
91
104
  if retries > 0
92
105
  retries -= 1
93
106
  open
94
107
  retry
95
- end
108
+ end
96
109
  end
97
110
 
98
111
  # Let's make sure we close the connection if we don't intend to
99
112
  # have persistent connections..
100
113
  close if !keep_alive
101
114
 
102
- # Build response
103
- response = Response.new(raw_response, uri)
104
-
105
- # TODO: what about redirects that go back and forth..
106
- # we should introduce a max number of auto_redirects..
107
-
108
- # Handle URL Redirection
109
- # TODO: better redirection support.. some bugs / cases here..
110
- if auto_redirect && raw_response.kind_of?(Net::HTTPRedirection) && !response.header['location'].nil?
111
- # binding.pry
112
- new_location = response.header['location']
113
- if new_location =~ /^http/i
114
- close # close existing connection..
115
- @uri = parse_uri(new_location)
116
- else
117
- uri.join! parse_uri(new_location.gsub('//','/')).request_uri
118
- end
119
-
120
- request(verb, uri.request_uri, headers, body)
121
- else
122
- response
123
- end
115
+ response
124
116
  end
125
117
 
126
118
 
127
119
  private
128
120
 
129
- def parse_uri(uri)
130
- Addressable::URI.parse(Addressable::URI.encode(Addressable::URI.unencode(uri)))
121
+ def parse_uri(url)
122
+ Addressable::URI.parse(Addressable::URI.encode(Addressable::URI.unencode(url)))
131
123
  end
132
124
 
133
125
  end
@@ -1,3 +1,3 @@
1
1
  module HttpRequest
2
- VERSION = '1.1.6'
2
+ VERSION = '1.1.8'
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: http-request
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.6
4
+ version: 1.1.8
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-11-08 00:00:00.000000000 Z
12
+ date: 2012-11-17 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: addressable
@@ -18,7 +18,7 @@ dependencies:
18
18
  requirements:
19
19
  - - ~>
20
20
  - !ruby/object:Gem::Version
21
- version: '2.2'
21
+ version: '2.3'
22
22
  type: :runtime
23
23
  prerelease: false
24
24
  version_requirements: !ruby/object:Gem::Requirement
@@ -26,7 +26,7 @@ dependencies:
26
26
  requirements:
27
27
  - - ~>
28
28
  - !ruby/object:Gem::Version
29
- version: '2.2'
29
+ version: '2.3'
30
30
  - !ruby/object:Gem::Dependency
31
31
  name: rake
32
32
  requirement: !ruby/object:Gem::Requirement
@@ -72,7 +72,6 @@ files:
72
72
  - lib/http-request/response.rb
73
73
  - lib/http-request/version.rb
74
74
  - lib/http-request.rb
75
- - lib/old.rb
76
75
  homepage: http://nulayer.com
77
76
  licenses: []
78
77
  post_install_message:
@@ -87,7 +86,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
87
86
  version: '0'
88
87
  segments:
89
88
  - 0
90
- hash: -4505057513829640071
89
+ hash: 4098152367455332880
91
90
  required_rubygems_version: !ruby/object:Gem::Requirement
92
91
  none: false
93
92
  requirements:
data/lib/old.rb DELETED
@@ -1,198 +0,0 @@
1
- # +-------------------------------------------------------------------------------+
2
- # | HttpRequest |
3
- # +-------------------------------------------------------------------------------+
4
- # | Author: Nulayer Inc. / www.nulayer.com |
5
- # +-------------------------------------------------------------------------------+
6
- # | BSD LICENSE |
7
- # | Copyright (c) 2007-2011, Nulayer Inc. |
8
- # | All rights reserved. |
9
- # | |
10
- # | Redistribution and use in source and binary forms, with or without |
11
- # | modification, are permitted provided that the following conditions are met: |
12
- # | * Redistributions of source code must retain the above copyright |
13
- # | notice, this list of conditions and the following disclaimer. |
14
- # | * Redistributions in binary form must reproduce the above copyright |
15
- # | notice, this list of conditions and the following disclaimer in the |
16
- # | documentation and/or other materials provided with the distribution. |
17
- # | * Neither the name of the <organization> nor the |
18
- # | names of its contributors may be used to endorse or promote products |
19
- # | derived from this software without specific prior written permission. |
20
- # | |
21
- # | THIS SOFTWARE IS PROVIDED BY NuLayer Inc. "AS IS" AND ANY |
22
- # | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
23
- # | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
24
- # | DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY |
25
- # | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
26
- # | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
27
- # | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
28
- # | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
29
- # | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
30
- # | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
31
- # +-------------------------------------------------------------------------------+
32
-
33
- require 'net/http'
34
-
35
- class HttpRequest
36
- VERSION = '1.0.5'
37
-
38
- class HTTPError < StandardError; end
39
- class UnexpectedError < StandardError; end
40
-
41
- class UnreachableError < HTTPError; end
42
- class ConnectionResetError < HTTPError; end
43
- class TimeoutError < HTTPError; end
44
- class RedirectError < HTTPError; end
45
-
46
- attr_accessor :uri
47
- attr_accessor :header
48
- attr_accessor :body
49
- attr_accessor :status
50
-
51
- class << self
52
- attr_accessor :user_agent, :timeout, :max_retries
53
- end
54
-
55
-
56
- def self.head(url, options={})
57
- http = HttpRequest.new(url)
58
- http.head(options)
59
- end
60
-
61
- def self.get(url, options={})
62
- http = HttpRequest.new(url)
63
- http.get(options)
64
- end
65
-
66
- def initialize(url)
67
- self.uri = url
68
- end
69
-
70
- def head(options={})
71
- request(:head, options)
72
- end
73
-
74
- def get(options={})
75
- request(:get, options)
76
- end
77
-
78
- def request(type, options={})
79
- user_agent = options[:user_agent] || HttpRequest.user_agent || 'HttpRequest'
80
- timeout = (options[:timeout] || HttpRequest.timeout || 10).to_i
81
- redirect_limit = options[:redirect_limit] || 5
82
- output_file = options[:output_file]
83
- content_max = options[:content_max]
84
- max_retries = HttpRequest.max_retries || 3
85
-
86
- # Check if we're in a redirecting loop
87
- if redirect_limit == 0
88
- raise RedirectError, "HTTP redirect too deep: #{uri.to_s}"
89
- end
90
-
91
- # Prepare the request
92
- req_path = uri.path
93
- req_path += "?#{uri.query}" if !uri.query.nil?
94
-
95
- req_klass = (type == :head ? Net::HTTP::Head : Net::HTTP::Get)
96
- req = req_klass.new(req_path, { 'User-Agent' => user_agent })
97
-
98
- # Basic authentication
99
- if uri.user && uri.password
100
- req.basic_auth uri.user, uri.password
101
- end
102
-
103
- # HTTP request block
104
- @retries = max_retries
105
- begin
106
- http = Net::HTTP.new(uri.host, uri.port)
107
-
108
- http.open_timeout = timeout
109
- http.read_timeout = timeout
110
-
111
- http.start do |http|
112
- http.request(req) do |response|
113
- # Save the header
114
- self.header = response.header
115
- self.body = nil
116
-
117
- # Restrict downloading of content
118
- download_content = true
119
- if !content_max.nil? && header['content-length'].to_i > content_max
120
- download_content = false
121
- end
122
-
123
- # Get the body
124
- if download_content
125
- if output_file
126
- open(output_file, "w") do |f|
127
- response.read_body { |data| f.write(data) }
128
- end
129
- else
130
- self.body = response.read_body
131
- end
132
- end
133
-
134
- # Handle URL Redirection
135
- if response.kind_of?(Net::HTTPRedirection) && !header['location'].nil?
136
- update_uri_location(header['location'])
137
- request type, options.merge({ :redirect_limit => redirect_limit-1 })
138
- end
139
- end
140
- end
141
- rescue ::Errno::ENETUNREACH
142
- raise UnreachableError, "network is unreachable: #{uri.to_s}"
143
- rescue ::Errno::ECONNRESET, ::Errno::ECONNREFUSED, ::SocketError
144
- raise ConnectionResetError, "connection reset by peer: #{uri.to_s}"
145
- rescue ::Timeout::Error
146
- raise TimeoutError, "connection timed out: #{uri.to_s}"
147
- rescue ::Errno::EINTR => ex
148
- # Transmission was interrupted, retry the request just once.
149
- # This usually occurs because the process received a signal.
150
- @retries -= 1
151
- if @retries >= 0
152
- retry
153
- else
154
- raise ex
155
- end
156
- rescue HTTPError => ex
157
- # Catch exceptions that may be raised above -- not sure why we have to do this
158
- raise ex
159
- rescue => ex
160
- raise UnexpectedError, "#{ex.inspect} -- #{uri.to_s}"
161
- ensure
162
- http.finish rescue nil
163
- http = nil
164
- end
165
-
166
- return self
167
- end
168
-
169
- def header=(header)
170
- return if header.nil?
171
- @header = header
172
- self.status = header.code.to_i
173
- end
174
-
175
- def reset!
176
- self.header = nil
177
- self.body = nil
178
- self.status = nil
179
- end
180
-
181
- def uri=(url)
182
- @uri = URI.parse(url)
183
- @uri.path = '/' if @uri.path.empty?
184
- reset!
185
- end
186
-
187
- def update_uri_location(location)
188
- if header['location'].to_s[0].to_s.chr == '/'
189
- url = "#{uri.scheme}://#{uri.host}"
190
- url += ":#{uri.port}" if uri.port != 80 && uri.port != 443
191
- url += location
192
- else
193
- url = location
194
- end
195
-
196
- self.uri = url
197
- end
198
- end