From b86aca6f74c312b5a84a6566ac71e33ec3ad191a Mon Sep 17 00:00:00 2001 From: Zach Borboa Date: Sat, 3 Dec 2022 12:23:34 -0800 Subject: [PATCH] Add Curl::diagnose() HTTP method check matches methods allowed --- src/Curl/Curl.php | 25 ++++++++++++ tests/PHPCurlClass/PHPCurlClassTest.php | 52 +++++++++++++++++++++++++ tests/PHPCurlClass/server.php | 18 +++++++-- 3 files changed, 91 insertions(+), 4 deletions(-) diff --git a/src/Curl/Curl.php b/src/Curl/Curl.php index 96f59bd..b4e93fc 100644 --- a/src/Curl/Curl.php +++ b/src/Curl/Curl.php @@ -1581,6 +1581,31 @@ class Curl '(CURLOPT_VERBOSE was enabled or CURLINFO_HEADER_OUT was disabled).' . "\n"; } + if (isset($this->responseHeaders['allow'])) { + $allowed_request_types = array_map(function ($v) { + return trim($v); + }, explode(',', strtoupper($this->responseHeaders['allow']))); + + $request_types = array( + 'DELETE' => $this->getOpt(CURLOPT_CUSTOMREQUEST) === 'DELETE', + 'GET' => $this->getOpt(CURLOPT_CUSTOMREQUEST) === 'GET' || $this->getOpt(CURLOPT_HTTPGET), + 'HEAD' => $this->getOpt(CURLOPT_CUSTOMREQUEST) === 'HEAD', + 'OPTIONS' => $this->getOpt(CURLOPT_CUSTOMREQUEST) === 'OPTIONS', + 'PATCH' => $this->getOpt(CURLOPT_CUSTOMREQUEST) === 'PATCH', + 'POST' => $this->getOpt(CURLOPT_CUSTOMREQUEST) === 'POST' || $this->getOpt(CURLOPT_POST), + 'PUT' => $this->getOpt(CURLOPT_CUSTOMREQUEST) === 'PUT', + 'SEARCH' => $this->getOpt(CURLOPT_CUSTOMREQUEST) === 'SEARCH', + ); + + foreach ($request_types as $http_method_name => $http_method_used) { + if ($http_method_used && !in_array($http_method_name, $allowed_request_types, true)) { + echo + 'Warning: A ' . $http_method_name . ' request was made, but only the following request ' . + 'types are allowed: ' . implode(', ', $allowed_request_types) . "\n"; + } + } + } + echo 'Response contains ' . $response_headers_count . ' ' . ( $response_headers_count === 1 ? 'header:' : 'headers:' diff --git a/tests/PHPCurlClass/PHPCurlClassTest.php b/tests/PHPCurlClass/PHPCurlClassTest.php index a354eeb..73a83de 100644 --- a/tests/PHPCurlClass/PHPCurlClassTest.php +++ b/tests/PHPCurlClass/PHPCurlClassTest.php @@ -4122,6 +4122,58 @@ class CurlTest extends \PHPUnit\Framework\TestCase } } + public function testDiagnoseAllowHeader() + { + $tests = [ + [ + 'http_method' => 'GET', + 'allow_header_name' => 'Allow', + 'allow_header_value' => 'POST, OPTIONS', + 'expected' => + 'Warning: A GET request was made, but only the following request types are allowed: POST, OPTIONS', + ], + [ + 'http_method' => 'GET', + 'allow_header_name' => 'allow', + 'allow_header_value' => 'OPTIONS, POST', + 'expected' => + 'Warning: A GET request was made, but only the following request types are allowed: OPTIONS, POST', + ], + [ + 'http_method' => 'POST', + 'allow_header_name' => 'allow', + 'allow_header_value' => 'GET, OPTIONS', + 'expected' => + 'Warning: A POST request was made, but only the following request types are allowed: GET, OPTIONS', + ], + [ + 'http_method' => 'POST', + 'allow_header_name' => 'allow', + 'allow_header_value' => 'GET,OPTIONS', + 'expected' => + 'Warning: A POST request was made, but only the following request types are allowed: GET, OPTIONS', + ], + [ + 'http_method' => 'POST', + 'allow_header_name' => 'ALLOW', + 'allow_header_value' => 'get,options', + 'expected' => + 'Warning: A POST request was made, but only the following request types are allowed: GET, OPTIONS', + ], + ]; + + foreach ($tests as $test_case) { + $test = new Test(); + $test->server('json_response', $test_case['http_method'], [ + 'key' => $test_case['allow_header_name'], + 'value' => $test_case['allow_header_value'], + ]); + + $test_output = $test->curl->diagnose(true); + $this->assertStringContainsString($test_case['expected'], $test_output); + } + } + public function testStopRequest() { $response_length_bytes = 1e6; // 1e6 = 1 megabyte diff --git a/tests/PHPCurlClass/server.php b/tests/PHPCurlClass/server.php index 5abfc9d..cde5f8a 100644 --- a/tests/PHPCurlClass/server.php +++ b/tests/PHPCurlClass/server.php @@ -181,13 +181,23 @@ if ($test === 'http_basic_auth') { echo 'OK'; exit; } elseif ($test === 'json_response') { - if ($request_method === 'POST') { + if (isset($_POST['key'])) { $key = $_POST['key']; - $value = $_POST['value']; - header($key . ': ' . $value); + } elseif (isset($_GET['key'])) { + $key = $_GET['key']; } else { - header('Content-Type: application/json'); + $key = 'Content-Type'; } + + if (isset($_POST['value'])) { + $value = $_POST['value']; + } elseif (isset($_GET['value'])) { + $value = $_GET['value']; + } else { + $value = 'application/json'; + } + + header($key . ': ' . $value); echo json_encode([ 'null' => null, 'true' => true,