Module: Locd::Proxy
- Includes:
- NRSER::Log::Mixin
- Defined in:
- lib/locd/proxy.rb
Overview
Stuff for running the proxy server, which does "vhost"-style routing of HTTP requests it receives to user-defined sites.
It does this by matching the HTTP Host header against site labels.
Built off proxymachine, which is itself built on eventmachine.
Constant Summary collapse
- HOST_RE =
Regexp to match HTTP "Host" header line.
/^Host\:\ /i
Class Method Summary collapse
-
.allocate_port ⇒ Fixnum
Find a port in Proxy.port_range that is not already used by a Agent::Site to give to a new site.
-
.extract_host(lines) ⇒ String
Get the request host from HTTP header lines.
-
.extract_path(lines) ⇒ String
Get the request path from HTTP header lines.
-
.find_and_start_site(pattern) ⇒ Locd::Agent::Site
Um, find and start a Agent::Site from a pattern.
-
.headers_received?(data) ⇒ Boolean
See if the lines include complete HTTP headers.
-
.http_response_for(status, text) ⇒ String
Generate an HTTP text response string.
-
.port ⇒ Fixnum
Get the proxy's port from it's
.plistif it exists, otherwise from the config setting. -
.port_range ⇒ Range<Fixnum, Fixnum>
Range of ports to allocate to Agent::Site when one is not provided by the user.
-
.route(data) ⇒ Hash<Symbol, (Hash | Boolean)] Command for ProxyMachine.
Route request based on data, see ProxyMachine docs for details.
-
.serve(bind: , port: ) ⇒ void
Run the proxy server.
Class Method Details
.allocate_port ⇒ Fixnum
Find a port in port_range that is not already used by a Agent::Site to give to a new site.
196 197 198 199 200 201 202 203 204 205 206 |
# File 'lib/locd/proxy.rb', line 196 def self.allocate_port allocated_ports = Locd::Agent::Site.ports port = port_range.find { |port| ! allocated_ports.include? port } if port.nil? raise "Could not allocate port for #{ remote_key }" end port end |
.extract_host(lines) ⇒ String
Get the request host from HTTP header lines.
96 97 98 99 100 101 |
# File 'lib/locd/proxy.rb', line 96 def self.extract_host lines lines. find { |line| line =~ HOST_RE }. chomp. split( ' ', 2 )[1] end |
.extract_path(lines) ⇒ String
Get the request path from HTTP header lines.
109 110 111 |
# File 'lib/locd/proxy.rb', line 109 def self.extract_path lines lines[0].split( ' ' )[1] end |
.find_and_start_site(pattern) ⇒ Locd::Agent::Site
Um, find and start a Agent::Site from a pattern.
214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 |
# File 'lib/locd/proxy.rb', line 214 def self.find_and_start_site pattern logger.debug "Finding and starting site...", pattern: pattern site = Locd::Agent::Site.find_only! pattern logger.debug "Found site!", site: site if site.running? logger.debug "Site is RUNNING" else logger.debug "Site STOPPED, starting..." site.start logger.debug "Site started." end site end |
.headers_received?(data) ⇒ Boolean
See if the lines include complete HTTP headers.
Looks for the '\r\n\r\n' string that separates the headers from the
body.
64 65 66 |
# File 'lib/locd/proxy.rb', line 64 def self.headers_received? data data.include? "\r\n\r\n" end |
.http_response_for(status, text) ⇒ String
Generate an HTTP text response string.
80 81 82 83 84 85 86 87 88 |
# File 'lib/locd/proxy.rb', line 80 def self.http_response_for status, text [ "HTTP/1.1 #{ status }", "Content-Type: text/plain; charset=utf-8", "Status: #{ status }", "", text ].join( "\r\n" ) end |
.port ⇒ Fixnum
Get the proxy's port from it's .plist if it exists, otherwise from
the config setting.
242 243 244 245 246 247 248 |
# File 'lib/locd/proxy.rb', line 242 def self.port if proxy = Locd::Agent::Proxy.get proxy.port else Locd.config[:proxy, :port, type: t.pos_int] end end |
.port_range ⇒ Range<Fixnum, Fixnum>
Range of ports to allocate to Agent::Site when one is not provided by the user.
Start (inclusive) and end (exclusive) values come from site.ports.start
and site.ports.end config values, which default to
55000...56000
182 183 184 |
# File 'lib/locd/proxy.rb', line 182 def self.port_range Locd.config[:site, :ports, :start]...Locd.config[:site, :ports, :end] end |
.route(data) ⇒ Hash<Symbol, (Hash | Boolean)] Command for ProxyMachine.
This finds the agent using the host as a pattern, so it will match with unique partial label. I think in the case that the host is not the full label it should probably return a HTTP redirect to the full label so that the user URL is bookmark-abel, etc...?
Route request based on data, see ProxyMachine docs for details.
128 129 130 131 132 133 134 135 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 |
# File 'lib/locd/proxy.rb', line 128 def self.route data lines = data.lines logger.debug "Received data:\n#{ lines.pretty_inspect }" unless headers_received? data logger.debug "Have not yet received HTTP headers, waiting..." logger.debug lines: lines return {noop: true} end logger.debug "HTTP headers received, processing...\n#{ }" logger.debug lines: lines host = extract_host lines logger.debug host: host path = extract_path lines logger.debug path: path # Label is the domain without the port label = if host.include? ':' host.split( ':', 2 )[0] else host end site = find_and_start_site label remote_host = "#{ Locd.config[:site, :bind] }:#{ site.port }" pm_cmd = {remote: remote_host} logger.debug "Routing to remote", cmd: pm_cmd return pm_cmd rescue Locd::RequestError => error logger.error error error.to_proxy_machine_cmd rescue Exception => error logger.error error {close: http_response_for( '500 Server Error', error. )} end |
.serve(bind: , port: ) ⇒ void
This method returns an undefined value.
Run the proxy server.
262 263 264 265 266 267 268 269 270 271 |
# File 'lib/locd/proxy.rb', line 262 def self.serve bind: config[:proxy, :bind], port: config[:proxy, :port] logger.info "Loc'd is starting ProxyMachine, hang on a sec...", bind: bind, port: port require 'locd/proxymachine' ProxyMachine.set_router method( :route ) ProxyMachine.run 'locd', bind, port end |