puma 0.9.1 → 0.9.2

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.

data/Manifest.txt CHANGED
@@ -23,7 +23,7 @@ ext/puma_http11/puma_http11.c
23
23
  lib/puma.rb
24
24
  lib/puma/app/status.rb
25
25
  lib/puma/cli.rb
26
- lib/puma/config.rb
26
+ lib/puma/configuration.rb
27
27
  lib/puma/const.rb
28
28
  lib/puma/control_cli.rb
29
29
  lib/puma/events.rb
@@ -35,12 +35,17 @@ lib/puma/thread_pool.rb
35
35
  lib/rack/handler/puma.rb
36
36
  puma.gemspec
37
37
  test/ab_rs.rb
38
+ test/config/app.rb
39
+ test/hello.ru
38
40
  test/lobster.ru
39
41
  test/mime.yaml
42
+ test/slow.ru
40
43
  test/test_app_status.rb
41
44
  test/test_cli.rb
45
+ test/test_config.rb
42
46
  test/test_http10.rb
43
47
  test/test_http11.rb
48
+ test/test_integration.rb
44
49
  test/test_persistent.rb
45
50
  test/test_rack_handler.rb
46
51
  test/test_rack_server.rb
data/bin/pumactl CHANGED
File without changes
@@ -4,9 +4,21 @@ module Puma
4
4
  def initialize(server, cli)
5
5
  @server = server
6
6
  @cli = cli
7
+ @auth_token = nil
8
+ end
9
+
10
+ attr_accessor :auth_token
11
+
12
+ def authenticate(env)
13
+ return true unless @auth_token
14
+ env['QUERY_STRING'].to_s.split(/&;/).include?("token=#{@auth_token}")
7
15
  end
8
16
 
9
17
  def call(env)
18
+ unless authenticate(env)
19
+ return [403, {}, ["Invalid auth token"]]
20
+ end
21
+
10
22
  case env['PATH_INFO']
11
23
  when "/stop"
12
24
  @server.stop
data/lib/puma/cli.rb CHANGED
@@ -3,7 +3,7 @@ require 'uri'
3
3
 
4
4
  require 'puma/server'
5
5
  require 'puma/const'
6
- require 'puma/config'
6
+ require 'puma/configuration'
7
7
 
8
8
  require 'rack/commonlogger'
9
9
 
@@ -11,7 +11,6 @@ module Puma
11
11
  # Handles invoke a Puma::Server in a command line style.
12
12
  #
13
13
  class CLI
14
- DefaultRackup = "config.ru"
15
14
  IS_JRUBY = defined?(JRUBY_VERSION)
16
15
 
17
16
  # Create a new CLI object using +argv+ as the command line
@@ -142,6 +141,11 @@ module Puma
142
141
  end
143
142
  end
144
143
 
144
+ o.on "--control-token TOKEN",
145
+ "The token to use as authentication for the control server" do |arg|
146
+ @options[:control_auth_token] = arg
147
+ end
148
+
145
149
  o.on '-t', '--threads INT', "min:max threads to use (default 0:16)" do |arg|
146
150
  min, max = arg.split(":")
147
151
  if max
@@ -163,20 +167,6 @@ module Puma
163
167
  end
164
168
  end
165
169
 
166
- # Load the specified rackup file, pull an options from
167
- # the rackup file, and set @app.
168
- #
169
- def load_rackup
170
- @app, options = Rack::Builder.parse_file @options[:rackup]
171
- @options.merge! options
172
-
173
- options.each do |key,val|
174
- if key.to_s[0,4] == "bind"
175
- @binds << val
176
- end
177
- end
178
- end
179
-
180
170
  # If configured, write the pid of the current process out
181
171
  # to a file.
182
172
  #
@@ -206,17 +196,14 @@ module Puma
206
196
  def parse_options
207
197
  @parser.parse! @argv
208
198
 
199
+ if @argv.last
200
+ @options[:rackup] = @argv.shift
201
+ end
202
+
209
203
  @config = Puma::Configuration.new @options
210
204
  @config.load
211
205
 
212
- unless @options[:rackup]
213
- @options[:rackup] = @argv.shift || DefaultRackup
214
- end
215
-
216
- if @options[:control_url] == "auto"
217
- path = @temp_status_path = Configuration.temp_path
218
- @options[:control_url] = "unix://#{path}"
219
- end
206
+ @temp_status_path = @options[:control_path_temp]
220
207
  end
221
208
 
222
209
  # Parse the options, load the rackup, start the server and wait
@@ -225,24 +212,15 @@ module Puma
225
212
  def run
226
213
  parse_options
227
214
 
228
- rackup = @options[:rackup]
229
-
230
- unless File.exists?(rackup)
231
- raise "Missing rackup file '#{rackup}'"
232
- end
215
+ app = @config.app
233
216
 
234
- load_rackup
235
217
  write_pid
236
218
  write_state
237
219
 
238
- unless @options[:quiet]
239
- @app = Rack::CommonLogger.new(@app, STDOUT)
240
- end
241
-
242
220
  min_t = @options[:min_threads]
243
221
  max_t = @options[:max_threads]
244
222
 
245
- server = Puma::Server.new @app, @events
223
+ server = Puma::Server.new app, @events
246
224
  server.min_threads = min_t
247
225
  server.max_threads = max_t
248
226
 
@@ -273,6 +251,11 @@ module Puma
273
251
  uri = URI.parse str
