mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
ENHANCEMENT: Restful service returns cached response on http and curl errors (from r108437)
git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/sapphire/trunk@112750 467b73ca-7a2a-4603-9d3b-597d59a354a9
This commit is contained in:
parent
6a83da1455
commit
d60ef78ba4
@ -101,17 +101,12 @@ class RestfulService extends ViewableData {
|
||||
* @todo Pass the response headers to RestfulService_Response
|
||||
*
|
||||
* This is a replacement of {@link connect()}.
|
||||
*
|
||||
* @return RestfulService_Response - If curl request produces error, the returned response's status code will be 500
|
||||
*/
|
||||
public function request($subURL = '', $method = "GET", $data = null, $headers = null, $curlOptions = array()) {
|
||||
$url = $this->baseURL . $subURL; // Url for the request
|
||||
if($this->queryString) {
|
||||
if(strpos($url, '?') !== false) {
|
||||
$url .= '&' . $this->queryString;
|
||||
} else {
|
||||
$url .= '?' . $this->queryString;
|
||||
}
|
||||
}
|
||||
$url = str_replace(' ', '%20', $url); // Encode spaces
|
||||
|
||||
$url = $this->getAbsoluteRequestURL($subURL);
|
||||
$method = strtoupper($method);
|
||||
|
||||
assert(in_array($method, array('GET','POST','PUT','DELETE','HEAD','OPTIONS')));
|
||||
@ -171,25 +166,53 @@ class RestfulService extends ViewableData {
|
||||
$responseBody = curl_exec($ch);
|
||||
$curlError = curl_error($ch);
|
||||
}
|
||||
|
||||
$statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
if($curlError !== '' || $statusCode == 0) $statusCode = 500;
|
||||
|
||||
if($responseBody === false) {
|
||||
user_error("Curl Error:" . $curlError, E_USER_WARNING);
|
||||
return;
|
||||
}
|
||||
|
||||
$statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
$response = new RestfulService_Response($responseBody, curl_getinfo($ch, CURLINFO_HTTP_CODE));
|
||||
|
||||
$response = new RestfulService_Response($responseBody, $statusCode);
|
||||
curl_close($ch);
|
||||
|
||||
// Serialise response object and write to cache
|
||||
$store = serialize($response);
|
||||
file_put_contents($cache_path,$store);
|
||||
|
||||
if($curlError === '' && !$response->isError()) {
|
||||
// Serialise response object and write to cache
|
||||
$store = serialize($response);
|
||||
file_put_contents($cache_path, $store);
|
||||
}
|
||||
else {
|
||||
// In case of curl or/and http indicate error, populate response's cachedBody property
|
||||
// with cached response body with the cache file exists
|
||||
if (@file_exists($cache_path)) {
|
||||
$store = file_get_contents($cache_path);
|
||||
$cachedResponse = unserialize($store);
|
||||
|
||||
$response->setCachedBody($cachedResponse->getBody());
|
||||
}
|
||||
else {
|
||||
$response->setCachedBody(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a full request url
|
||||
* @param string
|
||||
*/
|
||||
function getAbsoluteRequestURL($subURL) {
|
||||
$url = $this->baseURL . $subURL; // Url for the request
|
||||
if($this->queryString) {
|
||||
if(strpos($url, '?') !== false) {
|
||||
$url .= '&' . $this->queryString;
|
||||
} else {
|
||||
$url .= '?' . $this->queryString;
|
||||
}
|
||||
}
|
||||
|
||||
return str_replace(' ', '%20', $url); // Encode spaces
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets attributes as an array, of a particular type of element.
|
||||
* Example : <photo id="2636" owner="123" secret="ab128" server="2">
|
||||
@ -362,6 +385,12 @@ class RestfulService extends ViewableData {
|
||||
class RestfulService_Response extends SS_HTTPResponse {
|
||||
protected $simpleXML;
|
||||
|
||||
/**
|
||||
* @var boolean It should be populated with cached content
|
||||
* when a request referring to this response was unsuccessful
|
||||
*/
|
||||
protected $cachedBody = false;
|
||||
|
||||
function __construct($body, $statusCode = 200, $headers = null) {
|
||||
$this->setbody($body);
|
||||
$this->setStatusCode($statusCode);
|
||||
@ -380,6 +409,20 @@ class RestfulService_Response extends SS_HTTPResponse {
|
||||
return $this->simpleXML;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
function getCachedBody() {
|
||||
return $this->cachedBody;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string
|
||||
*/
|
||||
function setCachedBody($content) {
|
||||
$this->cachedBody = $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array of xpath matches
|
||||
*/
|
||||
|
@ -90,6 +90,41 @@ class RestfulServiceTest extends SapphireTest {
|
||||
$test1 = $connection->request('RestfulServiceTest_Controller/invalid?usetestmanifest=1&flush=1');
|
||||
$test1->xpath("\\fail");
|
||||
}
|
||||
|
||||
function testHttpErrorWithoutCache() {
|
||||
$connection = new RestfulService(Director::absoluteBaseURL(), 0);
|
||||
$response = $connection->request('RestfulServiceTest_Controller/httpErrorWithoutCache?usetestmanifest=1&flush=1');
|
||||
|
||||
$this->assertEquals(400, $response->getStatusCode());
|
||||
$this->assertFalse($response->getCachedBody());
|
||||
$this->assertContains("<error>HTTP Error</error>", $response->getBody());
|
||||
|
||||
}
|
||||
|
||||
function testHttpErrorWithCache() {
|
||||
$subUrl = 'RestfulServiceTest_Controller/httpErrorWithCache?usetestmanifest=1&flush=1';
|
||||
$connection = new RestfulService(Director::absoluteBaseURL(), 0);
|
||||
$this->createFakeCachedResponse($connection, $subUrl);
|
||||
$response = $connection->request($subUrl);
|
||||
|
||||
$this->assertEquals(400, $response->getStatusCode());
|
||||
$this->assertEquals("Cache response body",$response->getCachedBody());
|
||||
$this->assertContains("<error>HTTP Error</error>", $response->getBody());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Simulate cached response file for testing error requests that are supposed to have cache files
|
||||
*/
|
||||
private function createFakeCachedResponse($connection, $subUrl) {
|
||||
$fullUrl = $connection->getAbsoluteRequestURL($subUrl);
|
||||
$cachedir = TEMP_FOLDER; // Default silverstripe cache
|
||||
$cache_file = md5($fullUrl); // Encoded name of cache file
|
||||
$cache_path = $cachedir."/xmlresponse_$cache_file";
|
||||
$cacheResponse = new RestfulService_Response("Cache response body");
|
||||
$store = serialize($cacheResponse);
|
||||
file_put_contents($cache_path, $store);
|
||||
}
|
||||
}
|
||||
|
||||
class RestfulServiceTest_Controller extends Controller {
|
||||
@ -134,6 +169,29 @@ XML;
|
||||
header('Content-type: text/xml');
|
||||
echo $out;
|
||||
}
|
||||
|
||||
public function httpErrorWithoutCache() {
|
||||
$out = <<<XML
|
||||
<?xml version="1.0"?>
|
||||
<test>
|
||||
<error>HTTP Error</error>
|
||||
</test>
|
||||
XML;
|
||||
|
||||
$this->response->setBody($out);
|
||||
$this->response->setStatusCode(400);
|
||||
$this->response->addHeader('Content-type', 'text/xml');
|
||||
|
||||
return $this->response;
|
||||
}
|
||||
|
||||
/**
|
||||
* The body of this method is the same as self::httpErrorWithoutCache()
|
||||
* but we need it for caching since caching using request url to determine path to cache file
|
||||
*/
|
||||
public function httpErrorWithCache() {
|
||||
return $this->httpErrorWithoutCache();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user