Class: Tilia::Dav::TemporaryFileFilterPlugin

Inherits:
ServerPlugin show all
Defined in:
lib/tilia/dav/temporary_file_filter_plugin.rb

Overview

Temporary File Filter Plugin

The purpose of this filter is to intercept some of the garbage files operation systems and applications tend to generate when mounting a WebDAV share as a disk.

It will intercept these files and place them in a separate directory. these files are not deleted automatically, so it is adviceable to delete these after they are not accessed for 24 hours.

Currently it supports:

* OS/X style resource forks and .DS_Store
* desktop.ini and Thumbs.db (windows)
* .*.swp (vim temporary files)
* .dat.* (smultron temporary files)

Additional patterns can be added, by adding on to the temporaryFilePatterns property.

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods inherited from ServerPlugin

#features, #http_methods, #plugin_info, #plugin_name, #supported_report_set

Constructor Details

#initialize(data_dir = nil) ⇒ TemporaryFileFilterPlugin

Creates the plugin.

Make sure you specify a directory for your files. If you don’t, we will use PHP’s directory for session-storage instead, and you might not want that.

Parameters:

  • string|null

    data_dir



48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/tilia/dav/temporary_file_filter_plugin.rb', line 48

def initialize(data_dir = nil)
  @temporary_file_patterns = [
    /^\._(.*)$/,     # OS/X resource forks
    /^.DS_Store$/,   # OS/X custom folder settings
    /^desktop.ini$/, # Windows custom folder settings
    /^Thumbs.db$/,   # Windows thumbnail cache
    /^.(.*).swp$/,   # ViM temporary files
    /^\.dat(.*)$/,   # Smultron seems to create these
    /^~lock.(.*)\#$/ # Windows 7 lockfiles
  ]

  data_dir = ::File.join(Dir.tmpdir, 'tiliadav', '') unless data_dir
  Dir.mkdir(data_dir) unless ::File.directory?(data_dir)
  @data_dir = data_dir
end

Instance Attribute Details

#temporary_file_patternsObject

This is the list of patterns we intercept. If new patterns are added, they must be valid patterns for preg_match.



28
29
30
# File 'lib/tilia/dav/temporary_file_filter_plugin.rb', line 28

def temporary_file_patterns
  @temporary_file_patterns
end

Instance Method Details

#before_create_file(uri, data, _parent, _modified) ⇒ Object

This method is invoked if some subsystem creates a new file.

This is used to deal with HTTP LOCK requests which create a new file.

Parameters:

  • string

    uri

  • resource

    data

  • DAV\ICollection

    _parent_node

  • bool

    _modified Should be set to true, if this event handler changed &data.

Returns:

  • bool



114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/tilia/dav/temporary_file_filter_plugin.rb', line 114

def before_create_file(uri, data, _parent, _modified)
  temp_path = temp_file?(uri)
  if temp_path
    h_r = @server.http_response
    h_r.update_header('X-Sabre-Temp', 'true')
    ::File.open(temp_path, 'w') do |file|
      file.write(data)
    end
    return false
  end

  nil
end

#before_method(request, response) ⇒ Object

This method is called before any HTTP method handler

This method intercepts any GET, DELETE, PUT and PROPFIND calls to filenames that are known to match the ‘temporary file’ regex.

Parameters:

  • RequestInterface

    request

  • ResponseInterface

    response

Returns:

  • bool



85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/tilia/dav/temporary_file_filter_plugin.rb', line 85

def before_method(request, response)
  temp_location = temp_file?(request.path)
  return true unless temp_location

  case request.method
  when 'GET'
    http_get(request, response, temp_location)
  when 'PUT'
    http_put(request, response, temp_location)
  when 'PROPFIND'
    http_propfind(request, response, temp_location)
  when 'DELETE'
    http_delete(request, response, temp_location)
  else
    true
  end
end

#http_delete(_request, h_r, temp_location) ⇒ Object

