Creates a new RubyHandler instance for the Apache web server. It is to be installed as a custom 404 ErrorDocument handler.
The argument map
contains key/value pairs of URL prefixes and
upload base directories.
strategy
determines how merging happens:
:symlink
Files are symlinked
:copy
Files are copied
Integer
Files whose size is below that threshold are copied, others are symlinked (default)
# File lib/apache/upload_merger.rb, line 55 def initialize(map = {}, strategy = DEFAULT_MERGE_THRESHOLD) @map, @strategy = {}, strategy define_merger map.each { |prefix, dir| @map[prefix] = [%r{\A#{prefix}/(.*)}, dir] } end
If the current request
asked for a resource that's not
there, it will be merged from one of the appropriate upload directories,
determined by its URL prefix. If no matching resource could be found, the
original error will be thrown.
# File lib/apache/upload_merger.rb, line 69 def handler(request) request.add_common_vars # REDIRECT_URL if url = request.subprocess_env['REDIRECT_URL'] and prefix = request.path_info.untaint and map = @map[prefix] and path = url[map[0], 1].untaint and src = find(map[1], path) merge(src, File.join(request.server.document_root, prefix, path)) request.status = HTTP_OK request.internal_redirect(url) OK else DECLINED end end
TODO: optimize?
# File lib/apache/upload_merger.rb, line 118 def copy(src, dest, stat = File.stat(src)) File.open(src) { |src_| File.open(dest, CREATE_MODE, stat.mode) { |dest_| FileUtils.copy_stream(src_, dest_) } } rescue Errno::EEXIST end
# File lib/apache/upload_merger.rb, line 107 def copy_or_symlink(src, dest) stat = File.stat(src) stat.size > @strategy ? symlink(src, dest) : copy(src, dest, stat) end
# File lib/apache/upload_merger.rb, line 99 def define_merger class << self; self; end.send :alias_method, :merge, case @strategy when :symlink, :copy then @strategy when Integer then :copy_or_symlink else raise ArgumentError, "illegal strategy #{@strategy.inspect}" end end
TODO: make it fast and secure
# File lib/apache/upload_merger.rb, line 92 def find(dir, path) Dir["#{dir}/*/"].find { |subdir| file = File.join(subdir, path).untaint return file if File.exists?(file) } end
# File lib/apache/upload_merger.rb, line 112 def symlink(src, dest) File.symlink(src, dest) rescue Errno::EEXIST end