return "400 Bad Request" if propfind contains invalid elements or more then one

This commit is contained in:
Ralf Becker 2017-09-26 19:12:15 +02:00
parent 2d57801c6a
commit 1ae0f29f01
2 changed files with 56 additions and 24 deletions

View File

@ -668,10 +668,11 @@ class HTTP_WebDAV_Server
} }
// analyze request payload // analyze request payload
$propinfo = new _parse_propfind("php://input", $this->store_request); $propinfo = new _parse_propfind("php://input", $this->store_request, $handler);
if ($this->store_request) $this->request = $propinfo->request; if ($this->store_request) $this->request = $propinfo->request;
if (!$propinfo->success) { if ($propinfo->error) {
$this->http_status("400 Error"); $this->http_status("400 Bad Request");
if (method_exists($this, 'log')) $this->log('Error parsing propfind: '.$propinfo->error);
return; return;
} }
$options['root'] = $propinfo->root; $options['root'] = $propinfo->root;

View File

@ -43,12 +43,12 @@
class _parse_propfind class _parse_propfind
{ {
/** /**
* success state flag * Error message or null on success
* *
* @var bool * @var string
* @access public * @access public
*/ */
var $success = false; var $error;
/** /**
* found properties are collected here * found properties are collected here
@ -104,17 +104,24 @@ class _parse_propfind
*/ */
var $request; var $request;
/**
* HTTP method "PROPFIND" or eg. "REPORT" in CalDAV
*
* @var string
*/
var $method;
/** /**
* constructor * constructor
* *
* @access public * @access public
* @param string $path * @param string $path
* @param boolean $store_request =false if true whole request data will be made available in $this->request * @param boolean $store_request =false if true whole request data will be made available in $this->request
* @param string $method ='PROPFIND' HTTP method to enable certain checks
*/ */
function __construct($path, $store_request=false) function __construct($path, $store_request=false, $method='PROPFIND')
{ {
// success state flag $this->method = $method;
$this->success = true;
// property storage array // property storage array
$this->props = array(); $this->props = array();
@ -128,7 +135,7 @@ class _parse_propfind
// open input stream // open input stream
$f_in = fopen($path, "r"); $f_in = fopen($path, "r");
if (!$f_in) { if (!$f_in) {
$this->success = false; $this->error = "Can't open $path!";
return; return;
} }
@ -148,19 +155,27 @@ class _parse_propfind
xml_parser_set_option($xml_parser, xml_parser_set_option($xml_parser,
XML_OPTION_CASE_FOLDING, false); XML_OPTION_CASE_FOLDING, false);
try {
// parse input // parse input
while ($this->success && !feof($f_in)) { while (!$this->error && !feof($f_in)) {
$line = fgets($f_in); $line = fgets($f_in);
if ($store_request) $this->request .= $line; if ($store_request) $this->request .= $line;
if (is_string($line)) { if (is_string($line)) {
$had_input = true; $had_input = true;
$this->success &= xml_parse($xml_parser, $line, false); if (!xml_parse($xml_parser, $line, false))
{
$this->error = 'XML parsing';
}
} }
} }
// finish parsing // finish parsing
if ($had_input) { if ($had_input && !xml_parse($xml_parser, "", true)) {
$this->success &= xml_parse($xml_parser, "", true); $this->error = 'XML parsing';
}
}
catch(Exception $e) {
$this->error = $e->getMessage();
} }
// free parser // free parser
@ -201,6 +216,22 @@ class _parse_propfind
// special tags at level 1: <allprop> and <propname> // special tags at level 1: <allprop> and <propname>
if ($this->depth == 1) { if ($this->depth == 1) {
$this->use = 'props'; $this->use = 'props';
if ($this->method == 'PROPFIND' && (!in_array($tag, array('allprop', 'prop', 'propname')) || $this->props))
{
$err = "$tag not allowed in propfind";
if ($this->props)
{
$err .= ' together with ';
switch($this->props)
{
case 'Array': $err .= 'prop'; break;
case 'all': $err .= 'allprop'; break;
case 'names': $err .= 'propname'; break;
}
}
throw new Exception($err);
}
switch ($tag) switch ($tag)
{ {
case "allprop": case "allprop":