puma 0.8.2-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.

Files changed (63) hide show
  1. data/.gemtest +0 -0
  2. data/COPYING +55 -0
  3. data/Gemfile +6 -0
  4. data/History.txt +69 -0
  5. data/LICENSE +26 -0
  6. data/Manifest.txt +60 -0
  7. data/README.md +60 -0
  8. data/Rakefile +12 -0
  9. data/TODO +5 -0
  10. data/bin/puma +15 -0
  11. data/examples/builder.rb +29 -0
  12. data/examples/camping/README +3 -0
  13. data/examples/camping/blog.rb +294 -0
  14. data/examples/camping/tepee.rb +149 -0
  15. data/examples/httpd.conf +474 -0
  16. data/examples/mime.yaml +3 -0
  17. data/examples/mongrel.conf +9 -0
  18. data/examples/monitrc +57 -0
  19. data/examples/random_thrash.rb +19 -0
  20. data/examples/simpletest.rb +52 -0
  21. data/examples/webrick_compare.rb +20 -0
  22. data/ext/puma_http11/PumaHttp11Service.java +13 -0
  23. data/ext/puma_http11/ext_help.h +15 -0
  24. data/ext/puma_http11/extconf.rb +5 -0
  25. data/ext/puma_http11/http11_parser.c +1225 -0
  26. data/ext/puma_http11/http11_parser.h +63 -0
  27. data/ext/puma_http11/http11_parser.java.rl +161 -0
  28. data/ext/puma_http11/http11_parser.rl +146 -0
  29. data/ext/puma_http11/http11_parser_common.rl +54 -0
  30. data/ext/puma_http11/org/jruby/puma/Http11.java +225 -0
  31. data/ext/puma_http11/org/jruby/puma/Http11Parser.java +488 -0
  32. data/ext/puma_http11/puma_http11.c +482 -0
  33. data/lib/puma.rb +18 -0
  34. data/lib/puma/cli.rb +164 -0
  35. data/lib/puma/const.rb +132 -0
  36. data/lib/puma/events.rb +36 -0
  37. data/lib/puma/gems.rb +20 -0
  38. data/lib/puma/mime_types.yml +616 -0
  39. data/lib/puma/rack_patch.rb +22 -0
  40. data/lib/puma/server.rb +429 -0
  41. data/lib/puma/thread_pool.rb +95 -0
  42. data/lib/puma/utils.rb +44 -0
  43. data/lib/puma_http11.jar +0 -0
  44. data/lib/rack/handler/puma.rb +48 -0
  45. data/puma.gemspec +40 -0
  46. data/tasks/gem.rake +24 -0
  47. data/tasks/java.rake +12 -0
  48. data/tasks/native.rake +36 -0
  49. data/tasks/ragel.rake +24 -0
  50. data/test/lobster.ru +4 -0
  51. data/test/mime.yaml +3 -0
  52. data/test/test_cli.rb +19 -0
  53. data/test/test_http10.rb +27 -0
  54. data/test/test_http11.rb +151 -0
  55. data/test/test_persistent.rb +205 -0
  56. data/test/test_rack_handler.rb +10 -0
  57. data/test/test_rack_server.rb +122 -0
  58. data/test/test_thread_pool.rb +102 -0
  59. data/test/test_unix_socket.rb +37 -0
  60. data/test/test_ws.rb +97 -0
  61. data/test/testhelp.rb +41 -0
  62. data/tools/trickletest.rb +45 -0
  63. metadata +163 -0
