mongrel 1.1.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 mongrel might be problematic. Click here for more details.

Files changed (73) hide show
  1. data.tar.gz.sig +1 -0
  2. data/CHANGELOG +12 -0
  3. data/COPYING +55 -0
  4. data/LICENSE +55 -0
  5. data/Manifest +69 -0
  6. data/README +74 -0
  7. data/TODO +5 -0
  8. data/bin/mongrel_rails +283 -0
  9. data/examples/builder.rb +29 -0
  10. data/examples/camping/README +3 -0
  11. data/examples/camping/blog.rb +294 -0
  12. data/examples/camping/tepee.rb +149 -0
  13. data/examples/httpd.conf +474 -0
  14. data/examples/mime.yaml +3 -0
  15. data/examples/mongrel.conf +9 -0
  16. data/examples/mongrel_simple_ctrl.rb +92 -0
  17. data/examples/mongrel_simple_service.rb +116 -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/http11/ext_help.h +14 -0
  23. data/ext/http11/extconf.rb +6 -0
  24. data/ext/http11/http11.c +402 -0
  25. data/ext/http11/http11_parser.c +1221 -0
  26. data/ext/http11/http11_parser.h +49 -0
  27. data/ext/http11/http11_parser.java.rl +170 -0
  28. data/ext/http11/http11_parser.rl +152 -0
  29. data/ext/http11/http11_parser_common.rl +54 -0
  30. data/ext/http11_java/Http11Service.java +13 -0
  31. data/ext/http11_java/org/jruby/mongrel/Http11.java +266 -0
  32. data/ext/http11_java/org/jruby/mongrel/Http11Parser.java +572 -0
  33. data/lib/http11.jar +0 -0
  34. data/lib/mongrel.rb +355 -0
  35. data/lib/mongrel/camping.rb +107 -0
  36. data/lib/mongrel/cgi.rb +181 -0
  37. data/lib/mongrel/command.rb +222 -0
  38. data/lib/mongrel/configurator.rb +388 -0
  39. data/lib/mongrel/const.rb +110 -0
  40. data/lib/mongrel/debug.rb +203 -0
  41. data/lib/mongrel/gems.rb +22 -0
  42. data/lib/mongrel/handlers.rb +468 -0
  43. data/lib/mongrel/header_out.rb +28 -0
  44. data/lib/mongrel/http_request.rb +155 -0
  45. data/lib/mongrel/http_response.rb +163 -0
  46. data/lib/mongrel/init.rb +10 -0
  47. data/lib/mongrel/mime_types.yml +616 -0
  48. data/lib/mongrel/rails.rb +185 -0
  49. data/lib/mongrel/stats.rb +89 -0
  50. data/lib/mongrel/tcphack.rb +18 -0
  51. data/lib/mongrel/uri_classifier.rb +76 -0
  52. data/mongrel-public_cert.pem +20 -0
  53. data/mongrel.gemspec +263 -0
  54. data/setup.rb +1585 -0
  55. data/test/mime.yaml +3 -0
  56. data/test/mongrel.conf +1 -0
  57. data/test/test_cgi_wrapper.rb +26 -0
  58. data/test/test_command.rb +86 -0
  59. data/test/test_conditional.rb +107 -0
  60. data/test/test_configurator.rb +87 -0
  61. data/test/test_debug.rb +25 -0
  62. data/test/test_handlers.rb +103 -0
  63. data/test/test_http11.rb +156 -0
  64. data/test/test_redirect_handler.rb +44 -0
  65. data/test/test_request_progress.rb +99 -0
  66. data/test/test_response.rb +127 -0
  67. data/test/test_stats.rb +35 -0
  68. data/test/test_uriclassifier.rb +261 -0
  69. data/test/test_ws.rb +115 -0
  70. data/test/testhelp.rb +66 -0
  71. data/tools/trickletest.rb +45 -0
  72. metadata +186 -0
  73. metadata.gz.sig +4 -0
