83 lines
1.9 KiB
Ruby
83 lines
1.9 KiB
Ruby
"""
|
|
Auto-generated template used by vercel dev (Ruby, Rack)
|
|
Serves static files from PUBLIC_DIR before delegating to the user Rack app.
|
|
|
|
This file is written to the project at .vercel/ruby/vc_init_dev.rb
|
|
and executed by the dev server launcher.
|
|
"""
|
|
|
|
require 'rack'
|
|
require 'rack/handler/webrick'
|
|
require 'webrick'
|
|
require 'socket'
|
|
|
|
$stdout.sync = true
|
|
$stderr.sync = true
|
|
|
|
USER_ENTRYPOINT = "__VC_DEV_ENTRYPOINT__"
|
|
PUBLIC_DIR = 'public'
|
|
|
|
def build_user_app
|
|
if USER_ENTRYPOINT.end_with?('.ru')
|
|
app, _ = Rack::Builder.parse_file(USER_ENTRYPOINT)
|
|
app
|
|
else
|
|
# For dev we only support Rack entrypoints (.ru) to ensure consistent behavior
|
|
abort("Unsupported entrypoint: #{USER_ENTRYPOINT}. Please use a Rack config (.ru) file for vercel dev.")
|
|
end
|
|
end
|
|
|
|
class StaticThenApp
|
|
def initialize(app, public_dir)
|
|
@app = app
|
|
@public_dir = public_dir
|
|
@file_server = Rack::File.new(public_dir)
|
|
@base = File.expand_path(public_dir)
|
|
end
|
|
|
|
def call(env)
|
|
req_path = env['PATH_INFO'] || '/'
|
|
# Normalize path and guard against traversal
|
|
safe = req_path.sub(/^\//, '')
|
|
full = File.expand_path(safe, @base)
|
|
|
|
if full.start_with?(@base + File::SEPARATOR) && File.file?(full)
|
|
# Delegate to Rack::File which handles HEAD/GET correctly
|
|
return @file_server.call(env)
|
|
end
|
|
|
|
@app.call(env)
|
|
end
|
|
end
|
|
|
|
def static_then_app(user_app)
|
|
StaticThenApp.new(user_app, PUBLIC_DIR)
|
|
end
|
|
|
|
host = '127.0.0.1'
|
|
begin
|
|
sock = TCPServer.new(host, 0)
|
|
port = sock.addr[1]
|
|
ensure
|
|
sock&.close
|
|
end
|
|
|
|
app = static_then_app(build_user_app)
|
|
|
|
logger = WEBrick::Log.new($stderr)
|
|
logger.level = WEBrick::Log::WARN
|
|
server = WEBrick::HTTPServer.new(
|
|
BindAddress: host,
|
|
Port: port,
|
|
AccessLog: [],
|
|
Logger: logger
|
|
)
|
|
|
|
# Mount the Rack app at root
|
|
server.mount '/', Rack::Handler::WEBrick, app
|
|
|
|
trap('INT') { server.shutdown }
|
|
trap('TERM') { server.shutdown }
|
|
|
|
puts "Serving on http://#{host}:#{server.config[:Port]}"
|
|
server.start
|