From f14a6d177c29409b104c315ab01bafab2ee924c1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Philipp=20Sch=C3=BCttl=C3=B6ffel?=
 <schuettloeffel@zqs.uni-hannover.de>
Date: Mon, 13 Jan 2025 13:50:36 +0000
Subject: [PATCH] =?UTF-8?q?Resolve=20"Timeout=20f=C3=BCr=20HTTP=20Requests?=
 =?UTF-8?q?=20in=20Ilias-Schnittstelle=20implementieren"?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Closes #5014

Merge request studip/studip!3768
---
 app/controllers/admin/ilias_interface.php     |  8 ++++
 .../admin/ilias_interface/edit_server.php     | 12 ++++-
 lib/ilias_interface/ConnectedIlias.php        | 44 +++++++++++++++++--
 lib/ilias_interface/IliasSoap.php             | 24 +++++++++-
 lib/ilias_interface/StudipSoapClient.php      |  4 +-
 5 files changed, 82 insertions(+), 10 deletions(-)

diff --git a/app/controllers/admin/ilias_interface.php b/app/controllers/admin/ilias_interface.php
index 543324ec9ca..38fa8fafd5f 100644
--- a/app/controllers/admin/ilias_interface.php
+++ b/app/controllers/admin/ilias_interface.php
@@ -130,6 +130,8 @@ class Admin_IliasInterfaceController extends AuthenticatedController
                             'name' => '',
                             'version' => '',
                             'url' => _('https://<URL zur ILIAS-Installation>'),
+                            'http_connection_timeout' => 1,
+                            'http_request_timeout' => 3,
                             'client' => '',
                             'ldap_enable' => '',
                             'reconnect_accounts' => false,