274
252
 
275
253
  app = Puma::App::Status.new server, self
254
+
255
+ if token = @options[:control_auth_token]
256
+ app.auth_token = token unless token.empty? or token == :none
257
+ end
258
+
276
259
  status = Puma::Server.new app, @events
277
260
  status.min_threads = 0
278
261
  status.max_threads = 1
@@ -0,0 +1,190 @@
1
+ module Puma
2
+ class Configuration
3
+ DefaultRackup = "config.ru"
4
+
5
+ DefaultTCPHost = "0.0.0.0"
6
+ DefaultTCPPort = 9292
7
+
8
+ def initialize(options)
9
+ @options = options
10
+ @options[:binds] ||= []
11
+ end
12
+
13
+ attr_reader :options
14
+
15
+ def load
16
+ if path = @options[:config_file]
17
+ DSL.new(@options)._load_from path
18
+ end
19
+
20
+ # Rakeup default option support
21
+ if host = @options[:Host]
22
+ port = @options[:Port] || DefaultTCPPort
23
+
24
+ @options[:binds] << "tcp://#{host}:#{port}"
25
+ end
26
+
27
+ if @options[:binds].empty?
28
+ @options[:binds] << "tcp://#{DefaultTCPHost}:#{DefaultTCPPort}"
29
+ end
30
+
31
+ if @options[:control_url] == "auto"
32
+ path = Configuration.temp_path
33
+ @options[:control_url] = "unix://#{path}"
34
+ @options[:control_url_temp] = path
35
+ end
36
+
37
+ unless @options[:control_auth_token]
38
+ setup_random_token
39
+ end
40
+ end
41
+
42
+ # Load the specified rackup file, pull an options from
43
+ # the rackup file, and set @app.
44
+ #
45
+ def app
46
+ if app = @options[:app]
47
+ return app
48
+ end
49
+
50
+ path = @options[:rackup] || DefaultRackup
51
+
52
+ unless File.exists?(path)
53
+ raise "Missing rackup file '#{path}'"
54
+ end
55
+
56
+ app, options = Rack::Builder.parse_file path
57
+ @options.merge! options
58
+
59
+ options.each do |key,val|
60
+ if key.to_s[0,4] == "bind"
61
+ @options[:binds] << val
62
+ end
63
+ end
64
+
65
+ unless @options[:quiet]
66
+ app = Rack::CommonLogger.new(app, STDOUT)
67
+ end
68
+
69
+ return app
70
+ end
71
+
72
+ def setup_random_token
73
+ begin
74
+ require 'openssl'
75
+ rescue LoadError
76
+ end
77
+
78
+ count = 16
79
+
80
+ bytes = nil
81
+
82
+ if defined? OpenSSL::Random
83
+ bytes = OpenSSL::Random.random_bytes(count)
84
+ elsif File.exists?("/dev/urandom")
85
+ File.open("/dev/urandom") do |f|
86
+ bytes = f.read(count)
87
+ end
88
+ end
89
+
90
+ if bytes
91
+ token = ""
92
+ bytes.each_byte { |b| token << b.to_s(16) }
93
+ else
94
+ token = (0..count).to_a.map { rand(255).to_s(16) }.join
95
+ end
96
+
97
+ @options[:control_auth_token] = token
98
+ end
99
+
100
+ def self.temp_path
101
+ require 'tmpdir'
102
+
103
+ t = (Time.now.to_f * 1000).to_i
104
+ "#{Dir.tmpdir}/puma-status-#{t}-#{$$}"
105
+ end
106
+
107
+ # The methods that are available for use inside the config file.
108
+ #
109
+ class DSL
110
+ def initialize(options)
111
+ @options = options
112
+ end
113
+
114
+ def _load_from(path)
115
+ instance_eval File.read(path), path, 1
116
+ end
117
+
118
+ # Use +obj+ or +block+ as the Rack app. This allows a config file to
119
+ # be the app itself.
120
+ #
121
+ def app(obj=nil, &block)
122
+ obj ||= block
123
+
124
+ raise "Provide either a #call'able or a block" unless obj
125
+
126
+ @options[:app] = obj
127
+ end
128
+
129
+ # Start the Puma control rack app on +url+. This app can be communicated
130
+ # with to control the main server.
131
+ #
132
+ def activate_control_app(url="auto", opts=nil)
133
+ @options[:control_url] = url
134
+
135
+ if opts
136
+ if tok = opts[:auth_token]
137
+ @options[:control_auth_token] = tok
138
+ end
139
+
140
+ if opts[:no_token]
141
+ @options[:control_auth_token] = :none
142
+ end
143
+ end
144
+ end
145
+
146
+ # Bind the server to +url+. tcp:// and unix:// are the only accepted
147
+ # protocols.
148
+ #
149
+ def bind(url)
150
+ @options[:binds] << url
151
+ end
152
+
153
+ # Store the pid of the server in the file at +path+.
154
+ def pidfile(path)
155
+ @options[:pidfile] = path
156
+ end
157
+
158
+ # Disable request logging.
159
+ #
160
+ def quiet
161
+ @options[:quiet] = true
162
+ end
163
+
164
+ # Load +path+ as a rackup file.
165
+ #
166
+ def rackup(path)
167
+ @options[:rackup] = path.to_s
168
+ end
169
+
170
+ # Configure +min+ to be the minimum number of threads to use to answer
171
+ # requests and +max+ the maximum.
172
+ #
173
+ def threads(min, max)
174
+ if min > max
175
+ raise "The minimum number of threads must be less than the max"
176
+ end
177
+
178
+ @options[:min_threads] = min
179
+ @options[:max_threads] = max
180
+ end
181
+
182
+ # Use +path+ as the file to store the server info state. This is
183
+ # used by pumactl to query and control the server.
184
+ #
185
+ def state_path(path)
186
+ @options[:state] = path.to_s
187
+ end
188
+ end
189
+ end
190
+ end
data/lib/puma/const.rb CHANGED
@@ -71,7 +71,7 @@ module Puma
71
71
 
