puma 2.0.0.b4-java → 2.0.0.b7-java

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of puma might be problematic. Click here for more details.

@@ -36,14 +36,22 @@ module Puma
36
36
  @timeout_at = nil
37
37
 
38
38
  @requests_served = 0
39
+ @hijacked = false
39
40
  end
40
41
 
41
- attr_reader :env, :to_io, :body, :io, :timeout_at, :ready
42
+ attr_reader :env, :to_io, :body, :io, :timeout_at, :ready, :hijacked
42
43
 
43
44
  def inspect
44
45
  "#<Puma::Client:0x#{object_id.to_s(16)} @ready=#{@ready.inspect}>"
45
46
  end
46
47
 
48
+ # For the hijack protocol (allows us to just put the Client object
49
+ # into the env)
50
+ def call
51
+ @hijacked = true
52
+ env[HIJACK_IO] ||= @io
53
+ end
54
+
47
55
  def set_timeout(val)
48
56
  @timeout_at = Time.now + val
49
57
  end
@@ -1,4 +1,14 @@
1
1
  module Puma
2
+
3
+ # The CLI exports it's Configuration object here to allow
4
+ # apps to pick it up. An app needs to use it conditionally though
5
+ # since it is not set if the app is launched via another
6
+ # mechanism than the CLI class.
7
+
8
+ class << self
9
+ attr_accessor :cli_config
10
+ end
11
+
2
12
  class Configuration
3
13
  DefaultRackup = "config.ru"
4
14
 
@@ -44,26 +54,39 @@ module Puma
44
54
  end
45
55
  end
46
56
 
57
+ # Injects the Configuration object into the env
58
+ class ConfigMiddleware
59
+ def initialize(config, app)
60
+ @config = config
61
+ @app = app
62
+ end
63
+
64
+ def call(env)
65
+ env[Const::PUMA_CONFIG] = @config
66
+ @app.call(env)
67
+ end
68
+ end
69
+
47
70
  # Load the specified rackup file, pull an options from
48
71
  # the rackup file, and set @app.
49
72
  #
50
73
  def app
51
- if app = @options[:app]
52
- return app
53
- end
74
+ app = @options[:app]
54
75
 
55
- path = @options[:rackup] || DefaultRackup
76
+ unless app
77
+ path = @options[:rackup] || DefaultRackup
56
78
 
57
- unless File.exists?(path)
58
- raise "Missing rackup file '#{path}'"
59
- end
79
+ unless File.exists?(path)
80
+ raise "Missing rackup file '#{path}'"
81
+ end
60
82
 
61
- app, options = Rack::Builder.parse_file path
62
- @options.merge! options
83
+ app, options = Rack::Builder.parse_file path
84
+ @options.merge! options
63
85
 
64
- options.each do |key,val|
65
- if key.to_s[0,4] == "bind"
66
- @options[:binds] << val
86
+ options.each do |key,val|
87
+ if key.to_s[0,4] == "bind"
88
+ @options[:binds] << val
89
+ end
67
90
  end
68
91
  end
69
92
 
@@ -72,7 +95,7 @@ module Puma
72
95
  app = Rack::CommonLogger.new(app, logger)
73
96
  end
74
97
 
75
- return app
98
+ return ConfigMiddleware.new(self, app)
76
99
  end
77
100
 
78
101
  def setup_random_token
@@ -176,6 +199,14 @@ module Puma
176
199
  @options[:on_restart] << blk
177
200
  end
178
201
 
202
+ # Command to use to restart puma. This should be just how to
203
+ # load puma itself (ie. 'ruby -Ilib bin/puma'), not the arguments
204
+ # to puma, as those are the same as the original process.
205
+ #
206
+ def restart_command(cmd)
207
+ @options[:request_cmd] = cmd
208
+ end
209
+
179
210
  # Store the pid of the server in the file at +path+.
180
211
  def pidfile(path)
181
212
  @options[:pidfile] = path
