Class: Tilia::Dav::PartialUpdate::Plugin
- Inherits:
-
ServerPlugin
- Object
- ServerPlugin
- Tilia::Dav::PartialUpdate::Plugin
- Defined in:
- lib/tilia/dav/partial_update/plugin.rb
Overview
Partial update plugin (Patch method)
This plugin provides a way to modify only part of a target resource It may bu used to update a file chunk, upload big a file into smaller chunks or resume an upload.
patch_plugin = new SabreDAVPartialUpdatePlugin server.add_plugin(patch_plugin)
Constant Summary collapse
- RANGE_APPEND =
1
- RANGE_START =
2
- RANGE_END =
3
Instance Method Summary collapse
-
#features ⇒ Object
Returns a list of features for the HTTP OPTIONS Dav: header.
-
#http_methods(uri) ⇒ Object
Use this method to tell the server this plugin defines additional HTTP methods.
-
#http_patch(request, response) ⇒ Object
Patch an uri.
-
#http_update_range(request) ⇒ Object
Returns the HTTP custom range update header.
-
#plugin_name ⇒ Object
Returns a plugin name.
-
#setup(server) ⇒ Object
Initializes the plugin.
Methods inherited from ServerPlugin
#plugin_info, #supported_report_set
Instance Method Details
#features ⇒ Object
Returns a list of features for the HTTP OPTIONS Dav: header.
68 69 70 |
# File 'lib/tilia/dav/partial_update/plugin.rb', line 68 def features ['sabredav-partialupdate'] end |
#http_methods(uri) ⇒ Object
Use this method to tell the server this plugin defines additional HTTP methods.
This method is passed a uri. It should only return HTTP methods that are available for the specified uri.
We claim to support PATCH method (partirl update) if and only if
- the node exist
- the node implements our partial update interface
55 56 57 58 59 60 61 62 63 |
# File 'lib/tilia/dav/partial_update/plugin.rb', line 55 def http_methods(uri) tree = @server.tree if tree.node_exists(uri) node = tree.node_for_path(uri) return ['PATCH'] if node.is_a?(IPatchSupport) end [] end |
#http_patch(request, response) ⇒ Object
Patch an uri
The WebDAV patch request can be used to modify only a part of an existing resource. If the resource does not exist yet and the first offset is not 0, the request fails
81 82 83 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 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 |
# File 'lib/tilia/dav/partial_update/plugin.rb', line 81 def http_patch(request, response) path = request.path # Get the node. Will throw a 404 if not found node = @server.tree.node_for_path(path) unless node.is_a?(IPatchSupport) fail Exception::MethodNotAllowed, 'The target resource does not support the PATCH method.' end range = http_update_range(request) unless range fail Exception::BadRequest, 'No valid "X-Update-Range" found in the headers' end content_type = request.header('Content-Type').to_s.downcase unless content_type == 'application/x-sabredav-partialupdate' fail Exception::UnsupportedMediaType, "Unknown Content-Type header \"#{content_type}\"" end len = @server.http_request.header('Content-Length').to_i if len == 0 fail Exception::LengthRequired, 'A Content-Length header is required' end case range[0] when RANGE_START # Calculate the end-range if it doesn't exist. if range[2].blank? range[2] = range[1] + len - 1 else if range[2] < range[1] fail Exception::RequestedRangeNotSatisfiable, "The end offset (#{range[2]}) is lower than the start offset (#{range[1]})" end if range[2] - range[1] + 1 != len fail Exception::RequestedRangeNotSatisfiable, "Actual data length (#{len}) is not consistent with begin (#{range[1]}) and end (#{range[2]}) offsets" end end end unless @server.emit('beforeWriteContent', [path, node, nil, nil]) return nil end body = @server.http_request.body etag = node.patch(body, range[0], range[1]) @server.emit('afterWriteContent', [path, node]) response.update_header('Content-Length', '0') response.update_header('ETag', etag) if etag response.status = 204 # Breaks the event chain false end |
#http_update_range(request) ⇒ Object
Returns the HTTP custom range update header
This method returns null if there is no well-formed HTTP range request header. It returns array(1) if it was an append request, array(2, start, end) if it’s a start and end range, lastly it’s array(3, endoffset) if the offset was negative, and should be calculated from the end of the file.
Examples:
null - invalid
- 1
-
append
-
- 2,10,15
-
update bytes 10, 11, 12, 13, 14, 15
-
- 2,10,null
-
update bytes 10 until the end of the patch body
-
- 3,-5
-
update from 5 bytes from the end of the file.
-
159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 |
# File 'lib/tilia/dav/partial_update/plugin.rb', line 159 def http_update_range(request) range = request.header('X-Update-Range') return nil unless range # Matching "Range: bytes=1234-5678: both numbers are optional matches = /^(append)|(?:bytes=([0-9]+)-([0-9]*))|(?:bytes=(-[0-9]+))$/i.match(range) return nil unless matches if matches[1] == 'append' return [RANGE_APPEND] elsif matches[2].to_s.size > 0 return [RANGE_START, matches[2].to_i, matches[3].blank? ? nil : matches[3].to_i] else return [RANGE_END, matches[4].to_i] end end |
#plugin_name ⇒ Object
Returns a plugin name.
Using this name other plugins will be able to access other plugins using DAVServer::getPlugin
39 40 41 |
# File 'lib/tilia/dav/partial_update/plugin.rb', line 39 def plugin_name 'partialupdate' end |
#setup(server) ⇒ Object
Initializes the plugin
This method is automatically called by the Server class after addPlugin.
28 29 30 31 |
# File 'lib/tilia/dav/partial_update/plugin.rb', line 28 def setup(server) @server = server server.on('method:PATCH', method(:http_patch)) end |