Support default_middleware configuration option
[unicorn.git] / lib / unicorn.rb
blob5f2134d64b0d18e106c01bfecc942c5196c11958
1 # -*- encoding: binary -*-
2 require 'etc'
3 require 'stringio'
4 require 'kgio'
5 require 'raindrops'
6 require 'io/wait'
8 begin
9   require 'rack'
10 rescue LoadError
11   warn 'rack not available, functionality reduced'
12 end
14 # :stopdoc:
15 # Unicorn module containing all of the classes (include C extensions) for
16 # running a Unicorn web server.  It contains a minimalist HTTP server with just
17 # enough functionality to service web application requests fast as possible.
18 # :startdoc:
20 # unicorn exposes very little of an user-visible API and most of its
21 # internals are subject to change.  unicorn is designed to host Rack
22 # applications, so applications should be written against the Rack SPEC
23 # and not unicorn internals.
24 module Unicorn
26   # Raised inside TeeInput when a client closes the socket inside the
27   # application dispatch.  This is always raised with an empty backtrace
28   # since there is nothing in the application stack that is responsible
29   # for client shutdowns/disconnects.  This exception is visible to Rack
30   # applications unless PrereadInput middleware is loaded.  This
31   # is a subclass of the standard EOFError class and applications should
32   # not rescue it explicitly, but rescue EOFError instead.
33   ClientShutdown = Class.new(EOFError)
35   # :stopdoc:
37   # This returns a lambda to pass in as the app, this does not "build" the
38   # app (which we defer based on the outcome of "preload_app" in the
39   # Unicorn config).  The returned lambda will be called when it is
40   # time to build the app.
41   def self.builder(ru, op)
42     # allow Configurator to parse cli switches embedded in the ru file
43     op = Unicorn::Configurator::RACKUP.merge!(:file => ru, :optparse => op)
44     if ru =~ /\.ru$/ && !defined?(Rack::Builder)
45       abort "rack and Rack::Builder must be available for processing #{ru}"
46     end
48     # always called after config file parsing, may be called after forking
49     lambda do |_, server|
50       inner_app = case ru
51       when /\.ru$/
52         raw = File.read(ru)
53         raw.sub!(/^__END__\n.*/, '')
54         eval("Rack::Builder.new {(\n#{raw}\n)}.to_app", TOPLEVEL_BINDING, ru)
55       else
56         require ru
57         Object.const_get(File.basename(ru, '.rb').capitalize)
58       end
60       if $DEBUG
61         require 'pp'
62         pp({ :inner_app => inner_app })
63       end
65       return inner_app unless server.default_middleware
67       middleware = { # order matters
68         ContentLength: nil,
69         Chunked: nil,
70         CommonLogger: [ $stderr ],
71         ShowExceptions: nil,
72         Lint: nil,
73         TempfileReaper: nil,
74       }
76       # return value, matches rackup defaults based on env
77       # Unicorn does not support persistent connections, but Rainbows!
78       # and Zbatery both do.  Users accustomed to the Rack::Server default
79       # middlewares will need ContentLength/Chunked middlewares.
80       case ENV["RACK_ENV"]
81       when "development"
82       when "deployment"
83         middleware.delete(:ShowExceptions)
84         middleware.delete(:Lint)
85       else
86         return inner_app
87       end
88       Rack::Builder.new do
89         middleware.each do |m, args|
90           use(Rack.const_get(m), *args) if Rack.const_defined?(m)
91         end
92         run inner_app
93       end.to_app
94     end
95   end
97   # returns an array of strings representing TCP listen socket addresses
98   # and Unix domain socket paths.  This is useful for use with
99   # Raindrops::Middleware under Linux: https://bogomips.org/raindrops/
100   def self.listener_names
101     Unicorn::HttpServer::LISTENERS.map do |io|
102       Unicorn::SocketHelper.sock_name(io)
103     end + Unicorn::HttpServer::NEW_LISTENERS
104   end
106   def self.log_error(logger, prefix, exc)
107     message = exc.message
108     message = message.dump if /[[:cntrl:]]/ =~ message
109     logger.error "#{prefix}: #{message} (#{exc.class})"
110     exc.backtrace.each { |line| logger.error(line) }
111   end
113   F_SETPIPE_SZ = 1031 if RUBY_PLATFORM =~ /linux/
115   def self.pipe # :nodoc:
116     Kgio::Pipe.new.each do |io|
117       io.close_on_exec = true  # remove this when we only support Ruby >= 2.0
119       # shrink pipes to minimize impact on /proc/sys/fs/pipe-user-pages-soft
120       # limits.
121       if defined?(F_SETPIPE_SZ)
122         begin
123           io.fcntl(F_SETPIPE_SZ, Raindrops::PAGE_SIZE)
124         rescue Errno::EINVAL
125           # old kernel
126         end
127       end
128     end
129   end
130   # :startdoc:
132 # :enddoc:
134 %w(const socket_helper stream_input tee_input http_request configurator
135    tmpio util http_response worker http_server).each do |s|
136   require_relative "unicorn/#{s}"