mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
FIX Improve recent RestfulService fix for proxies
This commit is contained in:
parent
5c82609802
commit
b1f03db4ff
@ -224,8 +224,11 @@ class RestfulService extends ViewableData {
|
||||
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
|
||||
if(!ini_get('open_basedir')) curl_setopt($ch, CURLOPT_FOLLOWLOCATION,1);
|
||||
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
|
||||
//include headers in the response
|
||||
curl_setopt($ch, CURLOPT_HEADER, true);
|
||||
|
||||
|
||||
// Write headers to a temporary file
|
||||
$headerfd = tmpfile();
|
||||
curl_setopt($ch, CURLOPT_WRITEHEADER, $headerfd);
|
||||
|
||||
// Add headers
|
||||
if($this->customHeaders) {
|
||||
@ -260,8 +263,13 @@ class RestfulService extends ViewableData {
|
||||
curl_setopt_array($ch, $curlOptions);
|
||||
|
||||
// Run request
|
||||
$rawResponse = curl_exec($ch);
|
||||
$response = $this->extractResponse($ch, $rawResponse);
|
||||
$body = curl_exec($ch);
|
||||
|
||||
rewind($headerfd);
|
||||
$headers = stream_get_contents($headerfd);
|
||||
fclose($headerfd);
|
||||
|
||||
$response = $this->extractResponse($ch, $headers, $body);
|
||||
curl_close($ch);
|
||||
|
||||
return $response;
|
||||
@ -308,36 +316,26 @@ class RestfulService extends ViewableData {
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the response from raw data. The response could have multiple redirection
|
||||
* and proxy connect headers, so we are only interested in the last header before the body.
|
||||
* Extracts the response body and headers from a full curl response
|
||||
*
|
||||
* @param curl_handle $ch The curl handle for the request
|
||||
* @param string $rawResponse The raw response text
|
||||
*
|
||||
* @return RestfulService_Response The response object
|
||||
*/
|
||||
protected function extractResponse($ch, $rawResponse) {
|
||||
protected function extractResponse($ch, $rawHeaders, $rawBody) {
|
||||
//get the status code
|
||||
$statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
//get a curl error if there is one
|
||||
$curlError = curl_error($ch);
|
||||
//normalise the status code
|
||||
if(curl_error($ch) !== '' || $statusCode == 0) $statusCode = 500;
|
||||
|
||||
// Parse the headers and body from the response.
|
||||
// We cannot rely on CURLINFO_HEADER_SIZE here, it's miscalculated when connecting via
|
||||
// a proxy (see http://sourceforge.net/p/curl/bugs/1204/). This is fixed in curl 7.30.0.
|
||||
$headerParts = array();
|
||||
$parts = explode("\r\n\r\n", $rawResponse);
|
||||
while (isset($parts[0])) {
|
||||
if (strpos($parts[0], 'HTTP/')===0) $headerParts[] = array_shift($parts);
|
||||
else break; // We have reached the body.
|
||||
}
|
||||
$lastHeader = array_pop($headerParts);
|
||||
$body = implode("\r\n\r\n", $parts);
|
||||
|
||||
$parsedHeader = $this->parseRawHeaders($lastHeader);
|
||||
return new RestfulService_Response($body, $statusCode, $parsedHeader);
|
||||
//parse the headers
|
||||
$parts = array_filter(explode("\r\n\r\n", $rawHeaders));
|
||||
$lastHeaders = array_pop($parts);
|
||||
$headers = $this->parseRawHeaders($lastHeaders);
|
||||
//return the response object
|
||||
return new RestfulService_Response($rawBody, $statusCode, $headers);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -198,7 +198,7 @@ class RestfulServiceTest extends SapphireTest {
|
||||
|
||||
public function testExtractResponseRedirectionAndProxy() {
|
||||
// This is an example of real raw response for a request via a proxy that gets redirected.
|
||||
$rawResponse =
|
||||
$rawHeaders =
|
||||
"HTTP/1.0 200 Connection established\r\n" .
|
||||
"\r\n" .
|
||||
"HTTP/1.1 301 Moved Permanently\r\n" .
|
||||
@ -220,8 +220,8 @@ class RestfulServiceTest extends SapphireTest {
|
||||
"X-Frame-Options: SAMEORIGIN\r\n" .
|
||||
"Cache-Control: no-cache, max-age=0, must-revalidate, no-transform\r\n" .
|
||||
"Vary: Accept-Encoding\r\n" .
|
||||
"\r\n" .
|
||||
"<!doctype html></html>";
|
||||
"\r\n"
|
||||
;
|
||||
|
||||
$headerFunction = new ReflectionMethod('RestfulService', 'extractResponse');
|
||||
$headerFunction->setAccessible(true);
|
||||
@ -230,10 +230,10 @@ class RestfulServiceTest extends SapphireTest {
|
||||
$response = $headerFunction->invoke(
|
||||
new RestfulService(Director::absoluteBaseURL(),0),
|
||||
$ch,
|
||||
$rawResponse
|
||||
$rawHeaders,
|
||||
''
|
||||
);
|
||||
|
||||
$this->assertEquals($response->getBody(), '<!doctype html></html>', 'Body is correctly extracted.');
|
||||
$this->assertEquals(
|
||||
$response->getHeaders(),
|
||||
array(
|
||||
@ -250,53 +250,7 @@ class RestfulServiceTest extends SapphireTest {
|
||||
);
|
||||
}
|
||||
|
||||
public function testExtractResponseNewlinesInBody() {
|
||||
$rawResponse =
|
||||
"HTTP/1.1 200 OK\r\n" .
|
||||
"Server: nginx\r\n" .
|
||||
"\r\n" .
|
||||
"<!doctype html>\r\n" .
|
||||
"\r\n" .
|
||||
"</html>";
|
||||
|
||||
$headerFunction = new ReflectionMethod('RestfulService', 'extractResponse');
|
||||
$headerFunction->setAccessible(true);
|
||||
|
||||
$ch = curl_init();
|
||||
$response = $headerFunction->invoke(
|
||||
new RestfulService(Director::absoluteBaseURL(),0),
|
||||
$ch,
|
||||
$rawResponse
|
||||
);
|
||||
|
||||
$this->assertEquals($response->getBody(), "<!doctype html>\r\n\r\n</html>", 'Body is correctly extracted.');
|
||||
$this->assertEquals($response->getHeaders(), array('Server' => "nginx"), 'Headers are correctly extracted.');
|
||||
}
|
||||
|
||||
public function testExtractResponseNoBody() {
|
||||
// For example a response to HEAD request.
|
||||
$rawResponse =
|
||||
"HTTP/1.1 200 OK\r\n" .
|
||||
"Server: nginx";
|
||||
|
||||
$headerFunction = new ReflectionMethod('RestfulService', 'extractResponse');
|
||||
$headerFunction->setAccessible(true);
|
||||
|
||||
$ch = curl_init();
|
||||
$response = $headerFunction->invoke(
|
||||
new RestfulService(Director::absoluteBaseURL(),0),
|
||||
$ch,
|
||||
$rawResponse
|
||||
);
|
||||
|
||||
$this->assertEquals($response->getBody(), "", 'Body is correctly extracted.');
|
||||
$this->assertEquals($response->getHeaders(), array('Server' => "nginx"), 'Headers are correctly extracted.');
|
||||
}
|
||||
|
||||
public function testExtractResponseNoHead() {
|
||||
// Malformed response.
|
||||
$rawResponse = "I am a malformed response";
|
||||
|
||||
$headerFunction = new ReflectionMethod('RestfulService', 'extractResponse');
|
||||
$headerFunction->setAccessible(true);
|
||||
|
||||
@ -304,10 +258,10 @@ class RestfulServiceTest extends SapphireTest {
|
||||
$response = $headerFunction->invoke(
|
||||
new RestfulService(Director::absoluteBaseURL(),0),
|
||||
$ch,
|
||||
$rawResponse
|
||||
'',
|
||||
''
|
||||
);
|
||||
|
||||
$this->assertEquals($response->getBody(), "I am a malformed response", 'Body is correctly extracted.');
|
||||
$this->assertEquals($response->getHeaders(), array(), 'Headers are correctly extracted.');
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user