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)


8
9
10
11
12
13
14
# File 'lib/rack_dav/controller.rb', line 8

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

Instance Attribute Details

#requestObject (readonly)

Returns the value of attribute request.



6
7
8
# File 'lib/rack_dav/controller.rb', line 6

def request
  @request
end

#resourceObject (readonly)

Returns the value of attribute resource.



6
7
8
# File 'lib/rack_dav/controller.rb', line 6

def resource
  @resource
end

#responseObject (readonly)

Returns the value of attribute response.



6
7
8
# File 'lib/rack_dav/controller.rb', line 6

def response
  @response
end

Instance Method Details

#copyObject



84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/rack_dav/controller.rb', line 84

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, @options)
  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



65
66
67
68
69
70
71
72
73
74
75
# File 'lib/rack_dav/controller.rb', line 65

def delete
  delete_recursive(resource, errors = [])
  
  if errors.empty?
    response.status = NoContent
  else
    multistatus do |xml|
      response_errors(xml, errors)
    end
  end
end

#getObject

Raises:

  • (NotFound)


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

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(request, response)
  end
end

#headObject

Raises:

  • (NotFound)


34
35
36
37
38
39
# File 'lib/rack_dav/controller.rb', line 34

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

#lockObject

Raises:

  • (NotFound)


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

def lock
  raise NotFound if not resource.exist?

  lockscope = request_match("/lockinfo/lockscope/*")[0].name
  locktype = request_match("/lockinfo/locktype/*")[0].name
  owner = request_match("/lockinfo/owner/href")[0]
  locktoken = "opaquelocktoken:" + sprintf('%x-%x-%s', Time.now.to_i, Time.now.sec, resource.etag)

  response['Lock-Token'] = locktoken

  render_xml do |xml|
    xml.prop('xmlns:D' => "DAV:") do
      xml.lockdiscovery do
        xml.activelock do
          xml.lockscope { xml.tag! lockscope }
          xml.locktype { xml.tag! locktype }
          xml.depth 'Infinity'
          if owner
            xml.owner { xml.href owner.text }
          end
          xml.timeout "Second-60"
          xml.locktoken do
            xml.href locktoken
          end
        end
      end
    end
  end
end

#mkcolObject



77
78
79
80
81
82
# File 'lib/rack_dav/controller.rb', line 77

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

#moveObject



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

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, @options)
  dest = dest.child(resource.name) if dest.collection?
  
  dest_existed = dest.exist?
  
  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
# File 'lib/rack_dav/controller.rb', line 28

def options
  response["Allow"] = 'OPTIONS,HEAD,GET,PUT,POST,DELETE,PROPFIND,PROPPATCH,MKCOL,COPY,MOVE,LOCK,UNLOCK'
  response["Dav"] = "2"
  response["Ms-Author-Via"] = "DAV"
end

#postObject



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

def post
  map_exceptions do
    resource.post(request, response)
  end
end

#propfindObject

Raises:

  • (NotFound)


141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# File 'lib/rack_dav/controller.rb', line 141

def propfind
  raise NotFound if not resource.exist?

  if not request_match("/propfind/allprop").empty?
    names = resource.property_names
  else
    names = request_match("/propfind/prop/*").map { |e| e.name }
    raise BadRequest if names.empty?
  end

  multistatus do |xml|
    for resource in find_resources
      xml.response do
        xml.href "http://#{host}#{url_escape resource.path}"
        propstats xml, get_properties(resource, names)
      end
    end
  end
end

#proppatchObject

Raises:

  • (NotFound)


161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
# File 'lib/rack_dav/controller.rb', line 161

def proppatch
  raise NotFound if not resource.exist?

  prop_rem = request_match("/propertyupdate/remove/prop/*").map { |e| [e.name] }
  prop_set = request_match("/propertyupdate/set/prop/*").map { |e| [e.name, e.text] }

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

  resource.save
end

#putObject

Raises:

  • (Forbidden)


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

def put
  raise Forbidden if resource.collection?
  map_exceptions do
    resource.put(request, response)
  end
end

#unlockObject

Raises:

  • (NoContent)


209
210
211
# File 'lib/rack_dav/controller.rb', line 209

def unlock
  raise NoContent
end

#url_escape(s) ⇒ Object



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

def url_escape(s)
  s.gsub(/([^\/a-zA-Z0-9_.-]+)/n) do
    '%' + $1.unpack('H2' * $1.size).join('%').upcase
  end.tr(' ', '+')
end

#url_unescape(s) ⇒ Object



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

def url_unescape(s)
  s.tr('+', ' ').gsub(/((?:%[0-9a-fA-F]{2})+)/n) do
    [$1.delete('%')].pack('H*')
  end
end