unicorn 5.6.0 → 6.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -12,6 +12,7 @@
12
12
  #include "common_field_optimization.h"
13
13
  #include "global_variables.h"
14
14
  #include "c_util.h"
15
+ #include "epollexclusive.h"
15
16
 
16
17
  void init_unicorn_httpdate(void);
17
18
 
@@ -65,18 +66,6 @@ struct http_parser {
65
66
  static ID id_set_backtrace, id_is_chunked_p;
66
67
  static VALUE cHttpParser;
67
68
 
68
- #ifdef HAVE_RB_HASH_CLEAR /* Ruby >= 2.0 */
69
- # define my_hash_clear(h) (void)rb_hash_clear(h)
70
- #else /* !HAVE_RB_HASH_CLEAR - Ruby <= 1.9.3 */
71
-
72
- static ID id_clear;
73
-
74
- static void my_hash_clear(VALUE h)
75
- {
76
- rb_funcall(h, id_clear, 0);
77
- }
78
- #endif /* HAVE_RB_HASH_CLEAR */
79
-
80
69
  static void finalize_header(struct http_parser *hp);
81
70
 
82
71
  static void parser_raise(VALUE klass, const char *msg)
@@ -650,7 +639,7 @@ static VALUE HttpParser_clear(VALUE self)
650
639
  return HttpParser_init(self);
651
640
 
652
641
  http_parser_init(hp);
653
- my_hash_clear(hp->env);
642
+ rb_hash_clear(hp->env);
654
643
 
655
644
  return self;
656
645
  }
@@ -979,6 +968,7 @@ void Init_unicorn_http(void)
979
968
  e414 = rb_define_class_under(mUnicorn, "RequestURITooLongError",
980
969
  eHttpParserError);
981
970
 
971
+ id_uminus = rb_intern("-@");
982
972
  init_globals();
983
973
  rb_define_alloc_func(cHttpParser, HttpParser_alloc);
984
974
  rb_define_method(cHttpParser, "initialize", HttpParser_init, 0);
@@ -1029,5 +1019,7 @@ void Init_unicorn_http(void)
1029
1019
  id_clear = rb_intern("clear");
1030
1020
  #endif
1031
1021
  id_is_chunked_p = rb_intern("is_chunked?");
1022
+
1023
+ init_epollexclusive(mUnicorn);
1032
1024
  }
1033
1025
  #undef SET_GLOBAL
@@ -62,7 +62,6 @@ class Unicorn::HttpParser
62
62
  # This does minimal exception trapping and it is up to the caller
63
63
  # to handle any socket errors (e.g. user aborted upload).
64
64
  def read(socket)
65
- clear
66
65
  e = env
67
66
 
68
67
  # From https://www.ietf.org/rfc/rfc3875:
@@ -69,7 +69,6 @@ class Unicorn::HttpServer
69
69
  # incoming requests on the socket.
70
70
  def initialize(app, options = {})
71
71
  @app = app
72
- @request = Unicorn::HttpRequest.new
73
72
  @reexec_pid = 0
74
73
  @default_middleware = true
75
74
  options = options.dup
@@ -610,7 +609,7 @@ class Unicorn::HttpServer
610
609
  def e100_response_write(client, env)
611
610
  # We use String#freeze to avoid allocations under Ruby 2.1+
612
611
  # Not many users hit this code path, so it's better to reduce the
613
- # constant table sizes even for 1.9.3-2.0 users who'll hit extra
612
+ # constant table sizes even for Ruby 2.0 users who'll hit extra
614
613
  # allocations here.
