unicorn 0.96.1 → 0.97.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -29,6 +29,19 @@
29
29
  # error off_t size unknown for this platform!
30
30
  #endif /* SIZEOF_OFF_T check */
31
31
 
32
+ /*
33
+ * ragel enforces fpc as a const, and merely casting can make picky
34
+ * compilers unhappy, so we have this little helper do our dirty work
35
+ */
36
+ static inline void *deconst(const void *in)
37
+ {
38
+ union { const void *in; void *out; } tmp;
39
+
40
+ tmp.in = in;
41
+
42
+ return tmp.out;
43
+ }
44
+
32
45
  /*
33
46
  * capitalizes all lower-case ASCII characters and converts dashes
34
47
  * to underscores for HTTP headers. Locale-agnostic.
@@ -67,7 +67,7 @@ static void init_common_fields(void)
67
67
  char tmp[64];
68
68
  memcpy(tmp, HTTP_PREFIX, HTTP_PREFIX_LEN);
69
69
 
70
- for(i = 0; i < ARRAY_SIZE(common_http_fields); cf++, i++) {
70
+ for(i = ARRAY_SIZE(common_http_fields); --i >= 0; cf++) {
71
71
  /* Rack doesn't like certain headers prefixed with "HTTP_" */
72
72
  if (!strcmp("CONTENT_LENGTH", cf->name) ||
73
73
  !strcmp("CONTENT_TYPE", cf->name)) {
@@ -87,8 +87,8 @@ static VALUE find_common_field(const char *field, size_t flen)
87
87
  int i;
88
88
  struct common_field *cf = common_http_fields;
89
89
 
90
- for(i = 0; i < ARRAY_SIZE(common_http_fields); i++, cf++) {
91
- if (cf->len == flen && !memcmp(cf->name, field, flen))
90
+ for(i = ARRAY_SIZE(common_http_fields); --i >= 0; cf++) {
91
+ if (cf->len == (long)flen && !memcmp(cf->name, field, flen))
92
92
  return cf->value;
93
93
  }
94
94
  return Qnil;
@@ -47,7 +47,7 @@ static void rb_18_str_set_len(VALUE str, long len)
47
47
  # define rb_str_modify(x) do {} while (0)
48
48
  #endif /* ! defined(HAVE_RB_STR_MODIFY) */
49
49
 
50
- static inline int str_cstr_eq(VALUE val, const char *ptr, size_t len)
50
+ static inline int str_cstr_eq(VALUE val, const char *ptr, long len)
51
51
  {
52
52
  return (RSTRING_LEN(val) == len && !memcmp(ptr, RSTRING_PTR(val), len));
53
53
  }
@@ -56,7 +56,7 @@ static inline int str_cstr_eq(VALUE val, const char *ptr, size_t len)
56
56
  str_cstr_eq(val, const_str, sizeof(const_str) - 1)
57
57
 
58
58
  /* strcasecmp isn't locale independent */
59
- static int str_cstr_case_eq(VALUE val, const char *ptr, size_t len)
59
+ static int str_cstr_case_eq(VALUE val, const char *ptr, long len)
60
60
  {
61
61
  if (RSTRING_LEN(val) == len) {
62
62
  const char *v = RSTRING_PTR(val);
@@ -1,7 +1,5 @@
1
1
  #ifndef global_variables_h
2
2
  #define global_variables_h
3
- static VALUE mUnicorn;
4
- static VALUE cHttpParser;
5
3
  static VALUE eHttpParserError;
6
4
 
7
5
  static VALUE g_rack_url_scheme;
@@ -61,7 +59,7 @@ DEF_MAX_LENGTH(REQUEST_PATH, 1024);
61
59
  DEF_MAX_LENGTH(QUERY_STRING, (1024 * 10));
62
60
  DEF_MAX_LENGTH(HEADER, (1024 * (80 + 32)));
63
61
 
64
- void init_globals(void)
62
+ static void init_globals(void)
65
63
  {
66
64
  DEF_GLOBAL(rack_url_scheme, "rack.url_scheme");
67
65
  DEF_GLOBAL(request_method, "REQUEST_METHOD");
@@ -136,7 +136,7 @@ static inline void hp_invalid_if_trailer(struct http_parser *hp)
136
136
  }
137
137
 
138
138
  static void write_cont_value(struct http_parser *hp,
139
- const char *buffer, const char *p)
139
+ char *buffer, const char *p)
140
140
  {
141
141
  char *vptr;
142
142
 
@@ -154,7 +154,7 @@ static void write_cont_value(struct http_parser *hp,
154
154
  if (RSTRING_LEN(hp->cont) > 0)
155
155
  --hp->mark;
156
156
 
157
- vptr = (char *)PTR_TO(mark);
157
+ vptr = PTR_TO(mark);
158
158
 
159
159
  if (RSTRING_LEN(hp->cont) > 0) {
160
160
  assert((' ' == *vptr || '\t' == *vptr) && "invalid leading white space");
@@ -220,8 +220,8 @@ static void write_value(VALUE req, struct http_parser *hp,
220
220
  action mark {MARK(mark, fpc); }
221
221
 
222
222
  action start_field { MARK(start.field, fpc); }
223
- action snake_upcase_field { snake_upcase_char((char *)fpc); }
224
- action downcase_char { downcase_char((char *)fpc); }
223
+ action snake_upcase_field { snake_upcase_char(deconst(fpc)); }
224
+ action downcase_char { downcase_char(deconst(fpc)); }
225
225
  action write_field { hp->s.field_len = LEN(start.field, fpc); }
226
226
  action start_value { MARK(mark, fpc); }
227
227
  action write_value { write_value(req, hp, buffer, fpc); }
@@ -236,10 +236,9 @@ static void write_value(VALUE req, struct http_parser *hp,
236
236
  rb_hash_aset(req, g_http_host, STR_NEW(mark, fpc));
237
237
  }
238
238
  action request_uri {
239
- size_t len = LEN(mark, fpc);
240
239
  VALUE str;
241
240
 
242
- VALIDATE_MAX_LENGTH(len, REQUEST_URI);
241
+ VALIDATE_MAX_LENGTH(LEN(mark, fpc), REQUEST_URI);
243
242
  str = rb_hash_aset(req, g_request_uri, STR_NEW(mark, fpc));
244
243
  /*
245
244
  * "OPTIONS * HTTP/1.1\r\n" is a valid request, but we can't have '*'
@@ -263,9 +262,8 @@ static void write_value(VALUE req, struct http_parser *hp,
263
262
  action http_version { http_version(hp, req, PTR_TO(mark), LEN(mark, fpc)); }
264
263
  action request_path {
265
264
  VALUE val;
266
- size_t len = LEN(mark, fpc);
267
265
 
268
- VALIDATE_MAX_LENGTH(len, REQUEST_PATH);
266
+ VALIDATE_MAX_LENGTH(LEN(mark, fpc), REQUEST_PATH);
269
267
  val = rb_hash_aset(req, g_request_path, STR_NEW(mark, fpc));
270
268
 
271
269
  /* rack says PATH_INFO must start with "/" or be empty */
@@ -314,13 +312,13 @@ static void write_value(VALUE req, struct http_parser *hp,
314
312
 
315
313
  action skip_chunk_data {
316
314
  skip_chunk_data_hack: {
317
- size_t nr = MIN(hp->len.chunk, REMAINING);
315
+ size_t nr = MIN((size_t)hp->len.chunk, REMAINING);
318
316
  memcpy(RSTRING_PTR(req) + hp->s.dest_offset, fpc, nr);
319
317
  hp->s.dest_offset += nr;
320
318
  hp->len.chunk -= nr;
321
319
  p += nr;
322
320
  assert(hp->len.chunk >= 0 && "negative chunk length");
323
- if (hp->len.chunk > REMAINING) {
321
+ if ((size_t)hp->len.chunk > REMAINING) {
324
322
  HP_FL_SET(hp, INCHUNK);
325
323
  goto post_exec;
326
324
  } else {
@@ -346,7 +344,7 @@ static void http_parser_init(struct http_parser *hp)
346
344
 
347
345
  /** exec **/
348
346
  static void http_parser_execute(struct http_parser *hp,
349
- VALUE req, const char *buffer, size_t len)
347
+ VALUE req, char *buffer, size_t len)
350
348
  {
351
349
  const char *p, *pe;
352
350
  int cs = hp->cs;
@@ -360,7 +358,8 @@ static void http_parser_execute(struct http_parser *hp,
360
358
  p = buffer+off;
361
359
  pe = buffer+len;
362
360
 
363
- assert(pe - p == len - off && "pointers aren't same distance");
361
+ assert((void *)(pe - p) == (void *)(len - off) &&
362
+ "pointers aren't same distance");
364
363
 
365
364
  if (HP_FL_TEST(hp, INCHUNK)) {
366
365
  HP_FL_UNSET(hp, INCHUNK);
@@ -675,10 +674,13 @@ static VALUE HttpParser_filter_body(VALUE self, VALUE buf, VALUE data)
675
674
 
676
675
  void Init_unicorn_http(void)
677
676
  {
677
+ VALUE mUnicorn, cHttpParser;
678
+
678
679
  mUnicorn = rb_define_module("Unicorn");
680
+ cHttpParser = rb_define_class_under(mUnicorn, "HttpParser", rb_cObject);
679
681
  eHttpParserError =
680
682
  rb_define_class_under(mUnicorn, "HttpParserError", rb_eIOError);
681
- cHttpParser = rb_define_class_under(mUnicorn, "HttpParser", rb_cObject);
683
+
682
684
  init_globals();
683
685
  rb_define_alloc_func(cHttpParser, HttpParser_alloc);
684
686
  rb_define_method(cHttpParser, "initialize", HttpParser_init,0);
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'fcntl'
4
4
  require 'unicorn/socket_helper'
5
+ require 'etc'
5
6
  autoload :Rack, 'rack'
6
7
 
7
8
  # Unicorn module containing all of the classes (include C extensions) for running
@@ -27,6 +28,49 @@ module Unicorn
27
28
  def run(app, options = {})
28
29
  HttpServer.new(app, options).start.join
29
30
  end
31
+
32
+ # This returns a lambda to pass in as the app, this does not "build" the
33
+ # app (which we defer based on the outcome of "preload_app" in the
34
+ # Unicorn config). The returned lambda will be called when it is
35
+ # time to build the app.
36
+ def builder(ru, opts)
37
+ if ru =~ /\.ru\z/
38
+ # parse embedded command-line options in config.ru comments
39
+ /^#\\(.*)/ =~ File.read(ru) and opts.parse!($1.split(/\s+/))
40
+ end
41
+
42
+ lambda do ||
43
+ inner_app = case ru
44
+ when /\.ru$/
45
+ raw = File.read(ru)
46
+ raw.sub!(/^__END__\n.*/, '')
47
+ eval("Rack::Builder.new {(#{raw}\n)}.to_app", TOPLEVEL_BINDING, ru)
48
+ else
49
+ require ru
50
+ Object.const_get(File.basename(ru, '.rb').capitalize)
51
+ end
52
+
53
+ pp({ :inner_app => inner_app }) if $DEBUG
54
+
55
+ # return value, matches rackup defaults based on env
56
+ case ENV["RACK_ENV"]
57
+ when "development"
58
+ Rack::Builder.new do
59
+ use Rack::CommonLogger, $stderr
60
+ use Rack::ShowExceptions
61
+ use Rack::Lint
62
+ run inner_app
63
+ end.to_app
64
+ when "deployment"
65
+ Rack::Builder.new do
66
+ use Rack::CommonLogger, $stderr
67
+ run inner_app
68
+ end.to_app
69
+ else
70
+ inner_app
71
+ end
72
+ end
73
+ end
30
74
  end
31
75
 
32
76
  # This is the process manager of Unicorn. This manages worker
@@ -34,11 +78,11 @@ module Unicorn
34
78
  # Listener sockets are started in the master process and shared with
35
79
  # forked worker children.
36
80
 
37
- class HttpServer < Struct.new(:listener_opts, :timeout, :worker_processes,
81
+ class HttpServer < Struct.new(:app, :timeout, :worker_processes,
38
82
  :before_fork, :after_fork, :before_exec,
39
- :logger, :pid, :app, :preload_app,
83
+ :logger, :pid, :listener_opts, :preload_app,
40
84
  :reexec_pid, :orig_app, :init_listeners,
41
- :master_pid, :config, :ready_pipe)
85
+ :master_pid, :config, :ready_pipe, :user)
42
86
  include ::Unicorn::SocketHelper
43
87
 
44
88
  # prevents IO objects in here from being GC-ed
@@ -119,9 +163,7 @@ module Unicorn
119
163
  # releases of Unicorn. You may need to access it in the
120
164
  # before_fork/after_fork hooks. See the Unicorn::Configurator RDoc
121
165
  # for examples.
122
- class Worker < Struct.new(:nr, :tmp)
123
-
124
- autoload :Etc, 'etc'
166
+ class Worker < Struct.new(:nr, :tmp, :switched)
125
167
 
126
168
  # worker objects may be compared to just plain numbers
127
169
  def ==(other_nr)
@@ -151,6 +193,7 @@ module Unicorn
151
193
  Process::GID.change_privilege(gid)
152
194
  end
153
195
  Process.euid != uid and Process::UID.change_privilege(uid)
196
+ self.switched = true
154
197
  end
155
198
 
156
199
  end
@@ -210,7 +253,18 @@ module Unicorn
210
253
  end
211
254
  config_listeners.each { |addr| listen(addr) }
212
255
  raise ArgumentError, "no listeners" if LISTENERS.empty?
256
+
257
+ # this pipe is used to wake us up from select(2) in #join when signals
258
+ # are trapped. See trap_deferred.
259
+ init_self_pipe!
260
+
261
+ # setup signal handlers before writing pid file in case people get
262
+ # trigger happy and send signals as soon as the pid file exists.
263
+ # Note that signals don't actually get handled until the #join method
264
+ QUEUE_SIGS.each { |sig| trap_deferred(sig) }
265
+ trap(:CHLD) { |_| awaken_master }
213
266
  self.pid = config[:pid]
267
+
214
268
  self.master_pid = $$
215
269
  build_app! if preload_app
216
270
  maintain_worker_count
@@ -322,14 +376,9 @@ module Unicorn
322
376
  # one-at-a-time time and we'll happily drop signals in case somebody
323
377
  # is signalling us too often.
324
378
  def join
325
- # this pipe is used to wake us up from select(2) in #join when signals
326
- # are trapped. See trap_deferred
327
- init_self_pipe!
328
379
  respawn = true
329
380
  last_check = Time.now
330
381
 
331
- QUEUE_SIGS.each { |sig| trap_deferred(sig) }
332
- trap(:CHLD) { |sig_nr| awaken_master }
333
382
  proc_name 'master'
334
383
  logger.info "master process ready" # test_exec.rb relies on this message
335
384
  if ready_pipe
@@ -610,6 +659,7 @@ module Unicorn
610
659
  LISTENERS.each { |sock| sock.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) }
611
660
  worker.tmp.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
612
661
  after_fork.call(self, worker) # can drop perms
662
+ worker.user(*user) if user.kind_of?(Array) && ! worker.switched
613
663
  self.timeout /= 2.0 # halve it for select()
614
664
  build_app! unless preload_app
615
665
  end
@@ -725,6 +775,7 @@ module Unicorn
725
775
  end
726
776
 
727
777
  def load_config!
778
+ loaded_app = app
728
779
  begin
729
780
  logger.info "reloading config_file=#{config.config_file}"
730
781
  config[:listeners].replace(init_listeners)
@@ -735,9 +786,10 @@ module Unicorn
735
786
  self.app = orig_app
736
787
  build_app! if preload_app
737
788
  logger.info "done reloading config_file=#{config.config_file}"
738
- rescue => e
789
+ rescue StandardError, LoadError, SyntaxError => e
739
790
  logger.error "error reloading config_file=#{config.config_file}: " \
740
791
  "#{e.class} #{e.message}"
792
+ self.app = loaded_app
741
793
  end
742
794
  end
743
795
 
@@ -10,7 +10,7 @@ module Unicorn
10
10
  # See http://unicorn.bogomips.org/examples/unicorn.conf.rb for an
11
11
  # example config file. An example config file for use with nginx is
12
12
  # also available at http://unicorn.bogomips.org/examples/nginx.conf
13
- class Configurator < Struct.new(:set, :config_file)
13
+ class Configurator < Struct.new(:set, :config_file, :after_reload)
14
14
 
15
15
  # Default settings for Unicorn
16
16
  DEFAULTS = {
@@ -34,6 +34,10 @@ module Unicorn
34
34
  self.set = Hash.new(:unset)
35
35
  use_defaults = defaults.delete(:use_defaults)
36
36
  self.config_file = defaults.delete(:config_file)
37
+
38
+ # after_reload is only used by unicorn_rails, unsupported otherwise
39
+ self.after_reload = defaults.delete(:after_reload)
40
+
37
41
  set.merge!(DEFAULTS) if use_defaults
38
42
  defaults.each { |key, value| self.send(key, value) }
39
43
  Hash === set[:listener_opts] or
@@ -53,6 +57,9 @@ module Unicorn
53
57
  test(?w, path) || test(?w, File.dirname(path)) or \
54
58
  raise ArgumentError, "directory for #{var}=#{path} not writable"
55
59
  end
60
+
61
+ # unicorn_rails creates dirs here after working_directory is bound
62
+ after_reload.call if after_reload
56
63
  end
57
64
 
58
65
  def commit!(server, options = {}) #:nodoc:
@@ -329,6 +336,17 @@ module Unicorn
329
336
  HttpServer::START_CTX[:cwd] = ENV["PWD"] = path
330
337
  end
331
338
 
339
+ # Runs worker processes as the specified +user+ and +group+.
340
+ # The master process always stays running as the user who started it.
341
+ # This switch will occur after calling the after_fork hook, and only
342
+ # if the Worker#user method is not called in the after_fork hook
343
+ def user(user, group = nil)
344
+ # raises ArgumentError on invalid user/group
345
+ Etc.getpwnam(user)
346
+ Etc.getgrnam(group) if group
347
+ set[:user] = [ user, group ]
348
+ end
349
+
332
350
  # expands "unix:path/to/foo" to a socket relative to the current path
333
351
  # expands pathnames of sockets if relative to "~" or "~username"
334
352
  # expands "*:port and ":port" to "0.0.0.0:port"
@@ -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.96.1"
10
+ UNICORN_VERSION="0.97.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
@@ -16,12 +16,9 @@ module Unicorn
16
16
  # The basic max request size we'll try to read.
17
17
  CHUNK_SIZE=(16 * 1024)
18
18
 
19
- # This is the maximum header that is allowed before a client is booted. The parser detects
20
- # this, but we'd also like to do this as well.
21
- MAX_HEADER=1024 * (80 + 32)
22
-
23
- # Maximum request body size before it is moved out of memory and into a tempfile for reading.
24
- MAX_BODY=MAX_HEADER
19
+ # Maximum request body size before it is moved out of memory and into a
20
+ # temporary file for reading (112 kilobytes).
21
+ MAX_BODY=1024 * 112
25
22
 
26
23
  # common errors we'll send back
27
24
  ERROR_400_RESPONSE = "HTTP/1.1 400 Bad Request\r\n\r\n"
@@ -24,7 +24,7 @@ module Unicorn
24
24
 
25
25
  # Being explicitly single-threaded, we have certain advantages in
26
26
  # not having to worry about variables being clobbered :)
27
- BUF = ' ' * Const::CHUNK_SIZE # initial size, may grow
27
+ BUF = ""
28
28
  PARSER = HttpParser.new
29
29
  REQ = {}
30
30
 
@@ -13,19 +13,19 @@ module Unicorn
13
13
  #
14
14
  # When processing uploads, Unicorn exposes a TeeInput object under
15
15
  # "rack.input" of the Rack environment.
16
- class TeeInput < Struct.new(:socket, :req, :parser, :buf)
16
+ class TeeInput < Struct.new(:socket, :req, :parser, :buf, :len, :tmp, :buf2)
17
17
 
18
18
  # Initializes a new TeeInput object. You normally do not have to call
19
19
  # this unless you are writing an HTTP server.
20
20
  def initialize(*args)
21
21
  super(*args)
22
- @size = parser.content_length
23
- @tmp = @size && @size < Const::MAX_BODY ? StringIO.new("") : Util.tmpio
24
- @buf2 = buf.dup
22
+ self.len = parser.content_length
23
+ self.tmp = len && len < Const::MAX_BODY ? StringIO.new("") : Util.tmpio
24
+ self.buf2 = ""
25
25
  if buf.size > 0
26
- parser.filter_body(@buf2, buf) and finalize_input
27
- @tmp.write(@buf2)
28
- @tmp.seek(0)
26
+ parser.filter_body(buf2, buf) and finalize_input
27
+ tmp.write(buf2)
28
+ tmp.seek(0)
29
29
  end
30
30
  end
31
31
 
@@ -40,16 +40,16 @@ module Unicorn
40
40
  # all of the input stream before returning since there's no other
41
41
  # way to determine the size of the request body beforehand.
42
42
  def size
43
- @size and return @size
43
+ len and return len
44
44
 
45
45
  if socket
46
- pos = @tmp.pos
47
- while tee(Const::CHUNK_SIZE, @buf2)
46
+ pos = tmp.pos
47
+ while tee(Const::CHUNK_SIZE, buf2)
48
48
  end
49
- @tmp.seek(pos)
49
+ tmp.seek(pos)
50
50
  end
51
51
 
52
- @size = @tmp.size
52
+ self.len = tmp.size
53
53
  end
54
54
 
55
55
  # :call-seq:
@@ -72,22 +72,22 @@ module Unicorn
72
72
  # any data and only block when nothing is available (providing
73
73
  # IO#readpartial semantics).
74
74
  def read(*args)
75
- socket or return @tmp.read(*args)
75
+ socket or return tmp.read(*args)
76
76
 
77
77
  length = args.shift
78
78
  if nil == length
79
- rv = @tmp.read || ""
80
- while tee(Const::CHUNK_SIZE, @buf2)
81
- rv << @buf2
79
+ rv = tmp.read || ""
80
+ while tee(Const::CHUNK_SIZE, buf2)
81
+ rv << buf2
82
82
  end
83
83
  rv
84
84
  else
85
- rv = args.shift || @buf2.dup
86
- diff = @tmp.size - @tmp.pos
85
+ rv = args.shift || ""
86
+ diff = tmp.size - tmp.pos
87
87
  if 0 == diff
88
88
  ensure_length(tee(length, rv), length)
89
89
  else
90
- ensure_length(@tmp.read(diff > length ? length : diff, rv), length)
90
+ ensure_length(tmp.read(diff > length ? length : diff, rv), length)
91
91
  end
92
92
  end
93
93
  end
@@ -102,26 +102,26 @@ module Unicorn
102
102
  # This takes zero arguments for strict Rack::Lint compatibility,
103
103
  # unlike IO#gets.
104
104
  def gets
105
- socket or return @tmp.gets
105
+ socket or return tmp.gets
106
106
  nil == $/ and return read
107
107
 
108
- orig_size = @tmp.size
109
- if @tmp.pos == orig_size
110
- tee(Const::CHUNK_SIZE, @buf2) or return nil
111
- @tmp.seek(orig_size)
108
+ orig_size = tmp.size
109
+ if tmp.pos == orig_size
110
+ tee(Const::CHUNK_SIZE, buf2) or return nil
111
+ tmp.seek(orig_size)
112
112
  end
113
113
 
114
- line = @tmp.gets # cannot be nil here since size > pos
114
+ line = tmp.gets # cannot be nil here since size > pos
115
115
  $/ == line[-$/.size, $/.size] and return line
116
116
 
117
- # unlikely, if we got here, then @tmp is at EOF
117
+ # unlikely, if we got here, then tmp is at EOF
118
118
  begin
119
- orig_size = @tmp.pos
120
- tee(Const::CHUNK_SIZE, @buf2) or break
121
- @tmp.seek(orig_size)
122
- line << @tmp.gets
119
+ orig_size = tmp.pos
120
+ tee(Const::CHUNK_SIZE, buf2) or break
121
+ tmp.seek(orig_size)
122
+ line << tmp.gets
123
123
  $/ == line[-$/.size, $/.size] and return line
124
- # @tmp is at EOF again here, retry the loop
124
+ # tmp is at EOF again here, retry the loop
125
125
  end while true
126
126
 
127
127
  line
@@ -147,7 +147,7 @@ module Unicorn
147
147
  # the offset (zero) of the +ios+ pointer. Subsequent reads will
148
148
  # start from the beginning of the previously-buffered input.
149
149
  def rewind
150
- @tmp.rewind # Rack does not specify what the return value is here
150
+ tmp.rewind # Rack does not specify what the return value is here
151
151
  end
152
152
 
153
153
  private
@@ -160,7 +160,7 @@ module Unicorn
160
160
  # _entire_ request has been sent, and those will not have
161
161
  # raised EOFError on us.
162
162
  socket.close if socket
163
- raise ClientShutdown, "bytes_read=#{@tmp.size}", []
163
+ raise ClientShutdown, "bytes_read=#{tmp.size}", []
164
164
  when HttpParserError
165
165
  e.set_backtrace([])
166
166
  end
@@ -173,8 +173,8 @@ module Unicorn
173
173
  def tee(length, dst)
174
174
  unless parser.body_eof?
175
175
  if parser.filter_body(dst, socket.readpartial(length, buf)).nil?
176
- @tmp.write(dst)
177
- @tmp.seek(0, IO::SEEK_END) # workaround FreeBSD/OSX + MRI 1.8.x bug
176
+ tmp.write(dst)
177
+ tmp.seek(0, IO::SEEK_END) # workaround FreeBSD/OSX + MRI 1.8.x bug
178
178
  return dst
179
179
  end
180
180
  end
@@ -201,13 +201,13 @@ module Unicorn
201
201
  # streaming input bodies, this is a no-op for
202
202
  # "Transfer-Encoding: chunked" requests.
203
203
  def ensure_length(dst, length)
204
- # @size is nil for chunked bodies, so we can't ensure length for those
204
+ # len is nil for chunked bodies, so we can't ensure length for those
205
205
  # since they could be streaming bidirectionally and we don't want to
206
206
  # block the caller in that case.
207
- return dst if dst.nil? || @size.nil?
207
+ return dst if dst.nil? || len.nil?
208
208
 
209
- while dst.size < length && tee(length - dst.size, @buf2)
210
- dst << @buf2
209
+ while dst.size < length && tee(length - dst.size, buf2)
210
+ dst << buf2
211
211
  end
212
212
 
213
213
  dst