unicorn Ruby/Rack server user+dev discussion/patches/pulls/bugs/help
 help / color / mirror / code / Atom feed
* Support default_middleware configurator method
@ 2018-09-13 19:20 Jeremy Evans
  2018-09-13 22:34 ` Eric Wong
  0 siblings, 1 reply; 9+ messages in thread
From: Jeremy Evans @ 2018-09-13 19:20 UTC (permalink / raw)
  To: unicorn-public

I was originally looking for a way to turn off default middleware
without having to specify the -N command line option every time.
After reading the Unicorn.builder code, I thought it may be
possible to do this by specifying the option as an embedded option
in the rackup file, via the following line at the top of the file:

#\-N

Unfortunately, while this works for many other command line options,
because of Unicorn's internals, this doesn't work for -N, as
embedded options are not parsed until after the check for skipping
default middleware is made.

This patch makes the embedded -N option work, as well as adds a
default_middleware configuration file option.  It does this by
passing the HttpServer instance to the lambda that returns the
rack application.  It uses arity checking to do this, like the
previous approach, but support an arity of 2 instead of just an
arity of 0 (which is still supported for backwards compatibility).

An alternative approach would be to parse the embedded options
inside Unicorn.builder, but that results in them getting parsed
twice as well as duplicating some code.  Additionally, embedded
options are less understandable than unicorn configuration file
options.  If you want a patch for that simpler approach, I have one.

Thanks,
Jeremy


From 90cca6ff773d58657a4b466a03e8a21b486c913f Mon Sep 17 00:00:00 2001
From: Jeremy Evans <code@jeremyevans.net>
Date: Thu, 13 Sep 2018 10:48:25 -0700
Subject: [PATCH] Support default_middleware configuration option

This allows for the equivalent of the
-N/--no-default_middleware command line option to be
specified in the configuration file.  It
also allows the -N/--no-default_middleware embedded
configuration option in the rackup file, which should
have worked previously but did not because embedded
configuration options weren't parsed until after the
app was built.

In order to allow the configuration method to work, have
the lambda that Unicorn.builder returns accept two arguments.
Technically, only one argument is needed for the HttpServer
instance, but I'm guessing if the lambda accepts a single
argument, we expect that to be a rack application instead
of a lambda that returns a rack application.

The command line option (or rackup embedded configuration
option) to disable default middleware will take precedence
over the unicorn configuration file option if both are
present.

For backwards compatibility, if the lambda passed to
HttpServer accepts 0 arguments, then call it without
arguments.
---
 lib/unicorn.rb              |  8 ++------
 lib/unicorn/configurator.rb | 11 +++++++++++
 lib/unicorn/http_server.rb  |  8 +++++---
 3 files changed, 18 insertions(+), 9 deletions(-)

diff --git a/lib/unicorn.rb b/lib/unicorn.rb
index b6dae36..5f2134d 100644
--- a/lib/unicorn.rb
+++ b/lib/unicorn.rb
@@ -45,12 +45,8 @@ def self.builder(ru, op)
       abort "rack and Rack::Builder must be available for processing #{ru}"
     end
 
-    # Op is going to get cleared before the returned lambda is called, so
-    # save this value so that it's still there when we need it:
-    no_default_middleware = op[:no_default_middleware]
-
     # always called after config file parsing, may be called after forking
-    lambda do ||
+    lambda do |_, server|
       inner_app = case ru
       when /\.ru$/
         raw = File.read(ru)
@@ -66,7 +62,7 @@ def self.builder(ru, op)
         pp({ :inner_app => inner_app })
       end
 
-      return inner_app if no_default_middleware
+      return inner_app unless server.default_middleware
 
       middleware = { # order matters
         ContentLength: nil,
diff --git a/lib/unicorn/configurator.rb b/lib/unicorn/configurator.rb
index f34d38b..9c36dfe 100644
--- a/lib/unicorn/configurator.rb
+++ b/lib/unicorn/configurator.rb
@@ -265,6 +265,14 @@ def worker_processes(nr)
     set_int(:worker_processes, nr, 1)
   end
 
+  # sets whether to add default middleware in the development and
+  # deployment RACK_ENVs.
+  #
+  # default_middleware is only available in unicorn 5.5.0+
+  def default_middleware(bool)
+    set_bool(:default_middleware, bool)
+  end
+
   # sets listeners to the given +addresses+, replacing or augmenting the
   # current set.  This is for the global listener pool shared by all
   # worker processes.  For per-worker listeners, see the after_fork example
@@ -706,6 +714,9 @@ def parse_rackup_file # :nodoc:
 
     /^#\\(.*)/ =~ File.read(ru) or return
     RACKUP[:optparse].parse!($1.split(/\s+/))
+    if RACKUP[:no_default_middleware]
+      set[:default_middleware] = false
+    end
 
     if RACKUP[:daemonize]
       # unicorn_rails wants a default pid path, (not plain 'unicorn')
diff --git a/lib/unicorn/http_server.rb b/lib/unicorn/http_server.rb
index b2bbddb..7531886 100644
--- a/lib/unicorn/http_server.rb
+++ b/lib/unicorn/http_server.rb
@@ -14,7 +14,8 @@ class Unicorn::HttpServer
   attr_accessor :app, :timeout, :worker_processes,
                 :before_fork, :after_fork, :before_exec,
                 :listener_opts, :preload_app,
-                :orig_app, :config, :ready_pipe, :user
+                :orig_app, :config, :ready_pipe, :user,
+                :default_middleware
   attr_writer   :after_worker_exit, :after_worker_ready, :worker_exec
 
   attr_reader :pid, :logger
@@ -70,6 +71,7 @@ def initialize(app, options = {})
     @app = app
     @request = Unicorn::HttpRequest.new
     @reexec_pid = 0
+    @default_middleware = true
     options = options.dup
     @ready_pipe = options.delete(:ready_pipe)
     @init_listeners = options[:listeners] ? options[:listeners].dup : []
@@ -784,12 +786,12 @@ def listener_names(listeners = LISTENERS)
   end
 
   def build_app!
-    if app.respond_to?(:arity) && app.arity == 0
+    if app.respond_to?(:arity) && app.arity == 0 || app.arity == 2
       if defined?(Gem) && Gem.respond_to?(:refresh)
         logger.info "Refreshing Gem list"
         Gem.refresh
       end
-      self.app = app.call
+      self.app = app.arity == 0 ? app.call : app.call(nil, self)
     end
   end
 
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: Support default_middleware configurator method
  2018-09-13 19:20 Support default_middleware configurator method Jeremy Evans
@ 2018-09-13 22:34 ` Eric Wong
  2018-09-14  0:00   ` Jeremy Evans
  0 siblings, 1 reply; 9+ messages in thread
From: Eric Wong @ 2018-09-13 22:34 UTC (permalink / raw)
  To: Jeremy Evans; +Cc: unicorn-public

Jeremy Evans <code@jeremyevans.net> wrote:
> I was originally looking for a way to turn off default middleware
> without having to specify the -N command line option every time.
> After reading the Unicorn.builder code, I thought it may be
> possible to do this by specifying the option as an embedded option
> in the rackup file, via the following line at the top of the file:
> 
> #\-N
> 
> Unfortunately, while this works for many other command line options,
> because of Unicorn's internals, this doesn't work for -N, as
> embedded options are not parsed until after the check for skipping
> default middleware is made.

That was intentional, I think.  We should never be encouraging
users to pollute config.ru and make it difficult to migrate/test
other servers.

> This patch makes the embedded -N option work, as well as adds a
> default_middleware configuration file option

I really hate the -N vs RACK_ENV=none redundancy...  Is -N still
needed for Rails or something else while keeping RACK_ENV unset?

Worse case is we only support default_middleware as a config
option (but I prefer not to add more options).  Embedded -N support
is an anti-feature which leads to lock-in.

Thanks.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Support default_middleware configurator method
  2018-09-13 22:34 ` Eric Wong
