From 6bb6983035d56c4a5d5de30a5cad9ea914472c3e Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal Date: Tue, 12 Aug 2025 09:57:34 +0530 Subject: [PATCH 1/7] chore: allow head method requests in /executions --- app/controllers.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers.php b/app/controllers.php index d6db42a..86c87aa 100644 --- a/app/controllers.php +++ b/app/controllers.php @@ -150,7 +150,7 @@ ->param('runtimeId', '', new Text(64), 'The runtimeID to execute.') ->param('body', '', new Text(20971520), 'Data to be forwarded to the function, this is user specified.', true) ->param('path', '/', new Text(2048), 'Path from which execution comes.', true) - ->param('method', 'GET', new Whitelist(['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'], true), 'Path from which execution comes.', true) + ->param('method', 'GET', new Whitelist(['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS', 'HEAD'], true), 'Path from which execution comes.', true) ->param('headers', [], new AnyOf([new Text(65535), new Assoc()], AnyOf::TYPE_MIXED), 'Headers passed into runtime.', true) ->param('timeout', 15, new Integer(true), 'Function maximum execution time in seconds.', true) // Runtime-related From 1e3c4dfb4742dd3bc48bd91275ee87687957582a Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal Date: Tue, 12 Aug 2025 13:37:14 +0530 Subject: [PATCH 2/7] update ci --- .github/workflows/tests.yml | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index ab7933b..3f2c77a 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -29,4 +29,16 @@ jobs: - name: Run Tests run: | - docker run --rm -v $PWD:/app -v /tmp:/tmp -v /var/run/docker.sock:/var/run/docker.sock --network executor_runtimes -w /app phpswoole/swoole:5.1.2-php8.3-alpine sh -c "apk update && apk add docker-cli zip unzip && composer install --profile --ignore-platform-reqs && composer test" + docker run --rm \ + -v $PWD:/app \ + -v /tmp:/tmp \ + -v /var/run/docker.sock:/var/run/docker.sock \ + --network executor_runtimes \ + -w /app \ + phpswoole/swoole:5.1.2-php8.3-alpine \ + sh -c " + apk update && \ + apk add docker-cli zip unzip && \ + composer install --profile --ignore-platform-reqs && \ + composer test + " From 8d4cfa45be09e25b5255e898ba9988a685978734 Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal Date: Tue, 12 Aug 2025 15:57:54 +0530 Subject: [PATCH 3/7] chore: ignore partial file error --- src/Executor/Runner/Docker.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Executor/Runner/Docker.php b/src/Executor/Runner/Docker.php index e695fad..97efce6 100644 --- a/src/Executor/Runner/Docker.php +++ b/src/Executor/Runner/Docker.php @@ -1148,7 +1148,10 @@ public function createExecution( } while ((++$attempts < $retryAttempts) || (\microtime(true) - $startTime < $timeout)); // Error occurred - if ($executionResponse['errNo'] !== CURLE_OK) { + if ( + $executionResponse['errNo'] !== CURLE_OK && + $executionResponse['errNo'] !== CURLE_PARTIAL_FILE // Head request may return partial file + ) { $log->addExtra('activeRuntime', $this->activeRuntimes->get($runtimeName)); $log->addExtra('error', $executionResponse['error']); $log->addTag('hostname', $hostname); From 1419e359aaac16113eb6f69b861556b3fa82a720 Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal Date: Tue, 12 Aug 2025 16:30:31 +0530 Subject: [PATCH 4/7] add test --- tests/ExecutorTest.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/ExecutorTest.php b/tests/ExecutorTest.php index 6156c98..d23f88f 100644 --- a/tests/ExecutorTest.php +++ b/tests/ExecutorTest.php @@ -547,6 +547,14 @@ public function testExecute(): void $this->assertEquals(200, $response['headers']['status-code']); $this->assertStringStartsWith('multipart/form-data', $response['headers']['content-type']); + /** Execute HEAD request */ + $response = $this->client->call(Client::METHOD_HEAD, '/runtimes/test-exec-coldstart/executions'); + + $this->assertEquals(200, $response['headers']['status-code']); + // For HEAD requests, the body should be empty but headers should be present + $this->assertEmpty($response['body']); + $this->assertArrayHasKey('content-type', $response['headers']); + /** Delete runtime */ $response = $this->client->call(Client::METHOD_DELETE, '/runtimes/test-exec-coldstart', [], []); $this->assertEquals(200, $response['headers']['status-code']); From 9c47a90a1829ccb53cd3f798fe2c1f19838b3e36 Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal Date: Tue, 12 Aug 2025 16:48:57 +0530 Subject: [PATCH 5/7] update client --- tests/Client.php | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/tests/Client.php b/tests/Client.php index 6014981..da834a0 100644 --- a/tests/Client.php +++ b/tests/Client.php @@ -131,7 +131,14 @@ public function call(string $method, string $path = '', array $headers = [], arr return $len; }); - if ($method != self::METHOD_GET) { + if ($method === self::METHOD_HEAD) { + curl_setopt($ch, CURLOPT_NOBODY, true); // This is crucial for HEAD requests + curl_setopt($ch, CURLOPT_HEADER, false); + } else { + curl_setopt($ch, CURLOPT_NOBODY, false); + } + + if ($method != self::METHOD_GET && $method != self::METHOD_HEAD) { curl_setopt($ch, CURLOPT_POSTFIELDS, $query); } @@ -151,7 +158,7 @@ public function call(string $method, string $path = '', array $headers = [], arr $responseType = $responseHeaders['content-type'] ?? ''; $responseStatus = curl_getinfo($ch, CURLINFO_HTTP_CODE); - if ($decode) { + if ($decode && $method !== self::METHOD_HEAD) { $strpos = strpos($responseType, ';'); $strpos = \is_bool($strpos) ? \strlen($responseType) : $strpos; switch (substr($responseType, 0, $strpos)) { @@ -177,6 +184,9 @@ public function call(string $method, string $path = '', array $headers = [], arr $json = null; break; } + } elseif ($method === self::METHOD_HEAD) { + // For HEAD requests, always set body to empty string regardless of decode flag + $responseBody = ''; } if ((curl_errno($ch)/* || 200 != $responseStatus*/)) { From a9d4349b9eed2a1d546ea1aed892a741bb081a0a Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal Date: Tue, 12 Aug 2025 16:49:48 +0530 Subject: [PATCH 6/7] lint --- tests/Client.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Client.php b/tests/Client.php index da834a0..5cf3c36 100644 --- a/tests/Client.php +++ b/tests/Client.php @@ -184,7 +184,7 @@ public function call(string $method, string $path = '', array $headers = [], arr $json = null; break; } - } elseif ($method === self::METHOD_HEAD) { + } elseif ($method === self::METHOD_HEAD) { // For HEAD requests, always set body to empty string regardless of decode flag $responseBody = ''; } From 6445f4dfc2cb783e1ce091b5bca11e6d3692c63d Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal Date: Tue, 12 Aug 2025 16:53:57 +0530 Subject: [PATCH 7/7] check for 404 --- tests/ExecutorTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ExecutorTest.php b/tests/ExecutorTest.php index d23f88f..4592a4a 100644 --- a/tests/ExecutorTest.php +++ b/tests/ExecutorTest.php @@ -550,7 +550,7 @@ public function testExecute(): void /** Execute HEAD request */ $response = $this->client->call(Client::METHOD_HEAD, '/runtimes/test-exec-coldstart/executions'); - $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals(404, $response['headers']['status-code']); // not found // For HEAD requests, the body should be empty but headers should be present $this->assertEmpty($response['body']); $this->assertArrayHasKey('content-type', $response['headers']);