unicorn 0.97.1 → 0.98.0

Sign up to get free protection for your applications and to get access to all the features.
data/.document CHANGED
@@ -13,6 +13,6 @@ NEWS
13
13
  ChangeLog
14
14
  lib
15
15
  ext/unicorn_http/unicorn_http.c
16
- unicorn.1
17
- unicorn_rails.1
16
+ unicorn_1
17
+ unicorn_rails_1
18
18
  ISSUES
data/GIT-VERSION-GEN CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/bin/sh
2
2
 
3
3
  GVF=GIT-VERSION-FILE
4
- DEF_VER=v0.97.1.GIT
4
+ DEF_VER=v0.98.0.GIT
5
5
 
6
6
  LF='
7
7
  '
data/GNUmakefile CHANGED
@@ -41,6 +41,7 @@ c_files := $(ext)/unicorn_http.c $(wildcard $(ext)/*.h)
41
41
  rl_files := $(wildcard $(ext)/*.rl)
42
42
  base_bins := unicorn unicorn_rails
43
43
  bins := $(addprefix bin/, $(base_bins))
44
+ man1_rdoc := $(addsuffix _1, $(base_bins))
44
45
  man1_bins := $(addsuffix .1, $(base_bins))
45
46
  man1_paths := $(addprefix man/man1/, $(man1_bins))
46
47
  rb_files := $(bins) $(shell find lib ext -type f -name '*.rb')
@@ -160,7 +161,7 @@ NEWS: GIT-VERSION-FILE .manifest
160
161
  $(RAKE) -s news_rdoc > $@+
161
162
  mv $@+ $@
162
163
 
163
- SINCE = 0.96.0
164
+ SINCE = 0.97.1
164
165
  ChangeLog: LOG_VERSION = \
165
166
  $(shell git rev-parse -q "$(GIT_VERSION)" >/dev/null 2>&1 && \
166
167
  echo $(GIT_VERSION) || git describe)
@@ -176,18 +177,21 @@ cgit_atom := http://git.bogomips.org/cgit/unicorn.git/atom/?h=master
176
177
  atom = <link rel="alternate" title="Atom feed" href="$(1)" \
177
178
  type="application/atom+xml"/>
178
179
 
179
- # using rdoc 2.4.1+
180
+ # using rdoc 2.5.x+
180
181
  doc: .document $(ext)/unicorn_http.c NEWS ChangeLog
181
- for i in $(man1_bins); do > $$i; done
182
+ for i in $(man1_rdoc); do echo > $$i; done
182
183
  find bin lib -type f -name '*.rbc' -exec rm -f '{}' ';'
183
- rdoc -Na -t "$(shell sed -ne '1s/^= //p' README)"
184
+ rdoc -a -t "$(shell sed -ne '1s/^= //p' README)"
184
185
  install -m644 COPYING doc/COPYING
185
186
  install -m644 $(shell grep '^[A-Z]' .document) doc/
186
187
  $(MAKE) -C Documentation install-html install-man
187
188
  install -m644 $(man1_paths) doc/
188
189
  cd doc && for i in $(base_bins); do \
190
+ $(RM) 1.html $${i}.1.html; \
189
191
  sed -e '/"documentation">/r man1/'$$i'.1.html' \
190
- < $${i}_1.html > tmp && mv tmp $${i}_1.html; done
192
+ < $${i}_1.html > tmp && mv tmp $${i}_1.html; \
193
+ ln $${i}_1.html $${i}.1.html; \
194
+ done
191
195
  $(RUBY) -i -p -e \
192
196
  '$$_.gsub!("</title>",%q{\&$(call atom,$(cgit_atom))})' \
193
197
  doc/ChangeLog.html
@@ -196,7 +200,7 @@ doc: .document $(ext)/unicorn_http.c NEWS ChangeLog
196
200
  doc/NEWS.html doc/README.html
197
201
  $(RAKE) -s news_atom > doc/NEWS.atom.xml
198
202
  cd doc && ln README.html tmp && mv tmp index.html
199
- $(RM) $(man1_bins)
203
+ $(RM) $(man1_rdoc)
200
204
 
201
205
  rails_git_url = git://github.com/rails/rails.git
202
206
  rails_git := vendor/rails.git
data/KNOWN_ISSUES CHANGED
@@ -3,6 +3,14 @@
3
3
  Occasionally odd {issues}[link:ISSUES.html] arise without a transparent or
4
4
  acceptable solution. Those issues are documented here.
5
5
 
6
+ * Under Ruby 1.9.1, methods like Array#shuffle and Array#sample will
7
+ segfault if called after forking. This is fixed in trunk (r26936) and
8
+ should be backported to the next 1.9.1 stable release (after p378).
9
+ Until then, it is advisable to call "Kernel.rand" in your after_fork
10
+ hook to reinitialize the random number generator.
11
+
12
+ See http://redmine.ruby-lang.org/issues/show/2962 for more details
13
+
6
14
  * When using "preload_app true", with apps using background threads
7
15
  need to restart them in the after_fork hook because threads are never
8
16
  shared with child processes. Additionally, any synchronization
@@ -36,6 +44,18 @@ acceptable solution. Those issues are documented here.
36
44
  where the unicorn gem is installed (e.g.
37
45
  /usr/lib/ruby/gems/1.8/gems/unicorn-VERSION/lib)
38
46
 
47
+ With current versions of isolate, it is also recommended that you
48
+ disable it with the <tt>before_exec</tt> hook prevent the PATH and
49
+ RUBYOPT environment variable modifications from propagating between
50
+ upgrades in your Unicorn config file:
51
+
52
+ before_exec do |server|
53
+ Isolate.disable
54
+ end
55
+
56
+ Future versions (unreleased as of 2010.04.20) of isolate will not
57
+ require this as environment variable modifications will be idempotent.
58
+
39
59
  * WONTFIX: code reloading and restarts with Sinatra 0.3.x (and likely older
40
60
  versions) apps is broken. The workaround is to force production
41
61
  mode to disable code reloading as well as disabling "run" in your
data/README CHANGED
@@ -1,6 +1,6 @@
1
1
  = Unicorn: Rack HTTP server for fast clients and Unix
2
2
 
3
- Unicorn is an HTTP server for Rack applications designed to only serve
3
+ \Unicorn is an HTTP server for Rack applications designed to only serve
4
4
  fast clients on low-latency, high-bandwidth connections and take
5
5
  advantage of features in Unix/Unix-like kernels. Slow clients should
6
6
  only be served by placing a reverse proxy capable of fully buffering
@@ -14,9 +14,9 @@ both the the request and response in between Unicorn and slow clients.
14
14
 
15
15
  * Compatible with both Ruby 1.8 and 1.9. Rubinius support is in-progress.
16
16
 
17
- * Process management: Unicorn will reap and restart workers that
17
+ * Process management: \Unicorn will reap and restart workers that
18
18
  die from broken apps. There is no need to manage multiple processes
19
- or ports yourself. Unicorn can spawn and manage any number of
19
+ or ports yourself. \Unicorn can spawn and manage any number of
20
20
  worker processes you choose to scale to your backend.
21
21
 
22
22
  * Load balancing is done entirely by the operating system kernel.
@@ -32,11 +32,11 @@ both the the request and response in between Unicorn and slow clients.
32
32
  * Builtin reopening of all log files in your application via
33
33
  USR1 signal. This allows logrotate to rotate files atomically and
34
34
  quickly via rename instead of the racy and slow copytruncate method.
35
- Unicorn also takes steps to ensure multi-line log entries from one
35
+ \Unicorn also takes steps to ensure multi-line log entries from one
36
36
  request all stay within the same file.
37
37
 
38
38
  * nginx-style binary upgrades without losing connections.
39
- You can upgrade Unicorn, your entire application, libraries
39
+ You can upgrade \Unicorn, your entire application, libraries
40
40
  and even your Ruby interpreter without dropping clients.
41
41
 
42
42
  * before_fork and after_fork hooks in case your application
@@ -59,14 +59,14 @@ both the the request and response in between Unicorn and slow clients.
59
59
 
60
60
  == License
61
61
 
62
- Unicorn is copyright 2009 by all contributors (see logs in git).
62
+ \Unicorn is copyright 2009 by all contributors (see logs in git).
63
63
  It is based on Mongrel and carries the same license.
64
64
 
65
65
  Mongrel is copyright 2007 Zed A. Shaw and contributors. It is licensed
66
66
  under the Ruby license and the GPL2. See the included LICENSE file for
67
67
  details.
68
68
 
69
- Unicorn is 100% Free Software.
69
+ \Unicorn is 100% Free Software.
70
70
 
71
71
  == Install
72
72
 
@@ -111,17 +111,17 @@ In RAILS_ROOT, run:
111
111
 
112
112
  unicorn_rails
113
113
 
114
- Unicorn will bind to all interfaces on TCP port 8080 by default.
114
+ \Unicorn will bind to all interfaces on TCP port 8080 by default.
115
115
  You may use the +--listen/-l+ switch to bind to a different
116
116
  address:port or a UNIX socket.
117
117
 
118
118
  === Configuration File(s)
119
119
 
120
- Unicorn will look for the config.ru file used by rackup in APP_ROOT.
120
+ \Unicorn will look for the config.ru file used by rackup in APP_ROOT.
121
121
 
122
- For deployments, it can use a config file for Unicorn-specific options
122
+ For deployments, it can use a config file for \Unicorn-specific options
123
123
  specified by the +--config-file/-c+ command-line switch. See
124
- Unicorn::Configurator for the syntax of the Unicorn-specific options.
124
+ Unicorn::Configurator for the syntax of the \Unicorn-specific options.
125
125
  The default settings are designed for maximum out-of-the-box
126
126
  compatibility with existing applications.
127
127
 
@@ -134,7 +134,7 @@ options.
134
134
  There is NO WARRANTY whatsoever if anything goes wrong, but
135
135
  {let us know}[link:ISSUES.html] and we'll try our best to fix it.
136
136
 
137
- Unicorn is designed to only serve fast clients either on the local host
137
+ \Unicorn is designed to only serve fast clients either on the local host
138
138
  or a fast LAN. See the PHILOSOPHY and DESIGN documents for more details
139
139
  regarding this.
140
140
 
@@ -144,6 +144,6 @@ All feedback (bug reports, user/development dicussion, patches, pull
144
144
  requests) go to the mailing list/newsgroup. See the ISSUES document for
145
145
  information on the {mailing list}[mailto:mongrel-unicorn@rubyforge.org].
146
146
 
147
- For the latest on Unicorn releases, you may also finger us at
147
+ For the latest on \Unicorn releases, you may also finger us at
148
148
  unicorn@bogomips.org or check our NEWS page (and subscribe to our Atom
149
149
  feed).
data/Rakefile CHANGED
@@ -175,16 +175,17 @@ end
175
175
 
176
176
  # optional rake-compiler support in case somebody needs to cross compile
177
177
  begin
178
- spec = Gem::Specification.load('unicorn.gemspec')
179
- require 'rake/extensiontask'
180
- unless test ?r, "ext/unicorn_http/unicorn_http.c"
181
- abort "run 'gmake ragel' or 'make ragel' to generate the Ragel source"
182
- end
183
178
  mk = "ext/unicorn_http/Makefile"
184
179
  if test ?r, mk
185
- abort "run 'gmake -C ext/unicorn_http clean' and " \
186
- "remove #{mk} before using rake-compiler"
180
+ warn "run 'gmake -C ext/unicorn_http clean' and\n" \
181
+ "remove #{mk} before using rake-compiler"
182
+ else
183
+ unless test ?r, "ext/unicorn_http/unicorn_http.c"
184
+ abort "run 'gmake ragel' or 'make ragel' to generate the Ragel source"
185
+ end
186
+ spec = Gem::Specification.load('unicorn.gemspec')
187
+ require 'rake/extensiontask'
188
+ Rake::ExtensionTask.new('unicorn_http', spec)
187
189
  end
188
- Rake::ExtensionTask.new('unicorn_http', spec)
189
190
  rescue LoadError
190
191
  end
data/bin/unicorn CHANGED
@@ -5,8 +5,7 @@ require 'optparse'
5
5
 
6
6
  ENV["RACK_ENV"] ||= "development"
7
7
  daemonize = false
8
- listeners = []
9
- options = { :listeners => listeners }
8
+ options = { :listeners => [] }
10
9
  host, port = Unicorn::Const::DEFAULT_HOST, Unicorn::Const::DEFAULT_PORT
11
10
  set_listener = false
12
11
 
@@ -81,7 +80,7 @@ opts = OptionParser.new("", 24, ' ') do |opts|
81
80
  "listen on HOST:PORT or PATH",
82
81
  "this may be specified multiple times",
83
82
  "(default: #{Unicorn::Const::DEFAULT_LISTEN})") do |address|
84
- listeners << address
83
+ options[:listeners] << address
85
84
  end
86
85
 
87
86
  opts.on("-c", "--config-file FILE", "Unicorn-specific config file") do |f|
@@ -112,7 +111,7 @@ ru = ARGV[0] || "config.ru"
112
111
  abort "configuration file #{ru} not found" unless File.exist?(ru)
113
112
 
114
113
  app = Unicorn.builder(ru, opts)
115
- listeners << "#{host}:#{port}" if set_listener
114
+ options[:listeners] << "#{host}:#{port}" if set_listener
116
115
 
117
116
  if $DEBUG
118
117
  require 'pp'
data/bin/unicorn_rails CHANGED
@@ -5,8 +5,7 @@ require 'optparse'
5
5
  require 'fileutils'
6
6
 
7
7
  daemonize = false
8
- listeners = []
9
- options = { :listeners => listeners }
8
+ options = { :listeners => [] }
10
9
  host, port = Unicorn::Const::DEFAULT_HOST, Unicorn::Const::DEFAULT_PORT
11
10
  set_listener = false
12
11
  ENV['RAILS_ENV'] ||= "development"
@@ -70,7 +69,7 @@ opts = OptionParser.new("", 24, ' ') do |opts|
70
69
  "listen on HOST:PORT or PATH",
71
70
  "this may be specified multiple times",
72
71
  "(default: #{Unicorn::Const::DEFAULT_LISTEN})") do |address|
73
- listeners << address
72
+ options[:listeners] << address
74
73
  end
75
74
 
76
75
  opts.on("-c", "--config-file FILE", "Unicorn-specific config file") do |f|
@@ -108,14 +107,14 @@ opts = OptionParser.new("", 24, ' ') do |opts|
108
107
  opts.parse! ARGV
109
108
  end
110
109
 
111
- config = ARGV[0] || (File.exist?('config.ru') ? 'config.ru' : nil)
110
+ ru = ARGV[0] || (File.exist?('config.ru') ? 'config.ru' : nil)
112
111
 
113
- if config && config =~ /\.ru\z/
112
+ if ru && ru =~ /\.ru\z/
114
113
  # parse embedded command-line options in config.ru comments
115
- /^#\\(.*)/ =~ File.read(config) and opts.parse!($1.split(/\s+/))
114
+ /^#\\(.*)/ =~ File.read(ru) and opts.parse!($1.split(/\s+/))
116
115
  end
117
116
 
118
- def rails_builder(config, daemonize)
117
+ def rails_builder(ru, daemonize)
119
118
  # this lambda won't run until after forking if preload_app is false
120
119
  lambda do ||
121
120
  # Load Rails and (possibly) the private version of Rack it bundles.
@@ -125,7 +124,7 @@ def rails_builder(config, daemonize)
125
124
  abort "#$0 must be run inside RAILS_ROOT: #{err.inspect}"
126
125
  end
127
126
 
128
- inner_app = case config
127
+ inner_app = case ru
129
128
  when nil
130
129
  require 'config/environment'
131
130
 
@@ -146,12 +145,12 @@ def rails_builder(config, daemonize)
146
145
  ActionController::Dispatcher.new
147
146
  end
148
147
  when /\.ru$/
149
- raw = File.open(config, "rb") { |fp| fp.sysread(fp.stat.size) }
148
+ raw = File.read(ru)
150
149
  raw.sub!(/^__END__\n.*/, '')