@ 2018-09-14  0:00   ` Jeremy Evans
  2018-09-14 10:56     ` Eric Wong
  0 siblings, 1 reply; 9+ messages in thread
From: Jeremy Evans @ 2018-09-14  0:00 UTC (permalink / raw)
  To: Eric Wong; +Cc: unicorn-public

On 09/13 10:34, Eric Wong wrote:
> Jeremy Evans <code@jeremyevans.net> wrote:
> > I was originally looking for a way to turn off default middleware
> > without having to specify the -N command line option every time.
> > After reading the Unicorn.builder code, I thought it may be
> > possible to do this by specifying the option as an embedded option
> > in the rackup file, via the following line at the top of the file:
> > 
> > #\-N
> > 
> > Unfortunately, while this works for many other command line options,
> > because of Unicorn's internals, this doesn't work for -N, as
> > embedded options are not parsed until after the check for skipping
> > default middleware is made.
> 
> That was intentional, I think.  We should never be encouraging
> users to pollute config.ru and make it difficult to migrate/test
> other servers.
> 
> > This patch makes the embedded -N option work, as well as adds a
> > default_middleware configuration file option
> 
> I really hate the -N vs RACK_ENV=none redundancy...  Is -N still
> needed for Rails or something else while keeping RACK_ENV unset?

