implement RFC 5995 add member to collection via POST, but not yet set DAV:add-member due to problems with OS X clients

This commit is contained in:
Ralf Becker 2012-02-10 11:28:56 +00:00
parent 9d85196706
commit 21dfe8ac02
5 changed files with 57 additions and 26 deletions

View File

@ -506,16 +506,9 @@ class addressbook_groupdav extends groupdav_handler
$contact = $this->read($save_ok); $contact = $this->read($save_ok);
} }
// we should not return an etag here, as we never store the PUT vcard byte-by-byte // send evtl. necessary respose headers: Location, etag, ...
//header('ETag: "'.$this->get_etag($contact).'"'); $this->put_response_headers($contact, $options['path'], $retval, self::$path_attr != 'id');
// send GroupDAV Location header only if we dont use carddav_name as path-attribute
if ($retval !== true && self::$path_attr == 'id')
{
$path = preg_replace('|(.*)/[^/]*|', '\1/', $options['path']);
header($h='Location: '.$this->base_uri.$path.self::get_path($contact));
if ($this->debug) error_log(__METHOD__."($method,,$id) header('$h'): $retval");
}
if ($this->debug > 1) error_log(__METHOD__."(,'$id', $user, '$prefix') returning ".array2string($retval)); if ($this->debug > 1) error_log(__METHOD__."(,'$id', $user, '$prefix') returning ".array2string($retval));
return $retval; return $retval;
} }

View File

@ -703,13 +703,10 @@ class calendar_groupdav extends groupdav_handler
//header('ETag: "'.$etag.'"'); //header('ETag: "'.$etag.'"');
header('Schedule-Tag: "'.$schedule_tag.'"'); header('Schedule-Tag: "'.$schedule_tag.'"');
} }
// send GroupDAV Location header only if we dont use caldav_name as path-attribute
if ($retval !== true && self::$path_attr != 'caldav_name') // send evtl. necessary respose headers: Location, etag, ...
{ $this->put_response_headers($cal_id, $options['path'], $retval, self::$path_attr == 'caldav_name');
$path = preg_replace('|(.*)/[^/]*|', '\1/', $options['path']);
if ($this->debug) error_log(__METHOD__."(,$id,$user) cal_id=$cal_id: $retval");
header('Location: '.$this->base_uri.$path.$this->get_path($cal_id));
}
return $retval; return $retval;
} }

View File

@ -470,15 +470,9 @@ class infolog_groupdav extends groupdav_handler
$retval = '201 Created'; $retval = '201 Created';
} }
// we should not return an etag here, as we never store the PUT ical byte-by-byte // send evtl. necessary respose headers: Location, etag, ...
//header('ETag: "'.$this->get_etag($infoId).'"'); $this->put_response_headers($infoId, $options['path'], $retval, self::$path_attr == 'caldav_name');
// send GroupDAV Location header only if we dont use caldav_name as path-attribute
if ($retval !== true && self::$path_attr != 'caldav_name')
{
$path = preg_replace('|(.*)/[^/]*|', '\1/', $options['path']);
header('Location: '.$this->base_uri.$path.self::get_path($infoId));
}
return $retval; return $retval;
} }

View File