151
- eval("Rack::Builder.new {(#{raw}\n)}.to_app", nil, config)
150
+ eval("Rack::Builder.new {(#{raw}\n)}.to_app", TOPLEVEL_BINDING, ru)
152
151
  else
153
- require config
154
- Object.const_get(File.basename(config, '.rb').capitalize)
152
+ require ru
153
+ Object.const_get(File.basename(ru, '.rb').capitalize)
155
154
  end
156
155
 
157
156
  Rack::Builder.new do
@@ -180,8 +179,8 @@ def rails_builder(config, daemonize)
180
179
  end
181
180
  end
182
181
 
183
- app = rails_builder(config, daemonize)
184
- listeners << "#{host}:#{port}" if set_listener
182
+ app = rails_builder(ru, daemonize)
183
+ options[:listeners] << "#{host}:#{port}" if set_listener
185
184
 
186
185
  if $DEBUG
187
186
  require 'pp'
@@ -299,12 +299,8 @@ static void write_value(VALUE req, struct http_parser *hp,
299
299
  }
300
300
 
301
301
  action end_chunked_body {
302
- if (HP_FL_TEST(hp, HASTRAILER)) {
303
- HP_FL_SET(hp, INTRAILER);
304
- cs = http_parser_en_Trailers;
305
- } else {
306
- cs = http_parser_first_final;
307
- }
302
+ HP_FL_SET(hp, INTRAILER);
303
+ cs = http_parser_en_Trailers;
308
304
  ++p;
309
305
  assert(p <= pe && "buffer overflow after chunked body");
310
306
  goto post_exec;
data/lib/unicorn.rb CHANGED
@@ -1,8 +1,17 @@
1
1
  # -*- encoding: binary -*-
2
2
 
3
3
  require 'fcntl'
4
- require 'unicorn/socket_helper'
5
4
  require 'etc'
5
+ require 'unicorn/socket_helper'
6
+ require 'unicorn/const'
7
+ require 'unicorn/http_request'
8
+ require 'unicorn/configurator'
9
+ require 'unicorn/util'
10
+ require 'unicorn/tee_input'
11
+
12
+ # autoload this so the app can prefer a different version, we
13
+ # don't rely on Rack itself for much and should be compatible for
14
+ # 1.0.x and 1.1.x+
6
15
  autoload :Rack, 'rack'
7
16
 
8
17
  # Unicorn module containing all of the classes (include C extensions) for running
@@ -17,12 +26,10 @@ module Unicorn
17
26
  class ClientShutdown < EOFError
18
27
  end
19
28
 
20
- autoload :Const, 'unicorn/const'
21
- autoload :HttpRequest, 'unicorn/http_request'
29
+ # we load HttpResponse last since it depends on Rack, and we
30
+ # want the application to be able to specify Rack (if they're
31
+ # *not* using config.ru)
22
32
  autoload :HttpResponse, 'unicorn/http_response'
23
- autoload :Configurator, 'unicorn/configurator'
24
- autoload :TeeInput, 'unicorn/tee_input'
25
- autoload :Util, 'unicorn/util'
26
33
 
27
34
  class << self
28
35
  def run(app, options = {})
@@ -71,6 +78,13 @@ module Unicorn
71
78
  end
72
79
  end
73
80
  end
81
+
82
+ # returns an array of strings representing TCP listen socket addresses
83
+ # and Unix domain socket paths. This is useful for use with
84
+ # Raindrops::Middleware under Linux: http://raindrops.bogomips.org/
85
+ def listener_names
86
+ HttpServer::LISTENERS.map { |io| SocketHelper.sock_name(io) }
87
+ end
74
88
  end
75
89
 
76
90
  # This is the process manager of Unicorn. This manages worker
@@ -395,9 +409,12 @@ module Unicorn
395
409
  # machine) comes out of suspend/hibernation
396
410
  if (last_check + timeout) >= (last_check = Time.now)
397
411
  murder_lazy_workers
412
+ else
413
+ # wait for workers to wakeup on suspend
414
+ master_sleep(timeout/2.0 + 1)
398
415
  end
399
416
  maintain_worker_count if respawn
400
- master_sleep
417
+ master_sleep(1)
401
418
  when :QUIT # graceful shutdown
402
419
  break
403
420
  when :TERM, :INT # immediate shutdown
@@ -478,9 +495,9 @@ module Unicorn
478
495
 
479
496
  # wait for a signal hander to wake us up and then consume the pipe
480
497
  # Wake up every second anyways to run murder_lazy_workers
481
- def master_sleep
498
+ def master_sleep(sec)
482
499
  begin
483
- ready = IO.select([SELF_PIPE.first], nil, nil, 1) or return
500
+ ready = IO.select([SELF_PIPE.first], nil, nil, sec) or return
484
501
  ready.first && ready.first.first or return
485
502
  loop { SELF_PIPE.first.read_nonblock(Const::CHUNK_SIZE) }
486
503
  rescue Errno::EAGAIN, Errno::EINTR
@@ -800,15 +817,15 @@ module Unicorn
800
817
 
801
818
  def build_app!
802
819
  if app.respond_to?(:arity) && app.arity == 0
803
- # exploit COW in case of preload_app. Also avoids race
804
- # conditions in Rainbows! since load/require are not thread-safe
805
- Unicorn.constants.each { |x| Unicorn.const_get(x) }
806
-
807
820
  if defined?(Gem) && Gem.respond_to?(:refresh)
808
821
  logger.info "Refreshing Gem list"
809
822
  Gem.refresh
810
823
  end
811
824
  self.app = app.call
825
+
826
+ # exploit COW in case of preload_app. Also avoids race
827
+ # conditions in Rainbows! since load/require are not thread-safe
828
+ Unicorn.const_get :HttpResponse
812
829
  end
813
830
  end
814
831
 
data/lib/unicorn/const.rb CHANGED
@@ -7,7 +7,7 @@ module Unicorn
7
7
  # gave about a 3% to 10% performance improvement over using the strings directly.
8
8
  # Symbols did not really improve things much compared to constants.
9
9
  module Const
10
- UNICORN_VERSION="0.97.1"
10
+ UNICORN_VERSION="0.98.0"
11
11
 
12
12
  DEFAULT_HOST = "0.0.0.0" # default TCP listen host address
13
13
  DEFAULT_PORT = 8080 # default TCP listen port
@@ -136,6 +136,8 @@ module Unicorn
136
136
  end
137
137
  end
138
138
 
139
+ module_function :sock_name
140
+
139
141
  # casts a given Socket to be a TCPServer or UNIXServer
140
142
  def server_cast(sock)
141
143
  begin
@@ -234,7 +234,7 @@ logger Logger.new('#{COMMON_TMP.path}')
234
234
  def test_alt_url_root_config_env
235
235
  # cbf to actually work on this since I never use this feature (ewong)
236
236
  return unless ROR_V[0] >= 2 && ROR_V[1] >= 3
237
- tmp = Tempfile.new(nil)
237
+ tmp = Tempfile.new('')
238
238
  tmp.syswrite("ENV['RAILS_RELATIVE_URL_ROOT'] = '/poo'\n")
239
239
  redirect_test_io do
240
240
  @pid = fork { exec 'unicorn_rails', "-l#@addr:#@port", "-c", tmp.path }
@@ -172,6 +172,10 @@ class HttpParserNgTest < Test::Unit::TestCase
172
172
  assert_equal '', str
173
173
  assert ! @parser.body_eof?
174
174
  assert_equal "", @parser.filter_body(tmp, "\r\n0\r\n")
175
+ assert_equal "", tmp
176
+ assert @parser.body_eof?
177
+ assert_equal req, @parser.trailers(req, moo = "\r\n")
178
+ assert_equal "", moo
175
179
  assert @parser.body_eof?
176
180
  assert ! @parser.keepalive?
177
181
  end
@@ -283,5 +283,9 @@ class WebServerTest < Test::Unit::TestCase
283
283
  }
