Skip to content

Commit

Permalink
[close #1327] Fix double port bind in Rails
Browse files Browse the repository at this point in the history
The "default" configuration puma level is initialized with a "binds" of `tcp://0.0.0.0:9292`. Puma is designed to be able to bind to multiple ports. 

When a `:port` is sent from Rails along with an empty `user_supplied_options` then the port is treated as a "default". This is merged in with the system defaults, and then later converted into a "binds" via calling `config.port` in the `set_host_port_to_config` method. 

The bug comes due to the "level" of the configuration. Since both are being set on the same "level" the `port` call does not over-write the existing binds but instead prepends to the array. We can fix by ensuring that any binds in a given "level" are empty before setting it.
  • Loading branch information
schneems committed Aug 2, 2017
1 parent 238fad8 commit 0584a33
Show file tree
Hide file tree
Showing 3 changed files with 16 additions and 0 deletions.
4 changes: 4 additions & 0 deletions lib/puma/dsl.rb
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,10 @@ def bind(url)
@options[:binds] << url
end

def clear_binds!
@options[:binds] = []
end

# Define the TCP port to bind to. Use +bind+ for more advanced options.
#
def port(port, host=nil)
Expand Down
2 changes: 2 additions & 0 deletions lib/rack/handler/puma.rb
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ def self.valid_options
end
private
def self.set_host_port_to_config(host, port, config)
config.clear_binds! if host || port

if host && (host[0,1] == '.' || host[0,1] == '/')
config.bind "unix://#{host}"
elsif host && host =~ /^ssl:\/\//
Expand Down
10 changes: 10 additions & 0 deletions test/test_rack_handler.rb
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,16 @@ def test_config_wins_over_default
end
end

def test_user_port_wins_over_default_when_user_supplied_is_blank
user_port = 5001
@options[:user_supplied_options] = []
@options[:Port] = user_port
conf = Rack::Handler::Puma.config(->{}, @options)
conf.load

assert_equal ["tcp://0.0.0.0:#{user_port}"], conf.options[:binds]
end

def test_user_port_wins_over_default
user_port = 5001
@options[:Port] = user_port
Expand Down

0 comments on commit 0584a33

Please sign in to comment.