ぺーぺーSEのブログ

備忘録・メモ用サイト。

CalDAV(Calendaring Extensions to WebDAV : RFC 4791)についてのまとめ

CalDAV(RFC 4791)とは、iCalendar(RFC 2445)をWebDAV(RFC 4918)上でやり取りするための仕様。
iCalendarは、スケジュールのカレンダー情報を記述するための仕様。
CalDAVはiCalendarをWebDAVプロトコルでやり取りするための仕組み。
iCalendarデータのMIMEタイプは「text/calendar」。
このMIMEタイプを持つカレンダー・スケジュールデータファイルには、拡張子「ics」が付けられる。(Mac OSではタイプコード「iCal」)
「free and busy time」(空いた時間と予定のある時間)を含むデータには拡張子「ftb」が付与される。(Mac OSではタイプコード「iFBf」)
iCalendarは概ね下記の階層で記述される。

  • Calendar
    • Component
      • Property

Calendarは「BEGIN:VCALENDAR」で始まり「END:VCALENDAR」で終わる。
ComponentはCalendarの入れ子で

  • イベント (VEVENT)
    • カレンダー上で予定されたイベントについて記述された属性の集合体
  • ToDo (VTODO)
  • ジャーナル (VJOURNAL)
    • 日誌のように特定の日付にコメントを付けたり、作業内容や進捗の実績を記録するために利用
  • フリー・ビジータイム (VFREEBUSY)
    • 空いた時間と予定のある時間を定義
  • VTIMEZONE
    • 時間帯を定義
  • VALARM
    • アラーム設定を定義

などがあり「BEGIN:[XXX]」で始まり「END:[XXX]」で終わる。
PropertyはCalendarやComponentの属性を定義する。


■iCalendarの例(1997年7月14日-15日のパリ祭)

BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//hacksw/handcal//NONSGML v1.0//EN
BEGIN:VEVENT
DTSTART:19970714T170000Z
DTEND:19970715T035959Z
SUMMARY:Bastille Day Party
END:VEVENT
END:VCALENDAR



カレンダーの参照

CalDAVで最も良く利用されるREPORTメソッドについて説明する。
REPORTメソッドは、CalDAV固有のメソッドで、iCalファイルを一度に取得するためのメソッド
(ちなみに、CalDAV固有のメソッドはもうひとつMKCALENDARメソッドのみ。)

WebDAVでファイルを取得するためのメソッドはGETだが、
1月分のスケジュールを表示する場合には、複数iCalファイルを一度に取得する必要がある。
通常、CalDAVで扱う1つのファイルにはVCALENDARが1つ入っており、VCALENDARには一つのVEVENTが入っている。
(繰り返しイベントのようにVCALENDARには複数のVEVENTが入る場合もある)
つまり、CalDAVサーバー上には、各イベントが1つのiCalファイルとして扱われる。

REPORTメソッドは、「2010年4月のイベントを取得する」や「未承認のイベントを取得する」、「繰り返しイベントをある期間展開して取得する」など条件に合ったiCalファイルを取得するためのメソッド
以下は、2010年4月18日から4月24日のイベントGoogle Calendarから取得する電文。

REPORT /calendar/dav/test@gmail.com/events/ HTTP/1.1
Host: www.google.com
Depth: 1
Content-Type: application/xml; charset="utf-8"
Authorization: Basic XXXX
Content-Length: 467

<?xml version="1.0" encoding="utf-8" ?>
<C:calendar-query xmlns:D="DAV:"
                  xmlns:C="urn:ietf:params:xml:ns:caldav">
  <D:prop>
    <D:getetag/>
    <C:calendar-data/>
  </D:prop>
  <C:filter>
    <C:comp-filter name="VCALENDAR">
      <C:comp-filter name="VEVENT">
        <C:time-range start="20060104T000000Z"
                      end="20060105T000000Z"/>
      </C:comp-filter>
    </C:comp-filter>
  </C:filter>
</C:calendar-query>

検索条件はfilter要素に指定する。
filter要素には以下の3種類の条件が指定できる。

  • comp-filter要素
    • カレンダーのコンポーネントに対する条件文を指定
    • comp-filter要素は、time-range要素または、comp-prop要素を指定可能
    • 上記の例はcomp-filterにtime-range要素を指定している
  • prop-filter要素
    • カレンダーのコンポーネントに対する条件文を指定
    • 子要素にパラメータを条件に指定するparam-filter要素を指定可能
    • ただし、prop-filterが実装されているサーバーは多くは無い模様(Google CalendarとBedeworkはフィルターが効かない)
  • param-filter要素
    • カレンダーのコンポーネントのプロパティのパラメータに対する条件文を指定

上記のクエリーは以下の結果を返す。(ボディのみ記載)