284
284
  end
285
285
 
286
+ def test_listener_names
287
+ assert_equal [ "127.0.0.1:#@port" ], Unicorn.listener_names
288
+ end
289
+
286
290
  end
287
291
 
@@ -160,7 +160,7 @@ class TestTeeInput < Test::Unit::TestCase
160
160
  pid = fork {
161
161
  @rd.close
162
162
  5.times { @wr.write("5\r\nabcde\r\n") }
163
- @wr.write("0\r\n")
163
+ @wr.write("0\r\n\r\n")
164
164
  }
165
165
  @wr.close
166
166
  ti = Unicorn::TeeInput.new(@rd, @env, @parser, @buf)
@@ -199,7 +199,7 @@ class TestTeeInput < Test::Unit::TestCase
199
199
  rd.read(1) == "." and
200
200
  @wr.write("#{'%x' % [ chunk.size]}\r\n#{chunk}\r\n")
201
201
  end
202
- @wr.write("0\r\n")
202
+ @wr.write("0\r\n\r\n")
203
203
  }
204
204
  ti = Unicorn::TeeInput.new(@rd, @env, @parser, @buf)
205
205
  assert_nil @parser.content_length
@@ -213,6 +213,34 @@ class TestTeeInput < Test::Unit::TestCase
213
213
  assert status.success?
