Class: HttpSession
- Inherits:
-
Object
- Object
- HttpSession
- Defined in:
- lib/http_session.rb
Instance Attribute Summary collapse
-
#cookies ⇒ Object
storage for cookies, for instance method usage.
-
#handle ⇒ Object
storage for open session handle, for instance method usage.
Class Method Summary collapse
-
.exists?(host, use_ssl = false, port = nil) ⇒ Boolean
check if a session exists yet ot not.
-
.get(host, use_ssl = false, port = nil) ⇒ Object
get the session for the given host and port, nil if there isn’t one yet.
-
.get_request_url(url, headers = {}) ⇒ Object
shortcut for parsing a full url and performing simple GET requests returns Net::HTTPResponse, or raises Timeout::Error, SystemCallError, OpenSSL::SSL::SSLError, EOFError, Net::ProtocolError.
-
.key(host, use_ssl, port) ⇒ Object
just our own internal session key…
-
.open_timeout=(v) ⇒ Object
it really sux that plain ruby doesn’t have cattr_accessor so we have to do 30 lines of repeating ourselves!.
-
.port_or_default(port, use_ssl) ⇒ Object
return the given port, or defaults for ssl setting if it’s nil.
-
.post_request_url(url, params, headers = {}) ⇒ Object
shortcut for parsing a full url and performing simple POST requests returns Net::HTTPResponse, or raises Timeout::Error, SystemCallError, OpenSSL::SSL::SSLError, EOFError, Net::ProtocolError.
- .read_timeout=(v) ⇒ Object
- .redirect_limit=(v) ⇒ Object
- .retry_limit=(v) ⇒ Object
-
.session_store ⇒ Object
Simplest thread-safe pooling mechanism is to make a separate session store for every thread.
- .ssl_ca_file=(v) ⇒ Object
- .ssl_timeout=(v) ⇒ Object
- .ssl_verify_depth=(v) ⇒ Object
- .ssl_verify_mode=(v) ⇒ Object
-
.use(host, use_ssl = false, port = nil) ⇒ Object
get the session for the given host and port, creating a new one if it doesn’t exist.
Instance Method Summary collapse
-
#add_cookies(response) ⇒ Object
store the cookies from the given response into the session (ignores all host/path/expires/secure/etc cookie options!).
-
#close ⇒ Object
done with this session, close and reset it but it still exists in the session storage in a dormant/empty state, so next request would easily reopen it.
-
#cookie_string ⇒ Object
return all current cookies in a comma-delimited name=value string format.
-
#cookies? ⇒ Boolean
check if a session has any cookies or not.
-
#delete ⇒ Object
delete session from session storage (you should probably call close on it too, and set all references to nil so it gets garbage collected).
-
#initialize(host, use_ssl, port) ⇒ HttpSession
constructor
don’t use new() directly, use singleton get() or use() instead.
-
#request(uri = '/', headers = {}, type = :get, post_params = {}, redirect_limit = @@redirect_limit, retry_limit = @@retry_limit) ⇒ Object
internally handle GET and POST requests (recursively for redirects and retries) returns Net::HTTPResponse, or raises Timeout::Error, SystemCallError, OpenSSL::SSL::SSLError, EOFError, Net::ProtocolError.
Constructor Details
#initialize(host, use_ssl, port) ⇒ HttpSession
don’t use new() directly, use singleton get() or use() instead
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
# File 'lib/http_session.rb', line 128 def initialize(host, use_ssl, port) self.handle = Net::HTTP.new(host, port) self.handle.open_timeout = @@open_timeout # seems to have no effect? self.handle.read_timeout = @@read_timeout # seems to have an effect on establishing tcp connection?? self.handle.close_on_empty_response = true # seems to have no effect? if use_ssl self.handle.use_ssl = true # respond_to? check is a ruby-1.9.1-p378 (+/-?) bug workaround self.handle.ssl_timeout = @@ssl_timeout if OpenSSL::SSL::SSLContext.new.respond_to?(:ssl_timeout=) self.handle.verify_mode = @@ssl_verify_mode self.handle.ca_file = @@ssl_ca_file self.handle.verify_depth = @@ssl_verify_depth end self. = {} end |
Instance Attribute Details
#cookies ⇒ Object
storage for cookies, for instance method usage
191 192 193 |
# File 'lib/http_session.rb', line 191 def @cookies end |
#handle ⇒ Object
storage for open session handle, for instance method usage
125 126 127 |
# File 'lib/http_session.rb', line 125 def handle @handle end |
Class Method Details
.exists?(host, use_ssl = false, port = nil) ⇒ Boolean
check if a session exists yet ot not
150 151 152 |
# File 'lib/http_session.rb', line 150 def self.exists?(host, use_ssl=false, port=nil) session_store.has_key?(key(host, use_ssl, port)) end |
.get(host, use_ssl = false, port = nil) ⇒ Object
get the session for the given host and port, nil if there isn’t one yet
155 156 157 |
# File 'lib/http_session.rb', line 155 def self.get(host, use_ssl=false, port=nil) session_store[key(host, use_ssl, port)] end |
.get_request_url(url, headers = {}) ⇒ Object
shortcut for parsing a full url and performing simple GET requests returns Net::HTTPResponse, or raises Timeout::Error, SystemCallError, OpenSSL::SSL::SSLError, EOFError, Net::ProtocolError
58 59 60 61 |
# File 'lib/http_session.rb', line 58 def self.get_request_url(url, headers={}) parsed = URI.parse(url) use(parsed.host, parsed.scheme == 'https', parsed.port).request(parsed.path + (parsed.query.nil? ? '' : "?#{parsed.query}"), headers) end |
.key(host, use_ssl, port) ⇒ Object
just our own internal session key… (it looks like: “scheme://host:port”)
145 146 147 |
# File 'lib/http_session.rb', line 145 def self.key(host, use_ssl, port) "#{use_ssl ? 'https' : 'http'}://#{host}:#{port_or_default(port, use_ssl)}" end |
.open_timeout=(v) ⇒ Object
it really sux that plain ruby doesn’t have cattr_accessor so we have to do 30 lines of repeating ourselves!
8 9 10 |
# File 'lib/http_session.rb', line 8 def self.open_timeout=(v) @@open_timeout = v end |
.port_or_default(port, use_ssl) ⇒ Object
return the given port, or defaults for ssl setting if it’s nil
181 182 183 |
# File 'lib/http_session.rb', line 181 def self.port_or_default(port, use_ssl) port.nil? ? (use_ssl ? Net::HTTP.https_default_port : Net::HTTP.http_default_port) : port end |
.post_request_url(url, params, headers = {}) ⇒ Object
shortcut for parsing a full url and performing simple POST requests returns Net::HTTPResponse, or raises Timeout::Error, SystemCallError, OpenSSL::SSL::SSLError, EOFError, Net::ProtocolError
65 66 67 68 |
# File 'lib/http_session.rb', line 65 def self.post_request_url(url, params, headers={}) parsed = URI.parse(url) use(parsed.host, parsed.scheme == 'https', parsed.port).request(parsed.path + (parsed.query.nil? ? '' : "?#{parsed.query}"), headers, :post, params) end |
.read_timeout=(v) ⇒ Object
11 12 13 |
# File 'lib/http_session.rb', line 11 def self.read_timeout=(v) @@read_timeout = v end |
.redirect_limit=(v) ⇒ Object
14 15 16 |
# File 'lib/http_session.rb', line 14 def self.redirect_limit=(v) @@redirect_limit = v end |
.retry_limit=(v) ⇒ Object
17 18 19 |
# File 'lib/http_session.rb', line 17 def self.retry_limit=(v) @@retry_limit = v end |
.session_store ⇒ Object
Simplest thread-safe pooling mechanism is to make a separate session store for every thread. Each thread makes its own connection(s), the way you’d expect that way. Just don’t try to share http_session instances between separate threads, and it will work fine.
120 121 122 |
# File 'lib/http_session.rb', line 120 def self.session_store Thread.current['http_session_sessions'] ||= {} end |
.ssl_ca_file=(v) ⇒ Object
26 27 28 |
# File 'lib/http_session.rb', line 26 def self.ssl_ca_file=(v) @@ssl_ca_file = v end |
.ssl_timeout=(v) ⇒ Object
20 21 22 |
# File 'lib/http_session.rb', line 20 def self.ssl_timeout=(v) @@ssl_timeout = v end |
.ssl_verify_depth=(v) ⇒ Object
29 30 31 |
# File 'lib/http_session.rb', line 29 def self.ssl_verify_depth=(v) @@ssl_verify_depth = v end |
.ssl_verify_mode=(v) ⇒ Object
23 24 25 |
# File 'lib/http_session.rb', line 23 def self.ssl_verify_mode=(v) @@ssl_verify_mode = v end |
.use(host, use_ssl = false, port = nil) ⇒ Object
get the session for the given host and port, creating a new one if it doesn’t exist
160 161 162 163 164 |
# File 'lib/http_session.rb', line 160 def self.use(host, use_ssl=false, port=nil) exists?(host, use_ssl, port) ? get(host, use_ssl, port) : (session_store[key(host, use_ssl, port)] = new(host, use_ssl, port_or_default(port, use_ssl))) end |
Instance Method Details
#add_cookies(response) ⇒ Object
store the cookies from the given response into the session (ignores all host/path/expires/secure/etc cookie options!)
204 205 206 207 208 209 210 |
# File 'lib/http_session.rb', line 204 def (response) return unless response.key?('set-cookie') response.get_fields('set-cookie').each do || (key, val) = .split('; ')[0].split('=', 2) [key] = val end end |
#close ⇒ Object
done with this session, close and reset it but it still exists in the session storage in a dormant/empty state, so next request would easily reopen it
168 169 170 171 |
# File 'lib/http_session.rb', line 168 def close handle.finish if handle.started? self. = {} end |
#cookie_string ⇒ Object
return all current cookies in a comma-delimited name=value string format
199 200 201 |
# File 'lib/http_session.rb', line 199 def .collect { |name, val| "#{name}=#{val}" }.join(', ') end |
#cookies? ⇒ Boolean
check if a session has any cookies or not
194 195 196 |
# File 'lib/http_session.rb', line 194 def .length > 0 end |
#delete ⇒ Object
delete session from session storage (you should probably call close on it too, and set all references to nil so it gets garbage collected)
174 175 176 177 178 |
# File 'lib/http_session.rb', line 174 def delete if self.class.exists?(handle.address, handle.use_ssl?, handle.port) self.class.session_store.delete(self.class.key(handle.address, handle.use_ssl?, handle.port)) end end |
#request(uri = '/', headers = {}, type = :get, post_params = {}, redirect_limit = @@redirect_limit, retry_limit = @@retry_limit) ⇒ Object
internally handle GET and POST requests (recursively for redirects and retries) returns Net::HTTPResponse, or raises Timeout::Error, SystemCallError, OpenSSL::SSL::SSLError, EOFError, Net::ProtocolError
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
# File 'lib/http_session.rb', line 72 def request(uri='/', headers={}, type=:get, post_params={}, redirect_limit=@@redirect_limit, retry_limit=@@retry_limit) req = case type when :get Net::HTTP::Get.new(uri) when :post Net::HTTP::Post.new(uri) else raise ArgumentError, "bad type: #{type}" end headers.each { |k, v| req[k] = v } unless headers.empty? req['Cookie'] = if req.set_form_data(post_params) if type == :post begin handle.start unless handle.started? # may raise Timeout::Error or OpenSSL::SSL::SSLError response = handle.request(req) # may raise Errno::* (subclasses of SystemCallError) or EOFError rescue Timeout::Error, SystemCallError, EOFError handle.finish if handle.started? raise if retry_limit == 0 request(uri, headers, type, post_params, redirect_limit, retry_limit - 1) else response if response.kind_of?(Net::HTTPRedirection) raise Net::HTTPError.new('Redirection limit exceeded', response) if redirect_limit == 0 loc = URI.parse(response['location']) if loc.scheme && loc.host && loc.port self.class.use(loc.host, loc.scheme == 'https', loc.port).request(loc.path + (loc.query.nil? ? '' : "?#{loc.query}"), headers, :get, {}, redirect_limit - 1) else # only really bad web servers would ever send this... since it's not technically a valid value! request(loc.path + (loc.query.nil? ? '' : "?#{loc.query}"), headers, :get, {}, redirect_limit - 1) end else response.error! unless response.kind_of?(Net::HTTPOK) # raises Net::HTTP*Error/Exception (subclasses of Net::ProtocolError) raise Net::HTTPError.new('Document has no body', response) if response.body.nil? || response.body == '' response end end end |