rainbows 4.7.0 → 5.0.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.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/.gitattributes +5 -0
  3. data/GIT-VERSION-GEN +1 -1
  4. data/README +5 -9
  5. data/bin/rainbows +3 -3
  6. data/lib/rainbows.rb +18 -6
  7. data/lib/rainbows/configurator.rb +8 -8
  8. data/lib/rainbows/const.rb +0 -3
  9. data/lib/rainbows/coolio.rb +2 -7
  10. data/lib/rainbows/coolio/client.rb +6 -6
  11. data/lib/rainbows/coolio/heartbeat.rb +2 -2
  12. data/lib/rainbows/coolio/thread_client.rb +3 -3
  13. data/lib/rainbows/dev_fd_response.rb +8 -14
  14. data/lib/rainbows/epoll/client.rb +9 -10
  15. data/lib/rainbows/error.rb +2 -2
  16. data/lib/rainbows/ev_core.rb +11 -17
  17. data/lib/rainbows/event_machine/client.rb +7 -7
  18. data/lib/rainbows/event_machine/try_defer.rb +1 -4
  19. data/lib/rainbows/fiber.rb +1 -1
  20. data/lib/rainbows/fiber/base.rb +3 -3
  21. data/lib/rainbows/fiber/coolio/heartbeat.rb +1 -1
  22. data/lib/rainbows/fiber/io.rb +1 -1
  23. data/lib/rainbows/http_parser.rb +24 -0
  24. data/lib/rainbows/http_server.rb +5 -4
  25. data/lib/rainbows/join_threads.rb +2 -2
  26. data/lib/rainbows/max_body.rb +4 -9
  27. data/lib/rainbows/process_client.rb +11 -12
  28. data/lib/rainbows/response.rb +20 -37
  29. data/lib/rainbows/revactor.rb +0 -1
  30. data/lib/rainbows/revactor/client.rb +2 -3
  31. data/lib/rainbows/revactor/proxy.rb +1 -1
  32. data/lib/rainbows/reverse_proxy.rb +9 -19
  33. data/lib/rainbows/reverse_proxy/coolio.rb +3 -3
  34. data/lib/rainbows/reverse_proxy/ev_client.rb +2 -5
  35. data/lib/rainbows/reverse_proxy/event_machine.rb +1 -1
  36. data/lib/rainbows/sendfile.rb +3 -9
  37. data/lib/rainbows/server_token.rb +1 -6
  38. data/lib/rainbows/stream_response_epoll.rb +8 -9
  39. data/lib/rainbows/thread_timeout.rb +4 -4
  40. data/lib/rainbows/writer_thread_pool.rb +2 -2
  41. data/lib/rainbows/xepoll_thread_pool/client.rb +3 -4
  42. data/lib/rainbows/xepoll_thread_spawn/client.rb +3 -4
  43. data/rainbows.gemspec +1 -1
  44. data/t/t0105-rack-input-limit-bigger.sh +10 -2
  45. data/t/test_isolate.rb +1 -1
  46. metadata +5 -4
@@ -32,20 +32,20 @@ def on_readable
32
32
  when :wait_readable
33
33
  return
34
34
  when nil
35
- @env[AsyncCallback].call(@response)
35
+ @env['async.callback'].call(@response)
36
36
  return close
37
37
  end while true # we always read until EAGAIN or EOF
38
38
 
39
39
  rescue => e
40
40
  case e
41
41
  when Errno::ECONNRESET
42
- @env[AsyncCallback].call(@response)
42
+ @env['async.callback'].call(@response)
43
43
  return close
44
44
  when SystemCallError
45
45
  else
46
46
  Unicorn.log_error(@env["rack.logger"], "on_readable", e)
47
47
  end
48
- @env[AsyncCallback].call(Rainbows::ReverseProxy::E502)
48
+ @env['async.callback'].call(Rainbows::ReverseProxy::E502)
49
49
  close
50
50
  end
51
51
  end
@@ -3,18 +3,15 @@
3
3
  require 'tempfile'
4
4
  module Rainbows::ReverseProxy::EvClient
5
5
  include Rainbows::ReverseProxy::Synchronous
6
- AsyncCallback = "async.callback"
7
6
  CBB = Unicorn::TeeInput.client_body_buffer_size
8
- Content_Length = "Content-Length"
9
- Transfer_Encoding = "Transfer-Encoding"
10
7
 
11
8
  def receive_data(buf)
