mirror of
https://codeberg.org/Codeberg/pages-server.git
synced 2025-01-19 08:57:55 +00:00
Use proc_open() instead of exec() for runing git commands
shell_exec() could be used instead, but proc_open() has the added benefit of runing commands directly (if passed as array), without forking a shell. Also, shell_exec returns only the command output, and there is no way to capture return codes.
This commit is contained in:
parent
2266db03b7
commit
523b5f052c
1 changed files with 64 additions and 24 deletions
|
@ -148,10 +148,56 @@ $file_url = implode("/", $request_url_parts);
|
||||||
if (substr($git_root, 0, strlen($git_prefix)) !== $git_prefix)
|
if (substr($git_root, 0, strlen($git_prefix)) !== $git_prefix)
|
||||||
send_response(404, "this user/organization does not have codeberg pages");
|
send_response(404, "this user/organization does not have codeberg pages");
|
||||||
|
|
||||||
|
# Setup file descriptors
|
||||||
|
$null_fd = array(
|
||||||
|
1 => array('file','/dev/null','w'),
|
||||||
|
2 => array('file','/dev/null','w'),
|
||||||
|
);
|
||||||
|
|
||||||
|
$pipe_fd = array(
|
||||||
|
1 => array('pipe','w'),
|
||||||
|
2 => array('pipe','w'),
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Excute git commands
|
||||||
|
* @param string $cmd_array git command to be executed
|
||||||
|
* @param string &$stdout reference to $stdout variable, to receive stdout value
|
||||||
|
* @param string &$stderr reference to $stderr variable, to receive stderr value
|
||||||
|
* @param string &$retval reference to $retval variable, to receive return value
|
||||||
|
*/
|
||||||
|
function git_exec($cmd_array, &$stdout = false, &$retval = false, &$stderr = false) {
|
||||||
|
global $git_root, $pipe_fd;
|
||||||
|
$git_bin = '/usr/bin/git';
|
||||||
|
array_unshift($cmd_array, $git_bin);
|
||||||
|
|
||||||
|
$process = proc_open($cmd_array, $pipe_fd, $pipes, $git_root);
|
||||||
|
if($stdout !== false)
|
||||||
|
$stdout = stream_get_contents($pipes[1]);
|
||||||
|
if($stderr !== false)
|
||||||
|
$stderr = stream_get_contents($pipes[2]);
|
||||||
|
fclose($pipes[1]);
|
||||||
|
fclose($pipes[2]);
|
||||||
|
$tmpret = proc_close($process);
|
||||||
|
if($retval !== false)
|
||||||
|
$retval = $tmpret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether git command succeeds
|
||||||
|
* @param string $command git command to be checked
|
||||||
|
* @return bool true if return value is 0, false otherwise
|
||||||
|
*/
|
||||||
|
function git_check($cmd_array) {
|
||||||
|
global $git_root, $null_fd;
|
||||||
|
$git_bin = '/usr/bin/git';
|
||||||
|
array_unshift($cmd_array, $git_bin);
|
||||||
|
return ( proc_close(proc_open($cmd_array,$null_fd,$pipes,$git_root)) === 0 );
|
||||||
|
}
|
||||||
|
|
||||||
# If this is a folder, we explicitly redirect to folder URL, otherwise browsers will construct invalid relative links:
|
# If this is a folder, we explicitly redirect to folder URL, otherwise browsers will construct invalid relative links:
|
||||||
$command = "sh -c \"cd '$git_root' && /usr/bin/git ls-tree 'HEAD:$file_url' > /dev/null\"";
|
$command = ["ls-tree", "HEAD:$file_url"];
|
||||||
exec($command, $output, $retval);
|
if (git_check($command)) {
|
||||||
if ($retval === 0) {
|
|
||||||
if (substr($request_url, -1) !== "/") {
|
if (substr($request_url, -1) !== "/") {
|
||||||
$h = "Location: " . $request_url . "/";
|
$h = "Location: " . $request_url . "/";
|
||||||
if ($_SERVER['QUERY_STRING'] !== "")
|
if ($_SERVER['QUERY_STRING'] !== "")
|
||||||
|
@ -196,10 +242,10 @@ header("Content-Type: " . $mime_type);
|
||||||
|
|
||||||
#header("Cache-Control: public, max-age=10, immutable");
|
#header("Cache-Control: public, max-age=10, immutable");
|
||||||
|
|
||||||
$command = "sh -c \"cd '$git_root' && /usr/bin/git log --format='%H' -1\"";
|
$command = ["log", "--format=%H", "-1"];
|
||||||
exec($command, $output, $retval);
|
git_exec($command, $output, $retval);
|
||||||
if ($retval == 0 && count($output)) {
|
if ($retval === 0 && !empty($output)) {
|
||||||
$revision=$output[0];
|
$revision=trim($output);
|
||||||
header('ETag: "' . $revision . '"');
|
header('ETag: "' . $revision . '"');
|
||||||
if (isset($_SERVER["HTTP_IF_NONE_MATCH"])) {
|
if (isset($_SERVER["HTTP_IF_NONE_MATCH"])) {
|
||||||
$req_revision = str_replace('"', '', str_replace('W/"', '', $_SERVER["HTTP_IF_NONE_MATCH"]));
|
$req_revision = str_replace('"', '', str_replace('W/"', '', $_SERVER["HTTP_IF_NONE_MATCH"]));
|
||||||
|
@ -208,26 +254,20 @@ if ($retval == 0 && count($output)) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
$command = ["show", "HEAD:$file_url"];
|
||||||
## We are executing command twice (first for send_response-checking, then for actual raw output to stream),
|
git_exec($command, $output, $retval);
|
||||||
## which seems wasteful, but it seems exec+echo cannot do raw binary output? Is this true?
|
if ($retval !== 0) {
|
||||||
$command = "sh -c \"cd '$git_root' && /usr/bin/git show 'HEAD:$file_url'\"";
|
|
||||||
exec($command . " > /dev/null", $output, $retval);
|
|
||||||
if ($retval != 0) {
|
|
||||||
# Try adding '.html' suffix, if this does not work either, report error
|
# Try adding '.html' suffix, if this does not work either, report error
|
||||||
$command = "sh -c \"cd '$git_root' && /usr/bin/git show 'HEAD:$file_url.html'\"";
|
$command = ["show", "HEAD:$file_url.html"];
|
||||||
exec($command . " > /dev/null", $output, $retval);
|
git_exec($command, $output, $retval);
|
||||||
header("Content-Type: text/html");
|
header("Content-Type: text/html");
|
||||||
if ($retval != 0) {
|
if ($retval !== 0) {
|
||||||
# Render user-provided 404.html if exists, generic 404 message if not:
|
# Render user-provided 404.html if exists, generic 404 message if not:
|
||||||
http_response_code(404);
|
http_response_code(404);
|
||||||
$command = "sh -c \"cd '$git_root' && /usr/bin/git show 'HEAD:404.html'\"";
|
$command = ["show", "HEAD:404.html"];
|
||||||
exec($command . " > /dev/null", $output, $retval);
|
git_exec($command, $output, $retval);
|
||||||
if ($retval != 0)
|
if ($retval !== 0)
|
||||||
send_response(404 , "no such file in repo: '" . htmlspecialchars($file_url) . "'");
|
send_response(404, "no such file in repo: '" . htmlspecialchars($file_url) . "'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
echo $output;
|
||||||
## If we could directly exec+echo raw output from above, we wouldn't need to execute command twice:
|
|
||||||
passthru($command);
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue