暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

WebDav规范与WebDavServlet的锁的实现 (之一)

中间件技术讨论圈 2016-08-19
1133

有一个WebDavServlet,这个类继承了DefaultServlet


该类实际上是实现了WebDav的规范的类,这个WebDav规范实际上是基于http规范的再一层的封装(相当于再加了几个方法),其类似于FTP这样的功能,对web服务器上资源进行操作的,有lock,资源属性设置等等;

下面我们就讲述一下WebDav规范到底是什么,还有在Tomcat中是怎么通过WebDavServlet来实现WebDav规范的

1.WebDav规范到底是什么

WebDav规范,是一个rfc文件,毕竟是一个协议,其协议的官方网站为http://www.webdav.org/specs/rfc4918.xml

RFC4918 规范的主要作用,在规范文档最开始的Introduction中介绍的非常清晰,这里截取一下:

This document describes an extension to the HTTP/1.1 protocol that allows clients to perform remote Web content authoring operations. This extension provides a coherent set of methods, headers, request entity body formats, and response entity body formats that provide operations for:

Properties: The ability to create, remove, and query information about Web pages, such as their authors, creation dates, etc.

Collections: The ability to create sets of documents and to retrieve a hierarchical membership listing (like a directory listing in a file system).

Locking: The ability to keep more than one person from working on a document at the same time. This prevents the "lost update problem", in which modifications are lost as first one author, then another, writes changes without merging the other author's changes.

Namespace Operations: The ability to instruct the server to copy and move Web resources, operations that change the mapping from URLs to resources.


首先,WebDav规范明确的是基于http1.1之上再进行的扩展,也就是说doget,post,put..这些方法都有,而且客户端和服务器端的传输机制也是沿用的http协议;

其次,我们从下面的几个大的分类中看到,WebDav规范扩展的内容:

a.对资源的属性可以进行增加和删除

b.支持批量操作,例如对可以列出目录(这个功能就和DefaultServlet中的listings属性一样)

c.支持锁定操作,类似于CVS的概念,当一个人将资源锁定之后,其它请求不能对该资源进行增删改

d.增量支持了对web服务器上的资源修改工作,例如甚至可以移动web服务器上的资源,对其资源进行拷贝,在原有的doput,dodelete操作之上,又进了一步;


对于上述的这几类的操作,规范给出了增加和修改具体的http请求方法,一共是11个方法,在规范文档的第九章:


doPropfind:对资源属性的获取,

doProppatch:对资源属性的增删改,

doMkcol:对集合资源进行创建,

doGet:新增支持对集合资源的get,

doPost:新增支持对集合资源的post,

doDelete:新增支持对集合资源的删除,

doPut:新增支持对集合资源的修改,

doCopy:对资源的复制,从web服务器上的一个地方复制到另一个地方

doMove:对资源的移动

doLock:资源锁定

doUnLock:资源的解锁


总结一下,

这些操作中,其中doGet,doPost,doDelete,doPut这些在http1.1协议中也有,只不过这里增加了集合操作,而doMkcol是新增的方法,可以对批量的资源进行创建

doPropfind,doProppatch是WebDav规范增加的对资源属性的操作;

doCopy,doMove是直接改变web服务器中的资源的操作;

doLock,doUnLock是锁定的操作;

下面,主要针对于Tomcat这四类实现研究WebDavServlet;


2.WebDavServlet的锁的实现


首先来看看WebDavServlet对于锁的实现,采用其类中的一个内置LockInfo的对象:


几个属性比较关键:

path:对应资源的路径,说白了,也是lock锁在哪个资源上

type:当前对资源的操作是读或者写

scope:该锁是独占锁,还是共享锁,如果是共享锁的话,不影响读取,独占锁读取需要等待

depth:该属性设置是为了指示当前目录的层级,在WebDav规范中有0,1,Infinity等三个选项可以选

owner:所有者

tokens:锁的ID,该值通过了MD5进行了加密并且进行了字符集的转换

expiresAt:该lock的过期时间

creationDate:lock的创建的时间


WebDavServlet中每当客户端请求doLock的时候,http客户端的请求需要符合WebDav规范,我们从WebDav规范找到其doLock的一个客户端和服务器端交互的例子


