engineyard-mongrel 1.1.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. data/CHANGELOG +16 -0
  2. data/CONTRIBUTORS +17 -0
  3. data/COPYING +55 -0
  4. data/LICENSE +55 -0
  5. data/Manifest +71 -0
  6. data/README +74 -0
  7. data/bin/mongrel_rails +285 -0
  8. data/examples/builder.rb +29 -0
  9. data/examples/camping/README +3 -0
  10. data/examples/camping/blog.rb +294 -0
  11. data/examples/camping/tepee.rb +149 -0
  12. data/examples/httpd.conf +474 -0
  13. data/examples/mime.yaml +3 -0
  14. data/examples/mongrel.conf +9 -0
  15. data/examples/mongrel_simple_ctrl.rb +92 -0
  16. data/examples/mongrel_simple_service.rb +116 -0
  17. data/examples/monitrc +57 -0
  18. data/examples/random_thrash.rb +19 -0
  19. data/examples/simpletest.rb +52 -0
  20. data/examples/webrick_compare.rb +20 -0
  21. data/ext/http11/ext_help.h +15 -0
  22. data/ext/http11/extconf.rb +6 -0
  23. data/ext/http11/http11.c +527 -0
  24. data/ext/http11/http11_parser.c +1243 -0
  25. data/ext/http11/http11_parser.h +49 -0
  26. data/ext/http11/http11_parser.java.rl +171 -0
  27. data/ext/http11/http11_parser.rl +152 -0
  28. data/ext/http11/http11_parser_common.rl +54 -0
  29. data/ext/http11_java/Http11Service.java +13 -0
  30. data/ext/http11_java/org/jruby/mongrel/Http11.java +266 -0
  31. data/ext/http11_java/org/jruby/mongrel/Http11Parser.java +474 -0
  32. data/lib/mongrel.rb +360 -0
  33. data/lib/mongrel/camping.rb +107 -0
  34. data/lib/mongrel/cgi.rb +181 -0
  35. data/lib/mongrel/command.rb +222 -0
  36. data/lib/mongrel/configurator.rb +389 -0
  37. data/lib/mongrel/const.rb +110 -0
  38. data/lib/mongrel/debug.rb +203 -0
  39. data/lib/mongrel/gems.rb +22 -0
  40. data/lib/mongrel/handlers.rb +468 -0
  41. data/lib/mongrel/header_out.rb +28 -0
  42. data/lib/mongrel/http_request.rb +155 -0
  43. data/lib/mongrel/http_response.rb +166 -0
  44. data/lib/mongrel/init.rb +10 -0
  45. data/lib/mongrel/mime_types.yml +616 -0
  46. data/lib/mongrel/rails.rb +214 -0
  47. data/lib/mongrel/stats.rb +89 -0
  48. data/lib/mongrel/tcphack.rb +18 -0
  49. data/lib/mongrel/uri_classifier.rb +76 -0
  50. data/mongrel-public_cert.pem +20 -0
  51. data/setup.rb +1585 -0
  52. data/test/benchmark/previous.rb +11 -0
  53. data/test/benchmark/simple.rb +11 -0
  54. data/test/benchmark/utils.rb +82 -0
  55. data/test/mime.yaml +3 -0
  56. data/test/mongrel.conf +1 -0
  57. data/test/test_helper.rb +79 -0
  58. data/test/tools/trickletest.rb +45 -0
  59. data/test/unit/test_cgi_wrapper.rb +26 -0
  60. data/test/unit/test_command.rb +86 -0
  61. data/test/unit/test_conditional.rb +107 -0
  62. data/test/unit/test_configurator.rb +88 -0
  63. data/test/unit/test_debug.rb +25 -0
  64. data/test/unit/test_handlers.rb +136 -0
  65. data/test/unit/test_http_parser.rb +156 -0
  66. data/test/unit/test_redirect_handler.rb +45 -0
  67. data/test/unit/test_request_progress.rb +100 -0
  68. data/test/unit/test_response.rb +127 -0
  69. data/test/unit/test_stats.rb +35 -0
  70. data/test/unit/test_uriclassifier.rb +261 -0
  71. data/test/unit/test_ws.rb +116 -0
  72. metadata +158 -0