12
9
  if @body
13
10
  @body << buf
14
11
  else
15
12
  response = @parser.headers(@headers, @rbuf << buf) or return
16
- if (cl = @headers[Content_Length] && cl.to_i > CBB) ||
17
- (%r{\bchunked\b} =~ @headers[Transfer_Encoding])
13
+ if (cl = @headers['Content-Length'.freeze] && cl.to_i > CBB) ||
14
+ (%r{\bchunked\b} =~ @headers['Transfer-Encoding'.freeze])
18
15
  @body = LargeBody.new("")
19
16
  @body << @rbuf
20
17
  @response = response << @body
@@ -30,7 +30,7 @@ def on_write_complete
30
30
  end
31
31
 
32
32
  def unbind
33
- @env[AsyncCallback].call(@response || Rainbows::ReverseProxy::E502)
33
+ @env['async.callback'].call(@response || Rainbows::ReverseProxy::E502)
34
34
  end
35
35
  end
36
36
 
@@ -52,12 +52,10 @@ class Rainbows::Sendfile < Struct.new(:app)
52
52
  # +each+ in case a given concurrency model does not optimize
53
53
  # +to_path+ calls.
54
54
  class Body < Struct.new(:to_path) # :nodoc: all
55
- CONTENT_LENGTH = 'Content-Length'.freeze
56
-
57
55
  def self.new(path, headers)
58
- unless headers[CONTENT_LENGTH]
56
+ unless headers['Content-Length'.freeze]
59
57
  stat = File.stat(path)
60
- headers[CONTENT_LENGTH] = stat.size.to_s if stat.file?
58
+ headers['Content-Length'.freeze] = stat.size.to_s if stat.file?
61
59
  end
62
60
  super(path)
63
61
  end
@@ -71,14 +69,10 @@ def each
71
69
  end
72
70
  end
73
71
 
74
- # :stopdoc:
75
- X_SENDFILE = 'X-Sendfile'
76
- # :startdoc:
77
-
78
72
  def call(env) # :nodoc:
79
73
  status, headers, body = app.call(env)
80
74
  headers = Rack::Utils::HeaderHash.new(headers) unless Hash === headers
81
- if path = headers.delete(X_SENDFILE)
75
+ if path = headers.delete('X-Sendfile'.freeze)
82
76
  body = Body.new(path, headers) unless body.respond_to?(:to_path)
83
77
  end
84
78
  [ status, headers, body ]
@@ -19,11 +19,6 @@ module Rainbows
19
19
 
20
20
  class ServerToken < Struct.new(:app, :token)
21
21
 
22
- # :stopdoc:
23
- #
24
- # Freeze constants as they're slightly faster when setting hashes
25
- SERVER = "Server".freeze
26
-
27
22
  def initialize(app, token = Const::RACK_DEFAULTS['SERVER_SOFTWARE'])
28
23
  super
29
24
  end
@@ -31,7 +26,7 @@ def initialize(app, token = Const::RACK_DEFAULTS['SERVER_SOFTWARE'])
31
26
  def call(env)
32
27
  status, headers, body = app.call(env)
33
28
  headers = Rack::Utils::HeaderHash.new(headers) unless Hash === headers
34
- headers[SERVER] = token
29
+ headers['Server'.freeze] = token
35
30
  [ status, headers, body ]
36
31
  end
37
32
  # :startdoc:
@@ -20,33 +20,32 @@
20
20
  # * sleepy_penguin 3.0.1 or later
21
21
  module Rainbows::StreamResponseEpoll
22
22
  # :stopdoc:
23
- CODES = Unicorn::HttpResponse::CODES
24
- HEADER_END = "X-Accel-Buffering: no\r\n\r\n"
25
23
  autoload :Client, "rainbows/stream_response_epoll/client"
26
24
 
27
25
  def http_response_write(socket, status, headers, body)
28
- status = CODES[status.to_i] || status
29
26
  hijack = ep_client = false
30
27
 
31
28
  if headers
32
29
  # don't set extra headers here, this is only intended for
33
30
  # consuming by nginx.
34
- buf = "HTTP/1.0 #{status}\r\nStatus: #{status}\r\n"
31
+ code = status.to_i
32
+ msg = Rack::Utils::HTTP_STATUS_CODES[code]
33
+ buf = "HTTP/1.0 #{msg ? %Q(#{code} #{msg}) : status}\r\n"
35
34
  headers.each do |key, value|