I use RACK_ENV to configure the environment for my web applications, and
for a few reasons have used development/test/production as the
environment names.  I try as much as possible to have the development
environment mirror the production environment unless there is a good
reason to be different, and would like to avoid adding all of the
middleware Unicorn adds in development mode.

Additionally, let's say I want to add Rack::CommonLogger to both
development and production environments.  So in my config.ru, I add:

  use Rack::CommonLogger, Logger.new($stderr)

Now I load up the development version.  Then I have two common loggers
in development, with all requests being logged twice.  I currently
work around this by doing something like:

  unless ENV['RACK_ENV'] == 'development'
    use Rack::CommonLogger, Logger.new($stderr)
  end

I would like to avoid having to do that.

> Worse case is we only support default_middleware as a config
> option (but I prefer not to add more options).  Embedded -N support
> is an anti-feature which leads to lock-in.

I don't really care about embedded -N support.  I actually didn't even
know embedded command file options were possible until I saw the
comment in Unicorn.builder.  I just want some way to specify not to
load default middleware without requiring a command line option each
time.

Thanks,
Jeremy

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Support default_middleware configurator method
  2018-09-14  0:00   ` Jeremy Evans
@ 2018-09-14 10:56     ` Eric Wong
  2018-09-14 15:03       ` Jeremy Evans
  0 siblings, 1 reply; 9+ messages in thread
From: Eric Wong @ 2018-09-14 10:56 UTC (permalink / raw)
  To: Jeremy Evans; +Cc: unicorn-public

Jeremy Evans <code@jeremyevans.net> wrote:
> On 09/13 10:34, Eric Wong wrote:
> > Worse case is we only support default_middleware as a config
> > option (but I prefer not to add more options).  Embedded -N support
> > is an anti-feature which leads to lock-in.
> 
> I don't really care about embedded -N support.  I actually didn't even
> know embedded command file options were possible until I saw the
> comment in Unicorn.builder.  I just want some way to specify not to
> load default middleware without requiring a command line option each
> time.

Alright, I can accept a patch for the unicorn-specific config
option only; but it definitely must not be allowed to work in
.ru files.  Thanks.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Support default_middleware configurator method
  2018-09-14 10:56     ` Eric Wong
@ 2018-09-14 15:03       ` Jeremy Evans
  2018-09-19  7:39         ` Eric Wong
  0 siblings, 1 reply; 9+ messages in thread
From: Jeremy Evans @ 2018-09-14 15:03 UTC (permalink / raw)
  To: Eric Wong; +Cc: unicorn-public

On 09/14 10:56, Eric Wong wrote:
> Jeremy Evans <code@jeremyevans.net> wrote:
> > On 09/13 10:34, Eric Wong wrote:
> > > Worse case is we only support default_middleware as a config
> > > option (but I prefer not to add more options).  Embedded -N support
> > > is an anti-feature which leads to lock-in.
> > 
> > I don't really care about embedded -N support.  I actually didn't even
> > know embedded command file options were possible until I saw the
> > comment in Unicorn.builder.  I just want some way to specify not to
> > load default middleware without requiring a command line option each
> > time.
> 
> Alright, I can accept a patch for the unicorn-specific config
> option only; but it definitely must not be allowed to work in
> .ru files.  Thanks.

OK. To implement that, I modified the bin/unicorn file so -N
is only respected while parsing ARGV, and not while parsing
embedded configuration file options.

Thanks,
Jeremy

From d628cad9e5c4b6e15783f1089b3bd84f42061bfb Mon Sep 17 00:00:00 2001
From: Jeremy Evans <code@jeremyevans.net>
Date: Thu, 13 Sep 2018 10:48:25 -0700
Subject: [PATCH] Support default_middleware configuration option

This allows for the equivalent of the
-N/--no-default_middleware command line option to be
specified in the configuration file so it doesn't
need to be specified on the command line every time
unicorn is executed.

