class RackWebDAV::FileResource

Public Instance Methods

children() click to toggle source

If this is a collection, return the child resources.

# File lib/rack-webdav/file_resource.rb, line 9
def children
  Dir[file_path + '/*'].map do |path|
    child File.basename(path)
  end
end
collection?() click to toggle source

Is this resource a collection?

# File lib/rack-webdav/file_resource.rb, line 16
def collection?
  File.directory?(file_path)
end
content_length() click to toggle source

Return the size in bytes for this resource.

# File lib/rack-webdav/file_resource.rb, line 64
def content_length
  stat.size
end
content_type() click to toggle source

Return the mime type of this resource.

# File lib/rack-webdav/file_resource.rb, line 55
def content_type
  if stat.directory?
    "text/html"
  else
    mime_type(file_path, DefaultMimeTypes)
  end
end
copy(dest) click to toggle source

HTTP COPY request.

Copy this resource to given destination resource.

# File lib/rack-webdav/file_resource.rb, line 141
def copy(dest)
  if stat.directory?
    dest.make_collection
  else
    open(file_path, "rb") do |file|
      dest.write(file)
    end

    list_custom_properties.each do |prop|
      dest.set_custom_property(prop, get_custom_property(prop))
    end
  end
end
creation_date() click to toggle source

Return the creation time.

# File lib/rack-webdav/file_resource.rb, line 26
def creation_date
  stat.ctime
end
delete() click to toggle source

HTTP DELETE request.

Delete this resource.

# File lib/rack-webdav/file_resource.rb, line 130
def delete
  if stat.directory?
    Dir.rmdir(file_path)
  else
    File.unlink(file_path)
  end
end
etag() click to toggle source

Return an Etag, an unique hash value for this resource.

# File lib/rack-webdav/file_resource.rb, line 41
def etag
  sprintf('%x-%x-%x', stat.ino, stat.size, stat.mtime.to_i)
end
exist?() click to toggle source

Does this recource exist?

# File lib/rack-webdav/file_resource.rb, line 21
def exist?
  File.exist?(file_path)
end
get() click to toggle source

HTTP GET request.

Write the content of the resource to the response.body.

# File lib/rack-webdav/file_resource.rb, line 93
def get
  if stat.directory?
    content = ""
    Rack::Directory.new(root).call(@request.env)[2].each { |line| content << line }
    @response.body = [content]
    @response['Content-Length'] = (content.respond_to?(:bytesize) ? content.bytesize : content.size).to_s
  else
    file = File.open(file_path)
    @response.body = file
  end
end
get_custom_property(name) click to toggle source
# File lib/rack-webdav/file_resource.rb, line 80
def get_custom_property(name)
  value = xattr["rack-webdav:#{name}"]
  raise HTTPStatus::NotFound if value.nil?
  value
end
last_modified() click to toggle source

Return the time of last modification.

# File lib/rack-webdav/file_resource.rb, line 31
def last_modified
  stat.mtime
end
last_modified=(time) click to toggle source

Set the time of last modification.

# File lib/rack-webdav/file_resource.rb, line 36
def last_modified=(time)
  File.utime(Time.now, time, file_path)
end
list_custom_properties() click to toggle source
# File lib/rack-webdav/file_resource.rb, line 86
def list_custom_properties
  xattr.list.select { |a| a.start_with?('rack-webdav') }.map { |a| a.sub(/^rack-webdav:/, '') }
end
lock(token, timeout, scope = nil, type = nil, owner = nil) click to toggle source
# File lib/rack-webdav/file_resource.rb, line 187
def lock(token, timeout, scope = nil, type = nil, owner = nil)
  if scope && type
    # Create lock
    @@locks[token] = {
      :timeout => timeout,
      :scope   => scope,
      :type    => type,
      :owner   => owner,
      :path    => self.path
    }
    return true
  else
    # Refresh lock
    lock = @@locks[token]
    return false unless lock
    return [ lock[:timeout], lock[:scope], lock[:type], lock[:owner] ]
  end
end
locked?(token, etag = nil) click to toggle source
# File lib/rack-webdav/file_resource.rb, line 210
def locked?(token, etag = nil)
  if token.nil?
    # check parent directory match
    already_locks = @@locks.select { |lock_token, lock|
      found = false
      Pathname.new(self.path).ascend { |v|
        found = lock[:path].gsub(/\/$/, '') == v.to_s
        break if found
      }
      lock if found
    }
    return !already_locks.empty?
  else
    lock_paths = @@locks.select { |lock_token, lock| lock[:path] == self.path }
    self.exist? && @@locks.key?(token) == false && !lock_paths.empty?
  end
