Class: Revactor::HttpClient
- Inherits:
-
Rev::HttpClient
- Object
- Rev::HttpClient
- Revactor::HttpClient
- Defined in:
- lib/revactor/http_client.rb
Overview
A high performance HTTP client which wraps the asynchronous client in Rev
Constant Summary collapse
- REQUEST_TIMEOUT =
Default timeout for HTTP requests (until the response header is received)
60
- READ_TIMEOUT =
Read timeout for responses from the server
30
- MAX_REDIRECTS =
Maximum number of HTTP redirects to follow
10
- REDIRECT_STATUSES =
Statuses which indicate the request was redirected
[301, 302, 303, 307]
Class Method Summary collapse
- .connect(host, port = 80) ⇒ Object
-
.request(method, uri, options = {}) ⇒ Object
Perform an HTTP request for the given method and return a response object.
Instance Method Summary collapse
-
#controller=(controller) ⇒ Object
Change the controlling Actor for active mode reception Set the controlling actor.
-
#initialize(socket) ⇒ HttpClient
constructor
A new instance of HttpClient.
-
#request(method, path, options = {}) ⇒ Object
Initiate an HTTP request for the given path using the given method Supports the following options:.
Constructor Details
#initialize(socket) ⇒ HttpClient
Returns a new instance of HttpClient.
104 105 106 107 |
# File 'lib/revactor/http_client.rb', line 104 def initialize(socket) super @controller = @receiver ||= Actor.current end |
Class Method Details
.connect(host, port = 80) ⇒ Object
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
# File 'lib/revactor/http_client.rb', line 28 def connect(host, port = 80) client = super client.instance_variable_set :@receiver, Actor.current client.attach Rev::Loop.default Actor.receive do |filter| filter.when(T[Object, client]) do |, _| case when :http_connected client.disable return client when :http_connect_failed raise TCP::ConnectError, "connection refused" when :http_resolve_failed raise TCP::ResolveError, "couldn't resolve #{host}" else raise "unexpected message for #{client.inspect}: #{.inspect}" end end filter.after(TCP::CONNECT_TIMEOUT) do client.close unless client.closed? raise TCP::ConnectError, "connection timed out" end end end |
.request(method, uri, options = {}) ⇒ Object
Perform an HTTP request for the given method and return a response object
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
# File 'lib/revactor/http_client.rb', line 55 def request(method, uri, = {}) follow_redirects = .has_key?(:follow_redirects) ? [:follow_redirects] : true uri = URI.parse(uri) MAX_REDIRECTS.times do raise URI::InvalidURIError, "invalid HTTP URI: #{uri}" unless uri.is_a? URI::HTTP = uri.is_a?(URI::HTTPS) ? .merge(:ssl => true) : client = connect(uri.host, uri.port) response = client.request(method, uri.request_uri, ) # Request complete unless follow_redirects and REDIRECT_STATUSES.include? response.status return response unless block_given? begin yield response ensure response.close end return end response.close location = response.headers['location'] raise "redirect with no location header: #{uri}" if location.nil? # Convert path-based redirects to URIs unless /^[a-z]+:\/\// === location location = "#{uri.scheme}://#{uri.host}" << File.(location, uri.path) end uri = URI.parse(location) end raise HttpClientError, "exceeded maximum of #{MAX_REDIRECTS} redirects" end |
Instance Method Details
#controller=(controller) ⇒ Object
Change the controlling Actor for active mode reception Set the controlling actor
111 112 113 114 115 116 |
# File 'lib/revactor/http_client.rb', line 111 def controller=(controller) raise ArgumentError, "controller must be an actor" unless controller.is_a? Actor @receiver = controller if @receiver == @controller @controller = controller end |
#request(method, path, options = {}) ⇒ Object
Initiate an HTTP request for the given path using the given method Supports the following options:
ssl: Boolean
If true, an HTTPS request will be made
head: {Key: Value, Key2: Value2}
Specify HTTP headers, e.g. {'Connection': 'close'}
query: {Key: Value}
Specify query string parameters (auto-escaped)
cookies: {Key: Value}
Specify hash of cookies (auto-escaped)
body: String
Specify the request body (you must encode it for now)
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 |
# File 'lib/revactor/http_client.rb', line 136 def request(method, path, = {}) if [:ssl] ssl_handshake Actor.receive do |filter| filter.when(T[:https_connected, self]) do disable end filter.when(T[:http_closed, self]) do raise EOFError, "SSL handshake failed" end filter.after(TCP::CONNECT_TIMEOUT) do close unless closed? raise TCP::ConnectError, "SSL handshake timed out" end end end super enable Actor.receive do |filter| filter.when(T[:http_response_header, self]) do |_, _, response_header| return HttpResponse.new(self, response_header) end filter.when(T[:http_error, self, Object]) do |_, _, reason| close unless closed? raise HttpClientError, reason end filter.when(T[:http_closed, self]) do raise EOFError, "connection closed unexpectedly" end filter.after(REQUEST_TIMEOUT) do @finished = true close unless closed? raise HttpClientError, "request timed out" end end end |