36
35
  case key
37
36
  when "rack.hijack"
38
- hijack = hijack_prepare(value)
37
+ hijack = value
39
38
  body = nil # ensure we do not close body
40
39
  else
41
40
  if /\n/ =~ value
42
41
  # avoiding blank, key-only cookies with /\n+/
43
- buf << value.split(/\n+/).map! { |v| "#{key}: #{v}\r\n" }.join
42
+ value.split(/\n+/).each { |v| buf << "#{key}: #{v}\r\n" }
44
43
  else
45
44
  buf << "#{key}: #{value}\r\n"
46
45
  end
47
46
  end
48
47
  end
49
- buf << HEADER_END
48
+ buf << "X-Accel-Buffering: no\r\n\r\n".freeze
50
49
 
51
50
  case rv = socket.kgio_trywrite(buf)
52
51
  when nil then break
@@ -101,8 +100,8 @@ def process_client(client)
101
100
  status, headers, body = @app.call(env = @request.read(client))
102
101
 
103
102
  if 100 == status.to_i
104
- client.write(Unicorn::Const::EXPECT_100_RESPONSE)
105
- env.delete(Unicorn::Const::HTTP_EXPECT)
103
+ client.write("HTTP/1.1 100 Continue\r\n\r\n".freeze)
104
+ env.delete('HTTP_EXPECT'.freeze)
106
105
  status, headers, body = @app.call(env)
107
106
  end
108
107
  @request.headers? or headers = nil
@@ -63,7 +63,7 @@ class Rainbows::ThreadTimeout
63
63
 
64
64
  # The MRI 1.8 won't be usable in January 2038, we'll raise this
65
65
  # when we eventually drop support for 1.8 (before 2038, hopefully)
66
- NEVER = Time.at(0x7fffffff)
66
+ NEVER = 0x7fffffff
67
67
 
68
68
  def initialize(app, opts)
69
69
  # @timeout must be Numeric since we add this to Time
@@ -114,7 +114,7 @@ def call(env)
114
114
  # is hopeless and we might as well just die anyways.
115
115
  # initialize guarantees @timeout will be Numeric
116
116
  start_watchdog(env) unless @watchdog
117
- @active[Thread.current] = Time.now + @timeout
117
+ @active[Thread.current] = Rainbows.now + @timeout
118
118
 
119
119
  begin
120
120
  # It is important to unlock inside this begin block
@@ -162,7 +162,7 @@ def start_watchdog(env)
162
162
  # that are about to release themselves from the eye of the
163
163
  # watchdog thread.
164
164
  @lock.synchronize do
165
- now = Time.now
165
+ now = Rainbows.now
166
166
  @active.delete_if do |thread, expire_at|
167
167
  # We also use this loop to get the maximum possible time to
168
168
  # sleep for if we're not killing the thread.
@@ -184,7 +184,7 @@ def start_watchdog(env)
184
184
  sleep(@timeout)
185
185
  else
186
186
  # sleep until the next known thread is about to expire.
187
- sec = next_expiry - Time.now
187
+ sec = next_expiry - Rainbows.now
188
188
  sec > 0.0 ? sleep(sec) : Thread.pass # give other threads a chance
189
189
  end
190
190
  rescue => e
@@ -50,9 +50,9 @@ def worker_loop(worker) # :nodoc:
50
50
  end
51
51
  end
52
52
 
53
- @@q = qp.map { |q| q.queue }
53
+ @@q = qp.map(&:queue)
54
54
  super(worker) # accept loop from Unicorn
55
- qp.each { |q| q.quit! }
55
+ qp.each(&:quit!)
56
56
  end
57
57
  # :startdoc:
58
58
  end
@@ -38,15 +38,14 @@ def self.app_run(queue)
38
38
  ep = SleepyPenguin::Epoll
39
39
  EP = ep.new
40
40
  IN = ep::IN | ep::ONESHOT
41
- KATO = {}
42
- KATO.compare_by_identity if KATO.respond_to?(:compare_by_identity)
41
+ KATO = {}.compare_by_identity
43
42
  LOCK = Mutex.new
44
43
  Rainbows.at_quit do
45
44
  clients = nil
46
45
  LOCK.synchronize { clients = KATO.keys; KATO.clear }
47
46
  clients.each { |io| io.closed? or io.close }
48
47
  end
