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.
- data.tar.gz.sig +1 -0
- data/CHANGELOG +12 -0
- data/COPYING +55 -0
- data/LICENSE +55 -0
- data/Manifest +69 -0
- data/README +74 -0
- data/TODO +5 -0
- data/bin/mongrel_rails +283 -0
- data/examples/builder.rb +29 -0
- data/examples/camping/README +3 -0
- data/examples/camping/blog.rb +294 -0
- data/examples/camping/tepee.rb +149 -0
- data/examples/httpd.conf +474 -0
- data/examples/mime.yaml +3 -0
- data/examples/mongrel.conf +9 -0
- data/examples/mongrel_simple_ctrl.rb +92 -0
- data/examples/mongrel_simple_service.rb +116 -0
- data/examples/monitrc +57 -0
- data/examples/random_thrash.rb +19 -0
- data/examples/simpletest.rb +52 -0
- data/examples/webrick_compare.rb +20 -0
- data/ext/http11/ext_help.h +14 -0
- data/ext/http11/extconf.rb +6 -0
- data/ext/http11/http11.c +402 -0
- data/ext/http11/http11_parser.c +1221 -0
- data/ext/http11/http11_parser.h +49 -0
- data/ext/http11/http11_parser.java.rl +170 -0
- data/ext/http11/http11_parser.rl +152 -0
- data/ext/http11/http11_parser_common.rl +54 -0
- data/ext/http11_java/Http11Service.java +13 -0
- data/ext/http11_java/org/jruby/mongrel/Http11.java +266 -0
- data/ext/http11_java/org/jruby/mongrel/Http11Parser.java +572 -0
- data/lib/http11.jar +0 -0
- data/lib/mongrel.rb +355 -0
- data/lib/mongrel/camping.rb +107 -0
- data/lib/mongrel/cgi.rb +181 -0
- data/lib/mongrel/command.rb +222 -0
- data/lib/mongrel/configurator.rb +388 -0
- data/lib/mongrel/const.rb +110 -0
- data/lib/mongrel/debug.rb +203 -0
- data/lib/mongrel/gems.rb +22 -0
- data/lib/mongrel/handlers.rb +468 -0
- data/lib/mongrel/header_out.rb +28 -0
- data/lib/mongrel/http_request.rb +155 -0
- data/lib/mongrel/http_response.rb +163 -0
- data/lib/mongrel/init.rb +10 -0
- data/lib/mongrel/mime_types.yml +616 -0
- data/lib/mongrel/rails.rb +185 -0
- data/lib/mongrel/stats.rb +89 -0
- data/lib/mongrel/tcphack.rb +18 -0
- data/lib/mongrel/uri_classifier.rb +76 -0
- data/mongrel-public_cert.pem +20 -0
- data/mongrel.gemspec +263 -0
- data/setup.rb +1585 -0
- data/test/mime.yaml +3 -0
- data/test/mongrel.conf +1 -0
- data/test/test_cgi_wrapper.rb +26 -0
- data/test/test_command.rb +86 -0
- data/test/test_conditional.rb +107 -0
- data/test/test_configurator.rb +87 -0
- data/test/test_debug.rb +25 -0
- data/test/test_handlers.rb +103 -0
- data/test/test_http11.rb +156 -0
- data/test/test_redirect_handler.rb +44 -0
- data/test/test_request_progress.rb +99 -0
- data/test/test_response.rb +127 -0
- data/test/test_stats.rb +35 -0
- data/test/test_uriclassifier.rb +261 -0
- data/test/test_ws.rb +115 -0
- data/test/testhelp.rb +66 -0
- data/tools/trickletest.rb +45 -0
- metadata +186 -0
- 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
|
+
|
data/test/test_ws.rb
ADDED
@@ -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
|
+
|
data/test/testhelp.rb
ADDED
@@ -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}
|