@@ -234,9 +265,19 @@ module Puma
234
265
  @options[:workers] = count.to_i
235
266
  end
236
267
 
268
+ # *Cluster mode only* Code to run when a worker boots to setup
269
+ # the process before booting the app.
270
+ #
271
+ # This can be called multiple times to add hooks.
272
+ #
273
+ def on_worker_boot(&block)
274
+ @options[:worker_boot] << block
275
+ end
276
+
237
277
  # The directory to operate out of.
238
278
  def directory(dir)
239
279
  @options[:directory] = dir.to_s
280
+ @options[:worker_directory] = dir.to_s
240
281
  end
241
282
  end
242
283
  end
@@ -28,7 +28,7 @@ module Puma
28
28
  # too taxing on performance.
29
29
  module Const
30
30
 
31
- PUMA_VERSION = VERSION = "2.0.0.b4".freeze
31
+ PUMA_VERSION = VERSION = "2.0.0.b7".freeze
32
32
 
33
33
  FAST_TRACK_KA_TIMEOUT = 0.2
34
34
 
@@ -101,6 +101,7 @@ module Puma
101
101
  SERVER_PORT = "SERVER_PORT".freeze
102
102
  HTTP_HOST = "HTTP_HOST".freeze
103
103
  PORT_80 = "80".freeze
104
+ PORT_443 = "443".freeze
104
105
  LOCALHOST = "localhost".freeze
105
106
 
106
107
  SERVER_PROTOCOL = "SERVER_PROTOCOL".freeze
@@ -119,6 +120,7 @@ module Puma
119
120
  RACK_URL_SCHEME = "rack.url_scheme".freeze
120
121
  RACK_AFTER_REPLY = "rack.after_reply".freeze
121
122
  PUMA_SOCKET = "puma.socket".freeze
123
+ PUMA_CONFIG = "puma.config".freeze
122
124
 
123
125
  HTTP = "http".freeze
124
126
  HTTPS = "https".freeze
@@ -147,5 +149,9 @@ module Puma
147
149
  COLON = ": ".freeze
148
150
 
149
151
  NEWLINE = "\n".freeze
152
+
153
+ HIJACK_P = "rack.hijack?".freeze
154
+ HIJACK = "rack.hijack".freeze
155
+ HIJACK_IO = "rack.hijack_io".freeze
150
156
  end
151
157
  end
@@ -8,12 +8,12 @@ module Puma
8
8
  attach_function :execlp, [:string, :varargs], :int
9
9
  attach_function :chdir, [:string], :int
10
10
 
11
- def self.chdir_exec(dir, cmd, *argv)
11
+ def self.chdir_exec(dir, argv)
12
12
  chdir(dir)
13
- argv.unshift(cmd)
13
+ cmd = argv.first
14
14
  argv = ([:string] * argv.size).zip(argv).flatten
15
- argv <<:int
16
- argv << 0
15
+ argv << :string
16
+ argv << nil
17
17
  execlp(cmd, *argv)
18
18
  raise SystemCallError.new(FFI.errno)
19
19
  end
@@ -1,137 +1,139 @@
1
- module Puma::MiniSSL
2
- class Socket
3
- def initialize(socket, engine)
4
- @socket = socket
5
- @engine = engine
6
- end
1
+ module Puma
2
+ module MiniSSL
3
+ class Socket
4
+ def initialize(socket, engine)
5
+ @socket = socket
6
+ @engine = engine
7
+ end
7
8
 
8
- def to_io
9
- @socket
10
- end
9
+ def to_io
10
+ @socket
11
+ end
11
12
 
12
- def readpartial(size)
13
- while true
14
- output = @engine.read
15
- return output if output
13
+ def readpartial(size)
14
+ while true
15
+ output = @engine.read
16
+ return output if output
16
17
 
