Class: Portless::Proxy

Inherits:
Object
  • Object
show all
Defined in:
lib/portless/proxy.rb

Overview

The reverse proxy daemon (async-http: HTTP/1.1 + TLS + WebSockets; HTTP/2 in phase 2). Routes by Host to a backend 127.0.0.1: from the route store — exact match, then wildcard .name — adds X-Forwarded-, stamps the X-Portless-Rb health header, guards against proxy loops, and re-reads routes.json per request so new apps appear without a restart. A sibling :80 listener 302-redirects to HTTPS. Mirrors portless's proxy.ts.

Constant Summary collapse

HOP_HEADER =
"x-rb-portless-hops"
HOP_BY_HOP =
%w[connection keep-alive proxy-authenticate proxy-authorization
te trailers transfer-encoding upgrade host].freeze

Instance Method Summary collapse

Constructor Details

#initialize(port:, tls: true, route_store: RouteStore.new, certs: Certs.new) ⇒ Proxy

Returns a new instance of Proxy.



22
23
24
25
26
27
28
29
# File 'lib/portless/proxy.rb', line 22

def initialize(port:, tls: true, route_store: RouteStore.new, certs: Certs.new)
  @port = port
  @tls = tls
  @route_store = route_store
  @certs = certs
  @clients = {}
  @host_contexts = {}
end

Instance Method Details

#route_for(host) ⇒ Object

Exact host match, then wildcard fallback so *.name.localhost all reach the single app registered as name.localhost.



47
48
49
50
51
52
# File 'lib/portless/proxy.rb', line 47

def route_for(host)
  host = host.to_s.split(":").first.to_s.downcase
  routes = @route_store.routes
  routes.find { |r| r.hostname == host } ||
    routes.find { |r| host.end_with?(".#{r.hostname}") }
end

#runObject



31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/portless/proxy.rb', line 31

def run
  State.ensure_dir!
  @certs.ensure_ca! if @tls
  write_markers
  install_signal_handlers

  Async do
    make_server(listen_endpoint).run
    start_redirect_listener if @tls && @port != Constants::HTTP_PORT
  end
ensure
  cleanup
end