From a60f03f28e462edb700239a9242c5e3ac2059725 Mon Sep 17 00:00:00 2001 From: ajshort Date: Fri, 18 Mar 2011 23:38:30 +0000 Subject: [PATCH] ENHANCEMENT Sapphire Doesn't Read HTTP Headers (fixes #6311) --- control/Director.php | 41 +++++++++++++++++++++++++++++----- tests/control/DirectorTest.php | 35 +++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 5 deletions(-) diff --git a/control/Director.php b/control/Director.php index fb76363e6..3f1c7e0a6 100644 --- a/control/Director.php +++ b/control/Director.php @@ -87,11 +87,18 @@ class Director { array_merge((array)$_POST, (array)$_FILES), @file_get_contents('php://input') ); - - // @todo find better way to extract HTTP headers - if(isset($_SERVER['HTTP_ACCEPT'])) $req->addHeader("Accept", $_SERVER['HTTP_ACCEPT']); - if(isset($_SERVER['CONTENT_TYPE'])) $req->addHeader("Content-Type", $_SERVER['CONTENT_TYPE']); - if(isset($_SERVER['HTTP_REFERER'])) $req->addHeader("Referer", $_SERVER['HTTP_REFERER']); + + // Load the request headers. If we're not running on Apache, then we + // need to manually extract the headers from the $_SERVER array. + if (function_exists('apache_request_headers')) { + $headers = apache_request_headers(); + } else { + $headers = self::extract_request_headers($_SERVER); + } + + foreach ($headers as $header => $value) { + $req->addHeader($header, $value); + } // Load the session into the controller $session = new Session(isset($_SESSION) ? $_SESSION : null); @@ -536,7 +543,31 @@ class Director { $relativeUrl = Director::makeRelative($url); return (bool)self::is_relative_url($relativeUrl); } + + /** + * Takes a $_SERVER data array and extracts HTTP request headers. + * + * @param array $data + * @return array + */ + protected static function extract_request_headers(array $server) { + $headers = array(); + foreach($server as $key => $value) { + if(substr($key, 0, 5) == 'HTTP_') { + $key = substr($key, 5); + $key = strtolower(str_replace('_', ' ', $key)); + $key = str_replace(' ', '-', ucwords($key)); + $headers[$key] = $value; + } + } + + if(isset($server['CONTENT_TYPE'])) $headers['Content-Type'] = $server['CONTENT_TYPE']; + if(isset($server['CONTENT_LENGTH'])) $headers['Content-Length'] = $server['CONTENT_LENGTH']; + + return $headers; + } + /** * Given a filesystem reference relative to the site root, return the full file-system path. * diff --git a/tests/control/DirectorTest.php b/tests/control/DirectorTest.php index 74e2f885f..8de97a899 100644 --- a/tests/control/DirectorTest.php +++ b/tests/control/DirectorTest.php @@ -225,6 +225,41 @@ class DirectorTest extends SapphireTest { $this->assertFalse($output); } + /** + * @covers Director::extract_request_headers() + */ + public function testExtractRequestHeaders() { + $request = array( + 'REDIRECT_STATUS' => '200', + 'HTTP_HOST' => 'host', + 'HTTP_USER_AGENT' => 'User Agent', + 'HTTP_ACCEPT' => 'text/html', + 'HTTP_ACCEPT_LANGUAGE' => 'en-us', + 'HTTP_COOKIE' => 'PastMember=1', + 'SERVER_PROTOCOL' => 'HTTP/1.1', + 'REQUEST_METHOD' => 'GET', + 'REQUEST_URI' => '/', + 'SCRIPT_NAME' => '/sapphire/main.php', + 'CONTENT_TYPE' => 'text/xml', + 'CONTENT_LENGTH' => 10 + ); + + $headers = array( + 'Host' => 'host', + 'User-Agent' => 'User Agent', + 'Accept' => 'text/html', + 'Accept-Language' => 'en-us', + 'Cookie' => 'PastMember=1', + 'Content-Type' => 'text/xml', + 'Content-Length' => '10' + ); + + $method = new ReflectionMethod('Director', 'extract_request_headers'); + $method->setAccessible(true); + + $this->assertEquals($headers, $method->invoke(null, $request)); + } + } class DirectorTestRequest_Controller extends Controller implements TestOnly {