@@ -0,0 +1,205 @@
1
+ require 'puma'
2
+ require 'test/unit'
3
+ require 'timeout'
4
+
5
+ class TestPersistent < Test::Unit::TestCase
6
+ def setup
7
+ @valid_request = "GET / HTTP/1.1\r\nHost: test.com\r\nContent-Type: text/plain\r\n\r\n"
8
+ @close_request = "GET / HTTP/1.1\r\nHost: test.com\r\nContent-Type: text/plain\r\nConnection: close\r\n\r\n"
9
+ @http10_request = "GET / HTTP/1.0\r\nHost: test.com\r\nContent-Type: text/plain\r\n\r\n"
10
+ @keep_request = "GET / HTTP/1.0\r\nHost: test.com\r\nContent-Type: text/plain\r\nConnection: Keep-Alive\r\n\r\n"
11
+
12
+ @valid_post = "POST / HTTP/1.1\r\nHost: test.com\r\nContent-Type: text/plain\r\nContent-Length: 5\r\n\r\nhello"
13
+
14
+ @headers = { "X-Header" => "Works" }
15
+ @body = ["Hello"]
16
+ @inputs = []
17
+
18
+ @simple = lambda do |env|
19
+ @inputs << env['rack.input']
20
+ [200, @headers, @body]
21
+ end
22
+
23
+ @server = Puma::Server.new @simple
24
+ @server.add_tcp_listener "127.0.0.1", 9988
25
+ @server.run
26
+
27
+ @client = TCPSocket.new "127.0.0.1", 9988
28
+ end
29
+
30
+ def teardown
31
+ @client.close
32
+ @server.stop(true)
33
+ end
34
+
35
+ def lines(count, s=@client)
36
+ str = ""
37
+ timeout(5) do
38
+ count.times { str << s.gets }
39
+ end
40
+ str
41
+ end
42
+
43
+ def test_one_with_content_length
44
+ @client << @valid_request
45
+ sz = @body[0].size.to_s
46
+
47
+ assert_equal "HTTP/1.1 200 OK\r\nX-Header: Works\r\nContent-Length: #{sz}\r\n\r\n", lines(4)
48
+ assert_equal "Hello", @client.read(5)
49
+ end
50
+
51
+ def test_two_back_to_back
52
+ @client << @valid_request
53
+ sz = @body[0].size.to_s
54
+
55
+ assert_equal "HTTP/1.1 200 OK\r\nX-Header: Works\r\nContent-Length: #{sz}\r\n\r\n", lines(4)
56
+ assert_equal "Hello", @client.read(5)
57
+
58
+ @client << @valid_request
59
+ sz = @body[0].size.to_s
60
+
61
+ assert_equal "HTTP/1.1 200 OK\r\nX-Header: Works\r\nContent-Length: #{sz}\r\n\r\n", lines(4)
62
+ assert_equal "Hello", @client.read(5)
63
+ end
64
+
65
+ def test_post_then_get
66
+ @client << @valid_post
67
+ sz = @body[0].size.to_s
68
+
69
+ assert_equal "HTTP/1.1 200 OK\r\nX-Header: Works\r\nContent-Length: #{sz}\r\n\r\n", lines(4)
70
+ assert_equal "Hello", @client.read(5)
71
+
72
+ @client << @valid_request
73
+ sz = @body[0].size.to_s
74
+
75
+ assert_equal "HTTP/1.1 200 OK\r\nX-Header: Works\r\nContent-Length: #{sz}\r\n\r\n", lines(4)
76
+ assert_equal "Hello", @client.read(5)
77
+ end
78
+
79
+ def test_chunked
80
+ @body << "Chunked"
81
+
82
+ @client << @valid_request
83
+
84
+ assert_equal "HTTP/1.1 200 OK\r\nX-Header: Works\r\nTransfer-Encoding: chunked\r\n\r\n5\r\nHello\r\n7\r\nChunked\r\n0\r\n\r\n", lines(10)
85
+ end
86
+
87
+ def test_no_chunked_in_http10
88
+ @body << "Chunked"
89
+
90
+ @client << @http10_request
91
+
92
+ assert_equal "HTTP/1.0 200 OK\r\nX-Header: Works\r\nConnection: close\r\n\r\n", lines(4)
93
+ assert_equal "HelloChunked", @client.read
94
+ end
95
+
96
+ def test_hex
97
+ str = "This is longer and will be in hex"
98
+ @body << str
99
+
100
+ @client << @valid_request
101
+
102
+ assert_equal "HTTP/1.1 200 OK\r\nX-Header: Works\r\nTransfer-Encoding: chunked\r\n\r\n5\r\nHello\r\n#{str.size.to_s(16)}\r\n#{str}\r\n0\r\n\r\n", lines(10)
103
+
104
+ end
105
+
106
+ def test_client11_close
107
+ @client << @close_request
108
+ sz = @body[0].size.to_s
109
+
110
+ assert_equal "HTTP/1.1 200 OK\r\nX-Header: Works\r\nConnection: close\r\nContent-Length: #{sz}\r\n\r\n", lines(5)
111
+ assert_equal "Hello", @client.read(5)
112
+ end
113
+
114
+ def test_client10_close
115
+ @client << @http10_request
116
+ sz = @body[0].size.to_s
117
+
118
+ assert_equal "HTTP/1.0 200 OK\r\nX-Header: Works\r\nConnection: close\r\nContent-Length: #{sz}\r\n\r\n", lines(5)
119
+ assert_equal "Hello", @client.read(5)
120
+ end
121
+
122
+ def test_one_with_keep_alive_header
123
+ @client << @keep_request
124
+ sz = @body[0].size.to_s
125
+
126
+ assert_equal "HTTP/1.0 200 OK\r\nX-Header: Works\r\nContent-Length: #{sz}\r\n\r\n", lines(4)
127
+ assert_equal "Hello", @client.read(5)
128
+ end
129
+
130
+ def test_persistent_timeout
131
+ @server.persistent_timeout = 2
132
+ @client << @valid_request
133
+ sz = @body[0].size.to_s
134
+
135
+ assert_equal "HTTP/1.1 200 OK\r\nX-Header: Works\r\nContent-Length: #{sz}\r\n\r\n", lines(4)
136
+ assert_equal "Hello", @client.read(5)
137
+
138
+ sleep 3
139
+
140
+ assert_raises EOFError do
141
+ @client.read_nonblock(1)
142
+ end
143
+ end
144
+
145
+ def test_app_sets_content_length
146
+ @body = ["hello", " world"]
147
+ @headers['Content-Length'] = "11"
148
+
149
+ @client << @valid_request
150
+
151
+ assert_equal "HTTP/1.1 200 OK\r\nX-Header: Works\r\nContent-Length: 11\r\n\r\n",
152
+ lines(4)
153
+ assert_equal "hello world", @client.read(11)
154
+ end
155
+
156
+ def test_allow_app_to_chunk_itself
157
+ @headers = {'Transfer-Encoding' => "chunked" }
158
+
159
+ @body = ["5\r\nhello\r\n0\r\n\r\n"]
160
+
161
+ @client << @valid_request
162
+
163
+ assert_equal "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n5\r\nhello\r\n0\r\n\r\n", lines(7)
164
+ end
165
+
166
+
167
+ def test_two_requests_in_one_chunk
168
+ @server.persistent_timeout = 3
169
+
170
+ req = @valid_request.to_s
171
+ req << "GET /second HTTP/1.1\r\nHost: test.com\r\nContent-Type: text/plain\r\n\r\n"
172
+
173
+ @client << req
174
+
175
+ sz = @body[0].size.to_s
176
+
177
+ assert_equal "HTTP/1.1 200 OK\r\nX-Header: Works\r\nContent-Length: #{sz}\r\n\r\n", lines(4)
178
+ assert_equal "Hello", @client.read(5)
179
+
180
+ assert_equal "HTTP/1.1 200 OK\r\nX-Header: Works\r\nContent-Length: #{sz}\r\n\r\n", lines(4)
181
+ assert_equal "Hello", @client.read(5)
182
+ end
183
+
184
+ def test_second_request_not_in_first_req_body
185
+ @server.persistent_timeout = 3
186
+
187
+ req = @valid_request.to_s
188
+ req << "GET /second HTTP/1.1\r\nHost: test.com\r\nContent-Type: text/plain\r\n\r\n"
189
+
190
+ @client << req
191
+
192
+ sz = @body[0].size.to_s
193
+
194
+ assert_equal "HTTP/1.1 200 OK\r\nX-Header: Works\r\nContent-Length: #{sz}\r\n\r\n", lines(4)
195
+ assert_equal "Hello", @client.read(5)
196
+
197
+ assert_equal "HTTP/1.1 200 OK\r\nX-Header: Works\r\nContent-Length: #{sz}\r\n\r\n", lines(4)
198
+ assert_equal "Hello", @client.read(5)
199
+
200
+ assert_equal "", @inputs[0].string
201
+ assert_equal "", @inputs[1].string
202
+
203
+ end
204
+
205
+ end
@@ -0,0 +1,10 @@
1
+ require 'test/unit'
2
+
3
+ class TestPumaUnixSocket < Test::Unit::TestCase
4
+ def test_handler
5
+ handler = Rack::Handler.get(:puma)
6
+ assert_equal Rack::Handler::Puma, handler
7
+ handler = Rack::Handler.get('Puma')
8
+ assert_equal Rack::Handler::Puma, handler
9
+ end
10
+ end
@@ -0,0 +1,122 @@
1
+ require 'test/unit'
2
+ require 'puma'
3
+ require 'rack/lint'
4
+ require 'test/testhelp'
5
+ require 'rack/commonlogger'
6
+ require 'puma/rack_patch'
7
+
8
+ class TestRackServer < Test::Unit::TestCase
9
+
10
+ class ErrorChecker
11
+ def initialize(app)
12
+ @app = app
13
+ @exception = nil
14
+ @env = nil
15
+ end
16
+
17
+ attr_reader :exception, :env
18
+
19
+ def call(env)
20
+ begin
21
+ @env = env
22
+ return @app.call(env)
23
+ rescue Exception => e
24
+ @exception = e
25
+
26
+ [
27
+ 500,
28
+ { "X-Exception" => e.message, "X-Exception-Class" => e.class.to_s },
29
+ ["Error detected"]
30
+ ]
31
+ end
32
+ end
33
+ end
34
+
35
+ class ServerLint < Rack::Lint
36
+ def call(env)
37
+ assert("No env given") { env }
38
+ check_env env
39
+
40
+ @app.call(env)
41
+ end
42
+ end
43
+
44
+ def setup
45
+ @valid_request = "GET / HTTP/1.1\r\nHost: test.com\r\nContent-Type: text/plain\r\n\r\n"
46
+
47
+ @simple = lambda { |env| [200, { "X-Header" => "Works" }, ["Hello"]] }
48
+ @server = Puma::Server.new @simple
49
+ @server.add_tcp_listener "127.0.0.1", 9998
50
+
51
+ @stopped = false
52
+ end
53
+
54
+ def stop
55
+ @server.stop(true)
56
+ @stopped = true
57
+ end
58
+
59
+ def teardown
60
+ @server.stop(true) unless @stopped
61
+ end
62
+
63
+ def test_lint
64
+ @checker = ErrorChecker.new ServerLint.new(@simple)
65
+ @server.app = @checker
66
+
67
+ @server.run
68
+
69
+ hit(['http://localhost:9998/test'])
70
+
71
+ stop
72
+
73
+ if exc = @checker.exception
74
+ raise exc
75
+ end
76
+ end
77
+
78
+ def test_path_info
79
+ input = nil
80
+ @server.app = lambda { |env| input = env; @simple.call(env) }
81
+ @server.run
82
+
83
+ hit(['http://localhost:9998/test/a/b/c'])
84
+
85
+ stop
86
+
87
+ assert_equal "/test/a/b/c", input['PATH_INFO']
88
+ end
89
+
90
+ def test_after_reply
91
+ closed = false
92
+
93
+ @server.app = lambda do |env|
94
+ env['rack.after_reply'] << lambda { closed = true }
95
+ @simple.call(env)
96
+ end
97
+
98
+ @server.run
99
+
100
+ hit(['http://localhost:9998/test'])
101
+
102
+ stop
103
+
104
+ assert_equal true, closed
105
+ end
106
+
107
+ def test_common_logger
108
+ log = StringIO.new
109
+
110
+ logger = Rack::CommonLogger.new(@simple, log)
111
+
112
+ @server.app = logger
113
+
114
+ @server.run
115
+
116
+ hit(['http://localhost:9998/test'])
117
+
118
+ stop
119
+
120
+ assert_match %r!GET /test HTTP/1\.1!, log.string
121
+ end
122
+ end
@@ -0,0 +1,102 @@
1
+ require 'test/unit'
2
+
3
+ require 'puma/thread_pool'
4
+
5
+ class TestThreadPool < Test::Unit::TestCase
6
+
7
+ def teardown
8
+ @pool.shutdown if @pool
9
+ end
10
+
11
+ def new_pool(min, max, &blk)
12
+ blk = proc { } unless blk
13
+ @pool = Puma::ThreadPool.new(min, max, &blk)
14
+ end
15
+
16
+ def pause
17
+ sleep 0.2
18
+ end
19
+
20
+ def test_append_spawns
21
+ saw = []
22
+
23
+ pool = new_pool(0, 1) do |work|
24
+ saw << work
25
+ end
26
+
27
+ pool << 1
28
+
29
+ pause
30
+
31
+ assert_equal [1], saw
32
+ assert_equal 1, pool.spawned
33
+ end
34
+
35
+ def test_append_queues_on_max
36
+ finish = false
37
+ pool = new_pool(0, 1) { Thread.pass until finish }
38
+
39
+ pool << 1
40
+ pool << 2
41
+ pool << 3
42
+
43
+ pause
44
+
45
+ assert_equal 2, pool.backlog
46
+
47
+ finish = true
48
+ end
49
+
50
+ def test_trim
51
+ pool = new_pool(0, 1)
52
+
53
+ pool << 1
54
+
55
+ pause
56
+
57
+ assert_equal 1, pool.spawned
58
+ pool.trim
59
+
60
+ pause
61
+ assert_equal 0, pool.spawned
62
+ end
63
+
64
+ def test_trim_leaves_min
65
+ finish = false
66
+ pool = new_pool(1, 2) { Thread.pass until finish }
67
+
68
+ pool << 1
69
+ pool << 2
70
+
71
+ finish = true
72
+
73
+ assert_equal 2, pool.spawned
74
+ pool.trim
75
+ pause
76
+
77
+ assert_equal 1, pool.spawned
78
+ pool.trim
79
+ pause
80
+
81
+ assert_equal 1, pool.spawned
82
+
83
+ end
84
+
85
+ def test_trim_doesnt_overtrim
86
+ finish = false
87
+ pool = new_pool(1, 2) { Thread.pass until finish }
88
+
89
+ pool << 1
90
+ pool << 2
91
+
92
+ assert_equal 2, pool.spawned
93
+ pool.trim
94
+ pool.trim
95
+
96
+ finish = true
97
+
98
+ pause
99
+
100
+ assert_equal 1, pool.spawned
101
+ end
102
+ end
@@ -0,0 +1,37 @@
1
+ require 'test/unit'
2
+ require 'puma/server'
3
+
4
+ require 'socket'
5
+
6
+ # UNIX sockets are not recommended on JRuby
7
+ unless defined?(JRUBY_VERSION)
8
+ class TestPumaUnixSocket < Test::Unit::TestCase
9
+
10
+ App = lambda { |env| [200, {}, ["Works"]] }
11
+
12
+ Path = "test/puma.sock"
13
+
14
+ def setup
15
+ @server = Puma::Server.new App
16
+ @server.add_unix_listener Path
17
+ @server.run
18
+ end
19
+
20
+ def teardown
21
+ @server.stop(true)
22
+ File.unlink Path if File.exists? Path
23
+ end
24
+
25
+ def test_server
26
+ sock = UNIXSocket.new Path
27
+
28
+ sock << "GET / HTTP/1.0\r\nHost: blah.com\r\n\r\n"
29
+
30
+ expected = "HTTP/1.0 200 OK\r\nConnection: close\r\nContent-Length: 5\r\n\r\nWorks"
31
+
32
+ assert_equal expected, sock.read(expected.size)
33
+
34
+ sock.close
35
+ end
36
+ end
37
+ end