edgar-rack 1.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (138) hide show
  1. data/COPYING +18 -0
  2. data/KNOWN-ISSUES +21 -0
  3. data/README +401 -0
  4. data/Rakefile +101 -0
  5. data/SPEC +171 -0
  6. data/bin/rackup +4 -0
  7. data/contrib/rack_logo.svg +111 -0
  8. data/example/lobster.ru +4 -0
  9. data/example/protectedlobster.rb +14 -0
  10. data/example/protectedlobster.ru +8 -0
  11. data/lib/rack.rb +81 -0
  12. data/lib/rack/auth/abstract/handler.rb +37 -0
  13. data/lib/rack/auth/abstract/request.rb +43 -0
  14. data/lib/rack/auth/basic.rb +58 -0
  15. data/lib/rack/auth/digest/md5.rb +124 -0
  16. data/lib/rack/auth/digest/nonce.rb +51 -0
  17. data/lib/rack/auth/digest/params.rb +53 -0
  18. data/lib/rack/auth/digest/request.rb +40 -0
  19. data/lib/rack/builder.rb +80 -0
  20. data/lib/rack/cascade.rb +41 -0
  21. data/lib/rack/chunked.rb +52 -0
  22. data/lib/rack/commonlogger.rb +49 -0
  23. data/lib/rack/conditionalget.rb +63 -0
  24. data/lib/rack/config.rb +15 -0
  25. data/lib/rack/content_length.rb +29 -0
  26. data/lib/rack/content_type.rb +23 -0
  27. data/lib/rack/deflater.rb +96 -0
  28. data/lib/rack/directory.rb +157 -0
  29. data/lib/rack/etag.rb +59 -0
  30. data/lib/rack/file.rb +118 -0
  31. data/lib/rack/handler.rb +88 -0
  32. data/lib/rack/handler/cgi.rb +61 -0
  33. data/lib/rack/handler/evented_mongrel.rb +8 -0
  34. data/lib/rack/handler/fastcgi.rb +90 -0
  35. data/lib/rack/handler/lsws.rb +61 -0
  36. data/lib/rack/handler/mongrel.rb +90 -0
  37. data/lib/rack/handler/scgi.rb +59 -0
  38. data/lib/rack/handler/swiftiplied_mongrel.rb +8 -0
  39. data/lib/rack/handler/thin.rb +17 -0
  40. data/lib/rack/handler/webrick.rb +73 -0
  41. data/lib/rack/head.rb +19 -0
  42. data/lib/rack/lint.rb +567 -0
  43. data/lib/rack/lobster.rb +65 -0
  44. data/lib/rack/lock.rb +44 -0
  45. data/lib/rack/logger.rb +18 -0
  46. data/lib/rack/methodoverride.rb +27 -0
  47. data/lib/rack/mime.rb +210 -0
  48. data/lib/rack/mock.rb +185 -0
  49. data/lib/rack/nulllogger.rb +18 -0
  50. data/lib/rack/recursive.rb +61 -0
  51. data/lib/rack/reloader.rb +109 -0
  52. data/lib/rack/request.rb +307 -0
  53. data/lib/rack/response.rb +151 -0
  54. data/lib/rack/rewindable_input.rb +104 -0
  55. data/lib/rack/runtime.rb +27 -0
  56. data/lib/rack/sendfile.rb +139 -0
  57. data/lib/rack/server.rb +289 -0
  58. data/lib/rack/session/abstract/id.rb +348 -0
  59. data/lib/rack/session/cookie.rb +152 -0
  60. data/lib/rack/session/memcache.rb +93 -0
  61. data/lib/rack/session/pool.rb +79 -0
  62. data/lib/rack/showexceptions.rb +378 -0
  63. data/lib/rack/showstatus.rb +113 -0
  64. data/lib/rack/static.rb +53 -0
  65. data/lib/rack/urlmap.rb +55 -0
  66. data/lib/rack/utils.rb +698 -0
  67. data/rack.gemspec +39 -0
  68. data/test/cgi/lighttpd.conf +25 -0
  69. data/test/cgi/rackup_stub.rb +6 -0
  70. data/test/cgi/sample_rackup.ru +5 -0
  71. data/test/cgi/test +9 -0
  72. data/test/cgi/test.fcgi +8 -0
  73. data/test/cgi/test.ru +5 -0
  74. data/test/gemloader.rb +6 -0
  75. data/test/multipart/bad_robots +259 -0
  76. data/test/multipart/binary +0 -0
  77. data/test/multipart/empty +10 -0
  78. data/test/multipart/fail_16384_nofile +814 -0
  79. data/test/multipart/file1.txt +1 -0
  80. data/test/multipart/filename_and_modification_param +7 -0
  81. data/test/multipart/filename_with_escaped_quotes +6 -0
  82. data/test/multipart/filename_with_escaped_quotes_and_modification_param +7 -0
  83. data/test/multipart/filename_with_percent_escaped_quotes +6 -0
  84. data/test/multipart/filename_with_unescaped_quotes +6 -0
  85. data/test/multipart/ie +6 -0
  86. data/test/multipart/nested +10 -0
  87. data/test/multipart/none +9 -0
  88. data/test/multipart/semicolon +6 -0
  89. data/test/multipart/text +15 -0
  90. data/test/rackup/config.ru +31 -0
  91. data/test/spec_auth_basic.rb +70 -0
  92. data/test/spec_auth_digest.rb +241 -0
  93. data/test/spec_builder.rb +123 -0
  94. data/test/spec_cascade.rb +45 -0
  95. data/test/spec_cgi.rb +102 -0
  96. data/test/spec_chunked.rb +60 -0
  97. data/test/spec_commonlogger.rb +56 -0
  98. data/test/spec_conditionalget.rb +86 -0
  99. data/test/spec_config.rb +23 -0
  100. data/test/spec_content_length.rb +36 -0
  101. data/test/spec_content_type.rb +29 -0
  102. data/test/spec_deflater.rb +125 -0
  103. data/test/spec_directory.rb +57 -0
  104. data/test/spec_etag.rb +75 -0
  105. data/test/spec_fastcgi.rb +107 -0
  106. data/test/spec_file.rb +92 -0
  107. data/test/spec_handler.rb +49 -0
  108. data/test/spec_head.rb +30 -0
  109. data/test/spec_lint.rb +515 -0
  110. data/test/spec_lobster.rb +43 -0
  111. data/test/spec_lock.rb +142 -0
  112. data/test/spec_logger.rb +28 -0
  113. data/test/spec_methodoverride.rb +58 -0
  114. data/test/spec_mock.rb +241 -0
  115. data/test/spec_mongrel.rb +182 -0
  116. data/test/spec_nulllogger.rb +12 -0
  117. data/test/spec_recursive.rb +69 -0
  118. data/test/spec_request.rb +774 -0
  119. data/test/spec_response.rb +245 -0
  120. data/test/spec_rewindable_input.rb +118 -0
  121. data/test/spec_runtime.rb +39 -0
  122. data/test/spec_sendfile.rb +83 -0
  123. data/test/spec_server.rb +8 -0
  124. data/test/spec_session_abstract_id.rb +43 -0
  125. data/test/spec_session_cookie.rb +171 -0
  126. data/test/spec_session_memcache.rb +289 -0
  127. data/test/spec_session_pool.rb +200 -0
  128. data/test/spec_showexceptions.rb +87 -0
  129. data/test/spec_showstatus.rb +79 -0
  130. data/test/spec_static.rb +48 -0
  131. data/test/spec_thin.rb +86 -0
  132. data/test/spec_urlmap.rb +213 -0
  133. data/test/spec_utils.rb +678 -0
  134. data/test/spec_webrick.rb +141 -0
  135. data/test/testrequest.rb +78 -0
  136. data/test/unregistered_handler/rack/handler/unregistered.rb +7 -0
  137. data/test/unregistered_handler/rack/handler/unregistered_long_one.rb +7 -0
  138. metadata +329 -0
