@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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

authored by

Christopher Speck and committed by
epriestley
32d4ae8c 3bccb0dc

+90 -2
+2
src/__phutil_library_map__.php
··· 618 618 'DiffusionMercurialServeSSHWorkflow' => 'applications/diffusion/ssh/DiffusionMercurialServeSSHWorkflow.php', 619 619 'DiffusionMercurialWireClientSSHProtocolChannel' => 'applications/diffusion/ssh/DiffusionMercurialWireClientSSHProtocolChannel.php', 620 620 'DiffusionMercurialWireProtocol' => 'applications/diffusion/protocol/DiffusionMercurialWireProtocol.php', 621 + 'DiffusionMercurialWireProtocolTests' => 'applications/diffusion/protocol/__tests__/DiffusionMercurialWireProtocolTests.php', 621 622 'DiffusionMercurialWireSSHTestCase' => 'applications/diffusion/ssh/__tests__/DiffusionMercurialWireSSHTestCase.php', 622 623 'DiffusionMergedCommitsQueryConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionMergedCommitsQueryConduitAPIMethod.php', 623 624 'DiffusionMirrorDeleteController' => 'applications/diffusion/controller/DiffusionMirrorDeleteController.php', ··· 4341 4342 'DiffusionMercurialServeSSHWorkflow' => 'DiffusionMercurialSSHWorkflow', 4342 4343 'DiffusionMercurialWireClientSSHProtocolChannel' => 'PhutilProtocolChannel', 4343 4344 'DiffusionMercurialWireProtocol' => 'Phobject', 4345 + 'DiffusionMercurialWireProtocolTests' => 'PhabricatorTestCase', 4344 4346 'DiffusionMercurialWireSSHTestCase' => 'PhabricatorTestCase', 4345 4347 'DiffusionMergedCommitsQueryConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod', 4346 4348 'DiffusionMirrorDeleteController' => 'DiffusionController',
+3 -1
src/applications/diffusion/controller/DiffusionServeController.php
··· 536 536 $body = strlen($stderr)."\n".$stderr; 537 537 } else { 538 538 list($length, $body) = explode("\n", $stdout, 2); 539 + if ($cmd == 'capabilities') { 540 + $body = DiffusionMercurialWireProtocol::filterBundle2Capability($body); 541 + } 539 542 } 540 543 541 544 return id(new DiffusionMercurialResponse())->setContent($body); 542 545 } 543 - 544 546 545 547 private function getMercurialArguments() { 546 548 // Mercurial sends arguments in HTTP headers. "Why?", you might wonder,
+30
src/applications/diffusion/protocol/DiffusionMercurialWireProtocol.php
··· 99 99 return true; 100 100 } 101 101 102 + /** If the server version is running 3.4+ it will respond 103 + * with 'bundle2' capability in the format of "bundle2=(url-encoding)". 104 + * Until we maange to properly package up bundles to send back we 105 + * disallow the client from knowing we speak bundle2 by removing it 106 + * from the capabilities listing. 107 + * 108 + * The format of the capabilties string is: "a space separated list 109 + * of strings representing what commands the server supports" 110 + * @link https://www.mercurial-scm.org/wiki/CommandServer#Protocol 111 + * 112 + * @param string $capabilities - The string of capabilities to 113 + * strip the bundle2 capability from. This is expected to be 114 + * the space-separated list of strings resulting from the 115 + * querying the 'capabilties' command. 116 + * 117 + * @return string The resulting space-separated list of capabilities 118 + * which no longer contains the 'bundle2' capability. This is meant 119 + * to replace the original $body to send back to client. 120 + */ 121 + public static function filterBundle2Capability($capabilities) { 122 + $parts = explode(' ', $capabilities); 123 + foreach ($parts as $key => $part) { 124 + if (preg_match('/^bundle2=/', $part)) { 125 + unset($parts[$key]); 126 + break; 127 + } 128 + } 129 + return implode(' ', $parts); 130 + } 131 + 102 132 }
+48
src/applications/diffusion/protocol/__tests__/DiffusionMercurialWireProtocolTests.php
··· 1 + <?php 2 + 3 + final class DiffusionMercurialWireProtocolTests extends PhabricatorTestCase { 4 + 5 + public function testFilteringBundle2Capability() { 6 + // this was the result of running 'capabilities' over 7 + // `hg serve --stdio` on my systems with Mercurial 3.5.1, 2.6.2 8 + 9 + $capabilities_with_bundle2_hg_351 = 10 + 'lookup changegroupsubset branchmap pushkey '. 11 + 'known getbundle unbundlehash batch stream '. 12 + 'bundle2=HG20%0Achangegroup%3D01%2C02%0Adigests%3Dmd5%2Csha1%2Csha512'. 13 + '%0Aerror%3Dabort%2Cunsupportedcontent%2Cpushraced%2Cpushkey%0A'. 14 + 'hgtagsfnodes%0Alistkeys%0Apushkey%0Aremote-changegroup%3Dhttp%2Chttps '. 15 + 'unbundle=HG10GZ,HG10BZ,HG10UN httpheader=1024'; 16 + 17 + $capabilities_without_bundle2_hg_351 = 18 + 'lookup changegroupsubset branchmap pushkey '. 19 + 'known getbundle unbundlehash batch stream '. 20 + 'unbundle=HG10GZ,HG10BZ,HG10UN httpheader=1024'; 21 + 22 + $capabilities_hg_262 = 23 + 'lookup changegroupsubset branchmap pushkey '. 24 + 'known getbundle unbundlehash batch stream '. 25 + 'unbundle=HG10GZ,HG10BZ,HG10UN httpheader=1024 largefiles=serve'; 26 + 27 + $cases = array( 28 + array( 29 + 'name' => pht('Filter bundle2 from Mercurial 3.5.1'), 30 + 'input' => $capabilities_with_bundle2_hg_351, 31 + 'expect' => $capabilities_without_bundle2_hg_351, 32 + ), 33 + 34 + array( 35 + 'name' => pht('Filter bundle does not affect Mercurial 2.6.2'), 36 + 'input' => $capabilities_hg_262, 37 + 'expect' => $capabilities_hg_262, 38 + ), 39 + ); 40 + 41 + foreach ($cases as $case) { 42 + $actual = DiffusionMercurialWireProtocol::filterBundle2Capability( 43 + $case['input']); 44 + $this->assertEqual($case['expect'], $actual, $case['name']); 45 + } 46 + } 47 + 48 + }
+7 -1
src/applications/diffusion/ssh/DiffusionMercurialServeSSHWorkflow.php
··· 107 107 $this->didSeeWrite = true; 108 108 } 109 109 110 + $raw_message = $message['raw']; 111 + if ($command == 'capabilities') { 112 + $raw_message = DiffusionMercurialWireProtocol::filterBundle2Capability( 113 + $raw_message); 114 + } 115 + 110 116 // If we're good, return the raw message data. 111 - return $message['raw']; 117 + return $raw_message; 112 118 } 113 119 114 120 }