puma 1.4.0 → 1.5.0
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/.travis.yml +5 -0
- data/History.txt +24 -0
- data/README.md +1 -1
- data/Rakefile +1 -1
- data/ext/puma_http11/ext_help.h +2 -2
- data/ext/puma_http11/puma_http11.c +6 -3
- data/lib/puma/app/status.rb +1 -1
- data/lib/puma/cli.rb +44 -24
- data/lib/puma/configuration.rb +5 -0
- data/lib/puma/const.rb +1 -1
- data/lib/puma/events.rb +13 -0
- data/lib/puma/server.rb +43 -34
- data/lib/puma/thread_pool.rb +6 -4
- data/lib/rack/handler/puma.rb +5 -0
- data/puma.gemspec +2 -2
- data/test/test_app_status.rb +11 -33
- data/test/test_cli.rb +43 -0
- data/test/test_rack_server.rb +5 -5
- data/test/test_ws.rb +7 -15
- data/test/testhelp.rb +0 -4
- metadata +5 -5
data/.travis.yml
CHANGED
data/History.txt
CHANGED
@@ -1,3 +1,27 @@
|
|
1
|
+
=== 1.5.0 / 2012-07-19
|
2
|
+
|
3
|
+
* 7 contributers to this release:
|
4
|
+
* Christian Mayer
|
5
|
+
* Darío Javier Cravero
|
6
|
+
* Dirkjan Bussink
|
7
|
+
* Gianluca Padovani
|
8
|
+
* Santiago Pastorino
|
9
|
+
* Thibault Jouan
|
10
|
+
* tomykaira
|
11
|
+
|
12
|
+
* 6 bug fixes:
|
13
|
+
* Define RSTRING_NOT_MODIFIED for Rubinius
|
14
|
+
* Convert status to integer. Fixes #123
|
15
|
+
* Delete pidfile when stopping the server
|
16
|
+
* Allow compilation with -Werror=format-security option
|
17
|
+
* Fix wrong HTTP version for a HTTP/1.0 request
|
18
|
+
* Use String#bytesize instead of String#length
|
19
|
+
|
20
|
+
* 3 minor features:
|
21
|
+
* Added support for setting RACK_ENV via the CLI, config file, and rack app
|
22
|
+
* Allow Server#run to run sync. Fixes #111
|
23
|
+
* Puma can now run on windows
|
24
|
+
|
1
25
|
=== 1.4.0 / 2012-06-04
|
2
26
|
|
3
27
|
* 1 bug fix:
|
data/README.md
CHANGED
data/Rakefile
CHANGED
@@ -30,7 +30,7 @@ HOE.spec.files -= [".gemtest"]
|
|
30
30
|
|
31
31
|
# puma.gemspec
|
32
32
|
|
33
|
-
file "#{HOE.spec.name}.gemspec" => ['Rakefile'] do |t|
|
33
|
+
file "#{HOE.spec.name}.gemspec" => ['Rakefile', "lib/puma/const.rb"] do |t|
|
34
34
|
puts "Generating #{t.name}"
|
35
35
|
File.open(t.name, 'wb') { |f| f.write HOE.spec.to_ruby }
|
36
36
|
end
|
data/ext/puma_http11/ext_help.h
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
#ifndef ext_help_h
|
2
2
|
#define ext_help_h
|
3
3
|
|
4
|
-
#define RAISE_NOT_NULL(T) if(T == NULL) rb_raise(rb_eArgError, "NULL found for " # T " when shouldn't be.");
|
4
|
+
#define RAISE_NOT_NULL(T) if(T == NULL) rb_raise(rb_eArgError, "%s", "NULL found for " # T " when shouldn't be.");
|
5
5
|
#define DATA_GET(from,type,name) Data_Get_Struct(from,type,name); RAISE_NOT_NULL(name);
|
6
|
-
#define REQUIRE_TYPE(V, T) if(TYPE(V) != T) rb_raise(rb_eTypeError, "Wrong argument type for " # V " required " # T);
|
6
|
+
#define REQUIRE_TYPE(V, T) if(TYPE(V) != T) rb_raise(rb_eTypeError, "%s", "Wrong argument type for " # V " required " # T);
|
7
7
|
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
|
8
8
|
|
9
9
|
#ifdef DEBUG
|
@@ -2,6 +2,9 @@
|
|
2
2
|
* Copyright (c) 2005 Zed A. Shaw
|
3
3
|
* You can redistribute it and/or modify it under the same terms as Ruby.
|
4
4
|
*/
|
5
|
+
|
6
|
+
#define RSTRING_NOT_MODIFIED 1
|
7
|
+
|
5
8
|
#include "ruby.h"
|
6
9
|
#include "ext_help.h"
|
7
10
|
#include <assert.h>
|
@@ -38,7 +41,7 @@ static VALUE global_request_path;
|
|
38
41
|
#define DEF_MAX_LENGTH(N,length) const size_t MAX_##N##_LENGTH = length; const char *MAX_##N##_LENGTH_ERR = "HTTP element " # N " is longer than the " # length " allowed length."
|
39
42
|
|
40
43
|
/** Validates the max length of given input and throws an HttpParserError exception if over. */
|
41
|
-
#define VALIDATE_MAX_LENGTH(len, N) if(len > MAX_##N##_LENGTH) { rb_raise(eHttpParserError, MAX_##N##_LENGTH_ERR); }
|
44
|
+
#define VALIDATE_MAX_LENGTH(len, N) if(len > MAX_##N##_LENGTH) { rb_raise(eHttpParserError, "%s", MAX_##N##_LENGTH_ERR); }
|
42
45
|
|
43
46
|
/** Defines global strings in the init method. */
|
44
47
|
#define DEF_GLOBAL(N, val) global_##N = rb_str_new2(val); rb_global_variable(&global_##N)
|
@@ -377,7 +380,7 @@ VALUE HttpParser_execute(VALUE self, VALUE req_hash, VALUE data, VALUE start)
|
|
377
380
|
|
378
381
|
if(from >= dlen) {
|
379
382
|
rb_free_chars(dptr);
|
380
|
-
rb_raise(eHttpParserError, "Requested start is after data buffer end.");
|
383
|
+
rb_raise(eHttpParserError, "%s", "Requested start is after data buffer end.");
|
381
384
|
} else {
|
382
385
|
http->request = req_hash;
|
383
386
|
http_parser_execute(http, dptr, dlen, from);
|
@@ -386,7 +389,7 @@ VALUE HttpParser_execute(VALUE self, VALUE req_hash, VALUE data, VALUE start)
|
|
386
389
|
VALIDATE_MAX_LENGTH(http_parser_nread(http), HEADER);
|
387
390
|
|
388
391
|
if(http_parser_has_error(http)) {
|
389
|
-
rb_raise(eHttpParserError, "Invalid HTTP format, parsing fails.");
|
392
|
+
rb_raise(eHttpParserError, "%s", "Invalid HTTP format, parsing fails.");
|
390
393
|
} else {
|
391
394
|
return INT2FIX(http_parser_nread(http));
|
392
395
|
}
|
data/lib/puma/app/status.rb
CHANGED
@@ -41,7 +41,7 @@ module Puma
|
|
41
41
|
when "/stats"
|
42
42
|
b = @server.backlog
|
43
43
|
r = @server.running
|
44
|
-
|
44
|
+
return rack_response(200, %Q!{ "backlog": #{b}, "running": #{r} }!)
|
45
45
|
end
|
46
46
|
|
47
47
|
rack_response 404, "Unsupported action", 'text/plain'
|
data/lib/puma/cli.rb
CHANGED
@@ -31,7 +31,6 @@ module Puma
|
|
31
31
|
@status = nil
|
32
32
|
|
33
33
|
@restart = false
|
34
|
-
@temp_status_path = nil
|
35
34
|
|
36
35
|
@listeners = []
|
37
36
|
|
@@ -53,17 +52,10 @@ module Puma
|
|
53
52
|
remove.each do |k|
|
54
53
|
ENV.delete k
|
55
54
|
end
|
56
|
-
|
57
|
-
ENV['RACK_ENV'] ||= "development"
|
58
55
|
end
|
59
56
|
|
60
57
|
def restart_on_stop!
|
61
|
-
|
62
|
-
@restart = true
|
63
|
-
return true
|
64
|
-
else
|
65
|
-
return false
|
66
|
-
end
|
58
|
+
@restart = true
|
67
59
|
end
|
68
60
|
|
69
61
|
def generate_restart_data
|
@@ -137,17 +129,16 @@ module Puma
|
|
137
129
|
end
|
138
130
|
end
|
139
131
|
|
140
|
-
#
|
132
|
+
# Delegate +log+ to +@events+
|
141
133
|
#
|
142
134
|
def log(str)
|
143
|
-
@
|
135
|
+
@events.log str
|
144
136
|
end
|
145
137
|
|
146
|
-
#
|
138
|
+
# Delegate +error+ to +@events+
|
147
139
|
#
|
148
140
|
def error(str)
|
149
|
-
@
|
150
|
-
exit 1
|
141
|
+
@events.error str
|
151
142
|
end
|
152
143
|
|
153
144
|
# Build the OptionParser object to handle the available options.
|
@@ -220,6 +211,11 @@ module Puma
|
|
220
211
|
"Default: inferred" do |cmd|
|
221
212
|
@options[:restart_cmd] = cmd
|
222
213
|
end
|
214
|
+
|
215
|
+
o.on "-e", "--environment ENVIRONMENT",
|
216
|
+
"The environment to run the Rack app on (default development)" do |arg|
|
217
|
+
@options[:environment] = arg
|
218
|
+
end
|
223
219
|
end
|
224
220
|
|
225
221
|
@parser.banner = "puma <options> <rackup file>"
|
@@ -241,6 +237,21 @@ module Puma
|
|
241
237
|
end
|
242
238
|
end
|
243
239
|
|
240
|
+
def set_rack_environment
|
241
|
+
# Try the user option first, then the environment variable,
|
242
|
+
# finally default to development
|
243
|
+
|
244
|
+
ENV['RACK_ENV'] = @options[:environment] ||
|
245
|
+
ENV['RACK_ENV'] ||
|
246
|
+
'development'
|
247
|
+
end
|
248
|
+
|
249
|
+
def delete_pidfile
|
250
|
+
if path = @options[:pidfile]
|
251
|
+
File.unlink path
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
244
255
|
def write_state
|
245
256
|
require 'yaml'
|
246
257
|
|
@@ -268,13 +279,12 @@ module Puma
|
|
268
279
|
|
269
280
|
@config = Puma::Configuration.new @options
|
270
281
|
@config.load
|
271
|
-
|
272
|
-
@temp_status_path = @options[:control_path_temp]
|
273
282
|
end
|
274
283
|
|
275
284
|
def graceful_stop(server)
|
276
285
|
log " - Gracefully stopping, waiting for requests to finish"
|
277
286
|
server.stop(true)
|
287
|
+
delete_pidfile
|
278
288
|
log " - Goodbye!"
|
279
289
|
end
|
280
290
|
|
@@ -284,6 +294,8 @@ module Puma
|
|
284
294
|
def run
|
285
295
|
parse_options
|
286
296
|
|
297
|
+
set_rack_environment
|
298
|
+
|
287
299
|
app = @config.app
|
288
300
|
|
289
301
|
write_pid
|
@@ -298,6 +310,7 @@ module Puma
|
|
298
310
|
|
299
311
|
log "Puma #{Puma::Const::PUMA_VERSION} starting..."
|
300
312
|
log "* Min threads: #{min_t}, max threads: #{max_t}"
|
313
|
+
log "* Environment: #{ENV['RACK_ENV']}"
|
301
314
|
|
302
315
|
@options[:binds].each do |str|
|
303
316
|
uri = URI.parse str
|
@@ -419,14 +432,22 @@ module Puma
|
|
419
432
|
@status = status
|
420
433
|
end
|
421
434
|
|
422
|
-
|
423
|
-
|
424
|
-
|
435
|
+
begin
|
436
|
+
Signal.trap "SIGUSR2" do
|
437
|
+
@restart = true
|
438
|
+
server.begin_restart
|
439
|
+
end
|
440
|
+
rescue Exception
|
441
|
+
log "*** Sorry signal SIGUSR2 not implemented, restart feature disabled!"
|
425
442
|
end
|
426
443
|
|
427
|
-
|
428
|
-
|
429
|
-
|
444
|
+
begin
|
445
|
+
Signal.trap "SIGTERM" do
|
446
|
+
log " - Gracefully stopping, waiting for requests to finish"
|
447
|
+
server.stop false
|
448
|
+
end
|
449
|
+
rescue Exception
|
450
|
+
log "*** Sorry signal SIGTERM not implemented, gracefully stopping feature disabled!"
|
430
451
|
end
|
431
452
|
|
432
453
|
log "Use Ctrl-C to stop"
|
@@ -437,8 +458,6 @@ module Puma
|
|
437
458
|
graceful_stop server
|
438
459
|
end
|
439
460
|
|
440
|
-
File.unlink @temp_status_path if @temp_status_path
|
441
|
-
|
442
461
|
if @restart
|
443
462
|
log "* Restarting..."
|
444
463
|
@status.stop true if @status
|
@@ -448,6 +467,7 @@ module Puma
|
|
448
467
|
|
449
468
|
def stop
|
450
469
|
@server.stop(true) if @server
|
470
|
+
delete_pidfile
|
451
471
|
end
|
452
472
|
end
|
453
473
|
end
|
data/lib/puma/configuration.rb
CHANGED
@@ -208,6 +208,11 @@ module Puma
|
|
208
208
|
def state_path(path)
|
209
209
|
@options[:state] = path.to_s
|
210
210
|
end
|
211
|
+
|
212
|
+
# Set the environment in which the Rack's app will run.
|
213
|
+
def environment(environment)
|
214
|
+
@options[:environment] = environment
|
215
|
+
end
|
211
216
|
end
|
212
217
|
end
|
213
218
|
end
|
data/lib/puma/const.rb
CHANGED
data/lib/puma/events.rb
CHANGED
@@ -20,6 +20,19 @@ module Puma
|
|
20
20
|
|
21
21
|
attr_reader :stdout, :stderr
|
22
22
|
|
23
|
+
# Write +str+ to +@stdout+
|
24
|
+
#
|
25
|
+
def log(str)
|
26
|
+
@stdout.puts str
|
27
|
+
end
|
28
|
+
|
29
|
+
# Write +str+ to +@stderr+
|
30
|
+
#
|
31
|
+
def error(str)
|
32
|
+
@stderr.puts "ERROR: #{str}"
|
33
|
+
exit 1
|
34
|
+
end
|
35
|
+
|
23
36
|
# An HTTP parse error has occured.
|
24
37
|
# +server+ is the Server object, +env+ the request, and +error+ a
|
25
38
|
# parsing exception.
|
data/lib/puma/server.rb
CHANGED
@@ -185,10 +185,13 @@ module Puma
|
|
185
185
|
@thread_pool and @thread_pool.spawned
|
186
186
|
end
|
187
187
|
|
188
|
-
# Runs the server.
|
189
|
-
# The thread is always available via #thread to be join'd
|
188
|
+
# Runs the server.
|
190
189
|
#
|
191
|
-
|
190
|
+
# If +background+ is true (the default) then a thread is spun
|
191
|
+
# up in the background to handle requests. Otherwise requests
|
192
|
+
# are handled synchronously.
|
193
|
+
#
|
194
|
+
def run(background=true)
|
192
195
|
BasicSocket.do_not_reverse_lookup = true
|
193
196
|
|
194
197
|
@status = :run
|
@@ -201,40 +204,45 @@ module Puma
|
|
201
204
|
@thread_pool.auto_trim!(@auto_trim_time)
|
202
205
|
end
|
203
206
|
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
207
|
+
if background
|
208
|
+
@thread = Thread.new { handle_servers }
|
209
|
+
return @thread
|
210
|
+
else
|
211
|
+
handle_servers
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
def handle_servers
|
216
|
+
begin
|
217
|
+
check = @check
|
218
|
+
sockets = @ios
|
219
|
+
pool = @thread_pool
|
220
|
+
|
221
|
+
while @status == :run
|
222
|
+
begin
|
223
|
+
ios = IO.select sockets
|
224
|
+
ios.first.each do |sock|
|
225
|
+
if sock == check
|
226
|
+
break if handle_check
|
227
|
+
else
|
228
|
+
pool << [sock.accept, @envs.fetch(sock, @proto_env)]
|
219
229
|
end
|
220
|
-
rescue Errno::ECONNABORTED
|
221
|
-
# client closed the socket even before accept
|
222
|
-
client.close rescue nil
|
223
|
-
rescue Object => e
|
224
|
-
@events.unknown_error self, e, "Listen loop"
|
225
230
|
end
|
231
|
+
rescue Errno::ECONNABORTED
|
232
|
+
# client closed the socket even before accept
|
233
|
+
client.close rescue nil
|
234
|
+
rescue Object => e
|
235
|
+
@events.unknown_error self, e, "Listen loop"
|
226
236
|
end
|
237
|
+
end
|
227
238
|
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
end
|
239
|
+
graceful_shutdown if @status == :stop
|
240
|
+
ensure
|
241
|
+
unless @status == :restart
|
242
|
+
@ios.each { |i| i.close }
|
243
|
+
@unix_paths.each { |i| File.unlink i }
|
234
244
|
end
|
235
245
|
end
|
236
|
-
|
237
|
-
return @thread
|
238
246
|
end
|
239
247
|
|
240
248
|
# :nodoc:
|
@@ -279,7 +287,7 @@ module Puma
|
|
279
287
|
# a problem with the read operation on the client socket.
|
280
288
|
# Effect is to stop processing when the socket can't fill the buffer
|
281
289
|
# for further parsing.
|
282
|
-
while nparsed < data.
|
290
|
+
while nparsed < data.bytesize
|
283
291
|
nparsed = parser.execute(env, data, nparsed)
|
284
292
|
|
285
293
|
if parser.finished?
|
@@ -313,7 +321,7 @@ module Puma
|
|
313
321
|
return if !chunk or chunk.length == 0 # read failed, stop processing
|
314
322
|
|
315
323
|
data << chunk
|
316
|
-
if data.
|
324
|
+
if data.bytesize >= MAX_HEADER
|
317
325
|
raise HttpParserError,
|
318
326
|
"HEADER is longer than allowed, aborting client early."
|
319
327
|
end
|
@@ -418,6 +426,7 @@ module Puma
|
|
418
426
|
begin
|
419
427
|
begin
|
420
428
|
status, headers, res_body = @app.call(env)
|
429
|
+
status = status.to_i
|
421
430
|
|
422
431
|
if status == -1
|
423
432
|
unless headers.empty? and res_body == []
|
@@ -471,7 +480,7 @@ module Puma
|
|
471
480
|
if status == 200
|
472
481
|
client.write HTTP_10_200
|
473
482
|
else
|
474
|
-
client.write "HTTP/1.
|
483
|
+
client.write "HTTP/1.0 "
|
475
484
|
client.write status.to_s
|
476
485
|
client.write " "
|
477
486
|
client.write HTTP_STATUS_CODES[status]
|
data/lib/puma/thread_pool.rb
CHANGED
@@ -53,15 +53,17 @@ module Puma
|
|
53
53
|
@spawned += 1
|
54
54
|
|
55
55
|
th = Thread.new do
|
56
|
-
todo
|
56
|
+
todo = @todo
|
57
57
|
block = @block
|
58
|
+
mutex = @mutex
|
59
|
+
cond = @cond
|
58
60
|
|
59
61
|
while true
|
60
62
|
work = nil
|
61
63
|
|
62
64
|
continue = true
|
63
65
|
|
64
|
-
|
66
|
+
mutex.synchronize do
|
65
67
|
while todo.empty?
|
66
68
|
if @trim_requested > 0
|
67
69
|
@trim_requested -= 1
|
@@ -75,7 +77,7 @@ module Puma
|
|
75
77
|
end
|
76
78
|
|
77
79
|
@waiting += 1
|
78
|
-
|
80
|
+
cond.wait mutex
|
79
81
|
@waiting -= 1
|
80
82
|
|
81
83
|
if @shutdown
|
@@ -92,7 +94,7 @@ module Puma
|
|
92
94
|
block.call work
|
93
95
|
end
|
94
96
|
|
95
|
-
|
97
|
+
mutex.synchronize do
|
96
98
|
@spawned -= 1
|
97
99
|
@workers.delete th
|
98
100
|
end
|
data/lib/rack/handler/puma.rb
CHANGED
@@ -18,11 +18,16 @@ module Rack
|
|
18
18
|
app = Rack::CommonLogger.new(app, STDOUT)
|
19
19
|
end
|
20
20
|
|
21
|
+
if options[:environment]
|
22
|
+
ENV['RACK_ENV'] = options[:environment].to_s
|
23
|
+
end
|
24
|
+
|
21
25
|
server = ::Puma::Server.new(app)
|
22
26
|
min, max = options[:Threads].split(':', 2)
|
23
27
|
|
24
28
|
puts "Puma #{::Puma::Const::PUMA_VERSION} starting..."
|
25
29
|
puts "* Min threads: #{min}, max threads: #{max}"
|
30
|
+
puts "* Environment: #{ENV['RACK_ENV']}"
|
26
31
|
puts "* Listening on tcp://#{options[:Host]}:#{options[:Port]}"
|
27
32
|
|
28
33
|
server.add_tcp_listener options[:Host], options[:Port]
|
data/puma.gemspec
CHANGED
@@ -2,11 +2,11 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = "puma"
|
5
|
-
s.version = "1.
|
5
|
+
s.version = "1.5.0"
|
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 = "2012-
|
9
|
+
s.date = "2012-07-19"
|
10
10
|
s.description = "Puma is a simple, fast, and highly concurrent HTTP 1.1 server for Ruby web applications. It can be used with any application that supports Rack, and is considered the replacement for Webrick and Mongrel. It was designed to be the go-to server for [Rubinius](http://rubini.us), but also works well with JRuby and MRI. Puma is intended for use in both development and production environments.\n\nUnder the hood, Puma processes requests using a C-optimized Ragel extension (inherited from Mongrel) that provides fast, accurate HTTP 1.1 protocol parsing in a portable way. Puma then serves the request in a thread from an internal thread pool (which you can control). This allows Puma to provide real concurrency for your web application!\n\nWith Rubinius 2.0, Puma will utilize all cores on your CPU with real threads, meaning you won't have to spawn multiple processes to increase throughput. You can expect to see a similar benefit from JRuby.\n\nOn MRI, there is a Global Interpreter Lock (GIL) that ensures only one thread can be run at a time. But if you're doing a lot of blocking IO (such as HTTP calls to external APIs like Twitter), Puma still improves MRI's throughput by allowing blocking IO to be run concurrently (EventMachine-based servers such as Thin turn off this ability, requiring you to use special libraries). Your mileage may vary. In order to get the best throughput, it is highly recommended that you use a Ruby implementation with real threads like [Rubinius](http://rubini.us) or [JRuby](http://jruby.org)."
|
11
11
|
s.email = ["evan@phx.io"]
|
12
12
|
s.executables = ["puma", "pumactl"]
|
data/test/test_app_status.rb
CHANGED
@@ -28,79 +28,57 @@ class TestAppStatus < Test::Unit::TestCase
|
|
28
28
|
@app.auth_token = nil
|
29
29
|
end
|
30
30
|
|
31
|
-
def lint(
|
31
|
+
def lint(uri)
|
32
32
|
app = Rack::Lint.new @app
|
33
|
-
mock_env = Rack::MockRequest.env_for
|
33
|
+
mock_env = Rack::MockRequest.env_for uri
|
34
34
|
app.call mock_env
|
35
35
|
end
|
36
36
|
|
37
37
|
def test_bad_token
|
38
38
|
@app.auth_token = "abcdef"
|
39
39
|
|
40
|
-
|
41
|
-
|
42
|
-
status, _, _ = @app.call env
|
40
|
+
status, _, _ = lint('/whatever')
|
43
41
|
|
44
42
|
assert_equal 403, status
|
45
|
-
lint(env)
|
46
43
|
end
|
47
44
|
|
48
45
|
def test_good_token
|
49
46
|
@app.auth_token = "abcdef"
|
50
47
|
|
51
|
-
|
52
|
-
'PATH_INFO' => "/whatever",
|
53
|
-
'QUERY_STRING' => "token=abcdef"
|
54
|
-
}
|
55
|
-
|
56
|
-
status, _, _ = @app.call env
|
48
|
+
status, _, _ = lint('/whatever?token=abcdef')
|
57
49
|
|
58
50
|
assert_equal 404, status
|
59
|
-
lint(env)
|
60
51
|
end
|
61
52
|
|
62
53
|
def test_unsupported
|
63
|
-
|
64
|
-
|
65
|
-
status, _, _ = @app.call env
|
54
|
+
status, _, _ = lint('/not-real')
|
66
55
|
|
67
56
|
assert_equal 404, status
|
68
|
-
lint(env)
|
69
57
|
end
|
70
58
|
|
71
59
|
def test_stop
|
72
|
-
|
73
|
-
|
74
|
-
status, _ , body = @app.call env
|
60
|
+
status, _ , app = lint('/stop')
|
75
61
|
|
76
62
|
assert_equal :stop, @server.status
|
77
63
|
assert_equal 200, status
|
78
|
-
assert_equal ['{ "status": "ok" }'],
|
79
|
-
lint(env)
|
64
|
+
assert_equal ['{ "status": "ok" }'], app.enum_for.to_a
|
80
65
|
end
|
81
66
|
|
82
67
|
def test_halt
|
83
|
-
|
84
|
-
|
85
|
-
status, _ , body = @app.call env
|
68
|
+
status, _ , app = lint('/halt')
|
86
69
|
|
87
70
|
assert_equal :halt, @server.status
|
88
71
|
assert_equal 200, status
|
89
|
-
assert_equal ['{ "status": "ok" }'],
|
90
|
-
lint(env)
|
72
|
+
assert_equal ['{ "status": "ok" }'], app.enum_for.to_a
|
91
73
|
end
|
92
74
|
|
93
75
|
def test_stats
|
94
|
-
env = { 'PATH_INFO' => "/stats" }
|
95
|
-
|
96
76
|
@server.backlog = 1
|
97
77
|
@server.running = 9
|
98
78
|
|
99
|
-
status, _ ,
|
79
|
+
status, _ , app = lint('/stats')
|
100
80
|
|
101
81
|
assert_equal 200, status
|
102
|
-
assert_equal ['{ "backlog": 1, "running": 9 }'],
|
103
|
-
lint(env)
|
82
|
+
assert_equal ['{ "backlog": 1, "running": 9 }'], app.enum_for.to_a
|
104
83
|
end
|
105
|
-
|
106
84
|
end
|
data/test/test_cli.rb
CHANGED
@@ -5,6 +5,7 @@ require 'tempfile'
|
|
5
5
|
|
6
6
|
class TestCLI < Test::Unit::TestCase
|
7
7
|
def setup
|
8
|
+
@environment = 'production'
|
8
9
|
@tmp_file = Tempfile.new("puma-test")
|
9
10
|
@tmp_path = @tmp_file.path
|
10
11
|
@tmp_file.close!
|
@@ -26,6 +27,40 @@ class TestCLI < Test::Unit::TestCase
|
|
26
27
|
cli.write_pid
|
27
28
|
|
28
29
|
assert_equal File.read(@tmp_path).strip.to_i, Process.pid
|
30
|
+
|
31
|
+
cli.stop
|
32
|
+
assert !File.exist?(@tmp_path), "Pid file shouldn't exist anymore"
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_control_for_tcp
|
36
|
+
url = "tcp://127.0.0.1:9877/"
|
37
|
+
sin = StringIO.new
|
38
|
+
sout = StringIO.new
|
39
|
+
cli = Puma::CLI.new ["-b", "tcp://127.0.0.1:9876",
|
40
|
+
"--control", url,
|
41
|
+
"--control-token", "",
|
42
|
+
"test/lobster.ru"], sin, sout
|
43
|
+
cli.parse_options
|
44
|
+
|
45
|
+
thread_exception = nil
|
46
|
+
t = Thread.new do
|
47
|
+
begin
|
48
|
+
cli.run
|
49
|
+
rescue Exception => e
|
50
|
+
thread_exception = e
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
sleep 1
|
55
|
+
|
56
|
+
s = TCPSocket.new "127.0.0.1", 9877
|
57
|
+
s << "GET /stats HTTP/1.0\r\n\r\n"
|
58
|
+
body = s.read
|
59
|
+
assert_equal '{ "backlog": 0, "running": 0 }', body.split("\r\n").last
|
60
|
+
|
61
|
+
cli.stop
|
62
|
+
t.join
|
63
|
+
assert_equal nil, thread_exception
|
29
64
|
end
|
30
65
|
|
31
66
|
unless defined?(JRUBY_VERSION) || RbConfig::CONFIG["host_os"] =~ /mingw|mswin/
|
@@ -125,4 +160,12 @@ class TestCLI < Test::Unit::TestCase
|
|
125
160
|
assert_equal 'baz/qux', $LOAD_PATH[0]
|
126
161
|
$LOAD_PATH.shift
|
127
162
|
end
|
163
|
+
|
164
|
+
def test_environment
|
165
|
+
cli = Puma::CLI.new ["--environment", @environment]
|
166
|
+
cli.parse_options
|
167
|
+
cli.set_rack_environment
|
168
|
+
|
169
|
+
assert_equal ENV['RACK_ENV'], @environment
|
170
|
+
end
|
128
171
|
end
|
data/test/test_rack_server.rb
CHANGED
@@ -66,7 +66,7 @@ class TestRackServer < Test::Unit::TestCase
|
|
66
66
|
|
67
67
|
@server.run
|
68
68
|
|
69
|
-
hit(['http://
|
69
|
+
hit(['http://127.0.0.1:9998/test'])
|
70
70
|
|
71
71
|
stop
|
72
72
|
|
@@ -83,7 +83,7 @@ class TestRackServer < Test::Unit::TestCase
|
|
83
83
|
|
84
84
|
big = "x" * (1024 * 16)
|
85
85
|
|
86
|
-
Net::HTTP.post_form URI.parse('http://
|
86
|
+
Net::HTTP.post_form URI.parse('http://127.0.0.1:9998/test'),
|
87
87
|
{ "big" => big }
|
88
88
|
|
89
89
|
stop
|
@@ -98,7 +98,7 @@ class TestRackServer < Test::Unit::TestCase
|
|
98
98
|
@server.app = lambda { |env| input = env; @simple.call(env) }
|
99
99
|
@server.run
|
100
100
|
|
101
|
-
hit(['http://
|
101
|
+
hit(['http://127.0.0.1:9998/test/a/b/c'])
|
102
102
|
|
103
103
|
stop
|
104
104
|
|
@@ -115,7 +115,7 @@ class TestRackServer < Test::Unit::TestCase
|
|
115
115
|
|
116
116
|
@server.run
|
117
117
|
|
118
|
-
hit(['http://
|
118
|
+
hit(['http://127.0.0.1:9998/test'])
|
119
119
|
|
120
120
|
stop
|
121
121
|
|
@@ -131,7 +131,7 @@ class TestRackServer < Test::Unit::TestCase
|
|
131
131
|
|
132
132
|
@server.run
|
133
133
|
|
134
|
-
hit(['http://
|
134
|
+
hit(['http://127.0.0.1:9998/test'])
|
135
135
|
|
136
136
|
stop
|
137
137
|
|
data/test/test_ws.rb
CHANGED
@@ -25,19 +25,15 @@ class WebServerTest < Test::Unit::TestCase
|
|
25
25
|
@server = Server.new @tester, Events.strings
|
26
26
|
@server.add_tcp_listener "127.0.0.1", 9998
|
27
27
|
|
28
|
-
|
29
|
-
@server.run
|
30
|
-
end
|
28
|
+
@server.run
|
31
29
|
end
|
32
30
|
|
33
31
|
def teardown
|
34
|
-
|
35
|
-
@server.stop(true)
|
36
|
-
end
|
32
|
+
@server.stop(true)
|
37
33
|
end
|
38
34
|
|
39
35
|
def test_simple_server
|
40
|
-
hit(['http://
|
36
|
+
hit(['http://127.0.0.1:9998/test'])
|
41
37
|
assert @tester.ran_test, "Handler didn't really run"
|
42
38
|
end
|
43
39
|
|
@@ -73,17 +69,13 @@ class WebServerTest < Test::Unit::TestCase
|
|
73
69
|
end
|
74
70
|
|
75
71
|
def test_bad_client
|
76
|
-
|
77
|
-
do_test("GET /test HTTP/BAD", 3)
|
78
|
-
end
|
72
|
+
do_test("GET /test HTTP/BAD", 3)
|
79
73
|
end
|
80
74
|
|
81
75
|
def test_header_is_too_long
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
do_test(long, long.length/2, 10)
|
86
|
-
end
|
76
|
+
long = "GET /test HTTP/1.1\r\n" + ("X-Big: stuff\r\n" * 15000) + "\r\n"
|
77
|
+
assert_raises Errno::ECONNRESET, Errno::EPIPE, Errno::ECONNABORTED, Errno::EINVAL, IOError do
|
78
|
+
do_test(long, long.length/2, 10)
|
87
79
|
end
|
88
80
|
end
|
89
81
|
|
data/test/testhelp.rb
CHANGED
@@ -16,10 +16,6 @@ require 'stringio'
|
|
16
16
|
|
17
17
|
require 'puma'
|
18
18
|
|
19
|
-
def redirect_test_io
|
20
|
-
yield
|
21
|
-
end
|
22
|
-
|
23
19
|
# Either takes a string to do a get request against, or a tuple of [URI, HTTP] where
|
24
20
|
# HTTP is some kind of Net::HTTP request object (POST, HEAD, etc.)
|
25
21
|
def hit(uris)
|
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:
|
4
|
+
hash: 3
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 1
|
8
|
-
-
|
8
|
+
- 5
|
9
9
|
- 0
|
10
|
-
version: 1.
|
10
|
+
version: 1.5.0
|
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: 2012-
|
18
|
+
date: 2012-07-19 00:00:00 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
name: rack
|
@@ -198,7 +198,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
198
198
|
requirements: []
|
199
199
|
|
200
200
|
rubyforge_project: puma
|
201
|
-
rubygems_version: 1.8.
|
201
|
+
rubygems_version: 1.8.18
|
202
202
|
signing_key:
|
203
203
|
specification_version: 3
|
204
204
|
summary: Puma is a simple, fast, and highly concurrent HTTP 1.1 server for Ruby web applications
|