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
- ROTATE_LOGS_LABEL =
Label for the Loc'd proxy agent itself
'com.nrser.locd.rotate-logs'
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
.plist
if 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.
190 191 192 193 194 195 196 197 198 199 200 |
# File 'lib/locd/proxy.rb', line 190 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.
90 91 92 93 94 95 |
# File 'lib/locd/proxy.rb', line 90 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.
103 104 105 |
# File 'lib/locd/proxy.rb', line 103 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.
208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 |
# File 'lib/locd/proxy.rb', line 208 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.
58 59 60 |
# File 'lib/locd/proxy.rb', line 58 def self.headers_received? data data.include? "\r\n\r\n" end |
.http_response_for(status, text) ⇒ String
Generate an HTTP text response string.
74 75 76 77 78 79 80 81 82 |
# File 'lib/locd/proxy.rb', line 74 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.
236 237 238 239 240 241 242 |
# File 'lib/locd/proxy.rb', line 236 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
176 177 178 |
# File 'lib/locd/proxy.rb', line 176 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.
122 123 124 125 126 127 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 |
# File 'lib/locd/proxy.rb', line 122 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.
256 257 258 259 260 261 262 263 264 265 |
# File 'lib/locd/proxy.rb', line 256 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 |