Path: blob/master/src/applications/diffusion/protocol/DiffusionMercurialWireProtocol.php
12242 views
<?php12final class DiffusionMercurialWireProtocol extends Phobject {34public static function getCommandArgs($command) {5// We need to enumerate all of the Mercurial wire commands because the6// argument encoding varies based on the command. "Why?", you might ask,7// "Why would you do this?".89$commands = array(10'batch' => array('cmds', '*'),11'between' => array('pairs'),12'branchmap' => array(),13'branches' => array('nodes'),14'capabilities' => array(),15'changegroup' => array('roots'),16'changegroupsubset' => array('bases heads'),17'debugwireargs' => array('one two *'),18'getbundle' => array('*'),19'heads' => array(),20'hello' => array(),21'known' => array('nodes', '*'),22'listkeys' => array('namespace'),23'lookup' => array('key'),24'pushkey' => array('namespace', 'key', 'old', 'new'),25'protocaps' => array('caps'),26'stream_out' => array(''),27'unbundle' => array('heads'),28);2930if (!isset($commands[$command])) {31throw new Exception(32pht(33'Unknown Mercurial command "%s"!',34$command));35}3637return $commands[$command];38}3940public static function isReadOnlyCommand($command) {41$read_only = array(42'between' => true,43'branchmap' => true,44'branches' => true,45'capabilities' => true,46'changegroup' => true,47'changegroupsubset' => true,48'debugwireargs' => true,49'getbundle' => true,50'heads' => true,51'hello' => true,52'known' => true,53'listkeys' => true,54'lookup' => true,55'protocaps' => true,56'stream_out' => true,57);5859// Notably, the write commands are "pushkey" and "unbundle". The60// "batch" command is theoretically read only, but we require explicit61// analysis of the actual commands.6263return isset($read_only[$command]);64}6566public static function isReadOnlyBatchCommand($cmds) {67if (!strlen($cmds)) {68// We expect a "batch" command to always have a "cmds" string, so err69// on the side of caution and throw if we don't get any data here. This70// either indicates a mangled command from the client or a programming71// error in our code.72throw new Exception(pht("Expected nonempty '%s' specification!", 'cmds'));73}7475// For "batch" we get a "cmds" argument like:76//77// heads ;known nodes=78//79// We need to examine the commands (here, "heads" and "known") to make sure80// they're all read-only.8182// NOTE: Mercurial has some code to escape semicolons, but it does not83// actually function for command separation. For example, these two batch84// commands will produce completely different results (the former will run85// the lookup; the latter will fail with a parser error):86//87// lookup key=a:xb;lookup key=z* 088// lookup key=a:;b;lookup key=z* 089// ^90// |91// +-- Note semicolon.92//93// So just split unconditionally.9495$cmds = explode(';', $cmds);96foreach ($cmds as $sub_cmd) {97$name = head(explode(' ', $sub_cmd, 2));98if (!self::isReadOnlyCommand($name)) {99return false;100}101}102103return true;104}105106/** If the server version is running 3.4+ it will respond107* with 'bundle2' capability in the format of "bundle2=(url-encoding)".108* Until we manage to properly package up bundles to send back we109* disallow the client from knowing we speak bundle2 by removing it110* from the capabilities listing.111*112* The format of the capabilities string is: "a space separated list113* of strings representing what commands the server supports"114* @link https://www.mercurial-scm.org/wiki/CommandServer#Protocol115*116* @param string $capabilities - The string of capabilities to117* strip the bundle2 capability from. This is expected to be118* the space-separated list of strings resulting from the119* querying the 'capabilities' command.120*121* @return string The resulting space-separated list of capabilities122* which no longer contains the 'bundle2' capability. This is meant123* to replace the original $body to send back to client.124*/125public static function filterBundle2Capability($capabilities) {126$parts = explode(' ', $capabilities);127foreach ($parts as $key => $part) {128if (preg_match('/^bundle2=/', $part)) {129unset($parts[$key]);130break;131}132}133return implode(' ', $parts);134}135136}137138139