It explicitly excludes the use of -N/--no-default_middleware
as an embedded configuration option in the rackup file, by
ignoring the options after ARGV is parsed.

In order to allow the configuration method to work, have
the lambda that Unicorn.builder returns accept two arguments.
Technically, only one argument is needed for the HttpServer
instance, but I'm guessing if the lambda accepts a single
argument, we expect that to be a rack application instead
of a lambda that returns a rack application.

The command line option option to disable default middleware
will take precedence over the unicorn configuration file option
if both are present.

For backwards compatibility, if the lambda passed to
HttpServer accepts 0 arguments, then call it without
arguments.
---
 bin/unicorn                 |  4 +++-
 lib/unicorn.rb              |  8 ++------
 lib/unicorn/configurator.rb | 11 +++++++++++
 lib/unicorn/http_server.rb  |  8 +++++---
 4 files changed, 21 insertions(+), 10 deletions(-)

diff --git a/bin/unicorn b/bin/unicorn
index 3c5e5cb..00c8464 100755
--- a/bin/unicorn
+++ b/bin/unicorn
@@ -6,6 +6,7 @@
 ENV["RACK_ENV"] ||= "development"
 rackup_opts = Unicorn::Configurator::RACKUP
 options = rackup_opts[:options]
+set_no_default_middleware = true
 
 op = OptionParser.new("", 24, '  ') do |opts|
   cmd = File.basename($0)
@@ -60,7 +61,7 @@
 
   opts.on("-N", "--no-default-middleware",
           "do not load middleware implied by RACK_ENV") do |e|
-    rackup_opts[:no_default_middleware] = true
+    rackup_opts[:no_default_middleware] = true if set_no_default_middleware
   end
 
   opts.on("-D", "--daemonize", "run daemonized in the background") do |d|
@@ -110,6 +111,7 @@
   opts.parse! ARGV
 end
 
+set_no_default_middleware = false
 app = Unicorn.builder(ARGV[0] || 'config.ru', op)
 op = nil
 
diff --git a/lib/unicorn.rb b/lib/unicorn.rb
index b6dae36..5f2134d 100644
--- a/lib/unicorn.rb
+++ b/lib/unicorn.rb
@@ -45,12 +45,8 @@ def self.builder(ru, op)
       abort "rack and Rack::Builder must be available for processing #{ru}"
     end
 
-    # Op is going to get cleared before the returned lambda is called, so
-    # save this value so that it's still there when we need it:
-    no_default_middleware = op[:no_default_middleware]
-
     # always called after config file parsing, may be called after forking
-    lambda do ||
+    lambda do |_, server|
       inner_app = case ru
       when /\.ru$/
         raw = File.read(ru)
@@ -66,7 +62,7 @@ def self.builder(ru, op)
         pp({ :inner_app => inner_app })
       end
 
