Class: RackDAV::Controller

Inherits:
Object
  • Object
show all
Includes:
HTTPStatus
Defined in:
lib/rack_dav/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_dav/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_dav/controller.rb', line 10

def request
  @request
end

#resourceObject (readonly)

Returns the value of attribute resource.



10
11
12
# File 'lib/rack_dav/controller.rb', line 10

def resource
  @resource
end

#responseObject (readonly)

Returns the value of attribute response.



10
11
12
# File 'lib/rack_dav/controller.rb', line 10

def response
  @response
end

Instance Method Details

#copyObject



98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/rack_dav/controller.rb', line 98

def copy
  raise NotFound if not resource.exist?

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

  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 = 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)


73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/rack_dav/controller.rb', line 73

def delete
  raise NotFound if not resource.exist?

  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_dav/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_dav/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)


222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
# File 'lib/rack_dav/controller.rb', line 222

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



87
88
89
90
91
92
93
94
95
96
# File 'lib/rack_dav/controller.rb', line 87

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



127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
# File 'lib/rack_dav/controller.rb', line 127

def move
  raise NotFound if not resource.exist?

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

  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_dav/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



67
68
69
70
71
# File 'lib/rack_dav/controller.rb', line 67

def post
  map_exceptions do
    resource.post
  end
end

#propfindObject

Raises:

  • (NotFound)


158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
# File 'lib/rack_dav/controller.rb', line 158

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}#{url_escape resource.path}"
        propstats xml, get_properties(resource, nodes)
      end
    end
  end
end

#proppatchObject

Raises:

  • (NotFound)


195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
# File 'lib/rack_dav/controller.rb', line 195

def proppatch
  raise NotFound if not resource.exist?

  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}#{resource.path}"
        propstats xml, set_properties(resource, nodes)
      end
    end
  end
end

#putObject

Raises:

  • (Forbidden)


59
60
61
62
63
64
65
# File 'lib/rack_dav/controller.rb', line 59

def put
  raise Forbidden if resource.collection?
  map_exceptions do
    resource.put
  end
  response.status = Created
end

#unlockObject

Raises:

  • (MethodNotAllowed)


238
239
240
241
242
243
244
245
# File 'lib/rack_dav/controller.rb', line 238

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_dav/controller.rb', line 20

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

#url_unescape(s) ⇒ Object



24
25
26
# File 'lib/rack_dav/controller.rb', line 24

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