@@ -0,0 +1,88 @@
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/test_helper'
8
+
9
+ $test_plugin_fired = 0
10
+
11
+ class TestPlugin < GemPlugin::Plugin "/handlers"
12
+ include Mongrel::HttpHandlerPlugin
13
+
14
+ def process(request, response)
15
+ $test_plugin_fired += 1
16
+ end
17
+ end
18
+
19
+
20
+ class Sentinel < GemPlugin::Plugin "/handlers"
21
+ include Mongrel::HttpHandlerPlugin
22
+
23
+ def process(request, response)
24
+ raise "This Sentinel plugin shouldn't run."
25
+ end
26
+ end
27
+
28
+
29
+ class ConfiguratorTest < Test::Unit::TestCase
30
+
31
+ def test_base_handler_config
32
+ @port = process_based_port
33
+ @config = nil
34
+
35
+ redirect_test_io do
36
+ @config = Mongrel::Configurator.new :host => "localhost" do
37
+ listener :port => process_based_port do
38
+ # 2 in front should run, but the sentinel shouldn't since dirhandler processes the request
39
+ uri "/", :handler => plugin("/handlers/testplugin")
40
+ uri "/", :handler => plugin("/handlers/testplugin")
41
+ uri "/", :handler => Mongrel::DirHandler.new(".")
42
+ uri "/", :handler => plugin("/handlers/testplugin")
43
+
44
+ uri "/test", :handler => plugin("/handlers/testplugin")
45
+ uri "/test", :handler => plugin("/handlers/testplugin")
46
+ uri "/test", :handler => Mongrel::DirHandler.new(".")
47
+ uri "/test", :handler => plugin("/handlers/testplugin")
48
+
49
+ debug "/"
50
+ setup_signals
51
+
52
+ run_config(HERE + "/mongrel.conf")
53
+ load_mime_map(HERE + "/mime.yaml")
54
+
55
+ run
56
+ end
57
+ end
58
+ end
59
+
60
+ # pp @config.listeners.values.first.classifier.routes
61
+
62
+ @config.listeners.each do |host,listener|
63
+ assert listener.classifier.uris.length == 3, "Wrong number of registered URIs"
64
+ assert listener.classifier.uris.include?("/"), "/ not registered"
65
+ assert listener.classifier.uris.include?("/test"), "/test not registered"
66
+ end
67
+
68
+ res = Net::HTTP.get(URI.parse("http://localhost:#{@port}/test"))
69
+ assert res != nil, "Didn't get a response"
70
+ assert $test_plugin_fired == 3, "Test filter plugin didn't run 3 times."
71
+
72
+ redirect_test_io do
73
+ res = Net::HTTP.get(URI.parse("http://localhost:#{@port}/"))
74
+
75
+ assert res != nil, "Didn't get a response"
76
+ assert $test_plugin_fired == 6, "Test filter plugin didn't run 6 times."
77
+ end
78
+
79
+ redirect_test_io do
80
+ @config.stop(false, true)
81
+ end
82
+
83
+ assert_raise Errno::EBADF, Errno::ECONNREFUSED do
84
+ res = Net::HTTP.get(URI.parse("http://localhost:#{@port}/"))
85
+ end
86
+ end
87
+
88
+ end
@@ -0,0 +1,25 @@
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/test_helper'
8
+ require 'mongrel/debug'
9
+
10
+ class MongrelDbgTest < Test::Unit::TestCase
11
+
12
+ def test_tracing_to_log
13
+ FileUtils.rm_rf "log/mongrel_debug"
14
+
15
+ MongrelDbg::configure
16
+ out = StringIO.new
17
+
18
+ MongrelDbg::begin_trace(:rails)
19
+ MongrelDbg::trace(:rails, "Good stuff")
20
+ MongrelDbg::end_trace(:rails)
21
+
22
+ assert File.exist?("log/mongrel_debug"), "Didn't make logging directory"
23
+ end
24
+
25
+ end
@@ -0,0 +1,136 @@
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/test_helper'
8
+
9
+ class SimpleHandler < Mongrel::HttpHandler
10
+ def process(request, response)
11
+ response.start do |head,out|
12
+ head["Content-Type"] = "text/html"
13
+ results = "<html><body>Your request:<br /><pre>#{request.params.to_yaml}</pre><a href=\"/files\">View the files.</a></body></html>"
14
+ out << results
15
+ end
16
+ end
17
+ end
18
+
19
+ class DumbHandler < Mongrel::HttpHandler
20
+ def process(request, response)
21
+ response.start do |head,out|
22
+ head["Content-Type"] = "text/html"
23
+ out.write("test")
24
+ end
25
+ end
26
+ end
27
+
28
+ def check_status(results, expecting)
29
+ results.each do |res|
30
+ assert(res.kind_of?(expecting), "Didn't get #{expecting}, got: #{res.class}")
31
+ end
32
+ end
33
+
34
+ class HandlersTest < Test::Unit::TestCase
35
+
36
+ def setup
37
+ @port = process_based_port
38
+ stats = Mongrel::StatisticsFilter.new(:sample_rate => 1)
39
+
40
+ @config = Mongrel::Configurator.new :host => '127.0.0.1' do
41
+ listener :port => process_based_port do
42
+ uri "/", :handler => SimpleHandler.new
43
+ uri "/", :handler => stats
44
+ uri "/404", :handler => Mongrel::Error404Handler.new("Not found")
45
+ uri "/dumb", :handler => Mongrel::DeflateFilter.new
46
+ uri "/dumb", :handler => DumbHandler.new, :in_front => true
47
+ uri "/files", :handler => Mongrel::DirHandler.new("doc")
48
+ uri "/files_nodir", :handler => Mongrel::DirHandler.new("doc", listing_allowed=false, index_html="none")
49
+ uri "/status", :handler => Mongrel::StatusHandler.new(:stats_filter => stats)
50
+ uri "/relative", :handler => Mongrel::DirHandler.new(nil, listing_allowed=false, index_html="none")
51
+ end
52
+ end
53
+
54
+ unless windows?
55
+ File.open('/tmp/testfile', 'w') do
56
+ # Do nothing
57
+ end
58
+ end
59
+
60
+ @config.run
61
+ end
62
+
63
+ def teardown
64
+ @config.stop(false, true)
65
+ File.delete '/tmp/testfile' unless windows?
66
+ end
67
+
68
+ def test_registration_exception_is_not_lost
69
+ assert_raises(Mongrel::URIClassifier::RegistrationError) do
70
+ @config = Mongrel::Configurator.new do
71
+ listener do
72
+ uri "bogus", :handler => SimpleHandler.new
73
+ end
74
+ end
75
+ end
76
+ end
77
+
78
+ def test_more_web_server
79
+ res = hit([ "http://localhost:#{@port}/test",
80
+ "http://localhost:#{@port}/dumb",
81
+ "http://localhost:#{@port}/404",
82
+ "http://localhost:#{@port}/files/rdoc/index.html",
83
+ "http://localhost:#{@port}/files/rdoc/nothere.html",
84
+ "http://localhost:#{@port}/files/rdoc/",
85
+ "http://localhost:#{@port}/files_nodir/rdoc/",
86
+ "http://localhost:#{@port}/status",
87
+ ])
88
+ check_status res, String
89
+ end
90
+
91
+ def test_nil_dirhandler
92
+ return if windows?
93
+ # Camping uses this internally
94
+ handler = Mongrel::DirHandler.new(nil, false)
95
+ assert handler.can_serve("/tmp/testfile")
96
+ # Not a bug! A nil @file parameter is the only circumstance under which
97
+ # we are allowed to serve any existing file
98
+ assert handler.can_serve("../../../../../../../../../../tmp/testfile")
99
+ end
100
+
101
+ def test_non_nil_dirhandler_is_not_vulnerable_to_path_traversal
102
+ # The famous security bug of Mongrel 1.1.2
103
+ handler = Mongrel::DirHandler.new("/doc", false)
104
+ assert_nil handler.can_serve("/tmp/testfile")
105
+ assert_nil handler.can_serve("../../../../../../../../../../tmp/testfile")
106
+ end
107
+
108
+ def test_deflate
109
+ Net::HTTP.start("localhost", @port) do |h|
110
+ # Test that no accept-encoding returns a non-deflated response
111
+ req = h.get("/dumb")
112
+ assert(
113
+ !req['Content-Encoding'] ||
114
+ !req['Content-Encoding'].include?('deflate'))
115
+ assert_equal "test", req.body
116
+
117
+ req = h.get("/dumb", {"Accept-Encoding" => "deflate"})
118
+ # -MAX_WBITS stops zlib from looking for a zlib header
119
+ inflater = Zlib::Inflate.new(-Zlib::MAX_WBITS)
120
+ assert req['Content-Encoding'].include?('deflate')
121
+ assert_equal "test", inflater.inflate(req.body)
122
+ end
123
+ end
124
+
125
+ # TODO: find out why this fails on win32 but nowhere else
126
+ #def test_posting_fails_dirhandler
127
+ # req = Net::HTTP::Post.new("http://localhost:#{@port}/files/rdoc/")
128
+ # req.set_form_data({'from'=>'2005-01-01', 'to'=>'2005-03-31'}, ';')
129
+ # res = hit [["http://localhost:#{@port}/files/rdoc/",req]]
130
+ # check_status res, Net::HTTPNotFound
131
+ #end
132
+
133
+ def test_unregister
134
+ @config.listeners["127.0.0.1:#{@port}"].unregister("/")
135
+ end
136
+ end
@@ -0,0 +1,156 @@
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/test_helper'
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_strange_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
+
46
+ 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"
47
+ parser = HttpParser.new
48
+ req = {}
49
+ nread = parser.execute(req, nasty_pound_header, 0)
50
+ assert_equal nasty_pound_header.length, nread
51
+ assert parser.finished?
52
+ assert !parser.error?
53
+ end
54
+
55
+ def test_parse_error
56
+ parser = HttpParser.new
57
+ req = {}
58
+ bad_http = "GET / SsUTF/1.1"
59
+
60
+ error = false
61
+ begin
62
+ nread = parser.execute(req, bad_http, 0)
63
+ rescue => details
64
+ error = true
65
+ end
66
+
67
+ assert error, "failed to throw exception"
68
+ assert !parser.finished?, "Parser shouldn't be finished"
69
+ assert parser.error?, "Parser SHOULD have error"
70
+ end
71
+
72
+ def test_fragment_in_uri
73
+ parser = HttpParser.new
74
+ req = {}
75
+ get = "GET /forums/1/topics/2375?page=1#posts-17408 HTTP/1.1\r\n\r\n"
76
+ assert_nothing_raised do
77
+ parser.execute(req, get, 0)
78
+ end
79
+ assert parser.finished?
80
+ assert_equal '/forums/1/topics/2375?page=1', req['REQUEST_URI']
81
+ assert_equal 'posts-17408', req['FRAGMENT']
82
+ end
83
+
84
+ # lame random garbage maker
85
+ def rand_data(min, max, readable=true)
86
+ count = min + ((rand(max)+1) *10).to_i
87
+ res = count.to_s + "/"
88
+
89
+ if readable
90
+ res << Digest::SHA1.hexdigest(rand(count * 100).to_s) * (count / 40)
91
+ else
92
+ res << Digest::SHA1.digest(rand(count * 100).to_s) * (count / 20)
93
+ end
94
+
95
+ return res
96
+ end
97
+
98
+
99
+ def test_horrible_queries
100
+ parser = HttpParser.new
101
+
102
+ # then that large header names are caught
103
+ 10.times do |c|
104
+ get = "GET /#{rand_data(10,120)} HTTP/1.1\r\nX-#{rand_data(1024, 1024+(c*1024))}: Test\r\n\r\n"
105
+ assert_raises Mongrel::HttpParserError do
106
+ parser.execute({}, get, 0)
107
+ parser.reset
108
+ end
109
+ end
110
+
111
+ # then that large mangled field values are caught
112
+ 10.times do |c|
113
+ get = "GET /#{rand_data(10,120)} HTTP/1.1\r\nX-Test: #{rand_data(1024, 1024+(c*1024), false)}\r\n\r\n"
114
+ assert_raises Mongrel::HttpParserError do
115
+ parser.execute({}, get, 0)
116
+ parser.reset
117
+ end
118
+ end
119
+
120
+ # then large headers are rejected too
121
+ get = "GET /#{rand_data(10,120)} HTTP/1.1\r\n"
122
+ get << "X-Test: test\r\n" * (80 * 1024)
123
+ assert_raises Mongrel::HttpParserError do
124
+ parser.execute({}, get, 0)
125
+ parser.reset
126
+ end
127
+
128
+ # finally just that random garbage gets blocked all the time
129
+ 10.times do |c|
130
+ get = "GET #{rand_data(1024, 1024+(c*1024), false)} #{rand_data(1024, 1024+(c*1024), false)}\r\n\r\n"
131
+ assert_raises Mongrel::HttpParserError do
132
+ parser.execute({}, get, 0)
133
+ parser.reset
134
+ end
135
+ end
136
+
137
+ end
138
+
139
+
140
+
141
+ def test_query_parse
142
+ res = HttpRequest.query_parse("zed=1&frank=#{HttpRequest.escape('&&& ')}")
143
+ assert res["zed"], "didn't get the request right"
144
+ assert res["frank"], "no frank"
145
+ assert_equal "1", res["zed"], "wrong result"
146
+ assert_equal "&&& ", HttpRequest.unescape(res["frank"]), "wrong result"
147
+
148
+ res = HttpRequest.query_parse("zed=1&zed=2&zed=3&frank=11;zed=45")
149
+ assert res["zed"], "didn't get the request right"
150
+ assert res["frank"], "no frank"
151
+ assert_equal 4,res["zed"].length, "wrong number for zed"
152
+ assert_equal "11",res["frank"], "wrong number for frank"
153
+ end
154
+
155
+ end
156
+
@@ -0,0 +1,45 @@
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/test_helper'
8
+
9
+ class RedirectHandlerTest < Test::Unit::TestCase
10
+
11
+ def setup
12
+ @port = process_based_port
13
+ redirect_test_io do
14
+ @server = Mongrel::HttpServer.new('127.0.0.1', @port)
15
+ end
16
+ @server.run
17
+ @client = Net::HTTP.new('127.0.0.1', @port)
18
+ end
19
+
20
+ def teardown
21
+ @server.stop(true)
22
+ end
23
+
24
+ def test_simple_redirect
25
+ tester = Mongrel::RedirectHandler.new('/yo')
26
+ @server.register("/test", tester)
27
+
28
+ sleep(1)
29
+ res = @client.request_get('/test')
30
+ assert res != nil, "Didn't get a response"
31
+ assert_equal ['/yo'], res.get_fields('Location')
32
+ end
33
+
34
+ def test_rewrite
35
+ tester = Mongrel::RedirectHandler.new(/(\w+)/, '+\1+')
36
+ @server.register("/test", tester)
37
+
38
+ sleep(1)
39
+ res = @client.request_get('/test/something')
40
+ assert_equal ['/+test+/+something+'], res.get_fields('Location')
41
+ end
42
+
43
+ end
44
+
45
+