From 062358f8b1d9a7fa3d9be97f6b58e06fea7ca844 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Bartus?= Date: Sun, 28 Feb 2016 00:19:24 +0100 Subject: [PATCH 1/4] [ticket/14487] Try to handle connection timeouts PHPBB3-14487 --- phpBB/assets/javascript/installer.js | 62 ++++++++++++-- .../container/services_install_controller.yml | 6 ++ .../container/services_install_finish.yml | 2 +- .../container/services_installer.yml | 1 + phpBB/config/installer/routing/installer.yml | 5 ++ .../install/controller/timeout_check.php | 80 +++++++++++++++++++ .../helper/iohandler/ajax_iohandler.php | 41 +++++++++- phpBB/phpbb/install/installer.php | 22 ++++- 8 files changed, 210 insertions(+), 9 deletions(-) create mode 100644 phpBB/phpbb/install/controller/timeout_check.php diff --git a/phpBB/assets/javascript/installer.js b/phpBB/assets/javascript/installer.js index d9f446a28d..03b5b7deae 100644 --- a/phpBB/assets/javascript/installer.js +++ b/phpBB/assets/javascript/installer.js @@ -13,6 +13,9 @@ var currentProgress = 0; var refreshRequested = false; var transmissionOver = false; + var status = ''; + var statusCount = 0; + var statusTimeout = null; // Template related variables var $contentWrapper = $('.install-body').find('.main'); @@ -372,12 +375,45 @@ } if (timeoutDetected) { - addMessage('error', - [{ - title: installLang.title, - description: installLang.msg - }] - ); + status = queryInstallerStatus(); + statusCount = 0; + + if (status === 'continue') { + refreshRequested = false; + doRefresh(); + } else if (status === 'running') { + statusTimeout = setTimeout(function() { + var s = queryInstallerStatus(); + if (statusCount === 12) { // 1 minute hard cap + s = 'fail'; + } + + if (s === 'continue') { + refreshRequested = false; + doRefresh(); + clearTimeout(statusTimeout); + } else if (s === 'fail') { + addMessage('error', + [{ + title: installLang.title, + description: installLang.msg + }] + ); + clearTimeout(statusTimeout); + } + + statusCount++; + }, + 5000 + ); + } else { + addMessage('error', + [{ + title: installLang.title, + description: installLang.msg + }] + ); + } } } } @@ -564,4 +600,18 @@ submitForm($form, $(this)); }); } + + /** + * Queries the installer's status + */ + function queryInstallerStatus() + { + var data = null; + $.ajax({url: "../installer/status", dataType: "json"}) + .done(function(d) { + data = d; + }); + + return data.status; + } })(jQuery); // Avoid conflicts with other libraries diff --git a/phpBB/config/installer/container/services_install_controller.yml b/phpBB/config/installer/container/services_install_controller.yml index 394eb95c06..5aaba0f47f 100644 --- a/phpBB/config/installer/container/services_install_controller.yml +++ b/phpBB/config/installer/container/services_install_controller.yml @@ -65,3 +65,9 @@ services: - '@template' - '%core.root_path%' - '%core.php_ext%' + + phpbb.installer.controller.status: + class: phpbb\install\controller\timeout_check + arguments: + - '@phpbb.installer.controller.helper' + - '%core.root_path%' diff --git a/phpBB/config/installer/container/services_install_finish.yml b/phpBB/config/installer/container/services_install_finish.yml index f144cc6317..8b06ad7d97 100644 --- a/phpBB/config/installer/container/services_install_finish.yml +++ b/phpBB/config/installer/container/services_install_finish.yml @@ -26,7 +26,7 @@ services: - { name: service_collection, tag: install_finish, class_name_aware: true } installer.module.finish_install: - class: phpbb\install\module\install_filesystem\module + class: phpbb\install\module\install_finish\module parent: installer.module_base arguments: - '@installer.module.install_finish_collection' diff --git a/phpBB/config/installer/container/services_installer.yml b/phpBB/config/installer/container/services_installer.yml index 19b1b4f08e..57181b21d4 100644 --- a/phpBB/config/installer/container/services_installer.yml +++ b/phpBB/config/installer/container/services_installer.yml @@ -47,6 +47,7 @@ services: - '@request' - '@template' - '@router' + - '%core.root_path%' installer.helper.iohandler_cli: class: phpbb\install\helper\iohandler\cli_iohandler diff --git a/phpBB/config/installer/routing/installer.yml b/phpBB/config/installer/routing/installer.yml index 1961ba8ed6..47e16aa454 100644 --- a/phpBB/config/installer/routing/installer.yml +++ b/phpBB/config/installer/routing/installer.yml @@ -60,3 +60,8 @@ phpbb_convert_finish: path: /convert/finished defaults: _controller: phpbb.installer.controller.convert:finish + +phpbb_installer_status: + path: /installer/status + defaults: + _controller: phpbb.installer.controller.status:status diff --git a/phpBB/phpbb/install/controller/timeout_check.php b/phpBB/phpbb/install/controller/timeout_check.php new file mode 100644 index 0000000000..1c90e3caf3 --- /dev/null +++ b/phpBB/phpbb/install/controller/timeout_check.php @@ -0,0 +1,80 @@ + + * @license GNU General Public License, version 2 (GPL-2.0) + * + * For full copyright and license information, please see + * the docs/CREDITS.txt file. + * + */ + +namespace phpbb\install\controller; + +use Symfony\Component\HttpFoundation\JsonResponse; + +class timeout_check +{ + /** + * @var helper + */ + protected $helper; + + /** + * @var string + */ + protected $phpbb_root_path; + + /** + * Constructor + * + * @param helper $helper + * @param string $phpbb_root_path + */ + public function __construct(helper $helper, $phpbb_root_path) + { + $this->helper = $helper; + $this->phpbb_root_path = $phpbb_root_path; + } + + /** + * Controller for querying installer status + */ + public function status() + { + $lock_file = $this->phpbb_root_path . 'store/io_lock.lock'; + $response = new JsonResponse(); + + if (!file_exists($lock_file)) + { + $response->setData(array( + 'status' => 'fail', + )); + } + else + { + $fp = @fopen($lock_file, 'r'); + + if ($fp && flock($fp, LOCK_EX | LOCK_NB)) + { + $status = (filesize($lock_file) >= 2 && fread($fp, 2) === 'ok') ? 'continue' : 'fail'; + + $response->setData(array( + 'status' => $status, + )); + flock($fp, LOCK_UN); + fclose($fp); + } + else + { + $response->setData(array( + 'status' => 'running', + )); + } + } + + return $response; + } +} diff --git a/phpBB/phpbb/install/helper/iohandler/ajax_iohandler.php b/phpBB/phpbb/install/helper/iohandler/ajax_iohandler.php index 8c62ec7bd0..c168d26425 100644 --- a/phpBB/phpbb/install/helper/iohandler/ajax_iohandler.php +++ b/phpBB/phpbb/install/helper/iohandler/ajax_iohandler.php @@ -41,6 +41,11 @@ class ajax_iohandler extends iohandler_base */ protected $router; + /** + * @var string + */ + protected $phpbb_root_path; + /** * @var string */ @@ -76,6 +81,11 @@ class ajax_iohandler extends iohandler_base */ protected $redirect_url; + /** + * @var resource + */ + protected $file_lock_pointer; + /** * Constructor * @@ -83,8 +93,9 @@ class ajax_iohandler extends iohandler_base * @param \phpbb\request\request_interface $request HTTP request interface * @param \phpbb\template\template $template Template engine * @param router $router Router + * @param string $root_path Path to phpBB's root */ - public function __construct(path_helper $path_helper, \phpbb\request\request_interface $request, \phpbb\template\template $template, router $router) + public function __construct(path_helper $path_helper, \phpbb\request\request_interface $request, \phpbb\template\template $template, router $router, $root_path) { $this->path_helper = $path_helper; $this->request = $request; @@ -96,6 +107,7 @@ class ajax_iohandler extends iohandler_base $this->download = array(); $this->redirect_url = array(); $this->file_status = ''; + $this->phpbb_root_path = $root_path; parent::__construct(); } @@ -432,6 +444,33 @@ class ajax_iohandler extends iohandler_base $this->send_response(true); } + /** + * Acquires a file lock + */ + public function acquire_lock() + { + $lock_file = $this->phpbb_root_path . 'store/io_lock.lock'; + $this->file_lock_pointer = @fopen($lock_file, 'w+'); + + if ($this->file_lock_pointer) + { + flock($this->file_lock_pointer, LOCK_EX); + } + } + + /** + * Release file lock + */ + public function release_lock() + { + if ($this->file_lock_pointer) + { + fwrite($this->file_lock_pointer, 'ok'); + flock($this->file_lock_pointer, LOCK_UN); + fclose($this->file_lock_pointer); + } + } + /** * Callback function for language replacing * diff --git a/phpBB/phpbb/install/installer.php b/phpBB/phpbb/install/installer.php index b5709e96c7..240423ae78 100644 --- a/phpBB/phpbb/install/installer.php +++ b/phpBB/phpbb/install/installer.php @@ -22,6 +22,7 @@ use phpbb\install\exception\resource_limit_reached_exception; use phpbb\install\exception\user_interaction_required_exception; use phpbb\install\helper\config; use phpbb\install\helper\container_factory; +use phpbb\install\helper\iohandler\ajax_iohandler; use phpbb\install\helper\iohandler\cli_iohandler; use phpbb\install\helper\iohandler\iohandler_interface; use phpbb\path_helper; @@ -126,6 +127,11 @@ class installer */ public function run() { + if ($this->iohandler instanceof ajax_iohandler) + { + $this->iohandler->acquire_lock(); + } + // Load install progress $this->install_config->load_config(); @@ -174,7 +180,16 @@ class installer try { $iterator = $this->installer_modules->getIterator(); - $iterator->seek($module_index); + + if ($module_index < $iterator->count()) + { + $iterator->seek($module_index); + } + else + { + $iterator->seek($module_index - 1); + $iterator->next(); + } while ($iterator->valid()) { @@ -256,6 +271,11 @@ class installer $fail_cleanup = true; } + if ($this->iohandler instanceof ajax_iohandler) + { + $this->iohandler->release_lock(); + } + if ($install_finished) { // Send install finished message From 8993fef9c0ac2b49b9d51f9f804a13193ec64c36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Bartus?= Date: Mon, 29 Feb 2016 16:18:35 +0100 Subject: [PATCH 2/4] [ticket/14487] Update javascript PHPBB3-14487 --- phpBB/assets/javascript/installer.js | 104 +++++++++++++-------------- 1 file changed, 50 insertions(+), 54 deletions(-) diff --git a/phpBB/assets/javascript/installer.js b/phpBB/assets/javascript/installer.js index 03b5b7deae..166c2ec472 100644 --- a/phpBB/assets/javascript/installer.js +++ b/phpBB/assets/javascript/installer.js @@ -13,9 +13,7 @@ var currentProgress = 0; var refreshRequested = false; var transmissionOver = false; - var status = ''; var statusCount = 0; - var statusTimeout = null; // Template related variables var $contentWrapper = $('.install-body').find('.main'); @@ -341,6 +339,55 @@ } } + /** + * Processes status data + * + * @param status + */ + function processTimeoutResponse(status) { + if (statusCount === 12) { // 1 minute hard cap + status = 'fail'; + } + + if (status === 'continue') { + refreshRequested = false; + doRefresh(); + } else if (status === 'running') { + statusCount++; + setTimeout(queryInstallerStatus, 5000); + } else { + addMessage('error', + [{ + title: installLang.title, + description: installLang.msg + }] + ); + } + } + + /** + * Queries the installer's status + */ + function queryInstallerStatus() { + var url = $(location).attr('pathname'); + var lookUp = 'install/app.php'; + var position = url.indexOf(lookUp); + + if (position === -1) { + lookUp = 'install'; + position = url.indexOf(lookUp); + + if (position === -1) { + return false; + } + } + + url = url.substring(0, position) + lookUp + '/installer/status'; + $.getJSON(url, function(data) { + processTimeoutResponse(data.status); + }); + } + /** * Process updates in streamed response * @@ -375,45 +422,8 @@ } if (timeoutDetected) { - status = queryInstallerStatus(); statusCount = 0; - - if (status === 'continue') { - refreshRequested = false; - doRefresh(); - } else if (status === 'running') { - statusTimeout = setTimeout(function() { - var s = queryInstallerStatus(); - if (statusCount === 12) { // 1 minute hard cap - s = 'fail'; - } - - if (s === 'continue') { - refreshRequested = false; - doRefresh(); - clearTimeout(statusTimeout); - } else if (s === 'fail') { - addMessage('error', - [{ - title: installLang.title, - description: installLang.msg - }] - ); - clearTimeout(statusTimeout); - } - - statusCount++; - }, - 5000 - ); - } else { - addMessage('error', - [{ - title: installLang.title, - description: installLang.msg - }] - ); - } + queryInstallerStatus(); } } } @@ -600,18 +610,4 @@ submitForm($form, $(this)); }); } - - /** - * Queries the installer's status - */ - function queryInstallerStatus() - { - var data = null; - $.ajax({url: "../installer/status", dataType: "json"}) - .done(function(d) { - data = d; - }); - - return data.status; - } })(jQuery); // Avoid conflicts with other libraries From dacbf0922756a930821337b2d95d9982df1a43cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Bartus?= Date: Mon, 29 Feb 2016 16:40:09 +0100 Subject: [PATCH 3/4] [ticket/14487] Add loading indicator while polling status PHPBB3-14487 --- phpBB/assets/javascript/installer.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/phpBB/assets/javascript/installer.js b/phpBB/assets/javascript/installer.js index 166c2ec472..a11b76b863 100644 --- a/phpBB/assets/javascript/installer.js +++ b/phpBB/assets/javascript/installer.js @@ -354,8 +354,10 @@ doRefresh(); } else if (status === 'running') { statusCount++; + $('#loading_indicator').css('display', 'block'); setTimeout(queryInstallerStatus, 5000); } else { + $('#loading_indicator').css('display', 'none'); addMessage('error', [{ title: installLang.title, From b1a136e7bd8cc06ee320655a4ee7cf72dcd7c611 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Bartus?= Date: Mon, 29 Feb 2016 23:23:31 +0100 Subject: [PATCH 4/4] [ticket/14487] Add missing use statement PHPBB3-14487 --- phpBB/phpbb/install/event/kernel_exception_subscriber.php | 1 + 1 file changed, 1 insertion(+) diff --git a/phpBB/phpbb/install/event/kernel_exception_subscriber.php b/phpBB/phpbb/install/event/kernel_exception_subscriber.php index c2960cb13c..60b7d9a400 100644 --- a/phpBB/phpbb/install/event/kernel_exception_subscriber.php +++ b/phpBB/phpbb/install/event/kernel_exception_subscriber.php @@ -21,6 +21,7 @@ use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface; use Symfony\Component\HttpKernel\KernelEvents; use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent; +use Symfony\Component\HttpFoundation\JsonResponse; /** * Exception handler for the installer