72
72
  PATH_INFO = 'PATH_INFO'.freeze
73
73
 
74
- PUMA_VERSION = VERSION = "0.9.1".freeze
74
+ PUMA_VERSION = VERSION = "0.9.2".freeze
75
75
 
76
76
  PUMA_TMP_BASE = "puma".freeze
77
77
 
@@ -1,7 +1,7 @@
1
1
  require 'optparse'
2
2
 
3
3
  require 'puma/const'
4
- require 'puma/config'
4
+ require 'puma/configuration'
5
5
 
6
6
  require 'yaml'
7
7
  require 'uri'
@@ -11,8 +11,9 @@ require 'socket'
11
11
  module Puma
12
12
  class ControlCLI
13
13
 
14
- def initialize(argv)
14
+ def initialize(argv, stdout=STDOUT)
15
15
  @argv = argv
16
+ @stdout = stdout
16
17
  end
17
18
 
18
19
  def setup_options
@@ -59,57 +60,68 @@ module Puma
59
60
  end
60
61
  end
61
62
 
63
+ def request(sock, url)
64
+ token = @config.options[:control_auth_token]
65
+ if token
66
+ url = "#{url}?token=#{token}"
67
+ end
68
+
69
+ sock << "GET #{url} HTTP/1.0\r\n\r\n"
70
+
71
+ rep = sock.read.split("\r\n")
72
+
73
+ m = %r!HTTP/1.\d (\d+)!.match(rep.first)
74
+ if m[1] == "403"
75
+ raise "Unauthorized access to server (wrong auth token)"
76
+ elsif m[1] != "200"
77
+ raise "Bad response code from server: #{m[1]}"
78
+ end
79
+
80
+ return rep.last
81
+ end
82
+
62
83
  def command_pid
63
- puts "#{@state['pid']}"
84
+ @stdout.puts "#{@state['pid']}"
64
85
  end
65
86
 
66
87
  def command_stop
67
88
  sock = connect
68
- sock << "GET /stop HTTP/1.0\r\n\r\n"
69
- rep = sock.read
89
+ body = request sock, "/stop"
70
90
 
71
- body = rep.split("\r\n").last
72
91
  if body != '{ "status": "ok" }'
73
92
  raise "Invalid response: '#{body}'"
74
93
  else
75
- puts "Requested stop from server"
94
+ @stdout.puts "Requested stop from server"
76
95
  end
77
96
  end
78
97
 
79
98
  def command_halt
80
99
  sock = connect
81
- s << "GET /halt HTTP/1.0\r\n\r\n"
82
- rep = s.read
100
+ body = request sock, "/halt"
83
101
 
84
- body = rep.split("\r\n").last
85
102
  if body != '{ "status": "ok" }'
86
103
  raise "Invalid response: '#{body}'"
87
104
  else
88
- puts "Requested halt from server"
105
+ @stdout.puts "Requested halt from server"
89
106
  end
90
107
  end
91
108
 
92
109
  def command_restart
93
110
  sock = connect
94
- sock << "GET /restart HTTP/1.0\r\n\r\n"
95
- rep = sock.read
111
+ body = request sock, "/restart"
96
112
 
97
- body = rep.split("\r\n").last
98
113
  if body != '{ "status": "ok" }'
99
114
  raise "Invalid response: '#{body}'"
100
115
  else
101
- puts "Requested restart from server"
116
+ @stdout.puts "Requested restart from server"
102
117
  end
103
118
  end
104
119
 
105
120
  def command_stats
106
121
  sock = connect
107
- sock << "GET /stats HTTP/1.0\r\n\r\n"
108
- rep = sock.read
109
-
110
- body = rep.split("\r\n").last
122
+ body = request sock, "/stats"
111
123
 
112
- puts body
124
+ @stdout.puts body
113
125
  end
114
126
  end
115
127
  end
data/lib/puma/server.rb CHANGED
@@ -52,6 +52,7 @@ module Puma
52
52
  @thread_pool = nil
53
53
 
54
54
  @persistent_timeout = PERSISTENT_TIMEOUT
55
+ @persistent_check, @persistent_wakeup = IO.pipe
55
56
 
