diff --git a/src/aphront/AphrontRequest.php b/src/aphront/AphrontRequest.php index 9d806a851d..c1dc0d1305 100644 --- a/src/aphront/AphrontRequest.php +++ b/src/aphront/AphrontRequest.php @@ -49,6 +49,54 @@ final class AphrontRequest extends Phobject { return idx($this->uriData, $key, $default); } + /** + * Read line range parameter data from the request. + * + * Applications like Paste, Diffusion, and Harbormaster use "$12-14" in the + * URI to allow users to link to particular lines. + * + * @param string URI data key to pull line range information from. + * @param int|null Maximum length of the range. + * @return null|pair Null, or beginning and end of the range. + */ + public function getURILineRange($key, $limit) { + $range = $this->getURIData($key); + if (!strlen($range)) { + return null; + } + + $range = explode('-', $range, 2); + + foreach ($range as $key => $value) { + $value = (int)$value; + if (!$value) { + // If either value is "0", discard the range. + return null; + } + $range[$key] = $value; + } + + // If the range is like "$10", treat it like "$10-10". + if (count($range) == 1) { + $range[] = head($range); + } + + // If the range is "$7-5", treat it like "$5-7". + if ($range[1] < $range[0]) { + $range = array_reverse($range); + } + + // If the user specified something like "$1-999999999" and we have a limit, + // clamp it to a more reasonable range. + if ($limit !== null) { + if ($range[1] - $range[0] > $limit) { + $range[1] = $range[0] + $limit; + } + } + + return $range; + } + public function setApplicationConfiguration( $application_configuration) { $this->applicationConfiguration = $application_configuration; diff --git a/src/applications/paste/controller/PhabricatorPasteViewController.php b/src/applications/paste/controller/PhabricatorPasteViewController.php index f29c93a162..9b4079fd46 100644 --- a/src/applications/paste/controller/PhabricatorPasteViewController.php +++ b/src/applications/paste/controller/PhabricatorPasteViewController.php @@ -2,30 +2,10 @@ final class PhabricatorPasteViewController extends PhabricatorPasteController { - private $highlightMap; - public function shouldAllowPublic() { return true; } - public function willProcessRequest(array $data) { - $raw_lines = idx($data, 'lines'); - $map = array(); - if ($raw_lines) { - $lines = explode('-', $raw_lines); - $first = idx($lines, 0, 0); - $last = idx($lines, 1); - if ($last) { - $min = min($first, $last); - $max = max($first, $last); - $map = array_fuse(range($min, $max)); - } else { - $map[$first] = $first; - } - } - $this->highlightMap = $map; - } - public function handleRequest(AphrontRequest $request) { $viewer = $request->getViewer(); $id = $request->getURIData('id'); @@ -40,11 +20,18 @@ final class PhabricatorPasteViewController extends PhabricatorPasteController { return new Aphront404Response(); } + $lines = $request->getURILineRange('lines', 1000); + if ($lines) { + $map = range($lines[0], $lines[1]); + } else { + $map = array(); + } + $header = $this->buildHeaderView($paste); $curtain = $this->buildCurtain($paste); $subheader = $this->buildSubheaderView($paste); - $source_code = $this->buildSourceCodeView($paste, $this->highlightMap); + $source_code = $this->buildSourceCodeView($paste, $map); require_celerity_resource('paste-css');