17
- data = @socket.readpartial(size)
18
- @engine.inject(data)
19
- output = @engine.read
18
+ data = @socket.readpartial(size)
19
+ @engine.inject(data)
20
+ output = @engine.read
20
21
 
21
- return output if output
22
+ return output if output
22
23
 
23
- while neg_data = @engine.extract
24
- @socket.write neg_data
24
+ while neg_data = @engine.extract
25
+ @socket.write neg_data
26
+ end
25
27
  end
26
28
  end
27
- end
28
29
 
29
- def read_nonblock(size)
30
- while true
31
- output = @engine.read
32
- return output if output
30
+ def read_nonblock(size)
31
+ while true
32
+ output = @engine.read
33
+ return output if output
33
34
 
34
- data = @socket.read_nonblock(size)
35
+ data = @socket.read_nonblock(size)
35
36
 
36
- @engine.inject(data)
37
- output = @engine.read
37
+ @engine.inject(data)
38
+ output = @engine.read
38
39
 
39
- return output if output
40
+ return output if output
40
41
 
41
- while neg_data = @engine.extract
42
- @socket.write neg_data
42
+ while neg_data = @engine.extract
43
+ @socket.write neg_data
44
+ end
43
45
  end
44
46
  end
45
- end
46
47
 
47
- def write(data)
48
- need = data.size
48
+ def write(data)
49
+ need = data.size
49
50
 
50
- while true
51
- wrote = @engine.write data
52
- enc = @engine.extract
51
+ while true
52
+ wrote = @engine.write data
53
+ enc = @engine.extract
53
54
 
54
- if enc
55
- @socket.syswrite enc
56
- end
55
+ if enc
56
+ @socket.syswrite enc
57
+ end
57
58
 
58
- need -= wrote
59
+ need -= wrote
59
60
 
60
- return data.size if need == 0
61
+ return data.size if need == 0
61
62
 
62
- data = data[need..-1]
63
+ data = data[need..-1]
64
+ end
63
65
  end
64
- end
65
66
 
66
- alias_method :syswrite, :write
67
+ alias_method :syswrite, :write
67
68
 
68
- def flush
69
- @socket.flush
70
- end
69
+ def flush
70
+ @socket.flush
71
+ end
71
72
 
72
- def close
73
- @socket.close
74
- end
73
+ def close
74
+ @socket.close
75
+ end
75
76
 
76
- def peeraddr
77
- @socket.peeraddr
77
+ def peeraddr
78
+ @socket.peeraddr
79
+ end
78
80
  end
79
- end
80
81
 
81
- class Context
82
- attr_accessor :verify_mode
82
+ class Context
83
+ attr_accessor :verify_mode
83
84
 
84
- attr_reader :key
85
- attr_reader :cert
85
+ attr_reader :key
86
+ attr_reader :cert
86
87
 
87
- def key=(key)
88
- raise ArgumentError, "No such key file '#{key}'" unless File.exist? key
89
- @key = key
90
- end
88
+ def key=(key)
89
+ raise ArgumentError, "No such key file '#{key}'" unless File.exist? key
90
+ @key = key
91
+ end
91
92
 
92
- def cert=(cert)
93
- raise ArgumentError, "No such cert file '#{cert}'" unless File.exist? cert
94
- @cert = cert
93
+ def cert=(cert)
94
+ raise ArgumentError, "No such cert file '#{cert}'" unless File.exist? cert
95
+ @cert = cert
96
+ end
95
97
  end
96
- end
97
98
 
98
- VERIFY_NONE = 0
99
- VERIFY_PEER = 1
99
+ VERIFY_NONE = 0
100
+ VERIFY_PEER = 1
100
101
 
101
- #if defined?(JRUBY_VERSION)
102
+ #if defined?(JRUBY_VERSION)
102
103
  #class Engine
103
- #def self.server(key, cert)
104
- #new(key, cert)
105
- #end
104
+ #def self.server(key, cert)
105
+ #new(key, cert)
106
+ #end
107
+ #end
106
108
  #end
