passenger 2.2.1 → 2.2.2
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of passenger might be problematic. Click here for more details.
- data/Rakefile +66 -79
- data/bin/passenger-install-nginx-module +1 -1
- data/bin/passenger-memory-stats +1 -1
- data/bin/passenger-spawn-server +8 -2
- data/doc/Users guide Apache.html +33 -49
- data/doc/Users guide Apache.txt +28 -27
- data/doc/Users guide Nginx.html +9 -19
- data/doc/Users guide Nginx.txt +8 -20
- data/doc/cxxapi/Bucket_8h-source.html +1 -1
- data/doc/cxxapi/Configuration_8h-source.html +297 -300
- data/doc/cxxapi/DirectoryMapper_8h-source.html +1 -1
- data/doc/cxxapi/Hooks_8h-source.html +1 -1
- data/doc/cxxapi/annotated.html +1 -1
- data/doc/cxxapi/classHooks-members.html +1 -1
- data/doc/cxxapi/classHooks.html +1 -1
- data/doc/cxxapi/classPassenger_1_1DirectoryMapper-members.html +1 -1
- data/doc/cxxapi/classPassenger_1_1DirectoryMapper.html +1 -1
- data/doc/cxxapi/classes.html +1 -1
- data/doc/cxxapi/definitions_8h-source.html +1 -1
- data/doc/cxxapi/files.html +1 -1
- data/doc/cxxapi/functions.html +1 -1
- data/doc/cxxapi/functions_func.html +1 -1
- data/doc/cxxapi/graph_legend.html +1 -1
- data/doc/cxxapi/group__Configuration.html +1 -23
- data/doc/cxxapi/group__Core.html +1 -1
- data/doc/cxxapi/group__Hooks.html +1 -1
- data/doc/cxxapi/group__Support.html +1 -1
- data/doc/cxxapi/main.html +1 -1
- data/doc/cxxapi/modules.html +1 -1
- data/doc/users_guide_snippets/rackup_specifications.txt +4 -2
- data/ext/apache2/Configuration.h +0 -3
- data/ext/apache2/Hooks.cpp +5 -3
- data/ext/common/ApplicationPoolServer.h +1 -0
- data/ext/common/ApplicationPoolServerExecutable.cpp +5 -2
- data/ext/common/SpawnManager.h +1 -0
- data/ext/common/Utils.cpp +22 -23
- data/ext/common/Utils.h +32 -21
- data/ext/common/Version.h +31 -0
- data/ext/nginx/ContentHandler.c +61 -8
- data/ext/nginx/HelperServer.cpp +3 -0
- data/ext/nginx/HttpStatusExtractor.h +185 -0
- data/ext/nginx/StaticContentHandler.c +18 -3
- data/ext/nginx/config +2 -1
- data/ext/nginx/ngx_http_passenger_module.c +21 -15
- data/ext/oxt/backtrace.cpp +4 -2
- data/ext/oxt/spin_lock.hpp +3 -3
- data/lib/phusion_passenger/abstract_request_handler.rb +5 -3
- data/lib/phusion_passenger/admin_tools/control_process.rb +6 -1
- data/lib/phusion_passenger/constants.rb +2 -2
- data/lib/phusion_passenger/rack/application_spawner.rb +2 -1
- data/lib/phusion_passenger/rack/request_handler.rb +45 -35
- data/lib/phusion_passenger/templates/nginx/config_snippets.txt.erb +1 -1
- data/lib/phusion_passenger/utils.rb +13 -3
- data/misc/rake/cplusplus.rb +7 -0
- data/test/ApplicationPoolServer_ApplicationPoolTest.cpp +2 -0
- data/test/ApplicationPoolTest.cpp +39 -62
- data/test/CxxTestMain.cpp +6 -6
- data/test/HttpStatusExtractorTest.cpp +17 -0
- data/test/StandardApplicationPoolTest.cpp +2 -0
- data/test/UtilsTest.cpp +17 -28
- data/test/ruby/abstract_request_handler_spec.rb +3 -7
- data/test/ruby/utils_spec.rb +18 -13
- data/test/ruby/wsgi/application_spawner_spec.rb +5 -9
- data/test/stub/railsapp/app/controllers/{bar_controller_1.rb → bar_controller.rb} +0 -0
- data/test/stub/railsapp/app/controllers/bar_controller_1.txt +5 -0
- data/test/stub/railsapp/app/controllers/{bar_controller_2.rb → bar_controller_2.txt} +0 -0
- data/test/support/Support.h +20 -0
- data/test/support/config.rb +13 -0
- data/vendor/README +4 -3
- data/vendor/{rack-0.9.1 → rack-1.0.0-git}/COPYING +1 -1
- data/vendor/{rack-0.9.1 → rack-1.0.0-git}/KNOWN-ISSUES +0 -0
- data/vendor/{rack-0.9.1 → rack-1.0.0-git}/README +54 -7
- data/vendor/rack-1.0.0-git/Rakefile +164 -0
- data/vendor/{rack-0.9.1 → rack-1.0.0-git}/lib/rack.rb +7 -3
- data/vendor/{rack-0.9.1 → rack-1.0.0-git}/lib/rack/adapter/camping.rb +0 -0
- data/vendor/rack-1.0.0-git/lib/rack/auth/abstract/handler.rb +37 -0
- data/vendor/{rack-0.9.1 → rack-1.0.0-git}/lib/rack/auth/abstract/request.rb +0 -0
- data/vendor/{rack-0.9.1 → rack-1.0.0-git}/lib/rack/auth/basic.rb +0 -0
- data/vendor/{rack-0.9.1 → rack-1.0.0-git}/lib/rack/auth/digest/md5.rb +1 -1
- data/vendor/{rack-0.9.1 → rack-1.0.0-git}/lib/rack/auth/digest/nonce.rb +0 -0
- data/vendor/{rack-0.9.1 → rack-1.0.0-git}/lib/rack/auth/digest/params.rb +0 -0
- data/vendor/{rack-0.9.1 → rack-1.0.0-git}/lib/rack/auth/digest/request.rb +2 -2
- data/vendor/rack-1.0.0-git/lib/rack/auth/openid.rb +480 -0
- data/vendor/{rack-0.9.1 → rack-1.0.0-git}/lib/rack/builder.rb +1 -5
- data/vendor/{rack-0.9.1 → rack-1.0.0-git}/lib/rack/cascade.rb +0 -0
- data/vendor/rack-1.0.0-git/lib/rack/chunked.rb +49 -0
- data/vendor/{rack-0.9.1 → rack-1.0.0-git}/lib/rack/commonlogger.rb +0 -0
- data/vendor/{rack-0.9.1 → rack-1.0.0-git}/lib/rack/conditionalget.rb +4 -0
- data/vendor/{rack-0.9.1 → rack-1.0.0-git}/lib/rack/content_length.rb +7 -3
- data/vendor/rack-1.0.0-git/lib/rack/content_type.rb +23 -0
- data/vendor/rack-1.0.0-git/lib/rack/deflater.rb +96 -0
- data/vendor/{rack-0.9.1 → rack-1.0.0-git}/lib/rack/directory.rb +5 -2
- data/vendor/{rack-0.9.1 → rack-1.0.0-git}/lib/rack/file.rb +4 -1
- data/vendor/{rack-0.9.1 → rack-1.0.0-git}/lib/rack/handler.rb +22 -1
- data/vendor/{rack-0.9.1 → rack-1.0.0-git}/lib/rack/handler/cgi.rb +7 -3
- data/vendor/{rack-0.9.1 → rack-1.0.0-git}/lib/rack/handler/evented_mongrel.rb +0 -0
- data/vendor/{rack-0.9.1 → rack-1.0.0-git}/lib/rack/handler/fastcgi.rb +26 -24
- data/vendor/{rack-0.9.1 → rack-1.0.0-git}/lib/rack/handler/lsws.rb +7 -4
- data/vendor/{rack-0.9.1 → rack-1.0.0-git}/lib/rack/handler/mongrel.rb +5 -3
- data/vendor/{rack-0.9.1 → rack-1.0.0-git}/lib/rack/handler/scgi.rb +5 -3
- data/vendor/{rack-0.9.1 → rack-1.0.0-git}/lib/rack/handler/swiftiplied_mongrel.rb +0 -0
- data/vendor/{rack-0.9.1 → rack-1.0.0-git}/lib/rack/handler/thin.rb +3 -0
- data/vendor/{rack-0.9.1 → rack-1.0.0-git}/lib/rack/handler/webrick.rb +11 -5
- data/vendor/{rack-0.9.1 → rack-1.0.0-git}/lib/rack/head.rb +0 -0
- data/vendor/{rack-0.9.1 → rack-1.0.0-git}/lib/rack/lint.rb +138 -66
- data/vendor/{rack-0.9.1 → rack-1.0.0-git}/lib/rack/lobster.rb +0 -0
- data/vendor/rack-1.0.0-git/lib/rack/lock.rb +16 -0
- data/vendor/{rack-0.9.1 → rack-1.0.0-git}/lib/rack/methodoverride.rb +0 -0
- data/vendor/{rack-0.9.1 → rack-1.0.0-git}/lib/rack/mime.rb +4 -4
- data/vendor/{rack-0.9.1 → rack-1.0.0-git}/lib/rack/mock.rb +42 -5
- data/vendor/{rack-0.9.1 → rack-1.0.0-git}/lib/rack/recursive.rb +0 -0
- data/vendor/rack-1.0.0-git/lib/rack/reloader.rb +106 -0
- data/vendor/{rack-0.9.1 → rack-1.0.0-git}/lib/rack/request.rb +46 -10
- data/vendor/{rack-0.9.1 → rack-1.0.0-git}/lib/rack/response.rb +15 -3
- data/vendor/rack-1.0.0-git/lib/rack/rewindable_input.rb +98 -0
- data/vendor/rack-1.0.0-git/lib/rack/session/abstract/id.rb +142 -0
- data/vendor/{rack-0.9.1 → rack-1.0.0-git}/lib/rack/session/cookie.rb +2 -0
- data/vendor/rack-1.0.0-git/lib/rack/session/memcache.rb +109 -0
- data/vendor/rack-1.0.0-git/lib/rack/session/pool.rb +100 -0
- data/vendor/{rack-0.9.1 → rack-1.0.0-git}/lib/rack/showexceptions.rb +2 -1
- data/vendor/{rack-0.9.1 → rack-1.0.0-git}/lib/rack/showstatus.rb +1 -1
- data/vendor/{rack-0.9.1 → rack-1.0.0-git}/lib/rack/static.rb +0 -0
- data/vendor/{rack-0.9.1 → rack-1.0.0-git}/lib/rack/urlmap.rb +12 -5
- data/vendor/{rack-0.9.1 → rack-1.0.0-git}/lib/rack/utils.rb +212 -65
- metadata +71 -170
- data/doc/rdoc/classes/ConditionVariable.html +0 -194
- data/doc/rdoc/classes/Exception.html +0 -120
- data/doc/rdoc/classes/GC.html +0 -113
- data/doc/rdoc/classes/IO.html +0 -169
- data/doc/rdoc/classes/PhusionPassenger.html +0 -238
- data/doc/rdoc/classes/PhusionPassenger/AbstractInstaller.html +0 -153
- data/doc/rdoc/classes/PhusionPassenger/AbstractRequestHandler.html +0 -506
- data/doc/rdoc/classes/PhusionPassenger/AbstractServer.html +0 -692
- data/doc/rdoc/classes/PhusionPassenger/AbstractServer/ServerAlreadyStarted.html +0 -97
- data/doc/rdoc/classes/PhusionPassenger/AbstractServer/ServerError.html +0 -96
- data/doc/rdoc/classes/PhusionPassenger/AbstractServer/ServerNotStarted.html +0 -97
- data/doc/rdoc/classes/PhusionPassenger/AbstractServer/UnknownMessage.html +0 -96
- data/doc/rdoc/classes/PhusionPassenger/AbstractServerCollection.html +0 -598
- data/doc/rdoc/classes/PhusionPassenger/AdminTools.html +0 -140
- data/doc/rdoc/classes/PhusionPassenger/AdminTools/ControlProcess.html +0 -264
- data/doc/rdoc/classes/PhusionPassenger/AdminTools/ControlProcess/Instance.html +0 -138
- data/doc/rdoc/classes/PhusionPassenger/AppInitError.html +0 -154
- data/doc/rdoc/classes/PhusionPassenger/Application.html +0 -283
- data/doc/rdoc/classes/PhusionPassenger/ConsoleTextTemplate.html +0 -172
- data/doc/rdoc/classes/PhusionPassenger/FrameworkInitError.html +0 -145
- data/doc/rdoc/classes/PhusionPassenger/HTMLTemplate.html +0 -175
- data/doc/rdoc/classes/PhusionPassenger/InitializationError.html +0 -141
- data/doc/rdoc/classes/PhusionPassenger/InvalidPath.html +0 -92
- data/doc/rdoc/classes/PhusionPassenger/MessageChannel.html +0 -489
- data/doc/rdoc/classes/PhusionPassenger/NativeSupport.html +0 -350
- data/doc/rdoc/classes/PhusionPassenger/Rack.html +0 -91
- data/doc/rdoc/classes/PhusionPassenger/Rack/ApplicationSpawner.html +0 -185
- data/doc/rdoc/classes/PhusionPassenger/Rack/RequestHandler.html +0 -184
- data/doc/rdoc/classes/PhusionPassenger/Railz.html +0 -95
- data/doc/rdoc/classes/PhusionPassenger/Railz/ApplicationSpawner.html +0 -419
- data/doc/rdoc/classes/PhusionPassenger/Railz/ApplicationSpawner/Error.html +0 -98
- data/doc/rdoc/classes/PhusionPassenger/Railz/CGIFixed.html +0 -200
- data/doc/rdoc/classes/PhusionPassenger/Railz/FrameworkSpawner.html +0 -443
- data/doc/rdoc/classes/PhusionPassenger/Railz/FrameworkSpawner/Error.html +0 -98
- data/doc/rdoc/classes/PhusionPassenger/Railz/RequestHandler.html +0 -154
- data/doc/rdoc/classes/PhusionPassenger/SpawnManager.html +0 -402
- data/doc/rdoc/classes/PhusionPassenger/UnknownError.html +0 -125
- data/doc/rdoc/classes/PhusionPassenger/Utils.html +0 -694
- data/doc/rdoc/classes/PhusionPassenger/VersionNotFound.html +0 -140
- data/doc/rdoc/classes/PhusionPassenger/WSGI.html +0 -89
- data/doc/rdoc/classes/PhusionPassenger/WSGI/ApplicationSpawner.html +0 -188
- data/doc/rdoc/classes/PlatformInfo.html +0 -831
- data/doc/rdoc/classes/RakeExtensions.html +0 -197
- data/doc/rdoc/classes/Signal.html +0 -134
- data/doc/rdoc/created.rid +0 -1
- data/doc/rdoc/files/DEVELOPERS_TXT.html +0 -240
- data/doc/rdoc/files/README.html +0 -157
- data/doc/rdoc/files/ext/phusion_passenger/native_support_c.html +0 -92
- data/doc/rdoc/files/lib/phusion_passenger/abstract_installer_rb.html +0 -129
- data/doc/rdoc/files/lib/phusion_passenger/abstract_request_handler_rb.html +0 -131
- data/doc/rdoc/files/lib/phusion_passenger/abstract_server_collection_rb.html +0 -126
- data/doc/rdoc/files/lib/phusion_passenger/abstract_server_rb.html +0 -130
- data/doc/rdoc/files/lib/phusion_passenger/admin_tools/control_process_rb.html +0 -129
- data/doc/rdoc/files/lib/phusion_passenger/admin_tools_rb.html +0 -122
- data/doc/rdoc/files/lib/phusion_passenger/application_rb.html +0 -127
- data/doc/rdoc/files/lib/phusion_passenger/console_text_template_rb.html +0 -126
- data/doc/rdoc/files/lib/phusion_passenger/constants_rb.html +0 -122
- data/doc/rdoc/files/lib/phusion_passenger/dependencies_rb.html +0 -134
- data/doc/rdoc/files/lib/phusion_passenger/events_rb.html +0 -122
- data/doc/rdoc/files/lib/phusion_passenger/exceptions_rb.html +0 -122
- data/doc/rdoc/files/lib/phusion_passenger/html_template_rb.html +0 -126
- data/doc/rdoc/files/lib/phusion_passenger/message_channel_rb.html +0 -122
- data/doc/rdoc/files/lib/phusion_passenger/packaging_rb.html +0 -122
- data/doc/rdoc/files/lib/phusion_passenger/platform_info_rb.html +0 -127
- data/doc/rdoc/files/lib/phusion_passenger/rack/application_spawner_rb.html +0 -133
- data/doc/rdoc/files/lib/phusion_passenger/rack/request_handler_rb.html +0 -126
- data/doc/rdoc/files/lib/phusion_passenger/railz/application_spawner_rb.html +0 -143
- data/doc/rdoc/files/lib/phusion_passenger/railz/cgi_fixed_rb.html +0 -126
- data/doc/rdoc/files/lib/phusion_passenger/railz/framework_spawner_rb.html +0 -145
- data/doc/rdoc/files/lib/phusion_passenger/railz/request_handler_rb.html +0 -127
- data/doc/rdoc/files/lib/phusion_passenger/simple_benchmarking_rb.html +0 -122
- data/doc/rdoc/files/lib/phusion_passenger/spawn_manager_rb.html +0 -161
- data/doc/rdoc/files/lib/phusion_passenger/utils_rb.html +0 -175
- data/doc/rdoc/files/lib/phusion_passenger/wsgi/application_spawner_rb.html +0 -129
- data/doc/rdoc/files/misc/rake/extensions_rb.html +0 -130
- data/doc/rdoc/fr_class_index.html +0 -90
- data/doc/rdoc/fr_file_index.html +0 -76
- data/doc/rdoc/fr_method_index.html +0 -195
- data/doc/rdoc/index.html +0 -26
- data/doc/rdoc/rdoc-style.css +0 -187
- data/vendor/rack-0.9.1/AUTHORS +0 -8
- data/vendor/rack-0.9.1/ChangeLog +0 -1423
- data/vendor/rack-0.9.1/Rakefile +0 -188
- data/vendor/rack-0.9.1/SPEC +0 -129
- data/vendor/rack-0.9.1/lib/rack/auth/abstract/handler.rb +0 -28
- data/vendor/rack-0.9.1/lib/rack/auth/openid.rb +0 -438
- data/vendor/rack-0.9.1/lib/rack/deflater.rb +0 -87
- data/vendor/rack-0.9.1/lib/rack/reloader.rb +0 -64
- data/vendor/rack-0.9.1/lib/rack/session/abstract/id.rb +0 -153
- data/vendor/rack-0.9.1/lib/rack/session/memcache.rb +0 -97
- data/vendor/rack-0.9.1/lib/rack/session/pool.rb +0 -73
File without changes
|
@@ -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
|
File without changes
|
@@ -8,10 +8,10 @@ module Rack
|
|
8
8
|
# Also see the documentation for MIME_TYPES
|
9
9
|
#
|
10
10
|
# Usage:
|
11
|
-
# Rack::
|
11
|
+
# Rack::Mime.mime_type('.foo')
|
12
12
|
#
|
13
13
|
# This is a shortcut for:
|
14
|
-
# Rack::
|
14
|
+
# Rack::Mime::MIME_TYPES.fetch('.foo', 'application/octet-stream')
|
15
15
|
|
16
16
|
def mime_type(ext, fallback='application/octet-stream')
|
17
17
|
MIME_TYPES.fetch(ext, fallback)
|
@@ -26,12 +26,12 @@ module Rack
|
|
26
26
|
#
|
27
27
|
# require 'webrick/httputils'
|
28
28
|
# list = WEBrick::HTTPUtils.load_mime_types('/etc/mime.types')
|
29
|
-
# Rack::
|
29
|
+
# Rack::Mime::MIME_TYPES.merge!(list)
|
30
30
|
#
|
31
31
|
# To add the list mongrel provides, use:
|
32
32
|
#
|
33
33
|
# require 'mongrel/handlers'
|
34
|
-
# Rack::
|
34
|
+
# Rack::Mime::MIME_TYPES.merge!(Mongrel::DirHandler::MIME_TYPES)
|
35
35
|
|
36
36
|
MIME_TYPES = {
|
37
37
|
".3gp" => "video/3gpp",
|
@@ -40,7 +40,7 @@ module Rack
|
|
40
40
|
end
|
41
41
|
|
42
42
|
DEFAULT_ENV = {
|
43
|
-
"rack.version" => [0
|
43
|
+
"rack.version" => [1,0],
|
44
44
|
"rack.input" => StringIO.new,
|
45
45
|
"rack.errors" => StringIO.new,
|
46
46
|
"rack.multithread" => true,
|
@@ -73,14 +73,17 @@ module Rack
|
|
73
73
|
# Return the Rack environment used for a request to +uri+.
|
74
74
|
def self.env_for(uri="", opts={})
|
75
75
|
uri = URI(uri)
|
76
|
+
uri.path = "/#{uri.path}" unless uri.path[0] == ?/
|
77
|
+
|
76
78
|
env = DEFAULT_ENV.dup
|
77
79
|
|
78
|
-
env["REQUEST_METHOD"] = opts[:method]
|
80
|
+
env["REQUEST_METHOD"] = opts[:method] ? opts[:method].to_s.upcase : "GET"
|
79
81
|
env["SERVER_NAME"] = uri.host || "example.org"
|
80
82
|
env["SERVER_PORT"] = uri.port ? uri.port.to_s : "80"
|
81
83
|
env["QUERY_STRING"] = uri.query.to_s
|
82
84
|
env["PATH_INFO"] = (!uri.path || uri.path.empty?) ? "/" : uri.path
|
83
85
|
env["rack.url_scheme"] = uri.scheme || "http"
|
86
|
+
env["HTTPS"] = env["rack.url_scheme"] == "https" ? "on" : "off"
|
84
87
|
|
85
88
|
env["SCRIPT_NAME"] = opts[:script_name] || ""
|
86
89
|
|
@@ -90,6 +93,40 @@ module Rack
|
|
90
93
|
env["rack.errors"] = StringIO.new
|
91
94
|
end
|
92
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
|
+
multipart = false
|
105
|
+
query = lambda { |value|
|
106
|
+
case value
|
107
|
+
when Array
|
108
|
+
value.each(&query)
|
109
|
+
when Hash
|
110
|
+
value.values.each(&query)
|
111
|
+
when Utils::Multipart::UploadedFile
|
112
|
+
multipart = true
|
113
|
+
end
|
114
|
+
}
|
115
|
+
opts[:params].values.each(&query)
|
116
|
+
|
117
|
+
if multipart
|
118
|
+
opts[:input] = Utils::Multipart.build_multipart(params)
|
119
|
+
opts["CONTENT_LENGTH"] ||= opts[:input].length.to_s
|
120
|
+
opts["CONTENT_TYPE"] = "multipart/form-data; boundary=#{Utils::Multipart::MULTIPART_BOUNDARY}"
|
121
|
+
else
|
122
|
+
opts[:input] = Utils.build_nested_query(params)
|
123
|
+
end
|
124
|
+
else
|
125
|
+
opts[:input] = params
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
93
130
|
opts[:input] ||= ""
|
94
131
|
if String === opts[:input]
|
95
132
|
env["rack.input"] = StringIO.new(opts[:input])
|
@@ -97,6 +134,8 @@ module Rack
|
|
97
134
|
env["rack.input"] = opts[:input]
|
98
135
|
end
|
99
136
|
|
137
|
+
env["CONTENT_LENGTH"] ||= env["rack.input"].length.to_s
|
138
|
+
|
100
139
|
opts.each { |field, value|
|
101
140
|
env[field] = value if String === field
|
102
141
|
}
|
@@ -116,9 +155,7 @@ module Rack
|
|
116
155
|
@original_headers = headers
|
117
156
|
@headers = Rack::Utils::HeaderHash.new
|
118
157
|
headers.each { |field, values|
|
119
|
-
|
120
|
-
@headers[field] = value
|
121
|
-
}
|
158
|
+
@headers[field] = values
|
122
159
|
@headers[field] = "" if values.empty?
|
123
160
|
}
|
124
161
|
|
File without changes
|
@@ -0,0 +1,106 @@
|
|
1
|
+
# Copyright (c) 2009 Michael Fellinger m.fellinger@gmail.com
|
2
|
+
# All files in this distribution are subject to the terms of the Ruby license.
|
3
|
+
|
4
|
+
require 'pathname'
|
5
|
+
|
6
|
+
module Rack
|
7
|
+
|
8
|
+
# High performant source reloader
|
9
|
+
#
|
10
|
+
# This class acts as Rack middleware.
|
11
|
+
#
|
12
|
+
# What makes it especially suited for use in a production environment is that
|
13
|
+
# any file will only be checked once and there will only be made one system
|
14
|
+
# call stat(2).
|
15
|
+
#
|
16
|
+
# Please note that this will not reload files in the background, it does so
|
17
|
+
# only when actively called.
|
18
|
+
#
|
19
|
+
# It is performing a check/reload cycle at the start of every request, but
|
20
|
+
# also respects a cool down time, during which nothing will be done.
|
21
|
+
class Reloader
|
22
|
+
def initialize(app, cooldown = 10, backend = Stat)
|
23
|
+
@app = app
|
24
|
+
@cooldown = cooldown
|
25
|
+
@last = (Time.now - cooldown)
|
26
|
+
@cache = {}
|
27
|
+
@mtimes = {}
|
28
|
+
|
29
|
+
extend backend
|
30
|
+
end
|
31
|
+
|
32
|
+
def call(env)
|
33
|
+
if @cooldown and Time.now > @last + @cooldown
|
34
|
+
if Thread.list.size > 1
|
35
|
+
Thread.exclusive{ reload! }
|
36
|
+
else
|
37
|
+
reload!
|
38
|
+
end
|
39
|
+
|
40
|
+
@last = Time.now
|
41
|
+
end
|
42
|
+
|
43
|
+
@app.call(env)
|
44
|
+
end
|
45
|
+
|
46
|
+
def reload!(stderr = $stderr)
|
47
|
+
rotation do |file, mtime|
|
48
|
+
previous_mtime = @mtimes[file] ||= mtime
|
49
|
+
safe_load(file, mtime, stderr) if mtime > previous_mtime
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# A safe Kernel::load, issuing the hooks depending on the results
|
54
|
+
def safe_load(file, mtime, stderr = $stderr)
|
55
|
+
load(file)
|
56
|
+
stderr.puts "#{self.class}: reloaded `#{file}'"
|
57
|
+
file
|
58
|
+
rescue LoadError, SyntaxError => ex
|
59
|
+
stderr.puts ex
|
60
|
+
ensure
|
61
|
+
@mtimes[file] = mtime
|
62
|
+
end
|
63
|
+
|
64
|
+
module Stat
|
65
|
+
def rotation
|
66
|
+
files = [$0, *$LOADED_FEATURES].uniq
|
67
|
+
paths = ['./', *$LOAD_PATH].uniq
|
68
|
+
|
69
|
+
files.map{|file|
|
70
|
+
next if file =~ /\.(so|bundle)$/ # cannot reload compiled files
|
71
|
+
|
72
|
+
found, stat = figure_path(file, paths)
|
73
|
+
next unless found and stat and mtime = stat.mtime
|
74
|
+
|
75
|
+
@cache[file] = found
|
76
|
+
|
77
|
+
yield(found, mtime)
|
78
|
+
}.compact
|
79
|
+
end
|
80
|
+
|
81
|
+
# Takes a relative or absolute +file+ name, a couple possible +paths+ that
|
82
|
+
# the +file+ might reside in. Returns the full path and File::Stat for the
|
83
|
+
# path.
|
84
|
+
def figure_path(file, paths)
|
85
|
+
found = @cache[file]
|
86
|
+
found = file if !found and Pathname.new(file).absolute?
|
87
|
+
found, stat = safe_stat(found)
|
88
|
+
return found, stat if found
|
89
|
+
|
90
|
+
paths.each do |possible_path|
|
91
|
+
path = ::File.join(possible_path, file)
|
92
|
+
found, stat = safe_stat(path)
|
93
|
+
return ::File.expand_path(found), stat if found
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def safe_stat(file)
|
98
|
+
return unless file
|
99
|
+
stat = ::File.stat(file)
|
100
|
+
return file, stat if stat.file?
|
101
|
+
rescue Errno::ENOENT, Errno::ENOTDIR
|
102
|
+
@cache.delete(file) and false
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
@@ -8,11 +8,23 @@ module Rack
|
|
8
8
|
# req = Rack::Request.new(env)
|
9
9
|
# req.post?
|
10
10
|
# req.params["data"]
|
11
|
+
#
|
12
|
+
# The environment hash passed will store a reference to the Request object
|
13
|
+
# instantiated so that it will only instantiate if an instance of the Request
|
14
|
+
# object doesn't already exist.
|
11
15
|
|
12
16
|
class Request
|
13
17
|
# The environment of the request.
|
14
18
|
attr_reader :env
|
15
19
|
|
20
|
+
def self.new(env, *args)
|
21
|
+
if self == Rack::Request
|
22
|
+
env["rack.request"] ||= super
|
23
|
+
else
|
24
|
+
super
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
16
28
|
def initialize(env)
|
17
29
|
@env = env
|
18
30
|
end
|
@@ -26,6 +38,8 @@ module Rack
|
|
26
38
|
def query_string; @env["QUERY_STRING"].to_s end
|
27
39
|
def content_length; @env['CONTENT_LENGTH'] end
|
28
40
|
def content_type; @env['CONTENT_TYPE'] end
|
41
|
+
def session; @env['rack.session'] ||= {} end
|
42
|
+
def session_options; @env['rack.session.options'] ||= {} end
|
29
43
|
|
30
44
|
# The media type (type/subtype) portion of the CONTENT_TYPE header
|
31
45
|
# without any media type parameters. e.g., when CONTENT_TYPE is
|
@@ -34,7 +48,7 @@ module Rack
|
|
34
48
|
# For more information on the use of media types in HTTP, see:
|
35
49
|
# http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.7
|
36
50
|
def media_type
|
37
|
-
content_type && content_type.split(/\s*[;,]\s*/, 2)
|
51
|
+
content_type && content_type.split(/\s*[;,]\s*/, 2).first.downcase
|
38
52
|
end
|
39
53
|
|
40
54
|
# The media type parameters provided in CONTENT_TYPE as a Hash, or
|
@@ -80,6 +94,14 @@ module Rack
|
|
80
94
|
'multipart/form-data'
|
81
95
|
]
|
82
96
|
|
97
|
+
# The set of media-types. Requests that do not indicate
|
98
|
+
# one of the media types presents in this list will not be eligible
|
99
|
+
# for param parsing like soap attachments or generic multiparts
|
100
|
+
PARSEABLE_DATA_MEDIA_TYPES = [
|
101
|
+
'multipart/related',
|
102
|
+
'multipart/mixed'
|
103
|
+
]
|
104
|
+
|
83
105
|
# Determine whether the request body contains form-data by checking
|
84
106
|
# the request media_type against registered form-data media-types:
|
85
107
|
# "application/x-www-form-urlencoded" and "multipart/form-data". The
|
@@ -89,6 +111,12 @@ module Rack
|
|
89
111
|
FORM_DATA_MEDIA_TYPES.include?(media_type)
|
90
112
|
end
|
91
113
|
|
114
|
+
# Determine whether the request body contains data by checking
|
115
|
+
# the request media_type against registered parse-data media-types
|
116
|
+
def parseable_data?
|
117
|
+
PARSEABLE_DATA_MEDIA_TYPES.include?(media_type)
|
118
|
+
end
|
119
|
+
|
92
120
|
# Returns the data recieved in the query string.
|
93
121
|
def GET
|
94
122
|
if @env["rack.request.query_string"] == query_string
|
@@ -96,7 +124,7 @@ module Rack
|
|
96
124
|
else
|
97
125
|
@env["rack.request.query_string"] = query_string
|
98
126
|
@env["rack.request.query_hash"] =
|
99
|
-
Utils.
|
127
|
+
Utils.parse_nested_query(query_string)
|
100
128
|
end
|
101
129
|
end
|
102
130
|
|
@@ -107,13 +135,19 @@ module Rack
|
|
107
135
|
def POST
|
108
136
|
if @env["rack.request.form_input"].eql? @env["rack.input"]
|
109
137
|
@env["rack.request.form_hash"]
|
110
|
-
elsif form_data?
|
138
|
+
elsif form_data? || parseable_data?
|
111
139
|
@env["rack.request.form_input"] = @env["rack.input"]
|
112
140
|
unless @env["rack.request.form_hash"] =
|
113
141
|
Utils::Multipart.parse_multipart(env)
|
114
|
-
|
115
|
-
|
116
|
-
|
142
|
+
form_vars = @env["rack.input"].read
|
143
|
+
|
144
|
+
# Fix for Safari Ajax postings that always append \0
|
145
|
+
form_vars.sub!(/\0\z/, '')
|
146
|
+
|
147
|
+
@env["rack.request.form_vars"] = form_vars
|
148
|
+
@env["rack.request.form_hash"] = Utils.parse_nested_query(form_vars)
|
149
|
+
|
150
|
+
@env["rack.input"].rewind
|
117
151
|
end
|
118
152
|
@env["rack.request.form_hash"]
|
119
153
|
else
|
@@ -188,11 +222,13 @@ module Rack
|
|
188
222
|
|
189
223
|
url
|
190
224
|
end
|
191
|
-
|
225
|
+
|
226
|
+
def path
|
227
|
+
script_name + path_info
|
228
|
+
end
|
229
|
+
|
192
230
|
def fullpath
|
193
|
-
|
194
|
-
path << "?" << query_string unless query_string.empty?
|
195
|
-
path
|
231
|
+
query_string.empty? ? path : "#{path}?#{query_string}"
|
196
232
|
end
|
197
233
|
|
198
234
|
def accept_encoding
|
@@ -16,6 +16,8 @@ module Rack
|
|
16
16
|
# Your application's +call+ should end returning Response#finish.
|
17
17
|
|
18
18
|
class Response
|
19
|
+
attr_accessor :length
|
20
|
+
|
19
21
|
def initialize(body=[], status=200, header={}, &block)
|
20
22
|
@status = status
|
21
23
|
@header = Utils::HeaderHash.new({"Content-Type" => "text/html"}.
|
@@ -61,12 +63,13 @@ module Rack
|
|
61
63
|
expires = "; expires=" + value[:expires].clone.gmtime.
|
62
64
|
strftime("%a, %d-%b-%Y %H:%M:%S GMT") if value[:expires]
|
63
65
|
secure = "; secure" if value[:secure]
|
66
|
+
httponly = "; HttpOnly" if value[:httponly]
|
64
67
|
value = value[:value]
|
65
68
|
end
|
66
69
|
value = [value] unless Array === value
|
67
70
|
cookie = Utils.escape(key) + "=" +
|
68
71
|
value.map { |v| Utils.escape v }.join("&") +
|
69
|
-
"#{domain}#{path}#{expires}#{secure}"
|
72
|
+
"#{domain}#{path}#{expires}#{secure}#{httponly}"
|
70
73
|
|
71
74
|
case self["Set-Cookie"]
|
72
75
|
when Array
|
@@ -92,6 +95,10 @@ module Rack
|
|
92
95
|
:expires => Time.at(0) }.merge(value))
|
93
96
|
end
|
94
97
|
|
98
|
+
def redirect(target, status=302)
|
99
|
+
self.status = status
|
100
|
+
self["Location"] = target
|
101
|
+
end
|
95
102
|
|
96
103
|
def finish(&block)
|
97
104
|
@block = block
|
@@ -100,7 +107,6 @@ module Rack
|
|
100
107
|
header.delete "Content-Type"
|
101
108
|
[status.to_i, header.to_hash, []]
|
102
109
|
else
|
103
|
-
header["Content-Length"] ||= @length.to_s
|
104
110
|
[status.to_i, header.to_hash, self]
|
105
111
|
end
|
106
112
|
end
|
@@ -112,10 +118,16 @@ module Rack
|
|
112
118
|
@block.call(self) if @block
|
113
119
|
end
|
114
120
|
|
121
|
+
# Append to body and update Content-Length.
|
122
|
+
#
|
123
|
+
# NOTE: Do not mix #write and direct #body access!
|
124
|
+
#
|
115
125
|
def write(str)
|
116
126
|
s = str.to_s
|
117
|
-
@length += s
|
127
|
+
@length += Rack::Utils.bytesize(s)
|
118
128
|
@writer.call s
|
129
|
+
|
130
|
+
header["Content-Length"] = @length.to_s
|
119
131
|
str
|
120
132
|
end
|
121
133
|
|
@@ -0,0 +1,98 @@
|
|
1
|
+
require 'tempfile'
|
2
|
+
|
3
|
+
module Rack
|
4
|
+
# Class which can make any IO object rewindable, including non-rewindable ones. It does
|
5
|
+
# this by buffering the data into a tempfile, which is rewindable.
|
6
|
+
#
|
7
|
+
# rack.input is required to be rewindable, so if your input stream IO is non-rewindable
|
8
|
+
# by nature (e.g. a pipe or a socket) then you can wrap it in an object of this class
|
9
|
+
# to easily make it rewindable.
|
10
|
+
#
|
11
|
+
# Don't forget to call #close when you're done. This frees up temporary resources that
|
12
|
+
# RewindableInput uses, though it does *not* close the original IO object.
|
13
|
+
class RewindableInput
|
14
|
+
def initialize(io)
|
15
|
+
@io = io
|
16
|
+
@rewindable_io = nil
|
17
|
+
@unlinked = false
|
18
|
+
end
|
19
|
+
|
20
|
+
def gets
|
21
|
+
make_rewindable unless @rewindable_io
|
22
|
+
@rewindable_io.gets
|
23
|
+
end
|
24
|
+
|
25
|
+
def read(*args)
|
26
|
+
make_rewindable unless @rewindable_io
|
27
|
+
@rewindable_io.read(*args)
|
28
|
+
end
|
29
|
+
|
30
|
+
def each(&block)
|
31
|
+
make_rewindable unless @rewindable_io
|
32
|
+
@rewindable_io.each(&block)
|
33
|
+
end
|
34
|
+
|
35
|
+
def rewind
|
36
|
+
make_rewindable unless @rewindable_io
|
37
|
+
@rewindable_io.rewind
|
38
|
+
end
|
39
|
+
|
40
|
+
# Closes this RewindableInput object without closing the originally
|
41
|
+
# wrapped IO oject. Cleans up any temporary resources that this RewindableInput
|
42
|
+
# has created.
|
43
|
+
#
|
44
|
+
# This method may be called multiple times. It does nothing on subsequent calls.
|
45
|
+
def close
|
46
|
+
if @rewindable_io
|
47
|
+
if @unlinked
|
48
|
+
@rewindable_io.close
|
49
|
+
else
|
50
|
+
@rewindable_io.close!
|
51
|
+
end
|
52
|
+
@rewindable_io = nil
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
# Ruby's Tempfile class has a bug. Subclass it and fix it.
|
59
|
+
class Tempfile < ::Tempfile
|
60
|
+
def _close
|
61
|
+
@tmpfile.close if @tmpfile
|
62
|
+
@data[1] = nil if @data
|
63
|
+
@tmpfile = nil
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def make_rewindable
|
68
|
+
# Buffer all data into a tempfile. Since this tempfile is private to this
|
69
|
+
# RewindableInput object, we chmod it so that nobody else can read or write
|
70
|
+
# it. On POSIX filesystems we also unlink the file so that it doesn't
|
71
|
+
# even have a file entry on the filesystem anymore, though we can still
|
72
|
+
# access it because we have the file handle open.
|
73
|
+
@rewindable_io = Tempfile.new('RackRewindableInput')
|
74
|
+
@rewindable_io.chmod(0000)
|
75
|
+
if filesystem_has_posix_semantics?
|
76
|
+
@rewindable_io.unlink
|
77
|
+
@unlinked = true
|
78
|
+
end
|
79
|
+
|
80
|
+
buffer = ""
|
81
|
+
while @io.read(1024 * 4, buffer)
|
82
|
+
entire_buffer_written_out = false
|
83
|
+
while !entire_buffer_written_out
|
84
|
+
written = @rewindable_io.write(buffer)
|
85
|
+
entire_buffer_written_out = written == buffer.size
|
86
|
+
if !entire_buffer_written_out
|
87
|
+
buffer.slice!(0 .. written - 1)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
@rewindable_io.rewind
|
92
|
+
end
|
93
|
+
|
94
|
+
def filesystem_has_posix_semantics?
|
95
|
+
RUBY_PLATFORM !~ /(mswin|mingw|cygwin|java)/
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|