56
57
  @proto_env = {
57
58
  "rack.version".freeze => Rack::VERSION,
@@ -91,14 +92,18 @@ module Puma
91
92
  end
92
93
 
93
94
  # Tell the server to listen on host +host+, port +port+.
94
- # If optimize_for_latency is true (the default) then clients connecting
95
+ # If +optimize_for_latency+ is true (the default) then clients connecting
95
96
  # will be optimized for latency over throughput.
96
97
  #
97
- def add_tcp_listener(host, port, optimize_for_latency=true)
98
+ # +backlog+ indicates how many unaccepted connections the kernel should
99
+ # allow to accumulate before returning connection refused.
100
+ #
101
+ def add_tcp_listener(host, port, optimize_for_latency=true, backlog=1024)
98
102
  s = TCPServer.new(host, port)
99
103
  if optimize_for_latency
100
104
  s.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
101
105
  end
106
+ s.listen backlog
102
107
  @ios << s
103
108
  end
104
109
 
@@ -219,9 +224,11 @@ module Puma
219
224
  env = @proto_env.dup
220
225
  nparsed = 0
221
226
  else
222
- unless IO.select([client], nil, nil, @persistent_timeout)
227
+ unless ret = IO.select([client, @persistent_check], nil, nil, @persistent_timeout)
223
228
  raise EOFError, "Timed out persistent connection"
224
229
  end
230
+
231
+ return if ret.first.include? @persistent_check
225
232
  end
226
233
  else
227
234
  # Parser is not done, queue up more data to read and continue parsing
@@ -514,12 +521,14 @@ module Puma
514
521
  # off the request queue before finally exiting.
515
522
  #
516
523
  def stop(sync=false)
524
+ @persistent_wakeup.close
517
525
  @notify << STOP_COMMAND
518
526
 
519
527
  @thread.join if @thread && sync
520
528
  end
521
529
 
522
530
  def halt(sync=false)
531
+ @persistent_wakeup.close
523
532
  @notify << HALT_COMMAND
524
533
 
525
534
  @thread.join if @thread && sync
@@ -8,13 +8,13 @@ module Rack
8
8
  :Host => '0.0.0.0',
9
9
  :Port => 8080,
10
10
  :Threads => '0:16',
11
- :Quiet => false
11
+ :Verbose => false
12
12
  }
13
13
 
14
14
  def self.run(app, options = {})
15
15
  options = DEFAULT_OPTIONS.merge(options)
16
16
 
17
- unless options[:Quiet]
17
+ if options[:Verbose]
18
18
  app = Rack::CommonLogger.new(app, STDOUT)
19
19
  end
20
20
 
data/puma.gemspec CHANGED
@@ -2,23 +2,23 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = "puma"
5
- s.version = "0.9.1"
5
+ s.version = "0.9.2"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Evan Phoenix"]
9
- s.date = "2011-12-06"
9
+ s.date = "2011-12-19"
10
10
  s.description = "Puma is a small library that provides a very fast and concurrent HTTP 1.1 server for Ruby web applications. It is designed for running rack apps only.\n\nWhat makes Puma so fast is the careful use of an Ragel extension to provide fast, accurate HTTP 1.1 protocol parsing. This makes the server scream without too many portability issues."
11
11
  s.email = ["evan@phx.io"]
12
12
  s.executables = ["puma", "pumactl"]
13
13
  s.extensions = ["ext/puma_http11/extconf.rb"]
14
14
  s.extra_rdoc_files = ["History.txt", "Manifest.txt"]
15
- s.files = ["COPYING", "Gemfile", "History.txt", "LICENSE", "Manifest.txt", "README.md", "Rakefile", "TODO", "bin/puma", "bin/pumactl", "examples/config.rb", "ext/puma_http11/PumaHttp11Service.java", "ext/puma_http11/ext_help.h", "ext/puma_http11/extconf.rb", "ext/puma_http11/http11_parser.c", "ext/puma_http11/http11_parser.h", "ext/puma_http11/http11_parser.java.rl", "ext/puma_http11/http11_parser.rl", "ext/puma_http11/http11_parser_common.rl", "ext/puma_http11/org/jruby/puma/Http11.java", "ext/puma_http11/org/jruby/puma/Http11Parser.java", "ext/puma_http11/puma_http11.c", "lib/puma.rb", "lib/puma/app/status.rb", "lib/puma/cli.rb", "lib/puma/config.rb", "lib/puma/const.rb", "lib/puma/control_cli.rb", "lib/puma/events.rb", "lib/puma/jruby_restart.rb", "lib/puma/null_io.rb", "lib/puma/rack_patch.rb", "lib/puma/server.rb", "lib/puma/thread_pool.rb", "lib/rack/handler/puma.rb", "puma.gemspec", "test/ab_rs.rb", "test/lobster.ru", "test/mime.yaml", "test/test_app_status.rb", "test/test_cli.rb", "test/test_http10.rb", "test/test_http11.rb", "test/test_persistent.rb", "test/test_rack_handler.rb", "test/test_rack_server.rb", "test/test_thread_pool.rb", "test/test_unix_socket.rb", "test/test_ws.rb", "test/testhelp.rb", "tools/trickletest.rb"]
15
+ s.files = ["COPYING", "Gemfile", "History.txt", "LICENSE", "Manifest.txt", "README.md", "Rakefile", "TODO", "bin/puma", "bin/pumactl", "examples/config.rb", "ext/puma_http11/PumaHttp11Service.java", "ext/puma_http11/ext_help.h", "ext/puma_http11/extconf.rb", "ext/puma_http11/http11_parser.c", "ext/puma_http11/http11_parser.h", "ext/puma_http11/http11_parser.java.rl", "ext/puma_http11/http11_parser.rl", "ext/puma_http11/http11_parser_common.rl", "ext/puma_http11/org/jruby/puma/Http11.java", "ext/puma_http11/org/jruby/puma/Http11Parser.java", "ext/puma_http11/puma_http11.c", "lib/puma.rb", "lib/puma/app/status.rb", "lib/puma/cli.rb", "lib/puma/configuration.rb", "lib/puma/const.rb", "lib/puma/control_cli.rb", "lib/puma/events.rb", "lib/puma/jruby_restart.rb", "lib/puma/null_io.rb", "lib/puma/rack_patch.rb", "lib/puma/server.rb", "lib/puma/thread_pool.rb", "lib/rack/handler/puma.rb", "puma.gemspec", "test/ab_rs.rb", "test/config/app.rb", "test/hello.ru", "test/lobster.ru", "test/mime.yaml", "test/slow.ru", "test/test_app_status.rb", "test/test_cli.rb", "test/test_config.rb", "test/test_http10.rb", "test/test_http11.rb", "test/test_integration.rb", "test/test_persistent.rb", "test/test_rack_handler.rb", "test/test_rack_server.rb", "test/test_thread_pool.rb", "test/test_unix_socket.rb", "test/test_ws.rb", "test/testhelp.rb", "tools/trickletest.rb"]
16
16
  s.rdoc_options = ["--main", "README.md"]