@ -238,6 +238,14 @@ class groupdav extends HTTP_WebDAV_Server
$this->dav_powered_by); $this->dav_powered_by);
parent::HTTP_WebDAV_Server(); parent::HTTP_WebDAV_Server();
// hack to allow to use query parameters in WebDAV, which HTTP_WebDAV_Server interprets as part of the path
list($this->_SERVER['REQUEST_URI']) = explode('?',$this->_SERVER['REQUEST_URI']);
/*if (substr($this->_SERVER['REQUEST_URI'],-13) == '/;add-member/')
{
$_GET['add-member'] = '';
$this->_SERVER['REQUEST_URI'] = substr($this->_SERVER['REQUEST_URI'],0,-12);
}*/
//error_log($_SERVER['REQUEST_URI']." --> ".$this->_SERVER['REQUEST_URI']);
$this->egw_charset = translation::charset(); $this->egw_charset = translation::charset();
if (strpos($this->base_uri, 'http') === 0) if (strpos($this->base_uri, 'http') === 0)
@ -763,6 +771,13 @@ class groupdav extends HTTP_WebDAV_Server
$props['displayname'] = translation::convert(lang($app).' '.$this->account_name($user),$this->egw_charset,'utf-8'); $props['displayname'] = translation::convert(lang($app).' '.$this->account_name($user),$this->egw_charset,'utf-8');
} }
// rfc 5995 (Use POST to add members to WebDAV collections): we use collection path with add-member query param
/* leaving it switched off, until further testing, because OS X iCal seem to ignore it and OS X Addressbook uses POST to full URL without ?add-member
if ($app && !in_array($app,array('inbox','outbox','principals'))) // not on inbox, outbox or principals
{
$props['add-member'][] = self::mkprop('href',$this->base_uri.$path.'?add-member');
}*/
// add props modifyable via proppatch from client, eg. calendar-color, see self::$proppatch_props // add props modifyable via proppatch from client, eg. calendar-color, see self::$proppatch_props
foreach((array)$GLOBALS['egw_info']['user']['preferences'][$app] as $name => $value) foreach((array)$GLOBALS['egw_info']['user']['preferences'][$app] as $name => $value)
{ {
@ -1093,6 +1108,13 @@ class groupdav extends HTTP_WebDAV_Server
*/ */
function POST(&$options) function POST(&$options)
{ {
// for some reason OS X Addressbook (CFNetwork user-agent) uses now (DAV:add-member given with collection URL+"?add-member")
// POST to the collection URL plus a UID like name component (like for regular PUT) to create new entrys
if (isset($_GET['add-member']) || groupdav_handler::get_agent() == 'cfnetwork')
{
$_GET['add-member'] = ''; // otherwise we give no Location header
return $this->PUT($options);
}
// read the content in a string, if a stream is given // read the content in a string, if a stream is given
if (isset($options['stream'])) if (isset($options['stream']))
{ {
@ -1446,7 +1468,9 @@ class groupdav extends HTTP_WebDAV_Server
$id = array_pop($parts); $id = array_pop($parts);
$ok = $id && ($user || $user === 0) && in_array($app,array('addressbook','calendar','infolog','principals')); $ok = ($id || isset($_GET['add-member']) && $_SERVER['REQUEST_METHOD'] == 'POST') &&
($user || $user === 0) && in_array($app,array('addressbook','calendar','infolog','principals'));
if ($this->debug) if ($this->debug)
{ {
error_log(__METHOD__."('$path') returning " . ($ok ? 'true' : 'false') . ": id='$id', app='$app', user='$user', user_prefix='$user_prefix'"); error_log(__METHOD__."('$path') returning " . ($ok ? 'true' : 'false') . ": id='$id', app='$app', user='$user', user_prefix='$user_prefix'");
@ -1525,9 +1549,9 @@ class groupdav extends HTTP_WebDAV_Server
': '.($name=='AUTHORIZATION'?'Basic ***************':$value).$msg_nl,$msg_type,$msg_file); ': '.($name=='AUTHORIZATION'?'Basic ***************':$value).$msg_nl,$msg_type,$msg_file);
} }
} }
error_log(''.$msg_nl,$msg_type,$msg_file);
if ($this->request) if ($this->request)
{ {
error_log(''.$msg_nl,$msg_type,$msg_file);
foreach(explode("\n",$this->request) as $line) error_log($line.$msg_nl,$msg_type,$msg_file); foreach(explode("\n",$this->request) as $line) error_log($line.$msg_nl,$msg_type,$msg_file);
} }
error_log('HTTP/1.1 '.$this->_http_status.$msg_nl,$msg_type,$msg_file); error_log('HTTP/1.1 '.$this->_http_status.$msg_nl,$msg_type,$msg_file);

View File

@ -457,6 +457,29 @@ abstract class groupdav_handler
return $entry[self::$path_attr].self::$path_extension; return $entry[self::$path_attr].self::$path_extension;
} }
/**
* Send response-headers for a PUT (or POST with add-member query parameter)
*
* @param int|array $entry id or array of new created entry
* @param string $path
* @param int|string $retval
* @param boolean $path_attr_is_name=true true: path_attr is ca(l|rd)dav_name, false: id (GroupDAV needs Location header)
*/
function put_response_headers($entry, $path, $retval, $path_attr_is_name=true)
{
// we should not return an etag here, as EGroupware never stores ical/vcard byte-by-byte
//header('ETag: "'.$this->get_etag($entry).'"');
// send Location header only if we dont use caldav_name as path-attribute or
if ($retval !== true && (!$path_attr_is_name ||
// POST with add-member query parameter
$_SERVER['REQUEST_METHOD'] == 'POST' && isset($_GET['add-member'])))
{
$path = preg_replace('|(.*)/[^/]*|', '\1/', $path);
header('Location: '.$this->base_uri.$path.$this->get_path($entry));
}
}
/** /**
* Return calendars/addressbooks shared from other users with the current one * Return calendars/addressbooks shared from other users with the current one
* *