From 999cbb2ee842a26fba5c0040fb805574fe3cb306 Mon Sep 17 00:00:00 2001 From: Troy Davisson Date: Mon, 23 Oct 2017 13:54:51 -0400 Subject: [PATCH] Automatically re-login if session issue occurs mid-process (#175) * Automatically re-login if session issue occurs mid-process * Added changelog entries --- docs/changelog.md | 2 ++ src/Session.php | 87 ++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 76 insertions(+), 13 deletions(-) diff --git a/docs/changelog.md b/docs/changelog.md index b40f6e7..6f5a103 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -3,6 +3,8 @@ _Release TBD_ - Fix RETS 1.8 login response parsing for optional info-token-type +- Support automatic re-login if session issue occurs mid-process +- New option `disable_auto_retry` (bool) added to optionally disable automatic re-login behavior ## 2.4 diff --git a/src/Session.php b/src/Session.php index 63ba0a5..5fcc082 100644 --- a/src/Session.php +++ b/src/Session.php @@ -3,6 +3,7 @@ use GuzzleHttp\Client; use GuzzleHttp\Cookie\CookieJar; use GuzzleHttp\Cookie\CookieJarInterface; +use GuzzleHttp\Exception\ClientException; use Illuminate\Container\Container; use Illuminate\Support\Collection; use PHRETS\Exceptions\CapabilityUnavailable; @@ -300,11 +301,12 @@ public function Disconnect() /** * @param $capability * @param array $options - * @throws Exceptions\CapabilityUnavailable - * @throws Exceptions\RETSException + * @param bool $is_retry * @return ResponseInterface + * @throws CapabilityUnavailable + * @throws RETSException */ - protected function request($capability, $options = []) + protected function request($capability, $options = [], $is_retry = false) { $url = $this->capabilities->get($capability); @@ -328,13 +330,46 @@ protected function request($capability, $options = []) $this->last_request_url = $url; } - /** @var ResponseInterface $response */ - if ($this->configuration->readOption('use_post_method')) { - $this->debug('Using POST method per use_post_method option'); - $query = (array_key_exists('query', $options)) ? $options['query'] : null; - $response = $this->client->request('POST', $url, array_merge($options, ['form_params' => $query])); - } else { - $response = $this->client->request('GET', $url, $options); + try { + /** @var ResponseInterface $response */ + if ($this->configuration->readOption('use_post_method')) { + $this->debug('Using POST method per use_post_method option'); + $query = (array_key_exists('query', $options)) ? $options['query'] : null; + $response = $this->client->request('POST', $url, array_merge($options, ['form_params' => $query])); + } else { + $response = $this->client->request('GET', $url, $options); + } + } catch (ClientException $e) { + $this->debug("ClientException: " . $e->getCode() . ": " . $e->getMessage()); + + if ($e->getCode() != 401) { + // not an Unauthorized error, so bail + throw $e; + } + + if ($capability == 'Login') { + // unauthorized on a Login request, so bail + throw $e; + } + + if ($is_retry) { + // this attempt was already a retry, so let's stop here + $this->debug("Request retry failed. Won't retry again"); + throw $e; + } + + if ($this->getConfiguration()->readOption('disable_auto_retry')) { + // this attempt was already a retry, so let's stop here + $this->debug("Re-logging in disabled. Won't retry"); + throw $e; + } + + $this->debug("401 Unauthorized exception returned"); + $this->debug("Logging in again and retrying request"); + // see if logging in again and retrying the request works + $this->Login(); + + return $this->request($capability, $options, true); } $response = new \PHRETS\Http\Response($response); @@ -349,21 +384,47 @@ protected function request($capability, $options = []) } } } - + + $this->debug('Response: HTTP ' . $response->getStatusCode()); + if (preg_match('/text\/xml/', $response->getHeader('Content-Type')) and $capability != 'GetObject') { $parser = $this->grab(Strategy::PARSER_XML); $xml = $parser->parse($response); + if ($xml and isset($xml['ReplyCode'])) { $rc = (string)$xml['ReplyCode']; + + if ($rc == "20037" and $capability != 'Login') { + // must make Login request again. let's handle this automatically + + if ($this->getConfiguration()->readOption('disable_auto_retry')) { + // this attempt was already a retry, so let's stop here + $this->debug("Re-logging in disabled. Won't retry"); + throw new RETSException($xml['ReplyText'], (int)$xml['ReplyCode']); + } + + if ($is_retry) { + // this attempt was already a retry, so let's stop here + $this->debug("Request retry failed. Won't retry again"); + // let this error fall through to the more generic handling below + } else { + $this->debug("RETS 20037 re-auth requested"); + $this->debug("Logging in again and retrying request"); + // see if logging in again and retrying the request works + $this->Login(); + + return $this->request($capability, $options, true); + } + } + // 20201 - No records found - not exception worthy in my mind // 20403 - No objects found - not exception worthy in my mind - if ($rc != "0" and $rc != "20201" and $rc != "20403") { + if (!in_array($rc, [0, 20201, 20403])) { throw new RETSException($xml['ReplyText'], (int)$xml['ReplyCode']); } } } - $this->debug('Response: HTTP ' . $response->getStatusCode()); return $response; }