From 538c7da446907a4f910275ae6ead98b39420cd71 Mon Sep 17 00:00:00 2001 From: Marcel Pociot Date: Sat, 17 Oct 2020 21:07:29 +0200 Subject: [PATCH] Better memory management for binary responses. Fixes #140 --- app/Logger/LoggedRequest.php | 123 ++------------------------ app/Logger/LoggedResponse.php | 160 ++++++++++++++++++++++++++++++++++ 2 files changed, 167 insertions(+), 116 deletions(-) create mode 100644 app/Logger/LoggedResponse.php diff --git a/app/Logger/LoggedRequest.php b/app/Logger/LoggedRequest.php index 0932c62..d1626e7 100644 --- a/app/Logger/LoggedRequest.php +++ b/app/Logger/LoggedRequest.php @@ -19,11 +19,8 @@ class LoggedRequest implements \JsonSerializable /** @var Request */ protected $parsedRequest; - /** @var string */ - protected $rawResponse; - - /** @var Response */ - protected $parsedResponse; + /** @var LoggedResponse */ + protected $response; /** @var string */ protected $id; @@ -71,22 +68,8 @@ class LoggedRequest implements \JsonSerializable ], ]; - if ($this->parsedResponse) { - $logBody = $this->shouldReturnBody(); - - try { - $body = $logBody ? $this->parsedResponse->getBody() : ''; - } catch (\Exception $e) { - $body = ''; - } - - $data['response'] = [ - 'raw' => $logBody ? $this->rawResponse : 'SKIPPED BY CONFIG OR BINARY RESPONSE', - 'status' => $this->parsedResponse->getStatusCode(), - 'headers' => $this->parsedResponse->getHeaders()->toArray(), - 'reason' => $this->parsedResponse->getReasonPhrase(), - 'body' => $logBody ? $body : 'SKIPPED BY CONFIG OR BINARY RESPONSE', - ]; + if ($this->response) { + $data['response'] = $this->response->toArray(); } return $data; @@ -107,96 +90,6 @@ class LoggedRequest implements \JsonSerializable return preg_match('~[^\x20-\x7E\t\r\n]~', $string) > 0; } - protected function shouldReturnBody(): bool - { - if ($this->skipByStatus()) { - return false; - } - - if ($this->skipByContentType()) { - return false; - } - - if ($this->skipByExtension()) { - return false; - } - - if ($this->skipBySize()) { - return false; - } - - $header = $this->parsedResponse->getHeaders()->get('Content-Type'); - $contentType = $header ? $header->getMediaType() : ''; - $patterns = [ - 'application/json', - 'text/*', - '*javascript*', - ]; - - return Str::is($patterns, $contentType); - } - - protected function skipByStatus(): bool - { - if (empty(config()->get('expose.skip_body_log.status'))) { - return false; - } - - return Str::is(config()->get('expose.skip_body_log.status'), $this->parsedResponse->getStatusCode()); - } - - protected function skipByContentType(): bool - { - if (empty(config()->get('expose.skip_body_log.content_type'))) { - return false; - } - - $header = $this->parsedResponse->getHeaders()->get('Content-Type'); - $contentType = $header ? $header->getMediaType() : ''; - - return Str::is(config()->get('expose.skip_body_log.content_type'), $contentType); - } - - protected function skipByExtension(): bool - { - if (empty(config()->get('expose.skip_body_log.extension'))) { - return false; - } - - return Str::is(config()->get('expose.skip_body_log.extension'), $this->parsedRequest->getUri()->getPath()); - } - - protected function skipBySize(): bool - { - $configSize = $this->getConfigSize(config()->get('expose.skip_body_log.size', '1MB')); - $contentLength = $this->parsedResponse->getHeaders()->get('Content-Length'); - - if (! $contentLength) { - return false; - } - - $contentSize = $contentLength->getFieldValue() ?? 0; - - return $contentSize > $configSize; - } - - protected function getConfigSize(string $size): int - { - $units = ['B', 'KB', 'MB', 'GB']; - $number = substr($size, 0, -2); - $suffix = strtoupper(substr($size, -2)); - - // B or no suffix - if (is_numeric(substr($suffix, 0, 1))) { - return preg_replace('/[^\d]/', '', $size); - } - - // if we have an error in the input, default to GB - $exponent = array_flip($units)[$suffix] ?? 5; - - return $number * (1024 ** $exponent); - } - public function getRequest() { return $this->parsedRequest; @@ -204,9 +97,7 @@ class LoggedRequest implements \JsonSerializable public function setResponse(string $rawResponse, Response $response) { - $this->parsedResponse = $response; - - $this->rawResponse = $rawResponse; + $this->response = new LoggedResponse($rawResponse, $response, $this->getRequest()); if (is_null($this->stopTime)) { $this->stopTime = now(); @@ -223,9 +114,9 @@ class LoggedRequest implements \JsonSerializable return $this->rawRequest; } - public function getResponse(): ?Response + public function getResponse(): ?LoggedResponse { - return $this->parsedResponse; + return $this->response; } public function getPostData() diff --git a/app/Logger/LoggedResponse.php b/app/Logger/LoggedResponse.php new file mode 100644 index 0000000..a5454a0 --- /dev/null +++ b/app/Logger/LoggedResponse.php @@ -0,0 +1,160 @@ +rawResponse = $rawResponse; + $this->response = $response; + $this->request = $request; + + if (! $this->shouldReturnBody()) { + $this->rawResponse = 'SKIPPED BY CONFIG OR BINARY RESPONSE'; + $this->body = 'SKIPPED BY CONFIG OR BINARY RESPONSE'; + } else { + try { + $this->body = $response->getBody(); + } catch (\Exception $e) { + $this->body = ''; + } + } + + $this->statusCode = $response->getStatusCode(); + $this->reasonPhrase = $response->getReasonPhrase(); + $this->headers = $response->getHeaders()->toArray(); + + $this->response = null; + $this->request = null; + } + + protected function shouldReturnBody(): bool + { + if ($this->skipByStatus()) { + return false; + } + + if ($this->skipByContentType()) { + return false; + } + + if ($this->skipByExtension()) { + return false; + } + + if ($this->skipBySize()) { + return false; + } + + $header = $this->response->getHeaders()->get('Content-Type'); + $contentType = $header ? $header->getMediaType() : ''; + $patterns = [ + 'application/json', + 'text/*', + '*javascript*', + ]; + + return Str::is($patterns, $contentType); + } + + protected function skipByStatus(): bool + { + if (empty(config()->get('expose.skip_body_log.status'))) { + return false; + } + + return Str::is(config()->get('expose.skip_body_log.status'), $this->response->getStatusCode()); + } + + protected function skipByContentType(): bool + { + if (empty(config()->get('expose.skip_body_log.content_type'))) { + return false; + } + + $header = $this->response->getHeaders()->get('Content-Type'); + $contentType = $header ? $header->getMediaType() : ''; + + return Str::is(config()->get('expose.skip_body_log.content_type'), $contentType); + } + + protected function skipByExtension(): bool + { + if (empty(config()->get('expose.skip_body_log.extension'))) { + return false; + } + + return Str::is(config()->get('expose.skip_body_log.extension'), $this->request->getUri()->getPath()); + } + + protected function skipBySize(): bool + { + $configSize = $this->getConfigSize(config()->get('expose.skip_body_log.size', '1MB')); + $contentLength = $this->response->getHeaders()->get('Content-Length'); + + if (! $contentLength) { + return false; + } + + $contentSize = $contentLength->getFieldValue() ?? 0; + + return $contentSize > $configSize; + } + + protected function getConfigSize(string $size): int + { + $units = ['B', 'KB', 'MB', 'GB']; + $number = substr($size, 0, -2); + $suffix = strtoupper(substr($size, -2)); + + // B or no suffix + if (is_numeric(substr($suffix, 0, 1))) { + return preg_replace('/[^\d]/', '', $size); + } + + // if we have an error in the input, default to GB + $exponent = array_flip($units)[$suffix] ?? 5; + + return $number * (1024 ** $exponent); + } + + public function getStatusCode() + { + return $this->statusCode; + } + + public function getReasonPhrase() + { + return $this->reasonPhrase; + } + + public function toArray() + { + return [ + 'raw' => $this->rawResponse, + 'status' => $this->statusCode, + 'headers' => $this->headers, + 'reason' => $this->reasonPhrase, + 'body' => $this->body, + ]; + } +}