public function willWriteMessageCallback(PhabricatorSSHPassthruCommand $command, $message) { $command = $message['command']; // Check if this is a readonly command. $is_readonly = false; if ($command == 'batch') { $cmds = idx($message['arguments'], 'cmds'); if (DiffusionMercurialWireProtocol::isReadOnlyBatchCommand($cmds)) { $is_readonly = true; } } else { if (DiffusionMercurialWireProtocol::isReadOnlyCommand($command)) { $is_readonly = true; } } if (!$is_readonly) { $this->requireWriteAccess(); $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 $raw_message; }
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']); } }
private function serveMercurialRequest(PhabricatorRepository $repository, PhabricatorUser $viewer) { $request = $this->getRequest(); $bin = Filesystem::resolveBinary('hg'); if (!$bin) { throw new Exception(pht('Unable to find `%s` in %s!', 'hg', '$PATH')); } $env = $this->getCommonEnvironment($viewer); $input = PhabricatorStartup::getRawInput(); $cmd = $request->getStr('cmd'); $args = $this->getMercurialArguments(); $args = $this->formatMercurialArguments($cmd, $args); if (strlen($input)) { $input = strlen($input) . "\n" . $input . "0\n"; } $command = csprintf('%s serve --stdio', $bin); $command = PhabricatorDaemon::sudoCommandAsDaemonUser($command); list($err, $stdout, $stderr) = id(new ExecFuture('%C', $command))->setEnv($env, true)->setCWD($repository->getLocalPath())->write("{$cmd}\n{$args}{$input}")->resolve(); if ($err) { return new PhabricatorVCSResponse(500, pht('Error %d: %s', $err, $stderr)); } if ($cmd == 'getbundle' || $cmd == 'changegroup' || $cmd == 'changegroupsubset') { // We're not completely sure that "changegroup" and "changegroupsubset" // actually work, they're for very old Mercurial. $body = gzcompress($stdout); } else { if ($cmd == 'unbundle') { // This includes diagnostic information and anything echoed by commit // hooks. We ignore `stdout` since it just has protocol garbage, and // substitute `stderr`. $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); }