按照上述的示例,分析一下WebDavServlet 中的doLock方法,总共分为下面的几个步骤:


第一步:

首先调用isLock方法,判断该请求是否已经在该resource位置加过锁,;

如果发现其已经锁住了,那么直接按照WebDav返回response;

如果发现没有锁的话,doLock继续加锁;

因此这个isLock方法是判断该位置是否可加锁的重要的依据,

我们看看下面的代码:

  

该方法将请求头header和lockToken(Lock锁的ID)作为区分一个lock的唯一性的标识,说白了对应的就是该http请求和lockid,这两个标识的合集可以唯一区分一个请求中的加的锁,另外一个参数是path,这两个参数一块传入到isLocked方法中进行校验,完全可以判断出该请求中是否可以加锁;

在isLocked方法中有三个集合,这三个集合是WebDavServlet三个缓存:

resourceLocks这个集合,是当你给资源加锁了,该lock就会被加入这个Map集合中,标识着你这个资源已经被锁定了,这个Map的key是path路径,value是LockInfo对象,从上述的isLocked的判断可以看出,当通过path查询出对应的LockInfo对象时,说明该资源是上了锁;

conllectionLocks是指对于文件目录集合进行加锁,当你传入的path是一个文件目录的话,这个集合可以查看是否该目录有锁,除此之外,如果一个资源在一个目录中,该资源可以通过path.startWith(lock.path)来判断该资源所在的目录前缀是否存在锁,如果其目录存在锁,那么相当于这个资源会集成下来这个锁,这样的话,也不能够加锁成功;

上述的两个集合能查询出来存在对应的LockInfo,你还需要针对LockInfo.token集合中进行查询,这个集合是代表有n个http请求要同时对该Resource位置加锁,那么如果当前http请求的token在这个LockInfo.token集合中,说明该请求已经对这个Resource位置进行加锁了;


这三个资源集合梳理清楚之后,上面的isLocked方法会非常的清晰,当然,在LockInfo.token集合判断之前,如果发现resourceLocks和conllectionLocks中查询出来的LockInfo中的expiresAt已经过期的话,那么直接就直接从这两个集合中移除该path,说明加到该Resource位置的LockInfo锁已经过期,直接返回false,也就是意味着你可以随便加了;


第二步:第一步已经判断锁并没有重复,是可以尝试加的,那么new 一个LockInfo对象,然后是基于WebDav的doLock的请求规范,从req中其中的一些属性,如path都get出来,设置到这个LockInfo对象;


第三步:我们从前面的示例中看到,http请求中最后一部分是一个xml文件,实际上也就是请求端要加锁的信息,对于服务器端来说,肯定需要解析客户端请求的Lock锁的信息,将xml解析出来,继续设置到这个LockInfo对象中;


第四步:基于当前的LockInfo信息,生成唯一的locktoken


可以看到,lockToken是使用MD5进行加密,我们了解过MD5,是可以反推的,并且也是唯一的,这就是前面第一步中之所以可以使用LockInfo类中的lockToken作为当前请求是否已经对该资源加过锁的唯一依据;


第五步:依然是分成目录或者资源两种情况进行加锁操作,以资源为例:


对于规范中严格定义了独占锁和共享锁,也就是说共享锁可以加多个,而独占锁不可以:


因此,上面的代码中,如果查询到该资源处有锁,判断是否是独占锁,如果是的话,直接抛出错误,如果不是的话,共享锁可以加多个;当然,如果没有锁的话,直接就可以加,这里因为前面的resouceLocks和lock.tokens集合中都没有对应的元素,所以这里将该LockInfo加入到这几个集合中;

到这里为止,其实在服务器端的锁已经加上了,可以判断出该资源是否被加锁了;


第六步:按照WebDav的规范,响应也需要是xml的,因此继续组装前面的response的内容,并返回给客户端最终的结果:


到此为止,doLock方法就介绍完了,doUnLock方法其实就是doLock的反面,这里不再缀余


明天,我们继续分析WebDavServlet其余的几个方法


文章转载自中间件技术讨论圈,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论