end
locks() click to toggle source
# File lib/rack-webdav/file_resource.rb, line 239
def locks
  @@locks
end
make_collection() click to toggle source

HTTP MKCOL request.

Create this resource as collection.

# File lib/rack-webdav/file_resource.rb, line 166
def make_collection
  Dir.mkdir(file_path)
end
move(dest) click to toggle source

HTTP MOVE request.

Move this resource to given destination resource.

# File lib/rack-webdav/file_resource.rb, line 158
def move(dest)
  copy(dest)
  delete
end
other_owner_locked?(token, owner) click to toggle source
# File lib/rack-webdav/file_resource.rb, line 228
def other_owner_locked?(token, owner)
  return false if token.nil?
  return false if @@locks.key?(token) && owner.nil?
  other_owner = @@locks.select { |lock_token, lock|
    lock[:path] == self.path
  }.select { |lock_token, lock|
    !lock[:owner].nil? && lock[:owner] != owner
  }
  !other_owner.empty?
end
post() click to toggle source

HTTP POST request.

Usually forbidden.

# File lib/rack-webdav/file_resource.rb, line 123
def post
  raise HTTPStatus::Forbidden
end
put() click to toggle source

HTTP PUT request.

Save the content of the request.body.

# File lib/rack-webdav/file_resource.rb, line 108
def put
  if @request.env['HTTP_CONTENT_MD5']
    content_md5_pass?(@request.env) or raise HTTPStatus::BadRequest.new('Content-MD5 mismatch')
  end

  if content_continue_pass?(@request.env)
    raise HTTPStatus::Continue.new()
  end

  write(@request.body)
end
resource_type() click to toggle source

Return the resource type.

If this is a collection, return a collection element

# File lib/rack-webdav/file_resource.rb, line 48
def resource_type
  if collection?
    Nokogiri::XML::fragment('<D:collection xmlns:D="DAV:"/>').children.first
  end
end
set_custom_property(name, value) click to toggle source
# File lib/rack-webdav/file_resource.rb, line 68
def set_custom_property(name, value)
  if value.nil? || value.empty?
    begin
      xattr.remove("rack-webdav:#{name}")
    rescue Errno::ENOATTR
      # If the attribute being deleted doesn't exist, just do nothing
    end
  else
    xattr["rack-webdav:#{name}"] = value
  end
end
unlock(token) click to toggle source
# File lib/rack-webdav/file_resource.rb, line 206
def unlock(token)
  !!@@locks.delete(token)
end
write(io) click to toggle source

Write to this resource from given IO.

# File lib/rack-webdav/file_resource.rb, line 171
def write(io)
  tempfile = "#{file_path}.#{Process.pid}.#{object_id}"

  open(tempfile, "wb") do |file|
    while part = io.read(8192)
      file << part
    end
  end

  File.rename(tempfile, file_path)
ensure
  File.unlink(tempfile) rescue nil
end

Private Instance Methods

content_continue_pass?(env) click to toggle source
# File lib/rack-webdav/file_resource.rb, line 273
def content_continue_pass?(env)
  expected = env['HTTP_EXPECT'] or return false

  expected.downcase == '100-continue'
end
content_md5_pass?(env) click to toggle source
# File lib/rack-webdav/file_resource.rb, line 261
def content_md5_pass?(env)
  expected = env['HTTP_CONTENT_MD5'] or return true

  body   = env['rack.input'].dup
  digest = Digest::MD5.new.digest(body.read)
  actual = [ digest ].pack('m').strip

  body.rewind

  expected == actual
end
file_path() click to toggle source
# File lib/rack-webdav/file_resource.rb, line 249
def file_path
  root + '/' + path
end
root() click to toggle source
# File lib/rack-webdav/file_resource.rb, line 245
def root
  @options[:root]
end
stat() click to toggle source
# File lib/rack-webdav/file_resource.rb, line 253
def stat
  @stat ||= File.stat(file_path)
end
xattr() click to toggle source
# File lib/rack-webdav/file_resource.rb, line 257
def xattr
  @xattr ||= Xattr.new(file_path)
end