@@ -0,0 +1,182 @@
1
+ begin
2
+ require 'rack'
3
+ require 'rack/handler/mongrel'
4
+ require File.expand_path('../testrequest', __FILE__)
5
+ require 'timeout'
6
+
7
+ Thread.abort_on_exception = true
8
+ $tcp_defer_accept_opts = nil
9
+ $tcp_cork_opts = nil
10
+
11
+ describe Rack::Handler::Mongrel do
12
+ extend TestRequest::Helpers
13
+
14
+ @server = Mongrel::HttpServer.new(@host='0.0.0.0', @port=9201)
15
+ @server.register('/test',
16
+ Rack::Handler::Mongrel.new(Rack::Lint.new(TestRequest.new)))
17
+ @server.register('/stream',
18
+ Rack::Handler::Mongrel.new(Rack::Lint.new(StreamingRequest)))
19
+ @acc = @server.run
20
+
21
+ should "respond" do
22
+ lambda {
23
+ GET("/test")
24
+ }.should.not.raise
25
+ end
26
+
27
+ should "be a Mongrel" do
28
+ GET("/test")
29
+ status.should.equal 200
30
+ response["SERVER_SOFTWARE"].should =~ /Mongrel/
31
+ response["HTTP_VERSION"].should.equal "HTTP/1.1"
32
+ response["SERVER_PROTOCOL"].should.equal "HTTP/1.1"
33
+ response["SERVER_PORT"].should.equal "9201"
34
+ response["SERVER_NAME"].should.equal "0.0.0.0"
35
+ end
36
+
37
+ should "have rack headers" do
38
+ GET("/test")
39
+ response["rack.version"].should.equal [1,1]
40
+ response["rack.multithread"].should.be.true
41
+ response["rack.multiprocess"].should.be.false
42
+ response["rack.run_once"].should.be.false
43
+ end
44
+
45
+ should "have CGI headers on GET" do
46
+ GET("/test")
47
+ response["REQUEST_METHOD"].should.equal "GET"
48
+ response["SCRIPT_NAME"].should.equal "/test"
49
+ response["REQUEST_PATH"].should.equal "/test"
50
+ response["PATH_INFO"].should.be.equal ""
51
+ response["QUERY_STRING"].should.equal ""
52
+ response["test.postdata"].should.equal ""
53
+
54
+ GET("/test/foo?quux=1")
55
+ response["REQUEST_METHOD"].should.equal "GET"
56
+ response["SCRIPT_NAME"].should.equal "/test"
57
+ response["REQUEST_PATH"].should.equal "/test/foo"
58
+ response["PATH_INFO"].should.equal "/foo"
59
+ response["QUERY_STRING"].should.equal "quux=1"
60
+ end
61
+
62
+ should "have CGI headers on POST" do
63
+ POST("/test", {"rack-form-data" => "23"}, {'X-test-header' => '42'})
64
+ status.should.equal 200
65
+ response["REQUEST_METHOD"].should.equal "POST"
66
+ response["SCRIPT_NAME"].should.equal "/test"
67
+ response["REQUEST_PATH"].should.equal "/test"
68
+ response["QUERY_STRING"].should.equal ""
69
+ response["HTTP_X_TEST_HEADER"].should.equal "42"
70
+ response["test.postdata"].should.equal "rack-form-data=23"
71
+ end
72
+
73
+ should "support HTTP auth" do
74
+ GET("/test", {:user => "ruth", :passwd => "secret"})
75
+ response["HTTP_AUTHORIZATION"].should.equal "Basic cnV0aDpzZWNyZXQ="
76
+ end
77
+
78
+ should "set status" do
79
+ GET("/test?secret")
80
+ status.should.equal 403
81
+ response["rack.url_scheme"].should.equal "http"
82
+ end
83
+
84
+ should "provide a .run" do
85
+ block_ran = false
86
+ Thread.new {
87
+ Rack::Handler::Mongrel.run(lambda {}, {:Port => 9211}) { |server|
88
+ server.should.be.kind_of Mongrel::HttpServer
89
+ block_ran = true
90
+ }
91
+ }
92
+ sleep 1
93
+ block_ran.should.be.true
94
+ end
95
+
96
+ should "provide a .run that maps a hash" do
97
+ block_ran = false
98
+ Thread.new {
99
+ map = {'/'=>lambda{},'/foo'=>lambda{}}
100
+ Rack::Handler::Mongrel.run(map, :map => true, :Port => 9221) { |server|
101
+ server.should.be.kind_of Mongrel::HttpServer
102
+ server.classifier.uris.size.should.equal 2
103
+ server.classifier.uris.should.not.include '/arf'
104
+ server.classifier.uris.should.include '/'
105
+ server.classifier.uris.should.include '/foo'
106
+ block_ran = true
107
+ }
108
+ }
109
+ sleep 1
110
+ block_ran.should.be.true
111
+ end
112
+
113
+ should "provide a .run that maps a urlmap" do
114
+ block_ran = false
115
+ Thread.new {
116
+ map = Rack::URLMap.new({'/'=>lambda{},'/bar'=>lambda{}})
117
+ Rack::Handler::Mongrel.run(map, {:map => true, :Port => 9231}) { |server|
118
+ server.should.be.kind_of Mongrel::HttpServer
119
+ server.classifier.uris.size.should.equal 2
120
+ server.classifier.uris.should.not.include '/arf'
121
+ server.classifier.uris.should.include '/'
122
+ server.classifier.uris.should.include '/bar'
123
+ block_ran = true
124
+ }
125
+ }
126
+ sleep 1
127
+ block_ran.should.be.true
128
+ end
129
+
130
+ should "provide a .run that maps a urlmap restricting by host" do
131
+ block_ran = false
132
+ Thread.new {
133
+ map = Rack::URLMap.new({
134
+ '/' => lambda{},
135
+ '/foo' => lambda{},
136
+ '/bar' => lambda{},
137
+ 'http://localhost/' => lambda{},
138
+ 'http://localhost/bar' => lambda{},
139
+ 'http://falsehost/arf' => lambda{},
140
+ 'http://falsehost/qux' => lambda{}
141
+ })
142
+ opt = {:map => true, :Port => 9241, :Host => 'localhost'}
143
+ Rack::Handler::Mongrel.run(map, opt) { |server|
144
+ server.should.be.kind_of Mongrel::HttpServer
145
+ server.classifier.uris.should.include '/'
146
+ server.classifier.handler_map['/'].size.should.equal 2
147
+ server.classifier.uris.should.include '/foo'
148
+ server.classifier.handler_map['/foo'].size.should.equal 1
149
+ server.classifier.uris.should.include '/bar'
150
+ server.classifier.handler_map['/bar'].size.should.equal 2
151
+ server.classifier.uris.should.not.include '/qux'
152
+ server.classifier.uris.should.not.include '/arf'
153
+ server.classifier.uris.size.should.equal 3
154
+ block_ran = true
155
+ }
156
+ }
157
+ sleep 1
158
+ block_ran.should.be.true
159
+ end
160
+
161
+ should "stream #each part of the response" do
162
+ body = ''
163
+ begin
164
+ Timeout.timeout(1) do
165
+ Net::HTTP.start(@host, @port) do |http|
166
+ get = Net::HTTP::Get.new('/stream')
167
+ http.request(get) do |response|
168
+ response.read_body { |part| body << part }
169
+ end
170
+ end
171
+ end
172
+ rescue Timeout::Error
173
+ end
174
+ body.should.not.be.empty
175
+ end
176
+
177
+ @acc.raise Mongrel::StopServer
178
+ end
179
+
180
+ rescue LoadError
181
+ warn "Skipping Rack::Handler::Mongrel tests (Mongrel is required). `gem install mongrel` and try again."
182
+ end
@@ -0,0 +1,12 @@
1
+ require 'rack/nulllogger'
2
+
3
+ describe Rack::NullLogger do
4
+ should "act as a noop logger" do
5
+ app = lambda { |env|
6
+ env['rack.logger'].warn "b00m"
7
+ [200, {'Content-Type' => 'text/plain'}, ["Hello, World!"]]
8
+ }
9
+ logger = Rack::NullLogger.new(app)
10
+ lambda{ logger.call({}) }.should.not.raise
11
+ end
12
+ end
@@ -0,0 +1,69 @@
1
+ require 'rack/recursive'
2
+ require 'rack/mock'
3
+
4
+ describe Rack::Recursive do
5
+ @app1 = lambda { |env|
6
+ res = Rack::Response.new
7
+ res["X-Path-Info"] = env["PATH_INFO"]
8
+ res["X-Query-String"] = env["QUERY_STRING"]
9
+ res.finish do |inner_res|
10
+ inner_res.write "App1"
11
+ end
12
+ }
13
+
14
+ @app2 = lambda { |env|
15
+ Rack::Response.new.finish do |res|
16
+ res.write "App2"
17
+ _, _, body = env['rack.recursive.include'].call(env, "/app1")
18
+ body.each { |b|
19
+ res.write b
20
+ }
21
+ end
22
+ }
23
+
24
+ @app3 = lambda { |env|
25
+ raise Rack::ForwardRequest.new("/app1")
26
+ }
27
+
28
+ @app4 = lambda { |env|
29
+ raise Rack::ForwardRequest.new("http://example.org/app1/quux?meh")
30
+ }
31
+
32
+ should "allow for subrequests" do
33
+ res = Rack::MockRequest.new(Rack::Recursive.new(
34
+ Rack::URLMap.new("/app1" => @app1,
35
+ "/app2" => @app2))).
36
+ get("/app2")
37
+
38
+ res.should.be.ok
39
+ res.body.should.equal "App2App1"
40
+ end
41
+
42
+ should "raise error on requests not below the app" do
43
+ app = Rack::URLMap.new("/app1" => @app1,
44
+ "/app" => Rack::Recursive.new(
45
+ Rack::URLMap.new("/1" => @app1,
46
+ "/2" => @app2)))
47
+
48
+ lambda {
49
+ Rack::MockRequest.new(app).get("/app/2")
50
+ }.should.raise(ArgumentError).
51
+ message.should =~ /can only include below/
52
+ end
53
+
54
+ should "support forwarding" do
55
+ app = Rack::Recursive.new(Rack::URLMap.new("/app1" => @app1,
56
+ "/app3" => @app3,
57
+ "/app4" => @app4))
58
+
59
+ res = Rack::MockRequest.new(app).get("/app3")
60
+ res.should.be.ok
61
+ res.body.should.equal "App1"
62
+
63
+ res = Rack::MockRequest.new(app).get("/app4")
64
+ res.should.be.ok
65
+ res.body.should.equal "App1"
66
+ res["X-Path-Info"].should.equal "/quux"
67
+ res["X-Query-String"].should.equal "meh"
68
+ end
69
+ end
@@ -0,0 +1,774 @@
1
+ require 'stringio'
2
+ require 'cgi'
3
+ require 'rack/request'
4
+ require 'rack/mock'
5
+
6
+ describe Rack::Request do
7
+ should "wrap the rack variables" do
8
+ req = Rack::Request.new(Rack::MockRequest.env_for("http://example.com:8080/"))
9
+
10
+ req.body.should.respond_to? :gets
11
+ req.scheme.should.equal "http"
12
+ req.request_method.should.equal "GET"
13
+
14
+ req.should.be.get
15
+ req.should.not.be.post
16
+ req.should.not.be.put
17
+ req.should.not.be.delete
18
+ req.should.not.be.head
19
+
20
+ req.script_name.should.equal ""
21
+ req.path_info.should.equal "/"
22
+ req.query_string.should.equal ""
23
+
24
+ req.host.should.equal "example.com"
25
+ req.port.should.equal 8080
26
+
27
+ req.content_length.should.equal "0"
28
+ req.content_type.should.be.nil
29
+ end
30
+
31
+ should "figure out the correct host" do
32
+ req = Rack::Request.new \
33
+ Rack::MockRequest.env_for("/", "HTTP_HOST" => "www2.example.org")
34
+ req.host.should.equal "www2.example.org"
35
+
36
+ req = Rack::Request.new \
37
+ Rack::MockRequest.env_for("/", "SERVER_NAME" => "example.org", "SERVER_PORT" => "9292")
38
+ req.host.should.equal "example.org"
39
+
40
+ req = Rack::Request.new \
41
+ Rack::MockRequest.env_for("/", "HTTP_HOST" => "localhost:81", "HTTP_X_FORWARDED_HOST" => "example.org:9292")
42
+ req.host.should.equal "example.org"
43
+
44
+ env = Rack::MockRequest.env_for("/", "SERVER_ADDR" => "192.168.1.1", "SERVER_PORT" => "9292")
45
+ env.delete("SERVER_NAME")
46
+ req = Rack::Request.new(env)
47
+ req.host.should.equal "192.168.1.1"
48
+
49
+ env = Rack::MockRequest.env_for("/")
50
+ env.delete("SERVER_NAME")
51
+ req = Rack::Request.new(env)
52
+ req.host.should.equal ""
53
+ end
54
+
55
+ should "figure out the correct port" do
56
+ req = Rack::Request.new \
57
+ Rack::MockRequest.env_for("/", "HTTP_HOST" => "www2.example.org")
58
+ req.port.should.equal 80
59
+
60
+ req = Rack::Request.new \
61
+ Rack::MockRequest.env_for("/", "HTTP_HOST" => "www2.example.org:81")
62
+ req.port.should.equal 81
63
+
64
+ req = Rack::Request.new \
65
+ Rack::MockRequest.env_for("/", "SERVER_NAME" => "example.org", "SERVER_PORT" => "9292")
66
+ req.port.should.equal 9292
67
+
68
+ req = Rack::Request.new \
69
+ Rack::MockRequest.env_for("/", "HTTP_HOST" => "localhost:81", "HTTP_X_FORWARDED_HOST" => "example.org:9292")
70
+ req.port.should.equal 9292
71
+
72
+ req = Rack::Request.new \
73
+ Rack::MockRequest.env_for("/", "HTTP_HOST" => "localhost:81", "HTTP_X_FORWARDED_HOST" => "example.org")
74
+ req.port.should.equal 80
75
+
76
+ req = Rack::Request.new \
77
+ Rack::MockRequest.env_for("/", "HTTP_HOST" => "localhost:81", "HTTP_X_FORWARDED_HOST" => "example.org", "HTTP_X_FORWARDED_SSL" => "on")
78
+ req.port.should.equal 443
79
+
80
+ req = Rack::Request.new \
81
+ Rack::MockRequest.env_for("/", "HTTP_HOST" => "localhost:81", "HTTP_X_FORWARDED_HOST" => "example.org", "HTTP_X_FORWARDED_PROTO" => "https")
82
+ req.port.should.equal 443
83
+
84
+ req = Rack::Request.new \
85
+ Rack::MockRequest.env_for("/", "HTTP_HOST" => "localhost:81", "HTTP_X_FORWARDED_HOST" => "example.org", "HTTP_X_FORWARDED_PORT" => "9393")
86
+ req.port.should.equal 9393
87
+
88
+ req = Rack::Request.new \
89
+ Rack::MockRequest.env_for("/", "HTTP_HOST" => "localhost:81", "HTTP_X_FORWARDED_HOST" => "example.org:9393", "SERVER_PORT" => "80")
90
+ req.port.should.equal 9393
91
+
92
+ req = Rack::Request.new \
93
+ Rack::MockRequest.env_for("/", "HTTP_HOST" => "localhost:81", "HTTP_X_FORWARDED_HOST" => "example.org", "SERVER_PORT" => "9393")
94
+ req.port.should.equal 80
95
+ end
96
+
97
+ should "figure out the correct host with port" do
98
+ req = Rack::Request.new \
99
+ Rack::MockRequest.env_for("/", "HTTP_HOST" => "www2.example.org")
100
+ req.host_with_port.should.equal "www2.example.org"
101
+
102
+ req = Rack::Request.new \
103
+ Rack::MockRequest.env_for("/", "HTTP_HOST" => "localhost:81")
104
+ req.host_with_port.should.equal "localhost:81"
105
+
106
+ req = Rack::Request.new \
107
+ Rack::MockRequest.env_for("/", "SERVER_NAME" => "example.org", "SERVER_PORT" => "9292")
108
+ req.host_with_port.should.equal "example.org:9292"
109
+
110
+ req = Rack::Request.new \
111
+ Rack::MockRequest.env_for("/", "HTTP_HOST" => "localhost:81", "HTTP_X_FORWARDED_HOST" => "example.org:9292")
112
+ req.host_with_port.should.equal "example.org:9292"
113
+
114
+ req = Rack::Request.new \
115
+ Rack::MockRequest.env_for("/", "HTTP_HOST" => "localhost:81", "HTTP_X_FORWARDED_HOST" => "example.org", "SERVER_PORT" => "9393")
116
+ req.host_with_port.should.equal "example.org"
117
+ end
118
+
119
+ should "parse the query string" do
120
+ req = Rack::Request.new(Rack::MockRequest.env_for("/?foo=bar&quux=bla"))
121
+ req.query_string.should.equal "foo=bar&quux=bla"
122
+ req.GET.should.equal "foo" => "bar", "quux" => "bla"
123
+ req.POST.should.be.empty
124
+ req.params.should.equal "foo" => "bar", "quux" => "bla"
125
+ end
126
+
127
+ should "raise if rack.input is missing" do
128
+ req = Rack::Request.new({})
129
+ lambda { req.POST }.should.raise(RuntimeError)
130
+ end
131
+
132
+ should "parse POST data when method is POST and no Content-Type given" do
133
+ req = Rack::Request.new \
134
+ Rack::MockRequest.env_for("/?foo=quux",
135
+ "REQUEST_METHOD" => 'POST',
136
+ :input => "foo=bar&quux=bla")
137
+ req.content_type.should.be.nil
138
+ req.media_type.should.be.nil
139
+ req.query_string.should.equal "foo=quux"
140
+ req.GET.should.equal "foo" => "quux"
141
+ req.POST.should.equal "foo" => "bar", "quux" => "bla"
142
+ req.params.should.equal "foo" => "bar", "quux" => "bla"
143
+ end
144
+
145
+ should "parse POST data with explicit content type regardless of method" do
146
+ req = Rack::Request.new \
147
+ Rack::MockRequest.env_for("/",
148
+ "CONTENT_TYPE" => 'application/x-www-form-urlencoded;foo=bar',
149
+ :input => "foo=bar&quux=bla")
150
+ req.content_type.should.equal 'application/x-www-form-urlencoded;foo=bar'
151
+ req.media_type.should.equal 'application/x-www-form-urlencoded'
152
+ req.media_type_params['foo'].should.equal 'bar'
153
+ req.POST.should.equal "foo" => "bar", "quux" => "bla"
154
+ req.params.should.equal "foo" => "bar", "quux" => "bla"
155
+ end
156
+
157
+ should "not parse POST data when media type is not form-data" do
158
+ req = Rack::Request.new \
159
+ Rack::MockRequest.env_for("/?foo=quux",
160
+ "REQUEST_METHOD" => 'POST',
161
+ "CONTENT_TYPE" => 'text/plain;charset=utf-8',
162
+ :input => "foo=bar&quux=bla")
163
+ req.content_type.should.equal 'text/plain;charset=utf-8'
164
+ req.media_type.should.equal 'text/plain'
165
+ req.media_type_params['charset'].should.equal 'utf-8'
166
+ req.POST.should.be.empty
167
+ req.params.should.equal "foo" => "quux"
168
+ req.body.read.should.equal "foo=bar&quux=bla"
169
+ end
170
+
171
+ should "parse POST data on PUT when media type is form-data" do
172
+ req = Rack::Request.new \
173
+ Rack::MockRequest.env_for("/?foo=quux",
174
+ "REQUEST_METHOD" => 'PUT',
175
+ "CONTENT_TYPE" => 'application/x-www-form-urlencoded',
176
+ :input => "foo=bar&quux=bla")
177
+ req.POST.should.equal "foo" => "bar", "quux" => "bla"
178
+ req.body.read.should.equal "foo=bar&quux=bla"
179
+ end
180
+
181
+ should "rewind input after parsing POST data" do
182
+ input = StringIO.new("foo=bar&quux=bla")
183
+ req = Rack::Request.new \
184
+ Rack::MockRequest.env_for("/",
185
+ "CONTENT_TYPE" => 'application/x-www-form-urlencoded;foo=bar',
186
+ :input => input)
187
+ req.params.should.equal "foo" => "bar", "quux" => "bla"
188
+ input.read.should.equal "foo=bar&quux=bla"
189
+ end
190
+
191
+ should "clean up Safari's ajax POST body" do
192
+ req = Rack::Request.new \
193
+ Rack::MockRequest.env_for("/",
194
+ 'REQUEST_METHOD' => 'POST', :input => "foo=bar&quux=bla\0")
195
+ req.POST.should.equal "foo" => "bar", "quux" => "bla"
196
+ end
197
+
198
+ should "get value by key from params with #[]" do
199
+ req = Rack::Request.new \
200
+ Rack::MockRequest.env_for("?foo=quux")
201
+ req['foo'].should.equal 'quux'
202
+ req[:foo].should.equal 'quux'
203
+ end
204
+
205
+ should "set value to key on params with #[]=" do
206
+ req = Rack::Request.new \
207
+ Rack::MockRequest.env_for("?foo=duh")
208
+ req['foo'].should.equal 'duh'
209
+ req[:foo].should.equal 'duh'
210
+ req.params.should.equal 'foo' => 'duh'
211
+
212
+ req['foo'] = 'bar'
213
+ req.params.should.equal 'foo' => 'bar'
214
+ req['foo'].should.equal 'bar'
215
+ req[:foo].should.equal 'bar'
216
+
217
+ req[:foo] = 'jaz'
218
+ req.params.should.equal 'foo' => 'jaz'
219
+ req['foo'].should.equal 'jaz'
220
+ req[:foo].should.equal 'jaz'
221
+ end
222
+
223
+ should "return values for the keys in the order given from values_at" do
224
+ req = Rack::Request.new \
225
+ Rack::MockRequest.env_for("?foo=baz&wun=der&bar=ful")
226
+ req.values_at('foo').should.equal ['baz']
227
+ req.values_at('foo', 'wun').should.equal ['baz', 'der']
228
+ req.values_at('bar', 'foo', 'wun').should.equal ['ful', 'baz', 'der']
229
+ end
230
+
231
+ should "extract referrer correctly" do
232
+ req = Rack::Request.new \
233
+ Rack::MockRequest.env_for("/", "HTTP_REFERER" => "/some/path")
234
+ req.referer.should.equal "/some/path"
235
+
236
+ req = Rack::Request.new \
237
+ Rack::MockRequest.env_for("/")
238
+ req.referer.should.equal nil
239
+ end
240
+
241
+ should "extract user agent correctly" do
242
+ req = Rack::Request.new \
243
+ Rack::MockRequest.env_for("/", "HTTP_USER_AGENT" => "Mozilla/4.0 (compatible)")
244
+ req.user_agent.should.equal "Mozilla/4.0 (compatible)"
245
+
246
+ req = Rack::Request.new \
247
+ Rack::MockRequest.env_for("/")
248
+ req.user_agent.should.equal nil
249
+ end
250
+
251
+ should "treat missing content type as nil" do
252
+ req = Rack::Request.new \
253
+ Rack::MockRequest.env_for("/")
254
+ req.content_type.should.equal nil
255
+ end
256
+
257
+ should "treat empty content type as nil" do
258
+ req = Rack::Request.new \
259
+ Rack::MockRequest.env_for("/", "CONTENT_TYPE" => "")
260
+ req.content_type.should.equal nil
261
+ end
262
+
263
+ should "return nil media type for empty content type" do
264
+ req = Rack::Request.new \
265
+ Rack::MockRequest.env_for("/", "CONTENT_TYPE" => "")
266
+ req.media_type.should.equal nil
267
+ end
268
+
269
+ should "cache, but invalidates the cache" do
270
+ req = Rack::Request.new \
271
+ Rack::MockRequest.env_for("/?foo=quux",
272
+ "CONTENT_TYPE" => "application/x-www-form-urlencoded",
273
+ :input => "foo=bar&quux=bla")
274
+ req.GET.should.equal "foo" => "quux"
275
+ req.GET.should.equal "foo" => "quux"
276
+ req.env["QUERY_STRING"] = "bla=foo"
277
+ req.GET.should.equal "bla" => "foo"
278
+ req.GET.should.equal "bla" => "foo"
279
+
280
+ req.POST.should.equal "foo" => "bar", "quux" => "bla"
281
+ req.POST.should.equal "foo" => "bar", "quux" => "bla"
282
+ req.env["rack.input"] = StringIO.new("foo=bla&quux=bar")
283
+ req.POST.should.equal "foo" => "bla", "quux" => "bar"
284
+ req.POST.should.equal "foo" => "bla", "quux" => "bar"
285
+ end
286
+
287
+ should "figure out if called via XHR" do
288
+ req = Rack::Request.new(Rack::MockRequest.env_for(""))
289
+ req.should.not.be.xhr
290
+
291
+ req = Rack::Request.new \
292
+ Rack::MockRequest.env_for("", "HTTP_X_REQUESTED_WITH" => "XMLHttpRequest")
293
+ req.should.be.xhr
294
+ end
295
+
296
+ should "ssl detection" do
297
+ request = Rack::Request.new(Rack::MockRequest.env_for("/"))
298
+ request.scheme.should.equal "http"
299
+ request.should.not.be.ssl?
300
+
301
+ request = Rack::Request.new(Rack::MockRequest.env_for("/", 'HTTPS' => 'on'))
302
+ request.scheme.should.equal "https"
303
+ request.should.be.ssl?
304
+
305
+ request = Rack::Request.new(Rack::MockRequest.env_for("/", 'rack.url_scheme' => 'https'))
306
+ request.scheme.should.equal "https"
307
+ request.should.be.ssl?
308
+
309
+ request = Rack::Request.new(Rack::MockRequest.env_for("/", 'HTTP_HOST' => 'www.example.org:8080'))
310
+ request.scheme.should.equal "http"
311
+ request.should.not.be.ssl?
312
+
313
+ request = Rack::Request.new(Rack::MockRequest.env_for("/", 'HTTP_HOST' => 'www.example.org:8443', 'HTTPS' => 'on'))
314
+ request.scheme.should.equal "https"
315
+ request.should.be.ssl?
316
+
317
+ request = Rack::Request.new(Rack::MockRequest.env_for("/", 'HTTP_HOST' => 'www.example.org:8443', 'HTTP_X_FORWARDED_SSL' => 'on'))
318
+ request.scheme.should.equal "https"
319
+ request.should.be.ssl?
320
+
321
+ request = Rack::Request.new(Rack::MockRequest.env_for("/", 'HTTP_X_FORWARDED_PROTO' => 'https'))
322
+ request.scheme.should.equal "https"
323
+ request.should.be.ssl?
324
+
325
+ request = Rack::Request.new(Rack::MockRequest.env_for("/", 'HTTP_X_FORWARDED_PROTO' => 'https, http, http'))
326
+ request.scheme.should.equal "https"
327
+ request.should.be.ssl
328
+ end
329
+
330
+ should "parse cookies" do
331
+ req = Rack::Request.new \
332
+ Rack::MockRequest.env_for("", "HTTP_COOKIE" => "foo=bar;quux=h&m")
333
+ req.cookies.should.equal "foo" => "bar", "quux" => "h&m"
334
+ req.cookies.should.equal "foo" => "bar", "quux" => "h&m"
335
+ req.env.delete("HTTP_COOKIE")
336
+ req.cookies.should.equal({})
337
+ end
338
+
339
+ should "parse cookies according to RFC 2109" do
340
+ req = Rack::Request.new \
341
+ Rack::MockRequest.env_for('', 'HTTP_COOKIE' => 'foo=bar;foo=car')
342
+ req.cookies.should.equal 'foo' => 'bar'
343
+ end
344
+
345
+ should 'parse cookies with quotes' do
346
+ req = Rack::Request.new Rack::MockRequest.env_for('', {
347
+ 'HTTP_COOKIE' => '$Version="1"; Customer="WILE_E_COYOTE"; $Path="/acme"; Part_Number="Rocket_Launcher_0001"; $Path="/acme"'
348
+ })
349
+ req.cookies.should.equal({
350
+ '$Version' => '"1"',
351
+ 'Customer' => '"WILE_E_COYOTE"',
352
+ '$Path' => '"/acme"',
353
+ 'Part_Number' => '"Rocket_Launcher_0001"',
354
+ })
355
+ end
356
+
357
+ should "provide setters" do
358
+ req = Rack::Request.new(e=Rack::MockRequest.env_for(""))
359
+ req.script_name.should.equal ""
360
+ req.script_name = "/foo"
361
+ req.script_name.should.equal "/foo"
362
+ e["SCRIPT_NAME"].should.equal "/foo"
363
+
364
+ req.path_info.should.equal "/"
365
+ req.path_info = "/foo"
366
+ req.path_info.should.equal "/foo"
367
+ e["PATH_INFO"].should.equal "/foo"
368
+ end
369
+
370
+ should "provide the original env" do
371
+ req = Rack::Request.new(e = Rack::MockRequest.env_for(""))
372
+ req.env.should == e
373
+ end
374
+
375
+ should "restore the base URL" do
376
+ Rack::Request.new(Rack::MockRequest.env_for("")).base_url.
377
+ should.equal "http://example.org"
378
+ Rack::Request.new(Rack::MockRequest.env_for("", "SCRIPT_NAME" => "/foo")).base_url.
379
+ should.equal "http://example.org"
380
+ end
381
+
382
+ should "restore the URL" do
383
+ Rack::Request.new(Rack::MockRequest.env_for("")).url.
384
+ should.equal "http://example.org/"
385
+ Rack::Request.new(Rack::MockRequest.env_for("", "SCRIPT_NAME" => "/foo")).url.
386
+ should.equal "http://example.org/foo/"
387
+ Rack::Request.new(Rack::MockRequest.env_for("/foo")).url.
388
+ should.equal "http://example.org/foo"
389
+ Rack::Request.new(Rack::MockRequest.env_for("?foo")).url.
390
+ should.equal "http://example.org/?foo"
391
+ Rack::Request.new(Rack::MockRequest.env_for("http://example.org:8080/")).url.
392
+ should.equal "http://example.org:8080/"
393
+ Rack::Request.new(Rack::MockRequest.env_for("https://example.org/")).url.
394
+ should.equal "https://example.org/"
395
+
396
+ Rack::Request.new(Rack::MockRequest.env_for("https://example.com:8080/foo?foo")).url.
397
+ should.equal "https://example.com:8080/foo?foo"
398
+ end
399
+
400
+ should "restore the full path" do
401
+ Rack::Request.new(Rack::MockRequest.env_for("")).fullpath.
402
+ should.equal "/"
403
+ Rack::Request.new(Rack::MockRequest.env_for("", "SCRIPT_NAME" => "/foo")).fullpath.
404
+ should.equal "/foo/"
405
+ Rack::Request.new(Rack::MockRequest.env_for("/foo")).fullpath.
406
+ should.equal "/foo"
407
+ Rack::Request.new(Rack::MockRequest.env_for("?foo")).fullpath.
408
+ should.equal "/?foo"
409
+ Rack::Request.new(Rack::MockRequest.env_for("http://example.org:8080/")).fullpath.
410
+ should.equal "/"
411
+ Rack::Request.new(Rack::MockRequest.env_for("https://example.org/")).fullpath.
412
+ should.equal "/"
413
+
414
+ Rack::Request.new(Rack::MockRequest.env_for("https://example.com:8080/foo?foo")).fullpath.
415
+ should.equal "/foo?foo"
416
+ end
417
+
418
+ should "handle multiple media type parameters" do
419
+ req = Rack::Request.new \
420
+ Rack::MockRequest.env_for("/",
421
+ "CONTENT_TYPE" => 'text/plain; foo=BAR,baz=bizzle dizzle;BLING=bam')
422
+ req.should.not.be.form_data
423
+ req.media_type_params.should.include 'foo'
424
+ req.media_type_params['foo'].should.equal 'BAR'
425
+ req.media_type_params.should.include 'baz'
426
+ req.media_type_params['baz'].should.equal 'bizzle dizzle'
427
+ req.media_type_params.should.not.include 'BLING'
428
+ req.media_type_params.should.include 'bling'
429
+ req.media_type_params['bling'].should.equal 'bam'
430
+ end
431
+
432
+ should "parse with junk before boundry" do
433
+ # Adapted from RFC 1867.
434
+ input = <<EOF
435
+ blah blah\r
436
+ \r
437
+ --AaB03x\r
438
+ content-disposition: form-data; name="reply"\r
439
+ \r
440
+ yes\r
441
+ --AaB03x\r
442
+ content-disposition: form-data; name="fileupload"; filename="dj.jpg"\r
443
+ Content-Type: image/jpeg\r
444
+ Content-Transfer-Encoding: base64\r
445
+ \r
446
+ /9j/4AAQSkZJRgABAQAAAQABAAD//gA+Q1JFQVRPUjogZ2QtanBlZyB2MS4wICh1c2luZyBJSkcg\r
447
+ --AaB03x--\r
448
+ EOF
449
+ req = Rack::Request.new Rack::MockRequest.env_for("/",
450
+ "CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
451
+ "CONTENT_LENGTH" => input.size,
452
+ :input => input)
453
+
454
+ req.POST.should.include "fileupload"
455
+ req.POST.should.include "reply"
456
+
457
+ req.should.be.form_data
458
+ req.content_length.should.equal input.size
459
+ req.media_type.should.equal 'multipart/form-data'
460
+ req.media_type_params.should.include 'boundary'
461
+ req.media_type_params['boundary'].should.equal 'AaB03x'
462
+
463
+ req.POST["reply"].should.equal "yes"
464
+
465
+ f = req.POST["fileupload"]
466
+ f.should.be.kind_of Hash
467
+ f[:type].should.equal "image/jpeg"
468
+ f[:filename].should.equal "dj.jpg"
469
+ f.should.include :tempfile
470
+ f[:tempfile].size.should.equal 76
471
+ end
472
+
473
+ should "parse multipart form data" do
474
+ # Adapted from RFC 1867.
475
+ input = <<EOF
476
+ --AaB03x\r
477
+ content-disposition: form-data; name="reply"\r
478
+ \r
479
+ yes\r
480
+ --AaB03x\r
481
+ content-disposition: form-data; name="fileupload"; filename="dj.jpg"\r
482
+ Content-Type: image/jpeg\r
483
+ Content-Transfer-Encoding: base64\r
484
+ \r
485
+ /9j/4AAQSkZJRgABAQAAAQABAAD//gA+Q1JFQVRPUjogZ2QtanBlZyB2MS4wICh1c2luZyBJSkcg\r
486
+ --AaB03x--\r
487
+ EOF
488
+ req = Rack::Request.new Rack::MockRequest.env_for("/",
489
+ "CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
490
+ "CONTENT_LENGTH" => input.size,
491
+ :input => input)
492
+
493
+ req.POST.should.include "fileupload"
494
+ req.POST.should.include "reply"
495
+
496
+ req.should.be.form_data
497
+ req.content_length.should.equal input.size
498
+ req.media_type.should.equal 'multipart/form-data'
499
+ req.media_type_params.should.include 'boundary'
500
+ req.media_type_params['boundary'].should.equal 'AaB03x'
501
+
502
+ req.POST["reply"].should.equal "yes"
503
+
504
+ f = req.POST["fileupload"]
505
+ f.should.be.kind_of Hash
506
+ f[:type].should.equal "image/jpeg"
507
+ f[:filename].should.equal "dj.jpg"
508
+ f.should.include :tempfile
509
+ f[:tempfile].size.should.equal 76
510
+ end
511
+
512
+ should "parse big multipart form data" do
513
+ input = <<EOF
514
+ --AaB03x\r
515
+ content-disposition: form-data; name="huge"; filename="huge"\r
516
+ \r
517
+ #{"x"*32768}\r
518
+ --AaB03x\r
519
+ content-disposition: form-data; name="mean"; filename="mean"\r
520
+ \r
521
+ --AaB03xha\r
522
+ --AaB03x--\r
523
+ EOF
524
+ req = Rack::Request.new Rack::MockRequest.env_for("/",
525
+ "CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
526
+ "CONTENT_LENGTH" => input.size,
527
+ :input => input)
528
+
529
+ req.POST["huge"][:tempfile].size.should.equal 32768
530
+ req.POST["mean"][:tempfile].size.should.equal 10
531
+ req.POST["mean"][:tempfile].read.should.equal "--AaB03xha"
532
+ end
533
+
534
+ should "detect invalid multipart form data" do
535
+ input = <<EOF
536
+ --AaB03x\r
537
+ content-disposition: form-data; name="huge"; filename="huge"\r
538
+ EOF
539
+ req = Rack::Request.new Rack::MockRequest.env_for("/",
540
+ "CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
541
+ "CONTENT_LENGTH" => input.size,
542
+ :input => input)
543
+
544
+ lambda { req.POST }.should.raise(EOFError)
545
+
546
+ input = <<EOF
547
+ --AaB03x\r
548
+ content-disposition: form-data; name="huge"; filename="huge"\r
549
+ \r
550
+ foo\r
551
+ EOF
552
+ req = Rack::Request.new Rack::MockRequest.env_for("/",
553
+ "CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
554
+ "CONTENT_LENGTH" => input.size,
555
+ :input => input)
556
+
557
+ lambda { req.POST }.should.raise(EOFError)
558
+
559
+ input = <<EOF
560
+ --AaB03x\r
561
+ content-disposition: form-data; name="huge"; filename="huge"\r
562
+ \r
563
+ foo\r
564
+ EOF
565
+ req = Rack::Request.new Rack::MockRequest.env_for("/",
566
+ "CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
567
+ "CONTENT_LENGTH" => input.size,
568
+ :input => input)
569
+
570
+ lambda { req.POST }.should.raise(EOFError)
571
+ end
572
+
573
+ should "correctly parse the part name from Content-Id header" do
574
+ input = <<EOF
575
+ --AaB03x\r
576
+ Content-Type: text/xml; charset=utf-8\r
577
+ Content-Id: <soap-start>\r
578
+ Content-Transfer-Encoding: 7bit\r
579
+ \r
580
+ foo\r
581
+ --AaB03x--\r
582
+ EOF
583
+ req = Rack::Request.new Rack::MockRequest.env_for("/",
584
+ "CONTENT_TYPE" => "multipart/related, boundary=AaB03x",
585
+ "CONTENT_LENGTH" => input.size,
586
+ :input => input)
587
+
588
+ req.params.keys.should.equal ["<soap-start>"]
589
+ end
590
+
591
+ should "not try to interpret binary as utf8" do
592
+ if /regexp/.respond_to?(:kcode) # < 1.9
593
+ begin
594
+ original_kcode = $KCODE
595
+ $KCODE='UTF8'
596
+
597
+ input = <<EOF
598
+ --AaB03x\r
599
+ content-disposition: form-data; name="fileupload"; filename="junk.a"\r
600
+ content-type: application/octet-stream\r
601
+ \r
602
+ #{[0x36,0xCF,0x0A,0xF8].pack('c*')}\r
603
+ --AaB03x--\r
604
+ EOF
605
+
606
+ req = Rack::Request.new Rack::MockRequest.env_for("/",
607
+ "CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
608
+ "CONTENT_LENGTH" => input.size,
609
+ :input => input)
610
+
611
+ lambda{req.POST}.should.not.raise(EOFError)
612
+ req.POST["fileupload"][:tempfile].size.should.equal 4
613
+ ensure
614
+ $KCODE = original_kcode
615
+ end
616
+ else # >= 1.9
617
+ input = <<EOF
618
+ --AaB03x\r
619
+ content-disposition: form-data; name="fileupload"; filename="junk.a"\r
620
+ content-type: application/octet-stream\r
621
+ \r
622
+ #{[0x36,0xCF,0x0A,0xF8].pack('c*')}\r
623
+ --AaB03x--\r
624
+ EOF
625
+
626
+ req = Rack::Request.new Rack::MockRequest.env_for("/",
627
+ "CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
628
+ "CONTENT_LENGTH" => input.size,
629
+ :input => input)
630
+
631
+ lambda{req.POST}.should.not.raise(EOFError)
632
+ req.POST["fileupload"][:tempfile].size.should.equal 4
633
+ end
634
+ end
635
+
636
+ should "work around buggy 1.8.* Tempfile equality" do
637
+ input = <<EOF
638
+ --AaB03x\r
639
+ content-disposition: form-data; name="huge"; filename="huge"\r
640
+ \r
641
+ foo\r
642
+ --AaB03x--
643
+ EOF
644
+
645
+ rack_input = Tempfile.new("rackspec")
646
+ rack_input.write(input)
647
+ rack_input.rewind
648
+
649
+ req = Rack::Request.new Rack::MockRequest.env_for("/",
650
+ "CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
651
+ "CONTENT_LENGTH" => input.size,
652
+ :input => rack_input)
653
+
654
+ lambda{ req.POST }.should.not.raise
655
+ lambda{ req.POST }.should.not.raise("input re-processed!")
656
+ end
657
+
658
+ should "conform to the Rack spec" do
659
+ app = lambda { |env|
660
+ content = Rack::Request.new(env).POST["file"].inspect
661
+ size = content.respond_to?(:bytesize) ? content.bytesize : content.size
662
+ [200, {"Content-Type" => "text/html", "Content-Length" => size.to_s}, [content]]
663
+ }
664
+
665
+ input = <<EOF
666
+ --AaB03x\r
667
+ content-disposition: form-data; name="reply"\r
668
+ \r
669
+ yes\r
670
+ --AaB03x\r
671
+ content-disposition: form-data; name="fileupload"; filename="dj.jpg"\r
672
+ Content-Type: image/jpeg\r
673
+ Content-Transfer-Encoding: base64\r
674
+ \r
675
+ /9j/4AAQSkZJRgABAQAAAQABAAD//gA+Q1JFQVRPUjogZ2QtanBlZyB2MS4wICh1c2luZyBJSkcg\r
676
+ --AaB03x--\r
677
+ EOF
678
+ input.force_encoding("ASCII-8BIT") if input.respond_to? :force_encoding
679
+ res = Rack::MockRequest.new(Rack::Lint.new(app)).get "/",
680
+ "CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
681
+ "CONTENT_LENGTH" => input.size.to_s, "rack.input" => StringIO.new(input)
682
+
683
+ res.should.be.ok
684
+ end
685
+
686
+ should "parse Accept-Encoding correctly" do
687
+ parser = lambda do |x|
688
+ Rack::Request.new(Rack::MockRequest.env_for("", "HTTP_ACCEPT_ENCODING" => x)).accept_encoding
689
+ end
690
+
691
+ parser.call(nil).should.equal([])
692
+
693
+ parser.call("compress, gzip").should.equal([["compress", 1.0], ["gzip", 1.0]])
694
+ parser.call("").should.equal([])
695
+ parser.call("*").should.equal([["*", 1.0]])
696
+ parser.call("compress;q=0.5, gzip;q=1.0").should.equal([["compress", 0.5], ["gzip", 1.0]])
697
+ parser.call("gzip;q=1.0, identity; q=0.5, *;q=0").should.equal([["gzip", 1.0], ["identity", 0.5], ["*", 0] ])
698
+
699
+ lambda { parser.call("gzip ; q=1.0") }.should.raise(RuntimeError)
700
+ end
701
+
702
+ should 'provide ip information' do
703
+ app = lambda { |env|
704
+ request = Rack::Request.new(env)
705
+ response = Rack::Response.new
706
+ response.write request.ip
707
+ response.finish
708
+ }
709
+
710
+ mock = Rack::MockRequest.new(Rack::Lint.new(app))
711
+ res = mock.get '/', 'REMOTE_ADDR' => '123.123.123.123'
712
+ res.body.should.equal '123.123.123.123'
713
+
714
+ res = mock.get '/',
715
+ 'REMOTE_ADDR' => '123.123.123.123',
716
+ 'HTTP_X_FORWARDED_FOR' => '234.234.234.234'
717
+
718
+ res.body.should.equal '234.234.234.234'
719
+
720
+ res = mock.get '/',
721
+ 'REMOTE_ADDR' => '123.123.123.123',
722
+ 'HTTP_X_FORWARDED_FOR' => '234.234.234.234,212.212.212.212'
723
+
724
+ res.body.should.equal '234.234.234.234'
725
+
726
+ res = mock.get '/',
727
+ 'REMOTE_ADDR' => '123.123.123.123',
728
+ 'HTTP_X_FORWARDED_FOR' => 'unknown,234.234.234.234,212.212.212.212'
729
+
730
+ res.body.should.equal '234.234.234.234'
731
+ end
732
+
733
+ class MyRequest < Rack::Request
734
+ def params
735
+ {:foo => "bar"}
736
+ end
737
+ end
738
+
739
+ should "allow subclass request to be instantiated after parent request" do
740
+ env = Rack::MockRequest.env_for("/?foo=bar")
741
+
742
+ req1 = Rack::Request.new(env)
743
+ req1.GET.should.equal "foo" => "bar"
744
+ req1.params.should.equal "foo" => "bar"
745
+
746
+ req2 = MyRequest.new(env)
747
+ req2.GET.should.equal "foo" => "bar"
748
+ req2.params.should.equal :foo => "bar"
749
+ end
750
+
751
+ should "allow parent request to be instantiated after subclass request" do
752
+ env = Rack::MockRequest.env_for("/?foo=bar")
753
+
754
+ req1 = MyRequest.new(env)
755
+ req1.GET.should.equal "foo" => "bar"
756
+ req1.params.should.equal :foo => "bar"
757
+
758
+ req2 = Rack::Request.new(env)
759
+ req2.GET.should.equal "foo" => "bar"
760
+ req2.params.should.equal "foo" => "bar"
761
+ end
762
+
763
+ (0x20...0x7E).collect { |a|
764
+ b = a.chr
765
+ c = CGI.escape(b)
766
+ should "not strip '#{a}' => '#{c}' => '#{b}' escaped character from parameters when accessed as string" do
767
+ url = "/?foo=#{c}bar#{c}"
768
+ env = Rack::MockRequest.env_for(url)
769
+ req2 = Rack::Request.new(env)
770
+ req2.GET.should.equal "foo" => "#{b}bar#{b}"
771
+ req2.params.should.equal "foo" => "#{b}bar#{b}"
772
+ end
773
+ }
774
+ end