<?xml version="1.0" encoding="UTF-8"?>
<D:multistatus xmlns:D="DAV:">
  <D:response>
    <D:href>/calendar/dav/test%40gmail.com/events/test%40google.com.ics</D:href>
    <D:propstat>
      <D:status>HTTP/1.1 200 OK</D:status>
      <D:prop>
        <D:getetag>"63407192760"</D:getetag>
        <C:calendar-data xmlns:C="urn:ietf:params:xml:ns:caldav">BEGIN:VCALENDAR
PRODID:-//Google Inc//Google Calendar 70.9054//EN
VERSION:2.0
CALSCALE:GREGORIAN
X-WR-CALNAME:Ichiro Suzuki
X-WR-TIMEZONE:Asia/Tokyo
BEGIN:VTIMEZONE
TZID:Asia/Tokyo
X-LIC-LOCATION:Asia/Tokyo
BEGIN:STANDARD
TZOFFSETFROM:+0900
TZOFFSETTO:+0900
TZNAME:JST
DTSTART:19700101T000000
END:STANDARD
END:VTIMEZONE
BEGIN:VEVENT
DTSTART;VALUE=DATE:20100420
DTEND;VALUE=DATE:20100421
DTSTAMP:20100417T130600Z
UID:test@google.com
CREATED:20100417T130600Z
DESCRIPTION:
LAST-MODIFIED:20100417T130600Z
LOCATION:
SEQUENCE:0
STATUS:CONFIRMED
SUMMARY:テスト
TRANSP:TRANSPARENT
BEGIN:VALARM
ACTION:DISPLAY
DESCRIPTION:This is an event reminder
TRIGGER:-P0DT0H10M0S
END:VALARM
END:VEVENT
END:VCALENDAR</C:calendar-data>
      </D:prop>
    </D:propstat>
  </D:response>
</D:multistatus>

上記の例では、カレンダーのプロパティをすべて取得する。
記の例では、カレンダーのプロパティをすべて取得します。
必要なプロパティのみを結果に含める場合には、calendar-data要素にcomp要素を指定します。
また、RRULEプロパティを含む繰り返しイベントは展開して取得することもできます。expand要素に展開する開始日(start属性)と終了日(end属性)を指定。
以下は、18日から3日間のみ繰り返しを展開するようにexpand要素を指定しています。また、結果が長くなるのでcomp要素により取得するプロパティも絞り込んでいる。
プロパティの指定と、繰り返しイベントの展開は、Google Calendarでは実装されていないので、以下はBedeworkに対して実行した結果。

<?xml version="1.0" encoding="UTF-8" ?>

<multistatus xmlns="DAV:" xmlns:ns2="http://www.w3.org/2002/12/cal/ical#" xmlns:ns1="urn:ietf:params:xml:ns:caldav">
  <response>
    <href>/ucaldav/user/test1/calendar/test.ics</href>
    <propstat>
      <prop>
        <ns1:calendar-data><![CDATA[BEGIN:VCALENDAR
PRODID:BedeWork V3.5
VERSION:2.0
METHOD:REQUEST
BEGIN:VEVENT
DTSTAMP:20100417T143109Z
SUMMARY:毎日
UID:test
DTSTART:20100418T020000Z
DTEND:20100418T030000Z
RECURRENCE-ID:20100418T110000Z
END:VEVENT
END:VCALENDAR
]]></ns1:calendar-data>
      </prop>
      <status>HTTP/1.1 200 ok</status>
    </propstat>
  </response>
  <response>
    <href>/ucaldav/user/test1/calendar/test.ics</href>
    <propstat>
      <prop>
        <ns1:calendar-data><![CDATA[BEGIN:VCALENDAR
PRODID:BedeWork V3.5
VERSION:2.0
METHOD:REQUEST
BEGIN:VEVENT
DTSTAMP:20100417T143109Z
SUMMARY:毎日
UID:test
DTSTART:20100419T020000Z
DTEND:20100419T030000Z
RECURRENCE-ID:20100419T110000Z
END:VEVENT
END:VCALENDAR
]]></ns1:calendar-data>
      </prop>
      <status>HTTP/1.1 200 ok</status>
    </propstat>
  </response>
  <response>
    <href>/ucaldav/user/test1/calendar/test.ics</href>
    <propstat>
      <prop>
        <ns1:calendar-data><![CDATA[BEGIN:VCALENDAR
PRODID:BedeWork V3.5
VERSION:2.0
METHOD:REQUEST
BEGIN:VEVENT
DTSTAMP:20100417T143109Z
SUMMARY:毎日
UID:test
DTSTART:20100420T020000Z
DTEND:20100420T030000Z
RECURRENCE-ID:20100420T110000Z
END:VEVENT
END:VCALENDAR
]]></ns1:calendar-data>
      </prop>
      <status>HTTP/1.1 200 ok</status>
    </propstat>
  </response>
</multistatus>



カレンダーの更新

イベントの追加と更新はPUTメソッドを使ってicsファイルをアップロードする。削除はDELETEメソッドを利用する。
リクエストボディには、追加するイベントVEVENTを含むカレンダーVCALENDARを指定する。

