Add wrapper for Guzzle

This commit is contained in:
Lukas Reschke 2015-03-16 11:28:23 +01:00
parent 13904a7f89
commit 5f044ebf1b
27 changed files with 4872 additions and 233 deletions

@ -1 +1 @@
Subproject commit 244f75dc8d4552bb73a4aa93a1c6eeafdeb801d8
Subproject commit e4f341066a2f9740cabffd20aa76742ce7cd8bfd

View File

@ -122,9 +122,9 @@ class Share extends TestCase {
private function createMocks() {
$config = $this->getMockBuilder('\OCP\IConfig')
->disableOriginalConstructor()->getMock();
$certificateManager = $this->getMock('\OCP\ICertificateManager');
$clientService = $this->getMock('\OCP\Http\Client\IClientService');
$httpHelperMock = $this->getMockBuilder('\OC\HTTPHelper')
->setConstructorArgs(array($config, $certificateManager))
->setConstructorArgs([$config, $clientService])
->getMock();
$httpHelperMock->expects($this->any())->method('post')->with($this->anything())->will($this->returnValue(array('success' => true, 'result' => "{'ocs' : { 'meta' : { 'statuscode' : 100 }}}")));

View File

@ -11,6 +11,7 @@
namespace OCA\Files_Sharing\Controllers;
use Hoa\Core\Data\Data;
use OC;
use OC\Files\Filesystem;
use OC_Files;
@ -30,6 +31,7 @@ use OCA\Files_Sharing\Helper;
use OCP\User;
use OCP\Util;
use OCA\Files_Sharing\Activity;
use OCP\AppFramework\Http\DataResponse;
/**
* Class ShareController

View File

@ -210,37 +210,23 @@ class Storage extends DAV implements ISharedStorage {
}
}
/**
* @return mixed
* @throws ForbiddenException
* @throws NotFoundException
* @throws \Exception
*/
public function getShareInfo() {
$remote = $this->getRemote();
$token = $this->getToken();
$password = $this->getPassword();
$url = rtrim($remote, '/') . '/index.php/apps/files_sharing/shareinfo?t=' . $token;
$ch = curl_init();
// TODO: DI
$client = \OC::$server->getHTTPClientService()->newClient();
$response = $client->post($url, ['body' => ['password' => $password]]);
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS,
http_build_query(array('password' => $password)));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
$path = $this->certificateManager->getCertificateBundle();
if (is_readable($path)) {
curl_setopt($ch, CURLOPT_CAINFO, $path);
}
$result = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$errorMessage = curl_error($ch);
curl_close($ch);
if (!empty($errorMessage)) {
throw new \Exception($errorMessage);
}
switch ($status) {
switch ($response->getStatusCode()) {
case 401:
case 403:
throw new ForbiddenException();
@ -250,6 +236,6 @@ class Storage extends DAV implements ISharedStorage {
throw new \Exception();
}
return json_decode($result, true);
return json_decode($response->getBody(), true);
}
}

View File

@ -48,9 +48,9 @@ class Test_Files_Sharing_S2S_OCS_API extends TestCase {
$config = $this->getMockBuilder('\OCP\IConfig')
->disableOriginalConstructor()->getMock();
$certificateManager = $this->getMock('\OCP\ICertificateManager');
$clientService = $this->getMock('\OCP\Http\Client\IClientService');
$httpHelperMock = $this->getMockBuilder('\OC\HTTPHelper')
->setConstructorArgs(array($config, $certificateManager))
->setConstructorArgs([$config, $clientService])
->getMock();
$httpHelperMock->expects($this->any())->method('post')->with($this->anything())->will($this->returnValue(true));

3860
config/ca-bundle.crt Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,268 @@
<?php
/**
* Copyright (c) 2015 Lukas Reschke <lukas@owncloud.com>
* This file is licensed under the Affero General Public License version 3 or
* later.
* See the COPYING-README file.
*/
namespace OC\Http\Client;
use GuzzleHttp\Client as GuzzleClient;
use OCP\Http\Client\IClient;
use OCP\ICertificateManager;
use OCP\IConfig;
/**
* Class Client
*
* @package OC\Http
*/
class Client implements IClient {
/** @var GuzzleClient */
private $client;
/** @var IConfig */
private $config;
/** @var ICertificateManager */
private $certificateManager;
/**
* @param IConfig $config
* @param ICertificateManager $certificateManager
* @param GuzzleClient $client
*/
public function __construct(IConfig $config,
ICertificateManager $certificateManager,
GuzzleClient $client) {
$this->config = $config;
$this->client = $client;
$this->certificateManager = $certificateManager;
$this->setDefaultOptions();
}
/**
* Sets the default options to the client
*/
private function setDefaultOptions() {
// Either use default bundle or the user bundle if nothing is specified
if($this->certificateManager->listCertificates() !== []) {
$dataDir = $this->config->getSystemValue('datadirectory');
$this->client->setDefaultOption('verify', $dataDir.'/'.$this->certificateManager->getCertificateBundle());
} else {
$this->client->setDefaultOption('verify', \OC::$SERVERROOT . '/config/ca-bundle.crt');
}
$this->client->setDefaultOption('headers/User-Agent', 'ownCloud Server Crawler');
if($this->getProxyUri() !== '') {
$this->client->setDefaultOption('proxy', $this->getProxyUri());
}
}
/**
* Get the proxy URI
* @return string
*/
private function getProxyUri() {
$proxyHost = $this->config->getSystemValue('proxy', null);
$proxyUserPwd = $this->config->getSystemValue('proxyuserpwd', null);
$proxyUri = '';
if(!is_null($proxyUserPwd)) {
$proxyUri .= $proxyUserPwd.'@';
}
if(!is_null($proxyHost)) {
$proxyUri .= $proxyHost;
}
return $proxyUri;
}
/**
* Sends a GET request
* @param string $uri
* @param array $options Array such as
* 'query' => [
* 'field' => 'abc',
* 'other_field' => '123',
* 'file_name' => fopen('/path/to/file', 'r'),
* ],
* 'headers' => [
* 'foo' => 'bar',
* ],
* 'cookies' => ['
* 'foo' => 'bar',
* ],
* 'allow_redirects' => [
* 'max' => 10, // allow at most 10 redirects.
* 'strict' => true, // use "strict" RFC compliant redirects.
* 'referer' => true, // add a Referer header
* 'protocols' => ['https'] // only allow https URLs
* ],
* 'save_to' => '/path/to/file', // save to a file or a stream
* 'verify' => true, // bool or string to CA file
* 'debug' => true,
* 'timeout' => 5,
* @return Response
* @throws \Exception If the request could not get completed
*/
public function get($uri, array $options = []) {
$response = $this->client->get($uri, $options);
return new Response($response);
}
/**
* Sends a HEAD request
* @param string $uri
* @param array $options Array such as
* 'headers' => [
* 'foo' => 'bar',
* ],
* 'cookies' => ['
* 'foo' => 'bar',
* ],
* 'allow_redirects' => [
* 'max' => 10, // allow at most 10 redirects.
* 'strict' => true, // use "strict" RFC compliant redirects.
* 'referer' => true, // add a Referer header
* 'protocols' => ['https'] // only allow https URLs
* ],
* 'save_to' => '/path/to/file', // save to a file or a stream
* 'verify' => true, // bool or string to CA file
* 'debug' => true,
* 'timeout' => 5,
* @return Response
*/
public function head($uri, $options = []) {
$response = $this->client->head($uri, $options);
return new Response($response);
}
/**
* Sends a POST request
* @param string $uri
* @param array $options Array such as
* 'body' => [
* 'field' => 'abc',
* 'other_field' => '123',
* 'file_name' => fopen('/path/to/file', 'r'),
* ],
* 'headers' => [
* 'foo' => 'bar',
* ],
* 'cookies' => ['
* 'foo' => 'bar',
* ],
* 'allow_redirects' => [
* 'max' => 10, // allow at most 10 redirects.
* 'strict' => true, // use "strict" RFC compliant redirects.
* 'referer' => true, // add a Referer header
* 'protocols' => ['https'] // only allow https URLs
* ],
* 'save_to' => '/path/to/file', // save to a file or a stream
* 'verify' => true, // bool or string to CA file
* 'debug' => true,
* 'timeout' => 5,
* @return Response
*/
public function post($uri, array $options = []) {
$response = $this->client->post($uri, $options);
return new Response($response);
}
/**
* Sends a PUT request
* @param string $uri
* @param array $options Array such as
* 'body' => [
* 'field' => 'abc',
* 'other_field' => '123',
* 'file_name' => fopen('/path/to/file', 'r'),
* ],
* 'headers' => [
* 'foo' => 'bar',
* ],
* 'cookies' => ['
* 'foo' => 'bar',
* ],
* 'allow_redirects' => [
* 'max' => 10, // allow at most 10 redirects.
* 'strict' => true, // use "strict" RFC compliant redirects.
* 'referer' => true, // add a Referer header
* 'protocols' => ['https'] // only allow https URLs
* ],
* 'save_to' => '/path/to/file', // save to a file or a stream
* 'verify' => true, // bool or string to CA file
* 'debug' => true,
* 'timeout' => 5,
* @return Response
*/
public function put($uri, array $options = []) {
$response = $this->client->put($uri, $options);
return new Response($response);
}
/**
* Sends a DELETE request
* @param string $uri
* @param array $options Array such as
* 'body' => [
* 'field' => 'abc',
* 'other_field' => '123',
* 'file_name' => fopen('/path/to/file', 'r'),
* ],
* 'headers' => [
* 'foo' => 'bar',
* ],
* 'cookies' => ['
* 'foo' => 'bar',
* ],
* 'allow_redirects' => [
* 'max' => 10, // allow at most 10 redirects.
* 'strict' => true, // use "strict" RFC compliant redirects.
* 'referer' => true, // add a Referer header
* 'protocols' => ['https'] // only allow https URLs
* ],
* 'save_to' => '/path/to/file', // save to a file or a stream
* 'verify' => true, // bool or string to CA file
* 'debug' => true,
* 'timeout' => 5,
* @return Response
*/
public function delete($uri, array $options = []) {
$response = $this->client->delete($uri, $options);
return new Response($response);
}
/**
* Sends a options request
* @param string $uri
* @param array $options Array such as
* 'body' => [
* 'field' => 'abc',
* 'other_field' => '123',
* 'file_name' => fopen('/path/to/file', 'r'),
* ],
* 'headers' => [
* 'foo' => 'bar',
* ],
* 'cookies' => ['
* 'foo' => 'bar',
* ],
* 'allow_redirects' => [
* 'max' => 10, // allow at most 10 redirects.
* 'strict' => true, // use "strict" RFC compliant redirects.
* 'referer' => true, // add a Referer header
* 'protocols' => ['https'] // only allow https URLs
* ],
* 'save_to' => '/path/to/file', // save to a file or a stream
* 'verify' => true, // bool or string to CA file
* 'debug' => true,
* 'timeout' => 5,
* @return Response
*/
public function options($uri, array $options = []) {
$response = $this->client->options($uri, $options);
return new Response($response);
}
}

View File

@ -0,0 +1,43 @@
<?php
/**
* Copyright (c) 2015 Lukas Reschke <lukas@owncloud.com>
* This file is licensed under the Affero General Public License version 3 or
* later.
* See the COPYING-README file.
*/
namespace OC\Http\Client;
use GuzzleHttp\Client as GuzzleClient;
use OCP\Http\Client\IClientService;
use OCP\ICertificateManager;
use OCP\IConfig;
/**
* Class ClientService
*
* @package OC\Http
*/
class ClientService implements IClientService {
/** @var IConfig */
private $config;
/** @var ICertificateManager */
private $certificateManager;
/**
* @param IConfig $config
* @param ICertificateManager $certificateManager
*/
public function __construct(IConfig $config,
ICertificateManager $certificateManager) {
$this->config = $config;
$this->certificateManager = $certificateManager;
}
/**
* @return Client
*/
public function newClient() {
return new Client($this->config, $this->certificateManager, new GuzzleClient());
}
}

View File

@ -0,0 +1,58 @@
<?php
/**
* Copyright (c) 2015 Lukas Reschke <lukas@owncloud.com>
* This file is licensed under the Affero General Public License version 3 or
* later.
* See the COPYING-README file.
*/
namespace OC\Http\Client;
use OCP\Http\Client\IResponse;
use GuzzleHttp\Message\Response as GuzzleResponse;
/**
* Class Response
*
* @package OC\Http
*/
class Response implements IResponse {
/** @var GuzzleResponse */
private $response;
/**
* @param GuzzleResponse $response
*/
public function __construct(GuzzleResponse $response) {
$this->response = $response;
}
/**
* @return string
*/
public function getBody() {
return $this->response->getBody()->getContents();
}
/**
* @return int
*/
public function getStatusCode() {
return $this->response->getStatusCode();
}
/**
* @param $key
* @return string
*/
public function getHeader($key) {
return $this->response->getHeader($key);
}
/**
* @return array
*/
public function getHeaders() {
return $this->response->getHeaders();
}
}

View File

@ -1,6 +1,6 @@
<?php
/**
* Copyright (c) 2014 Lukas Reschke <lukas@owncloud.com>
* Copyright (c) 2014-2015 Lukas Reschke <lukas@owncloud.com>
* This file is licensed under the Affero General Public License version 3 or
* later.
* See the COPYING-README file.
@ -8,41 +8,31 @@
namespace OC;
use OCP\Http\Client\IClientService;
use OCP\IConfig;
use OCP\ICertificateManager;
/**
* Class HTTPHelper
*
* @package OC
* @deprecated Use \OCP\Http\Client\IClientService
*/
class HTTPHelper {
const USER_AGENT = 'ownCloud Server Crawler';
/** @var \OCP\IConfig */
private $config;
/** @var \OC\Security\CertificateManager */
private $certificateManager;
/** @var IClientService */
private $clientService;
/**
* @param \OCP\IConfig $config
* @param IConfig $config
* @param IClientService $clientService
*/
public function __construct(IConfig $config, ICertificateManager $certificateManager) {
public function __construct(IConfig $config,
IClientService $clientService) {
$this->config = $config;
$this->certificateManager = $certificateManager;
}
/**
* Returns the default context array
* @return array
*/
public function getDefaultContextArray() {
return array(
'http' => array(
'header' => 'User-Agent: ' . self::USER_AGENT . "\r\n",
'timeout' => 10,
'follow_location' => false, // Do not follow the location since we can't limit the protocol
),
'ssl' => array(
'disable_compression' => true
)
);
$this->clientService = $clientService;
}
/**
@ -52,87 +42,28 @@ class HTTPHelper {
* @return string of the response or false on error
* This function get the content of a page via curl, if curl is enabled.
* If not, file_get_contents is used.
* @deprecated Use \OCP\Http\Client\IClientService
*/
public function getUrlContent($url) {
if (!$this->isHTTPURL($url)) {
throw new \Exception('$url must start with https:// or http://', 1);
try {
$client = $this->clientService->newClient();
$response = $client->get($url);
return $response->getBody();
} catch (\Exception $e) {
return false;
}
$proxy = $this->config->getSystemValue('proxy', null);
$proxyUserPwd = $this->config->getSystemValue('proxyuserpwd', null);
$curl = curl_init();
$max_redirects = 10;
curl_setopt($curl, CURLOPT_HEADER, 0);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 10);
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS);
curl_setopt($curl, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS);
curl_setopt($curl, CURLOPT_USERAGENT, self::USER_AGENT);
if ($proxy !== null) {
curl_setopt($curl, CURLOPT_PROXY, $proxy);
}
if ($proxyUserPwd !== null) {
curl_setopt($curl, CURLOPT_PROXYUSERPWD, $proxyUserPwd);
}
if (ini_get('open_basedir') === '') {
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($curl, CURLOPT_MAXREDIRS, $max_redirects);
$data = curl_exec($curl);
} else {
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, false);
$mr = $max_redirects;
if ($mr > 0) {
$newURL = curl_getinfo($curl, CURLINFO_EFFECTIVE_URL);
$rCurl = curl_copy_handle($curl);
curl_setopt($rCurl, CURLOPT_HEADER, true);
curl_setopt($rCurl, CURLOPT_NOBODY, true);
curl_setopt($rCurl, CURLOPT_FORBID_REUSE, false);
curl_setopt($rCurl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($rCurl, CURLOPT_USERAGENT, self::USER_AGENT);
do {
curl_setopt($rCurl, CURLOPT_URL, $newURL);
$header = curl_exec($rCurl);
if (curl_errno($rCurl)) {
$code = 0;
} else {
$code = curl_getinfo($rCurl, CURLINFO_HTTP_CODE);
if ($code == 301 || $code == 302) {
preg_match('/Location:(.*?)\n/', $header, $matches);
$newURL = trim(array_pop($matches));
} else {
$code = 0;
}
}
} while ($code && --$mr);
curl_close($rCurl);
if ($mr > 0) {
curl_setopt($curl, CURLOPT_URL, $newURL);
}
}
if ($mr == 0 && $max_redirects > 0) {
$data = false;
} else {
$data = curl_exec($curl);
}
}
curl_close($curl);
return $data;
}
/**
* Returns the response headers of a HTTP URL without following redirects
* @param string $location Needs to be a HTTPS or HTTP URL
* @return array
* @deprecated Use \OCP\Http\Client\IClientService
*/
public function getHeaders($location) {
stream_context_set_default($this->getDefaultContextArray());
return get_headers($location, 1);
$client = $this->clientService->newClient();
$response = $client->get($location);
return $response->getHeaders();
}
/**
@ -144,51 +75,24 @@ class HTTPHelper {
return stripos($url, 'https://') === 0 || stripos($url, 'http://') === 0;
}
/**
* create string of parameters for post request
*
* @param array $parameters
* @return string
*/
private function assemblePostParameters(array $parameters) {
$parameterString = '';
foreach ($parameters as $key => $value) {
$parameterString .= $key . '=' . urlencode($value) . '&';
}
return rtrim($parameterString, '&');
}
/**
* send http post request
*
* @param string $url
* @param array $fields data send by the request
* @return bool
* @return array
* @deprecated Use \OCP\Http\Client\IClientService
*/
public function post($url, array $fields) {
$client = $this->clientService->newClient();
$fieldsString = $this->assemblePostParameters($fields);
$certBundle = $this->certificateManager->getCertificateBundle();
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, count($fields));
curl_setopt($ch, CURLOPT_POSTFIELDS, (string)$fieldsString);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
if (is_readable($certBundle)) {
curl_setopt($ch, CURLOPT_CAINFO, $certBundle);
try {
$response = $client->post($url, ['body' => $fields]);
} catch (\Exception $e) {
return ['success' => false, 'result' => $e->getMessage()];
}
$result = curl_exec($ch);
$success = $result ? true : false;
curl_close($ch);
return array('success' => $success, 'result' => $result);
return ['success' => true, 'result' => $response->getBody()];
}
}

View File

@ -244,8 +244,9 @@ class OC_Installer{
if(!isset($data['href'])) {
throw new \Exception($l->t("No href specified when installing app from http"));
}
file_put_contents($path, \OC_Util::getUrlContent($data['href']));
}else{
$client = \OC::$server->getHTTPClientService()->newClient();
$client->get($data['href'], ['save_to' => $path]);
} else {
if(!isset($data['path'])) {
throw new \Exception($l->t("No path specified when installing app from local file"));
}

View File

@ -67,16 +67,24 @@ class OCSClient {
return null;
}
$url = self::getAppStoreURL() . '/content/categories';
$xml = \OC::$server->getHTTPHelper()->getUrlContent($url);
if ($xml == false) {
$client = \OC::$server->getHTTPClientService()->newClient();
try {
$response = $client->get($url, ['timeout' => 5]);
} catch(\Exception $e) {
return null;
}
if($response->getStatusCode() !== 200) {
return null;
}
$loadEntities = libxml_disable_entity_loader(true);
$data = simplexml_load_string($xml);
$data = simplexml_load_string($response->getBody());
libxml_disable_entity_loader($loadEntities);
$tmp = $data->data;
$cats = array();
$cats = [];
foreach ($tmp->category as $value) {
@ -114,14 +122,21 @@ class OCSClient {
$filterUrl = '&filter=' . urlencode($filter);
$url = self::getAppStoreURL() . '/content/data?categories=' . urlencode($categoriesString)
. '&sortmode=new&page=' . urlencode($page) . '&pagesize=100' . $filterUrl . $version;
$apps = array();
$xml = \OC::$server->getHTTPHelper()->getUrlContent($url);
$apps = [];
if ($xml == false) {
$client = \OC::$server->getHTTPClientService()->newClient();
try {
$response = $client->get($url, ['timeout' => 5]);
} catch(\Exception $e) {
return null;
}
if($response->getStatusCode() !== 200) {
return null;
}
$loadEntities = libxml_disable_entity_loader(true);
$data = simplexml_load_string($xml);
$data = simplexml_load_string($response->getBody());
libxml_disable_entity_loader($loadEntities);
$tmp = $data->data->content;
@ -163,14 +178,19 @@ class OCSClient {
return null;
}
$url = self::getAppStoreURL() . '/content/data/' . urlencode($id);
$xml = \OC::$server->getHTTPHelper()->getUrlContent($url);
if ($xml == false) {
\OC_Log::write('core', 'Unable to parse OCS content for app ' . $id, \OC_Log::FATAL);
$client = \OC::$server->getHTTPClientService()->newClient();
try {
$response = $client->get($url, ['timeout' => 5]);
} catch(\Exception $e) {
return null;
}
if($response->getStatusCode() !== 200) {
return null;
}
$loadEntities = libxml_disable_entity_loader(true);
$data = simplexml_load_string($xml);
$data = simplexml_load_string($response->getBody());
libxml_disable_entity_loader($loadEntities);
$tmp = $data->data->content;
@ -178,7 +198,7 @@ class OCSClient {
\OC_Log::write('core', 'Invalid OCS content returned for app ' . $id, \OC_Log::FATAL);
return null;
}
$app = array();
$app = [];
$app['id'] = $tmp->id;
$app['name'] = $tmp->name;
$app['version'] = $tmp->version;
@ -212,14 +232,19 @@ class OCSClient {
return null;
}
$url = self::getAppStoreURL() . '/content/download/' . urlencode($id) . '/' . urlencode($item);
$xml = \OC::$server->getHTTPHelper()->getUrlContent($url);
if ($xml == false) {
\OC_Log::write('core', 'Unable to parse OCS content', \OC_Log::FATAL);
$client = \OC::$server->getHTTPClientService()->newClient();
try {
$response = $client->get($url, ['timeout' => 5]);
} catch(\Exception $e) {
return null;
}
if($response->getStatusCode() !== 200) {
return null;
}
$loadEntities = libxml_disable_entity_loader(true);
$data = simplexml_load_string($xml);
$data = simplexml_load_string($response->getBody());
libxml_disable_entity_loader($loadEntities);
$tmp = $data->data->content;

View File

@ -63,11 +63,13 @@ class CertificateManager implements ICertificateManager {
/**
* create the certificate bundle of all trusted certificated
*/
protected function createCertificateBundle() {
public function createCertificateBundle() {
$path = $this->getPathToCertificates();
$certs = $this->listCertificates();
$fh_certs = $this->view->fopen($path . '/rootcerts.crt', 'w');
// Write user certificates
foreach ($certs as $cert) {
$file = $path . '/uploads/' . $cert->getName();
$data = $this->view->file_get_contents($file);
@ -77,6 +79,9 @@ class CertificateManager implements ICertificateManager {
}
}
// Append the default certificates
$defaultCertificates = file_get_contents(\OC::$SERVERROOT . '/config/ca-bundle.crt');
fwrite($fh_certs, $defaultCertificates);
fclose($fh_certs);
}
@ -137,6 +142,9 @@ class CertificateManager implements ICertificateManager {
return $this->getPathToCertificates() . 'rootcerts.crt';
}
/**
* @return string
*/
private function getPathToCertificates() {
$path = is_null($this->uid) ? '/files_external/' : '/' . $this->uid . '/files_external/';

View File

@ -13,6 +13,7 @@ use OC\Diagnostics\EventLogger;
use OC\Diagnostics\QueryLogger;
use OC\Mail\Mailer;
use OC\Memcache\ArrayCache;
use OC\Http\Client\ClientService;
use OC\Security\CertificateManager;
use OC\Files\Node\Root;
use OC\Files\View;
@ -236,9 +237,18 @@ class Server extends SimpleContainer implements IServerContainer {
});
$this->registerService('HTTPHelper', function (Server $c) {
$config = $c->getConfig();
$user = $c->getUserSession()->getUser();
$uid = $user ? $user->getUID() : null;
return new HTTPHelper($config, new \OC\Security\CertificateManager($uid, new \OC\Files\View()));
return new HTTPHelper(
$config,
$c->getHTTPClientService()
);
});
$this->registerService('HttpClientService', function (Server $c) {
$user = \OC_User::getUser();
$uid = $user ? $user : null;
return new ClientService(
$c->getConfig(),
new \OC\Security\CertificateManager($uid, new \OC\Files\View())
);
});
$this->registerService('EventLogger', function (Server $c) {
if (defined('DEBUG') and DEBUG) {
@ -664,7 +674,7 @@ class Server extends SimpleContainer implements IServerContainer {
/**
* Returns an instance of the HTTP helper class
*
* @deprecated Use getHTTPClientService()
* @return \OC\HTTPHelper
*/
function getHTTPHelper() {
@ -689,6 +699,15 @@ class Server extends SimpleContainer implements IServerContainer {
return new CertificateManager($uid, new \OC\Files\View());
}
/**
* Returns an instance of the HTTP client service
*
* @return \OCP\Http\Client\IClientService
*/
function getHTTPClientService() {
return $this->query('HttpClientService');
}
/**
* Create a new event source
*

View File

@ -1193,33 +1193,21 @@ class OC_Util {
/**
* Check if the ownCloud server can connect to the internet
*
* @param \OCP\Http\Client\IClientService $clientService
* @return bool
*/
public static function isInternetConnectionWorking() {
public static function isInternetConnectionWorking(\OCP\Http\Client\IClientService $clientService) {
// in case there is no internet connection on purpose return false
if (self::isInternetConnectionEnabled() === false) {
return false;
}
// in case the connection is via proxy return true to avoid connecting to owncloud.org
if (OC_Config::getValue('proxy', '') != '') {
return true;
}
// try to connect to owncloud.org to see if http connections to the internet are possible.
$connected = @fsockopen("www.owncloud.org", 80);
if ($connected) {
fclose($connected);
return true;
} else {
// second try in case one server is down
$connected = @fsockopen("apps.owncloud.com", 80);
if ($connected) {
fclose($connected);
return true;
} else {
return false;
}
try {
$client = $clientService->newClient();
$response = $client->get('https://www.owncloud.org/');
return $response->getStatusCode() === 200;
} catch (\Exception $e) {
return false;
}
}

View File

@ -0,0 +1,181 @@
<?php
/**
* Copyright (c) 2015 Lukas Reschke <lukas@owncloud.com>
* This file is licensed under the Affero General Public License version 3 or
* later.
* See the COPYING-README file.
*/
namespace OCP\Http\Client;
/**
* Interface IClient
*
* @package OCP\Http
*/
interface IClient {
/**
* Sends a GET request
* @param string $uri
* @param array $options Array such as
* 'query' => [
* 'field' => 'abc',
* 'other_field' => '123',
* 'file_name' => fopen('/path/to/file', 'r'),
* ],
* 'headers' => [
* 'foo' => 'bar',
* ],
* 'cookies' => ['
* 'foo' => 'bar',
* ],
* 'allow_redirects' => [
* 'max' => 10, // allow at most 10 redirects.
* 'strict' => true, // use "strict" RFC compliant redirects.
* 'referer' => true, // add a Referer header
* 'protocols' => ['https'] // only allow https URLs
* ],
* 'save_to' => '/path/to/file', // save to a file or a stream
* 'verify' => true, // bool or string to CA file
* 'debug' => true,
* @return IResponse
* @throws \Exception If the request could not get completed
*/
public function get($uri, array $options = []);
/**
* Sends a HEAD request
* @param string $uri
* @param array $options Array such as
* 'headers' => [
* 'foo' => 'bar',
* ],
* 'cookies' => ['
* 'foo' => 'bar',
* ],
* 'allow_redirects' => [
* 'max' => 10, // allow at most 10 redirects.
* 'strict' => true, // use "strict" RFC compliant redirects.
* 'referer' => true, // add a Referer header
* 'protocols' => ['https'] // only allow https URLs
* ],
* 'save_to' => '/path/to/file', // save to a file or a stream
* 'verify' => true, // bool or string to CA file
* 'debug' => true,
* @return IResponse
*/
public function head($uri, $options = []);
/**
* Sends a POST request
* @param string $uri
* @param array $options Array such as
* 'body' => [
* 'field' => 'abc',
* 'other_field' => '123',
* 'file_name' => fopen('/path/to/file', 'r'),
* ],
* 'headers' => [
* 'foo' => 'bar',
* ],
* 'cookies' => ['
* 'foo' => 'bar',
* ],
* 'allow_redirects' => [
* 'max' => 10, // allow at most 10 redirects.
* 'strict' => true, // use "strict" RFC compliant redirects.
* 'referer' => true, // add a Referer header
* 'protocols' => ['https'] // only allow https URLs
* ],
* 'save_to' => '/path/to/file', // save to a file or a stream
* 'verify' => true, // bool or string to CA file
* 'debug' => true,
* @return IResponse
*/
public function post($uri, array $options = []);
/**
* Sends a PUT request
* @param string $uri
* @param array $options Array such as
* 'body' => [
* 'field' => 'abc',
* 'other_field' => '123',
* 'file_name' => fopen('/path/to/file', 'r'),
* ],
* 'headers' => [
* 'foo' => 'bar',
* ],
* 'cookies' => ['
* 'foo' => 'bar',
* ],
* 'allow_redirects' => [
* 'max' => 10, // allow at most 10 redirects.
* 'strict' => true, // use "strict" RFC compliant redirects.
* 'referer' => true, // add a Referer header
* 'protocols' => ['https'] // only allow https URLs
* ],
* 'save_to' => '/path/to/file', // save to a file or a stream
* 'verify' => true, // bool or string to CA file
* 'debug' => true,
* @return IResponse
*/
public function put($uri, array $options = []);
/**
* Sends a DELETE request
* @param string $uri
* @param array $options Array such as
* 'body' => [
* 'field' => 'abc',
* 'other_field' => '123',
* 'file_name' => fopen('/path/to/file', 'r'),
* ],
* 'headers' => [
* 'foo' => 'bar',
* ],
* 'cookies' => ['
* 'foo' => 'bar',
* ],
* 'allow_redirects' => [
* 'max' => 10, // allow at most 10 redirects.
* 'strict' => true, // use "strict" RFC compliant redirects.
* 'referer' => true, // add a Referer header
* 'protocols' => ['https'] // only allow https URLs
* ],
* 'save_to' => '/path/to/file', // save to a file or a stream
* 'verify' => true, // bool or string to CA file
* 'debug' => true,
* @return IResponse
*/
public function delete($uri, array $options = []);
/**
* Sends a options request
* @param string $uri
* @param array $options Array such as
* 'body' => [
* 'field' => 'abc',
* 'other_field' => '123',
* 'file_name' => fopen('/path/to/file', 'r'),
* ],
* 'headers' => [
* 'foo' => 'bar',
* ],
* 'cookies' => ['
* 'foo' => 'bar',
* ],
* 'allow_redirects' => [
* 'max' => 10, // allow at most 10 redirects.
* 'strict' => true, // use "strict" RFC compliant redirects.
* 'referer' => true, // add a Referer header
* 'protocols' => ['https'] // only allow https URLs
* ],
* 'save_to' => '/path/to/file', // save to a file or a stream
* 'verify' => true, // bool or string to CA file
* 'debug' => true,
* @return IResponse
*/
public function options($uri, array $options = []);
}

View File

@ -0,0 +1,21 @@
<?php
/**
* Copyright (c) 2015 Lukas Reschke <lukas@owncloud.com>
* This file is licensed under the Affero General Public License version 3 or
* later.
* See the COPYING-README file.
*/
namespace OCP\Http\Client;
/**
* Interface IClientService
*
* @package OCP\Http
*/
interface IClientService {
/**
* @return IClient
*/
public function newClient();
}

View File

@ -0,0 +1,37 @@
<?php
/**
* Copyright (c) 2015 Lukas Reschke <lukas@owncloud.com>
* This file is licensed under the Affero General Public License version 3 or
* later.
* See the COPYING-README file.
*/
namespace OCP\Http\Client;
/**
* Interface IResponse
*
* @package OCP\Http
*/
interface IResponse {
/**
* @return string
*/
public function getBody();
/**
* @return int
*/
public function getStatusCode();
/**
* @param $key
* @return string
*/
public function getHeader($key);
/**
* @return array
*/
public function getHeaders();
}

View File

@ -267,9 +267,17 @@ interface IServerContainer {
/**
* Returns an instance of the HTTP helper class
* @return \OC\HTTPHelper
* @deprecated Use \OCP\Http\Client\IClientService
*/
function getHTTPHelper();
/**
* Returns an instance of the HTTP client service
*
* @return \OCP\Http\Client\IClientService
*/
function getHTTPClientService();
/**
* Get the active event logger
*

View File

@ -0,0 +1,77 @@
<?php
/**
* @author Lukas Reschke
* @copyright 2015 Lukas Reschke lukas@owncloud.com
*
* This file is licensed under the Affero General Public License version 3 or
* later.
* See the COPYING-README file.
*/
namespace OC\Repair;
use OC\Files\View;
use OC\Hooks\BasicEmitter;
use OC\RepairStep;
use OC\Server;
use OCP\IConfig;
/**
* Class UpdateCertificateStore rewrites the user specific certificate store after
* an update has been performed. This is done because a new root certificate file
* might have been added.
*
* @package OC\Repair
*/
class UpdateCertificateStore extends BasicEmitter implements RepairStep {
/**
* FIXME: The certificate manager does only allow specifying the user
* within the constructor. This makes DI impossible.
* @var Server
*/
protected $server;
/** @var IConfig */
protected $config;
/**
* @param Server $server
* @param IConfig $config
*/
public function __construct(Server $server,
IConfig $config) {
$this->server = $server;
$this->config = $config;
}
/** {@inheritDoc} */
public function getName() {
return 'Update user certificate stores with new root certificates';
}
/** {@inheritDoc} */
public function run() {
$rootView = new View();
$dataDirectory = $this->config->getSystemValue('datadirectory', null);
if(is_null($dataDirectory)) {
throw new \Exception('No data directory specified');
}
$pathToRootCerts = '/files_external/rootcerts.crt';
foreach($rootView->getDirectoryContent('', 'httpd/unix-directory') as $fileInfo) {
$uid = trim($fileInfo->getPath(), '/');
if($rootView->file_exists($uid . $pathToRootCerts)) {
// Delete the existing root certificate
$rootView->unlink($uid . $pathToRootCerts);
/**
* FIXME: The certificate manager does only allow specifying the user
* within the constructor. This makes DI impossible.
*/
// Regenerate the certificates
$certificateManager = $this->server->getCertificateManager($uid);
$certificateManager->createCertificateBundle();
}
}
}
}

View File

@ -13,7 +13,7 @@ OCP\JSON::callCheck();
// no warning when has_internet_connection is false in the config
$hasInternet = true;
if (OC_Util::isInternetConnectionEnabled()) {
$hasInternet = OC_Util::isInternetConnectionWorking();
$hasInternet = OC_Util::isInternetConnectionWorking(\OC::$server->getHTTPClientService());
}
OCP\JSON::success(

View File

@ -21,10 +21,10 @@ class InfoParser extends \PHPUnit_Framework_TestCase {
public function setUp() {
$config = $this->getMockBuilder('\OCP\IConfig')
->disableOriginalConstructor()->getMock();
$certificateManager = $this->getMock('\OCP\ICertificateManager');
$clientService = $this->getMock('\OCP\Http\Client\IClientService');
$httpHelper = $this->getMockBuilder('\OC\HTTPHelper')
->setConstructorArgs(array($config, $certificateManager))
->setMethods(array('getHeaders'))
->setConstructorArgs([$config, $clientService])
->setMethods(['getHeaders'])
->getMock();
$urlGenerator = $this->getMockBuilder('\OCP\IURLGenerator')
->disableOriginalConstructor()

View File

@ -0,0 +1,25 @@
<?php
/**
* Copyright (c) 2015 Lukas Reschke <lukas@owncloud.com>
* This file is licensed under the Affero General Public License version 3 or
* later.
* See the COPYING-README file.
*/
namespace OC\Http\Client;
use GuzzleHttp\Client as GuzzleClient;
/**
* Class ClientServiceTest
*/
class ClientServiceTest extends \Test\TestCase {
public function testNewClient() {
$config = $this->getMock('\OCP\IConfig');
$certificateManager = $this->getMock('\OCP\ICertificateManager');
$expected = new Client($config, $certificateManager, new GuzzleClient());
$clientService = new ClientService($config, $certificateManager);
$this->assertEquals($expected, $clientService->newClient());
}
}

View File

@ -0,0 +1,110 @@
<?php
/**
* Copyright (c) 2015 Lukas Reschke <lukas@owncloud.com>
* This file is licensed under the Affero General Public License version 3 or
* later.
* See the COPYING-README file.
*/
namespace OC\Http\Client;
use GuzzleHttp\Message\Response;
use OCP\IConfig;
/**
* Class ClientTest
*/
class ClientTest extends \Test\TestCase {
/** @var \GuzzleHttp\Client */
private $guzzleClient;
/** @var Client */
private $client;
/** @var IConfig */
private $config;
public function setUp() {
parent::setUp();
$this->config = $this->getMock('\OCP\IConfig');
$this->guzzleClient = $this->getMockBuilder('\GuzzleHttp\Client')
->disableOriginalConstructor()
->getMock();
$certificateManager = $this->getMock('\OCP\ICertificateManager');
$this->client = new Client(
$this->config,
$certificateManager,
$this->guzzleClient
);
}
public function testGetProxyUri() {
$this->config
->expects($this->at(0))
->method('getSystemValue')
->with('proxy', null)
->willReturn(null);
$this->config
->expects($this->at(1))
->method('getSystemValue')
->with('proxyuserpwd', null)
->willReturn(null);
$this->assertSame('', \Test_Helper::invokePrivate($this->client, 'getProxyUri'));
}
public function testGetProxyUriProxyHostEmptyPassword() {
$this->config
->expects($this->at(0))
->method('getSystemValue')
->with('proxy', null)
->willReturn('foo');
$this->config
->expects($this->at(1))
->method('getSystemValue')
->with('proxyuserpwd', null)
->willReturn(null);
$this->assertSame('foo', \Test_Helper::invokePrivate($this->client, 'getProxyUri'));
}
public function testGetProxyUriProxyHostWithPassword() {
$this->config
->expects($this->at(0))
->method('getSystemValue')
->with('proxy', null)
->willReturn('foo');
$this->config
->expects($this->at(1))
->method('getSystemValue')
->with('proxyuserpwd', null)
->willReturn('username:password');
$this->assertSame('username:password@foo', \Test_Helper::invokePrivate($this->client, 'getProxyUri'));
}
public function testGet() {
$this->guzzleClient->method('get')
->willReturn(new Response(1337));
$this->assertEquals(1337, $this->client->get('http://localhost/', [])->getStatusCode());
}
public function testPost() {
$this->guzzleClient->method('post')
->willReturn(new Response(1337));
$this->assertEquals(1337, $this->client->post('http://localhost/', [])->getStatusCode());
}
public function testPut() {
$this->guzzleClient->method('put')
->willReturn(new Response(1337));
$this->assertEquals(1337, $this->client->put('http://localhost/', [])->getStatusCode());
}
public function testDelete() {
$this->guzzleClient->method('delete')
->willReturn(new Response(1337));
$this->assertEquals(1337, $this->client->delete('http://localhost/', [])->getStatusCode());
}
public function testOptions() {
$this->guzzleClient->method('options')
->willReturn(new Response(1337));
$this->assertEquals(1337, $this->client->options('http://localhost/', [])->getStatusCode());
}
}

View File

@ -0,0 +1,37 @@
<?php
/**
* Copyright (c) 2015 Lukas Reschke <lukas@owncloud.com>
* This file is licensed under the Affero General Public License version 3 or
* later.
* See the COPYING-README file.
*/
namespace OC\Http\Client;
use Guzzle\Stream\Stream;
use GuzzleHttp\Message\Response as GuzzleResponse;
/**
* Class ResponseTest
*/
class ResponseTest extends \Test\TestCase {
/** @var Response */
private $response;
/** @var GuzzleResponse */
private $guzzleResponse;
public function setUp() {
parent::setUp();
$this->guzzleResponse = new GuzzleResponse(1337);
$this->response = new Response($this->guzzleResponse);
}
public function testGetStatusCode() {
$this->assertEquals(1337, $this->response->getStatusCode());
}
public function testGetHeader() {
$this->guzzleResponse->setHeader('bar', 'foo');
$this->assertEquals('foo', $this->response->getHeader('bar'));
}
}

View File

@ -12,17 +12,15 @@ class TestHTTPHelper extends \Test\TestCase {
private $config;
/** @var \OC\HTTPHelper */
private $httpHelperMock;
/** @var \OC\Security\CertificateManager */
private $certificateManager;
protected function setUp() {
parent::setUp();
$this->config = $this->getMockBuilder('\OCP\IConfig')
->disableOriginalConstructor()->getMock();
$this->certificateManager = $this->getMock('\OCP\ICertificateManager');
$clientService = $this->getMock('\OCP\Http\Client\IClientService');
$this->httpHelperMock = $this->getMockBuilder('\OC\HTTPHelper')
->setConstructorArgs(array($this->config, $this->certificateManager))
->setConstructorArgs(array($this->config, $clientService))
->setMethods(array('getHeaders'))
->getMock();
}
@ -46,21 +44,4 @@ class TestHTTPHelper extends \Test\TestCase {
public function testIsHTTP($url, $expected) {
$this->assertSame($expected, $this->httpHelperMock->isHTTPURL($url));
}
/**
* @dataProvider postParameters
*/
public function testAssemblePostParameters($parameterList, $expectedResult) {
$helper = \OC::$server->getHTTPHelper();
$result = \Test_Helper::invokePrivate($helper, 'assemblePostParameters', array($parameterList));
$this->assertSame($expectedResult, $result);
}
public function postParameters() {
return array(
array(array('k1' => 'v1'), 'k1=v1'),
array(array('k1' => 'v1', 'k2' => 'v2'), 'k1=v1&k2=v2'),
array(array(), ''),
);
}
}

View File

@ -93,9 +93,9 @@ class UpdaterTest extends \Test\TestCase {
->getMock()
;
$certificateManager = $this->getMock('\OCP\ICertificateManager');
$clientService = $this->getMock('\OCP\Http\Client\IClientService');
$mockedHTTPHelper = $this->getMockBuilder('\OC\HTTPHelper')
->setConstructorArgs(array(\OC::$server->getConfig(), $certificateManager))
->setConstructorArgs([\OC::$server->getConfig(), $clientService])
->getMock()
;