1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-12-20 04:20:55 +01:00

Added an intercept to Mercurial's capabilities command to remove bundle2.

Summary:
If Mercurial 3.4+ is used to host repositories in Phabricator, any clients using 3.5+ will receive an exception after the bundle is pushed up. Clients will also fail to update phases for changesets pushed up.

Before directly responding to mercurial clients with all capabilities, this change filters out the 'bundle2' capability so the client negotiates using a legacy bundle wire format instead.

Test Plan:
Server: Mercurial 3.5
Client: Mercurial 3.4

Test with both HTTP and SSH protocols:
1. Create a local commit on client
2. Push commit to server
3. Verify the client emits something like:
```
searching for changes
remote: adding changesets
remote: adding manifests
remote: adding file changes
remote: added 1 changesets with 1 changes to 1 files
```

Closes T9450

Reviewers: epriestley, #blessed_reviewers

Reviewed By: epriestley, #blessed_reviewers

Subscribers: Korvin

Maniphest Tasks: T9450

Differential Revision: https://secure.phabricator.com/D14241
This commit is contained in:
Christopher Speck 2015-10-10 07:14:48 -07:00 committed by epriestley
parent 3bccb0dcf2
commit 32d4ae8cb2
5 changed files with 90 additions and 2 deletions

View file

@ -618,6 +618,7 @@ phutil_register_library_map(array(
'DiffusionMercurialServeSSHWorkflow' => 'applications/diffusion/ssh/DiffusionMercurialServeSSHWorkflow.php',
'DiffusionMercurialWireClientSSHProtocolChannel' => 'applications/diffusion/ssh/DiffusionMercurialWireClientSSHProtocolChannel.php',
'DiffusionMercurialWireProtocol' => 'applications/diffusion/protocol/DiffusionMercurialWireProtocol.php',
'DiffusionMercurialWireProtocolTests' => 'applications/diffusion/protocol/__tests__/DiffusionMercurialWireProtocolTests.php',
'DiffusionMercurialWireSSHTestCase' => 'applications/diffusion/ssh/__tests__/DiffusionMercurialWireSSHTestCase.php',
'DiffusionMergedCommitsQueryConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionMergedCommitsQueryConduitAPIMethod.php',
'DiffusionMirrorDeleteController' => 'applications/diffusion/controller/DiffusionMirrorDeleteController.php',
@ -4341,6 +4342,7 @@ phutil_register_library_map(array(
'DiffusionMercurialServeSSHWorkflow' => 'DiffusionMercurialSSHWorkflow',
'DiffusionMercurialWireClientSSHProtocolChannel' => 'PhutilProtocolChannel',
'DiffusionMercurialWireProtocol' => 'Phobject',
'DiffusionMercurialWireProtocolTests' => 'PhabricatorTestCase',
'DiffusionMercurialWireSSHTestCase' => 'PhabricatorTestCase',
'DiffusionMergedCommitsQueryConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod',
'DiffusionMirrorDeleteController' => 'DiffusionController',

View file

@ -536,12 +536,14 @@ final class DiffusionServeController extends DiffusionController {
$body = strlen($stderr)."\n".$stderr;
} else {
list($length, $body) = explode("\n", $stdout, 2);
if ($cmd == 'capabilities') {
$body = DiffusionMercurialWireProtocol::filterBundle2Capability($body);
}
}
return id(new DiffusionMercurialResponse())->setContent($body);
}
private function getMercurialArguments() {
// Mercurial sends arguments in HTTP headers. "Why?", you might wonder,
// "Why would you do this?".

View file

@ -99,4 +99,34 @@ final class DiffusionMercurialWireProtocol extends Phobject {
return true;
}
/** If the server version is running 3.4+ it will respond
* with 'bundle2' capability in the format of "bundle2=(url-encoding)".
* Until we maange to properly package up bundles to send back we
* disallow the client from knowing we speak bundle2 by removing it
* from the capabilities listing.
*
* The format of the capabilties string is: "a space separated list
* of strings representing what commands the server supports"
* @link https://www.mercurial-scm.org/wiki/CommandServer#Protocol
*
* @param string $capabilities - The string of capabilities to
* strip the bundle2 capability from. This is expected to be
* the space-separated list of strings resulting from the
* querying the 'capabilties' command.
*
* @return string The resulting space-separated list of capabilities
* which no longer contains the 'bundle2' capability. This is meant
* to replace the original $body to send back to client.
*/
public static function filterBundle2Capability($capabilities) {
$parts = explode(' ', $capabilities);
foreach ($parts as $key => $part) {
if (preg_match('/^bundle2=/', $part)) {
unset($parts[$key]);
break;
}
}
return implode(' ', $parts);
}
}

View file

@ -0,0 +1,48 @@
<?php
final class DiffusionMercurialWireProtocolTests extends PhabricatorTestCase {
public function testFilteringBundle2Capability() {
// this was the result of running 'capabilities' over
// `hg serve --stdio` on my systems with Mercurial 3.5.1, 2.6.2
$capabilities_with_bundle2_hg_351 =
'lookup changegroupsubset branchmap pushkey '.
'known getbundle unbundlehash batch stream '.
'bundle2=HG20%0Achangegroup%3D01%2C02%0Adigests%3Dmd5%2Csha1%2Csha512'.
'%0Aerror%3Dabort%2Cunsupportedcontent%2Cpushraced%2Cpushkey%0A'.
'hgtagsfnodes%0Alistkeys%0Apushkey%0Aremote-changegroup%3Dhttp%2Chttps '.
'unbundle=HG10GZ,HG10BZ,HG10UN httpheader=1024';
$capabilities_without_bundle2_hg_351 =
'lookup changegroupsubset branchmap pushkey '.
'known getbundle unbundlehash batch stream '.
'unbundle=HG10GZ,HG10BZ,HG10UN httpheader=1024';
$capabilities_hg_262 =
'lookup changegroupsubset branchmap pushkey '.
'known getbundle unbundlehash batch stream '.
'unbundle=HG10GZ,HG10BZ,HG10UN httpheader=1024 largefiles=serve';
$cases = array(
array(
'name' => pht('Filter bundle2 from Mercurial 3.5.1'),
'input' => $capabilities_with_bundle2_hg_351,
'expect' => $capabilities_without_bundle2_hg_351,
),
array(
'name' => pht('Filter bundle does not affect Mercurial 2.6.2'),
'input' => $capabilities_hg_262,
'expect' => $capabilities_hg_262,
),
);
foreach ($cases as $case) {
$actual = DiffusionMercurialWireProtocol::filterBundle2Capability(
$case['input']);
$this->assertEqual($case['expect'], $actual, $case['name']);
}
}
}

View file

@ -107,8 +107,14 @@ final class DiffusionMercurialServeSSHWorkflow
$this->didSeeWrite = true;
}
$raw_message = $message['raw'];
if ($command == 'capabilities') {
$raw_message = DiffusionMercurialWireProtocol::filterBundle2Capability(
$raw_message);
}
// If we're good, return the raw message data.
return $message['raw'];
return $raw_message;
}
}