This method handles the DELETE method.

If the file didn’t exist, it will return false, which will make the standard HTTP DELETE handler kick in.

Parameters:

  • RequestInterface

    request

  • ResponseInterface

    h_r

  • string

    temp_location

Returns:

  • bool



202
203
204
205
206
207
208
209
# File 'lib/tilia/dav/temporary_file_filter_plugin.rb', line 202

def http_delete(_request, h_r, temp_location)
  return nil unless ::File.exist?(temp_location)

  ::File.unlink(temp_location)
  h_r.update_header('X-Sabre-Temp', 'true')
  h_r.status = 204
  false
end

#http_get(_request, h_r, temp_location) ⇒ Object

This method handles the GET method for temporary files. If the file doesn’t exist, it will return false which will kick in the regular system for the GET method.

Parameters:

  • RequestInterface

    request

  • ResponseInterface

    h_r

  • string

    temp_location

Returns:

  • bool



159
160
161
162
163
164
165
166
167
168
# File 'lib/tilia/dav/temporary_file_filter_plugin.rb', line 159

def http_get(_request, h_r, temp_location)
  return nil unless ::File.exist?(temp_location)

  h_r.update_header('Content-Type', 'application/octet-stream')
  h_r.update_header('Content-Length', ::File.size(temp_location))
  h_r.update_header('X-Sabre-Temp', 'true')
  h_r.status = 200
  h_r.body = ::File.open(temp_location, 'r')
  false
end

#http_propfind(request, h_r, temp_location) ⇒ Object

This method handles the PROPFIND method.

It’s a very lazy method, it won’t bother checking the request body for which properties were requested, and just sends back a default set of properties.

Parameters:

  • RequestInterface

    request

  • ResponseInterface

    h_r

  • string

    temp_location

Returns:

  • bool



221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
# File 'lib/tilia/dav/temporary_file_filter_plugin.rb', line 221

def http_propfind(request, h_r, temp_location)
  return false unless ::File.exist?(temp_location)

  h_r.update_header('X-Sabre-Temp', 'true')
  h_r.status = 207
  h_r.update_header('Content-Type', 'application/xml; charset=utf-8')

  properties = {
    'href' => request.path,
    200    => {
      '{DAV:}getlastmodified'            => Xml::Property::GetLastModified.new(::File.mtime(temp_location)),
      '{DAV:}getcontentlength'           => ::File.size(temp_location),
      '{DAV:}resourcetype'               => Xml::Property::ResourceType.new(nil),
      "{#{Server::NS_SABREDAV}}tempFile" => true
    }
  }

  data = @server.generate_multi_status([properties])
  h_r.body = data
  false
end

#http_put(_request, h_r, temp_location) ⇒ Object

This method handles the PUT method.

Parameters:

  • RequestInterface

    request

  • ResponseInterface

    h_r

  • string

    temp_location

Returns:

  • bool



176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
# File 'lib/tilia/dav/temporary_file_filter_plugin.rb', line 176

def http_put(_request, h_r, temp_location)
  h_r.update_header('X-Sabre-Temp', 'true')

  new_file = !::File.exist?(temp_location)

  if !new_file && @server.http_request.header('If-None-Match')
    fail Exception::PreconditionFailed, 'The resource already exists, and an If-None-Match header was supplied'
  end

  ::File.open(temp_location, 'w') do |file|
    file.write(@server.http_request.body)
  end

  h_r.status = new_file ? 201 : 200
  false
end

#setup(server) ⇒ Object

Initialize the plugin

This is called automatically be the Server class after this plugin is added with SabreDAVServer::add_plugin

Parameters:

  • Server

    server

Returns:

  • void



71
72
73
74
75
# File 'lib/tilia/dav/temporary_file_filter_plugin.rb', line 71

def setup(server)
  @server = server
  @server.on('beforeMethod',     method(:before_method))
  @server.on('beforeCreateFile', method(:before_create_file))
end