615
614
  client.write(@request.response_start_sent ?
616
615
  "100 Continue\r\n\r\nHTTP/1.1 ".freeze :
@@ -621,6 +620,7 @@ class Unicorn::HttpServer
621
620
  # once a client is accepted, it is processed in its entirety here
622
621
  # in 3 easy steps: read request, call app, write app response
623
622
  def process_client(client)
623
+ @request = Unicorn::HttpRequest.new
624
624
  env = @request.read(client)
625
625
 
626
626
  if early_hints
@@ -629,6 +629,8 @@ class Unicorn::HttpServer
629
629
  end
630
630
  end
631
631
 
632
+ env["rack.after_reply"] = []
633
+
632
634
  status, headers, body = @app.call(env)
633
635
 
634
636
  begin
@@ -651,6 +653,8 @@ class Unicorn::HttpServer
651
653
  end
652
654
  rescue => e
653
655
  handle_error(client, e)
656
+ ensure
657
+ env["rack.after_reply"].each(&:call) if env
654
658
  end
655
659
 
656
660
  def nuke_listeners!(readers)
@@ -681,7 +685,6 @@ class Unicorn::HttpServer
681
685
  LISTENERS.each { |sock| sock.close_on_exec = true }
682
686
 
683
687
  worker.user(*user) if user.kind_of?(Array) && ! worker.switched
684
- self.timeout /= 2.0 # halve it for select()
685
688
  @config = nil
686
689
  build_app! unless preload_app
687
690
  @after_fork = @listener_opts = @orig_app = nil
@@ -695,59 +698,55 @@ class Unicorn::HttpServer
695
698
  logger.info "worker=#{worker_nr} reopening logs..."
696
699
  Unicorn::Util.reopen_logs
697
700
  logger.info "worker=#{worker_nr} done reopening logs"
701
+ false
698
702
  rescue => e
699
703
  logger.error(e) rescue nil
700
704
  exit!(77) # EX_NOPERM in sysexits.h
701
705
  end
702
706
 
707
+ def prep_readers(readers)
708
+ wtr = Unicorn::Waiter.prep_readers(readers)
709
+ @timeout *= 500 # to milliseconds for epoll, but halved
710
+ wtr
711
+ rescue
712
+ require_relative 'select_waiter'
713
+ @timeout /= 2.0 # halved for IO.select
714
+ Unicorn::SelectWaiter.new
715
+ end
716
+
703
717
  # runs inside each forked worker, this sits around and waits
704
718
  # for connections and doesn't die until the parent dies (or is
705
719
  # given a INT, QUIT, or TERM signal)
706
720
  def worker_loop(worker)
707
- ppid = @master_pid
708
721
  readers = init_worker_process(worker)
709
- nr = 0 # this becomes negative if we need to reopen logs
722
+ waiter = prep_readers(readers)
723
+ reopen = false
710
724
 
711
725
  # this only works immediately if the master sent us the signal
712
726
  # (which is the normal case)
713
- trap(:USR1) { nr = -65536 }
727
+ trap(:USR1) { reopen = true }
714
728
 
715
729
  ready = readers.dup
716
- nr_listeners = readers.size
717
730
  @after_worker_ready.call(self, worker)
718
731
 
719
732
  begin
720
- nr < 0 and reopen_worker_logs(worker.nr)
721
- nr = 0
733
+ reopen = reopen_worker_logs(worker.nr) if reopen
722
734
  worker.tick = time_now.to_i
723
- tmp = ready.dup
724
- while sock = tmp.shift
735
+ while sock = ready.shift
725
736
  # Unicorn::Worker#kgio_tryaccept is not like accept(2) at all,
726
737
  # but that will return false
727
738
  if client = sock.kgio_tryaccept
728
739
  process_client(client)
729
- nr += 1
730
740
  worker.tick = time_now.to_i
731
741
  end
732
- break if nr < 0
733
- end
734
-
735
- # make the following bet: if we accepted clients this round,
736
- # we're probably reasonably busy, so avoid calling select()
737
- # and do a speculative non-blocking accept() on ready listeners
738
- # before we sleep again in select().
739
- if nr == nr_listeners
740
- tmp = ready.dup
741
- redo
742
+ break if reopen
742
743
  end
743
744
 
744
- ppid == Process.ppid or return
745
-
746
- # timeout used so we can detect parent death:
745
+ # timeout so we can .tick and keep parent from SIGKILL-ing us
747
746
  worker.tick = time_now.to_i
748
- ret = IO.select(readers, nil, nil, @timeout) and ready = ret[0]
747
+ waiter.get_readers(ready, readers, @timeout)
749
748
  rescue => e
750
- redo if nr < 0 && readers[0]
749
+ redo if reopen && readers[0]
751
750
  Unicorn.log_error(@logger, "listen loop error", e) if readers[0]
752
751
  end while readers[0]
753
752
  end
@@ -60,7 +60,6 @@ module Unicorn::OobGC
60
60
  self.const_set :OOBGC_INTERVAL, interval
61
61
  ObjectSpace.each_object(Unicorn::HttpServer) do |s|
62
62
  s.extend(self)
63
- self.const_set :OOBGC_ENV, s.instance_variable_get(:@request).env
64
63
  end
65
64
  app # pretend to be Rack middleware since it was in the past
66
65
  end
@@ -68,9 +67,10 @@ module Unicorn::OobGC
68
67
  #:stopdoc:
69
68
  def process_client(client)
70
69
  super(client) # Unicorn::HttpServer#process_client
71
- if OOBGC_PATH =~ OOBGC_ENV['PATH_INFO'] && ((@@nr -= 1) <= 0)
70
+ env = instance_variable_get(:@request).env
71
+ if OOBGC_PATH =~ env['PATH_INFO'] && ((@@nr -= 1) <= 0)
72
72
  @@nr = OOBGC_INTERVAL
73
- OOBGC_ENV.clear
73
+ env.clear
74
74
  disabled = GC.enable
75
75
  GC.start
76
76
  GC.disable if disabled
@@ -0,0 +1,6 @@
1
+ # fallback for non-Linux and Linux <4.5 systems w/o EPOLLEXCLUSIVE
2
+ class Unicorn::SelectWaiter # :nodoc:
3
+ def get_readers(ready, readers, timeout) # :nodoc:
4
+ ret = IO.select(readers, nil, nil, timeout) and ready.replace(ret[0])
5
+ end
6
+ end
@@ -1 +1 @@
1
- Unicorn::Const::UNICORN_VERSION = '5.6.0'
1
+ Unicorn::Const::UNICORN_VERSION = '6.1.0'
data/lib/unicorn.rb CHANGED
@@ -114,8 +114,6 @@ module Unicorn
114
114
 
115
115
  def self.pipe # :nodoc:
116
116
  Kgio::Pipe.new.each do |io|
117
- io.close_on_exec = true # remove this when we only support Ruby >= 2.0
118
-
119
117
  # shrink pipes to minimize impact on /proc/sys/fs/pipe-user-pages-soft
120
118
  # limits.
121
119
  if defined?(F_SETPIPE_SZ)
data/t/GNUmakefile CHANGED
@@ -1,74 +1,5 @@
1
- # we can run tests in parallel with GNU make
1
+ # there used to be more, here, but we stopped relying on recursive make
2
2
  all::
3
+ $(MAKE) -C .. test-integration
3
4
 
4
- pid := $(shell echo $$PPID)
5
-
6
- RUBY = ruby
7
- RAKE = rake
8
- -include ../local.mk
9
- ifeq ($(RUBY_VERSION),)
10
- RUBY_VERSION := $(shell $(RUBY) -e 'puts RUBY_VERSION')
11
- endif
12
-
13
- ifeq ($(RUBY_VERSION),)
14
- $(error unable to detect RUBY_VERSION)
15
- endif
16
-
17
- RUBY_ENGINE := $(shell $(RUBY) -e 'puts((RUBY_ENGINE rescue "ruby"))')
18
- export RUBY_ENGINE
19
-
20
- MYLIBS := $(RUBYLIB)
21
-
22
- T = $(wildcard t[0-9][0-9][0-9][0-9]-*.sh)
23
-
24
- all:: $(T)
25
-
26
- # can't rely on "set -o pipefail" since we don't require bash or ksh93 :<
27
- t_pfx = trash/$@-$(RUBY_ENGINE)-$(RUBY_VERSION)
28
- TEST_OPTS =
29
- # TRACER = strace -f -o $(t_pfx).strace -s 100000
30
- # TRACER = /usr/bin/time -o $(t_pfx).time
31
-
32
- ifdef V
33
- ifeq ($(V),2)
34
- TEST_OPTS += --trace
35
- else
36
- TEST_OPTS += --verbose
37
- endif
38
- endif
39
-
40
- random_blob:
41
- dd if=/dev/urandom bs=1M count=30 of=$@.$(pid)
42
- mv $@.$(pid) $@
43
-
44
- $(T): random_blob
45
-
46
- dependencies := socat curl
47
- deps := $(addprefix .dep+,$(dependencies))
48
- $(deps): dep_bin = $(lastword $(subst +, ,$@))
49
- $(deps):
50
- @which $(dep_bin) > $@.$(pid) 2>/dev/null || :
51
- @test -s $@.$(pid) || \
52
- { echo >&2 "E '$(dep_bin)' not found in PATH=$(PATH)"; exit 1; }
53
- @mv $@.$(pid) $@
54
- dep: $(deps)
55
-
56
- test_prefix := $(CURDIR)/../test/$(RUBY_ENGINE)-$(RUBY_VERSION)
57
- $(test_prefix)/.stamp:
58
- $(MAKE) -C .. test-install
59
-
60
- $(T): export RUBY := $(RUBY)
61
- $(T): export RAKE := $(RAKE)
62
- $(T): export PATH := $(test_prefix)/bin:$(PATH)
63
- $(T): export RUBYLIB := $(test_prefix)/lib:$(MYLIBS)
64
- $(T): dep $(test_prefix)/.stamp trash/.gitignore
65
- $(TRACER) $(SHELL) $(SH_TEST_OPTS) $@ $(TEST_OPTS)
66
-
67
- trash/.gitignore:
68
- mkdir -p $(@D)
69
- echo '*' > $@
70
-
71
- clean:
72
- $(RM) -r trash/*
73
-
74
- .PHONY: $(T) clean
5
+ .PHONY: all
data/t/README CHANGED
@@ -10,7 +10,7 @@ comfortable writing integration tests with.
10
10
 
11
11
  == Requirements
12
12
 
13
- * {Ruby 1.9.3+}[https://www.ruby-lang.org/en/] (duh!)
13
+ * {Ruby 2.0.0+}[https://www.ruby-lang.org/en/] (duh!)
14
14
  * {GNU make}[https://www.gnu.org/software/make/]
15
15
  * {socat}[http://www.dest-unreach.org/socat/]
16
16
  * {curl}[https://curl.haxx.se/]
data/t/test-lib.sh CHANGED
@@ -94,7 +94,8 @@ check_stderr () {
94
94
  set +u
95
95
  _r_err=${1-${r_err}}
96
96
  set -u
97
- if grep -v $T $_r_err | grep -i Error
97
+ if grep -v $T $_r_err | grep -i Error | \
98
+ grep -v NameError.*Unicorn::Waiter
98
99
  then
99
100
  die "Errors found in $_r_err"
100
101
  elif grep SIGKILL $_r_err
@@ -574,7 +574,7 @@ EOF
574
574
  assert_equal String, results[0].class
575
575
  worker_pid = results[0].to_i
576
576
  assert_not_equal pid, worker_pid
577
- s = UNIXSocket.new(tmp.path)
577
+ s = unix_socket(tmp.path)
578
578
  s.syswrite("GET / HTTP/1.0\r\n\r\n")
579
579
  results = ''
580
580
  loop { results << s.sysread(4096) } rescue nil
@@ -732,7 +732,7 @@ EOF
732
732
  wait_for_file(sock_path)
733
733
  assert File.socket?(sock_path)
734
734
 
735
- sock = UNIXSocket.new(sock_path)
735
+ sock = unix_socket(sock_path)
736
736
  sock.syswrite("GET / HTTP/1.0\r\n\r\n")
737
737
  results = sock.sysread(4096)
738
738
 
@@ -742,7 +742,7 @@ EOF
742
742
  wait_for_file(sock_path)
743
743
  assert File.socket?(sock_path)
744
744
 
745
- sock = UNIXSocket.new(sock_path)
745
+ sock = unix_socket(sock_path)
746
746
  sock.syswrite("GET / HTTP/1.0\r\n\r\n")
747
747
  results = sock.sysread(4096)
748
748
 
@@ -777,7 +777,7 @@ EOF
777
777
  assert_equal pid, File.read(pid_file).to_i
778
778
  assert File.socket?(sock_path), "socket created"
779
779
 
780
- sock = UNIXSocket.new(sock_path)
780
+ sock = unix_socket(sock_path)
781
781
  sock.syswrite("GET / HTTP/1.0\r\n\r\n")
782
782
  results = sock.sysread(4096)
783
783
 
@@ -803,7 +803,7 @@ EOF
803
803
  wait_for_file(new_sock_path)
804
804
  assert File.socket?(new_sock_path), "socket exists"
805
805
  @sockets.each do |path|
806
- sock = UNIXSocket.new(path)
806
+ sock = unix_socket(path)
807
807
  sock.syswrite("GET / HTTP/1.0\r\n\r\n")
808
808
  results = sock.sysread(4096)
809
809
  assert_equal String, results.class
data/test/test_helper.rb CHANGED
@@ -28,22 +28,43 @@ require 'tempfile'
28
28
  require 'fileutils'
29
29
  require 'logger'
30
30
  require 'unicorn'
31
+ require 'io/nonblock'
31
32
 
32
33
  if ENV['DEBUG']
33
34
  require 'ruby-debug'
34
35
  Debugger.start
35
36
  end
36
37
 
38
+ unless RUBY_VERSION < '3.1'
39
+ warn "Unicorn was only tested against MRI up to 3.0.\n" \
40
+ "It might not properly work with #{RUBY_VERSION}"
41
+ end
42
+
37
43
  def redirect_test_io
38
44
  orig_err = STDERR.dup
39
45
  orig_out = STDOUT.dup
40
- STDERR.reopen("test_stderr.#{$$}.log", "a")
41
- STDOUT.reopen("test_stdout.#{$$}.log", "a")
46
+ rdr_pid = $$
47
+ new_out = File.open("test_stdout.#$$.log", "a")
48
+ new_err = File.open("test_stderr.#$$.log", "a")
49
+ new_out.sync = new_err.sync = true
50
+
51
+ if tail = ENV['TAIL'] # "tail -F" if GNU, "tail -f" otherwise
52
+ require 'shellwords'
53
+ cmd = tail.shellsplit
54
+ cmd << new_out.path
55
+ cmd << new_err.path
56
+ pid = Process.spawn(*cmd, { 1 => 2, :pgroup => true })
57
+ sleep 0.1 # wait for tail(1) to startup
58
+ end
59
+ STDERR.reopen(new_err)
60
+ STDOUT.reopen(new_out)
42
61
  STDERR.sync = STDOUT.sync = true
43
62
 
44
63
  at_exit do
45
- File.unlink("test_stderr.#{$$}.log") rescue nil
46
- File.unlink("test_stdout.#{$$}.log") rescue nil
64
+ if rdr_pid == $$
65
+ File.unlink(new_out.path) rescue nil
66
+ File.unlink(new_err.path) rescue nil
67
+ end
47
68
  end
48
69
 
49
70
  begin
@@ -51,6 +72,7 @@ def redirect_test_io
51
72
  ensure
52
73
  STDERR.reopen(orig_err)
53
74
  STDOUT.reopen(orig_out)
75
+ Process.kill(:TERM, pid) if pid
54
76
  end
55
77
  end
56
78
 
@@ -270,3 +292,15 @@ def reset_sig_handlers
270
292
  trap(sig, "DEFAULT")
271
293
  end
272
294
  end
295
+
296
+ def tcp_socket(*args)
297
+ sock = TCPSocket.new(*args)
298
+ sock.nonblock = false
299
+ sock
300
+ end
301
+
302
+ def unix_socket(*args)
303
+ sock = UNIXSocket.new(*args)
304
+ sock.nonblock = false
305
+ sock
306
+ end
@@ -3,6 +3,7 @@ require 'unicorn'
3
3
  require 'io/wait'
4
4
  require 'tempfile'
5
5
  require 'test/unit'
6
+ require './test/test_helper'
6
7
 
7
8
  class TestCccTCPI < Test::Unit::TestCase
8
9
  def test_ccc_tcpi
@@ -42,7 +43,7 @@ class TestCccTCPI < Test::Unit::TestCase
42
43
  wr.close
43
44
 
44
45
  # make sure the server is running, at least
45
- client = TCPSocket.new(host, port)
46
+ client = tcp_socket(host, port)
46
47
  client.write("GET / HTTP/1.1\r\nHost: example.com\r\n\r\n")
47
48
  assert client.wait(10), 'never got response from server'
48
49
  res = client.read
@@ -51,13 +52,13 @@ class TestCccTCPI < Test::Unit::TestCase
51
52
  client.close
52
53
 
53
54
  # start a slow request...
54
- sleeper = TCPSocket.new(host, port)
55
+ sleeper = tcp_socket(host, port)
55
56
  sleeper.write("GET /sleep HTTP/1.1\r\nHost: example.com\r\n\r\n")
56
57
 
57
58
  # and a bunch of aborted ones
58
59
  nr = 100
59
60
  nr.times do |i|
60
- client = TCPSocket.new(host, port)
61
+ client = tcp_socket(host, port)
61
62
  client.write("GET /collections/#{rand(10000)} HTTP/1.1\r\n" \
62
63
  "Host: example.com\r\n\r\n")
63
64
  client.close
@@ -34,6 +34,24 @@ class TestEarlyHintsHandler
34
34
  end
35
35
  end
36
36
 
37
+ class TestRackAfterReply
38
+ def initialize
39
+ @called = false
40
+ end
41
+
42
+ def call(env)
43
+ while env['rack.input'].read(4096)
44
+ end
45
+
46
+ env["rack.after_reply"] << -> { @called = true }
47
+
48
+ [200, { 'Content-Type' => 'text/plain' }, ["after_reply_called: #{@called}"]]
49
+ rescue Unicorn::ClientShutdown, Unicorn::HttpParserError => e
50
+ $stderr.syswrite("#{e.class}: #{e.message} #{e.backtrace.empty?}\n")
51
+ raise e
52
+ end
53
+ end
54
+
37
55
  class WebServerTest < Test::Unit::TestCase
38
56
 
39
57
  def setup
@@ -103,7 +121,7 @@ class WebServerTest < Test::Unit::TestCase
103
121
  @server.start
104
122
  end
105
123
 
106
- sock = TCPSocket.new('127.0.0.1', @port)
124
+ sock = tcp_socket('127.0.0.1', @port)
107
125
  sock.syswrite("GET / HTTP/1.0\r\n\r\n")
108
126
 
109
127
  responses = sock.read(4096)
@@ -114,6 +132,32 @@ class WebServerTest < Test::Unit::TestCase
114
132
  assert_match %r{^HTTP/1.[01] 200\b}, responses
115
133
  end
116
134
 
135
+ def test_after_reply
136
+ teardown
137
+
138
+ redirect_test_io do
139
+ @server = HttpServer.new(TestRackAfterReply.new,
140
+ :listeners => [ "127.0.0.1:#@port"])
141
+ @server.start
142
+ end
143
+
144
+ sock = tcp_socket('127.0.0.1', @port)
145
+ sock.syswrite("GET / HTTP/1.0\r\n\r\n")
146
+
147
+ responses = sock.read(4096)
148
+ assert_match %r{\AHTTP/1.[01] 200\b}, responses
149
+ assert_match %r{^after_reply_called: false}, responses
150
+
151
+ sock = tcp_socket('127.0.0.1', @port)
152
+ sock.syswrite("GET / HTTP/1.0\r\n\r\n")
153
+
154
+ responses = sock.read(4096)
155
+ assert_match %r{\AHTTP/1.[01] 200\b}, responses
156
+ assert_match %r{^after_reply_called: true}, responses
157
+
158
+ sock.close
159
+ end
160
+
117
161
  def test_broken_app
118
162
  teardown
119
163
  app = lambda { |env| raise RuntimeError, "hello" }
@@ -122,7 +166,7 @@ class WebServerTest < Test::Unit::TestCase
122
166
  @server = HttpServer.new(app, :listeners => [ "127.0.0.1:#@port"] )
123
167
  @server.start
124
168
  end
125
- sock = TCPSocket.new('127.0.0.1', @port)
169
+ sock = tcp_socket('127.0.0.1', @port)
126
170
  sock.syswrite("GET / HTTP/1.0\r\n\r\n")
127
171
  assert_match %r{\AHTTP/1.[01] 500\b}, sock.sysread(4096)
128
172
  assert_nil sock.close
@@ -135,7 +179,7 @@ class WebServerTest < Test::Unit::TestCase
135
179
 
136
180
  def test_client_shutdown_writes
137
181
  bs = 15609315 * rand
138
- sock = TCPSocket.new('127.0.0.1', @port)
182
+ sock = tcp_socket('127.0.0.1', @port)
139
183
  sock.syswrite("PUT /hello HTTP/1.1\r\n")
140
184
  sock.syswrite("Host: example.com\r\n")
141
185
  sock.syswrite("Transfer-Encoding: chunked\r\n")
@@ -162,7 +206,7 @@ class WebServerTest < Test::Unit::TestCase
162
206
 
163
207
  def test_client_shutdown_write_truncates
164
208
  bs = 15609315 * rand
165
- sock = TCPSocket.new('127.0.0.1', @port)
209
+ sock = tcp_socket('127.0.0.1', @port)
166
210
  sock.syswrite("PUT /hello HTTP/1.1\r\n")
167
211
  sock.syswrite("Host: example.com\r\n")
168
212
  sock.syswrite("Transfer-Encoding: chunked\r\n")
@@ -188,7 +232,7 @@ class WebServerTest < Test::Unit::TestCase
188
232
 
189
233
  def test_client_malformed_body
190
234
  bs = 15653984
191
- sock = TCPSocket.new('127.0.0.1', @port)
235
+ sock = tcp_socket('127.0.0.1', @port)
192
236
  sock.syswrite("PUT /hello HTTP/1.1\r\n")
193
237
  sock.syswrite("Host: example.com\r\n")
194
238
  sock.syswrite("Transfer-Encoding: chunked\r\n")
@@ -210,7 +254,7 @@ class WebServerTest < Test::Unit::TestCase
210
254
 
211
255
  def do_test(string, chunk, close_after=nil, shutdown_delay=0)
212
256
  # Do not use instance variables here, because it needs to be thread safe
213
- socket = TCPSocket.new("127.0.0.1", @port);
257
+ socket = tcp_socket("127.0.0.1", @port);
214
258
  request = StringIO.new(string)
215
259
  chunks_out = 0
216
260
 
@@ -255,14 +299,14 @@ class WebServerTest < Test::Unit::TestCase
255
299
  end
256
300
 
257
301
  def test_bad_client_400
258
- sock = TCPSocket.new('127.0.0.1', @port)
302
+ sock = tcp_socket('127.0.0.1', @port)
259
303
  sock.syswrite("GET / HTTP/1.0\r\nHost: foo\rbar\r\n\r\n")
260
304
  assert_match %r{\AHTTP/1.[01] 400\b}, sock.sysread(4096)
261
305
  assert_nil sock.close
262
306
  end
263
307
 
264
308
  def test_http_0_9
265
- sock = TCPSocket.new('127.0.0.1', @port)
309
+ sock = tcp_socket('127.0.0.1', @port)
266
310
  sock.syswrite("GET /hello\r\n")
267
311
  assert_match 'hello!\n', sock.sysread(4096)
268
312
  assert_nil sock.close
@@ -52,7 +52,7 @@ class SignalsTest < Test::Unit::TestCase
52
52
  redirect_test_io { HttpServer.new(app, opts).start.join }
53
53
  }
54
54
  wait_workers_ready("test_stderr.#{pid}.log", 1)
55
- sock = TCPSocket.new('127.0.0.1', @port)
55
+ sock = tcp_socket('127.0.0.1', @port)
56
56
  sock.syswrite("GET / HTTP/1.0\r\n\r\n")
57
57
  buf = sock.readpartial(4096)
58
58
  assert_nil sock.close
@@ -79,7 +79,7 @@ class SignalsTest < Test::Unit::TestCase
79
79
  }
80
80
  wr.close
81
81
  wait_workers_ready("test_stderr.#{pid}.log", 1)
82
- sock = TCPSocket.new('127.0.0.1', @port)
82
+ sock = tcp_socket('127.0.0.1', @port)
83
83
  sock.syswrite("GET / HTTP/1.0\r\n\r\n")
84
84
  buf = rd.readpartial(1)
85
85
  wait_master_ready("test_stderr.#{pid}.log")
@@ -102,7 +102,7 @@ class SignalsTest < Test::Unit::TestCase
102
102
  }
103
103
  t0 = Time.now
104
104
  wait_workers_ready("test_stderr.#{pid}.log", 1)
105
- sock = TCPSocket.new('127.0.0.1', @port)
105
+ sock = tcp_socket('127.0.0.1', @port)
106
106
  sock.syswrite("GET / HTTP/1.0\r\n\r\n")
107
107
 
108
108
  buf = nil
@@ -125,7 +125,7 @@ class SignalsTest < Test::Unit::TestCase
125
125
  }
126
126
  redirect_test_io { @server = HttpServer.new(app, @server_opts).start }
127
127
  wait_workers_ready("test_stderr.#{$$}.log", 1)
128
- sock = TCPSocket.new('127.0.0.1', @port)
128
+ sock = tcp_socket('127.0.0.1', @port)
129
129
  sock.syswrite("GET / HTTP/1.0\r\n\r\n")
130
130
  buf = ''
131
131
  header_len = pid = nil
@@ -163,13 +163,13 @@ class SignalsTest < Test::Unit::TestCase
163
163
  redirect_test_io { @server = HttpServer.new(app, @server_opts).start }
164
164
 
165
165
  wait_workers_ready("test_stderr.#{$$}.log", 1)
166
- sock = TCPSocket.new('127.0.0.1', @port)
166
+ sock = tcp_socket('127.0.0.1', @port)
167
167
  sock.syswrite("GET / HTTP/1.0\r\n\r\n")
168
168
  pid = sock.sysread(4096)[/\r\nX-Pid: (\d+)\r\n/, 1].to_i
169
169
  assert_nil sock.close
170
170
 
171
171
  assert pid > 0, "pid not positive: #{pid.inspect}"
172
- sock = TCPSocket.new('127.0.0.1', @port)
172
+ sock = tcp_socket('127.0.0.1', @port)
173
173
  sock.syswrite("PUT / HTTP/1.0\r\n")
174
174
  sock.syswrite("Content-Length: #{@bs * @count}\r\n\r\n")
175
175
  1000.times { Process.kill(:HUP, pid) }
@@ -116,7 +116,7 @@ class TestSocketHelper < Test::Unit::TestCase
116
116
  client.syswrite('abcde')
117
117
  exit 0
118
118
  end
119
- s = UNIXSocket.new(@unix_listener_path)
119
+ s = unix_socket(@unix_listener_path)
120
120
  IO.select([s])
121
121
  assert_equal 'abcde', s.sysread(5)
122
122
  pid, status = Process.waitpid2(pid)