mirror of
https://github.com/litespeedtech/openlitespeed.git
synced 2026-06-19 07:37:10 +00:00
Check in 1.9.0.1
This commit is contained in:
+1
-1
@@ -1,7 +1,7 @@
|
||||
cmake_minimum_required(VERSION 3.0)
|
||||
set( CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
|
||||
Project(openlitespeed VERSION 1.8.5)
|
||||
Project(openlitespeed VERSION 1.9.0)
|
||||
INCLUDE( ${PROJECT_SOURCE_DIR}/CMakeModules/common.cmake)
|
||||
INCLUDE(GNUInstallDirs)
|
||||
|
||||
|
||||
@@ -100,7 +100,7 @@ usage()
|
||||
echo " This should always be done for a first time build,"
|
||||
echo " but requires manually entering the root password"
|
||||
echo " -d : Debug build"
|
||||
echo " -p ON|OFF : Whether you want pagespeed compiled or not. Defaults ON only for x64 Linux"
|
||||
echo " -p ON|OFF : Whether you want pagespeed compiled or not. Defaults to OFF "
|
||||
echo " -o ON|OFF : Whether you want mod_security compiled or not. Defaults ON for everywhere but Mac"
|
||||
echo " -l ON|OFF : Whether you want lua compiled or not. Defaults ON only for x64 Linux"
|
||||
exit 1
|
||||
@@ -123,7 +123,6 @@ getOptions()
|
||||
MOD_LUA="OFF"
|
||||
if [ "${ISLINUX}" = "yes" ] && [ "${ARCH}" = "x86_64" ]; then
|
||||
if [ ! "${OSTYPE}" = "ALPINE" ] ; then
|
||||
MOD_PAGESPEED="ON"
|
||||
MOD_LUA="ON"
|
||||
ALPINE="ON"
|
||||
fi
|
||||
|
||||
@@ -153,17 +153,11 @@ class CAuthorizer
|
||||
}
|
||||
|
||||
if (isset($parts['scheme'])) {
|
||||
$expectedScheme = $this->isHttpsRequest() ? 'https' : 'http';
|
||||
if (strtolower($parts['scheme']) !== $expectedScheme) {
|
||||
if (strtolower($parts['scheme']) !== 'https') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$requestPort = $this->getRequestPort();
|
||||
if ($requestPort !== null && isset($parts['port']) && (int) $parts['port'] !== $requestPort) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -78,6 +78,18 @@ class ConfigActionContext
|
||||
}
|
||||
}
|
||||
|
||||
public function SetViewRoute($view, $viewName, $pid, $tid = null, $ref = null)
|
||||
{
|
||||
if ($this->_routeState != null && method_exists($this->_routeState, 'SetViewRoute')) {
|
||||
$this->_routeState->SetViewRoute($view, $viewName, $pid, $tid, $ref);
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_object($this->_mutationDisplay) && method_exists($this->_mutationDisplay, 'SetViewRoute')) {
|
||||
$this->_mutationDisplay->SetViewRoute($view, $viewName, $pid, $tid, $ref);
|
||||
}
|
||||
}
|
||||
|
||||
public function AddTopMsg($message)
|
||||
{
|
||||
if (is_object($this->_mutationDisplay) && method_exists($this->_mutationDisplay, 'AddTopMsg')) {
|
||||
|
||||
@@ -70,6 +70,11 @@ class ConfigActionRequest
|
||||
$this->_context->SetViewName($viewName);
|
||||
}
|
||||
|
||||
public function SetViewRoute($view, $viewName, $pid, $tid = null, $ref = null)
|
||||
{
|
||||
$this->_context->SetViewRoute($view, $viewName, $pid, $tid, $ref);
|
||||
}
|
||||
|
||||
public function AddTopMsg($message)
|
||||
{
|
||||
$this->_context->AddTopMsg($message);
|
||||
|
||||
+107
-1
@@ -26,6 +26,7 @@ class ConfigActionService
|
||||
$validationResult = self::validatePost($request);
|
||||
$displayData = $validationResult->GetExtracted();
|
||||
$hasDisplayData = true;
|
||||
self::appendValidationMessages($request, $validationResult);
|
||||
|
||||
if ($validationResult->HasErr()) {
|
||||
self::setAct($request, 'S');
|
||||
@@ -33,13 +34,22 @@ class ConfigActionService
|
||||
break;
|
||||
}
|
||||
|
||||
if ($validationResult->ShouldStopSave()) {
|
||||
self::setAct($request, 'S');
|
||||
break;
|
||||
}
|
||||
|
||||
$isNewEntry = self::isNewEntry($request);
|
||||
$changeDiff = self::buildChangeDiff($confdata, $displayData, $request);
|
||||
$markChanged = self::shouldMarkChangedAfterSave($request, $displayData);
|
||||
$forceReLogin = self::shouldForceReLoginAfterSave($request, $displayData);
|
||||
$confdata->SavePost($displayData, $request->GetMutationDisplay());
|
||||
$hasDisplayData = false;
|
||||
$trimRoute = true;
|
||||
if ($isNewEntry && self::routeToSavedEntryConfig($request, $displayData)) {
|
||||
$reloadConfig = true;
|
||||
} else {
|
||||
$trimRoute = true;
|
||||
}
|
||||
if ($isNewEntry) {
|
||||
OpsAuditLogger::configAdd(
|
||||
self::resolveAuditTarget($request),
|
||||
@@ -123,6 +133,17 @@ class ConfigActionService
|
||||
return new ConfigActionResult($displayData, $hasDisplayData, $reloadConfig, $markChanged, $forceReLogin);
|
||||
}
|
||||
|
||||
private static function appendValidationMessages($request, $validationResult)
|
||||
{
|
||||
if ($validationResult == null || !method_exists($validationResult, 'GetMessages')) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($validationResult->GetMessages() as $message) {
|
||||
self::appendTopMessage($request, $message);
|
||||
}
|
||||
}
|
||||
|
||||
private static function validatePost($request)
|
||||
{
|
||||
$result = $request->ValidatePost();
|
||||
@@ -386,6 +407,91 @@ class ConfigActionService
|
||||
return $rs->GetLastRef() === '~';
|
||||
}
|
||||
|
||||
private static function routeToSavedEntryConfig($request, $extractData)
|
||||
{
|
||||
if (!($extractData instanceof CNode)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$entryName = self::resolveSavedEntryName($extractData);
|
||||
if ($entryName === '') {
|
||||
return false;
|
||||
}
|
||||
|
||||
$target = self::resolveSavedEntryRoute($request, self::resolveMutationTableId($request));
|
||||
if ($target === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$request->SetViewRoute($target['view'], $entryName, $target['pid'], null, $entryName);
|
||||
return true;
|
||||
}
|
||||
|
||||
private static function resolveSavedEntryName($extractData)
|
||||
{
|
||||
$entryName = trim((string) $extractData->GetChildVal('name'));
|
||||
if ($entryName !== '') {
|
||||
return $entryName;
|
||||
}
|
||||
|
||||
$holderValue = trim((string) $extractData->Get(CNode::FLD_VAL));
|
||||
return $holderValue;
|
||||
}
|
||||
|
||||
private static function resolveSavedEntryRoute($request, $tid)
|
||||
{
|
||||
switch ($tid) {
|
||||
case 'V_TOPD':
|
||||
case 'V_BASE':
|
||||
return ['view' => 'vh_', 'pid' => 'base'];
|
||||
|
||||
case 'T_TOPD':
|
||||
return ['view' => 'tp_', 'pid' => 'mbr'];
|
||||
|
||||
case 'ADM_L_GENERAL':
|
||||
return ['view' => 'al_', 'pid' => 'lg'];
|
||||
|
||||
case 'L_GENERAL':
|
||||
case 'L_GENERAL_NEW':
|
||||
return [
|
||||
'view' => (self::resolveMutationView($request) === 'al') ? 'al_' : 'sl_',
|
||||
'pid' => 'lg',
|
||||
];
|
||||
|
||||
case 'LT_GENERAL_NEW':
|
||||
return ['view' => 'sl4_', 'pid' => 'ltg'];
|
||||
|
||||
case 'LB_GENERAL_NEW':
|
||||
return ['view' => 'lb_', 'pid' => 'lbgeneral'];
|
||||
|
||||
case 'LB4_GENERAL_NEW':
|
||||
return ['view' => 'lb4_', 'pid' => 'lb4general'];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static function resolveMutationView($request)
|
||||
{
|
||||
$disp = $request->GetMutationDisplay();
|
||||
if ($disp === null || !is_object($disp)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (method_exists($disp, 'GetRouteState')) {
|
||||
$rs = $disp->GetRouteState();
|
||||
if ($rs !== null && method_exists($rs, 'GetView')) {
|
||||
return (string) $rs->GetView();
|
||||
}
|
||||
}
|
||||
|
||||
if (method_exists($disp, 'GetView')) {
|
||||
return (string) $disp->GetView();
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
private static function shouldMarkChangedAfterSave($request, $extractData)
|
||||
{
|
||||
$tid = self::resolveMutationTableId($request);
|
||||
|
||||
@@ -24,6 +24,7 @@ class CValidation
|
||||
|
||||
protected $_request;
|
||||
protected $_go_flag;
|
||||
protected $_messages = [];
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
@@ -34,6 +35,7 @@ class CValidation
|
||||
{
|
||||
$this->_request = $request;
|
||||
$this->_go_flag = 1;
|
||||
$this->_messages = [];
|
||||
|
||||
$tbl = $request->GetTable();
|
||||
$tid = $request->GetTid();
|
||||
@@ -63,10 +65,7 @@ class CValidation
|
||||
if ($needCheck) {
|
||||
$this->validateAttr($attr, $dlayer);
|
||||
}
|
||||
if (($tid == 'V_TOPD' || $tid == 'V_BASE') && $attr->_type == 'vhname') {
|
||||
$updatedViewName = ($dlayer == null) ? null : $dlayer->Get(CNode::FLD_VAL);
|
||||
$hasUpdatedViewName = true;
|
||||
}
|
||||
$this->updateValidationRouteContext($tid, $attr, $dlayer, $updatedViewName, $hasUpdatedViewName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,12 +74,76 @@ class CValidation
|
||||
|
||||
// if 0 , make it always point to curr page
|
||||
|
||||
if ($this->_go_flag <= 0) {
|
||||
if ($this->_go_flag < 0) {
|
||||
$extracted->SetErr('Input error detected. Please resolve the error(s). ');
|
||||
}
|
||||
|
||||
$status = $this->_go_flag;
|
||||
$messages = $this->_messages;
|
||||
$this->_request = null;
|
||||
return new ConfigValidationResult($extracted, $updatedViewName, $hasUpdatedViewName);
|
||||
$this->_messages = [];
|
||||
return new ConfigValidationResult($extracted, $updatedViewName, $hasUpdatedViewName, $status, $messages);
|
||||
}
|
||||
|
||||
protected function addValidationMessage($type, $text, $title = '')
|
||||
{
|
||||
$this->_messages[] = [
|
||||
'type' => $type,
|
||||
'title' => $title,
|
||||
'text' => $text,
|
||||
];
|
||||
}
|
||||
|
||||
protected function updateValidationRouteContext($tid, $attr, $dlayer, &$updatedViewName, &$hasUpdatedViewName)
|
||||
{
|
||||
if ($dlayer == null || is_array($dlayer)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->_request == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$value = $dlayer->Get(CNode::FLD_VAL);
|
||||
if (($tid == 'V_TOPD' || $tid == 'V_BASE') && $attr->_type == 'vhname') {
|
||||
$updatedViewName = $value;
|
||||
$hasUpdatedViewName = true;
|
||||
if (method_exists($this->_request, 'SetViewName')) {
|
||||
$this->_request->SetViewName($value);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (in_array($tid, [
|
||||
'T_TOPD',
|
||||
'L_GENERAL',
|
||||
'L_GENERAL_NEW',
|
||||
'LT_GENERAL',
|
||||
'LT_GENERAL_NEW',
|
||||
'ADM_L_GENERAL',
|
||||
'LB_GENERAL',
|
||||
'LB_GENERAL_NEW',
|
||||
'LB4_GENERAL',
|
||||
'LB4_GENERAL_NEW',
|
||||
], true)
|
||||
&& $attr->GetKey() == 'name'
|
||||
&& ($attr->_type == 'name' || $attr->_type == 'vhname')) {
|
||||
$updatedViewName = $value;
|
||||
$hasUpdatedViewName = true;
|
||||
if (method_exists($this->_request, 'SetViewName')) {
|
||||
$this->_request->SetViewName($value);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (($tid == 'V_TOPD' || $tid == 'V_BASE') && $attr->GetKey() == 'vhRoot' && $value !== null && $value !== ''
|
||||
&& method_exists($this->_request, 'SetVHRoot')) {
|
||||
$this->_request->SetVHRoot(PathTool::GetAbsFile(
|
||||
$value,
|
||||
'SR',
|
||||
$this->_request->GetViewName()
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
protected function setValid($res)
|
||||
@@ -388,7 +451,8 @@ class CValidation
|
||||
if (($type == 'path' && !is_dir($absname)) || ($type == 'file' && !is_file($absname))) {
|
||||
$err = $type . ' ' . htmlspecialchars($absname) . ' does not exist.';
|
||||
if ($this->allow_create($attr, $absname)) {
|
||||
$err .= ' <button type="submit" name="file_create" value="' . htmlspecialchars($attr->GetKey(), ENT_QUOTES) . '" class="lst-btn lst-btn--secondary lst-btn--xs">CLICK TO CREATE</button>';
|
||||
$err .= ' <input type="hidden" name="a" value="s">';
|
||||
$err .= ' <button type="submit" name="file_create" value="' . htmlspecialchars($attr->GetKey(), ENT_QUOTES) . '" class="lst-btn lst-btn--danger lst-btn--xs">CLICK TO CREATE</button>';
|
||||
} else {
|
||||
$err .= ' Please create manually.';
|
||||
}
|
||||
@@ -540,9 +604,15 @@ class CValidation
|
||||
|
||||
if ($res == -1 && isset($_POST['file_create']) && $_POST['file_create'] == $attr->GetKey() && $this->allow_create($attr, $path)) {
|
||||
if (PathTool::createFile($path, $err, $attr->GetKey())) {
|
||||
$err = "$path has been created successfully.";
|
||||
$this->addValidationMessage(
|
||||
'success',
|
||||
htmlspecialchars($path, ENT_QUOTES) . ' has been created successfully. Click Save to apply this configuration.'
|
||||
);
|
||||
$err = null;
|
||||
return 0;
|
||||
}
|
||||
$res = 0; // make it always point to curr page
|
||||
|
||||
$res = -1;
|
||||
}
|
||||
|
||||
return $res;
|
||||
@@ -639,6 +709,9 @@ class CValidation
|
||||
$err = 'Fail to find $VH_ROOT';
|
||||
return -1;
|
||||
}
|
||||
if (substr($vhroot, -1, 1) !== '/') {
|
||||
$vhroot .= '/';
|
||||
}
|
||||
$path = $vhroot . substr($path, 9);
|
||||
} elseif ($s == '$') {
|
||||
$err = 'only accept absolute path or path relative to $SERVER_ROOT or $VH_ROOT: ' . $path;
|
||||
|
||||
+10
@@ -111,6 +111,11 @@ class ConfigValidationRequest
|
||||
return $this->_viewName;
|
||||
}
|
||||
|
||||
public function SetViewName($viewName)
|
||||
{
|
||||
$this->_viewName = $viewName;
|
||||
}
|
||||
|
||||
public function GetCurrentRef()
|
||||
{
|
||||
return $this->_currentRef;
|
||||
@@ -131,6 +136,11 @@ class ConfigValidationRequest
|
||||
return $this->_vhRoot;
|
||||
}
|
||||
|
||||
public function SetVHRoot($vhRoot)
|
||||
{
|
||||
$this->_vhRoot = $vhRoot;
|
||||
}
|
||||
|
||||
public function GetTableLocation()
|
||||
{
|
||||
return $this->_tableLocation;
|
||||
|
||||
+20
-2
@@ -4,15 +4,23 @@ namespace LSWebAdmin\Config\Validation;
|
||||
|
||||
class ConfigValidationResult
|
||||
{
|
||||
const STATUS_ERROR = -1;
|
||||
const STATUS_STOP = 0;
|
||||
const STATUS_OK = 1;
|
||||
|
||||
private $_extracted;
|
||||
private $_viewName;
|
||||
private $_hasViewNameUpdate;
|
||||
private $_status;
|
||||
private $_messages;
|
||||
|
||||
public function __construct($extracted, $viewName = null, $hasViewNameUpdate = false)
|
||||
public function __construct($extracted, $viewName = null, $hasViewNameUpdate = false, $status = self::STATUS_OK, $messages = [])
|
||||
{
|
||||
$this->_extracted = $extracted;
|
||||
$this->_viewName = $viewName;
|
||||
$this->_hasViewNameUpdate = $hasViewNameUpdate;
|
||||
$this->_status = (int) $status;
|
||||
$this->_messages = is_array($messages) ? $messages : [];
|
||||
}
|
||||
|
||||
public function GetExtracted()
|
||||
@@ -22,7 +30,17 @@ class ConfigValidationResult
|
||||
|
||||
public function HasErr()
|
||||
{
|
||||
return ($this->_extracted != null && $this->_extracted->HasErr());
|
||||
return ($this->_status < self::STATUS_STOP || ($this->_extracted != null && $this->_extracted->HasErr()));
|
||||
}
|
||||
|
||||
public function ShouldStopSave()
|
||||
{
|
||||
return ($this->_status == self::STATUS_STOP);
|
||||
}
|
||||
|
||||
public function GetMessages()
|
||||
{
|
||||
return $this->_messages;
|
||||
}
|
||||
|
||||
public function GetViewName()
|
||||
|
||||
@@ -12,14 +12,15 @@ class AdminCommandClient
|
||||
|
||||
private $_lastError = '';
|
||||
|
||||
public function sendCommand($cmd)
|
||||
public function sendCommand($cmd, $timeout = self::COMMAND_IO_TIMEOUT_SEC)
|
||||
{
|
||||
$sock = $this->openAuthenticatedSocket($cmd);
|
||||
if (!$sock) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$this->setSocketTimeout($sock, SO_RCVTIMEO, self::COMMAND_IO_TIMEOUT_SEC, 'cmd ' . trim($cmd) . ' failed to set receive timeout on admin socket')) {
|
||||
$readTimeout = ((int) $timeout > 0) ? (int) $timeout : self::COMMAND_IO_TIMEOUT_SEC;
|
||||
if (!$this->setSocketTimeout($sock, SO_RCVTIMEO, $readTimeout, 'cmd ' . trim($cmd) . ' failed to set receive timeout on admin socket')) {
|
||||
socket_close($sock);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -426,7 +426,6 @@ class DTblDefBase
|
||||
'ext_retryTimeout' => self::NewIntAttr('retryTimeout', DMsg::ALbl('l_retrytimeout'), false, 0),
|
||||
'ext_respBuffer' => self::NewSelAttr('respBuffer', DMsg::ALbl('l_respbuffer'), ['0' => DMsg::ALbl('o_no'), '1' => DMsg::ALbl('o_yes'), '2' => DMsg::ALbl('o_nofornph')], false),
|
||||
'ext_persistConn' => self::NewBoolAttr('persistConn', DMsg::ALbl('l_persistconn')),
|
||||
'ext_autoStart' => self::NewSelAttr('autoStart', DMsg::ALbl('l_autostart'), ['2' => DMsg::ALbl('o_thrucgidaemon'), '0' => DMsg::ALbl('o_no')], false),
|
||||
'ext_path' => self::NewPathAttr('path', DMsg::ALbl('l_command'), 'file1', 3, 'x', true, 'extAppPath'),
|
||||
'ext_backlog' => self::NewIntAttr('backlog', DMsg::ALbl('l_backlog'), true, 1, 100),
|
||||
'ext_instances' => self::NewIntAttr('instances', DMsg::ALbl('l_instances'), true, 0, 1000),
|
||||
@@ -1874,12 +1873,6 @@ class DTblDefBase
|
||||
$rules,
|
||||
];
|
||||
}
|
||||
if ($type == 'charset') {
|
||||
return [
|
||||
self::NewTextAttr('addDefaultCharset', DMsg::ALbl('l_adddefaultcharset'), 'charset'),
|
||||
$this->_attrs['enableIpGeo']
|
||||
];
|
||||
}
|
||||
if ($type == 'uri') {
|
||||
return [
|
||||
$this->_attrs['ctx_uri'],
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
namespace LSWebAdmin\Product\Base;
|
||||
|
||||
use LSWebAdmin\I18n\DMsg;
|
||||
|
||||
abstract class ProductBase
|
||||
{
|
||||
protected static $instances = [];
|
||||
@@ -79,35 +77,7 @@ abstract class ProductBase
|
||||
|
||||
protected function detectAvailableVersion()
|
||||
{
|
||||
$releasefile = $this->getServerRootPath('autoupdate/release');
|
||||
if ($releasefile === '') {
|
||||
return '';
|
||||
}
|
||||
|
||||
$releasefilecb = $releasefile . 'cb';
|
||||
$newver = '';
|
||||
$rel0 = '';
|
||||
$rel1 = '';
|
||||
|
||||
if (is_file($releasefilecb)) {
|
||||
$rel = trim(file_get_contents($releasefilecb));
|
||||
$rel0 = $this->extractReleaseVersion($rel);
|
||||
|
||||
if ($this->version != $rel0) {
|
||||
$newver = $rel . ' (' . DMsg::UIStr('note_curbranch') . ') ';
|
||||
}
|
||||
}
|
||||
|
||||
if (is_file($releasefile)) {
|
||||
$rel = trim(file_get_contents($releasefile));
|
||||
$rel1 = $this->extractReleaseVersion($rel);
|
||||
|
||||
if ($this->version != $rel1 && $rel0 != $rel1) {
|
||||
$newver .= $rel;
|
||||
}
|
||||
}
|
||||
|
||||
return $newver;
|
||||
return '';
|
||||
}
|
||||
|
||||
protected function extractReleaseVersion($release)
|
||||
@@ -120,6 +90,22 @@ abstract class ProductBase
|
||||
return $release;
|
||||
}
|
||||
|
||||
protected function readReleaseFile($relativePath)
|
||||
{
|
||||
$releaseFile = $this->getServerRootPath($relativePath);
|
||||
if ($releaseFile === '' || !is_file($releaseFile)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return trim((string) file_get_contents($releaseFile));
|
||||
}
|
||||
|
||||
protected function isNewRelease($release)
|
||||
{
|
||||
$version = $this->extractReleaseVersion($release);
|
||||
return ($release !== '' && $version !== '' && $this->version != $version);
|
||||
}
|
||||
|
||||
public static function extractBuildDisplay($versionOutput)
|
||||
{
|
||||
if (!is_string($versionOutput) || $versionOutput === '') {
|
||||
|
||||
@@ -1,173 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace LSWebAdmin\Product\Base;
|
||||
|
||||
use LSWebAdmin\Auth\CAuthorizer;
|
||||
use LSWebAdmin\Controller\AdminCommandClient;
|
||||
use LSWebAdmin\I18n\DMsg;
|
||||
use LSWebAdmin\Product\Current\Service;
|
||||
|
||||
abstract class VersionManagerBase
|
||||
{
|
||||
const ACTION_UPGRADE = 'upgrade';
|
||||
const ACTION_SWITCH = 'switchTo';
|
||||
const ACTION_REMOVE = 'remove';
|
||||
|
||||
abstract protected function getProduct();
|
||||
|
||||
abstract protected function downloadReleaseArchive($version);
|
||||
|
||||
protected function buildUpgradeCommand($version)
|
||||
{
|
||||
return 'upgrade:' . $version;
|
||||
}
|
||||
|
||||
public function getViewData()
|
||||
{
|
||||
$product = $this->getProduct();
|
||||
|
||||
return [
|
||||
'product_name' => $product->getProductName(),
|
||||
'edition' => method_exists($product, 'getEdition') ? $product->getEdition() : '',
|
||||
'version' => $product->getVersion(),
|
||||
'current_build' => method_exists($product, 'getCurrentBuild') ? $product->getCurrentBuild() : '',
|
||||
'release_log_url' => method_exists($product, 'getReleaseLogUrl') ? $product->getReleaseLogUrl() : '',
|
||||
'available_releases' => method_exists($product, 'getAvailableReleases') ? $product->getAvailableReleases() : [],
|
||||
'installed_releases' => method_exists($product, 'getInstalledReleases') ? $product->getInstalledReleases() : [],
|
||||
'license' => Service::LicenseInfo(),
|
||||
'has_validate_license' => $this->supportsValidateLicense(),
|
||||
];
|
||||
}
|
||||
|
||||
public function perform($action, $version = '')
|
||||
{
|
||||
switch ((string) $action) {
|
||||
case self::ACTION_UPGRADE:
|
||||
return $this->upgrade($version);
|
||||
|
||||
case self::ACTION_SWITCH:
|
||||
return $this->switchTo($version);
|
||||
|
||||
case self::ACTION_REMOVE:
|
||||
return $this->remove($version);
|
||||
|
||||
case 'validatelicense':
|
||||
if ($this->supportsValidateLicense()) {
|
||||
return $this->validateLicense();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected function supportsValidateLicense()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function upgrade($version)
|
||||
{
|
||||
if (!$this->isValidVersion($version)) {
|
||||
return $this->errorMessage(DMsg::UIStr('service_versionmanager_invalidversion'));
|
||||
}
|
||||
|
||||
if (!$this->downloadReleaseArchive($version)) {
|
||||
return $this->errorMessage(DMsg::UIStr('service_versionmanager_downloadfailed') . ' ' . $version);
|
||||
}
|
||||
|
||||
return $this->runCommand(
|
||||
$this->buildUpgradeCommand($version),
|
||||
DMsg::UIStr('service_versionmanager_upgrade_started') . ' ' . $version
|
||||
);
|
||||
}
|
||||
|
||||
protected function switchTo($version)
|
||||
{
|
||||
if (!$this->isValidVersion($version)) {
|
||||
return $this->errorMessage(DMsg::UIStr('service_versionmanager_invalidversion'));
|
||||
}
|
||||
|
||||
return $this->runCommand(
|
||||
'mgrver:' . $version,
|
||||
DMsg::UIStr('service_versionmanager_switch_started') . ' ' . $version
|
||||
);
|
||||
}
|
||||
|
||||
protected function remove($version)
|
||||
{
|
||||
if (!$this->isValidVersion($version)) {
|
||||
return $this->errorMessage(DMsg::UIStr('service_versionmanager_invalidversion'));
|
||||
}
|
||||
|
||||
return $this->runCommand(
|
||||
'mgrver:-d ' . $version,
|
||||
DMsg::UIStr('service_versionmanager_remove_started') . ' ' . $version
|
||||
);
|
||||
}
|
||||
|
||||
protected function validateLicense()
|
||||
{
|
||||
return $this->runCommand(
|
||||
'ValidateLicense',
|
||||
DMsg::UIStr('service_versionmanager_validate_started')
|
||||
);
|
||||
}
|
||||
|
||||
protected function runCommand($command, $successMessage)
|
||||
{
|
||||
if (!$this->sendCommand($command)) {
|
||||
return $this->errorMessage(DMsg::UIStr('service_versionmanager_commandfailed'));
|
||||
}
|
||||
|
||||
$this->waitForStatusChange();
|
||||
$this->getProduct()->refreshVersion();
|
||||
|
||||
return [
|
||||
'type' => 'success',
|
||||
'text' => $successMessage,
|
||||
];
|
||||
}
|
||||
|
||||
protected function sendCommand($command)
|
||||
{
|
||||
CAuthorizer::singleton()->Reauthenticate();
|
||||
return $this->getAdminCommandClient()->sendCommand($command . "\n");
|
||||
}
|
||||
|
||||
protected function waitForStatusChange()
|
||||
{
|
||||
Service::WaitForStatusChange();
|
||||
}
|
||||
|
||||
protected function getAdminCommandClient()
|
||||
{
|
||||
return new AdminCommandClient();
|
||||
}
|
||||
|
||||
protected function getServerRoot()
|
||||
{
|
||||
if (defined('SERVER_ROOT') && SERVER_ROOT !== '') {
|
||||
return SERVER_ROOT;
|
||||
}
|
||||
|
||||
if (isset($_SERVER['LS_SERVER_ROOT']) && is_string($_SERVER['LS_SERVER_ROOT']) && $_SERVER['LS_SERVER_ROOT'] !== '') {
|
||||
return rtrim($_SERVER['LS_SERVER_ROOT'], '/') . '/';
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
protected function isValidVersion($version)
|
||||
{
|
||||
return (preg_match('/^\d+\.\d+(\.\d+)?(RC\d+)?$/', (string) $version) === 1);
|
||||
}
|
||||
|
||||
protected function errorMessage($text)
|
||||
{
|
||||
return [
|
||||
'type' => 'danger',
|
||||
'text' => $text,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -43,6 +43,10 @@ class DTblDef extends DTblDefBase
|
||||
protected function loadCommonOptions()
|
||||
{
|
||||
parent::loadCommonOptions();
|
||||
$this->_options['extAutoStart'] = [
|
||||
'2' => DMsg::ALbl('o_thrucgidaemon'),
|
||||
'0' => DMsg::ALbl('o_no')
|
||||
];
|
||||
$this->_options['scriptHandler'] = $this->getSharedScriptHandlerOptions([
|
||||
'module' => DMsg::ALbl('l_modulehandler')
|
||||
]);
|
||||
@@ -64,12 +68,25 @@ class DTblDef extends DTblDefBase
|
||||
protected function loadCommonAttrs()
|
||||
{
|
||||
parent::loadCommonAttrs();
|
||||
$this->_attrs['ext_autoStart'] = self::NewSelAttr('autoStart', DMsg::ALbl('l_autostart'), $this->_options['extAutoStart'], false);
|
||||
$param = self::NewTextAreaAttr('param', DMsg::ALbl('l_moduleparams'), 'cust', true, 4, 'modParams', 1, 1);
|
||||
$param->SetFlag(DAttr::BM_RAWDATA);
|
||||
$this->_attrs['mod_params'] = $param;
|
||||
$this->_attrs['mod_enabled'] = self::NewBoolAttr('ls_enabled', DMsg::ALbl('l_enablehooks'), true, 'moduleEnabled');
|
||||
}
|
||||
|
||||
protected function get_ctx_attrs($type)
|
||||
{
|
||||
if ($type == 'charset') {
|
||||
return [
|
||||
self::NewTextAttr('addDefaultCharset', DMsg::ALbl('l_adddefaultcharset'), 'charset'),
|
||||
$this->_attrs['enableIpGeo']
|
||||
];
|
||||
}
|
||||
|
||||
return parent::get_ctx_attrs($type);
|
||||
}
|
||||
|
||||
protected function add_S_PROCESS($id) //keep
|
||||
{
|
||||
$attrs = [
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace LSWebAdmin\Product\Ows;
|
||||
|
||||
use LSWebAdmin\I18n\DMsg;
|
||||
use LSWebAdmin\Product\Base\ProductBase;
|
||||
|
||||
class Product extends ProductBase
|
||||
@@ -18,4 +19,30 @@ class Product extends ProductBase
|
||||
'bin/lshttpd',
|
||||
];
|
||||
}
|
||||
|
||||
protected function detectAvailableVersion()
|
||||
{
|
||||
$newVersion = '';
|
||||
$currentBranchVersion = '';
|
||||
|
||||
$currentBranchRelease = $this->readReleaseFile('autoupdate/releasecb');
|
||||
if ($currentBranchRelease !== '') {
|
||||
$currentBranchVersion = $this->extractReleaseVersion($currentBranchRelease);
|
||||
|
||||
if ($this->version != $currentBranchVersion) {
|
||||
$newVersion = $currentBranchRelease . ' (' . DMsg::UIStr('note_curbranch') . ') ';
|
||||
}
|
||||
}
|
||||
|
||||
$latestRelease = $this->readReleaseFile('autoupdate/release');
|
||||
if ($latestRelease !== '') {
|
||||
$latestVersion = $this->extractReleaseVersion($latestRelease);
|
||||
|
||||
if ($this->version != $latestVersion && $currentBranchVersion != $latestVersion) {
|
||||
$newVersion .= $latestRelease;
|
||||
}
|
||||
}
|
||||
|
||||
return $newVersion;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ class ConfRouteParser
|
||||
if (($pos = strpos($mid, '_')) > 0) {
|
||||
$view = substr($mid, 0, $pos + 1);
|
||||
$viewName = substr($mid, $pos + 1);
|
||||
if ($pid == '' || $view == 'sl' || $view == 'sl_' || $view == 'al' || $view == 'al_' || $view == 'lb' || $view == 'lb_' || $view == 'lb4_' || $pid == 'base' || $pid == 'mbr') {
|
||||
if ($pid == '' || $view == 'sl' || $view == 'sl_' || $view == 'sl4_' || $view == 'al' || $view == 'al_' || $view == 'lb' || $view == 'lb_' || $view == 'lb4_' || $pid == 'base' || $pid == 'mbr') {
|
||||
$ref = $viewName;
|
||||
}
|
||||
} else {
|
||||
@@ -125,7 +125,7 @@ class ConfRouteParser
|
||||
return substr($ref, 0, $pos);
|
||||
}
|
||||
|
||||
if ($view == 'sl_' || $view == 'al_' || $view == 'lb_' || $view == 'lb4_' || $pid == 'base' || $pid == 'mbr') {
|
||||
if ($view == 'sl_' || $view == 'sl4_' || $view == 'al_' || $view == 'lb_' || $view == 'lb4_' || $pid == 'base' || $pid == 'mbr') {
|
||||
return $viewName;
|
||||
}
|
||||
|
||||
|
||||
+11
-1
@@ -127,6 +127,16 @@ class ConfRouteState
|
||||
$this->_mid = substr($this->_mid, 0, $pos) . $suffix;
|
||||
}
|
||||
|
||||
public function SetViewRoute($view, $viewName, $pid, $tid = null, $ref = null)
|
||||
{
|
||||
$this->_view = $view;
|
||||
$this->_viewName = $viewName;
|
||||
$this->_mid = (is_string($view) && substr($view, -1) === '_') ? $view . $viewName : $view;
|
||||
$this->_pid = $pid;
|
||||
$this->_tid = $tid;
|
||||
$this->_ref = $ref;
|
||||
}
|
||||
|
||||
public function IsViewAction()
|
||||
{
|
||||
if (!is_string($this->_act) || $this->_act === '') {
|
||||
@@ -175,7 +185,7 @@ class ConfRouteState
|
||||
|
||||
if ($this->_ref && ($pos = strrpos($this->_ref, '`')) !== false) {
|
||||
$this->_ref = substr($this->_ref, 0, $pos);
|
||||
} elseif ($this->_view == 'sl_' || $this->_view == 'al_' || $this->_pid == 'base' || $this->_pid == 'mbr') {
|
||||
} elseif ($this->_view == 'sl_' || $this->_view == 'sl4_' || $this->_view == 'al_' || $this->_view == 'lb_' || $this->_view == 'lb4_' || $this->_pid == 'base' || $this->_pid == 'mbr') {
|
||||
$this->_ref = $this->_viewName;
|
||||
} else {
|
||||
$this->_ref = null;
|
||||
|
||||
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+26
-4
@@ -23,11 +23,21 @@ echo UI::content_header('layout-dashboard', DMsg::UIStr('menu_dashboard'), '', f
|
||||
<article>
|
||||
<div class="lst-dashboard-statusbar" id="dashboard_statusbar">
|
||||
<div class="lst-dashboard-statusbar__group lst-dashboard-statusbar__group--version">
|
||||
<?php if (UI::SupportsVersionManager()) { ?>
|
||||
<span id="dash_version_value" class="lst-dashboard-statusbar__value lst-dashboard-statusbar__version">
|
||||
<span class="lst-dashboard-statusbar__version-product">—</span>
|
||||
<a class="lst-dashboard-statusbar__version-link" href="index.php?view=versionmanager"></a>
|
||||
</span>
|
||||
<?php } else { ?>
|
||||
<span id="dash_version_value" class="lst-dashboard-statusbar__value">—</span>
|
||||
<?php if ($dashboardNewVersion !== '' && $dashboardNewVersionUrl !== '') { ?>
|
||||
<a class="lst-dashboard-statusbar__link" href="<?php echo UIBase::EscapeAttr($dashboardNewVersionUrl); ?>"<?php echo $dashboardNewVersionExternal ? ' rel="noopener noreferrer" target="_blank"' : ''; ?>><?php echo UIBase::Escape(DMsg::UIStr('note_newver') . ': ' . $dashboardNewVersion); ?></a>
|
||||
<?php } ?>
|
||||
<span class="lst-dashboard-statusbar__meta"><?php echo ($dashboardBuildDisplay !== '') ? UIBase::Escape($dashboardBuildDisplay) : ''; ?></span>
|
||||
<?php if ($dashboardNewVersion !== '' && $dashboardNewVersionUrl !== '') { ?>
|
||||
<a class="lst-dashboard-statusbar__link" href="<?php echo UIBase::EscapeAttr($dashboardNewVersionUrl); ?>"<?php echo $dashboardNewVersionExternal ? ' rel="noopener noreferrer" target="_blank"' : ''; ?>>
|
||||
<span class="lst-dashboard-statusbar__link-label"><?php echo UIBase::Escape(DMsg::UIStr('note_newver')); ?></span>
|
||||
<span class="lst-dashboard-statusbar__link-value"><?php echo UIBase::Escape($dashboardNewVersion); ?></span>
|
||||
</a>
|
||||
<?php } ?>
|
||||
</div>
|
||||
<div class="lst-dashboard-statusbar__group lst-dashboard-statusbar__group--pid">
|
||||
<span id="dash_pid_dot" class="lst-dashboard-statusdot is-off" aria-hidden="true"></span>
|
||||
@@ -555,7 +565,10 @@ echo UI::content_header('layout-dashboard', DMsg::UIStr('menu_dashboard'), '', f
|
||||
var pidValue,
|
||||
running,
|
||||
uptime,
|
||||
loadValue;
|
||||
loadValue,
|
||||
versionValue,
|
||||
versionProduct,
|
||||
versionLink;
|
||||
|
||||
if (!data) {
|
||||
return;
|
||||
@@ -574,7 +587,16 @@ echo UI::content_header('layout-dashboard', DMsg::UIStr('menu_dashboard'), '', f
|
||||
$("#dash_load_value").text(loadValue);
|
||||
|
||||
if (data.version_display || data.product_name) {
|
||||
$("#dash_version_value").text(data.version_display || data.product_name || "—");
|
||||
versionValue = $("#dash_version_value");
|
||||
versionProduct = versionValue.find(".lst-dashboard-statusbar__version-product");
|
||||
versionLink = versionValue.find(".lst-dashboard-statusbar__version-link");
|
||||
|
||||
if (versionProduct.length && versionLink.length) {
|
||||
versionProduct.text(data.product_name || "—");
|
||||
versionLink.text(data.version || "").attr("hidden", data.version ? null : "hidden");
|
||||
} else {
|
||||
versionValue.text(data.version_display || data.product_name || "—");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+34
-9
@@ -5,6 +5,31 @@ use LSWebAdmin\Product\Current\Product;
|
||||
use LSWebAdmin\Product\Current\UI;
|
||||
use LSWebAdmin\UI\UIBase;
|
||||
|
||||
if (!function_exists('lstAssetHref')) {
|
||||
function lstAssetHref($href)
|
||||
{
|
||||
if ($href === '' || $href[0] !== '/') {
|
||||
return $href;
|
||||
}
|
||||
|
||||
$paths = [];
|
||||
if (defined('SERVER_ROOT') && SERVER_ROOT !== '') {
|
||||
$paths[] = rtrim(SERVER_ROOT, '/') . '/admin/html' . $href;
|
||||
}
|
||||
|
||||
$paths[] = dirname(__DIR__, 2) . $href;
|
||||
$paths[] = dirname(__DIR__, 4) . $href;
|
||||
|
||||
foreach ($paths as $path) {
|
||||
if (is_file($path)) {
|
||||
return $href . '?v=' . filemtime($path);
|
||||
}
|
||||
}
|
||||
|
||||
return $href;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$no_main_header) { ?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-us">
|
||||
@@ -55,13 +80,13 @@ $consoleName = $product->getWebAdminConsoleName();
|
||||
<link rel="shortcut icon" href="/res/img/favicon/favicon.ico" type="image/x-icon">
|
||||
<link rel="icon" href="/res/img/favicon/favicon.ico" type="image/x-icon">
|
||||
|
||||
<link rel="stylesheet" type="text/css" media="screen" href="/res/css/googlefonts.css">
|
||||
<link rel="stylesheet" type="text/css" media="screen" href="/res/css/lst-theme.css">
|
||||
<link rel="stylesheet" type="text/css" media="screen" href="/res/css/lst-product-accent.css">
|
||||
<link rel="stylesheet" type="text/css" media="screen" href="/res/css/lst-components.css">
|
||||
<link rel="stylesheet" type="text/css" media="screen" href="/res/css/lst-shell.css">
|
||||
<?php if ($no_main_header) { ?>
|
||||
<link rel="stylesheet" type="text/css" media="screen" href="/res/css/lst-page-login.css">
|
||||
<link rel="stylesheet" type="text/css" media="screen" href="<?php echo UIBase::EscapeAttr(lstAssetHref('/res/css/googlefonts.css')); ?>">
|
||||
<link rel="stylesheet" type="text/css" media="screen" href="<?php echo UIBase::EscapeAttr(lstAssetHref('/res/css/lst-theme.css')); ?>">
|
||||
<link rel="stylesheet" type="text/css" media="screen" href="<?php echo UIBase::EscapeAttr(lstAssetHref('/res/css/lst-product-accent.css')); ?>">
|
||||
<link rel="stylesheet" type="text/css" media="screen" href="<?php echo UIBase::EscapeAttr(lstAssetHref('/res/css/lst-components.css')); ?>">
|
||||
<link rel="stylesheet" type="text/css" media="screen" href="<?php echo UIBase::EscapeAttr(lstAssetHref('/res/css/lst-shell.css')); ?>">
|
||||
<?php if ($no_main_header) { ?>
|
||||
<link rel="stylesheet" type="text/css" media="screen" href="<?php echo UIBase::EscapeAttr(lstAssetHref('/res/css/lst-page-login.css')); ?>">
|
||||
<?php } else {
|
||||
$lstPageStyles = [];
|
||||
if (isset($view)) {
|
||||
@@ -74,7 +99,7 @@ $consoleName = $product->getWebAdminConsoleName();
|
||||
}
|
||||
foreach ($lstPageStyles as $lstPageStyleHref) {
|
||||
?>
|
||||
<link rel="stylesheet" type="text/css" media="screen" href="<?php echo UIBase::EscapeAttr($lstPageStyleHref); ?>">
|
||||
<link rel="stylesheet" type="text/css" media="screen" href="<?php echo UIBase::EscapeAttr(lstAssetHref($lstPageStyleHref)); ?>">
|
||||
<?php
|
||||
}
|
||||
} ?>
|
||||
@@ -83,7 +108,7 @@ $consoleName = $product->getWebAdminConsoleName();
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
||||
<meta name="robots" content="noindex">
|
||||
|
||||
<script src="/res/js/libs/jquery-4.0.0.min.js"></script>
|
||||
<script src="<?php echo UIBase::EscapeAttr(lstAssetHref('/res/js/libs/jquery-4.0.0.min.js')); ?>"></script>
|
||||
<script type="text/javascript">
|
||||
(function () {
|
||||
var lstPasswordShowLabel = <?php echo json_encode(DMsg::ALbl('btn_showpassword')); ?>;
|
||||
|
||||
+3
-2
@@ -1,6 +1,7 @@
|
||||
<?php
|
||||
|
||||
use LSWebAdmin\I18n\DMsg;
|
||||
use LSWebAdmin\UI\UIBase;
|
||||
|
||||
?>
|
||||
<script type="text/javascript">
|
||||
@@ -84,8 +85,8 @@ use LSWebAdmin\I18n\DMsg;
|
||||
}
|
||||
</script>
|
||||
|
||||
<script src="/res/js/lst-app.js"></script>
|
||||
<script src="/res/js/lucide.min.js"></script>
|
||||
<script src="<?php echo UIBase::EscapeAttr(lstAssetHref('/res/js/lst-app.js')); ?>"></script>
|
||||
<script src="<?php echo UIBase::EscapeAttr(lstAssetHref('/res/js/lucide.min.js')); ?>"></script>
|
||||
<script>
|
||||
if (typeof lucide !== 'undefined') {
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
|
||||
Vendored
+1
-1
@@ -1010,7 +1010,7 @@ installation()
|
||||
util_cpdir "$SDIR_OWN" $DOC_MOD add-ons
|
||||
util_cpdir "$CONF_OWN" $DOC_MOD share/autoindex
|
||||
|
||||
util_ccpfile "$SDIR_OWN" $EXEC_MOD fcgi-bin/lsperld.fpl fcgi-bin/RackRunner.rb fcgi-bin/lsnode.js
|
||||
util_ccpfile "$SDIR_OWN" $EXEC_MOD fcgi-bin/lsperld.fpl fcgi-bin/RackRunner.rb fcgi-bin/lsnode.js fcgi-bin/lsnodesm.js
|
||||
util_cpfile "$SDIR_OWN" $EXEC_MOD fcgi-bin/RailsRunner.rb fcgi-bin/RailsRunner.rb.2.3
|
||||
util_cpfile "$SDIR_OWN" $EXEC_MOD lsns/bin/common.py lsns/bin/lshostexec lsns/bin/lscgctl lsns/bin/lscgstats lsns/bin/lspkgctl lsns/bin/lsnsctl lsns/bin/unmount_ns lsns/bin/cmd_ns lsns/bin/lssetup
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#endif
|
||||
|
||||
#include "lscgid.h"
|
||||
#include "nspersist.h"
|
||||
|
||||
#include <lsdef.h>
|
||||
#include <util/fdpass.h>
|
||||
@@ -176,6 +177,15 @@ static char s_sDataBuf[16384];
|
||||
static int s_fdControl = -1;
|
||||
static int s_ns_enabled = 0;
|
||||
|
||||
#define NS_WATCHER_RESTART_DELAY_INITIAL 5
|
||||
#define NS_WATCHER_RESTART_DELAY_MAX 300
|
||||
#define NS_WATCHER_RESTART_STABLE 60
|
||||
|
||||
static int s_ns_watcher_restart_delay =
|
||||
NS_WATCHER_RESTART_DELAY_INITIAL;
|
||||
static time_t s_ns_watcher_next_restart = 0;
|
||||
static time_t s_ns_watcher_last_start = 0;
|
||||
static int s_ns_watcher_disabled = 0;
|
||||
|
||||
static void log_cgi_error(const char *func, const char *arg,
|
||||
const char *explanation)
|
||||
@@ -1006,7 +1016,10 @@ static int new_conn(int fd)
|
||||
pid_t pid;
|
||||
pid = fork();
|
||||
if (!pid)
|
||||
{
|
||||
nspersist_socket_watcher_forked_child();
|
||||
child_main(fd);
|
||||
}
|
||||
close(fd);
|
||||
if (pid > 0)
|
||||
pid = 0;
|
||||
@@ -1019,6 +1032,96 @@ static int s_got_sigchild = 0;
|
||||
|
||||
|
||||
static void processSigchild();
|
||||
static int start_socket_watcher();
|
||||
static void schedule_socket_watcher_restart(int reset_if_stable,
|
||||
int immediate_allowed);
|
||||
static void schedule_socket_watcher_after_reap(int status);
|
||||
|
||||
|
||||
static int start_socket_watcher()
|
||||
{
|
||||
if (!s_ns_enabled || s_ns_watcher_disabled)
|
||||
return 0;
|
||||
|
||||
pid_t pid = nspersist_start_socket_watcher();
|
||||
if (pid > 0)
|
||||
{
|
||||
s_ns_watcher_last_start = time(NULL);
|
||||
s_ns_watcher_next_restart = 0;
|
||||
DEBUG_MESSAGE("socket watcher running as pid %d\n", (int)pid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pid == 0)
|
||||
{
|
||||
s_ns_watcher_disabled = 1;
|
||||
s_ns_watcher_next_restart = 0;
|
||||
DEBUG_MESSAGE("socket watcher disabled; unsupported by this host\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
schedule_socket_watcher_restart(0, 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static void schedule_socket_watcher_restart(int reset_if_stable,
|
||||
int immediate_allowed)
|
||||
{
|
||||
if (!s_ns_enabled || s_ns_watcher_disabled || !s_run)
|
||||
return;
|
||||
|
||||
time_t now = time(NULL);
|
||||
if (reset_if_stable && s_ns_watcher_last_start &&
|
||||
now - s_ns_watcher_last_start >= NS_WATCHER_RESTART_STABLE)
|
||||
{
|
||||
s_ns_watcher_restart_delay = NS_WATCHER_RESTART_DELAY_INITIAL;
|
||||
}
|
||||
|
||||
int delay = s_ns_watcher_restart_delay;
|
||||
if (immediate_allowed &&
|
||||
s_ns_watcher_restart_delay == NS_WATCHER_RESTART_DELAY_INITIAL)
|
||||
{
|
||||
delay = 0;
|
||||
}
|
||||
|
||||
s_ns_watcher_next_restart = now + delay;
|
||||
DEBUG_MESSAGE("socket watcher restart scheduled in %d seconds "
|
||||
"(next backoff %d seconds)\n", delay,
|
||||
s_ns_watcher_restart_delay);
|
||||
|
||||
if (s_ns_watcher_restart_delay < NS_WATCHER_RESTART_DELAY_MAX)
|
||||
{
|
||||
s_ns_watcher_restart_delay *= 2;
|
||||
if (s_ns_watcher_restart_delay > NS_WATCHER_RESTART_DELAY_MAX)
|
||||
s_ns_watcher_restart_delay = NS_WATCHER_RESTART_DELAY_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void schedule_socket_watcher_after_reap(int status)
|
||||
{
|
||||
int reset_if_stable = 1;
|
||||
int immediate_allowed = 0;
|
||||
|
||||
if (WIFSIGNALED(status))
|
||||
{
|
||||
int sig_num = WTERMSIG(status);
|
||||
DEBUG_MESSAGE("socket watcher killed by signal %d\n", sig_num);
|
||||
immediate_allowed = 1;
|
||||
}
|
||||
else if (WIFEXITED(status))
|
||||
{
|
||||
DEBUG_MESSAGE("socket watcher exited with status %d\n",
|
||||
WEXITSTATUS(status));
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_MESSAGE("socket watcher exited with status 0x%x\n", status);
|
||||
}
|
||||
|
||||
schedule_socket_watcher_restart(reset_if_stable, immediate_allowed);
|
||||
}
|
||||
|
||||
|
||||
static int run(int fdServerSock)
|
||||
@@ -1045,6 +1148,8 @@ static int run(int fdServerSock)
|
||||
}
|
||||
if (s_got_sigchild)
|
||||
processSigchild();
|
||||
if (s_ns_watcher_next_restart && time(NULL) >= s_ns_watcher_next_restart)
|
||||
start_socket_watcher();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -1083,6 +1188,11 @@ static void processSigchild()
|
||||
// continue;
|
||||
break;
|
||||
}
|
||||
if (nspersist_socket_watcher_reaped(status[0]))
|
||||
{
|
||||
schedule_socket_watcher_after_reap(status[1]);
|
||||
continue;
|
||||
}
|
||||
if (s_fdControl != -1)
|
||||
write(s_fdControl, status, sizeof(status));
|
||||
if (WIFSIGNALED(status[1]))
|
||||
@@ -1170,6 +1280,16 @@ int lscgid_main(int fd, char *argv0, const char *secret, char *pSock)
|
||||
|
||||
}
|
||||
s_ns_enabled = HttpServerConfig::getInstance().getNS();
|
||||
if (s_ns_enabled)
|
||||
{
|
||||
DEBUG_MESSAGE("Namespace container is enabled.\n");
|
||||
/* Start the host-side socket watcher that monitors MySQL
|
||||
* (and other) socket bounces and remounts stale bind mounts
|
||||
* inside persisted namespaces. */
|
||||
start_socket_watcher();
|
||||
}
|
||||
else
|
||||
DEBUG_MESSAGE("Namespace container is NOT enabled\n");
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1195,5 +1315,3 @@ int lscgid_main(int fd, char *argv0, const char *secret, char *pSock)
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -86,6 +86,7 @@ SetupOp s_setupOp_all[] =
|
||||
int s_setupOp_all_size = sizeof(s_setupOp_all);
|
||||
int s_listenPid = 0;
|
||||
int s_listenPidStatus = 0;
|
||||
pid_t s_ns_watcher_pid = 0;
|
||||
|
||||
|
||||
SetupOp s_SetupOp_default[] =
|
||||
@@ -2906,6 +2907,7 @@ static int do_ns(lscgid_t *pCGI, SetupOp *setupOp, int persisted)
|
||||
pid_t parent_pid;
|
||||
mode_t old_umask = -1;
|
||||
char *old_cwd = NULL;
|
||||
int host_root_fd = -1;
|
||||
|
||||
DEBUG_MESSAGE("Entering do_ns, uid: %d, ppid: %d\n", getuid(), getppid());
|
||||
debug_ops(setupOp);
|
||||
@@ -2938,6 +2940,14 @@ static int do_ns(lscgid_t *pCGI, SetupOp *setupOp, int persisted)
|
||||
|
||||
old_cwd = get_current_dir_name ();
|
||||
|
||||
/* Grab an O_PATH handle to the host root BEFORE the mount namespace is
|
||||
* modified so we can still reach host files after pivot_root. */
|
||||
host_root_fd = open("/", O_PATH);
|
||||
if (host_root_fd == -1)
|
||||
{
|
||||
DEBUG_MESSAGE("do_ns: open(/) for host_root_fd: %s\n", strerror(errno));
|
||||
}
|
||||
|
||||
if (!rc)
|
||||
rc = build_mount_namespace(pCGI);
|
||||
|
||||
@@ -2947,6 +2957,14 @@ static int do_ns(lscgid_t *pCGI, SetupOp *setupOp, int persisted)
|
||||
if (!rc)
|
||||
rc = cleanup_oldroot(pCGI, persisted);
|
||||
|
||||
/* After the namespace is fully built, check for stale socket bind mounts
|
||||
* and re-establish any that were replaced on the host side. */
|
||||
if (!rc && host_root_fd != -1)
|
||||
nspersist_remount_stale_sockets(host_root_fd);
|
||||
|
||||
if (host_root_fd != -1)
|
||||
close(host_root_fd);
|
||||
|
||||
//if (pCGI->m_oom_score_adjust != LS_OOM_NO_ADJ)
|
||||
// apply_oom_score_adj(pCGI->m_oom_score_adjust);
|
||||
|
||||
@@ -3206,6 +3224,27 @@ void ns_setverbose_callback(verbose_callback_t callback)
|
||||
void ns_done()
|
||||
{
|
||||
DEBUG_MESSAGE("ns_done\n");
|
||||
if (s_ns_watcher_pid > 0)
|
||||
{
|
||||
kill(s_ns_watcher_pid, SIGTERM);
|
||||
/* Bound the wait: poll for up to ~2 s, then SIGKILL and reap. */
|
||||
int waited_ms = 0;
|
||||
while (waited_ms < 2000)
|
||||
{
|
||||
pid_t r = waitpid(s_ns_watcher_pid, NULL, WNOHANG);
|
||||
if (r == s_ns_watcher_pid || r == -1)
|
||||
break;
|
||||
usleep(50000); /* 50 ms */
|
||||
waited_ms += 50;
|
||||
}
|
||||
if (waitpid(s_ns_watcher_pid, NULL, WNOHANG) == 0)
|
||||
{
|
||||
kill(s_ns_watcher_pid, SIGKILL);
|
||||
waitpid(s_ns_watcher_pid, NULL, 0);
|
||||
}
|
||||
s_ns_watcher_pid = 0;
|
||||
}
|
||||
|
||||
nspersist_done();
|
||||
if (s_proc_fd != -1)
|
||||
{
|
||||
|
||||
+1253
-12
File diff suppressed because it is too large
Load Diff
@@ -119,11 +119,11 @@ int lock_persist_vh_file(int report, int lock_type);
|
||||
/**
|
||||
* @fn unlock_close_persist_vh_file
|
||||
* @brief Unlocks and closes a lock file created by is_persisted.
|
||||
* @param[in] delete. Whether to delete the file (closed by the last)
|
||||
* @param[in] del. Whether to delete the file (closed by the last)
|
||||
* @param[out] none
|
||||
* @return 0 if no error, or an error code.
|
||||
**/
|
||||
int unlock_close_persist_vh_file(int delete);
|
||||
int unlock_close_persist_vh_file(int del);
|
||||
|
||||
/**
|
||||
* @fn persist_do_ns
|
||||
@@ -251,6 +251,66 @@ void persist_exit_child(char *desc, int rc);
|
||||
|
||||
int nspersist_setvhost(char *vhenv);
|
||||
|
||||
/**
|
||||
* @fn nspersist_remount_stale_sockets
|
||||
* @brief Check for bind-mounted socket files that have become stale (the
|
||||
* host-side socket was deleted and recreated) and re-establish them.
|
||||
* @param[in] host_root_fd An O_PATH descriptor opened on "/" in the initial
|
||||
* mount namespace BEFORE setns()/unshare() was called.
|
||||
* @return None.
|
||||
**/
|
||||
void nspersist_remount_stale_sockets(int host_root_fd);
|
||||
|
||||
/**
|
||||
* @fn nspersist_start_socket_watcher
|
||||
* @brief Start the host-side socket watcher daemon that monitors all
|
||||
* persisted namespaces' bind-mounted sockets and remounts stale ones
|
||||
* when host-side sockets are bounced (e.g. MySQL restart).
|
||||
*
|
||||
* Called once from the lscgid main daemon during startup. Forks a
|
||||
* dedicated watcher process that lives in the host mount namespace
|
||||
* (full visibility of the host filesystem) and uses inotify to detect
|
||||
* socket changes. When changes occur, it forks a helper that
|
||||
* setns()'s into each persisted namespace to perform the remount.
|
||||
*
|
||||
* @return The pid of the watcher process on success, -1 on error.
|
||||
* The caller should kill(pid, SIGTERM) during shutdown to stop it.
|
||||
**/
|
||||
pid_t nspersist_start_socket_watcher(void);
|
||||
|
||||
/**
|
||||
* @fn nspersist_socket_watcher_forked_child
|
||||
* @brief Clear inherited watcher state in forked request children. The
|
||||
* watcher belongs to the lscgid daemon process, so request children must not
|
||||
* signal or reap it from ns_done().
|
||||
* @return None.
|
||||
**/
|
||||
void nspersist_socket_watcher_forked_child(void);
|
||||
|
||||
/**
|
||||
* @fn nspersist_socket_watcher_reaped
|
||||
* @brief Clear watcher state when the lscgid parent reaps the watcher child.
|
||||
*
|
||||
* @param[in] pid The child pid returned by waitpid().
|
||||
* @return 1 if pid was the active watcher and was cleared, 0 otherwise.
|
||||
**/
|
||||
int nspersist_socket_watcher_reaped(pid_t pid);
|
||||
|
||||
/**
|
||||
* @fn nspersist_register_socket_mount
|
||||
* @brief Called by ns.c when a socket bind mount is created during
|
||||
* namespace setup, so the host-side watcher knows what to monitor.
|
||||
*
|
||||
* @param[in] uid The user id (used to identify the persisted namespace).
|
||||
* @param[in] persist_num The persist number (matches /var/lsns/uid/N).
|
||||
* @param[in] host_path The host-side path of the socket (source).
|
||||
* @param[in] ns_path The namespace-side bind mount target.
|
||||
* @return None.
|
||||
**/
|
||||
void nspersist_register_socket_mount(uid_t uid, int persist_num,
|
||||
const char *host_path,
|
||||
const char *ns_path);
|
||||
|
||||
extern mount_flags_data_t s_mount_flags_data[];
|
||||
|
||||
#ifdef __cplusplus
|
||||
@@ -259,4 +319,3 @@ extern mount_flags_data_t s_mount_flags_data[];
|
||||
|
||||
#endif // Linux
|
||||
#endif // _NS_OPTS_H
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ ExtWorkerConfig::ExtWorkerConfig(const char *pName)
|
||||
, m_iMaxIdleTime(INT_MAX)
|
||||
, m_iKeepAliveTimeout(INT_MAX)
|
||||
, m_iSelfManaged(1)
|
||||
, m_iStartByServer(0)
|
||||
, m_iStartByServer(EXTAPP_AUTOSTART_OFF)
|
||||
, m_iRefAddr(0)
|
||||
, m_iDaemonSuEXEC(0)
|
||||
, m_iDropCaps(0)
|
||||
@@ -66,7 +66,7 @@ ExtWorkerConfig::ExtWorkerConfig()
|
||||
, m_iMaxIdleTime(INT_MAX)
|
||||
, m_iKeepAliveTimeout(INT_MAX)
|
||||
, m_iSelfManaged(1)
|
||||
, m_iStartByServer(0)
|
||||
, m_iStartByServer(EXTAPP_AUTOSTART_OFF)
|
||||
, m_iRefAddr(0)
|
||||
, m_iDaemonSuEXEC(0)
|
||||
, m_iDropCaps(0)
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
#define EXTAPP_AUTOSTART_OFF 0
|
||||
#define EXTAPP_AUTOSTART_NORMAL 1
|
||||
#define EXTAPP_AUTOSTART_CGID 2
|
||||
#define EXTAPP_AUTOSTART_ASYNC_CGID 3
|
||||
|
||||
#define EXTAPP_RUNONSTART_OFF 0
|
||||
#define EXTAPP_RUNONSTART_ON 1
|
||||
|
||||
@@ -484,7 +484,7 @@ int LocalWorker::workerExec(LocalWorkerConfig &config, int fd)
|
||||
//Since we already in the chroot jail, do not use the global jail path
|
||||
//If start external app with lscgid, apply global chroot path,
|
||||
// as lscgid is not inside chroot
|
||||
if (config.getStartByServer() == 2)
|
||||
if (config.getStartByServer() == EXTAPP_AUTOSTART_CGID)
|
||||
{
|
||||
if (!pChroot)
|
||||
pChroot = procConfig.getChroot();
|
||||
|
||||
@@ -475,7 +475,7 @@ int ExtAppRegistry::configVhostOwnPhp(HttpVHost *pVHost)
|
||||
char appName[256];
|
||||
const char *pUri;
|
||||
char buf[MAX_PATH_LEN];
|
||||
int iAutoStart = 0;
|
||||
int iAutoStart = EXTAPP_AUTOSTART_OFF;
|
||||
const char *pPath = NULL;
|
||||
ExtWorker *pWorker = NULL;
|
||||
ExtWorkerConfig *pConfig = NULL;
|
||||
@@ -714,7 +714,7 @@ ExtWorker *ExtAppRegistry::configExtApp(const XmlNode *pNode, const HttpVHost *p
|
||||
const char *pType;
|
||||
const char *pUri;
|
||||
char buf[MAX_PATH_LEN];
|
||||
int iAutoStart = 0;
|
||||
int iAutoStart = EXTAPP_AUTOSTART_OFF;
|
||||
const char *pPath = NULL;
|
||||
ExtWorker *pWorker = NULL;
|
||||
ExtWorkerConfig *pConfig = NULL;
|
||||
@@ -815,9 +815,9 @@ ExtWorker *ExtAppRegistry::configExtApp(const XmlNode *pNode, const HttpVHost *p
|
||||
if ((iType == EA_FCGI) || (iType == EA_LOGGER) || (iType == EA_LSAPI) || (iType == EA_SCGI) || (iType == EA_UWSGI))
|
||||
{
|
||||
if (iType == EA_LOGGER)
|
||||
iAutoStart = 1;
|
||||
iAutoStart = EXTAPP_AUTOSTART_CGID;
|
||||
else if (iType == EA_SCGI || iType == EA_UWSGI)
|
||||
iAutoStart = 0;
|
||||
iAutoStart = EXTAPP_AUTOSTART_OFF;
|
||||
else
|
||||
iAutoStart = ConfigCtx::getCurConfigCtx()->getLongValue(pNode, "autoStart",
|
||||
0, 2, 1);
|
||||
|
||||
@@ -542,7 +542,7 @@ int HttpReq::processUnpackedHeaders(UnpackedHeaders *header)
|
||||
return result;
|
||||
|
||||
m_ver = HTTP_1_1;
|
||||
if (m_method == HttpMethod::HTTP_POST)
|
||||
if (m_method == HttpMethod::HTTP_POST || m_method == HttpMethod::HTTP_PATCH)
|
||||
m_lEntityLength = LSI_BODY_SIZE_UNKNOWN;
|
||||
keepAlive(0);
|
||||
|
||||
@@ -3164,7 +3164,7 @@ const char *HttpReq::getCfRealIpHeader(char *name, int &len)
|
||||
|
||||
char HttpReq::getRewriteLogLevel() const
|
||||
{
|
||||
if (LS_LOG_ENABLED(log4cxx::Level::DBG_LOW))
|
||||
if (LS_LOG_ENABLED(log4cxx::Level::DBG_HIGH))
|
||||
return 9;
|
||||
else
|
||||
return m_pVHost->getRewriteLogLevel();
|
||||
|
||||
@@ -1604,7 +1604,7 @@ void HttpVHost::setDefaultConfig(LocalWorkerConfig &config,
|
||||
config.setAppPath(pBinPath);
|
||||
config.setBackLog(pDefault->getBackLog());
|
||||
config.setSelfManaged(1);
|
||||
config.setStartByServer(EXTAPP_AUTOSTART_ASYNC_CGID);
|
||||
config.setStartByServer(EXTAPP_AUTOSTART_CGID);
|
||||
config.setMaxConns(maxConns);
|
||||
|
||||
if (config.isDetached())
|
||||
|
||||
@@ -2448,7 +2448,7 @@ LocalWorker *HttpServerImpl::createAdminPhpApp(const char *pChroot,
|
||||
pFcgiApp->getConfig().setAppPath(&pchPHPBin[iChrootLen]);
|
||||
pFcgiApp->getConfig().setBackLog(100);
|
||||
pFcgiApp->getConfig().setSelfManaged(0);
|
||||
pFcgiApp->getConfig().setStartByServer(1);
|
||||
pFcgiApp->getConfig().setStartByServer(EXTAPP_AUTOSTART_CGID);
|
||||
pFcgiApp->setMaxConns(4);
|
||||
pFcgiApp->getConfig().setKeepAliveTimeout(30);
|
||||
pFcgiApp->getConfig().setInstances(4);
|
||||
@@ -4282,7 +4282,7 @@ int HttpServerImpl::configIpToLoc(const XmlNode *pNode)
|
||||
int HttpServerImpl::configLsrecaptchaWorker(const XmlNode *pNode)
|
||||
{
|
||||
const char *pName = "lsrecaptcha";
|
||||
int iAutoStart = 1;
|
||||
int iAutoStart = EXTAPP_AUTOSTART_CGID;
|
||||
int backlog = 10;
|
||||
int instances = 1;
|
||||
int iMaxConns = 35;
|
||||
|
||||
@@ -91,7 +91,7 @@
|
||||
/***
|
||||
* Do not change the below format, it will be set correctly while packing the code
|
||||
*/
|
||||
#define BUILDTIME "built: Sat Apr 25 14:44:33 UTC 2026"
|
||||
#define BUILDTIME "built: Thu May 7 15:34:11 UTC 2026"
|
||||
|
||||
static const char s_pVersionFull[] = "LiteSpeed/" PACKAGE_VERSION
|
||||
" Open (" LS_MODULE_VERSION_INFO_ONELINE ") BUILD (" BUILDTIME ")";
|
||||
|
||||
@@ -414,6 +414,37 @@ int SslContext::configOptions(SslContextConfig *pConfig)
|
||||
pConfig->m_iProtocol);
|
||||
setProtocol(pConfig->m_iProtocol);
|
||||
}
|
||||
#ifdef OPENSSL_IS_BORINGSSL
|
||||
static const uint16_t s_signAlgsNoSha1[] =
|
||||
{
|
||||
SSL_SIGN_ED25519,
|
||||
SSL_SIGN_RSA_PSS_RSAE_SHA256,
|
||||
SSL_SIGN_RSA_PSS_RSAE_SHA384,
|
||||
SSL_SIGN_RSA_PSS_RSAE_SHA512,
|
||||
SSL_SIGN_ECDSA_SECP256R1_SHA256,
|
||||
SSL_SIGN_ECDSA_SECP384R1_SHA384,
|
||||
SSL_SIGN_ECDSA_SECP521R1_SHA512,
|
||||
SSL_SIGN_RSA_PKCS1_SHA256,
|
||||
SSL_SIGN_RSA_PKCS1_SHA384,
|
||||
SSL_SIGN_RSA_PKCS1_SHA512,
|
||||
};
|
||||
LS_DBG_L("[SSL:%p] Disable SHA1 for handshake signing/verifying algorithms.\n", this);
|
||||
if (!SSL_CTX_set_signing_algorithm_prefs(m_pCtx, s_signAlgsNoSha1,
|
||||
sizeof(s_signAlgsNoSha1) / sizeof(s_signAlgsNoSha1[0])))
|
||||
{
|
||||
LS_ERROR("[SSL:%p] Failed to set handshake signing algorithms: %s",
|
||||
this, SslError().what());
|
||||
return LS_FAIL;
|
||||
}
|
||||
|
||||
if (!SSL_CTX_set_verify_algorithm_prefs(m_pCtx, s_signAlgsNoSha1,
|
||||
sizeof(s_signAlgsNoSha1) / sizeof(s_signAlgsNoSha1[0])))
|
||||
{
|
||||
LS_ERROR("[SSL:%p] Failed to set handshake verifying algorithms: %s",
|
||||
this, SslError().what());
|
||||
return LS_FAIL;
|
||||
}
|
||||
#endif
|
||||
if (pConfig->m_iEnableECDHE)
|
||||
{
|
||||
LS_DBG_L("[SSL:%p] Enable ECDHE\n", this);
|
||||
|
||||
Reference in New Issue
Block a user