Skip to content

Commit

Permalink
more stuffs
Browse files Browse the repository at this point in the history
  • Loading branch information
nateberkopec committed Sep 26, 2019
1 parent 4da434a commit 6b84cd1
Show file tree
Hide file tree
Showing 4 changed files with 136 additions and 123 deletions.
155 changes: 37 additions & 118 deletions lib/puma/binder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

require 'puma/const'
require 'puma/util'
require 'puma/binding'

module Puma
class Binder
Expand All @@ -18,84 +19,27 @@ def initialize(events)
@bindings = []
@inherited_fds = {}
@activated_sockets = {}

@proto_env = {
"rack.version".freeze => RACK_VERSION,
"rack.errors".freeze => events.stderr,
"rack.multithread".freeze => true,
"rack.multiprocess".freeze => false,
"rack.run_once".freeze => false,
"SCRIPT_NAME".freeze => ENV['SCRIPT_NAME'] || "",

# I'd like to set a default CONTENT_TYPE here but some things
# depend on their not being a default set and inferring
# it from the content. And so if i set it here, it won't
# infer properly.

"QUERY_STRING".freeze => "",
SERVER_PROTOCOL => HTTP_11,
SERVER_SOFTWARE => PUMA_SERVER_STRING,
GATEWAY_INTERFACE => CGI_VER
}

@envs = {}
end

class Binding
extend Forwardable

def initialize(io, ssl_server = nil)
@io = io
@ssl_server = ssl_server
end
PROTO_ENV = {
"rack.version".freeze => RACK_VERSION,
"rack.multithread".freeze => true,
"rack.multiprocess".freeze => false,
"rack.run_once".freeze => false,
"SCRIPT_NAME".freeze => ENV['SCRIPT_NAME'] || "",

attr_reader :io

def to_s
"#{protocol}://#{addrinfo_to_uri}"
end
# I'd like to set a default CONTENT_TYPE here but some things
# depend on their not being a default set and inferring
# it from the content. And so if i set it here, it won't
# infer properly.

def protocol
if ssl?
"ssl"
elsif tcp?
"tcp"
elsif unix?
"unix"
end
end

def tcp?
TCPServer === io
end

def ssl?
defined?(MiniSSL::Server) && @ssl_server
end

def unix?
defined?(UNIXServer) && UNIXServer === io
end

def_delegators :@io, :close, :local_address
def_delegators :@ssl_server, :no_tlsv1, :no_tlsv1_1

private

def addrinfo_to_uri
if local_address.ipv6?
"[#{local_address.ip_address}]:#{local_address.ip_port}"
elsif local_address.ipv4?
local_address.ip_unpack.join(':')
elsif local_address.unix?
local_address.unix_path
end
end
end
"QUERY_STRING".freeze => "",
SERVER_PROTOCOL => HTTP_11,
SERVER_SOFTWARE => PUMA_SERVER_STRING,
GATEWAY_INTERFACE => CGI_VER
}

def env(sock)
@envs.fetch(sock, @proto_env)
end
attr_reader :bindings

def close
@bindings.each(&:close)
Expand All @@ -105,6 +49,16 @@ def bound_ios
@bindings.map(&:io)
end

def env_for_io(io)
@env_cache ||= Hash.new do |h, key|
binding_env = @bindings.find { |b| b.io == key }.env
env = PROTO_ENV.dup
env.merge!(binding_env).merge!("rack.errors".freeze => @events.stderr)
h[key] = env
end
@env_cache[io]
end

def import_from_env
remove = []

Expand Down Expand Up @@ -140,6 +94,7 @@ def import_from_env

def parse(binds, logger)
binds.each do |str|
puts str
uri = URI.parse str
case uri.scheme
when "tcp"
Expand Down Expand Up @@ -328,20 +283,13 @@ def add_tcp_listener(host, port, optimize_for_latency=true, backlog=1024)
@connected_port = s.addr[1]

@bindings << Binding.new(s)
s
end

attr_reader :connected_port

def inherit_tcp_listener(host, port, fd)
if fd.kind_of? TCPServer
s = fd
else
s = TCPServer.for_fd(fd)
end

s = fd.kind_of? TCPServer ? fd : TCPServer.for_fd(fd)
@bindings << Binding.new(s)
s
end

