Class: RackWebDAV::Controller

Inherits:
Object
  • Object
show all
Includes:
HTTPStatus
Defined in:
lib/rack-webdav/controller.rb

Constant Summary

Constants included from HTTPStatus

HTTPStatus::StatusMessage

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(request, response, options) ⇒ Controller

Returns a new instance of Controller.

Raises:

  • (Forbidden)


12
13
14
15
16
17
18
# File 'lib/rack-webdav/controller.rb', line 12

def initialize(request, response, options)
  @request  = request
  @response = response
  @options  = options
  @resource = resource_class.new(url_unescape(request.path_info), @request, @response, @options)
  raise Forbidden if request.path_info.include?('../')
end

Instance Attribute Details

#requestObject (readonly)

Returns the value of attribute request.



10
11
12
# File 'lib/rack-webdav/controller.rb', line 10

def request
  @request
end

#resourceObject (readonly)

Returns the value of attribute resource.



10
11
12
# File 'lib/rack-webdav/controller.rb', line 10

def resource
  @resource
end

#responseObject (readonly)

Returns the value of attribute response.



10
11
12
# File 'lib/rack-webdav/controller.rb', line 10

def response
  @response
end

Instance Method Details

#copyObject



106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/rack-webdav/controller.rb', line 106

def copy
  raise NotFound if not resource.exist?
  # Source Lock Check
  locktoken = request_locktoken('LOCK_TOKEN')
  locktoken ||= request_locktoken('IF')
  raise Locked if resource.locked?(locktoken) && !overwrite

  dest_uri = URI.parse(env['HTTP_DESTINATION'])
  destination = parse_destination(dest_uri)

  raise BadGateway if dest_uri.host and dest_uri.host != request.host
  raise Forbidden if destination == resource.path

  dest = resource_class.new(destination, @request, @response, @options)
  raise PreconditionFailed if dest.exist? && !overwrite
  # Destination Lock Check
  locktoken = request_locktoken('LOCK_TOKEN')
  locktoken ||= request_locktoken('IF')
  raise Locked if dest.locked?(locktoken)

  dest = dest.child(resource.name) if dest.collection?

  dest_existed = dest.exist?

  copy_recursive(resource, dest, depth, errors = [])

  if errors.empty?
    response.status = dest_existed ? NoContent : Created
  else
    multistatus do |xml|
      response_errors(xml, errors)
    end
  end
rescue URI::InvalidURIError => e
  raise BadRequest.new(e.message)
end

#deleteObject

Raises:

  • (NotFound)


80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/rack-webdav/controller.rb', line 80

def delete
  raise NotFound if not resource.exist?
  raise Locked if resource.locked?(request_locktoken('LOCK_TOKEN'))

  delete_recursive(resource, errors = [])

  if errors.empty?
    response.status = NoContent
  else
    multistatus do |xml|
      response_errors(xml, errors)
    end
  end
end

#getObject

Raises:

  • (NotFound)


48
49
50
51
52
53
54
55
56
57
# File 'lib/rack-webdav/controller.rb', line 48

def get
  raise NotFound if not resource.exist?
  response['Etag'] = resource.etag
  response['Content-Type'] = resource.content_type
  response['Content-Length'] = resource.content_length.to_s
  response['Last-Modified'] = resource.last_modified.httpdate
  map_exceptions do
    resource.get
  end
end

#headObject

Raises:

  • (NotFound)


40
41
42
43
44
45
46
# File 'lib/rack-webdav/controller.rb', line 40

def head
  raise NotFound if not resource.exist?
  response['Etag'] = resource.etag
  response['Content-Type'] = resource.content_type
  response['Content-Length'] = resource.content_length.to_s
  response['Last-Modified'] = resource.last_modified.httpdate
end

#lockObject

Raises:

  • (MethodNotAllowed)


242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
# File 'lib/rack-webdav/controller.rb', line 242

def lock
  raise MethodNotAllowed unless resource.lockable?
  raise NotFound if not resource.exist?

  timeout = request_timeout
  if timeout.nil? || timeout.zero?
    timeout = 60
  end

  if request_document.content.empty?
    refresh_lock timeout
  else
    create_lock timeout
  end
end

#mkcolObject



95
96
97
98
99
100
101
102
103
104
# File 'lib/rack-webdav/controller.rb', line 95

def mkcol
  # Reject message bodies - RFC2518:8.3.1
  body = @request.body.read(8)
  fail UnsupportedMediaType if !body.nil? && body.length > 0

  map_exceptions do
    resource.make_collection
  end
  response.status = Created
end

#moveObject



143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
# File 'lib/rack-webdav/controller.rb', line 143