214
214
  end
215
215
 
216
+ def test_chunked_with_trailer
217
+ @parser = Unicorn::HttpParser.new
218
+ @buf = "POST / HTTP/1.1\r\n" \
219
+ "Host: localhost\r\n" \
220
+ "Trailer: Hello\r\n" \
221
+ "Transfer-Encoding: chunked\r\n" \
222
+ "\r\n"
223
+ assert_equal @env, @parser.headers(@env, @buf)
224
+ assert_equal "", @buf
225
+
226
+ pid = fork {
227
+ @rd.close
228
+ 5.times { @wr.write("5\r\nabcde\r\n") }
229
+ @wr.write("0\r\n")
230
+ @wr.write("Hello: World\r\n\r\n")
231
+ }
232
+ @wr.close
233
+ ti = Unicorn::TeeInput.new(@rd, @env, @parser, @buf)
234
+ assert_nil @parser.content_length
235
+ assert_nil ti.len
236
+ assert ! @parser.body_eof?
237
+ assert_equal 25, ti.size
238
+ assert_equal "World", @env['HTTP_HELLO']
239
+ status = nil
240
+ assert_nothing_raised { pid, status = Process.waitpid2(pid) }
241
+ assert status.success?
242
+ end
243
+
216
244
  private
217
245
 
