1. Введение
Если посмотреть на статистику сайта SecuritySpace.com, то можно увидеть, что вот уже 5 лет в десятку самых используемых модулей сервера Apache входит модуль mod_dav. Однако, как ни странно, данное обстоятельство никоим образом не повлияло на количество материалов о mod_dav в русскоязычной части сети. Хотя такие парадоксы происходят у нас нередко. Что ж, попытаемся устранить этот пробел. Тем более, что модуль действительно заслуживает самого пристального внимания.
Статья, которую Вы читаете, является первой из серии статей про модуль mod_dav. Сама серия состоит из трех статей. Первая статья расскажет об основной задачи модуля, а именно о протоколе WebDAV. Вторая статья расскажет о том, как протокол реализован в Apache и как настроить сервер на работу с ним. А третья статья рассмотрит детали реализации модуля mod_dav. Итак, начнем.
2. Что такое WebDAV?
А начнем мы с названия. И что же означает "dav" в названии mod_dav? Такое название модуль получил потому, что основная его задача - реализация протокола WebDAV. С вопросом "что такое WebDAV?" обратимся к статье на Wikipedia.org:
"WebDAV - это современный и защищённый сетевой протокол высокого уровня, работающий поверх HTTP для доступа к объектам и коллекциям объектов. Сокращение от Web-based Distributed Authoring and Versioning."
Не знаю как вам, а мне данное определение ясности в назначении протокола не дало. Но попробуем все же разобраться.
Начнем с задач протокола. Как ясно из определения, протокол позволяет работать с документами на удаленном сервере. Однако, это слишком общее определение протокола, и не дает
никакого представления об его особенностях. А особенностей у него довольно много. Перечислим основные из них:
- Выполнение основных файловых операций над объектами на удаленном сервере;
- Выполнение расширенных файловых операций (блокировки, поддержка версий);
- Работа с любым типом объектов (не только файлы);
- Поддержка метаданных (свойств) объектов;
- Поддержка одновременной работы над объектами.
Как видите, протокол предоставляет довольно много интересных возможностей. Теперь осталось разобраться, где эти возможности протокола будут востребованы.
Вот основные сценарии применения протокола WebDAV:
- Совместная работа с веб-документами;
- Сетевая файловая система;
- Распределенная разработка программного обеспечения;
- Унифицированный доступ к произвольному хранилищу.
И в качестве доказательства полезности протокола приведем примеры его реального использования. Вот только некоторые из них:
- Subversion. Использует WebDAV для совместной работы при разработке программного
обеспечения.
- Microsoft Explorer/Office/Outlook. Протокол WebDAV
используется для возможности работы с документами на удаленном сервере.
- Adobe GoLive. Протокол используется для совместной работы с веб-документами.
- Apache. Реализует поддержку WebDAV в модуле mod_dav.
- Zope и Tomcat. WebDAV используется для управления
контентом.
Примечание: Работа WebDAV регулируется следующими стандартами:
3. Как работает WebDAV?
Как уже говорилось выше, WebDAV является расширением протокола HTTP/1.1. WebDAV добавил в HTTP/1.1 несколько новых заголовков и методов, а также изменил существующие методы
HTTP.
Были добавлены следующие заголовки:
- DAV:
- If:
- Depth:
- Overwrite:
- Destination:
- Lock-Token:
- Timeout:
- Status-URI:
И следующие методы:
- PROPFIND;
- PROPPATCH;
- MKCOL;
- LOCK UNLOCK;
- COPY/MOVE.
Для того чтобы понять принцип работы протокола, рассмотрим каждый метод подробнее.
3.1 Метод PROPFIND
Метод PROPFIND является одним из основных методов протокола. Он предназначается для получения свойств ресурса или коллекции. Требуемый ресурс (коллекция) задается в методе с помощью URI. Если URI идентифицирует коллекцию, то метод возвращает свойства всех ресурсов, принадлежащих этой
коллекции. Данный метод бывает трех типов:
- <prop> - возвращает значение заданных свойств;
- <allprop> - возвращает имена и значение всех свойств ресурса;
- <propname> - возвращает имена свойств ресурса.
Для наглядности рассмотрим каждый вид метода на примере.
Тип PROP метода PROPFIND
Данный тип метода PROPFIND предназначен для запроса значений определенных свойств ресурса или коллекции. Для получения этих значений, клиент должен
указать в запросе серверу имена всех необходимых ему свойств.
Вот так выглядит запрос клиента серверу:
PROPFIND /file HTTP/1.1
Host: www.foo.bar
Content-type: text/xml; charset="utf-8"
Content-Length: xxxx
<?xml version="1.0"> encoding="utf-8" ?>
<D:propfind xmlns:D="DAV:">
<D:prop xmlns:R="http://www.foo.bar/boxschema/">>
<R:bigbox/>
<R:author/>
<R:DingALing/>
<R:Random/>
</D:prop>
</D:propfind>
В этом запросе клиент запрашивает значения свойств: bigbox, author, DingALing, Random для ресурса (не коллекции) http://www.foo.bar/file.
Примечание: URI коллекции обязательно должен содержать символ "/" в качестве завершающего символа. Пример: http://www.foo.bar/bar/
А вот так выглядит ответ сервера клиенту на данный запрос:
HTTP/1.1 207 Multi-Status
Content-Type: text/xml; charset="utf-8"
Content-Length: xxxx
<?xml version="1.0" encoding="utf-8" ?>
<D:multistatus xmlns:D="DAV:">
<D:response>
<D:href>http://www.foo.bar/file</D:href>
<D:propstat>
<D:prop xmlns:R="http://www.foo.bar/boxschema/">
<R:bigbox>
<R:BoxType>Box type A</R:BoxType>
</R:bigbox>
<R:author>
<R:Name>J.J. Johnson</R:Name>
</R:author>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
<D:propstat>
<D:prop>
<R:DingALing/>
<R:Random/>
</D:prop>
<D:status>HTTP/1.1 403 Forbidden</D:status>
<D:responsedescription>
The user does not have access to the DingALing property.
</D:responsedescription>
</D:propstat>
</D:response>
<D:responsedescription>
There has been an access violation error.
</D:responsedescription>
</D:multistatus>
Данный ответ возвращает значения свойств bigbox, author, а также описание того, что данный пользователь не имеет доступа к свойствам DingALing и Random.
Примечание: В случае, если хоть одно свойство вернет значение отличное от HTTP/1.1 200 OK, то запрос считается неуспешным (<D:responsedescription> There has been an access violation error. </D:responsedescription>).
Тип ALLPROP метода PROPFIND
Тип ALLPROP предназначен для запроса всех значений всех имеющихся свойств ресурса или коллекции. Для формирования метода этого типа клиенту необходимо только указать URI ресурса (коллекции).
Так выглядит запрос клиента серверу:
PROPFIND /container/ HTTP/1.1
Host: www.foo.bar
Depth: 1
Content-Type: text/xml; charset="utf-8"
Content-Length: xxxx
<?xml version="1.0" encoding="utf-8" ?>
<D:propfind xmlns:D="DAV:">
<D:allprop/>
</D:propfind>
Вот ответ сервера клиенту на данный запрос:
HTTP/1.1 207 Multi-Status
Content-Type: text/xml; charset="utf-8"
Content-Length: xxxx
<?xml version="1.0" encoding="utf-8" ?>
<D:multistatus xmlns:D="DAV:">
<D:response>
<D:href>http://www.foo.bar/container/</D:href>
<D:propstat>
<D:prop xmlns:R="http://www.foo.bar/boxschema/">
<R:bigbox>
<R:BoxType>Box type A</R:BoxType>
</R:bigbox>
<R:author>
<R:Name>Hadrian</R:Name>
</R:author>
<D:creationdate>
1997-12-01T17:42:21-08:00
</D:creationdate>
<D:displayname>
Example collection
</D:displayname>
<D:resourcetype>
<D:collection/>
</D:resourcetype>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
<D:response>
<D:href>http://www.foo.bar/container/front.html</D:href>
<D:propstat>
<D:prop xmlns:R="http://www.foo.bar/boxschema/">>
<R:bigbox>
<R:BoxType>Box type B</R:BoxType>
</R:bigbox>
<D:creationdate>
1997-12-01T18:27:21-08:00
</D:creationdate>
<D:displayname>
Example HTML resource
</D:displayname>
<D:getcontentlength>
4525
</D:getcontentlength>
<D:getcontenttype>
text/html
</D:getcontenttype>
<D:getetag>
zzyzx
</D:getetag>
<D:getlastmodified>
Monday, 12-Jan-98 09:25:56 GMT
</D:getlastmodified>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
</D:multistatus>
Ответ сервера возвращает все свойства (bigbox, author, creationdate, displayname, resourcetype) коллекции http://www.foo.bar/container/ и все свойства вложенных в эту коллекцию ресурсов. В нашем случае таким ресурсом является файл http://www.foo.bar/container/front.html, который обладает следующими свойствами: bigbox, creationdate, displayname, getcontentlength, getcontenttype, getetag, getlastmodified.
Тип PROPNAME метода PROPFIND
И последним типом метода PROPFIND является тип PROPNAME. Этот тип метода предназначен для получения имен всех свойств указанного ресурса (коллекции).
Так выглядит запрос этого типа:
PROPFIND /container/ HTTP/1.1
Host: www.foo.bar
Content-Type: text/xml; charset="utf-8"
Content-Length: xxxx
<?xml version="1.0" encoding="utf-8" ?>
<propfind xmlns="DAV:">
<propname/>
</propfind>
В нем клиент запрашивает имена всех свойств коллекции /container/, а также имена свойств всех вложенных в этот контейнер ресурсов.
Так выглядит ответ сервера на данный запрос:
HTTP/1.1 207 Multi-Status
Content-Type: text/xml; charset="utf-8"
Content-Length: xxxx
<?xml version="1.0" encoding="utf-8" ?>
<multistatus xmlns="DAV:">
<response>
<href>http://www.foo.bar/container/</href>
<propstat>
<prop xmlns:R="http://www.foo.bar/boxschema/">
<R:bigbox/>
<R:author/>
<creationdate/>
<displayname/>
<resourcetype/>
</prop>
<status>HTTP/1.1 200 OK</status>
</propstat>
</response>
<response>
<href>http://www.foo.bar/container/front.html</href>
<propstat>
<prop xmlns:R="http://www.foo.bar/boxschema/">>
<R:bigbox/>
<creationdate/>
<displayname/>
<getcontentlength/>
<getcontenttype/>
<getetag/>
<getlastmodified/>
</prop>
<status>HTTP/1.1 200 OK</status>
</propstat>
</response>
</multistatus>
Данный ответ показывает, что у коллекции http://www.foo.bar/container/ есть пять свойств: bigbox, author, creationdate, displayname, resourcetype. А вложенный ресурс http://www.foo.bar/container/front.html обладает следующими свойствами: bigbox, creationdate, displayname, getcontentlength, getcontenttype, getetag, getlastmodified.
3.2 Метод PROPPATCH
Как видно из названия метода PROPPATCH он предназначен для изменения свойств ресурсов, а именно для добавления, удаления или изменения свойств ресурса, заданного в URI.
Рассмотрим пример такого запроса:
PROPPATCH /bar.html HTTP/1.1
Host: www.foo.com
Content-Type: text/xml; charset="utf-8"
Content-Length: xxxx
<?xml version="1.0" encoding="utf-8" ?>
<D:propertyupdate xmlns:D="DAV:"
xmlns:Z="http://www.w3.com/standards/z39.50/">
<D:set>
<D:prop>
<Z:authors>
<Z:Author>Jim Whitehead</Z:Author>
<Z:Author>Roy Fielding</Z:Author>
</Z:authors>
</D:prop>
</D:set>
<D:remove>
<D:prop>
<Z:Copyright-Owner/>
</D:prop>
</D:remove>
</D:propertyupdate>
В этом запросе клиент пытается создать для ресурса http://www.foo.com/bar.html свойство authors и удалить свойство Copyright-Owner.
А вот так выглядит ответ сервера клиенту на этот запрос:
HTTP/1.1 207 Multi-Status
Content-Type: text/xml; charset="utf-8"
Content-Length: xxxx
<?xml version="1.0" encoding="utf-8" ?>
<D:multistatus xmlns:D="DAV:"
xmlns:Z="http://www.w3.com/standards/z39.50">
<D:response>
<D:href>http://www.foo.com/bar.html</D:href>
<D:propstat>
<D:prop>
<Z:Authors/>
</D:prop>
<D:status>HTTP/1.1 424 Failed Dependency</D:status>
</D:propstat>
<D:propstat>
<D:prop>
<Z:Copyright-Owner/>
</D:prop>
<D:status>HTTP/1.1 409 Conflict</D:status>
</D:propstat>
<D:responsedescription>
Copyright Owner can not be deleted or altered.
</D:responsedescription>
</D:response>
</D:multistatus>
Сервер показывает, что свойство Copyright-Owner не может быть удалено, поэтому ни одно свойство не будет изменено.
Ответ 424 Failed Dependency показывает, что операция над свойством Authors была бы выполнена успешно, если не произошел бы конфликт с удалением Copyright-Owner.
3.3 Метод MKCOL
Метод MKCOL является одним из самых простых методов WebDAV и предназначен для создания новой коллекции.
В этом примере клиент запрашивает сервер создать коллекцию /webdisc/xfiles/:
MKCOL /webdisc/xfiles/ HTTP/1.1
Host: www.server.org
В ответе сервер сообщает, что коллекция создана:
HTTP/1.1 201 Created
3.4 Метод LOCK
Метод LOCK предназначен для создания блокировки доступа любого типа. Блокировки влияют и на ресурсы, и на коллекции. Если заблокирован ресурс, то и все его свойства также являются заблокированными.
Данный пример запроса пытается наложить эксклюзивную блокировку на изменения ресурса /file.html
LOCK /file.html HTTP/1.1
Host: www.host.com
Content-Type: text/xml; charset="utf-8"
Content-Length: xxx
<?xml version="1.0" encoding="utf-8" ?>
<D:lockinfo xmlns:D="DAV:">
<D:lockscope>
<D:exclusive/>
</D:lockscope>
<D:locktype>
<D:write/>
</D:locktype>
</D:lockinfo>
Сервер показывает, что блокировка успешно создана. Ответ сервера также содержит значение opaquelocktoken, которое является уникальным идентификатором блокировки.
HTTP/1.1 200 OK
Content-Type: text/xml; charset="utf-8"
Content-Length: xxx
<?xml version="1.0" encoding="utf-8"?>
<D:prop xmlns:D="DAV:">
<D:lockdiscovery>
<D:activelock>
<D:locktype>
<D:write/>
</D:locktype>
<D:lockscope>
<D:exclusive/>
</D:lockscope>
<D:locktoken>
<D:href>
opaquelocktoken: e71d4fae-5dec-22d6-fea5-00a0c91e6be4
</D:href>
</D:locktoken>
</D:activelock>
</D:lockdiscovery>
</D:prop>
3.5 Метод UNLOCK
Метод UNLOCK предназначен для снятия блокировки с ресурса. Для формирования запроса требуется URI ресурса и значение opaquelocktoken созданной ранее блокировки.
Пример снятия блокировки:
UNLOCK /1234.html HTTP/1.1
Host: www.host.ru
Lock-Token: <opaquelocktoken:e71d4fae-5dec-22d6-fea5-00a0c91e6be4>
Данный запрос пытается снять блокировку (opaquelocktoken:e71d4fae-5dec-22d6-fea5-00a0c91e6be4) с ресурса 1234.html.
Ответ сервера показывает, что блокировка была успешно снята:
HTTP/1.1 204 No Content
Использование кода 204 (No Content) вместо 200 (OK) происходит, потому что сообщение ответа не содержит тела.
3.6 Методы COPY/MOVE
Метод COPY предназначен для создания копии ресурса, заданного с помощью URI. А URI копии ресурса задается в заголовке Destination. Метод копирует как ресурсы, так и коллекции (в зависимости от значения заголовка Depth).
В этом примере клиент пытается скопировать ресурс /~fielding/index.html и переписать им ресурс http://www.ics.uci.edu/users/f/fielding/index.html
COPY /~fielding/index.html HTTP/1.1
Host: www.ics.uci.edu
Destination: http://www.ics.uci.edu/users/f/fielding/index.html
Ответ сервера 204 No Content показывает, что ресурс http://www.ics.uci.edu/users/f/fielding/index.html был успешно перезаписан ресурсом /~fielding/index.html
HTTP/1.1 204 No Content
Метод MOVE функционирует аналогично методу COPY за исключением того, что после копирования ресурс удаляется.
Пример запроса:
MOVE /~fielding/index.html HTTP/1.1
Host: www.ics.uci.edu
Destination: http://www.ics.uci.edu/users/f/fielding/index.html
Ответ сервера 201 Created показывает, что ресурс http://www.ics.uci.edu/users/f/fielding/index.html не существовал до копирования.
HTTP/1.1 201 Created
Location: http://www.ics.uci.edu/users/f/fielding/index.html
Примечание: Помимо рассмотренных выше новых методов, протокол WebDAV переопределяет семантику методов HTTP/1.1: GET, HEAD, POST, DELETE. Значение методов осталось то же, но теперь они стали работать с ресурсами, коллекциями и свойствами.
Вот и все, что я хотел рассказать вам про протокол WebDAV. Информации, полученной из данной статьи, вполне достаточно, чтобы приступить к нашей основной цели, а именно, к изучению работы модуля mod_dav. Чем мы и займемся в следующей статье.
Более подробно про протокол WebDAV вы можете узнать в книге "WebDAV: Next-Generation Collaborative Web Authoring".
Ссылки