unicorn 5.3.1 → 5.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. checksums.yaml +5 -5
  2. data/.manifest +2 -0
  3. data/.olddoc.yml +1 -1
  4. data/Application_Timeouts +4 -4
  5. data/Documentation/unicorn.1.txt +1 -1
  6. data/Documentation/unicorn_rails.1.txt +6 -8
  7. data/GIT-VERSION-FILE +1 -1
  8. data/GIT-VERSION-GEN +1 -1
  9. data/GNUmakefile +6 -1
  10. data/ISSUES +10 -10
  11. data/LATEST +22 -102
  12. data/LICENSE +2 -2
  13. data/Links +9 -7
  14. data/NEWS +107 -0
  15. data/README +13 -6
  16. data/Sandbox +2 -2
  17. data/bin/unicorn +3 -1
  18. data/bin/unicorn_rails +2 -2
  19. data/examples/logrotate.conf +1 -1
  20. data/examples/nginx.conf +3 -2
  21. data/ext/unicorn_http/common_field_optimization.h +24 -6
  22. data/ext/unicorn_http/extconf.rb +30 -0
  23. data/ext/unicorn_http/global_variables.h +2 -2
  24. data/ext/unicorn_http/httpdate.c +2 -2
  25. data/ext/unicorn_http/unicorn_http.c +229 -219
  26. data/ext/unicorn_http/unicorn_http.rl +19 -9
  27. data/lib/unicorn/configurator.rb +13 -2
  28. data/lib/unicorn/http_request.rb +2 -2
  29. data/lib/unicorn/http_response.rb +3 -2
  30. data/lib/unicorn/http_server.rb +21 -23
  31. data/lib/unicorn/launcher.rb +1 -1
  32. data/lib/unicorn/socket_helper.rb +4 -3
  33. data/lib/unicorn/util.rb +3 -3
  34. data/lib/unicorn/version.rb +1 -1
  35. data/lib/unicorn/worker.rb +16 -2
  36. data/lib/unicorn.rb +26 -9
  37. data/man/man1/unicorn.1 +7 -5
  38. data/man/man1/unicorn_rails.1 +11 -11
  39. data/t/README +4 -4
  40. data/t/hijack.ru +12 -0
  41. data/t/t0200-rack-hijack.sh +22 -1
  42. data/t/t0301-no-default-middleware-ignored-in-config.sh +25 -0
  43. data/t/t0301.ru +13 -0
  44. data/test/exec/test_exec.rb +6 -7
  45. data/test/unit/test_ccc.rb +1 -1
  46. data/test/unit/test_droplet.rb +1 -1
  47. data/test/unit/test_http_parser.rb +16 -0
  48. data/test/unit/test_request.rb +10 -10
  49. data/test/unit/test_server.rb +5 -5
  50. data/test/unit/test_signals.rb +2 -2
  51. data/test/unit/test_socket_helper.rb +4 -4
  52. data/test/unit/test_util.rb +25 -0
  53. data/unicorn.gemspec +1 -1
  54. metadata +5 -4
@@ -13,7 +13,7 @@
13
13
  #include "global_variables.h"
14
14
  #include "c_util.h"
15
15
 
16
- void init_unicorn_httpdate(VALUE mark_ary);
16
+ void init_unicorn_httpdate(void);
17
17
 
18
18
  #define UH_FL_CHUNKED 0x1
19
19
  #define UH_FL_HASBODY 0x2
@@ -26,6 +26,7 @@ void init_unicorn_httpdate(VALUE mark_ary);
26
26
  #define UH_FL_HASHEADER 0x100
27
27
  #define UH_FL_TO_CLEAR 0x200
28
28
  #define UH_FL_RESSTART 0x400 /* for check_client_connection */
29
+ #define UH_FL_HIJACK 0x800
29
30
 
30
31
  /* all of these flags need to be set for keepalive to be supported */
31
32
  #define UH_FL_KEEPALIVE (UH_FL_KAVERSION | UH_FL_REQEOF | UH_FL_HASHEADER)
@@ -607,6 +608,10 @@ static VALUE HttpParser_clear(VALUE self)
607
608
  {
608
609
  struct http_parser *hp = data_get(self);
609
610
 
611
+ /* we can't safely reuse .buf and .env if hijacked */
612
+ if (HP_FL_TEST(hp, HIJACK))
613
+ return HttpParser_init(self);
614
+
610
615
  http_parser_init(hp);
611
616
  my_hash_clear(hp->env);
612
617
 
@@ -813,6 +818,15 @@ static VALUE HttpParser_env(VALUE self)
813
818
  return data_get(self)->env;
814
819
  }