17
17
  s.require_paths = ["lib"]
18
18
  s.rubyforge_project = "puma"
19
19
  s.rubygems_version = "1.8.12"
20
20
  s.summary = "Puma is a small library that provides a very fast and concurrent HTTP 1.1 server for Ruby web applications"
21
- s.test_files = ["test/test_app_status.rb", "test/test_cli.rb", "test/test_http10.rb", "test/test_http11.rb", "test/test_persistent.rb", "test/test_rack_handler.rb", "test/test_rack_server.rb", "test/test_thread_pool.rb", "test/test_unix_socket.rb", "test/test_ws.rb"]
21
+ s.test_files = ["test/test_app_status.rb", "test/test_cli.rb", "test/test_config.rb", "test/test_http10.rb", "test/test_http11.rb", "test/test_integration.rb", "test/test_persistent.rb", "test/test_rack_handler.rb", "test/test_rack_server.rb", "test/test_thread_pool.rb", "test/test_unix_socket.rb", "test/test_ws.rb"]
22
22
 
23
23
  if s.respond_to? :specification_version then
24
24
  s.specification_version = 3
@@ -26,15 +26,18 @@ Gem::Specification.new do |s|
26
26
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
27
27
  s.add_runtime_dependency(%q<rack>, ["~> 1.2"])
28
28
  s.add_development_dependency(%q<rake-compiler>, ["~> 0.7.0"])
29
- s.add_development_dependency(%q<hoe>, ["~> 2.10"])
29
+ s.add_development_dependency(%q<hoe>, ["~> 2.12"])
30
+ s.add_development_dependency(%q<rdoc>, ["~> 3.10"])
30
31
  else
31
32
  s.add_dependency(%q<rack>, ["~> 1.2"])
32
33
  s.add_dependency(%q<rake-compiler>, ["~> 0.7.0"])
33
- s.add_dependency(%q<hoe>, ["~> 2.10"])
34
+ s.add_dependency(%q<hoe>, ["~> 2.12"])
35
+ s.add_dependency(%q<rdoc>, ["~> 3.10"])
34
36
  end
35
37
  else
36
38
  s.add_dependency(%q<rack>, ["~> 1.2"])
37
39
  s.add_dependency(%q<rake-compiler>, ["~> 0.7.0"])
38
- s.add_dependency(%q<hoe>, ["~> 2.10"])
40
+ s.add_dependency(%q<hoe>, ["~> 2.12"])
41
+ s.add_dependency(%q<rdoc>, ["~> 3.10"])
39
42
  end
40
43
  end
@@ -0,0 +1,3 @@
1
+ app do |env|
2
+ [200, {}, ["embedded app"]]
3
+ end
data/test/hello.ru ADDED
@@ -0,0 +1 @@
1
+ run lambda { |env| [200, {}, ["Hello World"]] }
data/test/slow.ru ADDED
@@ -0,0 +1,4 @@
1
+ run lambda { |env|
2
+ 30000000.times { }
3
+ [200, {}, ["Hello World"]]
4
+ }
@@ -24,12 +24,36 @@ class TestAppStatus < Test::Unit::TestCase
24
24
  def setup
25
25
  @server = FakeServer.new
26
26
  @app = Puma::App::Status.new(@server, @server)
27
+ @app.auth_token = nil
28
+ end
29
+
30
+ def test_bad_token
31
+ @app.auth_token = "abcdef"
32
+
33
+ env = { 'PATH_INFO' => "/whatever" }
34
+
35
+ status, _, _ = @app.call env
36
+
37
+ assert_equal 403, status
38
+ end
39
+
40
+ def test_good_token
41
+ @app.auth_token = "abcdef"
42
+
43
+ env = {
44
+ 'PATH_INFO' => "/whatever",
45
+ 'QUERY_STRING' => "token=abcdef"
46
+ }
47
+
48
+ status, _, _ = @app.call env
49
+
50
+ assert_equal 404, status
27
51
  end
28
52
 
29
53
  def test_unsupported
30
54
  env = { 'PATH_INFO' => "/not-real" }
31
55
 
32
- status, header, body = @app.call env
56
+ status, _, _ = @app.call env
33
57
 
34
58
  assert_equal 404, status
35
59
  end
@@ -37,7 +61,7 @@ class TestAppStatus < Test::Unit::TestCase
37
61
  def test_stop
