Add comments
This commit is contained in:
@@ -23,35 +23,54 @@ require 'calligraphy/put'
|
|||||||
require 'calligraphy/unlock'
|
require 'calligraphy/unlock'
|
||||||
|
|
||||||
module Calligraphy
|
module Calligraphy
|
||||||
|
# Constants used throughout Calligraphy.
|
||||||
DAV_NS = 'DAV:'
|
DAV_NS = 'DAV:'
|
||||||
DAV_NO_LOCK_REGEX = /DAV:no-lock/i
|
DAV_NO_LOCK_REGEX = /DAV:no-lock/i
|
||||||
DAV_NOT_NO_LOCK_REGEX = /Not\s+<DAV:no-lock>/i
|
DAV_NOT_NO_LOCK_REGEX = /Not\s+<DAV:no-lock>/i
|
||||||
ETAG_IF_REGEX = /\[(.+?)\]/
|
ETAG_IF_REGEX = /\[(.+?)\]/
|
||||||
|
INFINITY = 1.0 / 0.0 unless defined? INFINITY
|
||||||
LOCK_TOKEN_ANGLE_REGEX = /[<>]/
|
LOCK_TOKEN_ANGLE_REGEX = /[<>]/
|
||||||
LOCK_TOKEN_REGEX = /<(urn:uuid:.+?)>/
|
LOCK_TOKEN_REGEX = /<(urn:uuid:.+?)>/
|
||||||
RESOURCE_REGEX = /^<+(.+?)>\s/
|
RESOURCE_REGEX = /^<+(.+?)>\s/
|
||||||
TAGGED_LIST_REGEX = /\)\s</
|
TAGGED_LIST_REGEX = /\)\s</
|
||||||
UNTAGGAGED_LIST_REGEX = /\)\s\(/
|
UNTAGGAGED_LIST_REGEX = /\)\s\(/
|
||||||
|
|
||||||
mattr_accessor :allowed_methods
|
# HTTP methods allowed by the WebDavRequestsController.
|
||||||
@@allowed_methods = %w(
|
mattr_accessor :allowed_http_methods
|
||||||
options head get put delete copy move mkcol propfind proppatch lock unlock
|
@@allowed_http_methods = %w(
|
||||||
|
options head get put delete copy
|
||||||
|
move mkcol propfind proppatch lock unlock
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Proc responsible for returning the user's password, API key,
|
||||||
|
# or HA1 digest hash so that Rails can check user credentials.
|
||||||
|
# Should be overridden to handle your particular application's
|
||||||
|
# user and/or authentication setup.
|
||||||
mattr_accessor :digest_password_procedure
|
mattr_accessor :digest_password_procedure
|
||||||
@@digest_password_procedure = Proc.new { |x| 'changeme!' }
|
@@digest_password_procedure = Proc.new { |username| 'changeme!' }
|
||||||
|
|
||||||
|
# If Digest Authentication is enabled by default.
|
||||||
mattr_accessor :enable_digest_authentication
|
mattr_accessor :enable_digest_authentication
|
||||||
@@enable_digest_authentication = false
|
@@enable_digest_authentication = false
|
||||||
|
|
||||||
|
# The realm used in HTTP Basic Authentication.
|
||||||
|
mattr_accessor :http_authentication_realm
|
||||||
|
@@http_authentication_realm = 'Application'
|
||||||
|
|
||||||
|
# Maximum lock lifetime in seconds.
|
||||||
mattr_accessor :lock_timeout_period
|
mattr_accessor :lock_timeout_period
|
||||||
@@lock_timeout_period = 24 * 60 * 60
|
@@lock_timeout_period = 24 * 60 * 60
|
||||||
|
|
||||||
|
# The HTTP actions Calligraphy is responsible for handling.
|
||||||
mattr_accessor :web_dav_actions
|
mattr_accessor :web_dav_actions
|
||||||
@@web_dav_actions = %i(
|
@@web_dav_actions = %i(
|
||||||
options get put delete copy move mkcol propfind proppatch lock unlock
|
options get put delete copy move
|
||||||
|
mkcol propfind proppatch lock unlock
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Default way to set up Calligraphy.
|
||||||
|
# Run `rails generate calligraphy_install` to generate a
|
||||||
|
# fresh initializer with all configuration values.
|
||||||
def self.configure
|
def self.configure
|
||||||
yield self
|
yield self
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,61 +1,85 @@
|
|||||||
module ActionDispatch::Routing
|
module ActionDispatch::Routing
|
||||||
class Mapper
|
class Mapper
|
||||||
module HttpHelpers
|
module HttpHelpers
|
||||||
|
# Define a Calligraphy route that only recognizes HTTP COPY.
|
||||||
|
# copy 'bacon', to: 'food#bacon'
|
||||||
def copy(*args, &block)
|
def copy(*args, &block)
|
||||||
args = set_web_dav_args args
|
args = set_web_dav_args args
|
||||||
map_method :copy, args, &block
|
map_method :copy, args, &block
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Define a Calligraphy route that only recognizes HTTP HEAD.
|
||||||
|
# head 'bacon', to: 'food#bacon'
|
||||||
def head(*args, &block)
|
def head(*args, &block)
|
||||||
args = set_web_dav_args args
|
args = set_web_dav_args args
|
||||||
map_method :head, args, &block
|
map_method :head, args, &block
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Define a Calligraphy route that only recognizes HTTP LOCK.
|
||||||
|
# lock 'bacon', to: 'food#bacon'
|
||||||
def lock(*args, &block)
|
def lock(*args, &block)
|
||||||
args = set_web_dav_args args
|
args = set_web_dav_args args
|
||||||
map_method :lock, args, &block
|
map_method :lock, args, &block
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Define a Calligraphy route that only recognizes HTTP MKCOL.
|
||||||
|
# mkcol 'bacon', to: 'food#bacon'
|
||||||
def mkcol(*args, &block)
|
def mkcol(*args, &block)
|
||||||
args = set_web_dav_args args
|
args = set_web_dav_args args
|
||||||
map_method :mkcol, args, &block
|
map_method :mkcol, args, &block
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Define a Calligraphy route that only recognizes HTTP MOVE.
|
||||||
|
# move 'bacon', to: 'food#bacon'
|
||||||
def move(*args, &block)
|
def move(*args, &block)
|
||||||
args = set_web_dav_args args
|
args = set_web_dav_args args
|
||||||
map_method :move, args, &block
|
map_method :move, args, &block
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Define a Calligraphy route that only recognizes HTTP OPTIONS.
|
||||||
|
# options 'bacon', to: 'food#bacon'
|
||||||
def options(*args, &block)
|
def options(*args, &block)
|
||||||
args = set_web_dav_args args
|
args = set_web_dav_args args
|
||||||
map_method :options, args, &block
|
map_method :options, args, &block
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Define a Calligraphy route that only recognizes HTTP PROPFIND.
|
||||||
|
# propfind 'bacon', to: 'food#bacon'
|
||||||
def propfind(*args, &block)
|
def propfind(*args, &block)
|
||||||
args = set_web_dav_args args
|
args = set_web_dav_args args
|
||||||
map_method :propfind, args, &block
|
map_method :propfind, args, &block
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Define a Calligraphy route that only recognizes HTTP PROPPATCH.
|
||||||
|
# proppatch 'bacon', to: 'food#bacon'
|
||||||
def proppatch(*args, &block)
|
def proppatch(*args, &block)
|
||||||
args = set_web_dav_args args
|
args = set_web_dav_args args
|
||||||
map_method :proppatch, args, &block
|
map_method :proppatch, args, &block
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Define a Calligraphy route that only recognizes HTTP UNLOCK.
|
||||||
|
# unlock 'bacon', to: 'food#bacon'
|
||||||
def unlock(*args, &block)
|
def unlock(*args, &block)
|
||||||
args = set_web_dav_args args
|
args = set_web_dav_args args
|
||||||
map_method :unlock, args, &block
|
map_method :unlock, args, &block
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Define a Calligraphy route that only recognizes HTTP DELETE.
|
||||||
|
# web_dav_delete 'broccoli', to: 'food#broccoli'
|
||||||
def web_dav_delete(*args, &block)
|
def web_dav_delete(*args, &block)
|
||||||
args = set_web_dav_args args
|
args = set_web_dav_args args
|
||||||
map_method :delete, args, &block
|
map_method :delete, args, &block
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Define a Calligraphy route that only recognizes HTTP GET.
|
||||||
|
# web_dav_get 'bacon', to: 'food#bacon'
|
||||||
def web_dav_get(*args, &block)
|
def web_dav_get(*args, &block)
|
||||||
args = set_web_dav_args args
|
args = set_web_dav_args args
|
||||||
map_method :get, args, &block
|
map_method :get, args, &block
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Define a Calligraphy route that only recognizes HTTP PUT.
|
||||||
|
# web_dav_put 'bacon', to: 'food#bacon'
|
||||||
def web_dav_put(*args, &block)
|
def web_dav_put(*args, &block)
|
||||||
args = set_web_dav_args args
|
args = set_web_dav_args args
|
||||||
map_method :put, args, &block
|
map_method :put, args, &block
|
||||||
@@ -64,9 +88,10 @@ module ActionDispatch::Routing
|
|||||||
private
|
private
|
||||||
|
|
||||||
def set_web_dav_args(args)
|
def set_web_dav_args(args)
|
||||||
options = {}
|
options = {
|
||||||
options[:controller] = 'calligraphy/rails/web_dav_requests'
|
controller: 'calligraphy/rails/web_dav_requests',
|
||||||
options[:action] = 'invoke_method'
|
action: 'invoke_method'
|
||||||
|
}
|
||||||
[args[0], options]
|
[args[0], options]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -84,6 +109,26 @@ module ActionDispatch::Routing
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# With Calligraphy, a resourceful route provides mappings between WebDAV
|
||||||
|
# HTTP verbs and URLs and WebDAV controller actions. A single entry in
|
||||||
|
# the routing file, such as:
|
||||||
|
#
|
||||||
|
# calligraphy_resource :photos
|
||||||
|
#
|
||||||
|
# creates eleven different routes in your application, all mapping to the
|
||||||
|
# WebDavRequests controller:
|
||||||
|
#
|
||||||
|
# OPTIONS /photos/*resource
|
||||||
|
# GET /photos/*resource
|
||||||
|
# PUT /photos/*resource
|
||||||
|
# DELETE /photos/*resource
|
||||||
|
# COPY /photos/*resource
|
||||||
|
# MOVE /photos/*resource
|
||||||
|
# MKCOL /photos/*resource
|
||||||
|
# PROPFIND /photos/*resource
|
||||||
|
# PROPPATCH /photos/*resource
|
||||||
|
# LOCK /photos/*resource
|
||||||
|
# UNLOCK /photos/*resource
|
||||||
def calligraphy_resource(*resources, &block)
|
def calligraphy_resource(*resources, &block)
|
||||||
options = resources.extract_options!.dup
|
options = resources.extract_options!.dup
|
||||||
|
|
||||||
@@ -94,6 +139,7 @@ module ActionDispatch::Routing
|
|||||||
with_scope_level(:resource) do
|
with_scope_level(:resource) do
|
||||||
options = apply_action_options options
|
options = apply_action_options options
|
||||||
singleton_resoure = ActionDispatch::Routing::Mapper::SingletonResource
|
singleton_resoure = ActionDispatch::Routing::Mapper::SingletonResource
|
||||||
|
|
||||||
resource_scope(singleton_resoure.new resources.pop, api_only?, @scope[:shallow], options) do
|
resource_scope(singleton_resoure.new resources.pop, api_only?, @scope[:shallow], options) do
|
||||||
yield if block_given?
|
yield if block_given?
|
||||||
|
|
||||||
@@ -108,6 +154,9 @@ module ActionDispatch::Routing
|
|||||||
|
|
||||||
def set_mappings_for_web_dav_resources
|
def set_mappings_for_web_dav_resources
|
||||||
parent_resource.web_dav_actions.each do |action|
|
parent_resource.web_dav_actions.each do |action|
|
||||||
|
# Rails already defines GET, PUT, and DELETE actions which we don't
|
||||||
|
# want to override. Instead, we map WebDAV GET, PUT, and DELETE
|
||||||
|
# HTTP actions to 'web_dav_' prefixed methods.
|
||||||
if [:get, :put, :delete].include? action
|
if [:get, :put, :delete].include? action
|
||||||
send "web_dav_#{action.to_s}", '*resource'
|
send "web_dav_#{action.to_s}", '*resource'
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -4,13 +4,16 @@ module Calligraphy::Rails
|
|||||||
before_action :authenticate_with_digest_authentiation
|
before_action :authenticate_with_digest_authentiation
|
||||||
before_action :set_resource
|
before_action :set_resource
|
||||||
|
|
||||||
|
# Entry-point for all WebDAV requests. Handles checking and validating
|
||||||
|
# preconditions, directing of requests to the proper WebDAV action
|
||||||
|
# method, and composing responses to send back to the client.
|
||||||
def invoke_method
|
def invoke_method
|
||||||
method = request.request_method.downcase
|
method = request.request_method.downcase
|
||||||
|
|
||||||
if check_preconditions
|
if check_preconditions
|
||||||
if method == 'head'
|
if method == 'head'
|
||||||
status = get head: true
|
status = get head: true
|
||||||
elsif Calligraphy.allowed_methods.include? method
|
elsif Calligraphy.allowed_http_methods.include? method
|
||||||
set_resource_client_nonce(method) if Calligraphy.enable_digest_authentication
|
set_resource_client_nonce(method) if Calligraphy.enable_digest_authentication
|
||||||
|
|
||||||
status, body = send method
|
status, body = send method
|
||||||
@@ -27,14 +30,16 @@ module Calligraphy::Rails
|
|||||||
private
|
private
|
||||||
|
|
||||||
def verify_resource_scope
|
def verify_resource_scope
|
||||||
head :forbidden if params[:resource].include? '..'
|
head :forbidden if %w(. ..).any? { |seg| params[:resource].include? seg }
|
||||||
end
|
end
|
||||||
|
|
||||||
def authenticate_with_digest_authentiation
|
def authenticate_with_digest_authentiation
|
||||||
if Calligraphy.enable_digest_authentication
|
return unless Calligraphy.enable_digest_authentication
|
||||||
authenticate_or_request_with_http_digest do |username|
|
|
||||||
Calligraphy.digest_password_procedure.call(username)
|
realm = Calligraphy.http_authentication_realm
|
||||||
end
|
|
||||||
|
authenticate_or_request_with_http_digest(realm) do |username|
|
||||||
|
Calligraphy.digest_password_procedure.call(username)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -58,8 +63,8 @@ module Calligraphy::Rails
|
|||||||
|
|
||||||
def evaluate_if_header
|
def evaluate_if_header
|
||||||
conditions_met = false
|
conditions_met = false
|
||||||
|
|
||||||
condition_lists = get_if_conditions
|
condition_lists = get_if_conditions
|
||||||
|
|
||||||
condition_lists.each do |list|
|
condition_lists.each do |list|
|
||||||
conditions = parse_preconditions list
|
conditions = parse_preconditions list
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user