Module: Portless::Health
- Defined in:
- lib/portless/health.rb
Overview
"Is our proxy on this port?" — every proxied response carries the X-Portless-Rb header, so a HEAD probe distinguishes our proxy from any other process holding 443/80/1355. The default proxy is HTTPS, so we try a TLS handshake first (no noisy plaintext-to-TLS errors), then plain HTTP. Mirrors portless's isProxyRunning + discoverState.
Constant Summary collapse
- REQUEST =
"HEAD / HTTP/1.0\r\nHost: rb-portless.localhost\r\n\r\n"
Class Method Summary collapse
-
.discover_port ⇒ Object
The port our proxy is currently on, if any: an explicit marker file, else a probe of the usual suspects.
- .marker?(response) ⇒ Boolean
- .probe_plain(port, timeout) ⇒ Object
- .probe_tls(port, timeout) ⇒ Object
- .proxy_running?(port, timeout: 1.0) ⇒ Boolean
- .read_port_file ⇒ Object
Class Method Details
.discover_port ⇒ Object
The port our proxy is currently on, if any: an explicit marker file, else a probe of the usual suspects.
53 54 55 56 57 58 59 60 61 |
# File 'lib/portless/health.rb', line 53 def discover_port from_file = read_port_file return from_file if from_file && proxy_running?(from_file) candidates = [ Integer(ENV["PORTLESS_PORT"], exception: false), Constants::HTTPS_PORT, Constants::HTTP_PORT, Constants::FALLBACK_PROXY_PORT ].compact candidates.each { |port| return port if proxy_running?(port) } nil end |
.marker?(response) ⇒ Boolean
49 |
# File 'lib/portless/health.rb', line 49 def marker?(response) = response.to_s.downcase.include?(Constants::HEALTH_HEADER) |
.probe_plain(port, timeout) ⇒ Object
39 40 41 42 43 44 45 46 47 |
# File 'lib/portless/health.rb', line 39 def probe_plain(port, timeout) Socket.tcp("127.0.0.1", port, connect_timeout: timeout) do |sock| sock.write(REQUEST) sock.close_write marker?(Timeout.timeout(timeout) { sock.read(4096) }) end rescue StandardError false end |
.probe_tls(port, timeout) ⇒ Object
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
# File 'lib/portless/health.rb', line 22 def probe_tls(port, timeout) socket = Socket.tcp("127.0.0.1", port, connect_timeout: timeout) ctx = OpenSSL::SSL::SSLContext.new ctx.verify_mode = OpenSSL::SSL::VERIFY_NONE ssl = OpenSSL::SSL::SSLSocket.new(socket, ctx) ssl.sync_close = true ssl.connect ssl.write(REQUEST) # Read timeout too — a port that accepts but never answers must not hang us. marker?(Timeout.timeout(timeout) { ssl.read(4096) }) rescue StandardError false ensure ssl&.close socket&.close unless ssl end |
.proxy_running?(port, timeout: 1.0) ⇒ Boolean
18 19 20 |
# File 'lib/portless/health.rb', line 18 def proxy_running?(port, timeout: 1.0) probe_tls(port, timeout) || probe_plain(port, timeout) end |
.read_port_file ⇒ Object
63 64 65 66 67 |
# File 'lib/portless/health.rb', line 63 def read_port_file Integer(File.read(State.proxy_port_file).strip, exception: false) rescue StandardError nil end |