def add_ssl_listener(host, port, ctx,
Expand All @@ -365,33 +313,19 @@ def add_ssl_listener(host, port, ctx,
s.setsockopt(Socket::SOL_SOCKET,Socket::SO_REUSEADDR, true)
s.listen backlog


ssl = MiniSSL::Server.new s, ctx
env = @proto_env.dup
env[HTTPS_KEY] = HTTPS
@envs[ssl] = env

@bindings << Binding.new(ssl.to_io, ssl)
s
@bindings << Binding.new(s, ssl)
end

def inherit_ssl_listener(fd, ctx)
require 'puma/minissl'
MiniSSL.check

if fd.kind_of? TCPServer
s = fd
else
s = TCPServer.for_fd(fd)
end
s = fd.kind_of? TCPServer ? fd : TCPServer.for_fd(fd)
ssl = MiniSSL::Server.new(s, ctx)

env = @proto_env.dup
env[HTTPS_KEY] = HTTPS
@envs[ssl] = env

@bindings << Binding.new(ssl.to_io, ssl)
s
@bindings << Binding.new(s, ssl)
end

# Tell the server to listen on +path+ as a UNIX domain socket.
Expand Down Expand Up @@ -424,39 +358,24 @@ def add_unix_listener(path, umask=nil, mode=nil, backlog=1024)
if mode
File.chmod mode, path
end

env = @proto_env.dup
env[REMOTE_ADDR] = "127.0.0.1"
@envs[s] = env

s
end

def inherit_unix_listener(path, fd)
if fd.kind_of? TCPServer
s = fd
else
s = UNIXServer.for_fd fd
end
@bindings << Binding.new(s)
# TODO: bug? Should this read kind_of? UNIXServer?
s = fd.kind_of? TCPServer ? fd : UNIXServer.for_fd(fd)

env = @proto_env.dup
env[REMOTE_ADDR] = "127.0.0.1"
@envs[s] = env

s
@bindings << Binding.new(s)
end

def close_listeners
@bindings.each do |binder|
binder.close
next unless binder.unix?
File.unlink(binder.io.path)
binder.unlink_fd if binder.unix?
end
end

def close_unix_paths
binders.select(&:unix?).each { |b| File.unlink(b.path) if File.exist?(b.path) }
@bindings.select(&:unix?).each(&:unlink_fd)
end

def redirects_for_restart
Expand Down
69 changes: 69 additions & 0 deletions lib/puma/binding.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
module Puma
class Binding
include Puma::Const
extend Forwardable

def initialize(io, ssl_server = nil)
@io = io
@ssl_server = ssl_server
@path = io.path if unix?
end

attr_reader :io

def to_s
"#{protocol}://#{addrinfo_to_uri}"
end

def protocol
if ssl?
"ssl"
elsif tcp?
"tcp"
elsif unix?
"unix"
end
end

def tcp?
TCPServer === io
end

def ssl?
defined?(MiniSSL::Server) && @ssl_server
end

def unix?
defined?(UNIXServer) && UNIXServer === io
end

def unlink_fd
File.unlink(@path) if File.exist?(@path)
end

def env
if unix?
{ REMOTE_ADDR => "127.0.0.1" }
elsif ssl?
{ HTTPS_KEY => HTTPS }
else
{}
end
end

def_delegators :@io, :close, :local_address
def_delegators :@ssl_server, :no_tlsv1, :no_tlsv1_1

private

def addrinfo_to_uri
if local_address.ipv6?
"[#{local_address.ip_address}]:#{local_address.ip_port}"
elsif local_address.ipv4?
local_address.ip_unpack.join(':')
elsif local_address.unix?
local_address.unix_path
end
end
end
end
2 changes: 1 addition & 1 deletion lib/puma/server.rb
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,7 @@ def handle_servers
else
begin
if io = sock.accept_nonblock
client = Client.new io, @binder.env(sock)
client = Client.new io, @binder.env_for_io(sock)
if remote_addr_value
client.peerip = remote_addr_value
elsif remote_addr_header
Expand Down
33 changes: 29 additions & 4 deletions test/test_binder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,34 @@ def test_allows_both_tcp_and_unix
assert_parsing_logs_uri [:tcp, :unix]
end

def test_binder_for_env
@binder.parse(["tcp://localhost:#{UniquePort.call}"], @events)
io = @binder.bindings.first.io

proto = Puma::Binder::PROTO_ENV
env = @binder.env_for_io(io)

assert_equal(env, env.merge(proto)) # Env contains the entire PROTO_ENV
assert_equal @events.stderr, env["rack.errors"]
end

def test_binder_for_env_unix
skip UNIX_SKT_MSG unless UNIX_SKT_EXIST
@binder.parse(["unix://test/#{name}_server.sock"], @events)
io = @binder.bindings.first.io

assert_equal("127.0.0.1", @binder.env_for_io(io)[Puma::Const::REMOTE_ADDR])
ensure
@binder.close_unix_paths if UNIX_SKT_EXIST
end

def test_binder_for_env_ssl
@binder.parse(["ssl://localhost:0?key=#{key}&cert=#{cert}"], @events)
io = @binder.bindings.first.io

assert_equal(Puma::Const::HTTPS, @binder.env_for_io(io)[Puma::Const::HTTPS_KEY])
end

private

def assert_parsing_logs_uri(order = [:unix, :tcp])
Expand All @@ -102,10 +130,7 @@ def assert_parsing_logs_uri(order = [:unix, :tcp])
assert stdout.include?(uri_unix), "\n#{stdout}\n"
assert stdout.include?(uri_tcp) , "\n#{stdout}\n"
ensure
if UNIX_SKT_EXIST
@binder.close
File.unlink(path_unix) if File.exist? path_unix
end
@binder.close_unix_paths if UNIX_SKT_EXIST
end
end

Expand Down

0 comments on commit 6b84cd1

Please sign in to comment.