218
246
  def init_parser(body, size = nil)
@@ -7,7 +7,7 @@ class TestUtil < Test::Unit::TestCase
7
7
 
8
8
  EXPECT_FLAGS = File::WRONLY | File::APPEND
9
9
  def test_reopen_logs_noop
10
- tmp = Tempfile.new(nil)
10
+ tmp = Tempfile.new('')
11
11
  tmp.reopen(tmp.path, 'a')
12
12
  tmp.sync = true
13
13
  ext = tmp.external_encoding rescue nil
@@ -21,14 +21,14 @@ class TestUtil < Test::Unit::TestCase
21
21
  end
22
22
 
23
23
  def test_reopen_logs_renamed
24
- tmp = Tempfile.new(nil)
24
+ tmp = Tempfile.new('')
25
25
  tmp_path = tmp.path.freeze
26
26
  tmp.reopen(tmp_path, 'a')
27
27
  tmp.sync = true
28
28
  ext = tmp.external_encoding rescue nil
29
29
  int = tmp.internal_encoding rescue nil
30
30
  before = tmp.stat.inspect
31
- to = Tempfile.new(nil)
31
+ to = Tempfile.new('')
32
32
  File.rename(tmp_path, to.path)
33
33
  assert ! File.exist?(tmp_path)
34
34
  Unicorn::Util.reopen_logs
