* WebDAV: fixed not working range requests causing eg. direct playing of video files to fail

plus IDE warning fixes from trunk
This commit is contained in:
Ralf Becker 2015-01-17 17:33:05 +00:00
parent 791e03b44a
commit 7e9dcd422e

View File

@ -190,7 +190,7 @@ class HTTP_WebDAV_Server
* *
* dispatch WebDAV HTTP request to the apropriate method handler * dispatch WebDAV HTTP request to the apropriate method handler
* *
* @param $prefix=null prefix filesystem path with given path, eg. "/webdav" for owncloud 4.5 remote.php * @param $prefix =null prefix filesystem path with given path, eg. "/webdav" for owncloud 4.5 remote.php
* @return void * @return void
*/ */
function ServeRequest($prefix=null) function ServeRequest($prefix=null)
@ -213,18 +213,19 @@ class HTTP_WebDAV_Server
// seem to pass '?' unencoded, so we need to extract the path info out // seem to pass '?' unencoded, so we need to extract the path info out
// of the request URI ourselves // of the request URI ourselves
// if request URI contains a full url, remove schema and domain // if request URI contains a full url, remove schema and domain
$matches = null;
if (preg_match('|^https?://[^/]+(/.*)$|', $path_info=$this->_SERVER["REQUEST_URI"], $matches)) if (preg_match('|^https?://[^/]+(/.*)$|', $path_info=$this->_SERVER["REQUEST_URI"], $matches))
{ {
$path_info = $matches[1]; $path_info = $matches[1];
} }
$path_info = substr($path_info, strlen($this->_SERVER["SCRIPT_NAME"])); $path_info_raw = substr($path_info, strlen($this->_SERVER["SCRIPT_NAME"]));
// just in case the path came in empty ... // just in case the path came in empty ...
if (empty($path_info)) { if (empty($path_info_raw)) {
$path_info = "/"; $path_info_raw = "/";
} }
$path_info = $this->_urldecode($path_info); $path_info = self::_urldecode($path_info_raw);
if ($prefix && strpos($path_info, $prefix) === 0) if ($prefix && strpos($path_info, $prefix) === 0)
{ {
@ -237,7 +238,7 @@ class HTTP_WebDAV_Server
// set path // set path
// $_SERVER['PATH_INFO'] is already urldecoded // $_SERVER['PATH_INFO'] is already urldecoded
//$this->path = $this->_urldecode($path_info); //$this->path = self::_urldecode($path_info);
// quote '#' (e.g. OpenOffice uses this for lock-files) // quote '#' (e.g. OpenOffice uses this for lock-files)
$this->path = strtr($path_info,array( $this->path = strtr($path_info,array(
'%' => '%25', '%' => '%25',
@ -306,7 +307,6 @@ class HTTP_WebDAV_Server
} else { // method not found/implemented } else { // method not found/implemented
if ($this->_SERVER["REQUEST_METHOD"] == "LOCK") { if ($this->_SERVER["REQUEST_METHOD"] == "LOCK") {
$error = '412 Precondition failed'; $error = '412 Precondition failed';
;
} else { } else {
$error = '405 Method not allowed'; $error = '405 Method not allowed';
header("Allow: ".join(", ", $this->_allow())); // tell client what's allowed header("Allow: ".join(", ", $this->_allow())); // tell client what's allowed
@ -650,7 +650,7 @@ class HTTP_WebDAV_Server
/** /**
* PROPFIND method handler * PROPFIND method handler
* *
* @param string $handler='PROPFIND' allows to use method eg. for CalDAV REPORT * @param string $handler ='PROPFIND' allows to use method eg. for CalDAV REPORT
* @return void * @return void
*/ */
function http_PROPFIND($handler='PROPFIND') function http_PROPFIND($handler='PROPFIND')
@ -691,7 +691,7 @@ class HTTP_WebDAV_Server
if (is_array($lock) && count($lock)) { if (is_array($lock) && count($lock)) {
$created = isset($lock['created']) ? $lock['created'] : time(); $created = isset($lock['created']) ? $lock['created'] : time();
$modified = isset($lock['modified']) ? $lock['modified'] : time(); $modified = isset($lock['modified']) ? $lock['modified'] : time();
$files['files'][] = array("path" => $this->_slashify($this->path), $files['files'][] = array("path" => self::_slashify($this->path),
"props" => array($this->mkprop("displayname", $this->path), "props" => array($this->mkprop("displayname", $this->path),
$this->mkprop("creationdate", $created), $this->mkprop("creationdate", $created),
$this->mkprop("getlastmodified", $modified), $this->mkprop("getlastmodified", $modified),
@ -917,10 +917,10 @@ class HTTP_WebDAV_Server
/* TODO right now the user implementation has to make sure /* TODO right now the user implementation has to make sure
collections end in a slash, this should be done in here collections end in a slash, this should be done in here
by checking the resource attribute */ by checking the resource attribute */
$href = $this->_mergePaths($this->base_uri, $path); $href_raw = $this->_mergePaths($this->base_uri, $path);
/* minimal urlencoding is needed for the resource path */ /* minimal urlencoding is needed for the resource path */
$href = $this->_urlencode($href); $href = $this->_urlencode($href_raw);
if ($this->crrnd) if ($this->crrnd)
{ {
@ -1240,7 +1240,7 @@ class HTTP_WebDAV_Server
* we can NOT send Content-Length headers, as the have to reflect size * we can NOT send Content-Length headers, as the have to reflect size
* AFTER applying compression/transfer encoding. * AFTER applying compression/transfer encoding.
* *
* @param boolean $set=null * @param boolean $set =null
* @return boolean true if we use compression, false otherwise * @return boolean true if we use compression, false otherwise
*/ */
public static function use_compression($set=null) public static function use_compression($set=null)
@ -1314,23 +1314,24 @@ class HTTP_WebDAV_Server
return; return;
} }
if (isset($range['end'])) { if (!empty($range['end'])) {
$size = $range['end']-$range['start']+1; $size = $range['end']-$range['start']+1;
$this->http_status("206 Partial content"); $this->http_status("206 Partial content");
if (!self::use_compression()) header("Content-Length: $size"); if (!self::use_compression()) header("Content-Length: $size");
header("Content-Range: bytes $range[start]-$range[end]/" header("Content-Range: bytes $range[start]-$range[end]/"
. (isset($options['size']) ? $options['size'] : "*")); . (isset($options['size']) ? $options['size'] : "*"));
while ($size && !feof($options['stream'])) { while ($size > 0 && !feof($options['stream'])) {
$buffer = fread($options['stream'], 4096); $buffer = fread($options['stream'], $size < 8192 ? $size : 8192);
$size -= $this->bytes($buffer); $size -= self::bytes($buffer);
echo $buffer; echo $buffer;
} }
} else { } else {
$this->http_status("206 Partial content"); $this->http_status("206 Partial content");
if (isset($options['size'])) { if (isset($options['size'])) {
if (!self::use_compression()) header("Content-Length: ".($options['size'] - $range['start'])); if (!self::use_compression()) header("Content-Length: ".($options['size'] - $range['start']));
header("Content-Range: bytes ".$range['start']."-".$range['end']."/" header("Content-Range: bytes ".$range['start']."-".
. (isset($options['size']) ? $options['size'] : "*")); (isset($options['size']) ? $options['size']-1 : "")."/"
. (isset($options['size']) ? $options['size'] : "*"));
} }
fpassthru($options['stream']); fpassthru($options['stream']);
} }
@ -1358,7 +1359,7 @@ class HTTP_WebDAV_Server
fseek($options['stream'], $from, SEEK_SET); fseek($options['stream'], $from, SEEK_SET);
while ($size && !feof($options['stream'])) { while ($size && !feof($options['stream'])) {
$buffer = fread($options['stream'], 4096); $buffer = fread($options['stream'], 4096);
$size -= $this->bytes($buffer); $size -= self::bytes($buffer);
echo $buffer; echo $buffer;
} }
} }
@ -1376,7 +1377,7 @@ class HTTP_WebDAV_Server
if (is_array($options['data'])) { if (is_array($options['data'])) {
// reply to partial request // reply to partial request
} else { } else {
if (!self::use_compression()) header("Content-Length: ".$this->bytes($options['data'])); if (!self::use_compression()) header("Content-Length: ".self::bytes($options['data']));
echo $options['data']; echo $options['data'];
} }
} }
@ -1406,6 +1407,7 @@ class HTTP_WebDAV_Server
if (isset($this->_SERVER['HTTP_RANGE'])) { if (isset($this->_SERVER['HTTP_RANGE'])) {
// we only support standard "bytes" range specifications for now // we only support standard "bytes" range specifications for now
$matches = null;
if (preg_match('/bytes\s*=\s*(.+)/', $this->_SERVER['HTTP_RANGE'], $matches)) { if (preg_match('/bytes\s*=\s*(.+)/', $this->_SERVER['HTTP_RANGE'], $matches)) {
$options["ranges"] = array(); $options["ranges"] = array();
@ -1613,6 +1615,7 @@ class HTTP_WebDAV_Server
// single byte range requests are supported // single byte range requests are supported
// the header format is also specified in RFC 2616 14.16 // the header format is also specified in RFC 2616 14.16
// TODO we have to ensure that implementations support this or send 501 instead // TODO we have to ensure that implementations support this or send 501 instead
$matches = null;
if (!preg_match('@bytes\s+(\d+)-(\d+)/((\d+)|\*)@', $val, $matches)) { if (!preg_match('@bytes\s+(\d+)-(\d+)/((\d+)|\*)@', $val, $matches)) {
$this->http_status('400 bad request'); $this->http_status('400 bad request');
echo 'The service does only support single byte ranges'; echo 'The service does only support single byte ranges';
@ -1623,7 +1626,7 @@ class HTTP_WebDAV_Server
if (is_numeric($matches[3])) { if (is_numeric($matches[3])) {
$range['total_length'] = $matches[3]; $range['total_length'] = $matches[3];
} }
$option['ranges'][] = $range; $options['ranges'][] = $range;
// TODO make sure the implementation supports partial POST // TODO make sure the implementation supports partial POST
// this has to be done in advance to avoid data being overwritten // this has to be done in advance to avoid data being overwritten
@ -1792,6 +1795,7 @@ class HTTP_WebDAV_Server
// single byte range requests are supported // single byte range requests are supported
// the header format is also specified in RFC 2616 14.16 // the header format is also specified in RFC 2616 14.16
// TODO we have to ensure that implementations support this or send 501 instead // TODO we have to ensure that implementations support this or send 501 instead
$matches = null;
if (!preg_match('@bytes\s+(\d+)-(\d+)/((\d+)|\*)@', $val, $matches)) { if (!preg_match('@bytes\s+(\d+)-(\d+)/((\d+)|\*)@', $val, $matches)) {
$this->http_status("400 bad request"); $this->http_status("400 bad request");
echo "The service does only support single byte ranges"; echo "The service does only support single byte ranges";
@ -2156,7 +2160,7 @@ class HTTP_WebDAV_Server
} }
$content .= '</'.($this->crrnd?'':'D:')."error>\n"; $content .= '</'.($this->crrnd?'':'D:')."error>\n";
} }
if (!self::use_compression()) header("Content-Length: ".$this->bytes($content)); if (!self::use_compression()) header("Content-Length: ".self::bytes($content));
if ($content) echo $options['content']; if ($content) echo $options['content'];
} }
@ -2189,7 +2193,7 @@ class HTTP_WebDAV_Server
$http_host.= ":".$url["port"]; $http_host.= ":".$url["port"];
} else { } else {
// only path given, set host to self // only path given, set host to self
$http_host == $http_header_host; $http_host = $http_header_host;
} }
if ($http_host == $http_header_host && if ($http_host == $http_header_host &&
@ -2267,7 +2271,7 @@ class HTTP_WebDAV_Server
* @praram boolen property raw-flag * @praram boolen property raw-flag
* @return array property array * @return array property array
*/ */
function mkprop() public static function mkprop()
{ {
$args = func_get_args(); $args = func_get_args();
switch (count($args)) { switch (count($args)) {
@ -2323,7 +2327,7 @@ class HTTP_WebDAV_Server
* @param void * @param void
* @return string a new UUID * @return string a new UUID
*/ */
function _new_uuid() public static function _new_uuid()
{ {
// use uuid extension from PECL if available // use uuid extension from PECL if available
if (function_exists("uuid_create")) { if (function_exists("uuid_create")) {
@ -2353,9 +2357,9 @@ class HTTP_WebDAV_Server
* @param void * @param void
* @return string new RFC2518 opaque lock token * @return string new RFC2518 opaque lock token
*/ */
function _new_locktoken() public static function _new_locktoken()
{ {
return "opaquelocktoken:".HTTP_WebDAV_Server::_new_uuid(); return "opaquelocktoken:".self::_new_uuid();
} }
// }}} // }}}
@ -2558,6 +2562,7 @@ class HTTP_WebDAV_Server
*/ */
function _check_uri_condition($uri, $condition) function _check_uri_condition($uri, $condition)
{ {
unset($uri); // not used, but required by function signature
// not really implemented here, // not really implemented here,
// implementations must override // implementations must override
@ -2694,7 +2699,7 @@ class HTTP_WebDAV_Server
* @param string URL to encode * @param string URL to encode
* @return string encoded URL * @return string encoded URL
*/ */
function _urlencode($url) public static function _urlencode($url)
{ {
// cadaver (and probably all neon using agents) need a more complete url encoding // cadaver (and probably all neon using agents) need a more complete url encoding
// otherwise special chars like "$,()'" in filenames do NOT work // otherwise special chars like "$,()'" in filenames do NOT work
@ -2724,7 +2729,7 @@ class HTTP_WebDAV_Server
* @param string URL to decode * @param string URL to decode
* @return string decoded URL * @return string decoded URL
*/ */
function _urldecode($path) public static function _urldecode($path)
{ {
return rawurldecode($path); return rawurldecode($path);
} }
@ -2850,10 +2855,10 @@ class HTTP_WebDAV_Server
* @param string directory path * @param string directory path
* @returns string directory path wiht trailing slash * @returns string directory path wiht trailing slash
*/ */
function _slashify($path) public static function _slashify($path)
{ {
//error_log(__METHOD__." called with $path"); //error_log(__METHOD__." called with $path");
if ($path[$this->bytes($path)-1] != '/') { if ($path[self::bytes($path)-1] != '/') {
//error_log(__METHOD__." added slash at the end of path"); //error_log(__METHOD__." added slash at the end of path");
$path = $path."/"; $path = $path."/";
} }
@ -2866,10 +2871,10 @@ class HTTP_WebDAV_Server
* @param string directory path * @param string directory path
* @returns string directory path wihtout trailing slash * @returns string directory path wihtout trailing slash
*/ */
function _unslashify($path) public static function _unslashify($path)
{ {
//error_log(__METHOD__." called with $path"); //error_log(__METHOD__." called with $path");
if ($path[$this->bytes($path)-1] == '/') { if ($path[self::bytes($path)-1] == '/') {
$path = substr($path, 0, -1); $path = substr($path, 0, -1);
//error_log(__METHOD__." removed slash at the end of path"); //error_log(__METHOD__." removed slash at the end of path");
} }
@ -2883,14 +2888,14 @@ class HTTP_WebDAV_Server
* @param string child path * @param string child path
* @return string merged path * @return string merged path
*/ */
function _mergePaths($parent, $child) public static function _mergePaths($parent, $child)
{ {
//error_log("merge called :\n$parent \n$child\n" . function_backtrace()); //error_log("merge called :\n$parent \n$child\n" . function_backtrace());
//error_log("merge :\n".print_r($this->_mergePaths($this->_SERVER["SCRIPT_NAME"], $this->path)true)); //error_log("merge :\n".print_r($this->_mergePaths($this->_SERVER["SCRIPT_NAME"], $this->path)true));
if ($child{0} == '/') { if ($child{0} == '/') {
return $this->_unslashify($parent).$child; return self::_unslashify($parent).$child;
} else { } else {
return $this->_slashify($parent).$child; return self::_slashify($parent).$child;
} }
} }
@ -2900,9 +2905,9 @@ class HTTP_WebDAV_Server
* @param string $str * @param string $str
* @return int * @return int
*/ */
function bytes($str) public static function bytes($str)
{ {
static $func_overload; static $func_overload=null;
if (is_null($func_overload)) if (is_null($func_overload))
{ {
@ -2918,4 +2923,3 @@ class HTTP_WebDAV_Server
* c-basic-offset: 4 * c-basic-offset: 4
* End: * End:
*/ */
?>