Class: RackDAV::Controller

Inherits:
Object
  • Object
show all
Includes:
HTTPStatus
Defined in:
lib/rack_dav/controller.rb

Constant Summary collapse

@@uri =
URI::RFC2396_Parser.new

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)


14
15
16
17
18
19
20
# File 'lib/rack_dav/controller.rb', line 14

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



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
126
127
# File 'lib/rack_dav/controller.rb', line 100

def copy
  raise NotFound if not resource.exist?

  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 = 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.to_i : Created.to_i
  else
    multistatus do |xml|
      response_errors(xml, errors)
    end
  end
rescue URI::InvalidURIError => e
  raise BadRequest.new(e.message)
end

#deleteObject

Raises:

  • (NotFound)


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

def delete
  raise NotFound if not resource.exist?

  delete_recursive(resource, errors = [])

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

#getObject

Raises:

  • (NotFound)


50
51
52
53
54
55
56
57
58
59
# File 'lib/rack_dav/controller.rb', line 50

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)


42
43
44
45
46
47
48
# File 'lib/rack_dav/controller.rb', line 42

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)


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

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



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

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.to_i
end

#moveObject



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
157
158
# File 'lib/rack_dav/controller.rb', line 129

def move
  raise NotFound if not resource.exist?

  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.to_i : Created.to_i
  else
    multistatus do |xml|
      response_errors(xml, errors)
    end
  end
rescue URI::InvalidURIError => e
  raise BadRequest.new(e.message)
end

#optionsObject



30
31
32
33
34
35
36
37
38
39
40
# File 'lib/rack_dav/controller.rb', line 30

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



69
70
71
72
73
# File 'lib/rack_dav/controller.rb', line 69

def post
  map_exceptions do
    resource.post
  end
end

#propfindObject

Raises:

  • (NotFound)


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
194
195
# File 'lib/rack_dav/controller.rb', line 160

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)


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

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

#putObject

Raises:

  • (Forbidden)


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

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

#unlockObject

Raises:

  • (MethodNotAllowed)


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

def unlock
  raise MethodNotAllowed unless resource.lockable?

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

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

#url_escape(s) ⇒ Object



22
23
24
# File 'lib/rack_dav/controller.rb', line 22

def url_escape(s)
  @@uri.escape(s)
end

#url_unescape(s) ⇒ Object



26
27
28
# File 'lib/rack_dav/controller.rb', line 26

def url_unescape(s)
  @@uri.unescape(s).force_valid_encoding
end