@@ -0,0 +1,261 @@
1
+ # Copyright (c) 2005 Zed A. Shaw
2
+ # You can redistribute it and/or modify it under the same terms as Ruby.
3
+ #
4
+ # Additional work donated by contributors. See http://mongrel.rubyforge.org/attributions.html
5
+ # for more information.
6
+
7
+ require 'test/testhelp'
8
+
9
+ include Mongrel
10
+
11
+ class URIClassifierTest < Test::Unit::TestCase
12
+
13
+ def test_uri_finding
14
+ uri_classifier = URIClassifier.new
15
+ uri_classifier.register("/test", 1)
16
+
17
+ script_name, path_info, value = uri_classifier.resolve("/test")
18
+ assert_equal 1, value
19
+ assert_equal "/test", script_name
20
+ end
21
+
22
+ def test_root_handler_only
23
+ uri_classifier = URIClassifier.new
24
+ uri_classifier.register("/", 1)
25
+
26
+ script_name, path_info, value = uri_classifier.resolve("/test")
27
+ assert_equal 1, value
28
+ assert_equal "/", script_name
29
+ assert_equal "/test", path_info
30
+ end
31
+
32
+ def test_uri_prefix_ops
33
+ test = "/pre/fix/test"
34
+ prefix = "/pre"
35
+
36
+ uri_classifier = URIClassifier.new
37
+ uri_classifier.register(prefix,1)
38
+
39
+ script_name, path_info, value = uri_classifier.resolve(prefix)
40
+ script_name, path_info, value = uri_classifier.resolve(test)
41
+ assert_equal 1, value
42
+ assert_equal prefix, script_name
43
+ assert_equal test[script_name.length .. -1], path_info
44
+
45
+ assert uri_classifier.inspect
46
+ assert_equal prefix, uri_classifier.uris[0]
47
+ end
48
+
49
+ def test_not_finding
50
+ test = "/cant/find/me"
51
+ uri_classifier = URIClassifier.new
52
+ uri_classifier.register(test, 1)
53
+
54
+ script_name, path_info, value = uri_classifier.resolve("/nope/not/here")
55
+ assert_nil script_name
56
+ assert_nil path_info
57
+ assert_nil value
58
+ end
59
+
60
+ def test_exceptions
61
+ uri_classifier = URIClassifier.new
62
+
63
+ uri_classifier.register("/test", 1)
64
+
65
+ failed = false
66
+ begin
67
+ uri_classifier.register("/test", 1)
68
+ rescue => e
69
+ failed = true
70
+ end
71
+
72
+ assert failed
73
+
74
+ failed = false
75
+ begin
76
+ uri_classifier.register("", 1)
77
+ rescue => e
78
+ failed = true
79
+ end
80
+
81
+ assert failed
82
+ end
83
+
84
+
85
+ def test_register_unregister
86
+ uri_classifier = URIClassifier.new
87
+
88
+ 100.times do
89
+ uri_classifier.register("/stuff", 1)
90
+ value = uri_classifier.unregister("/stuff")
91
+ assert_equal 1, value
92
+ end
93
+
94
+ uri_classifier.register("/things",1)
95
+ script_name, path_info, value = uri_classifier.resolve("/things")
96
+ assert_equal 1, value
97
+
98
+ uri_classifier.unregister("/things")
99
+ script_name, path_info, value = uri_classifier.resolve("/things")
100
+ assert_nil value
101
+
102
+ end
103
+
104
+
105
+ def test_uri_branching
106
+ uri_classifier = URIClassifier.new
107
+ uri_classifier.register("/test", 1)
108
+ uri_classifier.register("/test/this",2)
109
+
110
+ script_name, path_info, handler = uri_classifier.resolve("/test")
111
+ script_name, path_info, handler = uri_classifier.resolve("/test/that")
112
+ assert_equal "/test", script_name, "failed to properly find script off branch portion of uri"
113
+ assert_equal "/that", path_info
114
+ assert_equal 1, handler, "wrong result for branching uri"
115
+ end
116
+
117
+ def test_all_prefixing
118
+ tests = ["/test","/test/that","/test/this"]
119
+ uri = "/test/this/that"
120
+ uri_classifier = URIClassifier.new
121
+
122
+ current = ""
123
+ uri.each_byte do |c|
124
+ current << c.chr
125
+ uri_classifier.register(current, c)
126
+ end
127
+
128
+
129
+ # Try to resolve everything with no asserts as a fuzzing
130
+ tests.each do |prefix|
131
+ current = ""
132
+ prefix.each_byte do |c|
133
+ current << c.chr
134
+ script_name, path_info, handler = uri_classifier.resolve(current)
135
+ assert script_name
136
+ assert path_info
137
+ assert handler
138
+ end
139
+ end
140
+
141
+ # Assert that we find stuff
142
+ tests.each do |t|
143
+ script_name, path_info, handler = uri_classifier.resolve(t)
144
+ assert handler
145
+ end
146
+
147
+ # Assert we don't find stuff
148
+ script_name, path_info, handler = uri_classifier.resolve("chicken")
149
+ assert_nil handler
150
+ assert_nil script_name
151
+ assert_nil path_info
152
+ end
153
+
154
+
155
+ # Verifies that a root mounted ("/") handler resolves
156
+ # such that path info matches the original URI.
157
+ # This is needed to accommodate real usage of handlers.
158
+ def test_root_mounted
159
+ uri_classifier = URIClassifier.new
160
+ root = "/"
161
+ path = "/this/is/a/test"
162
+
163
+ uri_classifier.register(root, 1)
164
+
165
+ script_name, path_info, handler = uri_classifier.resolve(root)
166
+ assert_equal 1, handler
167
+ assert_equal root, path_info
168
+ assert_equal root, script_name
169
+
170
+ script_name, path_info, handler = uri_classifier.resolve(path)
171
+ assert_equal path, path_info
172
+ assert_equal root, script_name
173
+ assert_equal 1, handler
174
+ end
175
+
176
+ # Verifies that a root mounted ("/") handler
177
+ # is the default point, doesn't matter the order we use
178
+ # to register the URIs
179
+ def test_classifier_order
180
+ tests = ["/before", "/way_past"]
181
+ root = "/"
182
+ path = "/path"
183
+
184
+ uri_classifier = URIClassifier.new
185
+ uri_classifier.register(path, 1)
186
+ uri_classifier.register(root, 2)
187
+
188
+ tests.each do |uri|
189
+ script_name, path_info, handler = uri_classifier.resolve(uri)
190
+ assert_equal root, script_name, "#{uri} did not resolve to #{root}"
191
+ assert_equal uri, path_info
192
+ assert_equal 2, handler
193
+ end
194
+ end
195
+
196
+ if ENV['BENCHMARK']
197
+ # Eventually we will have a suite of benchmarks instead of lamely installing a test
198
+
199
+ def test_benchmark
200
+
201
+ # This URI set should favor a TST. Both versions increase linearly until you hit 14
202
+ # URIs, then the TST flattens out.
203
+ @uris = %w(
204
+ /
205
+ /dag /dig /digbark /dog /dogbark /dog/bark /dug /dugbarking /puppy
206
+ /c /cat /cat/tree /cat/tree/mulberry /cats /cot /cot/tree/mulberry /kitty /kittycat
207
+ # /eag /eig /eigbark /eog /eogbark /eog/bark /eug /eugbarking /iuppy
208
+ # /f /fat /fat/tree /fat/tree/mulberry /fats /fot /fot/tree/mulberry /jitty /jittyfat
209
+ # /gag /gig /gigbark /gog /gogbark /gog/bark /gug /gugbarking /kuppy
210
+ # /h /hat /hat/tree /hat/tree/mulberry /hats /hot /hot/tree/mulberry /litty /littyhat
211
+ # /ceag /ceig /ceigbark /ceog /ceogbark /ceog/cbark /ceug /ceugbarking /ciuppy
212
+ # /cf /cfat /cfat/ctree /cfat/ctree/cmulberry /cfats /cfot /cfot/ctree/cmulberry /cjitty /cjittyfat
213
+ # /cgag /cgig /cgigbark /cgog /cgogbark /cgog/cbark /cgug /cgugbarking /ckuppy
214
+ # /ch /chat /chat/ctree /chat/ctree/cmulberry /chats /chot /chot/ctree/cmulberry /citty /cittyhat
215
+ )
216
+
217
+ @requests = %w(
218
+ /
219
+ /dig
220
+ /digging
221
+ /dogging
222
+ /dogbarking/
223
+ /puppy/barking
224
+ /c
225
+ /cat
226
+ /cat/shrub
227
+ /cat/tree
228
+ /cat/tree/maple
229
+ /cat/tree/mulberry/tree
230
+ /cat/tree/oak
231
+ /cats/
232
+ /cats/tree
233
+ /cod
234
+ /zebra
235
+ )
236
+
237
+ @classifier = URIClassifier.new
238
+ @uris.each do |uri|
239
+ @classifier.register(uri, 1)
240
+ end
241
+
242
+ puts "#{@uris.size} URIs / #{@requests.size * 10000} requests"
243
+
244
+ Benchmark.bm do |x|
245
+ x.report do
246
+ # require 'ruby-prof'
247
+ # profile = RubyProf.profile do
248
+ 10000.times do
249
+ @requests.each do |request|
250
+ @classifier.resolve(request)
251
+ end
252
+ end
253
+ # end
254
+ # File.open("profile.html", 'w') { |file| RubyProf::GraphHtmlPrinter.new(profile).print(file, 0) }
255
+ end
256
+ end
257
+ end
258
+ end
259
+
260
+ end
261
+
@@ -0,0 +1,115 @@
1
+ # Copyright (c) 2005 Zed A. Shaw
2
+ # You can redistribute it and/or modify it under the same terms as Ruby.
3
+ #
4
+ # Additional work donated by contributors. See http://mongrel.rubyforge.org/attributions.html
5
+ # for more information.
6
+
7
+ require 'test/testhelp'
8
+
9
+ include Mongrel
10
+
11
+ class TestHandler < Mongrel::HttpHandler
12
+ attr_reader :ran_test
13
+
14
+ def process(request, response)
15
+ @ran_test = true
16
+ response.socket.write("HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\nhello!\n")
17
+ end
18
+ end
19
+
20
+
21
+ class WebServerTest < Test::Unit::TestCase
22
+
23
+ def setup
24
+ @valid_request = "GET / HTTP/1.1\r\nHost: www.zedshaw.com\r\nContent-Type: text/plain\r\n\r\n"
25
+
26
+ redirect_test_io do
27
+ # We set num_processors=1 so that we can test the reaping code
28
+ @server = HttpServer.new("127.0.0.1", 9998, num_processors=1)
29
+ end
30
+
31
+ @tester = TestHandler.new
32
+ @server.register("/test", @tester)
33
+ redirect_test_io do
34
+ @server.run
35
+ end
36
+ end
37
+
38
+ def teardown
39
+ redirect_test_io do
40
+ @server.stop(true)
41
+ end
42
+ end
43
+
44
+ def test_simple_server
45
+ hit(['http://localhost:9998/test'])
46
+ assert @tester.ran_test, "Handler didn't really run"
47
+ end
48
+
49
+
50
+ def do_test(string, chunk, close_after=nil, shutdown_delay=0)
51
+ # Do not use instance variables here, because it needs to be thread safe
52
+ socket = TCPSocket.new("127.0.0.1", 9998);
53
+ request = StringIO.new(string)
54
+ chunks_out = 0
55
+
56
+ while data = request.read(chunk)
57
+ chunks_out += socket.write(data)
58
+ socket.flush
59
+ sleep 0.2
60
+ if close_after and chunks_out > close_after
61
+ socket.close
62
+ sleep 1
63
+ end
64
+ end
65
+ sleep(shutdown_delay)
66
+ socket.write(" ") # Some platforms only raise the exception on attempted write
67
+ socket.flush
68
+ end
69
+
70
+ def test_trickle_attack
71
+ do_test(@valid_request, 3)
72
+ end
73
+
74
+ def test_close_client
75
+ assert_raises IOError do
76
+ do_test(@valid_request, 10, 20)
77
+ end
78
+ end
79
+
80
+ def test_bad_client
81
+ redirect_test_io do
82
+ do_test("GET /test HTTP/BAD", 3)
83
+ end
84
+ end
85
+
86
+ def test_header_is_too_long
87
+ redirect_test_io do
88
+ long = "GET /test HTTP/1.1\r\n" + ("X-Big: stuff\r\n" * 15000) + "\r\n"
89
+ assert_raises Errno::ECONNRESET, Errno::EPIPE, Errno::ECONNABORTED, Errno::EINVAL, IOError do
90
+ do_test(long, long.length/2, 10)
91
+ end
92
+ end
93
+ end
94
+
95
+ def test_num_processors_overload
96
+ redirect_test_io do
97
+ assert_raises Errno::ECONNRESET, Errno::EPIPE, Errno::ECONNABORTED, Errno::EINVAL do
98
+ tests = [
99
+ Thread.new { do_test(@valid_request, 1) },
100
+ Thread.new { do_test(@valid_request, 10) },
101
+ ]
102
+
103
+ tests.each {|t| t.join}
104
+ end
105
+ end
106
+ end
107
+
108
+ def test_file_streamed_request
109
+ body = "a" * (Mongrel::Const::MAX_BODY * 2)
110
+ long = "GET /test HTTP/1.1\r\nContent-length: #{body.length}\r\n\r\n" + body
111
+ do_test(long, Mongrel::Const::CHUNK_SIZE * 2 -400)
112
+ end
113
+
114
+ end
115
+
@@ -0,0 +1,66 @@
1
+ # Copyright (c) 2005 Zed A. Shaw
2
+ # You can redistribute it and/or modify it under the same terms as Ruby.
3
+ #
4
+ # Additional work donated by contributors. See http://mongrel.rubyforge.org/attributions.html
5
+ # for more information.
6
+
7
+
8
+ HERE = File.dirname(__FILE__)
9
+ %w(lib ext bin test).each do |dir|
10
+ $LOAD_PATH.unshift "#{HERE}/../#{dir}"
11
+ end
12
+
13
+ require 'rubygems'
14
+ require 'test/unit'
15
+ require 'net/http'
16
+ require 'timeout'
17
+ require 'cgi/session'
18
+ require 'fileutils'
19
+ require 'benchmark'
20
+ require 'digest/sha1'
21
+ require 'uri'
22
+ require 'stringio'
23
+ require 'pp'
24
+
25
+ require 'mongrel'
26
+ require 'mongrel/stats'
27
+
28
+ if ENV['DEBUG']
29
+ require 'ruby-debug'
30
+ Debugger.start
31
+ end
32
+
33
+ def redirect_test_io
34
+ orig_err = STDERR.dup
35
+ orig_out = STDOUT.dup
36
+ STDERR.reopen("test_stderr.log")
37
+ STDOUT.reopen("test_stdout.log")
38
+
39
+ begin
40
+ yield
41
+ ensure
42
+ STDERR.reopen(orig_err)
43
+ STDOUT.reopen(orig_out)
44
+ end
45
+ end
46
+
47
+ # Either takes a string to do a get request against, or a tuple of [URI, HTTP] where
48
+ # HTTP is some kind of Net::HTTP request object (POST, HEAD, etc.)
49
+ def hit(uris)
50
+ results = []
51
+ uris.each do |u|
52
+ res = nil
53
+
54
+ if u.kind_of? String
55
+ res = Net::HTTP.get(URI.parse(u))
56
+ else
57
+ url = URI.parse(u[0])
58
+ res = Net::HTTP.new(url.host, url.port).start {|h| h.request(u[1]) }
59
+ end
60
+
61
+ assert res != nil, "Didn't get a response: #{u}"
62
+ results << res
63
+ end
64
+
65
+ return results
66
+ end
@@ -0,0 +1,45 @@
1
+ require 'socket'
2
+ require 'stringio'
3
+
4
+ def do_test(st, chunk)
5
+ s = TCPSocket.new('127.0.0.1',ARGV[0].to_i);
6
+ req = StringIO.new(st)
7
+ nout = 0
8
+ randstop = rand(st.length / 10)
9
+ STDERR.puts "stopping after: #{randstop}"
10
+
11
+ begin
12
+ while data = req.read(chunk)
13
+ nout += s.write(data)
14
+ s.flush
15
+ sleep 0.1
16
+ if nout > randstop
17
+ STDERR.puts "BANG! after #{nout} bytes."
18
+ break
19
+ end
20
+ end
21
+ rescue Object => e
22
+ STDERR.puts "ERROR: #{e}"
23
+ ensure
24
+ s.close
25
+ end
26
+ end
27
+
28
+ content = "-" * (1024 * 240)
29
+ st = "GET / HTTP/1.1\r\nHost: www.zedshaw.com\r\nContent-Type: text/plain\r\nContent-Length: #{content.length}\r\n\r\n#{content}"
30
+
31
+ puts "length: #{content.length}"
32
+
33
+ threads = []
34
+ ARGV[1].to_i.times do
35
+ t = Thread.new do
36
+ size = 100
37
+ puts ">>>> #{size} sized chunks"
38
+ do_test(st, size)
39
+ end
40
+
41
+ t.abort_on_exception = true
42
+ threads << t
43
+ end
44
+
45
+ threads.each {|t| t.join}