38
62
  env = { 'PATH_INFO' => "/stop" }
39
63
 
40
- status, header, body = @app.call env
64
+ status, _ , body = @app.call env
41
65
 
42
66
  assert_equal :stop, @server.status
43
67
  assert_equal 200, status
@@ -47,7 +71,7 @@ class TestAppStatus < Test::Unit::TestCase
47
71
  def test_halt
48
72
  env = { 'PATH_INFO' => "/halt" }
49
73
 
50
- status, header, body = @app.call env
74
+ status, _ , body = @app.call env
51
75
 
52
76
  assert_equal :halt, @server.status
53
77
  assert_equal 200, status
@@ -60,7 +84,7 @@ class TestAppStatus < Test::Unit::TestCase
60
84
  @server.backlog = 1
61
85
  @server.running = 9
62
86
 
63
- status, header, body = @app.call env
87
+ status, _ , body = @app.call env
64
88
 
65
89
  assert_equal 200, status
66
90
  assert_equal ['{ "backlog": 1, "running": 9 }'], body
data/test/test_cli.rb CHANGED
@@ -34,7 +34,10 @@ class TestCLI < Test::Unit::TestCase
34
34
  sin = StringIO.new
35
35
  sout = StringIO.new
36
36
 
37
- cli = Puma::CLI.new ["-b", "unix://#{@tmp_path2}", "--control", url, "test/lobster.ru"], sin, sout
37
+ cli = Puma::CLI.new ["-b", "unix://#{@tmp_path2}",
38
+ "--control", url,
39
+ "--control-token", "",
40
+ "test/lobster.ru"], sin, sout
38
41
  cli.parse_options
39
42
 
40
43
  t = Thread.new { cli.run }
@@ -57,7 +60,10 @@ class TestCLI < Test::Unit::TestCase
57
60
  sin = StringIO.new
58
61
  sout = StringIO.new
59
62
 
60
- cli = Puma::CLI.new ["-b", "unix://#{@tmp_path2}", "--control", url, "test/lobster.ru"], sin, sout
63
+ cli = Puma::CLI.new ["-b", "unix://#{@tmp_path2}",
64
+ "--control", url,
65
+ "--control-token", "",
66
+ "test/lobster.ru"], sin, sout
61
67
  cli.parse_options
62
68
 
63
69
  t = Thread.new { cli.run }
@@ -0,0 +1,16 @@
1
+ require 'test/unit'
2
+
3
+ require 'puma'
4
+ require 'puma/configuration'
5
+
6
+ class TestConfigFile < Test::Unit::TestCase
7
+ def test_app_from_app_DSL
8
+ opts = { :config_file => "test/config/app.rb" }
9
+ conf = Puma::Configuration.new opts
10
+ conf.load
11
+
12
+ app = conf.app
13
+
14
+ assert_equal [200, {}, ["embedded app"]], app.call(nil)
15
+ end
16
+ end
data/test/test_http11.rb CHANGED
@@ -37,14 +37,6 @@ class Http11ParserTest < Test::Unit::TestCase
37
37
  assert_equal should_be_good.length, nread
38
38
  assert parser.finished?
39
39
  assert !parser.error?
