feat: allow HEAD requests and add test for it

This commit is contained in:
Chirag Aggarwal
2025-08-12 16:14:15 +05:30
parent f81fd16d26
commit f8afbbbf3c
3 changed files with 64 additions and 2 deletions
+1 -1
View File
@@ -963,7 +963,7 @@ services:
hostname: exc1
<<: *x-logging
stop_signal: SIGINT
image: openruntimes/executor:0.7.22
image: openruntimes/executor:executor-local
restart: unless-stopped
networks:
- appwrite
+17 -1
View File
@@ -216,6 +216,19 @@ class Client
return $len;
});
// Special handling for HEAD requests
if ($method === self::METHOD_HEAD) {
curl_setopt($ch, CURLOPT_NOBODY, true); // This is crucial for HEAD requests
curl_setopt($ch, CURLOPT_HEADER, false); // We handle headers via HEADERFUNCTION
} else {
curl_setopt($ch, CURLOPT_NOBODY, false);
}
// Only set POST fields for non-GET and non-HEAD requests
if ($method != self::METHOD_GET && $method != self::METHOD_HEAD) {
curl_setopt($ch, CURLOPT_POSTFIELDS, $query);
}
if ($method != self::METHOD_GET) {
curl_setopt($ch, CURLOPT_POSTFIELDS, $query);
}
@@ -229,7 +242,7 @@ class Client
$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)) {
@@ -255,6 +268,9 @@ class Client
$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*/)) {
@@ -74,6 +74,52 @@ class FunctionsCustomClientTest extends Scope
$this->cleanupFunction($functionId);
}
public function testCreateHeadExecution()
{
/**
* Test for SUCCESS
*/
$functionId = $this->setupFunction([
'functionId' => ID::unique(),
'name' => 'Test',
'execute' => [Role::user($this->getUser()['$id'])->toString()],
'runtime' => 'node-22',
'entrypoint' => 'index.js',
'events' => [
'users.*.create',
'users.*.delete',
],
'timeout' => 10,
]);
$this->setupDeployment($functionId, [
'code' => $this->packageFunction('basic'),
'activate' => true
]);
// Deny create async execution as guest
$execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], [
'async' => true,
]);
$this->assertEquals(401, $execution['headers']['status-code']);
// Allow create async execution as user
$execution = $this->client->call(Client::METHOD_HEAD, '/functions/' . $functionId . '/executions', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'async' => true,
]);
fwrite(STDOUT, json_encode($execution, JSON_PRETTY_PRINT));
$this->assertEquals(200, $execution['headers']['status-code']);
$this->assertEmpty($execution['body']);
$this->cleanupFunction($functionId);
}
public function testCreateCustomExecution(): array
{
/**