107
- #end
108
109
 
109
- class Server
110
- def initialize(socket, ctx)
111
- @socket = socket
112
- @ctx = ctx
113
- end
110
+ class Server
111
+ def initialize(socket, ctx)
112
+ @socket = socket
113
+ @ctx = ctx
114
+ end
114
115
 
115
- def to_io
116
- @socket
117
- end
116
+ def to_io
117
+ @socket
118
+ end
118
119
 
119
- def accept
120
- io = @socket.accept
121
- engine = Engine.server @ctx.key, @ctx.cert
120
+ def accept
121
+ io = @socket.accept
122
+ engine = Engine.server @ctx.key, @ctx.cert
122
123
 
123
- Socket.new io, engine
124
- end
124
+ Socket.new io, engine
125
+ end
125
126
 
126
- def accept_nonblock
127
- io = @socket.accept_nonblock
128
- engine = Engine.server @ctx.key, @ctx.cert
127
+ def accept_nonblock
128
+ io = @socket.accept_nonblock
129
+ engine = Engine.server @ctx.key, @ctx.cert
129
130
 
130
- Socket.new io, engine
131
- end
131
+ Socket.new io, engine
132
+ end
132
133
 
133
- def close
134
- @socket.close
134
+ def close
135
+ @socket.close
136
+ end
135
137
  end
136
138
  end
137
139
  end
@@ -0,0 +1,7 @@
1
+ require 'rack/handler/puma'
2
+
3
+ module Rack::Handler
4
+ def self.default(options = {})
5
+ Rack::Handler::Puma
6
+ end
7
+ end
@@ -1,3 +1,5 @@
1
+ require 'puma/util'
2
+
1
3
  module Puma
2
4
  class Reactor
3
5
  DefaultSleepFor = 5
@@ -8,7 +10,7 @@ module Puma
8
10
  @app_pool = app_pool
9
11
 
10
12
  @mutex = Mutex.new
11
- @ready, @trigger = IO.pipe
13
+ @ready, @trigger = Puma::Util.pipe
12
14
  @input = []
13
15
  @sleep_for = DefaultSleepFor
14
16
  @timeouts = []
@@ -48,7 +50,9 @@ module Puma
48
50
  # list or we'll accidentally close the socket when
49
51
  # it's in use!
50
52
  if c.timeout_at
51
- @timeouts.delete c
53
+ @mutex.synchronize do
54
+ @timeouts.delete c
55
+ end
52
56
  end
53
57
 
54
58
  begin
@@ -76,19 +80,24 @@ module Puma
76
80
  end
77
81
 
78
82
  unless @timeouts.empty?
79
- now = Time.now
83
+ @mutex.synchronize do
84
+ now = Time.now
80
85
 
81
- while @timeouts.first.timeout_at < now
82
- c = @timeouts.shift
83
- sockets.delete c
84
- c.close
86
+ while @timeouts.first.timeout_at < now
87
+ c = @timeouts.shift
88
+ sockets.delete c
89
+ c.close
85
90
 
86
- break if @timeouts.empty?
87
- end
91
+ break if @timeouts.empty?
92
+ end
88
93
 
89
- calculate_sleep
94
+ calculate_sleep
95
+ end
90
96
  end
91
97
  end
98
+ ensure
99
+ @trigger.close
100
+ @ready.close
92
101
  end
93
102
 
94
103
  def run_in_thread
@@ -135,11 +144,18 @@ module Puma
135
144
 
136
145
  # Close all watched sockets and clear them from being watched
137
146
  def clear!
138
- @trigger << "c"
147
+ begin
148
+ @trigger << "c"
149
+ rescue IOError
150
+ end
139
151
  end
140
152
 
141
153
  def shutdown
142
- @trigger << "!"
154
+ begin
155
+ @trigger << "!"
156
+ rescue IOError
157
+ end
158
+
143
159
  @thread.join
144
160
  end
145
161
  end