Module: OKF::Server::Runner
- Defined in:
- lib/okf/server/runner.rb
Overview
Runs a Rack app under WEBrick — the handful of lines a rackup dependency
would otherwise bring in. WEBrick ships with Ruby up to 2.7 and as the
webrick gem from 3.0 on; both work here, so the gem's server mode keeps
rack's own Ruby support range (>= 2.4).
The env it builds covers what a GET-serving Rack app needs (method, path, query, headers, rack.input); it is not a general CGI bridge. Part of the shell — it opens sockets.
Class Method Summary collapse
-
.build(app, host:, port:) ⇒ Object
A configured-but-not-started WEBrick server, so callers (and tests) can pick the port (0 = ephemeral), start it on their own thread, and shut it down deterministically.
- .env_for(request) ⇒ Object
- .handle(app, request, response) ⇒ Object
-
.read_body(request) ⇒ Object
The request body as a string; bodyless requests (every GET this server sees) read as "".
-
.run(app, host:, port:) ⇒ Object
Serve
appuntil interrupted (INT/TERM shut the server down).
Class Method Details
.build(app, host:, port:) ⇒ Object
A configured-but-not-started WEBrick server, so callers (and tests) can pick the port (0 = ephemeral), start it on their own thread, and shut it down deterministically.
29 30 31 32 33 34 35 36 |
# File 'lib/okf/server/runner.rb', line 29 def build(app, host:, port:) server = WEBrick::HTTPServer.new( BindAddress: host, Port: port, Logger: WEBrick::Log.new(nil, WEBrick::BasicLog::WARN), AccessLog: [] ) server.mount_proc("/") { |request, response| handle(app, request, response) } server end |
.env_for(request) ⇒ Object
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
# File 'lib/okf/server/runner.rb', line 49 def env_for(request) env = { "REQUEST_METHOD" => request.request_method, "SCRIPT_NAME" => "", "PATH_INFO" => request.path, "QUERY_STRING" => request.query_string.to_s, "SERVER_NAME" => request.host.to_s, "SERVER_PORT" => request.port.to_s, "SERVER_PROTOCOL" => "HTTP/#{request.http_version}", "rack.url_scheme" => "http", "rack.input" => StringIO.new(read_body(request)), "rack.errors" => $stderr } request.each { |name, value| env["HTTP_#{name.upcase.tr("-", "_")}"] = value } # Rack reads the entity headers unprefixed. env["CONTENT_TYPE"] = env.delete("HTTP_CONTENT_TYPE") if env.key?("HTTP_CONTENT_TYPE") env["CONTENT_LENGTH"] = env.delete("HTTP_CONTENT_LENGTH") if env.key?("HTTP_CONTENT_LENGTH") env end |
.handle(app, request, response) ⇒ Object
38 39 40 41 42 43 44 45 46 47 |
# File 'lib/okf/server/runner.rb', line 38 def handle(app, request, response) status, headers, body = app.call(env_for(request)) response.status = status.to_i headers.each { |name, value| response[name] = value } payload = String.new body.each { |chunk| payload << chunk } # a Rack body only guarantees #each response.body = payload ensure body.close if body.respond_to?(:close) end |
.read_body(request) ⇒ Object
The request body as a string; bodyless requests (every GET this server sees) read as "".
71 72 73 74 75 |
# File 'lib/okf/server/runner.rb', line 71 def read_body(request) request.body.to_s rescue WEBrick::HTTPStatus::Status, StandardError "" end |
.run(app, host:, port:) ⇒ Object
Serve app until interrupted (INT/TERM shut the server down).
20 21 22 23 24 |
# File 'lib/okf/server/runner.rb', line 20 def run(app, host:, port:) server = build(app, host: host, port: port) %w[INT TERM].each { |signal| trap(signal) { server.shutdown } } server.start end |