diff options
author | Vincent Petry <vincent@nextcloud.com> | 2022-07-25 21:31:57 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-07-25 21:31:57 +0300 |
commit | 96efba0e1d6918a8c06915b634858a426d07a84f (patch) | |
tree | 32d166159ff27846f1f9adba86f9aca303ea466a | |
parent | 17019bea3f47a54511a0d21bb6f79a8f51917ac1 (diff) | |
parent | d7fe2aad351f4f4a7e86b8192462a1d8cf232c30 (diff) |
Merge pull request #1109 from nextcloud/backport/1106/stable24v24.0.7rc1v24.0.7v24.0.6rc1v24.0.6v24.0.5rc1v24.0.5v24.0.4rc1v24.0.4stable24
[stable24] Bump sabre/dav to 4.4.0
41 files changed, 378 insertions, 212 deletions
diff --git a/composer.json b/composer.json index eeae51e5..8bf12a73 100644 --- a/composer.json +++ b/composer.json @@ -43,7 +43,7 @@ "psr/container": "^1.1.1", "psr/event-dispatcher": "^1.0", "punic/punic": "^1.6", - "sabre/dav": "^4.2.1", + "sabre/dav": "^4.4.0", "scssphp/scssphp": "^1.8.1", "stecman/symfony-console-completion": "^0.11.0", "swiftmailer/swiftmailer": "^6.0", diff --git a/composer.lock b/composer.lock index 8ae606d1..4cf586e9 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "7461dcd296fb237e529761da75c52926", + "content-hash": "5ee0b77ff564d2f8fe67e711d9b20735", "packages": [ { "name": "aws/aws-sdk-php", @@ -3548,16 +3548,16 @@ }, { "name": "sabre/dav", - "version": "4.2.1", + "version": "4.4.0", "source": { "type": "git", "url": "https://github.com/sabre-io/dav.git", - "reference": "5e651f9ddc2b05745f5b28cd697c8e8c6a0b6146" + "reference": "b65362abc926520eda2c57e219f022a6c288069d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sabre-io/dav/zipball/5e651f9ddc2b05745f5b28cd697c8e8c6a0b6146", - "reference": "5e651f9ddc2b05745f5b28cd697c8e8c6a0b6146", + "url": "https://api.github.com/repos/sabre-io/dav/zipball/b65362abc926520eda2c57e219f022a6c288069d", + "reference": "b65362abc926520eda2c57e219f022a6c288069d", "shasum": "" }, "require": { @@ -3572,7 +3572,7 @@ "ext-spl": "*", "lib-libxml": ">=2.7.0", "php": "^7.1.0 || ^8.0", - "psr/log": "^1.0", + "psr/log": "^1.0 || ^2.0 || ^3.0", "sabre/event": "^5.0", "sabre/http": "^5.0.5", "sabre/uri": "^2.0", @@ -3599,8 +3599,8 @@ "autoload": { "psr-4": { "Sabre\\DAV\\": "lib/DAV/", - "Sabre\\DAVACL\\": "lib/DAVACL/", "Sabre\\CalDAV\\": "lib/CalDAV/", + "Sabre\\DAVACL\\": "lib/DAVACL/", "Sabre\\CardDAV\\": "lib/CardDAV/" } }, @@ -3630,7 +3630,7 @@ "issues": "https://github.com/sabre-io/dav/issues", "source": "https://github.com/fruux/sabre-dav" }, - "time": "2021-11-30T13:53:16+00:00" + "time": "2022-06-27T09:07:55+00:00" }, { "name": "sabre/event", @@ -3656,14 +3656,14 @@ }, "type": "library", "autoload": { - "psr-4": { - "Sabre\\Event\\": "lib/" - }, "files": [ "lib/coroutine.php", "lib/Loop/functions.php", "lib/Promise/functions.php" - ] + ], + "psr-4": { + "Sabre\\Event\\": "lib/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -3700,16 +3700,16 @@ }, { "name": "sabre/http", - "version": "5.1.3", + "version": "5.1.6", "source": { "type": "git", "url": "https://github.com/sabre-io/http.git", - "reference": "315f592adfcba8aeb73c2fd64285205747acbbd7" + "reference": "9976ac34ced206bd6579b7b37b401de9fac98dae" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sabre-io/http/zipball/315f592adfcba8aeb73c2fd64285205747acbbd7", - "reference": "315f592adfcba8aeb73c2fd64285205747acbbd7", + "url": "https://api.github.com/repos/sabre-io/http/zipball/9976ac34ced206bd6579b7b37b401de9fac98dae", + "reference": "9976ac34ced206bd6579b7b37b401de9fac98dae", "shasum": "" }, "require": { @@ -3759,7 +3759,7 @@ "issues": "https://github.com/sabre-io/http/issues", "source": "https://github.com/fruux/sabre-http" }, - "time": "2021-11-04T07:02:36+00:00" + "time": "2022-07-15T14:51:14+00:00" }, { "name": "sabre/uri", @@ -3820,16 +3820,16 @@ }, { "name": "sabre/vobject", - "version": "4.4.1", + "version": "4.4.3", "source": { "type": "git", "url": "https://github.com/sabre-io/vobject.git", - "reference": "06feff370141fd3118609f808e86d9315864bf14" + "reference": "2a043b994fa8d8a655c3d50d73c1ad443d31d677" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sabre-io/vobject/zipball/06feff370141fd3118609f808e86d9315864bf14", - "reference": "06feff370141fd3118609f808e86d9315864bf14", + "url": "https://api.github.com/repos/sabre-io/vobject/zipball/2a043b994fa8d8a655c3d50d73c1ad443d31d677", + "reference": "2a043b994fa8d8a655c3d50d73c1ad443d31d677", "shasum": "" }, "require": { @@ -3920,7 +3920,7 @@ "issues": "https://github.com/sabre-io/vobject/issues", "source": "https://github.com/fruux/sabre-vobject" }, - "time": "2021-12-07T09:45:33+00:00" + "time": "2022-07-15T15:21:17+00:00" }, { "name": "sabre/xml", @@ -3951,13 +3951,13 @@ }, "type": "library", "autoload": { - "psr-4": { - "Sabre\\Xml\\": "lib/" - }, "files": [ "lib/Deserializer/functions.php", "lib/Serializer/functions.php" - ] + ], + "psr-4": { + "Sabre\\Xml\\": "lib/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ diff --git a/composer/autoload_classmap.php b/composer/autoload_classmap.php index ac3cf959..a5ccf833 100644 --- a/composer/autoload_classmap.php +++ b/composer/autoload_classmap.php @@ -2376,6 +2376,7 @@ return array( 'Sabre\\DAV\\Auth\\Backend\\File' => $vendorDir . '/sabre/dav/lib/DAV/Auth/Backend/File.php', 'Sabre\\DAV\\Auth\\Backend\\IMAP' => $vendorDir . '/sabre/dav/lib/DAV/Auth/Backend/IMAP.php', 'Sabre\\DAV\\Auth\\Backend\\PDO' => $vendorDir . '/sabre/dav/lib/DAV/Auth/Backend/PDO.php', + 'Sabre\\DAV\\Auth\\Backend\\PDOBasicAuth' => $vendorDir . '/sabre/dav/lib/DAV/Auth/Backend/PDOBasicAuth.php', 'Sabre\\DAV\\Auth\\Plugin' => $vendorDir . '/sabre/dav/lib/DAV/Auth/Plugin.php', 'Sabre\\DAV\\Browser\\GuessContentType' => $vendorDir . '/sabre/dav/lib/DAV/Browser/GuessContentType.php', 'Sabre\\DAV\\Browser\\HtmlOutput' => $vendorDir . '/sabre/dav/lib/DAV/Browser/HtmlOutput.php', diff --git a/composer/autoload_static.php b/composer/autoload_static.php index ac1dd778..34954920 100644 --- a/composer/autoload_static.php +++ b/composer/autoload_static.php @@ -3007,6 +3007,7 @@ class ComposerStaticInit2f23f73bc0cc116b4b1eee1521aa8652 'Sabre\\DAV\\Auth\\Backend\\File' => __DIR__ . '/..' . '/sabre/dav/lib/DAV/Auth/Backend/File.php', 'Sabre\\DAV\\Auth\\Backend\\IMAP' => __DIR__ . '/..' . '/sabre/dav/lib/DAV/Auth/Backend/IMAP.php', 'Sabre\\DAV\\Auth\\Backend\\PDO' => __DIR__ . '/..' . '/sabre/dav/lib/DAV/Auth/Backend/PDO.php', + 'Sabre\\DAV\\Auth\\Backend\\PDOBasicAuth' => __DIR__ . '/..' . '/sabre/dav/lib/DAV/Auth/Backend/PDOBasicAuth.php', 'Sabre\\DAV\\Auth\\Plugin' => __DIR__ . '/..' . '/sabre/dav/lib/DAV/Auth/Plugin.php', 'Sabre\\DAV\\Browser\\GuessContentType' => __DIR__ . '/..' . '/sabre/dav/lib/DAV/Browser/GuessContentType.php', 'Sabre\\DAV\\Browser\\HtmlOutput' => __DIR__ . '/..' . '/sabre/dav/lib/DAV/Browser/HtmlOutput.php', diff --git a/composer/installed.json b/composer/installed.json index a3f43ada..f03e67f9 100644 --- a/composer/installed.json +++ b/composer/installed.json @@ -3704,17 +3704,17 @@ }, { "name": "sabre/dav", - "version": "4.2.1", - "version_normalized": "4.2.1.0", + "version": "4.4.0", + "version_normalized": "4.4.0.0", "source": { "type": "git", "url": "https://github.com/sabre-io/dav.git", - "reference": "5e651f9ddc2b05745f5b28cd697c8e8c6a0b6146" + "reference": "b65362abc926520eda2c57e219f022a6c288069d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sabre-io/dav/zipball/5e651f9ddc2b05745f5b28cd697c8e8c6a0b6146", - "reference": "5e651f9ddc2b05745f5b28cd697c8e8c6a0b6146", + "url": "https://api.github.com/repos/sabre-io/dav/zipball/b65362abc926520eda2c57e219f022a6c288069d", + "reference": "b65362abc926520eda2c57e219f022a6c288069d", "shasum": "" }, "require": { @@ -3729,7 +3729,7 @@ "ext-spl": "*", "lib-libxml": ">=2.7.0", "php": "^7.1.0 || ^8.0", - "psr/log": "^1.0", + "psr/log": "^1.0 || ^2.0 || ^3.0", "sabre/event": "^5.0", "sabre/http": "^5.0.5", "sabre/uri": "^2.0", @@ -3748,7 +3748,7 @@ "ext-imap": "*", "ext-pdo": "*" }, - "time": "2021-11-30T13:53:16+00:00", + "time": "2022-06-27T09:07:55+00:00", "bin": [ "bin/sabredav", "bin/naturalselection" @@ -3758,8 +3758,8 @@ "autoload": { "psr-4": { "Sabre\\DAV\\": "lib/DAV/", - "Sabre\\DAVACL\\": "lib/DAVACL/", "Sabre\\CalDAV\\": "lib/CalDAV/", + "Sabre\\DAVACL\\": "lib/DAVACL/", "Sabre\\CardDAV\\": "lib/CardDAV/" } }, @@ -3818,14 +3818,14 @@ "type": "library", "installation-source": "dist", "autoload": { - "psr-4": { - "Sabre\\Event\\": "lib/" - }, "files": [ "lib/coroutine.php", "lib/Loop/functions.php", "lib/Promise/functions.php" - ] + ], + "psr-4": { + "Sabre\\Event\\": "lib/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -3862,17 +3862,17 @@ }, { "name": "sabre/http", - "version": "5.1.3", - "version_normalized": "5.1.3.0", + "version": "5.1.6", + "version_normalized": "5.1.6.0", "source": { "type": "git", "url": "https://github.com/sabre-io/http.git", - "reference": "315f592adfcba8aeb73c2fd64285205747acbbd7" + "reference": "9976ac34ced206bd6579b7b37b401de9fac98dae" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sabre-io/http/zipball/315f592adfcba8aeb73c2fd64285205747acbbd7", - "reference": "315f592adfcba8aeb73c2fd64285205747acbbd7", + "url": "https://api.github.com/repos/sabre-io/http/zipball/9976ac34ced206bd6579b7b37b401de9fac98dae", + "reference": "9976ac34ced206bd6579b7b37b401de9fac98dae", "shasum": "" }, "require": { @@ -3891,7 +3891,7 @@ "suggest": { "ext-curl": " to make http requests with the Client class" }, - "time": "2021-11-04T07:02:36+00:00", + "time": "2022-07-15T14:51:14+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -3988,17 +3988,17 @@ }, { "name": "sabre/vobject", - "version": "4.4.1", - "version_normalized": "4.4.1.0", + "version": "4.4.3", + "version_normalized": "4.4.3.0", "source": { "type": "git", "url": "https://github.com/sabre-io/vobject.git", - "reference": "06feff370141fd3118609f808e86d9315864bf14" + "reference": "2a043b994fa8d8a655c3d50d73c1ad443d31d677" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sabre-io/vobject/zipball/06feff370141fd3118609f808e86d9315864bf14", - "reference": "06feff370141fd3118609f808e86d9315864bf14", + "url": "https://api.github.com/repos/sabre-io/vobject/zipball/2a043b994fa8d8a655c3d50d73c1ad443d31d677", + "reference": "2a043b994fa8d8a655c3d50d73c1ad443d31d677", "shasum": "" }, "require": { @@ -4015,7 +4015,7 @@ "suggest": { "hoa/bench": "If you would like to run the benchmark scripts" }, - "time": "2021-12-07T09:45:33+00:00", + "time": "2022-07-15T15:21:17+00:00", "bin": [ "bin/vobject", "bin/generate_vcards" @@ -4125,13 +4125,13 @@ "type": "library", "installation-source": "dist", "autoload": { - "psr-4": { - "Sabre\\Xml\\": "lib/" - }, "files": [ "lib/Deserializer/functions.php", "lib/Serializer/functions.php" - ] + ], + "psr-4": { + "Sabre\\Xml\\": "lib/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -6372,6 +6372,6 @@ "install-path": "../web-auth/webauthn-lib" } ], - "dev": true, + "dev": false, "dev-package-names": [] } diff --git a/composer/installed.php b/composer/installed.php index 91618aed..b901821f 100644 --- a/composer/installed.php +++ b/composer/installed.php @@ -3,11 +3,11 @@ 'name' => 'nextcloud/3rdparty', 'pretty_version' => 'dev-master', 'version' => 'dev-master', - 'reference' => 'b7964c17e8a2198313ee31f6117c1eb692f6e2c9', + 'reference' => '17019bea3f47a54511a0d21bb6f79a8f51917ac1', 'type' => 'library', 'install_path' => __DIR__ . '/../', 'aliases' => array(), - 'dev' => true, + 'dev' => false, ), 'versions' => array( 'aws/aws-sdk-php' => array( @@ -283,7 +283,7 @@ 'nextcloud/3rdparty' => array( 'pretty_version' => 'dev-master', 'version' => 'dev-master', - 'reference' => 'b7964c17e8a2198313ee31f6117c1eb692f6e2c9', + 'reference' => '17019bea3f47a54511a0d21bb6f79a8f51917ac1', 'type' => 'library', 'install_path' => __DIR__ . '/../', 'aliases' => array(), @@ -572,9 +572,9 @@ ), ), 'sabre/dav' => array( - 'pretty_version' => '4.2.1', - 'version' => '4.2.1.0', - 'reference' => '5e651f9ddc2b05745f5b28cd697c8e8c6a0b6146', + 'pretty_version' => '4.4.0', + 'version' => '4.4.0.0', + 'reference' => 'b65362abc926520eda2c57e219f022a6c288069d', 'type' => 'library', 'install_path' => __DIR__ . '/../sabre/dav', 'aliases' => array(), @@ -590,9 +590,9 @@ 'dev_requirement' => false, ), 'sabre/http' => array( - 'pretty_version' => '5.1.3', - 'version' => '5.1.3.0', - 'reference' => '315f592adfcba8aeb73c2fd64285205747acbbd7', + 'pretty_version' => '5.1.6', + 'version' => '5.1.6.0', + 'reference' => '9976ac34ced206bd6579b7b37b401de9fac98dae', 'type' => 'library', 'install_path' => __DIR__ . '/../sabre/http', 'aliases' => array(), @@ -608,9 +608,9 @@ 'dev_requirement' => false, ), 'sabre/vobject' => array( - 'pretty_version' => '4.4.1', - 'version' => '4.4.1.0', - 'reference' => '06feff370141fd3118609f808e86d9315864bf14', + 'pretty_version' => '4.4.3', + 'version' => '4.4.3.0', + 'reference' => '2a043b994fa8d8a655c3d50d73c1ad443d31d677', 'type' => 'library', 'install_path' => __DIR__ . '/../sabre/vobject', 'aliases' => array(), diff --git a/sabre/dav/README.md b/sabre/dav/README.md index acdb1e03..32ca1c3f 100644 --- a/sabre/dav/README.md +++ b/sabre/dav/README.md @@ -14,16 +14,17 @@ http://sabre.io/ Build status ------------ -| branch | status | minimum PHP version | -| ------------ | ------ | ------------------- | -| master | [![Build Status](https://travis-ci.org/sabre-io/dav.svg?branch=master)](https://travis-ci.org/sabre-io/dav) | PHP 7.1 | -| 3.1 | [![Build Status](https://travis-ci.org/sabre-io/dav.svg?branch=3.0)](https://travis-ci.org/sabre-io/dav) | PHP 5.5 | -| 3.0 | [![Build Status](https://travis-ci.org/sabre-io/dav.svg?branch=3.0)](https://travis-ci.org/sabre-io/dav) | PHP 5.4 | -| 2.1 | [![Build Status](https://travis-ci.org/sabre-io/dav.svg?branch=2.1)](https://travis-ci.org/sabre-io/dav) | PHP 5.4 | -| 2.0 | [![Build Status](https://travis-ci.org/sabre-io/dav.svg?branch=2.0)](https://travis-ci.org/sabre-io/dav) | PHP 5.4 | -| 1.8 | [![Build Status](https://travis-ci.org/sabre-io/dav.svg?branch=1.8)](https://travis-ci.org/sabre-io/dav) | PHP 5.3 | -| 1.7 | [![Build Status](https://travis-ci.org/sabre-io/dav.svg?branch=1.7)](https://travis-ci.org/sabre-io/dav) | PHP 5.3 | -| 1.6 | [![Build Status](https://travis-ci.org/sabre-io/dav.svg?branch=1.6)](https://travis-ci.org/sabre-io/dav) | PHP 5.3 | +| branch | status | PHP version | +|------------|---------------------------------------------------------------------------|--------------------| +| master 4.* | ![CI](https://github.com/sabre-io/dav/actions/workflows/ci.yml/badge.svg) | PHP 7.1 up, 8.0 up | +| 3.2 | unmaintained | PHP 5.5 to 7.1 | +| 3.1 | unmaintained | PHP 5.5 | +| 3.0 | unmaintained | PHP 5.4 | +| 2.1 | unmaintained | PHP 5.4 | +| 2.0 | unmaintained | PHP 5.4 | +| 1.8 | unmaintained | PHP 5.3 | +| 1.7 | unmaintained | PHP 5.3 | +| 1.6 | unmaintained | PHP 5.3 | Documentation ------------- diff --git a/sabre/dav/composer.json b/sabre/dav/composer.json index 7c9596d2..5f0a44d6 100644 --- a/sabre/dav/composer.json +++ b/sabre/dav/composer.json @@ -29,7 +29,7 @@ "ext-date" : "*", "ext-iconv" : "*", "lib-libxml" : ">=2.7.0", - "psr/log": "^1.0", + "psr/log": "^1.0 || ^2.0 || ^3.0", "ext-json": "*" }, "require-dev" : { diff --git a/sabre/dav/lib/CalDAV/Backend/PDO.php b/sabre/dav/lib/CalDAV/Backend/PDO.php index 0d5df396..2f48ab98 100644 --- a/sabre/dav/lib/CalDAV/Backend/PDO.php +++ b/sabre/dav/lib/CalDAV/Backend/PDO.php @@ -948,42 +948,46 @@ SQL; } list($calendarId, $instanceId) = $calendarId; - // Current synctoken - $stmt = $this->pdo->prepare('SELECT synctoken FROM '.$this->calendarTableName.' WHERE id = ?'); - $stmt->execute([$calendarId]); - $currentToken = $stmt->fetchColumn(0); - - if (is_null($currentToken)) { - return null; - } - $result = [ - 'syncToken' => $currentToken, 'added' => [], 'modified' => [], 'deleted' => [], ]; if ($syncToken) { - $query = 'SELECT uri, operation FROM '.$this->calendarChangesTableName.' WHERE synctoken >= ? AND synctoken < ? AND calendarid = ? ORDER BY synctoken'; + $query = 'SELECT uri, operation, synctoken FROM '.$this->calendarChangesTableName.' WHERE synctoken >= ? AND calendarid = ? ORDER BY synctoken'; if ($limit > 0) { - $query .= ' LIMIT '.(int) $limit; + // Fetch one more raw to detect result truncation + $query .= ' LIMIT '.((int) $limit + 1); } // Fetching all changes $stmt = $this->pdo->prepare($query); - $stmt->execute([$syncToken, $currentToken, $calendarId]); + $stmt->execute([$syncToken, $calendarId]); $changes = []; // This loop ensures that any duplicates are overwritten, only the // last change on a node is relevant. while ($row = $stmt->fetch(\PDO::FETCH_ASSOC)) { - $changes[$row['uri']] = $row['operation']; + $changes[$row['uri']] = $row; } + $currentToken = null; + $result_count = 0; foreach ($changes as $uri => $operation) { - switch ($operation) { + if (!is_null($limit) && $result_count >= $limit) { + $result['result_truncated'] = true; + break; + } + + if (null === $currentToken || $currentToken < $operation['synctoken'] + 1) { + // SyncToken in CalDAV perspective is consistently the next number of the last synced change event in this class. + $currentToken = $operation['synctoken'] + 1; + } + + ++$result_count; + switch ($operation['operation']) { case 1: $result['added'][] = $uri; break; @@ -995,7 +999,24 @@ SQL; break; } } + + if (!is_null($currentToken)) { + $result['syncToken'] = $currentToken; + } else { + // This means returned value is equivalent to syncToken + $result['syncToken'] = $syncToken; + } } else { + // Current synctoken + $stmt = $this->pdo->prepare('SELECT synctoken FROM '.$this->calendarTableName.' WHERE id = ?'); + $stmt->execute([$calendarId]); + $currentToken = $stmt->fetchColumn(0); + + if (is_null($currentToken)) { + return null; + } + $result['syncToken'] = $currentToken; + // No synctoken supplied, this is the initial sync. $query = 'SELECT uri FROM '.$this->calendarObjectTableName.' WHERE calendarid = ?'; $stmt = $this->pdo->prepare($query); diff --git a/sabre/dav/lib/CalDAV/Calendar.php b/sabre/dav/lib/CalDAV/Calendar.php index 9f32e702..6e989314 100644 --- a/sabre/dav/lib/CalDAV/Calendar.php +++ b/sabre/dav/lib/CalDAV/Calendar.php @@ -396,7 +396,8 @@ class Calendar implements ICalendar, DAV\IProperties, DAV\Sync\ISyncCollection, * 'deleted' => [ * 'foo.php.bak', * 'old.txt' - * ] + * ], + * 'result_truncated' : true * ]; * * The syncToken property should reflect the *current* syncToken of the @@ -406,6 +407,9 @@ class Calendar implements ICalendar, DAV\IProperties, DAV\Sync\ISyncCollection, * If the syncToken is specified as null, this is an initial sync, and all * members should be reported. * + * If result is truncated due to server limitation or limit by client, + * set result_truncated to true, otherwise set to false or do not add the key. + * * The modified property is an array of nodenames that have changed since * the last token. * @@ -422,12 +426,17 @@ class Calendar implements ICalendar, DAV\IProperties, DAV\Sync\ISyncCollection, * should be treated as infinite. * * If the limit (infinite or not) is higher than you're willing to return, - * you should throw a Sabre\DAV\Exception\TooMuchMatches() exception. + * the result should be truncated to fit the limit. + * Note that even when the result is truncated, syncToken must be consistent + * with the truncated result, not the result before truncation. + * (See RFC6578 Section 3.6 for detail) * * If the syncToken is expired (due to data cleanup) or unknown, you must * return null. * * The limit is 'suggestive'. You are free to ignore it. + * TODO: RFC6578 Setion 3.7 says that the server must fail when the server + * cannot truncate according to the limit, so it may not be just suggestive. * * @param string $syncToken * @param int $syncLevel diff --git a/sabre/dav/lib/DAV/Auth/Backend/PDOBasicAuth.php b/sabre/dav/lib/DAV/Auth/Backend/PDOBasicAuth.php new file mode 100644 index 00000000..39324e4d --- /dev/null +++ b/sabre/dav/lib/DAV/Auth/Backend/PDOBasicAuth.php @@ -0,0 +1,114 @@ +<?php + +namespace Sabre\DAV\Auth\Backend; + +/** + * This is an authentication backend that uses a database to manage passwords. + * + * @copyright Copyright (C) fruux GmbH (https://fruux.com/) + * @license http://sabre.io/license/ Modified BSD License + */ +class PDOBasicAuth extends AbstractBasic +{ + /** + * Reference to PDO connection. + * + * @var PDO + */ + protected $pdo; + + /** + * PDO table name we'll be using. + * + * @var string + */ + protected $tableName; + + /** + * PDO digest column name we'll be using + * (i.e. digest, password, password_hash). + * + * @var string + */ + protected $digestColumn; + + /** + * PDO uuid(unique user identifier) column name we'll be using + * (i.e. username, email). + * + * @var string + */ + protected $uuidColumn; + + /** + * Digest prefix: + * if the backend you are using for is prefixing + * your password hashes set this option to your prefix to + * cut it off before verfiying. + * + * @var string + */ + protected $digestPrefix; + + /** + * Creates the backend object. + * + * If the filename argument is passed in, it will parse out the specified file fist. + */ + public function __construct(\PDO $pdo, array $options = []) + { + $this->pdo = $pdo; + if (isset($options['tableName'])) { + $this->tableName = $options['tableName']; + } else { + $this->tableName = 'users'; + } + if (isset($options['digestColumn'])) { + $this->digestColumn = $options['digestColumn']; + } else { + $this->digestColumn = 'digest'; + } + if (isset($options['uuidColumn'])) { + $this->uuidColumn = $options['uuidColumn']; + } else { + $this->uuidColumn = 'username'; + } + if (isset($options['digestPrefix'])) { + $this->digestPrefix = $options['digestPrefix']; + } + } + + /** + * Validates a username and password. + * + * This method should return true or false depending on if login + * succeeded. + * + * @param string $username + * @param string $password + * + * @return bool + */ + public function validateUserPass($username, $password) + { + $stmt = $this->pdo->prepare('SELECT '.$this->digestColumn.' FROM '.$this->tableName.' WHERE '.$this->uuidColumn.' = ?'); + $stmt->execute([$username]); + $result = $stmt->fetchAll(); + + if (!count($result)) { + return false; + } else { + $digest = $result[0][$this->digestColumn]; + + if (isset($this->digestPrefix)) { + $digest = substr($digest, strlen($this->digestPrefix)); + } + + if (password_verify($password, $digest)) { + return true; + } + + return false; + } + } +} diff --git a/sabre/dav/lib/DAV/CorePlugin.php b/sabre/dav/lib/DAV/CorePlugin.php index 74350c28..dbd8976b 100644 --- a/sabre/dav/lib/DAV/CorePlugin.php +++ b/sabre/dav/lib/DAV/CorePlugin.php @@ -645,6 +645,10 @@ class CorePlugin extends ServerPlugin if (!$this->server->emit('beforeBind', [$copyInfo['destination']])) { return false; } + if (!$this->server->emit('beforeCopy', [$path, $copyInfo['destination']])) { + return false; + } + if ($copyInfo['destinationExists']) { if (!$this->server->emit('beforeUnbind', [$copyInfo['destination']])) { return false; @@ -653,6 +657,7 @@ class CorePlugin extends ServerPlugin } $this->server->tree->copy($path, $copyInfo['destination']); + $this->server->emit('afterCopy', [$path, $copyInfo['destination']]); $this->server->emit('afterBind', [$copyInfo['destination']]); // If a resource was overwritten we should send a 204, otherwise a 201 diff --git a/sabre/dav/lib/DAV/StringUtil.php b/sabre/dav/lib/DAV/StringUtil.php index 13a4399e..edfb7fa5 100644 --- a/sabre/dav/lib/DAV/StringUtil.php +++ b/sabre/dav/lib/DAV/StringUtil.php @@ -77,10 +77,8 @@ class StringUtil */ public static function ensureUTF8($input) { - $encoding = mb_detect_encoding($input, ['UTF-8', 'ISO-8859-1'], true); - - if ('ISO-8859-1' === $encoding) { - return utf8_encode($input); + if (!mb_check_encoding($input, 'UTF-8') && mb_check_encoding($input, 'ISO-8859-1')) { + return mb_convert_encoding($input, 'UTF-8', 'ISO-8859-1'); } else { return $input; } diff --git a/sabre/dav/lib/DAV/Sync/Plugin.php b/sabre/dav/lib/DAV/Sync/Plugin.php index 32106abb..8609f759 100644 --- a/sabre/dav/lib/DAV/Sync/Plugin.php +++ b/sabre/dav/lib/DAV/Sync/Plugin.php @@ -124,6 +124,10 @@ class Plugin extends DAV\ServerPlugin throw new DAV\Exception\InvalidSyncToken('Invalid or unknown sync token'); } + if (!array_key_exists('result_truncated', $changeInfo)) { + $changeInfo['result_truncated'] = false; + } + // Encoding the response $this->sendSyncCollectionResponse( $changeInfo['syncToken'], @@ -131,7 +135,8 @@ class Plugin extends DAV\ServerPlugin $changeInfo['added'], $changeInfo['modified'], $changeInfo['deleted'], - $report->properties + $report->properties, + $changeInfo['result_truncated'] ); } @@ -141,7 +146,7 @@ class Plugin extends DAV\ServerPlugin * @param string $syncToken * @param string $collectionUrl */ - protected function sendSyncCollectionResponse($syncToken, $collectionUrl, array $added, array $modified, array $deleted, array $properties) + protected function sendSyncCollectionResponse($syncToken, $collectionUrl, array $added, array $modified, array $deleted, array $properties, bool $resultTruncated = false) { $fullPaths = []; @@ -164,6 +169,10 @@ class Plugin extends DAV\ServerPlugin $fullPath = $collectionUrl.'/'.$item; $responses[] = new DAV\Xml\Element\Response($fullPath, [], 404); } + if ($resultTruncated) { + $responses[] = new DAV\Xml\Element\Response($collectionUrl.'/', [], 507); + } + $multiStatus = new DAV\Xml\Response\MultiStatus($responses, self::SYNCTOKEN_PREFIX.$syncToken); $this->server->httpResponse->setStatus(207); diff --git a/sabre/dav/lib/DAV/Tree.php b/sabre/dav/lib/DAV/Tree.php index 2417979a..8215e2c3 100644 --- a/sabre/dav/lib/DAV/Tree.php +++ b/sabre/dav/lib/DAV/Tree.php @@ -226,7 +226,7 @@ class Tree // flushing the entire cache $path = trim($path, '/'); foreach ($this->cache as $nodePath => $node) { - if ('' === $path || $nodePath == $path || 0 === strpos($nodePath, $path.'/')) { + if ('' === $path || $nodePath == $path || 0 === strpos((string) $nodePath, $path.'/')) { unset($this->cache[$nodePath]); } } diff --git a/sabre/dav/lib/DAV/Version.php b/sabre/dav/lib/DAV/Version.php index b6e64677..c6273ef7 100644 --- a/sabre/dav/lib/DAV/Version.php +++ b/sabre/dav/lib/DAV/Version.php @@ -16,5 +16,5 @@ class Version /** * Full version number. */ - public const VERSION = '4.2.1'; + public const VERSION = '4.4.0'; } diff --git a/sabre/http/CHANGELOG.md b/sabre/http/CHANGELOG.md index 4db8cc77..2dddce4f 100644 --- a/sabre/http/CHANGELOG.md +++ b/sabre/http/CHANGELOG.md @@ -1,6 +1,23 @@ ChangeLog ========= +5.1.6 (2022-07-15) +------------------ + +* #187 Allow testSendToGetLargeContent peak memory usage to be specified externally (@phil-davis) +* #188 Fix various small typos and grammar (@phil-davis) +* #189 Fix typo in text of status code 203 'Non-Authoritative Information' (@phil-davis) + +5.1.5 (2022-07-09) +------------------ + +* #184 Remove 4GB file size workaround for 32bit OS / Stream Videos on IOS (@schoetju) + +5.1.4 (2022-06-24) +------------------ + +* #182 Fix encoding detection on PHP 8.1 (@come-nc) + 5.1.3 (2021-11-04) ------------------ @@ -72,7 +89,7 @@ ChangeLog * #65: It's now possible to supply request/response bodies using a callback functions. This allows very high-speed/low-memory responses to be created. (@petrkotek). -* Strict typing is used every where this is applicable. +* Strict typing is used everywhere this is applicable. * Removed `URLUtil` class. It was deprecated a long time ago, and most of its functions moved to the `sabre/uri` package. * Removed `Util` class. Most of its functions moved to the `functions.php` @@ -91,7 +108,7 @@ ChangeLog 4.2.3 (2017-06-12) ------------------ -* #74, #77: Work around 4GB file size limit at 32 Bit systems +* #74, #77: Work around 4GB file size limit at 32-Bit systems 4.2.2 (2017-01-02) @@ -279,7 +296,7 @@ ChangeLog * Changed: Response::send() is now Sapi::sendResponse($response). * Changed: Request::createFromPHPRequest is now Sapi::getRequest(). * Changed: Message::getBodyAsStream and Message::getBodyAsString were added. The - existing Message::getBody changed it's behavior, so be careful. + existing Message::getBody changed its behavior, so be careful. 2.0.0alpha5 (2013-11-07) diff --git a/sabre/http/README.md b/sabre/http/README.md index 8159b4d4..2f01c144 100644 --- a/sabre/http/README.md +++ b/sabre/http/README.md @@ -28,11 +28,11 @@ The objects are extendable and easily mockable. Build status ------------ -| branch | status | -| ------ | ------ | +| branch | status | +|--------|---------------------------------------------------------------------------------------------------------------| | master | [![Build Status](https://travis-ci.org/sabre-io/http.svg?branch=master)](https://travis-ci.org/sabre-io/http) | -| 4.2 | [![Build Status](https://travis-ci.org/sabre-io/http.svg?branch=4.2)](https://travis-ci.org/sabre-io/http) | -| 3.0 | [![Build Status](https://travis-ci.org/sabre-io/http.svg?branch=3.0)](https://travis-ci.org/sabre-io/http) | +| 4.2 | [![Build Status](https://travis-ci.org/sabre-io/http.svg?branch=4.2)](https://travis-ci.org/sabre-io/http) | +| 3.0 | [![Build Status](https://travis-ci.org/sabre-io/http.svg?branch=3.0)](https://travis-ci.org/sabre-io/http) | Installation ------------ @@ -84,7 +84,7 @@ $request = HTTP\Sapi::getRequest(); This line should only happen once in your entire application. Everywhere else you should pass this request object around using dependency injection. -You should always typehint on it's interface: +You should always typehint on its interface: ```php function handleRequest(HTTP\RequestInterface $request) { @@ -133,9 +133,9 @@ Simply extending Request and Response may pose some problems: 1. You may want to extend the objects with new behaviors differently, in different subsystems of your application, -2. The `Sapi::getRequest` factory always returns a instance of +2. The `Sapi::getRequest` factory always returns an instance of `Request` so you would have to override the factory method as well, -3. By controlling the instantation and depend on specific `Request` and +3. By controlling the instantiation and depend on specific `Request` and `Response` instances in your library or application, you make it harder to work with other applications which also use `sabre/http`. @@ -162,7 +162,7 @@ class MyRequest extends HTTP\RequestDecorator { Our application assumes that the true `Request` object was instantiated somewhere else, by some other subsystem. This could simply be a call like `$request = Sapi::getRequest()` at the top of your application, -but could also be somewhere in a unittest. +but could also be somewhere in a unit test. All we know in the current subsystem, is that we received a `$request` and that it implements `Sabre\HTTP\RequestInterface`. To decorate this object, @@ -296,7 +296,7 @@ $remoteUrl = 'http://example.org/'; // The url we're proxying from. Please note that this must be a relative url, // and basically acts as the base url. // -// If youre $remoteUrl doesn't end with a slash, this one probably shouldn't +// If your $remoteUrl doesn't end with a slash, this one probably shouldn't // either. $myBaseUrl = '/reverseproxy.php'; // $myBaseUrl = '/~evert/sabre/http/examples/reverseproxy.php/'; @@ -412,10 +412,10 @@ function setBaseUrl($url); * If the full path is equal to the base url, this method will return an * empty string. * - * This method will also urldecode the path, and if the url was incoded as + * This method will also urldecode the path, and if the url was encoded as * ISO-8859-1, it will convert it to UTF-8. * - * If the path is outside of the base url, a LogicException will be thrown. + * If the path is outside the base url, a LogicException will be thrown. * * @return string */ @@ -491,7 +491,7 @@ function getBodyAsStream(); function getBodyAsString(); /** - * Returns the message body, as it's internal representation. + * Returns the message body, as its internal representation. * * This could be either a string or a stream. * @@ -515,7 +515,7 @@ function setBody($body); function getHeaders(); /** - * Returns a specific HTTP header, based on it's name. + * Returns a specific HTTP header, based on its name. * * The name must be treated as case-insensitive. * @@ -529,7 +529,7 @@ function getHeader($name); /** * Updates a HTTP header. * - * The case-sensitity of the name value must be retained as-is. + * The case-sensitivity of the name value must be retained as-is. * * @param string $name * @param string $value @@ -561,7 +561,7 @@ function addHeaders(array $headers); /** * Removes a HTTP header. * - * The specified header name must be treated as case-insenstive. + * The specified header name must be treated as case-insensitive. * This method should return true if the header was successfully deleted, * and false if the header did not exist. * @@ -593,7 +593,7 @@ function getHttpVersion(); /** * Returns the current HTTP status. * - * This is the status-code as well as the human readable string. + * This is the status-code as well as the human-readable string. * * @return string */ @@ -602,7 +602,7 @@ function getStatus(); /** * Sets the HTTP status code. * - * This can be either the full HTTP status code with human readable string, + * This can be either the full HTTP status code with human-readable string, * for example: "403 I can't let you do that, Dave". * * Or just the code, in which case the appropriate default message will be @@ -635,7 +635,7 @@ function getBodyAsStream(); function getBodyAsString(); /** - * Returns the message body, as it's internal representation. + * Returns the message body, as its internal representation. * * This could be either a string or a stream. * @@ -660,7 +660,7 @@ function setBody($body); function getHeaders(); /** - * Returns a specific HTTP header, based on it's name. + * Returns a specific HTTP header, based on its name. * * The name must be treated as case-insensitive. * @@ -674,7 +674,7 @@ function getHeader($name); /** * Updates a HTTP header. * - * The case-sensitity of the name value must be retained as-is. + * The case-sensitivity of the name value must be retained as-is. * * @param string $name * @param string $value @@ -706,7 +706,7 @@ function addHeaders(array $headers); /** * Removes a HTTP header. * - * The specified header name must be treated as case-insenstive. + * The specified header name must be treated as case-insensitive. * This method should return true if the header was successfully deleted, * and false if the header did not exist. * diff --git a/sabre/http/lib/Auth/AbstractAuth.php b/sabre/http/lib/Auth/AbstractAuth.php index 645f07ed..07f451bc 100644 --- a/sabre/http/lib/Auth/AbstractAuth.php +++ b/sabre/http/lib/Auth/AbstractAuth.php @@ -50,7 +50,7 @@ abstract class AbstractAuth } /** - * This method sends the needed HTTP header and statuscode (401) to force + * This method sends the needed HTTP header and status code (401) to force * the user to login. */ abstract public function requireLogin(); diff --git a/sabre/http/lib/Auth/Basic.php b/sabre/http/lib/Auth/Basic.php index d04b4a81..c1bad1a5 100644 --- a/sabre/http/lib/Auth/Basic.php +++ b/sabre/http/lib/Auth/Basic.php @@ -49,7 +49,7 @@ class Basic extends AbstractAuth } /** - * This method sends the needed HTTP header and statuscode (401) to force + * This method sends the needed HTTP header and status code (401) to force * the user to login. */ public function requireLogin() diff --git a/sabre/http/lib/Auth/Bearer.php b/sabre/http/lib/Auth/Bearer.php index 988bb29d..580e2394 100644 --- a/sabre/http/lib/Auth/Bearer.php +++ b/sabre/http/lib/Auth/Bearer.php @@ -42,7 +42,7 @@ class Bearer extends AbstractAuth } /** - * This method sends the needed HTTP header and statuscode (401) to force + * This method sends the needed HTTP header and status code (401) to force * authentication. */ public function requireLogin() diff --git a/sabre/http/lib/Auth/Digest.php b/sabre/http/lib/Auth/Digest.php index a093d8b7..e80e7830 100644 --- a/sabre/http/lib/Auth/Digest.php +++ b/sabre/http/lib/Auth/Digest.php @@ -133,7 +133,7 @@ class Digest extends AbstractAuth return false; } // We need to add an md5 of the entire request body to the A2 part of the hash - $body = $this->request->getBody($asString = true); + $body = $this->request->getBody(); $this->request->setBody($body); $A2 .= ':'.md5($body); } elseif (!($this->qop & self::QOP_AUTH)) { @@ -174,7 +174,7 @@ class Digest extends AbstractAuth /** * This method returns the full digest string. * - * It should be compatibile with mod_php format and other webservers. + * It should be compatible with mod_php format and other webservers. * * If the header could not be found, null will be returned * diff --git a/sabre/http/lib/Client.php b/sabre/http/lib/Client.php index 99ffcf8c..2bc7483a 100644 --- a/sabre/http/lib/Client.php +++ b/sabre/http/lib/Client.php @@ -26,7 +26,7 @@ use Sabre\Uri; * request before it's done, such as adding authentication headers. * * The afterRequest event will be emitted after the request is completed - * succesfully. + * successfully. * * If a HTTP error is returned (status code higher than 399) the error event is * triggered. It's possible using this event to retry the request, by setting @@ -53,7 +53,7 @@ class Client extends EventEmitter protected $curlSettings = []; /** - * Wether or not exceptions should be thrown when a HTTP error is returned. + * Whether exceptions should be thrown when a HTTP error is returned. * * @var bool */ diff --git a/sabre/http/lib/Message.php b/sabre/http/lib/Message.php index 6474f38d..dc57ca90 100644 --- a/sabre/http/lib/Message.php +++ b/sabre/http/lib/Message.php @@ -96,7 +96,7 @@ abstract class Message implements MessageInterface } /** - * Returns the message body, as it's internal representation. + * Returns the message body, as its internal representation. * * This could be either a string, a stream or a callback writing the body to php://output. * @@ -141,7 +141,7 @@ abstract class Message implements MessageInterface } /** - * Returns a specific HTTP header, based on it's name. + * Returns a specific HTTP header, based on its name. * * The name must be treated as case-insensitive. * If the header does not exist, this method must return null. @@ -172,7 +172,7 @@ abstract class Message implements MessageInterface * For every time the HTTP header appeared in the request or response, an * item will appear in the array. * - * If the header did not exists, this method will return an empty array. + * If the header did not exist, this method will return an empty array. * * @return string[] */ diff --git a/sabre/http/lib/MessageDecoratorTrait.php b/sabre/http/lib/MessageDecoratorTrait.php index 6f49dadf..191ba0f7 100644 --- a/sabre/http/lib/MessageDecoratorTrait.php +++ b/sabre/http/lib/MessageDecoratorTrait.php @@ -51,7 +51,7 @@ trait MessageDecoratorTrait } /** - * Returns the message body, as it's internal representation. + * Returns the message body, as its internal representation. * * This could be either a string or a stream. * @@ -91,7 +91,7 @@ trait MessageDecoratorTrait } /** - * Returns a specific HTTP header, based on it's name. + * Returns a specific HTTP header, based on its name. * * The name must be treated as case-insensitive. * If the header does not exist, this method must return null. @@ -116,7 +116,7 @@ trait MessageDecoratorTrait * For every time the HTTP header appeared in the request or response, an * item will appear in the array. * - * If the header did not exists, this method will return an empty array. + * If the header did not exist, this method will return an empty array. */ public function getHeaderAsArray(string $name): array { diff --git a/sabre/http/lib/MessageInterface.php b/sabre/http/lib/MessageInterface.php index 8504f0f5..4531654b 100644 --- a/sabre/http/lib/MessageInterface.php +++ b/sabre/http/lib/MessageInterface.php @@ -33,7 +33,7 @@ interface MessageInterface public function getBodyAsString(): string; /** - * Returns the message body, as it's internal representation. + * Returns the message body, as its internal representation. * * This could be either a string, a stream or a callback writing the body to php://output * @@ -61,7 +61,7 @@ interface MessageInterface public function hasHeader(string $name): bool; /** - * Returns a specific HTTP header, based on it's name. + * Returns a specific HTTP header, based on its name. * * The name must be treated as case-insensitive. * If the header does not exist, this method must return null. @@ -83,7 +83,7 @@ interface MessageInterface * For every time the HTTP header appeared in the request or response, an * item will appear in the array. * - * If the header did not exists, this method will return an empty array. + * If the header did not exist, this method will return an empty array. * * @return string[] */ @@ -92,7 +92,7 @@ interface MessageInterface /** * Updates a HTTP header. * - * The case-sensitity of the name value must be retained as-is. + * The case-sensitivity of the name value must be retained as-is. * * If the header already existed, it will be overwritten. * @@ -131,7 +131,7 @@ interface MessageInterface /** * Removes a HTTP header. * - * The specified header name must be treated as case-insenstive. + * The specified header name must be treated as case-insensitive. * This method should return true if the header was successfully deleted, * and false if the header did not exist. */ diff --git a/sabre/http/lib/Request.php b/sabre/http/lib/Request.php index 496629a5..b8395ff4 100644 --- a/sabre/http/lib/Request.php +++ b/sabre/http/lib/Request.php @@ -155,7 +155,7 @@ class Request extends Message implements RequestInterface * If the full path is equal to the base url, this method will return an * empty string. * - * This method will also urldecode the path, and if the url was incoded as + * This method will also urldecode the path, and if the url was encoded as * ISO-8859-1, it will convert it to UTF-8. * * If the path is outside of the base url, a LogicException will be thrown. diff --git a/sabre/http/lib/RequestDecorator.php b/sabre/http/lib/RequestDecorator.php index 0ad24925..23e790e7 100644 --- a/sabre/http/lib/RequestDecorator.php +++ b/sabre/http/lib/RequestDecorator.php @@ -104,7 +104,7 @@ class RequestDecorator implements RequestInterface * If the full path is equal to the base url, this method will return an * empty string. * - * This method will also urldecode the path, and if the url was incoded as + * This method will also urldecode the path, and if the url was encoded as * ISO-8859-1, it will convert it to UTF-8. * * If the path is outside of the base url, a LogicException will be thrown. diff --git a/sabre/http/lib/RequestInterface.php b/sabre/http/lib/RequestInterface.php index 83fa85bd..5ec7777c 100644 --- a/sabre/http/lib/RequestInterface.php +++ b/sabre/http/lib/RequestInterface.php @@ -67,7 +67,7 @@ interface RequestInterface extends MessageInterface * If the full path is equal to the base url, this method will return an * empty string. * - * This method will also urldecode the path, and if the url was incoded as + * This method will also urldecode the path, and if the url was encoded as * ISO-8859-1, it will convert it to UTF-8. * * If the path is outside of the base url, a LogicException will be thrown. diff --git a/sabre/http/lib/Response.php b/sabre/http/lib/Response.php index 2369bb41..c06c9637 100644 --- a/sabre/http/lib/Response.php +++ b/sabre/http/lib/Response.php @@ -25,7 +25,7 @@ class Response extends Message implements ResponseInterface 200 => 'OK', 201 => 'Created', 202 => 'Accepted', - 203 => 'Non-Authorative Information', + 203 => 'Non-Authoritative Information', 204 => 'No Content', 205 => 'Reset Content', 206 => 'Partial Content', @@ -137,7 +137,7 @@ class Response extends Message implements ResponseInterface /** * Sets the HTTP status code. * - * This can be either the full HTTP status code with human readable string, + * This can be either the full HTTP status code with human-readable string, * for example: "403 I can't let you do that, Dave". * * Or just the code, in which case the appropriate default message will be diff --git a/sabre/http/lib/ResponseDecorator.php b/sabre/http/lib/ResponseDecorator.php index 5f9fe7c6..30b9ec0e 100644 --- a/sabre/http/lib/ResponseDecorator.php +++ b/sabre/http/lib/ResponseDecorator.php @@ -47,7 +47,7 @@ class ResponseDecorator implements ResponseInterface /** * Sets the HTTP status code. * - * This can be either the full HTTP status code with human readable string, + * This can be either the full HTTP status code with human-readable string, * for example: "403 I can't let you do that, Dave". * * Or just the code, in which case the appropriate default message will be diff --git a/sabre/http/lib/ResponseInterface.php b/sabre/http/lib/ResponseInterface.php index 9bd93f17..fd73d25c 100644 --- a/sabre/http/lib/ResponseInterface.php +++ b/sabre/http/lib/ResponseInterface.php @@ -28,7 +28,7 @@ interface ResponseInterface extends MessageInterface /** * Sets the HTTP status code. * - * This can be either the full HTTP status code with human readable string, + * This can be either the full HTTP status code with human-readable string, * for example: "403 I can't let you do that, Dave". * * Or just the code, in which case the appropriate default message will be diff --git a/sabre/http/lib/Sapi.php b/sabre/http/lib/Sapi.php index 823d5df2..f8e8397f 100644 --- a/sabre/http/lib/Sapi.php +++ b/sabre/http/lib/Sapi.php @@ -26,7 +26,7 @@ use InvalidArgumentException; * * php://output * * You can choose to either call all these methods statically, but you can also - * instantiate this as an object to allow for polymorhpism. + * instantiate this as an object to allow for polymorphism. * * @copyright Copyright (C) fruux GmbH (https://fruux.com/) * @author Evert Pot (http://evertpot.com/) @@ -89,41 +89,33 @@ class Sapi if (null !== $contentLength) { $output = fopen('php://output', 'wb'); if (is_resource($body) && 'stream' == get_resource_type($body)) { - if (PHP_INT_SIZE > 4) { - // use the dedicated function on 64 Bit systems - // a workaround to make PHP more possible to use mmap based copy, see https://github.com/sabre-io/http/pull/119 - $left = (int) $contentLength; - // copy with 4MiB chunks - $chunk_size = 4 * 1024 * 1024; - stream_set_chunk_size($output, $chunk_size); - // If this is a partial response, flush the beginning bytes until the first position that is a multiple of the page size. - $contentRange = $response->getHeader('Content-Range'); - // Matching "Content-Range: bytes 1234-5678/7890" - if (null !== $contentRange && preg_match('/^bytes\s([0-9]+)-([0-9]+)\//i', $contentRange, $matches)) { - // 4kB should be the default page size on most architectures - $pageSize = 4096; - $offset = (int) $matches[1]; - $delta = ($offset % $pageSize) > 0 ? ($pageSize - $offset % $pageSize) : 0; - if ($delta > 0) { - $left -= stream_copy_to_stream($body, $output, min($delta, $left)); - } + // a workaround to make PHP more possible to use mmap based copy, see https://github.com/sabre-io/http/pull/119 + $left = (int) $contentLength; + // copy with 4MiB chunks + $chunk_size = 4 * 1024 * 1024; + stream_set_chunk_size($output, $chunk_size); + // If this is a partial response, flush the beginning bytes until the first position that is a multiple of the page size. + $contentRange = $response->getHeader('Content-Range'); + // Matching "Content-Range: bytes 1234-5678/7890" + if (null !== $contentRange && preg_match('/^bytes\s([0-9]+)-([0-9]+)\//i', $contentRange, $matches)) { + // 4kB should be the default page size on most architectures + $pageSize = 4096; + $offset = (int) $matches[1]; + $delta = ($offset % $pageSize) > 0 ? ($pageSize - $offset % $pageSize) : 0; + if ($delta > 0) { + $left -= stream_copy_to_stream($body, $output, min($delta, $left)); } - while ($left > 0) { - $copied = stream_copy_to_stream($body, $output, min($left, $chunk_size)); - // stream_copy_to_stream($src, $dest, $maxLength) must return the number of bytes copied or false in case of failure - // But when the $maxLength is greater than the total number of bytes remaining in the stream, - // It returns the negative number of bytes copied - // So break the loop in such cases. - if ($copied <= 0) { - break; - } - $left -= $copied; - } - } else { - // workaround for 32 Bit systems to avoid stream_copy_to_stream - while (!feof($body)) { - fwrite($output, fread($body, 8192)); + } + while ($left > 0) { + $copied = stream_copy_to_stream($body, $output, min($left, $chunk_size)); + // stream_copy_to_stream($src, $dest, $maxLength) must return the number of bytes copied or false in case of failure + // But when the $maxLength is greater than the total number of bytes remaining in the stream, + // It returns the negative number of bytes copied + // So break the loop in such cases. + if ($copied <= 0) { + break; } + $left -= $copied; } } else { fwrite($output, $body, (int) $contentLength); @@ -215,7 +207,7 @@ class Sapi // Normalizing it to be prettier $header = strtolower(substr($key, 5)); - // Transforming dashes into spaces, and uppercasing + // Transforming dashes into spaces, and upper-casing // every first letter. $header = ucwords(str_replace('_', ' ', $header)); diff --git a/sabre/http/lib/Version.php b/sabre/http/lib/Version.php index f182979c..47582f22 100644 --- a/sabre/http/lib/Version.php +++ b/sabre/http/lib/Version.php @@ -16,5 +16,5 @@ class Version /** * Full version number. */ - const VERSION = '5.1.3'; + const VERSION = '5.1.6'; } diff --git a/sabre/http/lib/functions.php b/sabre/http/lib/functions.php index 97673da4..d0477d94 100644 --- a/sabre/http/lib/functions.php +++ b/sabre/http/lib/functions.php @@ -349,7 +349,7 @@ function parseMimeType(string $str): array // The quality parameter, if it appears, also marks the end of // the parameter list. Anything after the q= counts as an // 'accept extension' and could introduce new semantics in - // content-negotation. + // content-negotiation. if ('q' !== $partName) { $parameters[$partName] = $part; } else { @@ -404,11 +404,9 @@ function decodePath(string $path): string function decodePathSegment(string $path): string { $path = rawurldecode($path); - $encoding = mb_detect_encoding($path, ['UTF-8', 'ISO-8859-1']); - switch ($encoding) { - case 'ISO-8859-1': - $path = utf8_encode($path); + if (!mb_check_encoding($path, 'UTF-8') && mb_check_encoding($path, 'ISO-8859-1')) { + $path = mb_convert_encoding($path, 'UTF-8', 'ISO-8859-1'); } return $path; diff --git a/sabre/vobject/lib/Component.php b/sabre/vobject/lib/Component.php index f33b628a..cb08c006 100644 --- a/sabre/vobject/lib/Component.php +++ b/sabre/vobject/lib/Component.php @@ -249,7 +249,7 @@ class Component extends Node $result = []; foreach ($this->children as $childGroup) { foreach ($childGroup as $child) { - if ($child instanceof Property && strtoupper($child->group) === $group) { + if ($child instanceof Property && $child->group && strtoupper($child->group) === $group) { $result[] = $child; } } diff --git a/sabre/vobject/lib/Component/VCard.php b/sabre/vobject/lib/Component/VCard.php index eac78984..90a6df72 100644 --- a/sabre/vobject/lib/Component/VCard.php +++ b/sabre/vobject/lib/Component/VCard.php @@ -291,6 +291,11 @@ class VCard extends VObject\Document $this->FN = (string) $this->ORG; $repaired = true; + // Otherwise, the NICKNAME property may work + } elseif (isset($this->NICKNAME)) { + $this->FN = (string) $this->NICKNAME; + $repaired = true; + // Otherwise, the EMAIL property may work } elseif (isset($this->EMAIL)) { $this->FN = (string) $this->EMAIL; diff --git a/sabre/vobject/lib/Parser/MimeDir.php b/sabre/vobject/lib/Parser/MimeDir.php index db0f8153..e9cc75bd 100644 --- a/sabre/vobject/lib/Parser/MimeDir.php +++ b/sabre/vobject/lib/Parser/MimeDir.php @@ -378,6 +378,9 @@ class MimeDir extends Parser $property['parameters'][$lastParam] = $value; } elseif (is_array($property['parameters'][$lastParam])) { $property['parameters'][$lastParam][] = $value; + } elseif ($property['parameters'][$lastParam] === $value) { + // When the current value of the parameter is the same as the + // new one, then we can leave the current parameter as it is. } else { $property['parameters'][$lastParam] = [ $property['parameters'][$lastParam], diff --git a/sabre/vobject/lib/Property/ICalendar/CalAddress.php b/sabre/vobject/lib/Property/ICalendar/CalAddress.php index 2dbbc6ea..c90967d7 100644 --- a/sabre/vobject/lib/Property/ICalendar/CalAddress.php +++ b/sabre/vobject/lib/Property/ICalendar/CalAddress.php @@ -53,7 +53,11 @@ class CalAddress extends Text return $input; } list($schema, $everythingElse) = explode(':', $input, 2); + $schema = strtolower($schema); + if ('mailto' === $schema) { + $everythingElse = strtolower($everythingElse); + } - return strtolower($schema).':'.$everythingElse; + return $schema.':'.$everythingElse; } } diff --git a/sabre/vobject/lib/StringUtil.php b/sabre/vobject/lib/StringUtil.php index 2333d6ab..b04539e4 100644 --- a/sabre/vobject/lib/StringUtil.php +++ b/sabre/vobject/lib/StringUtil.php @@ -40,23 +40,11 @@ class StringUtil */ public static function convertToUTF8($str) { - $encoding = mb_detect_encoding($str, ['UTF-8', 'ISO-8859-1', 'WINDOWS-1252'], true); - - switch ($encoding) { - case 'ISO-8859-1': - $newStr = utf8_encode($str); - break; - /* Unreachable code. Not sure yet how we can improve this - * situation. - case 'WINDOWS-1252' : - $newStr = iconv('cp1252', 'UTF-8', $str); - break; - */ - default: - $newStr = $str; + if (!mb_check_encoding($str, 'UTF-8') && mb_check_encoding($str, 'ISO-8859-1')) { + $str = mb_convert_encoding($str, 'UTF-8', 'ISO-8859-1'); } // Removing any control characters - return preg_replace('%(?:[\x00-\x08\x0B-\x0C\x0E-\x1F\x7F])%', '', $newStr); + return preg_replace('%(?:[\x00-\x08\x0B-\x0C\x0E-\x1F\x7F])%', '', $str); } } diff --git a/sabre/vobject/lib/Version.php b/sabre/vobject/lib/Version.php index 64938bf0..4659730f 100644 --- a/sabre/vobject/lib/Version.php +++ b/sabre/vobject/lib/Version.php @@ -14,5 +14,5 @@ class Version /** * Full version number. */ - const VERSION = '4.4.1'; + const VERSION = '4.4.3'; } |