49
- @@last_expire = Time.now
48
+ @@last_expire = Rainbows.now
50
49
 
51
50
  def kato_set
52
51
  LOCK.synchronize { KATO[self] = @@last_expire }
@@ -70,7 +69,7 @@ def self.loop
70
69
  end
71
70
 
72
71
  def self.expire
73
- return if ((now = Time.now) - @@last_expire) < 1.0
72
+ return if ((now = Rainbows.now) - @@last_expire) < 1.0
74
73
  if (ot = KEEPALIVE_TIMEOUT) >= 0
75
74
  ot = now - ot
76
75
  defer = []
@@ -27,15 +27,14 @@ def self.included(klass) # included in Rainbows::Client
27
27
  ep = SleepyPenguin::Epoll
28
28
  EP = ep.new
29
29
  IN = ep::IN | ep::ONESHOT
30
- KATO = {}
31
- KATO.compare_by_identity if KATO.respond_to?(:compare_by_identity)
30
+ KATO = {}.compare_by_identity
32
31
  LOCK = Mutex.new
33
32
  Rainbows.at_quit do
34
33
  clients = nil
35
34
  LOCK.synchronize { clients = KATO.keys; KATO.clear }
36
35
  clients.each { |io| io.closed? or io.shutdown }
37
36
  end
38
- @@last_expire = Time.now
37
+ @@last_expire = Rainbows.now
39
38
 
40
39
  def kato_set
41
40
  LOCK.synchronize { KATO[self] = @@last_expire }
@@ -59,7 +58,7 @@ def self.loop
59
58
  end
60
59
 
61
60
  def self.expire
62
- return if ((now = Time.now) - @@last_expire) < 1.0
61
+ return if ((now = Rainbows.now) - @@last_expire) < 1.0
63
62
  if (ot = KEEPALIVE_TIMEOUT) >= 0
64
63
  ot = now - ot
65
64
  defer = []
@@ -27,7 +27,7 @@
27
27
  # we need unicorn for the HTTP parser and process management
28
28
  # we need unicorn 4.8.0+ since we depend on undocumented/unsupported
29
29
  # unicorn internals.
30
- s.add_dependency(%q<unicorn>, ["~> 4.8"])
30
+ s.add_dependency(%q<unicorn>, ["~> 5.0"])
31
31
 
32
32
  s.add_development_dependency(%q<isolate>, "~> 3.1")
33
33
  s.add_development_dependency(%q<olddoc>, "~> 1.0")
@@ -25,7 +25,11 @@ t_begin "stops a regular request" && {
25
25
  rm -f $tmp
26
26
  dbgcat curl_err
27
27
  dbgcat curl_out
28
- grep 413 $curl_err
28
+ if ! grep 413 $curl_err
29
+ then
30
+ # send error as documented in curl(1) manpage
31
+ grep -F '(55)' $curl_err
32
+ fi
29
33
  test -e $ok
30
34
  }
31
35
 
@@ -36,7 +40,11 @@ t_begin "stops a large chunked request" && {
36
40
  http://$listen/ > $curl_out 2> $curl_err || > $ok
37
41
  dbgcat curl_err
38
42
  dbgcat curl_out
39
- grep 413 $curl_err
43
+ if ! grep 413 $curl_err
44
+ then
45
+ # send error as documented in curl(1) manpage
46
+ grep -F '(55)' $curl_err
47
+ fi
40
48
  test -e $ok
41
49
  }
42
50
 
@@ -20,7 +20,7 @@
20
20
  gem 'rack', '1.6.4'
21
21
  gem 'kcar', '0.5.0'
22
22
  gem 'raindrops', '0.13.0'
23
- gem 'unicorn', '4.9.0'
23
+ gem 'unicorn', '5.0.1'
24
24
 
25
25
  if engine == "ruby"
26
26
  gem 'sendfile', '1.2.2'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rainbows
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.7.0
4
+ version: 5.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rainbows! hackers
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-10-19 00:00:00.000000000 Z
11
+ date: 2015-11-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -44,14 +44,14 @@ dependencies:
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '4.8'
47
+ version: '5.0'
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '4.8'
54
+ version: '5.0'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: isolate
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -139,6 +139,7 @@ extra_rdoc_files:
139
139
  - HACKING
140
140
  files:
141
141
  - ".document"
142
+ - ".gitattributes"
142
143
  - ".gitignore"
143
144
  - ".manifest"
144
145
  - ".olddoc.yml"