bug #37868 [Lock] MongoDbStore handle duplicate querystring keys in mongodb uri when stripping (kralos)

This PR was squashed before being merged into the 5.1 branch.

Discussion
----------

[Lock] MongoDbStore handle duplicate querystring keys in mongodb uri when stripping

| Q             | A
| ------------- | ---
| Branch?       | 5.1
| Bug fix?      | yes
| New feature?  | no
| Deprecations? | no
| Tickets       | Fix #37864
| License       | MIT
| Doc PR        |

Allow duplicate querystring keys when stripping `collection`. `readPreferenceTags` is currently allowed to be specified twice so re-assembling the querystring with `http_build_query` will also strip duplicated `readPreferenceTags`. Use `preg_match` instead.

Commits
-------

c1ea9ae476 [Lock] MongoDbStore handle duplicate querystring keys in mongodb uri when stripping
This commit is contained in:
Fabien Potencier 2020-08-19 12:50:41 +02:00
commit c426abed85
2 changed files with 17 additions and 19 deletions

View File

@ -141,30 +141,21 @@ class MongoDbStore implements BlockingStoreInterface
if (false === $parsedUrl = parse_url($uri)) {
throw new InvalidArgumentException(sprintf('The given MongoDB Connection URI "%s" is invalid.', $uri));
}
$query = [];
if (isset($parsedUrl['query'])) {
parse_str($parsedUrl['query'], $query);
}
if (isset($query['collection'])) {
$this->options['collection'] = $query['collection'];
$queryStringPos = strrpos($uri, $parsedUrl['query']);
unset($query['collection']);
$prefix = substr($uri, 0, $queryStringPos);
$newQuery = http_build_query($query, '', '&', PHP_QUERY_RFC3986);
if (empty($newQuery)) {
$prefix = rtrim($prefix, '?');
}
$suffix = substr($uri, $queryStringPos + \strlen($parsedUrl['query']));
$uri = $prefix.$newQuery.$suffix;
}
$pathDb = ltrim($parsedUrl['path'] ?? '', '/') ?: null;
if (null !== $pathDb) {
$this->options['database'] = $pathDb;
}
$matches = [];
if (preg_match('/^(.*[\?&])collection=([^&#]*)&?(([^#]*).*)$/', $uri, $matches)) {
$prefix = $matches[1];
$this->options['collection'] = $matches[2];
if (empty($matches[4])) {
$prefix = substr($prefix, 0, -1);
}
$uri = $prefix.$matches[3];
}
return $uri;
}

View File

@ -187,5 +187,12 @@ class MongoDbStoreTest extends AbstractStoreTest
yield ['mongodb://localhost/?replicaSet=repl', ['database' => 'test', 'collection' => 'lock'], 'mongodb://localhost/?replicaSet=repl'];
yield ['mongodb://localhost/test?collection=lock&replicaSet=repl', [], 'mongodb://localhost/test?replicaSet=repl'];
yield ['mongodb://localhost/test?replicaSet=repl', ['collection' => 'lock'], 'mongodb://localhost/test?replicaSet=repl'];
yield ['mongodb://localhost/test?readPreferenceTags=dc:foo&collection=lock&readPreferenceTags=dc:bar', [], 'mongodb://localhost/test?readPreferenceTags=dc:foo&readPreferenceTags=dc:bar'];
yield ['mongodb://localhost?foo_collection=x&collection=lock&bar_collection=x#collection=x', ['database' => 'test'], 'mongodb://localhost?foo_collection=x&bar_collection=x#collection=x'];
yield ['mongodb://localhost?collection=lock&foo_collection=x&bar_collection=x#collection=x', ['database' => 'test'], 'mongodb://localhost?foo_collection=x&bar_collection=x#collection=x'];
yield ['mongodb://localhost?foo_collection=x&bar_collection=x&collection=lock#collection=x', ['database' => 'test'], 'mongodb://localhost?foo_collection=x&bar_collection=x#collection=x'];
yield ['mongodb://user:?collection=a@localhost?collection=lock', ['database' => 'test'], 'mongodb://user:?collection=a@localhost'];
yield ['mongodb://user:&collection=a@localhost/?collection=lock', ['database' => 'test'], 'mongodb://user:&collection=a@localhost/'];
}
}