class Apache::UploadMerger

Constants

CREATE_MODE
DEFAULT_MERGE_THRESHOLD
VERSION

Public Class Methods

new(map = {}, strategy = DEFAULT_MERGE_THRESHOLD) click to toggle source

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
55 def initialize(map = {}, strategy = DEFAULT_MERGE_THRESHOLD)
56   @map, @strategy = {}, strategy
57 
58   define_merger
59 
60   map.each { |prefix, dir|
61     @map[prefix] = [%r{\A#{prefix}/(.*)}, dir]
62   }
63 end

Public Instance Methods

handler(request) click to toggle source

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
69 def handler(request)
70   request.add_common_vars  # REDIRECT_URL
71 
72   if url    = request.subprocess_env['REDIRECT_URL'] and
73      prefix = request.path_info.untaint              and
74      map    = @map[prefix]                           and
75      path   = url[map[0], 1].untaint                 and
76      src    = find(map[1], path)
77 
78     merge(src, File.join(request.server.document_root, prefix, path))
79 
80     request.status = HTTP_OK
81     request.internal_redirect(url)
82 
83     OK
84   else
85     DECLINED
86   end
87 end

Private Instance Methods

copy(src, dest, stat = File.stat(src)) click to toggle source

TODO: optimize?

    # File lib/apache/upload_merger.rb
118 def copy(src, dest, stat = File.stat(src))
119   File.open(src) { |src_|
120     File.open(dest, CREATE_MODE, stat.mode) { |dest_|
121       FileUtils.copy_stream(src_, dest_)
122     }
123   }
124 rescue Errno::EEXIST
125 end
define_merger() click to toggle source
    # File lib/apache/upload_merger.rb
 99 def define_merger
100   class << self; self; end.send :alias_method, :merge, case @strategy
101     when :symlink, :copy then @strategy
102     when Integer         then :copy_or_symlink
103     else raise ArgumentError, "illegal strategy #{@strategy.inspect}"
104   end
105 end
find(dir, path) click to toggle source

TODO: make it fast and secure

   # File lib/apache/upload_merger.rb
92 def find(dir, path)
93   Dir["#{dir}/*/"].find { |subdir|
94     file = File.join(subdir, path).untaint
95     return file if File.exists?(file)
96   }
97 end