40
-
41
- nasty_pound_header = "GET / HTTP/1.1\r\nX-SSL-Bullshit: -----BEGIN CERTIFICATE-----\r\n\tMIIFbTCCBFWgAwIBAgICH4cwDQYJKoZIhvcNAQEFBQAwcDELMAkGA1UEBhMCVUsx\r\n\tETAPBgNVBAoTCGVTY2llbmNlMRIwEAYDVQQLEwlBdXRob3JpdHkxCzAJBgNVBAMT\r\n\tAkNBMS0wKwYJKoZIhvcNAQkBFh5jYS1vcGVyYXRvckBncmlkLXN1cHBvcnQuYWMu\r\n\tdWswHhcNMDYwNzI3MTQxMzI4WhcNMDcwNzI3MTQxMzI4WjBbMQswCQYDVQQGEwJV\r\n\tSzERMA8GA1UEChMIZVNjaWVuY2UxEzARBgNVBAsTCk1hbmNoZXN0ZXIxCzAJBgNV\r\n\tBAcTmrsogriqMWLAk1DMRcwFQYDVQQDEw5taWNoYWVsIHBhcmQYJKoZIhvcNAQEB\r\n\tBQADggEPADCCAQoCggEBANPEQBgl1IaKdSS1TbhF3hEXSl72G9J+WC/1R64fAcEF\r\n\tW51rEyFYiIeZGx/BVzwXbeBoNUK41OK65sxGuflMo5gLflbwJtHBRIEKAfVVp3YR\r\n\tgW7cMA/s/XKgL1GEC7rQw8lIZT8RApukCGqOVHSi/F1SiFlPDxuDfmdiNzL31+sL\r\n\t0iwHDdNkGjy5pyBSB8Y79dsSJtCW/iaLB0/n8Sj7HgvvZJ7x0fr+RQjYOUUfrePP\r\n\tu2MSpFyf+9BbC/aXgaZuiCvSR+8Snv3xApQY+fULK/xY8h8Ua51iXoQ5jrgu2SqR\r\n\twgA7BUi3G8LFzMBl8FRCDYGUDy7M6QaHXx1ZWIPWNKsCAwEAAaOCAiQwggIgMAwG\r\n\tA1UdEwEB/wQCMAAwEQYJYIZIAYb4QgEBBAQDAgWgMA4GA1UdDwEB/wQEAwID6DAs\r\n\tBglghkgBhvhCAQ0EHxYdVUsgZS1TY2llbmNlIFVzZXIgQ2VydGlmaWNhdGUwHQYD\r\n\tVR0OBBYEFDTt/sf9PeMaZDHkUIldrDYMNTBZMIGaBgNVHSMEgZIwgY+AFAI4qxGj\r\n\tloCLDdMVKwiljjDastqooXSkcjBwMQswCQYDVQQGEwJVSzERMA8GA1UEChMIZVNj\r\n\taWVuY2UxEjAQBgNVBAsTCUF1dGhvcml0eTELMAkGA1UEAxMCQ0ExLTArBgkqhkiG\r\n\t9w0BCQEWHmNhLW9wZXJhdG9yQGdyaWQtc3VwcG9ydC5hYy51a4IBADApBgNVHRIE\r\n\tIjAggR5jYS1vcGVyYXRvckBncmlkLXN1cHBvcnQuYWMudWswGQYDVR0gBBIwEDAO\r\n\tBgwrBgEEAdkvAQEBAQYwPQYJYIZIAYb4QgEEBDAWLmh0dHA6Ly9jYS5ncmlkLXN1\r\n\tcHBvcnQuYWMudmT4sopwqlBWsvcHViL2NybC9jYWNybC5jcmwwPQYJYIZIAYb4QgEDBDAWLmh0\r\n\tdHA6Ly9jYS5ncmlkLXN1cHBvcnQuYWMudWsvcHViL2NybC9jYWNybC5jcmwwPwYD\r\n\tVR0fBDgwNjA0oDKgMIYuaHR0cDovL2NhLmdyaWQt5hYy51ay9wdWIv\r\n\tY3JsL2NhY3JsLmNybDANBgkqhkiG9w0BAQUFAAOCAQEAS/U4iiooBENGW/Hwmmd3\r\n\tXCy6Zrt08YjKCzGNjorT98g8uGsqYjSxv/hmi0qlnlHs+k/3Iobc3LjS5AMYr5L8\r\n\tUO7OSkgFFlLHQyC9JzPfmLCAugvzEbyv4Olnsr8hbxF1MbKZoQxUZtMVu29wjfXk\r\n\thTeApBv7eaKCWpSp7MCbvgzm74izKhu3vlDk9w6qVrxePfGgpKPqfHiOoGhFnbTK\r\n\twTC6o2xq5y0qZ03JonF7OJspEd3I5zKY3E+ov7/ZhW6DqT8UFvsAdjvQbXyhV8Eu\r\n\tYhixw1aKEPzNjNowuIseVogKOLXxWI5vAi5HgXdS0/ES5gDGsABo4fqovUKlgop3\r\n\tRA==\r\n\t-----END CERTIFICATE-----\r\n\r\n"
42
- parser = HttpParser.new
43
- req = {}
44
- #nread = parser.execute(req, nasty_pound_header, 0)
45
- #assert_equal nasty_pound_header.length, nread
46
- #assert parser.finished?
47
- #assert !parser.error?
48
40
  end
49
41
 
50
42
  def test_parse_error
@@ -54,8 +46,8 @@ class Http11ParserTest < Test::Unit::TestCase
54
46
 
55
47
  error = false
56
48
  begin
57
- nread = parser.execute(req, bad_http, 0)
58
- rescue => details
49
+ parser.execute(req, bad_http, 0)
50
+ rescue
59
51
  error = true
60
52
  end
61
53
 
@@ -0,0 +1,48 @@
1
+ require 'test/unit'
2
+ require 'rubygems'
3
+ require 'socket'
4
+
5
+ require 'puma/cli'
6
+ require 'puma/control_cli'
7
+
8
+ class TestIntegration < Test::Unit::TestCase
9
+ def setup
10
+ @state_path = "test/test_puma.state"
11
+ @bind_path = "test/test_server.sock"
12
+ @control_path = "test/test_control.sock"
13
+ end
14
+
15
+ def teardown
16
+ File.unlink @state_path rescue nil
17
+ File.unlink @bind_path rescue nil
18
+ File.unlink @control_path rescue nil
19
+ end
20
+
21
+ def test_stop_via_pumactl
22
+ if defined? JRUBY_VERSION
23
+ assert true
24
+ return
25
+ end
26
+
27
+ sin = StringIO.new
28
+ sout = StringIO.new
29
+
30
+ cli = Puma::CLI.new %W!-q -S #{@state_path} -b unix://#{@bind_path} --control unix://#{@control_path} test/hello.ru!, sin, sout
31
+
32
+ t = Thread.new do
33
+ cli.run
34
+ end
35
+
36
+ sleep 1
37
+
38
+ s = UNIXSocket.new @bind_path
39
+ s << "GET / HTTP/1.0\r\n\r\n"
40
+ assert_equal "Hello World", s.read.split("\r\n").last
41
+
42
+ ccli = Puma::ControlCLI.new %W!-S #{@state_path} stop!, sout
43
+
44
+ ccli.run
45
+
46
+ assert_kind_of Thread, t.join(1), "server didn't stop"
47
+ end
48
+ end
data/test/test_ws.rb CHANGED
@@ -90,7 +90,7 @@ class WebServerTest < Test::Unit::TestCase
90
90
  def test_file_streamed_request