PUT https://www.google.com/calendar/dav/hrendoh@gmail.com/events/test@google.com.ics HTTP/1.1
Host: www.google.com
Content-Type: text/calendar; charset="utf-8"
Authorization: Basic xxx
Content-Length: 258

BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Example Corp.//CalDAV Client//EN
BEGIN:VEVENT
UID:test@google.com
DTSTAMP:20100426T160000Z
DTSTART:20100426T170000Z
DTEND:20100426T180000Z
SUMMARY:Fiddlerから追加
END:VEVENT
END:VCALENDAR

追加なのでレスポンスコードは201が返される。

HTTP/1.1 201 Created
DAV: 1, calendar-access, calendar-schedule, calendar-proxy
Content-Type: text/calendar; component=vevent; charset=UTF-8
Date: Sat, 24 Apr 2010 14:02:43 GMT
Expires: Sat, 24 Apr 2010 14:02:43 GMT
Cache-Control: private, max-age=0
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
Content-Length: 0
Server: GSE
UIDとファイル名について

UIDは、コレクション(WebDAVのフォルダ)内でユニークな値を指定する。
また、PUTするカレンダーのファイル名は.icsにするのが通例。Google Calendarも、Google Calendarから追加したイベントをREPORTメソッドで取得すると、結果の各イベントのファイル名は.icsというファイル名なっている。ファイル名は、WebDAVのhref要素で確認できる。
(ただし、CalDAVでPUTする場合はUIDとファイル名があってなくても登録できる。)

イベントの編集

イベントの編集は、既存のURLに対してPUTを実行する。
追加のリクエストでSUMMARYのみ変更して実行する。

PUT https://www.google.com/calendar/dav/test@gmail.com/events/test@google.com.ics HTTP/1.1
Host: www.google.com
Content-Type: text/calendar; charset="utf-8"
Authorization: Basic xxx
Content-Length: 258

BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Example Corp.//CalDAV Client//EN
BEGIN:VEVENT
UID:test@google.com
DTSTAMP:20100426T160000Z
DTSTART:20100426T170000Z
DTEND:20100426T180000Z
SUMMARY:Fiddlerから編集
END:VEVENT
END:VCALENDAR

編集成功のレスポンスコードは204。

HTTP/1.1 204 No Content
DAV: 1, calendar-access, calendar-schedule, calendar-proxy
Date: Sat, 24 Apr 2010 15:24:09 GMT
Server: GSE
イベントの削除

イベントの削除はDELETE。

DELETE https://www.google.com/calendar/dav/test@gmail.com/events/test@google.com.ics HTTP/1.1
Host: www.google.com
Content-Type: text/calendar; charset="utf-8"
Authorization: Basic xxx

削除成功のレスポンスコードは204。

HTTP/1.1 204 No Content
DAV: 1, calendar-access, calendar-schedule, calendar-proxy
Date: Sat, 24 Apr 2010 15:34:18 GMT
Server: GSE
予定の調整機能について(RFC 6638 - Scheduling Extensions to CalDAV)

CalDAVにおけるイベントの更新は、CalDAV Access (RFC 4791)では、PUT/DELETEメソッドについては特に定義されていないので、実際にはWebDAVでicsファイルを扱っているだけ。
しかし、予定の調整に関する仕様CalDAV Scheduling (draft-desruisseaux-caldav-sched)では、PUTやDELETEメソッドでイベントの更新があった場合の、スケジューリングメッセージのやり取りについての機能が追加される。

メモ

CalDAVで使用するHTTPメソッド
  • ACL
    • ACLを設定する
      • ACL(アクセスコントロールリスト)とは、ユーザーの役職や所属グループなどに応じてアクセス可能なリソースを制限する際に、ユーザー名とリソースとのひも付けを確認するためのリスト。
  • CONNECT
  • COPY
  • DELETE(DEL)
    • eventやcollection(folder)をサーバから削除する
      • DEL /user/calendar/myevent.ics
  • GET
    • eventを読取・検索する
      • GET /user/calendar/myevent.ics
    • ETAG(例えば"123124321524-1")も取得する
      • ETAGはeventをバージョニングするために使われる文字
      • myevent.icsが変更されたときにETAGは作成される
  • HEAD
    • eventの存在を確認する
    • evenのETAGのみを取得する
  • LOCK
  • MKCALENDAR
    • サーバにcollection(foler)を作成する
  • MKCOL
  • MOVE
  • OPTIONS
    • Check which actions can be made on a resource
  • POST
  • PROPFIND
  • PROPPATCH
  • PUT
    • eventをサーバに置く、あるいは更新する
      • PUT /user/calendar/myevent.ics
    • ETAGも返却される
    • ETAGを変更することも可能
  • REPORT
    • UID、LOCATION、SUMMARY等を使ってcollection(folder)にクエリを発行する
      • REPORT /user/calendar/
    • クエリはボディのXMLで表現する
  • TRACE
  • UNLOCK

http://milton.io/reference/milton-api/apidocs/io/milton/http/Request.Method.html

ツール