-      return inner_app if no_default_middleware
+      return inner_app unless server.default_middleware
 
       middleware = { # order matters
         ContentLength: nil,
diff --git a/lib/unicorn/configurator.rb b/lib/unicorn/configurator.rb
index f34d38b..9c36dfe 100644
--- a/lib/unicorn/configurator.rb
+++ b/lib/unicorn/configurator.rb
@@ -265,6 +265,14 @@ def worker_processes(nr)
     set_int(:worker_processes, nr, 1)
   end
 
+  # sets whether to add default middleware in the development and
+  # deployment RACK_ENVs.
+  #
+  # default_middleware is only available in unicorn 5.5.0+
+  def default_middleware(bool)
+    set_bool(:default_middleware, bool)
+  end
+
   # sets listeners to the given +addresses+, replacing or augmenting the
   # current set.  This is for the global listener pool shared by all
   # worker processes.  For per-worker listeners, see the after_fork example
@@ -706,6 +714,9 @@ def parse_rackup_file # :nodoc:
 
     /^#\\(.*)/ =~ File.read(ru) or return
     RACKUP[:optparse].parse!($1.split(/\s+/))
+    if RACKUP[:no_default_middleware]
+      set[:default_middleware] = false
+    end
 
     if RACKUP[:daemonize]
       # unicorn_rails wants a default pid path, (not plain 'unicorn')
diff --git a/lib/unicorn/http_server.rb b/lib/unicorn/http_server.rb
index b2bbddb..7531886 100644
--- a/lib/unicorn/http_server.rb
+++ b/lib/unicorn/http_server.rb
@@ -14,7 +14,8 @@ class Unicorn::HttpServer
   attr_accessor :app, :timeout, :worker_processes,
                 :before_fork, :after_fork, :before_exec,
                 :listener_opts, :preload_app,
-                :orig_app, :config, :ready_pipe, :user
+                :orig_app, :config, :ready_pipe, :user,
+                :default_middleware
   attr_writer   :after_worker_exit, :after_worker_ready, :worker_exec
 
   attr_reader :pid, :logger
@@ -70,6 +71,7 @@ def initialize(app, options = {})
     @app = app
     @request = Unicorn::HttpRequest.new
     @reexec_pid = 0
+    @default_middleware = true
     options = options.dup
     @ready_pipe = options.delete(:ready_pipe)
     @init_listeners = options[:listeners] ? options[:listeners].dup : []
@@ -784,12 +786,12 @@ def listener_names(listeners = LISTENERS)
   end
 
   def build_app!
-    if app.respond_to?(:arity) && app.arity == 0
+    if app.respond_to?(:arity) && app.arity == 0 || app.arity == 2
       if defined?(Gem) && Gem.respond_to?(:refresh)
         logger.info "Refreshing Gem list"
         Gem.refresh
       end
-      self.app = app.call
+      self.app = app.arity == 0 ? app.call : app.call(nil, self)
     end
   end
 
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: Support default_middleware configurator method
  2018-09-14 15:03       ` Jeremy Evans
@ 2018-09-19  7:39         ` Eric Wong
  2018-09-21  0:21           ` Jeremy Evans
  2018-09-21  0:34           ` [PATCH 2/1] tests: ensure -N/--no-default-middleware not supported in config.ru Eric Wong
  0 siblings, 2 replies; 9+ messages in thread
From: Eric Wong @ 2018-09-19  7:39 UTC (permalink / raw)
  To: Jeremy Evans; +Cc: unicorn-public

Jeremy Evans <code@jeremyevans.net> wrote:
> OK. To implement that, I modified the bin/unicorn file so -N
> is only respected while parsing ARGV, and not while parsing
> embedded configuration file options.

Thanks.

Unfortunately, -N on the command-line was broken by your patch.
I fixed configurator.rb ordering (below) to pass t0300
integration test.

Also, using a non-config.ru .rb file (TestHandler in
test/unit/test_server.rb) was broken because of missing
parentheses.

Will squash the following changes in before pushing:

diff --git a/lib/unicorn/configurator.rb b/lib/unicorn/configurator.rb
index 9c36dfe..d426edf 100644
--- a/lib/unicorn/configurator.rb
+++ b/lib/unicorn/configurator.rb
@@ -88,6 +88,9 @@ def reload(merge_defaults = true) #:nodoc:
     RACKUP[:set_listener] and
       set[:listeners] << "#{RACKUP[:host]}:#{RACKUP[:port]}"
 
+    RACKUP[:no_default_middleware] and
+      set[:default_middleware] = false
+
     # unicorn_rails creates dirs here after working_directory is bound
     after_reload.call if after_reload
 
@@ -714,9 +717,6 @@ def parse_rackup_file # :nodoc:
 
     /^#\\(.*)/ =~ File.read(ru) or return
     RACKUP[:optparse].parse!($1.split(/\s+/))
-    if RACKUP[:no_default_middleware]
-      set[:default_middleware] = false
-    end
 
     if RACKUP[:daemonize]
       # unicorn_rails wants a default pid path, (not plain 'unicorn')
diff --git a/lib/unicorn/http_server.rb b/lib/unicorn/http_server.rb
index 7531886..62f6171 100644
--- a/lib/unicorn/http_server.rb
+++ b/lib/unicorn/http_server.rb
@@ -786,7 +786,7 @@ def listener_names(listeners = LISTENERS)
   end
 
   def build_app!
-    if app.respond_to?(:arity) && app.arity == 0 || app.arity == 2
+    if app.respond_to?(:arity) && (app.arity == 0 || app.arity == 2)
       if defined?(Gem) && Gem.respond_to?(:refresh)
         logger.info "Refreshing Gem list"
         Gem.refresh

But there's still no tests for the config file option...
I assume you tested that part locally?
Thanks again.

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: Support default_middleware configurator method
  2018-09-19  7:39         ` Eric Wong
@ 2018-09-21  0:21           ` Jeremy Evans
  2018-09-23  8:52             ` Eric Wong
  2018-09-21  0:34           ` [PATCH 2/1] tests: ensure -N/--no-default-middleware not supported in config.ru Eric Wong
  1 sibling, 1 reply; 9+ messages in thread
From: Jeremy Evans @ 2018-09-21  0:21 UTC (permalink / raw)
  To: Eric Wong; +Cc: unicorn-public

On 09/19 07:39, Eric Wong wrote:
> Jeremy Evans <code@jeremyevans.net> wrote:
> > OK. To implement that, I modified the bin/unicorn file so -N
> > is only respected while parsing ARGV, and not while parsing
> > embedded configuration file options.
> 
> Thanks.
> 
> Unfortunately, -N on the command-line was broken by your patch.
> I fixed configurator.rb ordering (below) to pass t0300
> integration test.
> 
> Also, using a non-config.ru .rb file (TestHandler in
> test/unit/test_server.rb) was broken because of missing
> parentheses.

Sorry about both of those issues and for the delay in responding to
this.  I've included your changes in the following squashed commit,
which also includes an integration test for the default_middleware
configuration option, based on the existing integration test for
the -N option.

Thanks,
Jeremy

From fdbbcc82b838a39abdc43448490eb83d80c4f763 Mon Sep 17 00:00:00 2001
From: Jeremy Evans <code@jeremyevans.net>
Date: Thu, 13 Sep 2018 10:48:25 -0700
Subject: [PATCH] Support default_middleware configuration option

This allows for the equivalent of the
-N/--no-default_middleware command line option to be
specified in the configuration file so it doesn't
need to be specified on the command line every time
unicorn is executed.

It explicitly excludes the use of -N/--no-default_middleware
as an embedded configuration option in the rackup file, by
ignoring the options after ARGV is parsed.

In order to allow the configuration method to work, have
the lambda that Unicorn.builder returns accept two arguments.
Technically, only one argument is needed for the HttpServer
instance, but I'm guessing if the lambda accepts a single
argument, we expect that to be a rack application instead
of a lambda that returns a rack application.

The command line option option to disable default middleware
will take precedence over the unicorn configuration file option
if both are present.

For backwards compatibility, if the lambda passed to
HttpServer accepts 0 arguments, then call it without
arguments.
---
 bin/unicorn                         |  4 +++-
 lib/unicorn.rb                      |  8 ++------
 lib/unicorn/configurator.rb         | 11 +++++++++++
 lib/unicorn/http_server.rb          |  8 +++++---
 t/t0301-default-middleware-false.sh | 22 ++++++++++++++++++++++
 5 files changed, 43 insertions(+), 10 deletions(-)
 create mode 100644 t/t0301-default-middleware-false.sh

diff --git a/bin/unicorn b/bin/unicorn
index 3c5e5cb..00c8464 100755
--- a/bin/unicorn
+++ b/bin/unicorn
@@ -6,6 +6,7 @@
 ENV["RACK_ENV"] ||= "development"
 rackup_opts = Unicorn::Configurator::RACKUP
 options = rackup_opts[:options]
+set_no_default_middleware = true
 
 op = OptionParser.new("", 24, '  ') do |opts|
   cmd = File.basename($0)
@@ -60,7 +61,7 @@
 
   opts.on("-N", "--no-default-middleware",
           "do not load middleware implied by RACK_ENV") do |e|
-    rackup_opts[:no_default_middleware] = true
+    rackup_opts[:no_default_middleware] = true if set_no_default_middleware
   end
 
   opts.on("-D", "--daemonize", "run daemonized in the background") do |d|
@@ -110,6 +111,7 @@
   opts.parse! ARGV
 end
 
+set_no_default_middleware = false
 app = Unicorn.builder(ARGV[0] || 'config.ru', op)
 op = nil
 
diff --git a/lib/unicorn.rb b/lib/unicorn.rb
index b6dae36..5f2134d 100644
--- a/lib/unicorn.rb
+++ b/lib/unicorn.rb
@@ -45,12 +45,8 @@ def self.builder(ru, op)
       abort "rack and Rack::Builder must be available for processing #{ru}"
     end
 
-    # Op is going to get cleared before the returned lambda is called, so
-    # save this value so that it's still there when we need it:
-    no_default_middleware = op[:no_default_middleware]
-
     # always called after config file parsing, may be called after forking
-    lambda do ||
+    lambda do |_, server|
       inner_app = case ru
       when /\.ru$/
         raw = File.read(ru)
@@ -66,7 +62,7 @@ def self.builder(ru, op)
         pp({ :inner_app => inner_app })
       end
 
-      return inner_app if no_default_middleware
+      return inner_app unless server.default_middleware
 
       middleware = { # order matters
         ContentLength: nil,
diff --git a/lib/unicorn/configurator.rb b/lib/unicorn/configurator.rb
index f34d38b..d426edf 100644
--- a/lib/unicorn/configurator.rb
+++ b/lib/unicorn/configurator.rb
@@ -88,6 +88,9 @@ def reload(merge_defaults = true) #:nodoc:
     RACKUP[:set_listener] and
       set[:listeners] << "#{RACKUP[:host]}:#{RACKUP[:port]}"
 
+    RACKUP[:no_default_middleware] and
+      set[:default_middleware] = false
+
     # unicorn_rails creates dirs here after working_directory is bound
     after_reload.call if after_reload
 
@@ -265,6 +268,14 @@ def worker_processes(nr)
     set_int(:worker_processes, nr, 1)
   end
 
+  # sets whether to add default middleware in the development and
+  # deployment RACK_ENVs.
+  #
+  # default_middleware is only available in unicorn 5.5.0+
+  def default_middleware(bool)
+    set_bool(:default_middleware, bool)
+  end
+
   # sets listeners to the given +addresses+, replacing or augmenting the
   # current set.  This is for the global listener pool shared by all
   # worker processes.  For per-worker listeners, see the after_fork example
diff --git a/lib/unicorn/http_server.rb b/lib/unicorn/http_server.rb
index b2bbddb..62f6171 100644
--- a/lib/unicorn/http_server.rb
+++ b/lib/unicorn/http_server.rb
@@ -14,7 +14,8 @@ class Unicorn::HttpServer
   attr_accessor :app, :timeout, :worker_processes,
                 :before_fork, :after_fork, :before_exec,
                 :listener_opts, :preload_app,
-                :orig_app, :config, :ready_pipe, :user
+                :orig_app, :config, :ready_pipe, :user,
+                :default_middleware
   attr_writer   :after_worker_exit, :after_worker_ready, :worker_exec
 
   attr_reader :pid, :logger
@@ -70,6 +71,7 @@ def initialize(app, options = {})
     @app = app
     @request = Unicorn::HttpRequest.new
     @reexec_pid = 0
+    @default_middleware = true
     options = options.dup
     @ready_pipe = options.delete(:ready_pipe)
     @init_listeners = options[:listeners] ? options[:listeners].dup : []
@@ -784,12 +786,12 @@ def listener_names(listeners = LISTENERS)
   end
 
   def build_app!
-    if app.respond_to?(:arity) && app.arity == 0
+    if app.respond_to?(:arity) && (app.arity == 0 || app.arity == 2)
       if defined?(Gem) && Gem.respond_to?(:refresh)
         logger.info "Refreshing Gem list"
         Gem.refresh
       end
-      self.app = app.call
+      self.app = app.arity == 0 ? app.call : app.call(nil, self)
     end
   end
 
diff --git a/t/t0301-default-middleware-false.sh b/t/t0301-default-middleware-false.sh
new file mode 100644
index 0000000..c505f1d
--- /dev/null
+++ b/t/t0301-default-middleware-false.sh
@@ -0,0 +1,22 @@
+#!/bin/sh
+. ./test-lib.sh
+t_plan 3 "test the default_middleware false configuration option"
+
+t_begin "setup and start" && {
+	unicorn_setup
+	echo default_middleware false >> $unicorn_config
+	unicorn -D -c $unicorn_config fails-rack-lint.ru
+	unicorn_wait_start
+}
+
+t_begin "check exit status with Rack::Lint not present" && {
+	test 42 -eq "$(curl -sf -o/dev/null -w'%{http_code}' http://$listen/)"
+}
+
+t_begin "killing succeeds" && {
+	kill $unicorn_pid
+	check_stderr
+}
+
+t_done
+
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 2/1] tests: ensure -N/--no-default-middleware not supported in config.ru
  2018-09-19  7:39         ` Eric Wong
  2018-09-21  0:21           ` Jeremy Evans
@ 2018-09-21  0:34           ` Eric Wong
  1 sibling, 0 replies; 9+ messages in thread
From: Eric Wong @ 2018-09-21  0:34 UTC (permalink / raw)
  To: Jeremy Evans; +Cc: unicorn-public

Eric Wong <e@80x24.org> wrote:
> Will squash the following changes in before pushing:

Squashed and pushed to master as 5985dd50a9bd72388dd5ca4886d6dffc083f87d4

Also added a new test to ensure we don't start supporting -N in
config.ru:

--------8<----------
Subject: [PATCH] tests: ensure -N/--no-default-middleware not supported in
 config.ru

Continue to make it easy to migrate AWAY from unicorn because
vendor lock-in is the worst thing, especially if it's on us.
---
 ...no-default-middleware-ignored-in-config.sh | 25 +++++++++++++++++++
 t/t0301.ru                                    | 13 ++++++++++
 2 files changed, 38 insertions(+)
 create mode 100755 t/t0301-no-default-middleware-ignored-in-config.sh
 create mode 100644 t/t0301.ru

diff --git a/t/t0301-no-default-middleware-ignored-in-config.sh b/t/t0301-no-default-middleware-ignored-in-config.sh
new file mode 100755
index 0000000..0b6cd94
--- /dev/null
+++ b/t/t0301-no-default-middleware-ignored-in-config.sh
@@ -0,0 +1,25 @@
+#!/bin/sh
+. ./test-lib.sh
+t_plan 3 "-N / --no-default-middleware option not supported in config.ru"
+
+t_begin "setup and start" && {
+	unicorn_setup
+	RACK_ENV=development unicorn -D -c $unicorn_config t0301.ru
+	unicorn_wait_start
+}
+
+t_begin "check switches parsed as expected and -N ignored for Rack::Lint" && {
+	debug=false
+	lint=
+	eval "$(curl -sf http://$listen/vars)"
+	test x"$debug" = xtrue
+	test x"$lint" != x
+	test -f "$lint"
+}
+
+t_begin "killing succeeds" && {
+	kill $unicorn_pid
+	check_stderr
+}
+
+t_done
diff --git a/t/t0301.ru b/t/t0301.ru
new file mode 100644
index 0000000..1ae8ea7
--- /dev/null
+++ b/t/t0301.ru
@@ -0,0 +1,13 @@
+#\-N --debug
+run(lambda do |env|
+  case env['PATH_INFO']
+  when '/vars'
+    b = "debug=#{$DEBUG.inspect}\n" \
+        "lint=#{caller.grep(%r{rack/lint\.rb})[0].split(':')[0]}\n"
+  end
+  h = {
+    'Content-Length' => b.size.to_s,
+    'Content-Type' => 'text/plain',
+  }
+  [ 200, h, [ b ] ]
+end)
-- 
EW

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: Support default_middleware configurator method
  2018-09-21  0:21           ` Jeremy Evans
@ 2018-09-23  8:52             ` Eric Wong
  0 siblings, 0 replies; 9+ messages in thread
From: Eric Wong @ 2018-09-23  8:52 UTC (permalink / raw)
  To: Jeremy Evans; +Cc: unicorn-public

Jeremy Evans <code@jeremyevans.net> wrote:
> Sorry about both of those issues and for the delay in responding to
> this.

No worries, I haven't been around much, either.

> I've included your changes in the following squashed commit,
> which also includes an integration test for the default_middleware
> configuration option, based on the existing integration test for
> the -N option.

Whoops, sorry, I guess I wasn't clear when I said I already
applied your change with squashes as
5985dd50a9bd72388dd5ca4886d6dffc083f87d4 in my message:
https://bogomips.org/unicorn-public/20180921003441.i4uxywyptlyscwv6@dcvr/

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2018-09-23  8:52 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-09-13 19:20 Support default_middleware configurator method Jeremy Evans
2018-09-13 22:34 ` Eric Wong
2018-09-14  0:00   ` Jeremy Evans
2018-09-14 10:56     ` Eric Wong
2018-09-14 15:03       ` Jeremy Evans
2018-09-19  7:39         ` Eric Wong
2018-09-21  0:21           ` Jeremy Evans
2018-09-23  8:52             ` Eric Wong
2018-09-21  0:34           ` [PATCH 2/1] tests: ensure -N/--no-default-middleware not supported in config.ru Eric Wong

Code repositories for project(s) associated with this public inbox

	https://yhbt.net/unicorn.git/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).