91
91
  body = "a" * (Puma::Const::MAX_BODY * 2)
92
92
  long = "GET /test HTTP/1.1\r\nContent-length: #{body.length}\r\n\r\n" + body
93
- do_test(long, Puma::Const::CHUNK_SIZE * 2 -400)
93
+ do_test(long, (Puma::Const::CHUNK_SIZE * 2) - 400)
94
94
  end
95
95
 
96
96
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: puma
3
3
  version: !ruby/object:Gem::Version
4
- hash: 57
4
+ hash: 63
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 9
9
- - 1
10
- version: 0.9.1
9
+ - 2
10
+ version: 0.9.2
11
11
  platform: ruby
12
12
  authors:
13
13
  - Evan Phoenix
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-12-06 00:00:00 Z
18
+ date: 2011-12-19 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  name: rack
@@ -118,7 +118,7 @@ files:
118
118
  - lib/puma.rb
119
119
  - lib/puma/app/status.rb
120
120
  - lib/puma/cli.rb
121
- - lib/puma/config.rb
121
+ - lib/puma/configuration.rb
122
122
  - lib/puma/const.rb
123
123
  - lib/puma/control_cli.rb
124
124
  - lib/puma/events.rb
@@ -130,12 +130,17 @@ files:
130
130
  - lib/rack/handler/puma.rb
131
131
  - puma.gemspec
132
132
  - test/ab_rs.rb
133
+ - test/config/app.rb
134
+ - test/hello.ru
133
135
  - test/lobster.ru
134
136
  - test/mime.yaml
137
+ - test/slow.ru
135
138
  - test/test_app_status.rb
136
139
  - test/test_cli.rb
140
+ - test/test_config.rb
137
141
  - test/test_http10.rb
138
142
  - test/test_http11.rb
143
+ - test/test_integration.rb
139
144
  - test/test_persistent.rb
140
145
  - test/test_rack_handler.rb
141
146
  - test/test_rack_server.rb
@@ -181,8 +186,10 @@ summary: Puma is a small library that provides a very fast and concurrent HTTP 1
181
186
  test_files:
182
187
  - test/test_app_status.rb
183
188
  - test/test_cli.rb
189
+ - test/test_config.rb
184
190
  - test/test_http10.rb
185
191
  - test/test_http11.rb
192
+ - test/test_integration.rb
186
193
  - test/test_persistent.rb
187
194
  - test/test_rack_handler.rb
188
195
  - test/test_rack_server.rb
data/lib/puma/config.rb DELETED
@@ -1,98 +0,0 @@
1
- module Puma
2
- class Configuration
3
- DefaultTCPHost = "0.0.0.0"
4
- DefaultTCPPort = 9292
5
-
6
- def initialize(options)
7
- @options = options
8
- @options[:binds] ||= []
9
- end
10
-
11
- attr_reader :options
12
-
13
- def load
14
- if path = @options[:config_file]
15
- instance_eval File.read(path), path, 1
16
- end
17
-
18
- # Rakeup default option support
19
- if host = @options[:Host]
20
- port = @options[:Port] || DefaultTCPPort
21
-
22
- @options[:binds] << "tcp://#{host}:#{port}"
23
- end
24
-
25
- if @options[:binds].empty?
26
- @options[:binds] << "tcp://#{DefaultTCPHost}:#{DefaultTCPPort}"
27
- end
28
- end
29
-
30
- def self.temp_path
31
- require 'tmpdir'
32
-
33
- t = (Time.now.to_f * 1000).to_i
34
- "#{Dir.tmpdir}/puma-status-#{t}-#{$$}"
35
- end
36
-
37
- # Use +obj+ or +block+ as the Rack app. This allows a config file to
38
- # be the app itself.
39
- #
40
- def app(obj=nil, &block)
41
- obj ||= block
42
-
43
- raise "Provide either a #call'able or a block" unless obj
44
-
45
- @options[:app] = obj
46
- end
47
-
48
- # Start the Puma control rack app on +url+. This app can be communicated
49
- # with to control the main server.
50
- #
51
- def activate_control_app(url="auto")
52
- @options[:control_url] = url
53
- end
54
-
55
- # Bind the server to +url+. tcp:// and unix:// are the only accepted
56
- # protocols.
57
- #
58
- def bind(url)
59
- @options[:binds] << url
60
- end
61
-
62
- # Store the pid of the server in the file at +path+.
63
- def pidfile(path)
64
- @options[:pidfile] = path
65
- end
66
-
67
- # Disable request logging.
68
- #
69
- def quiet
70
- @options[:quiet] = true
71
- end
72
-
73
- # Load +path+ as a rackup file.
74
- #
75
- def rackup(path)
76
- @options[:rackup] = path.to_s
77
- end
78
-
79
- # Configure +min+ to be the minimum number of threads to use to answer
80
- # requests and +max+ the maximum.
81
- #
82
- def threads(min, max)
83
- if min > max
84
- raise "The minimum number of threads must be less than the max"
85
- end
86
-
87
- @options[:min_threads] = min
88
- @options[:max_threads] = max
89
- end
90
-
91
- # Use +path+ as the file to store the server info state. This is
92
- # used by pumactl to query and control the server.
93
- #
94
- def state_path(path)
95
- @options[:state] = path.to_s
96
- end
97
- end
98
- end