unicorn 0.96.1 → 0.97.0

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.
@@ -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