def move
  raise NotFound if not resource.exist?
  raise Locked if resource.locked?(request_locktoken('LOCK_TOKEN'))

  dest_uri = URI.parse(env['HTTP_DESTINATION'])
  destination = parse_destination(dest_uri)

  raise BadGateway if dest_uri.host and dest_uri.host != request.host
  raise Forbidden if destination == resource.path

  dest = resource_class.new(destination, @request, @response, @options)
  raise PreconditionFailed if dest.exist? && !overwrite

  dest_existed = dest.exist?
  dest = dest.child(resource.name) if dest.collection?

  raise Conflict if depth <= 1

  copy_recursive(resource, dest, depth, errors = [])
  delete_recursive(resource, errors)

  if errors.empty?
    response.status = dest_existed ? NoContent : Created
  else
    multistatus do |xml|
      response_errors(xml, errors)
    end
  end
rescue URI::InvalidURIError => e
  raise BadRequest.new(e.message)
end

#optionsObject



28
29
30
31
32
33
34
35
36
37
38
# File 'lib/rack-webdav/controller.rb', line 28

def options
  response["Allow"] = 'OPTIONS,HEAD,GET,PUT,POST,DELETE,PROPFIND,PROPPATCH,MKCOL,COPY,MOVE'
  response["Dav"] = "1"

  if resource.lockable?
    response["Allow"] << ",LOCK,UNLOCK"
    response["Dav"]   << ",2"
  end

  response["Ms-Author-Via"] = "DAV"
end

#postObject



74
75
76
77
78
# File 'lib/rack-webdav/controller.rb', line 74

def post
  map_exceptions do
    resource.post
  end
end

#propfindObject

Raises:

  • (NotFound)


175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
# File 'lib/rack-webdav/controller.rb', line 175

def propfind
  raise NotFound if not resource.exist?

  if not request_match("/d:propfind/d:allprop").empty?
    nodes = all_prop_nodes
  else
    nodes = request_match("/d:propfind/d:prop/*")
    nodes = all_prop_nodes if nodes.empty?
  end

  nodes.each do |n|
    # Don't allow empty namespace declarations
    # See litmus props test 3
    raise BadRequest if n.namespace.nil? && n.namespace_definitions.empty?

    # Set a blank namespace if one is included in the request
    # See litmus props test 16
    # <propfind xmlns="DAV:"><prop><nonamespace xmlns=""/></prop></propfind>
    if n.namespace.nil?
      nd = n.namespace_definitions.first
      if nd.prefix.nil? && nd.href.empty?
        n.add_namespace(nil, '')
      end
    end
  end

  multistatus do |xml|
    for resource in find_resources
      resource.path.gsub!(/\/\//, '/')
      xml.response do
        xml.href "http://#{host}#{@request.script_name}#{url_escape resource.path}"
        propstats xml, get_properties(resource, nodes)
      end
    end
  end
end

#proppatchObject

Raises:

  • (NotFound)


212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
# File 'lib/rack-webdav/controller.rb', line 212

def proppatch
  raise NotFound if not resource.exist?
  locktoken = request_locktoken('LOCK_TOKEN')
  locktoken ||= request_locktoken('IF')
  raise Locked if resource.locked?(locktoken)

  nodes = request_match("/d:propertyupdate[d:remove/d:prop/* or d:set/d:prop/*]//d:prop/*")

  # Set a blank namespace if one is included in the request
  # See litmus props test 15
  # <propertyupdate xmlns="DAV:"><set>
  #   <prop><nonamespace xmlns="">randomvalue</nonamespace></prop>
  # </set></propertyupdate>
  nodes.each do |n|
    nd = n.namespace_definitions.first
    if !nd.nil? && nd.prefix.nil? && nd.href.empty?
      n.add_namespace(nil, '')
    end
  end

  multistatus do |xml|
    for resource in find_resources
      xml.response do
        xml.href "http://#{host}#{@request.script_name}#{resource.path}"
        propstats xml, set_properties(resource, nodes)
      end
    end
  end
end

#putObject

Raises:

  • (Forbidden)


59
60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/rack-webdav/controller.rb', line 59

def put
  raise Forbidden if resource.collection?
  locktoken = request_locktoken('LOCK_TOKEN')
  locktoken ||= request_locktoken('IF')
  locketag = request_locketag('IF')
  raise PreconditionFailed if locketag && locketag != resource.etag
  raise Locked if resource.locked?(locktoken, locketag)

  map_exceptions do
    resource.put
  end
  response.status = Created
  response['Location'] = "#{request.scheme}://#{request.host}:#{request.port}#{url_format_for_response(resource)}"
end

#unlockObject

Raises:

  • (MethodNotAllowed)


258
259
260
261
262
263
264
265
# File 'lib/rack-webdav/controller.rb', line 258

def unlock
  raise MethodNotAllowed unless resource.lockable?

  locktoken = request_locktoken('LOCK_TOKEN')
  raise BadRequest if locktoken.nil?

  response.status = resource.unlock(locktoken) ? NoContent : Forbidden
end

#url_escape(s) ⇒ Object



20
21
22
# File 'lib/rack-webdav/controller.rb', line 20

def url_escape(s)
  URI.escape(s)
end

#url_unescape(s) ⇒ Object



24
25
26
# File 'lib/rack-webdav/controller.rb', line 24

def url_unescape(s)
  URI.unescape(s).force_valid_encoding
end