freels-mongrel 1.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. data/CHANGELOG +12 -0
  2. data/COPYING +55 -0
  3. data/LICENSE +55 -0
  4. data/Manifest +70 -0
  5. data/README +74 -0
  6. data/Rakefile +237 -0
  7. data/TODO +4 -0
  8. data/bin/mongrel_rails +284 -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 +15 -0
  23. data/ext/http11/extconf.rb +6 -0
  24. data/ext/http11/http11.c +527 -0
  25. data/ext/http11/http11_parser.c +1216 -0
  26. data/ext/http11/http11_parser.h +49 -0
  27. data/ext/http11/http11_parser.java.rl +171 -0
  28. data/ext/http11/http11_parser.rl +165 -0
  29. data/ext/http11/http11_parser_common.rl +55 -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/mongrel.rb +359 -0
  34. data/lib/mongrel/camping.rb +107 -0
  35. data/lib/mongrel/cgi.rb +182 -0
  36. data/lib/mongrel/command.rb +220 -0
  37. data/lib/mongrel/configurator.rb +389 -0
  38. data/lib/mongrel/const.rb +114 -0
  39. data/lib/mongrel/debug.rb +203 -0
  40. data/lib/mongrel/gems.rb +22 -0
  41. data/lib/mongrel/handlers.rb +472 -0
  42. data/lib/mongrel/header_out.rb +28 -0
  43. data/lib/mongrel/http_request.rb +155 -0
  44. data/lib/mongrel/http_response.rb +163 -0
  45. data/lib/mongrel/init.rb +10 -0
  46. data/lib/mongrel/logger.rb +74 -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 +47 -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 +88 -0
  61. data/test/test_debug.rb +25 -0
  62. data/test/test_handlers.rb +104 -0
  63. data/test/test_http11.rb +272 -0
  64. data/test/test_redirect_handler.rb +44 -0
  65. data/test/test_request_progress.rb +100 -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 +116 -0
  70. data/test/testhelp.rb +74 -0
  71. data/tools/trickletest.rb +45 -0
  72. metadata +202 -0
