diff options
author | Robin Appelman <robin@icewind.nl> | 2022-03-18 18:37:38 +0300 |
---|---|---|
committer | Robin Appelman <robin@icewind.nl> | 2022-04-13 15:21:12 +0300 |
commit | 1823ab0316fd75a09bef6959a775ef47d48be530 (patch) | |
tree | 2feeac5743b827ad6a3dc385185d49d9f8ff683f | |
parent | 1292675de73eb2fd3b29ed713cbd152974cd6c9e (diff) |
chunked icap
Signed-off-by: Robin Appelman <robin@icewind.nl>
-rw-r--r-- | lib/ICAP/ICAPClient.php | 14 | ||||
-rw-r--r-- | lib/ICAP/ICAPRequest.php | 10 | ||||
-rw-r--r-- | lib/Scanner/ICAP.php | 27 |
3 files changed, 30 insertions, 21 deletions
diff --git a/lib/ICAP/ICAPClient.php b/lib/ICAP/ICAPClient.php index 1e872e2..313cbcd 100644 --- a/lib/ICAP/ICAPClient.php +++ b/lib/ICAP/ICAPClient.php @@ -29,8 +29,6 @@ class ICAPClient { private string $host; private int $port; - const USER_AGENT = 'NC-ICAP-CLIENT/0.5.0'; - /** * Constructor * @@ -56,7 +54,7 @@ class ICAPClient { ); if (!$stream) { - throw new \Exception( + throw new RuntimeException( "Cannot connect to \"tcp://{$this->host}:{$this->port}\": $errorMessage (code $errorCode)" ); } @@ -68,12 +66,12 @@ class ICAPClient { * Send REQMOD request * * @param string $service ICAP service - * @param array $body Request body data - * @return array Response array - * @throws RuntimeException + * @param array $headers + * @param string $requestHeader + * @return ICAPRequest Response array */ - public function reqmod(string $service, array $headers, string $requestHeader, int $bodyLength): ICAPRequest { + public function reqmod(string $service, array $headers, string $requestHeader): ICAPRequest { $stream = $this->connect(); - return new ICAPRequest($stream, $this->host, $service, 'REQMOD', $headers, $requestHeader, $bodyLength); + return new ICAPRequest($stream, $this->host, $service, 'REQMOD', $headers, $requestHeader); } } diff --git a/lib/ICAP/ICAPRequest.php b/lib/ICAP/ICAPRequest.php index 2bec713..f4c97b0 100644 --- a/lib/ICAP/ICAPRequest.php +++ b/lib/ICAP/ICAPRequest.php @@ -27,9 +27,9 @@ class ICAPRequest { const USER_AGENT = 'NC-ICAP-CLIENT/0.5.0'; /** @var resource */ - private $stream; + public $stream; - public function __construct($stream, string $host, string $service, string $method, array $headers, string $requestHeader, int $bodyLength) { + public function __construct($stream, string $host, string $service, string $method, array $headers, string $requestHeader) { $this->stream = $stream; if (!array_key_exists('Host', $headers)) { @@ -62,18 +62,16 @@ class ICAPRequest { $request .= "\r\n"; $request .= $requestHeader; - $request .= dechex($bodyLength); - $request .= "\r\n"; fwrite($this->stream, $request); } public function write(string $data) { - fwrite($this->stream, $data); + fwrite($this->stream, dechex(strlen($data)) . "\r\n" . $data . "\r\n"); } public function finish(): array { - fwrite($this->stream, "\r\n0\r\n\r\n"); + fwrite($this->stream, "0\r\n\r\n"); return (new ResponseParser())->read_response($this->stream); } } diff --git a/lib/Scanner/ICAP.php b/lib/Scanner/ICAP.php index 5a0c88b..2a0efe9 100644 --- a/lib/Scanner/ICAP.php +++ b/lib/Scanner/ICAP.php @@ -25,6 +25,7 @@ namespace OCA\Files_Antivirus\Scanner; use OCA\Files_Antivirus\AppConfig; use OCA\Files_Antivirus\ICAP\ICAPClient; +use OCA\Files_Antivirus\ICAP\ICAPRequest; use OCA\Files_Antivirus\Status; use OCA\Files_Antivirus\StatusFactory; use OCP\Http\Client\IClientService; @@ -32,6 +33,7 @@ use OCP\ILogger; class ICAP extends ScannerBase { private ICAPClient $icapClient; + private ?ICAPRequest $request; public function __construct( AppConfig $config, @@ -52,17 +54,28 @@ class ICAP extends ScannerBase { public function initScanner() { parent::initScanner(); $this->writeHandle = fopen("php://temp", 'w+'); + $this->request = $this->icapClient->reqmod('req', [ + 'Allow' => 204, + ], "PUT / HTTP/1.0\r\nHost: 127.0.0.1\r\n\r\n"); } - protected function scanBuffer() { + protected function writeChunk($chunk) { + if (ftell($this->writeHandle) > 1024 * 1024) { + $this->flushBuffer(); + } + parent::writeChunk($chunk); + } + + private function flushBuffer() { rewind($this->writeHandle); $data = stream_get_contents($this->writeHandle); + $this->request->write($data); + $this->writeHandle = fopen("php://temp", 'w+'); + } - $request = $this->icapClient->reqmod('req', [ - 'Allow' => 204 - ], "PUT / HTTP/1.0\r\nHost: 127.0.0.1\r\n\r\n", strlen($data)); - $request->write($data); - $response = $request->finish(); + protected function scanBuffer() { + $this->flushBuffer(); + $response = $this->request->finish(); $code = (int)$response['protocol']['code'] ?? 500; $this->status->setNumericStatus(Status::SCANRESULT_CLEAN); @@ -80,7 +93,7 @@ class ICAP extends ScannerBase { $this->status->setNumericStatus(Status::SCANRESULT_INFECTED); } } else { - throw new \RuntimeException('AV failed!'); + throw new \RuntimeException('Invalid response from ICAP server'); } } |