815
820
 
821
+ static VALUE HttpParser_hijacked_bang(VALUE self)
822
+ {
823
+ struct http_parser *hp = data_get(self);
824
+
825
+ HP_FL_SET(hp, HIJACK);
826
+
827
+ return self;
828
+ }
829
+
816
830
  /**
817
831
  * call-seq:
818
832
  * parser.filter_body(dst, src) => nil/src
@@ -917,11 +931,8 @@ static VALUE HttpParser_rssget(VALUE self)
917
931
 
918
932
  void Init_unicorn_http(void)
919
933
  {
920
- static VALUE mark_ary;
921
934
  VALUE mUnicorn, cHttpParser;
922
935
 
923
- mark_ary = rb_ary_new();
924
- rb_global_variable(&mark_ary);
925
936
  mUnicorn = rb_define_module("Unicorn");
926
937
  cHttpParser = rb_define_class_under(mUnicorn, "HttpParser", rb_cObject);
927
938
  eHttpParserError =
@@ -931,7 +942,7 @@ void Init_unicorn_http(void)
931
942
  e414 = rb_define_class_under(mUnicorn, "RequestURITooLongError",
932
943
  eHttpParserError);
933
944
 
934
- init_globals(mark_ary);
945
+ init_globals();
935
946
  rb_define_alloc_func(cHttpParser, HttpParser_alloc);
936
947
  rb_define_method(cHttpParser, "initialize", HttpParser_init, 0);
937
948
  rb_define_method(cHttpParser, "clear", HttpParser_clear, 0);
@@ -947,6 +958,7 @@ void Init_unicorn_http(void)
947
958
  rb_define_method(cHttpParser, "next?", HttpParser_next, 0);
948
959
  rb_define_method(cHttpParser, "buf", HttpParser_buf, 0);
949
960
  rb_define_method(cHttpParser, "env", HttpParser_env, 0);
961
+ rb_define_method(cHttpParser, "hijacked!", HttpParser_hijacked_bang, 0);
950
962
  rb_define_method(cHttpParser, "response_start_sent=", HttpParser_rssset, 1);
951
963
  rb_define_method(cHttpParser, "response_start_sent", HttpParser_rssget, 0);
952
964
 
@@ -967,16 +979,14 @@ void Init_unicorn_http(void)
967
979
 
968
980
  rb_define_singleton_method(cHttpParser, "max_header_len=", set_maxhdrlen, 1);
969
981
 
970
- init_common_fields(mark_ary);
982
+ init_common_fields();
971
983
  SET_GLOBAL(g_http_host, "HOST");
972
984
  SET_GLOBAL(g_http_trailer, "TRAILER");
973
985
  SET_GLOBAL(g_http_transfer_encoding, "TRANSFER_ENCODING");
974
986
  SET_GLOBAL(g_content_length, "CONTENT_LENGTH");
975
987
  SET_GLOBAL(g_http_connection, "CONNECTION");
976
988
  id_set_backtrace = rb_intern("set_backtrace");
977
- init_unicorn_httpdate(mark_ary);
978
-
979
- OBJ_FREEZE(mark_ary);
989
+ init_unicorn_httpdate();
980
990
 
981
991
  #ifndef HAVE_RB_HASH_CLEAR
982
992
  id_clear = rb_intern("clear");
@@ -88,6 +88,9 @@ class Unicorn::Configurator
88
88
  RACKUP[:set_listener] and
89
89
  set[:listeners] << "#{RACKUP[:host]}:#{RACKUP[:port]}"
90
90
 
91
+ RACKUP[:no_default_middleware] and
92
+ set[:default_middleware] = false
93
+
91
94
  # unicorn_rails creates dirs here after working_directory is bound
92
95
  after_reload.call if after_reload
93
96
 
@@ -235,7 +238,7 @@ class Unicorn::Configurator
235
238
  # server 192.168.0.9:8080 fail_timeout=0;
236
239
  # }
237
240
  #
238
- # See http://nginx.org/en/docs/http/ngx_http_upstream_module.html
241
+ # See https://nginx.org/en/docs/http/ngx_http_upstream_module.html
239
242
  # for more details on nginx upstream configuration.
240
243
  def timeout(seconds)
241
244
  set_int(:timeout, seconds, 3)
@@ -265,6 +268,14 @@ class Unicorn::Configurator
265
268
  set_int(:worker_processes, nr, 1)
266
269
  end
267
270
 
271
+ # sets whether to add default middleware in the development and
272
+ # deployment RACK_ENVs.
273
+ #
274
+ # default_middleware is only available in unicorn 5.5.0+
275
+ def default_middleware(bool)
276
+ set_bool(:default_middleware, bool)
277
+ end
278
+
268
279
  # sets listeners to the given +addresses+, replacing or augmenting the
269
280
  # current set. This is for the global listener pool shared by all
270
281
  # worker processes. For per-worker listeners, see the after_fork example
@@ -587,7 +598,7 @@ class Unicorn::Configurator
587
598
  # just let chdir raise errors
588
599
  path = File.expand_path(path)
589
600
  if config_file &&
590
- config_file[0] != ?/ &&
601
+ ! config_file.start_with?('/') &&
591
602
  ! File.readable?("#{path}/#{config_file}")
592
603
  raise ArgumentError,
593
604
  "config_file=#{config_file} would not be accessible in" \
@@ -2,7 +2,6 @@
2
2
  # :enddoc:
3
3
  # no stable API here
4
4
  require 'unicorn_http'
5
- require 'raindrops'
6
5
 
7
6
  # TODO: remove redundant names
8
7
  Unicorn.const_set(:HttpRequest, Unicorn::HttpParser)
@@ -66,7 +65,7 @@ class Unicorn::HttpParser
66
65
  clear
67
66
  e = env
68
67
 
69
- # From http://www.ietf.org/rfc/rfc3875:
68
+ # From https://www.ietf.org/rfc/rfc3875:
70
69
  # "Script authors should be aware that the REMOTE_ADDR and
71
70
  # REMOTE_HOST meta-variables (see sections 4.1.8 and 4.1.9)
72
71
  # may not identify the ultimate source of the request. They
@@ -98,6 +97,7 @@ class Unicorn::HttpParser
98
97
  # for rack.hijack, we respond to this method so no extra allocation
99
98
  # of a proc object
100
99
  def call
100
+ hijacked!
101
101
  env['rack.hijack_io'] = env['unicorn.socket']
102
102
  end
103
103
 
@@ -21,13 +21,13 @@ module Unicorn::HttpResponse
21
21
 
22
22
  # writes the rack_response to socket as an HTTP response
23
23
  def http_response_write(socket, status, headers, body,
24
- response_start_sent=false)
24
+ req = Unicorn::HttpRequest.new)
25
25
  hijack = nil
26
26
 
27
27
  if headers
28
28
  code = status.to_i
29
29
  msg = STATUS_CODES[code]
30
- start = response_start_sent ? ''.freeze : 'HTTP/1.1 '.freeze
30
+ start = req.response_start_sent ? ''.freeze : 'HTTP/1.1 '.freeze
31
31
  buf = "#{start}#{msg ? %Q(#{code} #{msg}) : status}\r\n" \
32
32
  "Date: #{httpdate}\r\n" \
33
33
  "Connection: close\r\n"
@@ -52,6 +52,7 @@ module Unicorn::HttpResponse
52
52
  end
53
53
 
54
54
  if hijack
55
+ req.hijacked!
55
56
  hijack.call(socket)
56
57
  else
57
58
  body.each { |chunk| socket.write(chunk) }
@@ -14,7 +14,8 @@ class Unicorn::HttpServer
14
14
  attr_accessor :app, :timeout, :worker_processes,
15
15
  :before_fork, :after_fork, :before_exec,
16
16
  :listener_opts, :preload_app,
17
- :orig_app, :config, :ready_pipe, :user
17
+ :orig_app, :config, :ready_pipe, :user,
18
+ :default_middleware
18
19
  attr_writer :after_worker_exit, :after_worker_ready, :worker_exec
19
20
 
20
21
  attr_reader :pid, :logger
@@ -70,6 +71,7 @@ class Unicorn::HttpServer
70
71
  @app = app
71
72
  @request = Unicorn::HttpRequest.new
72
73
  @reexec_pid = 0
74
+ @default_middleware = true
73
75
  options = options.dup
74
76
  @ready_pipe = options.delete(:ready_pipe)
75
77
  @init_listeners = options[:listeners] ? options[:listeners].dup : []
@@ -82,7 +84,7 @@ class Unicorn::HttpServer
82
84
  # * The master process never closes or reinitializes this once
83
85
  # initialized. Signal handlers in the master process will write to
84
86
  # it to wake up the master from IO.select in exactly the same manner
85
- # djb describes in http://cr.yp.to/docs/selfpipe.html
87
+ # djb describes in https://cr.yp.to/docs/selfpipe.html
86
88
  #
87
89
  # * The workers immediately close the pipe they inherit. See the
88
90
  # Unicorn::Worker class for the pipe workers use.
@@ -148,7 +150,7 @@ class Unicorn::HttpServer
148
150
  def listeners=(listeners)
149
151
  cur_names, dead_names = [], []
150
152
  listener_names.each do |name|
151
- if ?/ == name[0]
153
+ if name.start_with?('/')
152
154
  # mark unlinked sockets as dead so we can rebind them
153
155
  (File.socket?(name) ? cur_names : dead_names) << name
154
156
  else
@@ -380,7 +382,7 @@ class Unicorn::HttpServer
380
382
 
381
383
  # wait for a signal hander to wake us up and then consume the pipe
382
384
  def master_sleep(sec)
383
- @self_pipe[0].kgio_wait_readable(sec) or return
385
+ @self_pipe[0].wait(sec) or return
384
386
  # 11 bytes is the maximum string length which can be embedded within
385
387
  # the Ruby itself and not require a separate malloc (on 32-bit MRI 1.9+).
386
388
  # Most reads are only one byte here and uncommon, so it's not worth a
@@ -520,9 +522,6 @@ class Unicorn::HttpServer
520
522
  Unicorn::Configurator::RACKUP.clear
521
523
  @ready_pipe = @init_listeners = @before_exec = @before_fork = nil
522
524
 
523
- # http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/36450
524
- srand # remove in unicorn 6
525
-
526
525
  # The OpenSSL PRNG is seeded with only the pid, and apps with frequently
527
526
  # dying workers can recycle pids
528
527
  OpenSSL::Random.seed(rand.to_s) if defined?(OpenSSL::Random)
@@ -553,9 +552,9 @@ class Unicorn::HttpServer
553
552
  @workers[pid] = worker
554
553
  worker.atfork_parent
555
554
  end
556
- rescue => e
557
- @logger.error(e) rescue nil
558
- exit!
555
+ rescue => e
556
+ @logger.error(e) rescue nil
557
+ exit!
559
558
  end
560
559
 
561
560
  def maintain_worker_count
@@ -586,7 +585,7 @@ class Unicorn::HttpServer
586
585
  client.kgio_trywrite(err_response(code, @request.response_start_sent))
587
586
  end
588
587
  client.close
589
- rescue
588
+ rescue
590
589
  end
591
590
 
592
591
  def e100_response_write(client, env)
@@ -614,8 +613,7 @@ class Unicorn::HttpServer
614
613
  return if @request.hijacked?
615
614
  end
616
615
  @request.headers? or headers = nil
617
- http_response_write(client, status, headers, body,
618
- @request.response_start_sent)
616
+ http_response_write(client, status, headers, body, @request)
619
617
  ensure
620
618
  body.respond_to?(:close) and body.close
621
619
  end
@@ -670,9 +668,9 @@ class Unicorn::HttpServer
670
668
  logger.info "worker=#{worker_nr} reopening logs..."
671
669
  Unicorn::Util.reopen_logs
672
670
  logger.info "worker=#{worker_nr} done reopening logs"
673
- rescue => e
674
- logger.error(e) rescue nil
675
- exit!(77) # EX_NOPERM in sysexits.h
671
+ rescue => e
672
+ logger.error(e) rescue nil
673
+ exit!(77) # EX_NOPERM in sysexits.h
676
674
  end
677
675
 
678
676
  # runs inside each forked worker, this sits around and waits
@@ -758,11 +756,11 @@ class Unicorn::HttpServer
758
756
  wpid <= 0 and return
759
757
  Process.kill(0, wpid)
760
758
  wpid
761
- rescue Errno::EPERM
762
- logger.info "pid=#{path} possibly stale, got EPERM signalling PID:#{wpid}"
763
- nil
764
- rescue Errno::ESRCH, Errno::ENOENT
765
- # don't unlink stale pid files, racy without non-portable locking...
759
+ rescue Errno::EPERM
760
+ logger.info "pid=#{path} possibly stale, got EPERM signalling PID:#{wpid}"
761
+ nil
762
+ rescue Errno::ESRCH, Errno::ENOENT
763
+ # don't unlink stale pid files, racy without non-portable locking...
766
764
  end
767
765
 
768
766
  def load_config!
@@ -788,12 +786,12 @@ class Unicorn::HttpServer
788
786
  end
789
787
 
790
788
  def build_app!
791
- if app.respond_to?(:arity) && app.arity == 0
789
+ if app.respond_to?(:arity) && (app.arity == 0 || app.arity == 2)
792
790
  if defined?(Gem) && Gem.respond_to?(:refresh)
793
791
  logger.info "Refreshing Gem list"
794
792
  Gem.refresh
795
793
  end
796
- self.app = app.call
794
+ self.app = app.arity == 0 ? app.call : app.call(nil, self)
797
795
  end
798
796
  end
799
797
 
@@ -31,7 +31,7 @@ module Unicorn::Launcher
31
31
  # \_ parent - exits immediately ASAP
32
32
  # \_ unicorn master - writes to pipe when ready
33
33
 
34
- rd, wr = IO.pipe
34
+ rd, wr = Unicorn.pipe
35
35
  grandparent = $$
36
36
  if fork
37
37
  wr.close # grandparent does not write
@@ -83,6 +83,7 @@ module Unicorn
83
83
  rescue => e
84
84
  logger.error("#{sock_name(sock)} " \
85
85
  "failed to set accept_filter=#{name} (#{e.inspect})")
86
+ logger.error("perhaps accf_http(9) needs to be loaded".freeze)
86
87
  end if arg != got
87
88
  end
88
89
  end
@@ -100,8 +101,8 @@ module Unicorn
100
101
  log_buffer_sizes(sock, " after: ")
101
102
  end
102
103
  sock.listen(opt[:backlog])
103
- rescue => e
104
- Unicorn.log_error(logger, "#{sock_name(sock)} #{opt.inspect}", e)
104
+ rescue => e
105
+ Unicorn.log_error(logger, "#{sock_name(sock)} #{opt.inspect}", e)
105
106
  end
106
107
 
107
108
  def log_buffer_sizes(sock, pfx = '')
@@ -116,7 +117,7 @@ module Unicorn
116
117
  def bind_listen(address = '0.0.0.0:8080', opt = {})
117
118
  return address unless String === address
118
119
 
119
- sock = if address[0] == ?/
120
+ sock = if address.start_with?('/')
120
121
  if File.exist?(address)
121
122
  if File.socket?(address)
122
123
  begin
data/lib/unicorn/util.rb CHANGED
@@ -11,8 +11,8 @@ module Unicorn::Util # :nodoc:
11
11
  fp.stat.file? &&
12
12
  fp.sync &&
13
13
  (fp.fcntl(Fcntl::F_GETFL) & append_flags) == append_flags
14
- rescue IOError, Errno::EBADF
15
- false
14
+ rescue IOError, Errno::EBADF
15
+ false
16
16
  end
17
17
 
18
18
  def self.chown_logs(uid, gid)
@@ -64,7 +64,7 @@ module Unicorn::Util # :nodoc:
64
64
  fp.reopen(fp.path, "a")
65
65
  else
66
66
  # We should not need this workaround, Ruby can be fixed:
67
- # http://bugs.ruby-lang.org/issues/9036
67
+ # https://bugs.ruby-lang.org/issues/9036
68
68
  # MRI will not call call fclose(3) or freopen(3) here
69
69
  # since there's no associated std{in,out,err} FILE * pointer
70
70
  # This should atomically use dup3(2) (or dup2(2)) syscall
@@ -1 +1 @@
1
- Unicorn::Const::UNICORN_VERSION = '5.3.1'
1
+ Unicorn::Const::UNICORN_VERSION = '5.5.1'
@@ -122,6 +122,11 @@ class Unicorn::Worker
122
122
  # the +after_fork+ hook after any privileged functions need to be
123
123
  # run (e.g. to set per-worker CPU affinity, niceness, etc)
124
124
  #
125
+ # +group+ can be specified as a string, or as an array of two
126
+ # strings. If an array of two strings is given, the first string
127
+ # is used as the primary group of the process, and the second is
128
+ # used as the group of the log files.
129
+ #
125
130
  # Any and all errors raised within this method will be propagated
126
131
  # directly back to the caller (usually the +after_fork+ hook.
127
132
  # These errors commonly include ArgumentError for specifying an
@@ -134,8 +139,17 @@ class Unicorn::Worker
134
139
  # insufficient because modern systems have fine-grained
135
140
  # capabilities. Let the caller handle any and all errors.
136
141
  uid = Etc.getpwnam(user).uid
137
- gid = Etc.getgrnam(group).gid if group
138
- Unicorn::Util.chown_logs(uid, gid)
142
+
143
+ if group
144
+ if group.is_a?(Array)
145
+ group, log_group = group
146
+ log_gid = Etc.getgrnam(log_group).gid
147
+ end
148
+ gid = Etc.getgrnam(group).gid
149
+ log_gid ||= gid
150
+ end
151
+
152
+ Unicorn::Util.chown_logs(uid, log_gid)
139
153
  if gid && Process.egid != gid
140
154
  Process.initgroups(user, gid)
141
155
  Process::GID.change_privilege(gid)
data/lib/unicorn.rb CHANGED
@@ -2,6 +2,8 @@
2
2
  require 'etc'
3
3
  require 'stringio'
4
4
  require 'kgio'
5
+ require 'raindrops'
6
+ require 'io/wait'
5
7
 
6
8
  begin
7
9
  require 'rack'
@@ -43,12 +45,8 @@ module Unicorn
43
45
  abort "rack and Rack::Builder must be available for processing #{ru}"
44
46
  end
45
47
 
46
- # Op is going to get cleared before the returned lambda is called, so
47
- # save this value so that it's still there when we need it:
48
- no_default_middleware = op[:no_default_middleware]
49
-
50
48
  # always called after config file parsing, may be called after forking
51
- lambda do ||
49
+ lambda do |_, server|
52
50
  inner_app = case ru
53
51
  when /\.ru$/
54
52
  raw = File.read(ru)
@@ -59,9 +57,12 @@ module Unicorn
59
57
  Object.const_get(File.basename(ru, '.rb').capitalize)
60
58
  end
61
59
 
62
- pp({ :inner_app => inner_app }) if $DEBUG
60
+ if $DEBUG
61
+ require 'pp'
62
+ pp({ :inner_app => inner_app })
63
+ end
63
64
 
64
- return inner_app if no_default_middleware
65
+ return inner_app unless server.default_middleware
65
66
 
66
67
  middleware = { # order matters
67
68
  ContentLength: nil,
@@ -109,9 +110,25 @@ module Unicorn
109
110
  exc.backtrace.each { |line| logger.error(line) }
110
111
  end
111
112
 
112
- # remove this when we only support Ruby >= 2.0
113
+ F_SETPIPE_SZ = 1031 if RUBY_PLATFORM =~ /linux/
114
+
113
115
  def self.pipe # :nodoc:
114
- Kgio::Pipe.new.each { |io| io.close_on_exec = true }
116
+ Kgio::Pipe.new.each do |io|
117
+ io.close_on_exec = true # remove this when we only support Ruby >= 2.0
118
+
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
+ rescue Errno::EPERM
127
+ # resizes fail if Linux is close to the pipe limit for the user
128
+ # or if the user does not have permissions to resize
129
+ end
130
+ end
131
+ end
115
132
  end
116
133
  # :startdoc:
117
134
  end
data/man/man1/unicorn.1 CHANGED
@@ -1,4 +1,7 @@
1
+ .\" Automatically generated by Pandoc 1.17.2
2
+ .\"
1
3
  .TH "UNICORN" "1" "September 15, 2009" "Unicorn User Manual" ""
4
+ .hy
2
5
  .SH NAME
3
6
  .PP
4
7
  unicorn \- a rackup\-like command to launch the Unicorn HTTP server
@@ -61,10 +64,9 @@ socket.
61
64
  Defaults to "0.0.0.0:8080" (all addresses on TCP port 8080) For
62
65
  production deployments, specifying the "listen" directive in CONFIG_FILE
63
66
  is recommended as it allows fine\-tuning of socket options.
67
+ \-N, \-\-no\-default\-middleware
64
68
  .RS
65
69
  .RE
66
- .TP
67
- .B \-N, \-\-no\-default\-middleware
68
70
  Disables loading middleware implied by RACK_ENV.
69
71
  This bypasses the configuration documented in the RACK ENVIRONMENT
70
72
  section, but still allows RACK_ENV to be used for
@@ -116,8 +118,8 @@ Turn on verbose warnings, the $VERBOSE variable is set to true.
116
118
  .RE
117
119
  .TP
118
120
  .B \-I, \-\-include PATH
119
- specify
120
- \f[I]L\f[]\f[I]O\f[]\f[I]A\f[]\f[I]D\f[]~\f[I]P\f[]~\f[I]A\f[]\f[I]T\f[]\f[I]H\f[].\f[I]P\f[]\f[I]A\f[]\f[I]T\f[]\f[I]H\f[]\f[I]w\f[]\f[I]i\f[]\f[I]l\f[]\f[I]l\f[]\f[I]b\f[]\f[I]e\f[]\f[I]p\f[]\f[I]r\f[]\f[I]e\f[]\f[I]p\f[]\f[I]e\f[]\f[I]n\f[]\f[I]d\f[]\f[I]e\f[]\f[I]d\f[]\f[I]t\f[]\f[I]o\f[]LOAD_PATH.
121
+ specify $LOAD_PATH.
122
+ PATH will be prepended to $LOAD_PATH.
121
123
  The \[aq]:\[aq] character may be used to delimit multiple directories.
122
124
  This directive may be used more than once.
123
125
  Modifications to $LOAD_PATH take place immediately and in the order they
@@ -212,7 +214,7 @@ the unicorn config file.
212
214
  .IP \[bu] 2
213
215
  Unicorn RDoc (https://bogomips.org/unicorn/)
214
216
  .IP \[bu] 2
215
- Rack RDoc (http://www.rubydoc.info/github/rack/rack/)
217
+ Rack RDoc (https://www.rubydoc.info/github/rack/rack/)
216
218
  .IP \[bu] 2
217
219
  Rackup HowTo (https://github.com/rack/rack/wiki/tutorial-rackup-howto)
218
220
  .SH AUTHORS
@@ -1,4 +1,7 @@
1
+ .\" Automatically generated by Pandoc 1.17.2
2
+ .\"
1
3
  .TH "UNICORN_RAILS" "1" "September 17, 2009" "Unicorn User Manual" ""
4
+ .hy
2
5
  .SH NAME
3
6
  .PP
4
7
  unicorn_rails \- unicorn launcher for Rails 1.x and 2.x users
@@ -7,18 +10,15 @@ unicorn_rails \- unicorn launcher for Rails 1.x and 2.x users
7
10
  unicorn_rails [\-c CONFIG_FILE] [\-E RAILS_ENV] [\-D] [RACKUP_FILE]
8
11
  .SH DESCRIPTION
9
12
  .PP
10
- A rackup(1)\-like command to launch Rails applications using Unicorn.
13
+ A rackup(1)\-like command to launch ancient Rails (2.x and earlier)
14
+ applications using Unicorn.
15
+ Rails 3 (and later) support Rack natively, so users are encouraged to
16
+ use unicorn(1) instead of unicorn_rails(1).
17
+ .PP
11
18
  It is expected to be started in your Rails application root
12
19
  (RAILS_ROOT), but the "working_directory" directive may be used in the
13
20
  CONFIG_FILE.
14
21
  .PP
15
- It is designed to help Rails 1.x and 2.y users transition to Rack, but
16
- it is NOT needed for Rails 3 applications.
17
- Rails 3 users are encouraged to use unicorn(1) instead of
18
- unicorn_rails(1).
19
- Users of Rails 1.x/2.y may also use unicorn(1) instead of
20
- unicorn_rails(1).
21
- .PP
22
22
  The outward interface resembles rackup(1), the internals and default
23
23
  middleware loading is designed like the \f[C]script/server\f[] command
24
24
  distributed with Rails.
@@ -125,8 +125,8 @@ Turn on verbose warnings, the $VERBOSE variable is set to true.
125
125
  .RE
126
126
  .TP
127
127
  .B \-I, \-\-include PATH
128
- specify
129
- \f[I]L\f[]\f[I]O\f[]\f[I]A\f[]\f[I]D\f[]~\f[I]P\f[]~\f[I]A\f[]\f[I]T\f[]\f[I]H\f[].\f[I]P\f[]\f[I]A\f[]\f[I]T\f[]\f[I]H\f[]\f[I]w\f[]\f[I]i\f[]\f[I]l\f[]\f[I]l\f[]\f[I]b\f[]\f[I]e\f[]\f[I]p\f[]\f[I]r\f[]\f[I]e\f[]\f[I]p\f[]\f[I]e\f[]\f[I]n\f[]\f[I]d\f[]\f[I]e\f[]\f[I]d\f[]\f[I]t\f[]\f[I]o\f[]LOAD_PATH.
128
+ specify $LOAD_PATH.
129
+ PATH will be prepended to $LOAD_PATH.
130
130
  The \[aq]:\[aq] character may be used to delimit multiple directories.
131
131
  This directive may be used more than once.
132
132
  Modifications to $LOAD_PATH take place immediately and in the order they
@@ -202,7 +202,7 @@ unicorn(1)
202
202
  .IP \[bu] 2
203
203
  Unicorn RDoc (https://bogomips.org/unicorn/)
204
204
  .IP \[bu] 2
205
- Rack RDoc (http://www.rubydoc.info/github/rack/rack/)
205
+ Rack RDoc (https://www.rubydoc.info/github/rack/rack/)
206
206
  .IP \[bu] 2
207
207
  Rackup HowTo (https://github.com/rack/rack/wiki/tutorial-rackup-howto)
208
208
  .SH AUTHORS
data/t/README CHANGED
@@ -10,17 +10,17 @@ comfortable writing integration tests with.
10
10
 
11
11
  == Requirements
12
12
 
13
- * {Ruby 1.9.3+}[https://www.ruby-lang.org/] (duh!)
14
- * {GNU make}[http://www.gnu.org/software/make/]
13
+ * {Ruby 1.9.3+}[https://www.ruby-lang.org/en/] (duh!)
14
+ * {GNU make}[https://www.gnu.org/software/make/]
15
15
  * {socat}[http://www.dest-unreach.org/socat/]
16
- * {curl}[http://curl.haxx.se/]
16
+ * {curl}[https://curl.haxx.se/]
17
17
  * standard UNIX shell utilities (Bourne sh, awk, sed, grep, ...)
18
18
 
19
19
  We do not use bashisms or any non-portable, non-POSIX constructs
20
20
  in our shell code. We use the "pipefail" option if available and
21
21
  mainly test with {ksh}[http://kornshell.com/], but occasionally
22
22
  with {dash}[http://gondor.apana.org.au/~herbert/dash/] and
23
- {bash}[http://www.gnu.org/software/bash/], too.
23
+ {bash}[https://www.gnu.org/software/bash/], too.
24
24
 
25
25
  == Running Tests
26
26
 
data/t/hijack.ru CHANGED
@@ -11,11 +11,15 @@ class DieIfUsed
11
11
  warn "closed DieIfUsed #{@@n += 1}\n"
12
12
  end
13
13
  end
14
+
15
+ envs = []
16
+
14
17
  run lambda { |env|
15
18
  case env["PATH_INFO"]
16
19
  when "/hijack_req"
17
20
  if env["rack.hijack?"]
18
21
  io = env["rack.hijack"].call
22
+ envs << env
19
23
  if io.respond_to?(:read_nonblock) &&
20
24
  env["rack.hijack_io"].respond_to?(:read_nonblock)
21
25
 
@@ -33,11 +37,19 @@ run lambda { |env|
33
37
  {
34
38
  "Content-Length" => r.bytesize.to_s,
35
39
  "rack.hijack" => proc do |io|
40
+ envs << env
36
41
  io.write(r)
37
42
  io.close
38
43
  end
39
44
  },
40
45
  DieIfUsed.new
41
46
  ]
47
+ when "/normal_env_id"
48
+ b = "#{env.object_id}\n"
49
+ h = {
50
+ 'Content-Type' => 'text/plain',
51
+ 'Content-Length' => b.bytesize.to_s,
52
+ }
53
+ [ 200, h, [ b ] ]
42
54
  end
43
55
  }
@@ -1,6 +1,6 @@
1
1
  #!/bin/sh
2
2
  . ./test-lib.sh
3
- t_plan 5 "rack.hijack tests (Rack 1.5+ (Rack::VERSION >= [ 1,2]))"
3
+ t_plan 9 "rack.hijack tests (Rack 1.5+ (Rack::VERSION >= [ 1,2]))"
4
4
 
5
5
  t_begin "setup and start" && {
6
6
  unicorn_setup
@@ -8,14 +8,35 @@ t_begin "setup and start" && {
8
8
  unicorn_wait_start
9
9
  }
10
10
 
11
+ t_begin "normal env reused between requests" && {
12
+ env_a="$(curl -sSf http://$listen/normal_env_id)"
13
+ b="$(curl -sSf http://$listen/normal_env_id)"
14
+ test x"$env_a" = x"$b"
15
+ }
16
+
11
17
  t_begin "check request hijack" && {
12
18
  test "xrequest.hijacked" = x"$(curl -sSfv http://$listen/hijack_req)"
13
19
  }
14
20
 
21
+ t_begin "env changed after request hijack" && {
22
+ env_b="$(curl -sSf http://$listen/normal_env_id)"
23
+ test x"$env_a" != x"$env_b"
24
+ }
25
+
15
26
  t_begin "check response hijack" && {
16
27
  test "xresponse.hijacked" = x"$(curl -sSfv http://$listen/hijack_res)"
17
28
  }
18
29
 
30
+ t_begin "env changed after response hijack" && {
31
+ env_c="$(curl -sSf http://$listen/normal_env_id)"
32
+ test x"$env_b" != x"$env_c"
33
+ }
34
+
35
+ t_begin "env continues to be reused between requests" && {
36
+ b="$(curl -sSf http://$listen/normal_env_id)"
37
+ test x"$env_c" = x"$b"
38
+ }
39
+
19
40
  t_begin "killing succeeds after hijack" && {
20
41
  kill $unicorn_pid
21
42
  }