@@ -0,0 +1,272 @@
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 HttpParserTest < Test::Unit::TestCase
12
+
13
+ def test_parse_simple
14
+ parser = HttpParser.new
15
+ req = {}
16
+ http = "GET / HTTP/1.1\r\n\r\n"
17
+ nread = parser.execute(req, http, 0)
18
+
19
+ assert nread == http.length, "Failed to parse the full HTTP request"
20
+ assert parser.finished?, "Parser didn't finish"
21
+ assert !parser.error?, "Parser had error"
22
+ assert nread == parser.nread, "Number read returned from execute does not match"
23
+
24
+ assert_equal 'HTTP/1.1', req['SERVER_PROTOCOL']
25
+ assert_equal '/', req['REQUEST_PATH']
26
+ assert_equal 'HTTP/1.1', req['HTTP_VERSION']
27
+ assert_equal '/', req['REQUEST_URI']
28
+ assert_equal 'CGI/1.2', req['GATEWAY_INTERFACE']
29
+ assert_equal 'GET', req['REQUEST_METHOD']
30
+ assert_nil req['FRAGMENT']
31
+ assert_nil req['QUERY_STRING']
32
+
33
+ parser.reset
34
+ assert parser.nread == 0, "Number read after reset should be 0"
35
+ end
36
+
37
+ def test_parse_dumbfuck_headers
38
+ parser = HttpParser.new
39
+ req = {}
40
+ should_be_good = "GET / HTTP/1.1\r\naaaaaaaaaaaaa:++++++++++\r\n\r\n"
41
+ nread = parser.execute(req, should_be_good, 0)
42
+ assert_equal should_be_good.length, nread
43
+ assert parser.finished?
44
+ assert !parser.error?
45
+ assert_equal "++++++++++", req["HTTP_AAAAAAAAAAAAA"]
46
+
47
+ 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"
48
+ parser = HttpParser.new
49
+ req = {}
50
+ #nread = parser.execute(req, nasty_pound_header, 0)
51
+ #assert_equal nasty_pound_header.length, nread
52
+ #assert parser.finished?
53
+ #assert !parser.error?
54
+ end
55
+
56
+ def test_parse_ie6_urls
57
+ %w(/some/random/path"
58
+ /some/random/path>
59
+ /some/random/path<
60
+ /we/love/you/ie6?q=<"">
61
+ /url?<="&>="
62
+ /mal"formed"?
63
+ ).each do |path|
64
+ parser = HttpParser.new
65
+ req = {}
66
+ sorta_safe = %(GET #{path} HTTP/1.1\r\n\r\n)
67
+ nread = parser.execute(req, sorta_safe, 0)
68
+ assert_equal sorta_safe.length, nread
69
+ assert parser.finished?
70
+ assert !parser.error?
71
+ end
72
+ end
73
+
74
+ def test_parse_error
75
+ parser = HttpParser.new
76
+ req = {}
77
+ bad_http = "GET / SsUTF/1.1"
78
+
79
+ error = false
80
+ begin
81
+ nread = parser.execute(req, bad_http, 0)
82
+ rescue => details
83
+ error = true
84
+ end
85
+
86
+ assert error, "failed to throw exception"
87
+ assert !parser.finished?, "Parser shouldn't be finished"
88
+ assert parser.error?, "Parser SHOULD have error"
89
+ end
90
+
91
+ def test_parse_like_optimized_header
92
+ parser = HttpParser.new
93
+ req = {}
94
+ should_be_good = "GET / HTTP/1.1\r\nAuthorizationn: zz\r\n\r\n"
95
+ nread = parser.execute(req, should_be_good, 0)
96
+ assert_equal should_be_good.length, nread
97
+ assert parser.finished?
98
+ assert !parser.error?
99
+ assert_equal "zz", req["HTTP_AUTHORIZATIONN"]
100
+ assert ! req["HTTP_AUTHORIZATION"]
101
+ end
102
+
103
+ def test_parse_twin_lookalike_optimized_headers
104
+ parser = HttpParser.new
105
+ req = {}
106
+ should_be_good = "GET / HTTP/1.1\r\n" \
107
+ "Accept-Encoding: abcdef\r\n" \
108
+ "Accept-Language: zyxvut\r\n" \
109
+ "\r\n"
110
+ nread = parser.execute(req, should_be_good, 0)
111
+ assert_equal should_be_good.length, nread
112
+ assert parser.finished?
113
+ assert !parser.error?
114
+ assert_equal "abcdef", req["HTTP_ACCEPT_ENCODING"]
115
+ assert_equal "zyxvut", req["HTTP_ACCEPT_LANGUAGE"]
116
+ end
117
+
118
+ if RUBY_PLATFORM !~ /java/
119
+ # as of now, the Java version does not have the same global-object
120
+ # reuse optimization the C version does
121
+
122
+ def test_parse_optimized_headers_global_objects_used
123
+ parser = HttpParser.new
124
+ req = {}
125
+ should_be_good = "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n"
126
+ nread = parser.execute(req, should_be_good, 0)
127
+ assert_equal should_be_good.length, nread
128
+ assert parser.finished?
129
+ assert !parser.error?
130
+ assert_equal "example.com", req["HTTP_HOST"]
131
+
132
+ frozen_host_a = nil
133
+ req.each { |k,v| k == "HTTP_HOST" && frozen_host_a = k }
134
+
135
+ parser = HttpParser.new
136
+ req = {}
137
+ should_be_good = "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n"
138
+ nread = parser.execute(req, should_be_good, 0)
139
+ assert_equal should_be_good.length, nread
140
+ assert parser.finished?
141
+ assert !parser.error?
142
+
143
+ frozen_host_b = nil
144
+ req.each { |k,v| k == "HTTP_HOST" && frozen_host_b = k }
145
+ assert_equal "HTTP_HOST", frozen_host_a
146
+ assert_equal "HTTP_HOST", frozen_host_b
147
+ assert_equal frozen_host_a.object_id, frozen_host_b.object_id
148
+ end
149
+ end
150
+
151
+ def test_host_port_parsing
152
+ parser = HttpParser.new
153
+ req = {}
154
+ should_be_good = "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n"
155
+ nread = parser.execute(req, should_be_good, 0)
156
+ assert_equal should_be_good.length, nread
157
+ assert parser.finished?
158
+ assert !parser.error?
159
+ assert_equal "example.com", req["HTTP_HOST"]
160
+ assert_equal "example.com", req["SERVER_NAME"]
161
+ assert_equal "80", req["SERVER_PORT"]
162
+
163
+ parser = HttpParser.new
164
+ req = {}
165
+ should_be_good = "GET / HTTP/1.1\r\nHost: example.com:123\r\n\r\n"
166
+ nread = parser.execute(req, should_be_good, 0)
167
+ assert_equal should_be_good.length, nread
168
+ assert parser.finished?
169
+ assert !parser.error?
170
+ assert_equal "example.com:123", req["HTTP_HOST"]
171
+ assert_equal "example.com", req["SERVER_NAME"]
172
+ assert_equal "123", req["SERVER_PORT"]
173
+
174
+ # null character in domain name is never actually valid, but if it
175
+ # becomes valid in Web 3.0, we'll be ready for it.
176
+ parser = HttpParser.new
177
+ req = {}
178
+ should_be_good = "GET / HTTP/1.1\r\nHost: example.com\0:123\r\n\r\n"
179
+ nread = parser.execute(req, should_be_good, 0)
180
+ assert_equal should_be_good.length, nread
181
+ assert parser.finished?
182
+ assert !parser.error?
183
+ assert_equal "example.com\0:123", req["HTTP_HOST"]
184
+ assert_equal "example.com\0", req["SERVER_NAME"]
185
+ assert_equal "123", req["SERVER_PORT"]
186
+ end
187
+
188
+ def test_fragment_in_uri
189
+ parser = HttpParser.new
190
+ req = {}
191
+ get = "GET /forums/1/topics/2375?page=1#posts-17408 HTTP/1.1\r\n\r\n"
192
+ assert_nothing_raised do
193
+ parser.execute(req, get, 0)
194
+ end
195
+ assert parser.finished?
196
+ assert_equal '/forums/1/topics/2375?page=1', req['REQUEST_URI']
197
+ assert_equal 'posts-17408', req['FRAGMENT']
198
+ end
199
+
200
+ # lame random garbage maker
201
+ def rand_data(min, max, readable=true)
202
+ count = min + ((rand(max)+1) *10).to_i
203
+ res = count.to_s + "/"
204
+
205
+ if readable
206
+ res << Digest::SHA1.hexdigest(rand(count * 100).to_s) * (count / 40)
207
+ else
208
+ res << Digest::SHA1.digest(rand(count * 100).to_s) * (count / 20)
209
+ end
210
+
211
+ return res
212
+ end
213
+
214
+
215
+ def test_horrible_queries
216
+ parser = HttpParser.new
217
+
218
+ # then that large header names are caught
219
+ 10.times do |c|
220
+ get = "GET /#{rand_data(10,120)} HTTP/1.1\r\nX-#{rand_data(1024, 1024+(c*1024))}: Test\r\n\r\n"
221
+ assert_raises Mongrel::HttpParserError do
222
+ parser.execute({}, get, 0)
223
+ parser.reset
224
+ end
225
+ end
226
+
227
+ # then that large mangled field values are caught
228
+ 10.times do |c|
229
+ get = "GET /#{rand_data(10,120)} HTTP/1.1\r\nX-Test: #{rand_data(1024, 1024+(c*1024), false)}\r\n\r\n"
230
+ assert_raises Mongrel::HttpParserError do
231
+ parser.execute({}, get, 0)
232
+ parser.reset
233
+ end
234
+ end
235
+
236
+ # then large headers are rejected too
237
+ get = "GET /#{rand_data(10,120)} HTTP/1.1\r\n"
238
+ get << "X-Test: test\r\n" * (80 * 1024)
239
+ assert_raises Mongrel::HttpParserError do
240
+ parser.execute({}, get, 0)
241
+ parser.reset
242
+ end
243
+
244
+ # finally just that random garbage gets blocked all the time
245
+ 10.times do |c|
246
+ get = "GET #{rand_data(1024, 1024+(c*1024), false)} #{rand_data(1024, 1024+(c*1024), false)}\r\n\r\n"
247
+ assert_raises Mongrel::HttpParserError do
248
+ parser.execute({}, get, 0)
249
+ parser.reset
250
+ end
251
+ end
252
+
253
+ end
254
+
255
+
256
+
257
+ def test_query_parse
258
+ res = HttpRequest.query_parse("zed=1&frank=#{HttpRequest.escape('&&& ')}")
259
+ assert res["zed"], "didn't get the request right"
260
+ assert res["frank"], "no frank"
261
+ assert_equal "1", res["zed"], "wrong result"
262
+ assert_equal "&&& ", HttpRequest.unescape(res["frank"]), "wrong result"
263
+
264
+ res = HttpRequest.query_parse("zed=1&zed=2&zed=3&frank=11;zed=45")
265
+ assert res["zed"], "didn't get the request right"
266
+ assert res["frank"], "no frank"
267
+ assert_equal 4,res["zed"].length, "wrong number for zed"
268
+ assert_equal "11",res["frank"], "wrong number for frank"
269
+ end
270
+
271
+ end
272
+
@@ -0,0 +1,44 @@
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
+ class RedirectHandlerTest < Test::Unit::TestCase
10
+
11
+ def setup
12
+ redirect_test_io do
13
+ @server = Mongrel::HttpServer.new('127.0.0.1', process_based_port)
14
+ end
15
+ @server.run
16
+ @client = Net::HTTP.new('127.0.0.1', process_based_port)
17
+ end
18
+
19
+ def teardown
20
+ @server.stop(true)
21
+ end
22
+
23
+ def test_simple_redirect
24
+ tester = Mongrel::RedirectHandler.new('/yo')
25
+ @server.register("/test", tester)
26
+
27
+ sleep(1)
28
+ res = @client.request_get('/test')
29
+ assert res != nil, "Didn't get a response"
30
+ assert_equal ['/yo'], res.get_fields('Location')
31
+ end
32
+
33
+ def test_rewrite
34
+ tester = Mongrel::RedirectHandler.new(/(\w+)/, '+\1+')
35
+ @server.register("/test", tester)
36
+
37
+ sleep(1)
38
+ res = @client.request_get('/test/something')
39
+ assert_equal ['/+test+/+something+'], res.get_fields('Location')
40
+ end
41
+
42
+ end
43
+
44
+
@@ -0,0 +1,100 @@
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
+ class UploadBeginHandler < Mongrel::HttpHandler
10
+ attr_reader :request_began, :request_progressed, :request_processed
11
+
12
+ def initialize
13
+ @request_notify = true
14
+ end
15
+
16
+ def reset
17
+ @request_began = false
18
+ @request_progressed = false
19
+ @request_processed = false
20
+ end
21
+
22
+ def request_begins(params)
23
+ @request_began = true
24
+ end
25
+
26
+ def request_progress(params,len,total)
27
+ @request_progressed = true
28
+ end
29
+
30
+ def process(request, response)
31
+ @request_processed = true
32
+ response.start do |head,body|
33
+ body.write("test")
34
+ end
35
+ end
36
+
37
+ end
38
+
39
+ class RequestProgressTest < Test::Unit::TestCase
40
+ def setup
41
+ @port = process_based_port
42
+ redirect_test_io do
43
+ @server = Mongrel::HttpServer.new("127.0.0.1", @port)
44
+ end
45
+ @handler = UploadBeginHandler.new
46
+ @server.register("/upload", @handler)
47
+ @server.run
48
+ end
49
+
50
+ def teardown
51
+ @server.stop(true)
52
+ end
53
+
54
+ def test_begin_end_progress
55
+ Net::HTTP.get("localhost", "/upload", @port)
56
+ assert @handler.request_began
57
+ assert @handler.request_progressed
58
+ assert @handler.request_processed
59
+ end
60
+
61
+ def call_and_assert_handlers_in_turn(handlers)
62
+ # reset all handlers
63
+ handlers.each { |h| h.reset }
64
+
65
+ # make the call
66
+ Net::HTTP.get("localhost", "/upload", @port)
67
+
68
+ # assert that each one was fired
69
+ handlers.each { |h|
70
+ assert h.request_began && h.request_progressed && h.request_processed,
71
+ "Callbacks NOT fired for #{h}"
72
+ }
73
+ end
74
+
75
+ def test_more_than_one_begin_end_progress
76
+ handlers = [@handler]
77
+
78
+ second = UploadBeginHandler.new
79
+ @server.register("/upload", second)
80
+ handlers << second
81
+ call_and_assert_handlers_in_turn(handlers)
82
+
83
+ # check three handlers
84
+ third = UploadBeginHandler.new
85
+ @server.register("/upload", third)
86
+ handlers << third
87
+ call_and_assert_handlers_in_turn(handlers)
88
+
89
+ # remove handlers to make sure they've all gone away
90
+ @server.unregister("/upload")
91
+ handlers.each { |h| h.reset }
92
+ Net::HTTP.get("localhost", "/upload", @port)
93
+ handlers.each { |h|
94
+ assert !h.request_began && !h.request_progressed && !h.request_processed
95
+ }
96
+
97
+ # re-register upload to the state before this test
98
+ @server.register("/upload", @handler)
99
+ end
100
+ end
@@ -0,0 +1,127 @@
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 ResponseTest < Test::Unit::TestCase
12
+
13
+ def test_response_headers
14
+ out = StringIO.new
15
+ resp = HttpResponse.new(out)
16
+ resp.status = 200
17
+ resp.header["Accept"] = "text/plain"
18
+ resp.header["X-Whatever"] = "stuff"
19
+ resp.body.write("test")
20
+ resp.finished
21
+
22
+ assert out.length > 0, "output didn't have data"
23
+ end
24
+
25
+ def test_response_200
26
+ io = StringIO.new
27
+ resp = HttpResponse.new(io)
28
+ resp.start do |head,out|
29
+ head["Accept"] = "text/plain"
30
+ out.write("tested")
31
+ out.write("hello!")
32
+ end
33
+
34
+ resp.finished
35
+ assert io.length > 0, "output didn't have data"
36
+ end
37
+
38
+ def test_response_duplicate_header_squash
39
+ io = StringIO.new
40
+ resp = HttpResponse.new(io)
41
+ resp.start do |head,out|
42
+ head["Content-Length"] = 30
43
+ head["Content-Length"] = 0
44
+ end
45
+
46
+ resp.finished
47
+
48
+ assert_equal io.length, 95, "too much output"
49
+ end
50
+
51
+
52
+ def test_response_some_duplicates_allowed
53
+ allowed_duplicates = ["Set-Cookie", "Set-Cookie2", "Warning", "WWW-Authenticate"]
54
+ io = StringIO.new
55
+ resp = HttpResponse.new(io)
56
+ resp.start do |head,out|
57
+ allowed_duplicates.each do |dup|
58
+ 10.times do |i|
59
+ head[dup] = i
60
+ end
61
+ end
62
+ end
63
+
64
+ resp.finished
65
+
66
+ assert_equal io.length, 734, "wrong amount of output"
67
+ end
68
+
69
+ def test_response_404
70
+ io = StringIO.new
71
+
72
+ resp = HttpResponse.new(io)
73
+ resp.start(404) do |head,out|
74
+ head['Accept'] = "text/plain"
75
+ out.write("NOT FOUND")
76
+ end
77
+
78
+ resp.finished
79
+ assert io.length > 0, "output didn't have data"
80
+ end
81
+
82
+ def test_response_file
83
+ contents = "PLAIN TEXT\r\nCONTENTS\r\n"
84
+ require 'tempfile'
85
+ tmpf = Tempfile.new("test_response_file")
86
+ tmpf.binmode
87
+ tmpf.write(contents)
88
+ tmpf.rewind
89
+
90
+ io = StringIO.new
91
+ resp = HttpResponse.new(io)
92
+ resp.start(200) do |head,out|
93
+ head['Content-Type'] = 'text/plain'
94
+ resp.send_header
95
+ resp.send_file(tmpf.path)
96
+ end
97
+ io.rewind
98
+ tmpf.close
99
+
100
+ assert io.length > 0, "output didn't have data"
101
+ assert io.read[-contents.length..-1] == contents, "output doesn't end with file payload"
102
+ end
103
+
104
+ def test_response_with_custom_reason
105
+ reason = "You made a bad request"
106
+ io = StringIO.new
107
+ resp = HttpResponse.new(io)
108
+ resp.start(400, false, reason) { |head,out| }
109
+ resp.finished
110
+
111
+ io.rewind
112
+ assert_match(/.* #{reason}$/, io.readline.chomp, "wrong custom reason phrase")
113
+ end
114
+
115
+ def test_response_with_default_reason
116
+ code = 400
117
+ io = StringIO.new
118
+ resp = HttpResponse.new(io)
119
+ resp.start(code) { |head,out| }
120
+ resp.finished
121
+
122
+ io.rewind
123
+ assert_match(/.* #{HTTP_STATUS_CODES[code]}$/, io.readline.chomp, "wrong default reason phrase")
124
+ end
125
+
126
+ end
127
+