Last active
January 8, 2021 03:15
-
-
Save kirs/2dd4fcae9983df8b7b5b6c335b97f8e3 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'webrick' | |
# How much of this is solved by frozen string literal? | |
Ractor.make_shareable(WEBrick::Config::HTTP) | |
Ractor.make_shareable(WEBrick::LF) | |
Ractor.make_shareable(WEBrick::CRLF) | |
Ractor.make_shareable(WEBrick::HTTPRequest::BODY_CONTAINABLE_METHODS) | |
Ractor.make_shareable(WEBrick::HTTPStatus::StatusMessage) | |
# To pick up changes from https://github.com/ruby/ruby/pull/4007 | |
Object.send(:remove_const, :URI) | |
require '/Users/kir/src/github.com/ruby/ruby/lib/uri.rb' | |
require 'rack' | |
# Make it frozen | |
Ractor.make_shareable(Rack::VERSION) | |
# https://github.com/ruby/ruby/pull/4008 | |
Ractor.make_shareable(Time::RFC2822_DAY_NAME) | |
Ractor.make_shareable(Time::RFC2822_MONTH_NAME) | |
require 'uri' | |
Ractor.make_shareable(URI::RFC3986_PARSER) | |
Ractor.make_shareable(URI::DEFAULT_PARSER) | |
require 'stringio' | |
pipe = Ractor.new do | |
loop do | |
Ractor.yield(Ractor.recv, move: true) | |
end | |
end | |
# has to be explicitly required from the main thread: | |
# https://bugs.ruby-lang.org/issues/17477 | |
require 'pp' | |
def env_from_request(req) | |
env = req.meta_vars | |
env.delete_if { |k, v| v.nil? } | |
rack_input = StringIO.new(req.body.to_s) | |
rack_input.set_encoding(Encoding::BINARY) | |
env.update( | |
Rack::RACK_VERSION => Rack::VERSION, | |
Rack::RACK_INPUT => rack_input, | |
Rack::RACK_ERRORS => $stderr, | |
Rack::RACK_MULTITHREAD => true, | |
Rack::RACK_MULTIPROCESS => false, | |
Rack::RACK_RUNONCE => false, | |
Rack::RACK_URL_SCHEME => ["yes", "on", "1"].include?(env[Rack::HTTPS]) ? "https" : "http" | |
) | |
env[Rack::QUERY_STRING] ||= "" | |
unless env[Rack::PATH_INFO] == "" | |
path, n = req.request_uri.path, env[Rack::SCRIPT_NAME].length | |
env[Rack::PATH_INFO] = path[n, path.length - n] | |
end | |
env[Rack::REQUEST_PATH] ||= [env[Rack::SCRIPT_NAME], env[Rack::PATH_INFO]].join | |
env | |
end | |
CPU_COUNT = 4 | |
workers = CPU_COUNT.times.map do | |
Ractor.new(pipe) do |pipe| | |
app = lambda do |e| | |
[200, {'Content-Type' => 'text/html'}, ['hello world']] | |
end | |
loop do | |
s = pipe.take | |
req = WEBrick::HTTPRequest.new(WEBrick::Config::HTTP.merge(RequestTimeout: nil)) | |
req.parse(s) | |
env = env_from_request(req) | |
status, headers, body = app.call(env) | |
resp = WEBrick::HTTPResponse.new(WEBrick::Config::HTTP) | |
begin | |
resp.status = status.to_i | |
io_lambda = nil | |
headers.each { |k, vs| | |
if k.downcase == "set-cookie" | |
resp.cookies.concat vs.split("\n") | |
else | |
# Since WEBrick won't accept repeated headers, | |
# merge the values per RFC 1945 section 4.2. | |
resp[k] = vs.split("\n").join(", ") | |
end | |
} | |
body.each { |part| | |
resp.body << part | |
} | |
ensure | |
body.close if body.respond_to? :close | |
end | |
pp env | |
resp.send_response(s) | |
end | |
end | |
end | |
listener = Ractor.new(pipe) do |pipe| | |
server = TCPServer.new(8080) | |
loop do | |
conn, _ = server.accept | |
pipe.send(conn, move: true) | |
end | |
end | |
loop do | |
Ractor.select(listener, *workers) | |
# if the line above returned, one of the workers or the listener has crashed | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment