eac-rack 1.1.1

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 (111) hide show
  1. data/COPYING +18 -0
  2. data/KNOWN-ISSUES +21 -0
  3. data/README +399 -0
  4. data/bin/rackup +4 -0
  5. data/contrib/rack_logo.svg +111 -0
  6. data/example/lobster.ru +4 -0
  7. data/example/protectedlobster.rb +14 -0
  8. data/example/protectedlobster.ru +8 -0
  9. data/lib/rack.rb +92 -0
  10. data/lib/rack/adapter/camping.rb +22 -0
  11. data/lib/rack/auth/abstract/handler.rb +37 -0
  12. data/lib/rack/auth/abstract/request.rb +37 -0
  13. data/lib/rack/auth/basic.rb +58 -0
  14. data/lib/rack/auth/digest/md5.rb +124 -0
  15. data/lib/rack/auth/digest/nonce.rb +51 -0
  16. data/lib/rack/auth/digest/params.rb +55 -0
  17. data/lib/rack/auth/digest/request.rb +40 -0
  18. data/lib/rack/builder.rb +80 -0
  19. data/lib/rack/cascade.rb +41 -0
  20. data/lib/rack/chunked.rb +49 -0
  21. data/lib/rack/commonlogger.rb +49 -0
  22. data/lib/rack/conditionalget.rb +47 -0
  23. data/lib/rack/config.rb +15 -0
  24. data/lib/rack/content_length.rb +29 -0
  25. data/lib/rack/content_type.rb +23 -0
  26. data/lib/rack/deflater.rb +96 -0
  27. data/lib/rack/directory.rb +157 -0
  28. data/lib/rack/etag.rb +23 -0
  29. data/lib/rack/file.rb +90 -0
  30. data/lib/rack/handler.rb +88 -0
  31. data/lib/rack/handler/cgi.rb +61 -0
  32. data/lib/rack/handler/evented_mongrel.rb +8 -0
  33. data/lib/rack/handler/fastcgi.rb +89 -0
  34. data/lib/rack/handler/lsws.rb +63 -0
  35. data/lib/rack/handler/mongrel.rb +90 -0
  36. data/lib/rack/handler/scgi.rb +62 -0
  37. data/lib/rack/handler/swiftiplied_mongrel.rb +8 -0
  38. data/lib/rack/handler/thin.rb +18 -0
  39. data/lib/rack/handler/webrick.rb +69 -0
  40. data/lib/rack/head.rb +19 -0
  41. data/lib/rack/lint.rb +575 -0
  42. data/lib/rack/lobster.rb +65 -0
  43. data/lib/rack/lock.rb +16 -0
  44. data/lib/rack/logger.rb +20 -0
  45. data/lib/rack/methodoverride.rb +27 -0
  46. data/lib/rack/mime.rb +206 -0
  47. data/lib/rack/mock.rb +189 -0
  48. data/lib/rack/nulllogger.rb +18 -0
  49. data/lib/rack/recursive.rb +57 -0
  50. data/lib/rack/reloader.rb +109 -0
  51. data/lib/rack/request.rb +271 -0
  52. data/lib/rack/response.rb +149 -0
  53. data/lib/rack/rewindable_input.rb +100 -0
  54. data/lib/rack/runtime.rb +27 -0
  55. data/lib/rack/sendfile.rb +142 -0
  56. data/lib/rack/server.rb +212 -0
  57. data/lib/rack/session/abstract/id.rb +140 -0
  58. data/lib/rack/session/cookie.rb +90 -0
  59. data/lib/rack/session/memcache.rb +119 -0
  60. data/lib/rack/session/pool.rb +100 -0
  61. data/lib/rack/showexceptions.rb +349 -0
  62. data/lib/rack/showstatus.rb +106 -0
  63. data/lib/rack/static.rb +38 -0
  64. data/lib/rack/urlmap.rb +56 -0
  65. data/lib/rack/utils.rb +614 -0
  66. data/rack.gemspec +38 -0
  67. data/test/spec_rack_auth_basic.rb +73 -0
  68. data/test/spec_rack_auth_digest.rb +226 -0
  69. data/test/spec_rack_builder.rb +84 -0
  70. data/test/spec_rack_camping.rb +51 -0
  71. data/test/spec_rack_cascade.rb +48 -0
  72. data/test/spec_rack_cgi.rb +89 -0
  73. data/test/spec_rack_chunked.rb +62 -0
  74. data/test/spec_rack_commonlogger.rb +61 -0
  75. data/test/spec_rack_conditionalget.rb +41 -0
  76. data/test/spec_rack_config.rb +24 -0
  77. data/test/spec_rack_content_length.rb +43 -0
  78. data/test/spec_rack_content_type.rb +30 -0
  79. data/test/spec_rack_deflater.rb +127 -0
  80. data/test/spec_rack_directory.rb +61 -0
  81. data/test/spec_rack_etag.rb +17 -0
  82. data/test/spec_rack_fastcgi.rb +89 -0
  83. data/test/spec_rack_file.rb +75 -0
  84. data/test/spec_rack_handler.rb +43 -0
  85. data/test/spec_rack_head.rb +30 -0
  86. data/test/spec_rack_lint.rb +528 -0
  87. data/test/spec_rack_lobster.rb +45 -0
  88. data/test/spec_rack_lock.rb +38 -0
  89. data/test/spec_rack_logger.rb +21 -0
  90. data/test/spec_rack_methodoverride.rb +60 -0
  91. data/test/spec_rack_mock.rb +243 -0
  92. data/test/spec_rack_mongrel.rb +189 -0
  93. data/test/spec_rack_nulllogger.rb +13 -0
  94. data/test/spec_rack_recursive.rb +77 -0
  95. data/test/spec_rack_request.rb +545 -0
  96. data/test/spec_rack_response.rb +221 -0
  97. data/test/spec_rack_rewindable_input.rb +118 -0
  98. data/test/spec_rack_runtime.rb +35 -0
  99. data/test/spec_rack_sendfile.rb +86 -0
  100. data/test/spec_rack_session_cookie.rb +73 -0
  101. data/test/spec_rack_session_memcache.rb +273 -0
  102. data/test/spec_rack_session_pool.rb +172 -0
  103. data/test/spec_rack_showexceptions.rb +21 -0
  104. data/test/spec_rack_showstatus.rb +72 -0
  105. data/test/spec_rack_static.rb +37 -0
  106. data/test/spec_rack_thin.rb +91 -0
  107. data/test/spec_rack_urlmap.rb +215 -0
  108. data/test/spec_rack_utils.rb +554 -0
  109. data/test/spec_rack_webrick.rb +130 -0
  110. data/test/spec_rackup.rb +154 -0
  111. metadata +311 -0
@@ -0,0 +1,65 @@
1
+ require 'zlib'
2
+
3
+ require 'rack/request'
4
+ require 'rack/response'
5
+
6
+ module Rack
7
+ # Paste has a Pony, Rack has a Lobster!
8
+ class Lobster
9
+ LobsterString = Zlib::Inflate.inflate("eJx9kEEOwyAMBO99xd7MAcytUhPlJyj2
10
+ P6jy9i4k9EQyGAnBarEXeCBqSkntNXsi/ZCvC48zGQoZKikGrFMZvgS5ZHd+aGWVuWwhVF0
11
+ t1drVmiR42HcWNz5w3QanT+2gIvTVCiE1lm1Y0eU4JGmIIbaKwextKn8rvW+p5PIwFl8ZWJ
12
+ I8jyiTlhTcYXkekJAzTyYN6E08A+dk8voBkAVTJQ==".delete("\n ").unpack("m*")[0])
13
+
14
+ LambdaLobster = lambda { |env|
15
+ if env["QUERY_STRING"].include?("flip")
16
+ lobster = LobsterString.split("\n").
17
+ map { |line| line.ljust(42).reverse }.
18
+ join("\n")
19
+ href = "?"
20
+ else
21
+ lobster = LobsterString
22
+ href = "?flip"
23
+ end
24
+
25
+ content = ["<title>Lobstericious!</title>",
26
+ "<pre>", lobster, "</pre>",
27
+ "<a href='#{href}'>flip!</a>"]
28
+ length = content.inject(0) { |a,e| a+e.size }.to_s
29
+ [200, {"Content-Type" => "text/html", "Content-Length" => length}, content]
30
+ }
31
+
32
+ def call(env)
33
+ req = Request.new(env)
34
+ if req.GET["flip"] == "left"
35
+ lobster = LobsterString.split("\n").
36
+ map { |line| line.ljust(42).reverse }.
37
+ join("\n")
38
+ href = "?flip=right"
39
+ elsif req.GET["flip"] == "crash"
40
+ raise "Lobster crashed"
41
+ else
42
+ lobster = LobsterString
43
+ href = "?flip=left"
44
+ end
45
+
46
+ res = Response.new
47
+ res.write "<title>Lobstericious!</title>"
48
+ res.write "<pre>"
49
+ res.write lobster
50
+ res.write "</pre>"
51
+ res.write "<p><a href='#{href}'>flip!</a></p>"
52
+ res.write "<p><a href='?flip=crash'>crash!</a></p>"
53
+ res.finish
54
+ end
55
+
56
+ end
57
+ end
58
+
59
+ if $0 == __FILE__
60
+ require 'rack'
61
+ require 'rack/showexceptions'
62
+ Rack::Handler::WEBrick.run \
63
+ Rack::ShowExceptions.new(Rack::Lint.new(Rack::Lobster.new)),
64
+ :Port => 9292
65
+ end
@@ -0,0 +1,16 @@
1
+ module Rack
2
+ class Lock
3
+ FLAG = 'rack.multithread'.freeze
4
+
5
+ def initialize(app, lock = Mutex.new)
6
+ @app, @lock = app, lock
7
+ end
8
+
9
+ def call(env)
10
+ old, env[FLAG] = env[FLAG], false
11
+ @lock.synchronize { @app.call(env) }
12
+ ensure
13
+ env[FLAG] = old
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,20 @@
1
+ require 'logger'
2
+
3
+ module Rack
4
+ # Sets up rack.logger to write to rack.errors stream
5
+ class Logger
6
+ def initialize(app, level = ::Logger::INFO)
7
+ @app, @level = app, level
8
+ end
9
+
10
+ def call(env)
11
+ logger = ::Logger.new(env['rack.errors'])
12
+ logger.level = @level
13
+
14
+ env['rack.logger'] = logger
15
+ @app.call(env)
16
+ ensure
17
+ logger.close
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,27 @@
1
+ module Rack
2
+ class MethodOverride
3
+ HTTP_METHODS = %w(GET HEAD PUT POST DELETE OPTIONS)
4
+
5
+ METHOD_OVERRIDE_PARAM_KEY = "_method".freeze
6
+ HTTP_METHOD_OVERRIDE_HEADER = "HTTP_X_HTTP_METHOD_OVERRIDE".freeze
7
+
8
+ def initialize(app)
9
+ @app = app
10
+ end
11
+
12
+ def call(env)
13
+ if env["REQUEST_METHOD"] == "POST"
14
+ req = Request.new(env)
15
+ method = req.POST[METHOD_OVERRIDE_PARAM_KEY] ||
16
+ env[HTTP_METHOD_OVERRIDE_HEADER]
17
+ method = method.to_s.upcase
18
+ if HTTP_METHODS.include?(method)
19
+ env["rack.methodoverride.original_method"] = env["REQUEST_METHOD"]
20
+ env["REQUEST_METHOD"] = method
21
+ end
22
+ end
23
+
24
+ @app.call(env)
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,206 @@
1
+ module Rack
2
+ module Mime
3
+ # Returns String with mime type if found, otherwise use +fallback+.
4
+ # +ext+ should be filename extension in the '.ext' format that
5
+ # File.extname(file) returns.
6
+ # +fallback+ may be any object
7
+ #
8
+ # Also see the documentation for MIME_TYPES
9
+ #
10
+ # Usage:
11
+ # Rack::Mime.mime_type('.foo')
12
+ #
13
+ # This is a shortcut for:
14
+ # Rack::Mime::MIME_TYPES.fetch('.foo', 'application/octet-stream')
15
+
16
+ def mime_type(ext, fallback='application/octet-stream')
17
+ MIME_TYPES.fetch(ext.to_s.downcase, fallback)
18
+ end
19
+ module_function :mime_type
20
+
21
+ # List of most common mime-types, selected various sources
22
+ # according to their usefulness in a webserving scope for Ruby
23
+ # users.
24
+ #
25
+ # To amend this list with your local mime.types list you can use:
26
+ #
27
+ # require 'webrick/httputils'
28
+ # list = WEBrick::HTTPUtils.load_mime_types('/etc/mime.types')
29
+ # Rack::Mime::MIME_TYPES.merge!(list)
30
+ #
31
+ # To add the list mongrel provides, use:
32
+ #
33
+ # require 'mongrel/handlers'
34
+ # Rack::Mime::MIME_TYPES.merge!(Mongrel::DirHandler::MIME_TYPES)
35
+
36
+ MIME_TYPES = {
37
+ ".3gp" => "video/3gpp",
38
+ ".a" => "application/octet-stream",
39
+ ".ai" => "application/postscript",
40
+ ".aif" => "audio/x-aiff",
41
+ ".aiff" => "audio/x-aiff",
42
+ ".asc" => "application/pgp-signature",
43
+ ".asf" => "video/x-ms-asf",
44
+ ".asm" => "text/x-asm",
45
+ ".asx" => "video/x-ms-asf",
46
+ ".atom" => "application/atom+xml",
47
+ ".au" => "audio/basic",
48
+ ".avi" => "video/x-msvideo",
49
+ ".bat" => "application/x-msdownload",
50
+ ".bin" => "application/octet-stream",
51
+ ".bmp" => "image/bmp",
52
+ ".bz2" => "application/x-bzip2",
53
+ ".c" => "text/x-c",
54
+ ".cab" => "application/vnd.ms-cab-compressed",
55
+ ".cc" => "text/x-c",
56
+ ".chm" => "application/vnd.ms-htmlhelp",
57
+ ".class" => "application/octet-stream",
58
+ ".com" => "application/x-msdownload",
59
+ ".conf" => "text/plain",
60
+ ".cpp" => "text/x-c",
61
+ ".crt" => "application/x-x509-ca-cert",
62
+ ".css" => "text/css",
63
+ ".csv" => "text/csv",
64
+ ".cxx" => "text/x-c",
65
+ ".deb" => "application/x-debian-package",
66
+ ".der" => "application/x-x509-ca-cert",
67
+ ".diff" => "text/x-diff",
68
+ ".djv" => "image/vnd.djvu",
69
+ ".djvu" => "image/vnd.djvu",
70
+ ".dll" => "application/x-msdownload",
71
+ ".dmg" => "application/octet-stream",
72
+ ".doc" => "application/msword",
73
+ ".dot" => "application/msword",
74
+ ".dtd" => "application/xml-dtd",
75
+ ".dvi" => "application/x-dvi",
76
+ ".ear" => "application/java-archive",
77
+ ".eml" => "message/rfc822",
78
+ ".eps" => "application/postscript",
79
+ ".exe" => "application/x-msdownload",
80
+ ".f" => "text/x-fortran",
81
+ ".f77" => "text/x-fortran",
82
+ ".f90" => "text/x-fortran",
83
+ ".flv" => "video/x-flv",
84
+ ".for" => "text/x-fortran",
85
+ ".gem" => "application/octet-stream",
86
+ ".gemspec" => "text/x-script.ruby",
87
+ ".gif" => "image/gif",
88
+ ".gz" => "application/x-gzip",
89
+ ".h" => "text/x-c",
90
+ ".hh" => "text/x-c",
91
+ ".htm" => "text/html",
92
+ ".html" => "text/html",
93
+ ".ico" => "image/vnd.microsoft.icon",
94
+ ".ics" => "text/calendar",
95
+ ".ifb" => "text/calendar",
96
+ ".iso" => "application/octet-stream",
97
+ ".jar" => "application/java-archive",
98
+ ".java" => "text/x-java-source",
99
+ ".jnlp" => "application/x-java-jnlp-file",
100
+ ".jpeg" => "image/jpeg",
101
+ ".jpg" => "image/jpeg",
102
+ ".js" => "application/javascript",
103
+ ".json" => "application/json",
104
+ ".log" => "text/plain",
105
+ ".m3u" => "audio/x-mpegurl",
106
+ ".m4v" => "video/mp4",
107
+ ".man" => "text/troff",
108
+ ".manifest"=> "text/cache-manifest",
109
+ ".mathml" => "application/mathml+xml",
110
+ ".mbox" => "application/mbox",
111
+ ".mdoc" => "text/troff",
112
+ ".me" => "text/troff",
113
+ ".mid" => "audio/midi",
114
+ ".midi" => "audio/midi",
115
+ ".mime" => "message/rfc822",
116
+ ".mml" => "application/mathml+xml",
117
+ ".mng" => "video/x-mng",
118
+ ".mov" => "video/quicktime",
119
+ ".mp3" => "audio/mpeg",
120
+ ".mp4" => "video/mp4",
121
+ ".mp4v" => "video/mp4",
122
+ ".mpeg" => "video/mpeg",
123
+ ".mpg" => "video/mpeg",
124
+ ".ms" => "text/troff",
125
+ ".msi" => "application/x-msdownload",
126
+ ".odp" => "application/vnd.oasis.opendocument.presentation",
127
+ ".ods" => "application/vnd.oasis.opendocument.spreadsheet",
128
+ ".odt" => "application/vnd.oasis.opendocument.text",
129
+ ".ogg" => "application/ogg",
130
+ ".ogv" => "video/ogg",
131
+ ".p" => "text/x-pascal",
132
+ ".pas" => "text/x-pascal",
133
+ ".pbm" => "image/x-portable-bitmap",
134
+ ".pdf" => "application/pdf",
135
+ ".pem" => "application/x-x509-ca-cert",
136
+ ".pgm" => "image/x-portable-graymap",
137
+ ".pgp" => "application/pgp-encrypted",
138
+ ".pkg" => "application/octet-stream",
139
+ ".pl" => "text/x-script.perl",
140
+ ".pm" => "text/x-script.perl-module",
141
+ ".png" => "image/png",
142
+ ".pnm" => "image/x-portable-anymap",
143
+ ".ppm" => "image/x-portable-pixmap",
144
+ ".pps" => "application/vnd.ms-powerpoint",
145
+ ".ppt" => "application/vnd.ms-powerpoint",
146
+ ".ps" => "application/postscript",
147
+ ".psd" => "image/vnd.adobe.photoshop",
148
+ ".py" => "text/x-script.python",
149
+ ".qt" => "video/quicktime",
150
+ ".ra" => "audio/x-pn-realaudio",
151
+ ".rake" => "text/x-script.ruby",
152
+ ".ram" => "audio/x-pn-realaudio",
153
+ ".rar" => "application/x-rar-compressed",
154
+ ".rb" => "text/x-script.ruby",
155
+ ".rdf" => "application/rdf+xml",
156
+ ".roff" => "text/troff",
157
+ ".rpm" => "application/x-redhat-package-manager",
158
+ ".rss" => "application/rss+xml",
159
+ ".rtf" => "application/rtf",
160
+ ".ru" => "text/x-script.ruby",
161
+ ".s" => "text/x-asm",
162
+ ".sgm" => "text/sgml",
163
+ ".sgml" => "text/sgml",
164
+ ".sh" => "application/x-sh",
165
+ ".sig" => "application/pgp-signature",
166
+ ".snd" => "audio/basic",
167
+ ".so" => "application/octet-stream",
168
+ ".svg" => "image/svg+xml",
169
+ ".svgz" => "image/svg+xml",
170
+ ".swf" => "application/x-shockwave-flash",
171
+ ".t" => "text/troff",
172
+ ".tar" => "application/x-tar",
173
+ ".tbz" => "application/x-bzip-compressed-tar",
174
+ ".tcl" => "application/x-tcl",
175
+ ".tex" => "application/x-tex",
176
+ ".texi" => "application/x-texinfo",
177
+ ".texinfo" => "application/x-texinfo",
178
+ ".text" => "text/plain",
179
+ ".tif" => "image/tiff",
180
+ ".tiff" => "image/tiff",
181
+ ".torrent" => "application/x-bittorrent",
182
+ ".tr" => "text/troff",
183
+ ".txt" => "text/plain",
184
+ ".vcf" => "text/x-vcard",
185
+ ".vcs" => "text/x-vcalendar",
186
+ ".vrml" => "model/vrml",
187
+ ".war" => "application/java-archive",
188
+ ".wav" => "audio/x-wav",
189
+ ".wma" => "audio/x-ms-wma",
190
+ ".wmv" => "video/x-ms-wmv",
191
+ ".wmx" => "video/x-ms-wmx",
192
+ ".wrl" => "model/vrml",
193
+ ".wsdl" => "application/wsdl+xml",
194
+ ".xbm" => "image/x-xbitmap",
195
+ ".xhtml" => "application/xhtml+xml",
196
+ ".xls" => "application/vnd.ms-excel",
197
+ ".xml" => "application/xml",
198
+ ".xpm" => "image/x-xpixmap",
199
+ ".xsl" => "application/xml",
200
+ ".xslt" => "application/xslt+xml",
201
+ ".yaml" => "text/yaml",
202
+ ".yml" => "text/yaml",
203
+ ".zip" => "application/zip",
204
+ }
205
+ end
206
+ end
@@ -0,0 +1,189 @@
1
+ require 'uri'
2
+ require 'stringio'
3
+ require 'rack/lint'
4
+ require 'rack/utils'
5
+ require 'rack/response'
6
+
7
+ module Rack
8
+ # Rack::MockRequest helps testing your Rack application without
9
+ # actually using HTTP.
10
+ #
11
+ # After performing a request on a URL with get/post/put/delete, it
12
+ # returns a MockResponse with useful helper methods for effective
13
+ # testing.
14
+ #
15
+ # You can pass a hash with additional configuration to the
16
+ # get/post/put/delete.
17
+ # <tt>:input</tt>:: A String or IO-like to be used as rack.input.
18
+ # <tt>:fatal</tt>:: Raise a FatalWarning if the app writes to rack.errors.
19
+ # <tt>:lint</tt>:: If true, wrap the application in a Rack::Lint.
20
+
21
+ class MockRequest
22
+ class FatalWarning < RuntimeError
23
+ end
24
+
25
+ class FatalWarner
26
+ def puts(warning)
27
+ raise FatalWarning, warning
28
+ end
29
+
30
+ def write(warning)
31
+ raise FatalWarning, warning
32
+ end
33
+
34
+ def flush
35
+ end
36
+
37
+ def string
38
+ ""
39
+ end
40
+ end
41
+
42
+ DEFAULT_ENV = {
43
+ "rack.version" => [1,1],
44
+ "rack.input" => StringIO.new,
45
+ "rack.errors" => StringIO.new,
46
+ "rack.multithread" => true,
47
+ "rack.multiprocess" => true,
48
+ "rack.run_once" => false,
49
+ }
50
+
51
+ def initialize(app)
52
+ @app = app
53
+ end
54
+
55
+ def get(uri, opts={}) request("GET", uri, opts) end
56
+ def post(uri, opts={}) request("POST", uri, opts) end
57
+ def put(uri, opts={}) request("PUT", uri, opts) end
58
+ def delete(uri, opts={}) request("DELETE", uri, opts) end
59
+
60
+ def request(method="GET", uri="", opts={})
61
+ env = self.class.env_for(uri, opts.merge(:method => method))
62
+
63
+ if opts[:lint]
64
+ app = Rack::Lint.new(@app)
65
+ else
66
+ app = @app
67
+ end
68
+
69
+ errors = env["rack.errors"]
70
+ MockResponse.new(*(app.call(env) + [errors]))
71
+ end
72
+
73
+ # Return the Rack environment used for a request to +uri+.
74
+ def self.env_for(uri="", opts={})
75
+ uri = URI(uri)
76
+ uri.path = "/#{uri.path}" unless uri.path[0] == ?/
77
+
78
+ env = DEFAULT_ENV.dup
79
+
80
+ env["REQUEST_METHOD"] = opts[:method] ? opts[:method].to_s.upcase : "GET"
81
+ env["SERVER_NAME"] = uri.host || "example.org"
82
+ env["SERVER_PORT"] = uri.port ? uri.port.to_s : "80"
83
+ env["QUERY_STRING"] = uri.query.to_s
84
+ env["PATH_INFO"] = (!uri.path || uri.path.empty?) ? "/" : uri.path
85
+ env["rack.url_scheme"] = uri.scheme || "http"
86
+ env["HTTPS"] = env["rack.url_scheme"] == "https" ? "on" : "off"
87
+
88
+ env["SCRIPT_NAME"] = opts[:script_name] || ""
89
+
90
+ if opts[:fatal]
91
+ env["rack.errors"] = FatalWarner.new
92
+ else
93
+ env["rack.errors"] = StringIO.new
94
+ end
95
+
96
+ if params = opts[:params]
97
+ if env["REQUEST_METHOD"] == "GET"
98
+ params = Utils.parse_nested_query(params) if params.is_a?(String)
99
+ params.update(Utils.parse_nested_query(env["QUERY_STRING"]))
100
+ env["QUERY_STRING"] = Utils.build_nested_query(params)
101
+ elsif !opts.has_key?(:input)
102
+ opts["CONTENT_TYPE"] = "application/x-www-form-urlencoded"
103
+ if params.is_a?(Hash)
104
+ if data = Utils::Multipart.build_multipart(params)
105
+ opts[:input] = data
106
+ opts["CONTENT_LENGTH"] ||= data.length.to_s
107
+ opts["CONTENT_TYPE"] = "multipart/form-data; boundary=#{Utils::Multipart::MULTIPART_BOUNDARY}"
108
+ else
109
+ opts[:input] = Utils.build_nested_query(params)
110
+ end
111
+ else
112
+ opts[:input] = params
113
+ end
114
+ end
115
+ end
116
+
117
+ empty_str = ""
118
+ empty_str.force_encoding("ASCII-8BIT") if empty_str.respond_to? :force_encoding
119
+ opts[:input] ||= empty_str
120
+ if String === opts[:input]
121
+ rack_input = StringIO.new(opts[:input])
122
+ else
123
+ rack_input = opts[:input]
124
+ end
125
+
126
+ rack_input.set_encoding(Encoding::BINARY) if rack_input.respond_to?(:set_encoding)
127
+ env['rack.input'] = rack_input
128
+
129
+ env["CONTENT_LENGTH"] ||= env["rack.input"].length.to_s
130
+
131
+ opts.each { |field, value|
132
+ env[field] = value if String === field
133
+ }
134
+
135
+ env
136
+ end
137
+ end
138
+
139
+ # Rack::MockResponse provides useful helpers for testing your apps.
140
+ # Usually, you don't create the MockResponse on your own, but use
141
+ # MockRequest.
142
+
143
+ class MockResponse
144
+ def initialize(status, headers, body, errors=StringIO.new(""))
145
+ @status = status.to_i
146
+
147
+ @original_headers = headers
148
+ @headers = Rack::Utils::HeaderHash.new
149
+ headers.each { |field, values|
150
+ @headers[field] = values
151
+ @headers[field] = "" if values.empty?
152
+ }
153
+
154
+ @body = ""
155
+ body.each { |part| @body << part }
156
+
157
+ @errors = errors.string if errors.respond_to?(:string)
158
+ end
159
+
160
+ # Status
161
+ attr_reader :status
162
+
163
+ # Headers
164
+ attr_reader :headers, :original_headers
165
+
166
+ def [](field)
167
+ headers[field]
168
+ end
169
+
170
+
171
+ # Body
172
+ attr_reader :body
173
+
174
+ def =~(other)
175
+ @body =~ other
176
+ end
177
+
178
+ def match(other)
179
+ @body.match other
180
+ end
181
+
182
+
183
+ # Errors
184
+ attr_accessor :errors
185
+
186
+
187
+ include Response::Helpers
188
+ end
189
+ end