unicorn 5.3.1 → 5.5.1

Sign up to get free protection for your applications and to get access to all the features.
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
  }