@@ -171,6 +173,8 @@ class Admin_IliasInterfaceController extends AuthenticatedController
                 if (count($info)) {
                     $this->valid_url = true;
                     $this->ilias_config['url'] = Request::get('ilias_url');
+                    $this->ilias_config['http_connection_timeout'] = (int) Request::get('ilias_http_connection_timeout');
+                    $this->ilias_config['http_request_timeout'] = (int) Request::get('ilias_http_request_timeout');
                     if ($info['version']) {
                         $this->ilias_version = $info['version'];
                         $this->ilias_version_date = $info['version_date'];
@@ -220,6 +224,8 @@ class Admin_IliasInterfaceController extends AuthenticatedController
             if (Request::get('ilias_name')) {
                 $this->ilias_config['name'] = Request::get('ilias_name');
                 $this->ilias_config['url'] = Request::get('ilias_url');
+                $this->ilias_config['http_connection_timeout'] = (int) Request::get('ilias_http_connection_timeout');
+                $this->ilias_config['http_request_timeout'] = (int) Request::get('ilias_http_request_timeout');
             }
             $info = ConnectedIlias::getIliasInfo($this->ilias_config['url']);
             if (count($info)) {
@@ -298,6 +304,8 @@ class Admin_IliasInterfaceController extends AuthenticatedController
                     $this->ilias_configs[$index]['version'] = Request::get('ilias_version');
                 }
                 $this->ilias_configs[$index]['url'] = Request::get('ilias_url');
+                $this->ilias_configs[$index]['http_connection_timeout'] = (int) Request::get('ilias_http_connection_timeout');
+                $this->ilias_configs[$index]['http_request_timeout'] = (int) Request::get('ilias_http_request_timeout');
                 if (Request::getInstance()->offsetExists('ilias_client')) {
                     $this->ilias_configs[$index]['client'] = Request::get('ilias_client');
                 }
diff --git a/app/views/admin/ilias_interface/edit_server.php b/app/views/admin/ilias_interface/edit_server.php
index 7e72d4ccebc..18c648a2b2d 100644
--- a/app/views/admin/ilias_interface/edit_server.php
+++ b/app/views/admin/ilias_interface/edit_server.php
@@ -42,6 +42,14 @@
         <span class="required">  <?= _('URL') ?></span>
         <input type="text" name="ilias_url" size="50" maxlength="255" value="<?= $ilias_config['url'] ?>" required>
     </label>
+    <label>
+        <span class="required">  <?= _('HTTP Connection Timeout (in Sekunden)') ?></span>
+        <input type="number" name="ilias_http_connection_timeout" value="<?= $ilias_config['http_connection_timeout'] ?? 1 ?>" required>
+    </label>
+    <label>
+        <span class="required">  <?= _('HTTP Request Timeout (in Sekunden)') ?></span>
+        <input type="number" name="ilias_http_request_timeout" value="<?= $ilias_config['http_request_timeout'] ?? 3 ?>" required>
+    </label>
     <? if ($valid_url) : ?>
         <label for="ilias_version">
             <span class="required"><?= _('ILIAS Version') ?></span>
@@ -54,10 +62,10 @@
         </label>
         <label>
             <span class="required">  <?= _('Name des ILIAS-Mandanten') ?></span>
-            <? if (count($ilias_clients) == 1) : ?>
+            <? if (isset($ilias_clients) && count($ilias_clients) == 1) : ?>
                 <input type="hidden" name="ilias_client" value="<?=htmlReady($ilias_clients[0])?>">
                 <div><?=htmlReady($ilias_clients[0])?></div>
-            <? elseif (count($ilias_clients) > 1) : ?>
+            <? elseif (isset($ilias_clients) && count($ilias_clients) > 1) : ?>
                 <select name="ilias_client">
                 <? foreach ($ilias_clients as $client_name) : ?>
                     <option value="<?=htmlReady($client_name)?>" <?= $client_name == $ilias_config['client'] ? ' selected' : ''?>><?=htmlReady($client_name)?></option>
diff --git a/lib/ilias_interface/ConnectedIlias.php b/lib/ilias_interface/ConnectedIlias.php
index a917e1a797e..45f5e3dcfcb 100644
--- a/lib/ilias_interface/ConnectedIlias.php
+++ b/lib/ilias_interface/ConnectedIlias.php
@@ -82,7 +82,16 @@ class ConnectedIlias
         $this->ilias_int_version = $this->getIntVersion($this->ilias_config['version']);
 
         // init soap client
-        $this->soap_client = new IliasSoap($this->index, $this->ilias_config['url'].'/webservice/soap/server.php?wsdl', $this->ilias_config['client'], $this->ilias_int_version, $this->ilias_config['admin'], $this->ilias_config['admin_pw']);
+        $this->soap_client = new IliasSoap(
+            $this->index,
+            $this->ilias_config['url'] . '/webservice/soap/server.php?wsdl',
+            $this->ilias_config['client'],
+            $this->ilias_int_version,
+            $this->ilias_config['admin'],
+            $this->ilias_config['admin_pw'],
+            $this->ilias_config['http_connection_timeout'],
+            $this->ilias_config['http_request_timeout']
+        );
         $this->soap_client->setCachingStatus($this->ilias_interface_config['cache']);
 
         // init current user (only if ILIAS installation is active)
@@ -154,14 +163,34 @@ class ConnectedIlias
     public static function getIliasInfo($url)
     {
         $info = [];
+
+        $stream_context = get_default_http_stream_context($url);
+        stream_context_set_option(
+            $stream_context,
+            'http',
+            'timeout',
+            3
+        );
+
         // check if url exists
-        $check = @get_headers($url . 'login.php');
+        $check = @get_headers($url . 'login.php', false, $stream_context);
         if (strpos($check[0], '200') === false) {
             return $info;
         } else {
             $info['url'] = $url;
         }
-        $soap_client = new IliasSoap('new', $url.'/webservice/soap/server.php?wsdl');
+
+        $soap_client = new IliasSoap(
+            'new',
+            $url . '/webservice/soap/server.php?wsdl',
+            '',
+            '',
+            '',
+            '',
+            1,
+            3
+        );
+
         $soap_client->setCachingStatus(false);
         if ($client_info = $soap_client->getInstallationInfoXML()) {
             $info = array_merge($info, $client_info);
@@ -223,7 +252,14 @@ class ConnectedIlias
         }
 
         // check if url exists
-        $check = @get_headers($this->ilias_config['url'] . 'webservice/soap/server.php');
+        $stream_context = get_default_http_stream_context($this->ilias_config['url']);
+        stream_context_set_option(
+            $stream_context,
+            'http',
+            'timeout',
+            $this->ilias_config['http_request_timeout']
+        );
+        $check = @get_headers($this->ilias_config['url'] . 'webservice/soap/server.php', false, $stream_context);
         if (strpos($check[0], '200') === false) {
             $this->error[] = sprintf(_('Die URL "%s" ist nicht erreichbar.'), $this->ilias_config['url']);
             return false;
diff --git a/lib/ilias_interface/IliasSoap.php b/lib/ilias_interface/IliasSoap.php
index 91681955020..6b6226db72a 100644
--- a/lib/ilias_interface/IliasSoap.php
+++ b/lib/ilias_interface/IliasSoap.php
@@ -44,7 +44,7 @@ class IliasSoap extends StudipSoapClient
      * @param string $admin_login ILIAS admin account login
      * @param string $admin_password ILIAS admin account password
      */
-    public function __construct($index, $soap_path, $ilias_client = '', $ilias_version = '', $admin_login = '', $admin_password = '')
+    public function __construct($index, $soap_path, $ilias_client = '', $ilias_version = '', $admin_login = '', $admin_password = '', $http_connection_timeout = NULL, $http_request_timeout = NULL)
     {
         $this->index = $index;
         $this->ilias_client = $ilias_client;
@@ -53,7 +53,27 @@ class IliasSoap extends StudipSoapClient
         $this->admin_password = $admin_password;
         $this->separator_string = " / ";
 
-        parent::__construct($soap_path);
+        $stream_context = get_default_http_stream_context($soap_path);
+
+        if (is_int($http_request_timeout)) {
+            stream_context_set_option(
+                $stream_context,
+                'http',
+                'timeout',
+                $http_request_timeout
+            );
+        }
+
+        $options = [
+            'trace' => 0,
+            'stream_context' => $stream_context
+        ];
+
+        if (is_int($http_connection_timeout)) {
+            $options['connection_timeout'] = $http_connection_timeout;
+        }
+
+        parent::__construct($soap_path, $options);
 
         $this->user_type = "admin";
 
diff --git a/lib/ilias_interface/StudipSoapClient.php b/lib/ilias_interface/StudipSoapClient.php
index 6a22f86243f..a92d1e5325e 100644
--- a/lib/ilias_interface/StudipSoapClient.php
+++ b/lib/ilias_interface/StudipSoapClient.php
@@ -15,10 +15,10 @@ class StudipSoapClient
     public $error;
     public $faultstring;
 
-    function __construct($path)
+    function __construct($path, $options = ['trace' => 0])
     {
         try {
-            $this->soap_client = new SoapClient($path, ['trace' => 0]);
+            $this->soap_client = new SoapClient($path, $options);
         } catch (SoapFault $fault) {
             $this->error = "Soap Constructor Error " . $fault->faultcode . ": ".$fault->faultstring;
         }
-- 
GitLab