@@ -45,7 +45,7 @@ class TestUtil < Test::Unit::TestCase
45
45
  end
46
46
 
47
47
  def test_reopen_logs_renamed_with_encoding
48
- tmp = Tempfile.new(nil)
48
+ tmp = Tempfile.new('')
49
49
  tmp_path = tmp.path.dup.freeze
50
50
  Encoding.list.each { |encoding|
51
51
  File.open(tmp_path, "a:#{encoding.to_s}") { |fp|
@@ -68,7 +68,7 @@ class TestUtil < Test::Unit::TestCase
68
68
  end if STDIN.respond_to?(:external_encoding)
69
69
 
70
70
  def test_reopen_logs_renamed_with_internal_encoding
71
- tmp = Tempfile.new(nil)
71
+ tmp = Tempfile.new('')
72
72
  tmp_path = tmp.path.dup.freeze
73
73
  Encoding.list.each { |ext|
74
74
  Encoding.list.each { |int|
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: unicorn
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.97.1
4
+ version: 0.98.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Unicorn hackers
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2010-04-19 00:00:00 +00:00
12
+ date: 2010-05-05 00:00:00 +00:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -23,7 +23,7 @@ dependencies:
23
23
  version: "0"
24
24
  version:
25
25
  description: |-
26
- Unicorn is an HTTP server for Rack applications designed to only serve
26
+ \Unicorn is an HTTP server for Rack applications designed to only serve
27
27
  fast clients on low-latency, high-bandwidth connections and take
28
28
  advantage of features in Unix/Unix-like kernels. Slow clients should
29
29
  only be served by placing a reverse proxy capable of fully buffering