Skip to content

Commit ca0978d

Browse files
authored
Merge pull request #10 from dcarbone/feature/better-guzzle-integration
Feature/better guzzle integration
2 parents d354a71 + 483a49a commit ca0978d

File tree

5 files changed

+189
-46
lines changed

5 files changed

+189
-46
lines changed

README.md

+12-10
Original file line numberDiff line numberDiff line change
@@ -48,16 +48,18 @@ You may alternatively define values yourself:
4848

4949
```php
5050
$config = new \DCarbone\PHPConsulAPI\Config([
51-
'HttpClient' => $client // REQUIRED Client conforming to GuzzleHttp\ClientInterface
52-
53-
'Address' => 'address of server', // REQUIRED
54-
'Scheme' => 'http or https', // REQUIRED
55-
'Datacenter' => 'name of datacenter', // OPTIONAL
56-
'HttpAuth' => 'user:pass', // OPTIONAL,
57-
'WaitTime' => 30, // OPTIONAL, not used yet
58-
'Token' => 'auth token', // OPTIONAL
59-
'TokenInHeader' => false // OPTIONAL
60-
'InsecureSkipVerify' => false, // OPTIONAL
51+
'HttpClient' => $client // [required] Client conforming to GuzzleHttp\ClientInterface
52+
'Address' => 'address of server', // [required]
53+
54+
'Scheme' => 'http or https', // [optional] defaults to "http"
55+
'Datacenter' => 'name of datacenter', // [optional]
56+
'HttpAuth' => 'user:pass', // [optional]
57+
'Token' => 'auth token', // [optional] default auth token to use
58+
'TokenInHeader' => false, // [optional] specifies whether to send the token in the header or query string
59+
'InsecureSkipVerify' => false, // [optional] if set to true, ignores all SSL validation
60+
'CAFile' => '', // [optional] path to ca cert file, see http://docs.guzzlephp.org/en/latest/request-options.html#verify
61+
'CertFile' => '', // [optional] path to client pem. if set, requires KeyFile also be set
62+
'KeyFile' => '', // [optional] path to client
6163
]);
6264
```
6365

src/AbstractClient.php

+1-5
Original file line numberDiff line numberDiff line change
@@ -101,11 +101,7 @@ protected function doRequest(Request $r) {
101101
try {
102102
// If we actually have a client defined...
103103
if (isset($this->c->HttpClient) && $this->c->HttpClient instanceof ClientInterface) {
104-
$response = $this->c->HttpClient->send($r->toPsrRequest(), [
105-
'http_errors' => false,
106-
'verify' => $this->c->isInsecureSkipVerify(),
107-
'decode_content' => false,
108-
]);
104+
$response = $this->c->HttpClient->send($r->toPsrRequest(), $this->c->getGuzzleRequestOptions());
109105
} // Otherwise, throw error to be caught below
110106
else {
111107
throw new \RuntimeException('Unable to execute query as no HttpClient has been defined.');

src/Config.php

+165-29
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
*/
1818
use GuzzleHttp\Client;
1919
use GuzzleHttp\ClientInterface;
20+
use GuzzleHttp\RequestOptions;
2021

2122
/**
2223
* Class Config
@@ -65,6 +66,27 @@ class Config {
6566
*/
6667
public $Token = '';
6768

69+
/**
70+
* Optional path to CA certificate
71+
*
72+
* @var string
73+
*/
74+
public $CAFile = '';
75+
76+
/**
77+
* Optional path to certificate. If set, KeyFile must also be set
78+
*
79+
* @var string
80+
*/
81+
public $CertFile = '';
82+
83+
/**
84+
* Optional path to private key. If set, CertFile must also be set
85+
*
86+
* @var string
87+
*/
88+
public $KeyFile = '';
89+
6890
/**
6991
* Whether to skip SSL validation. This does nothing unless you use it within your HttpClient of choice.
7092
*
@@ -91,13 +113,30 @@ class Config {
91113
* @param array $config
92114
*/
93115
public function __construct(array $config = []) {
94-
foreach ($config as $k => $v) {
116+
foreach ($config + self::getDefaultConfig() as $k => $v) {
95117
$this->{"set{$k}"}($v);
96118
}
97119

98120
if (null !== $this->HttpAuth && !isset($this->HttpAuth)) {
99121
$this->HttpAuth = new HttpAuth();
100122
}
123+
124+
// quick validation on key/cert combo
125+
$c = $this->getCertFile();
126+
$k = $this->getKeyFile();
127+
if (('' !== $k && '' === $c) || ('' !== $c && '' === $k)) {
128+
throw new \InvalidArgumentException(sprintf(
129+
'%s - CertFile and KeyFile must be both either empty or populated. Key: %s; Cert: %s',
130+
get_class($this),
131+
$k,
132+
$c
133+
));
134+
}
135+
136+
// if client hasn't been constructed, construct.
137+
if (null === $this->HttpClient) {
138+
$this->HttpClient = new Client();
139+
}
101140
}
102141

103142
/**
@@ -106,34 +145,52 @@ public function __construct(array $config = []) {
106145
* @return \DCarbone\PHPConsulAPI\Config
107146
*/
108147
public static function newDefaultConfig() {
109-
$conf = new static([
148+
return new static(self::getDefaultConfig());
149+
}
150+
151+
/**
152+
* @return array
153+
*/
154+
private static function getDefaultConfig() {
155+
$conf = [
110156
'Address' => '127.0.0.1:8500',
111157
'Scheme' => 'http',
112-
]);
113-
114-
$envParams = static::getEnvironmentConfig();
115-
if (isset($envParams[Consul::HTTPAddrEnvName])) {
116-
$conf->setAddress($envParams[Consul::HTTPAddrEnvName]);
117-
}
118-
119-
if (isset($envParams[Consul::HTTPTokenEnvName])) {
120-
$conf->setToken($envParams[Consul::HTTPTokenEnvName]);
121-
}
122-
123-
if (isset($envParams[Consul::HTTPAuthEnvName])) {
124-
$conf->setHttpAuth($envParams[Consul::HTTPAuthEnvName]);
125-
}
126-
127-
if (isset($envParams[Consul::HTTPSSLEnvName]) && $envParams[Consul::HTTPSSLEnvName]) {
128-
$conf->setScheme('https');
129-
}
130-
131-
if (isset($envParams[Consul::HTTPSSLVerifyEnvName]) && !$envParams[Consul::HTTPSSLVerifyEnvName]) {
132-
$conf->setInsecureSkipVerify(false);
158+
];
159+
160+
// parse env vars
161+
foreach (static::getEnvironmentConfig() as $k => $v) {
162+
switch ($k) {
163+
case Consul::HTTPAddrEnvName:
164+
$conf['Address'] = $v;
165+
break;
166+
case Consul::HTTPTokenEnvName:
167+
$conf['Token'] = $v;
168+
break;
169+
case Consul::HTTPAuthEnvName:
170+
$conf['HttpAuth'] = $v;
171+
break;
172+
case Consul::HTTPCAFileEnvName:
173+
$conf['CAFile'] = $v;
174+
break;
175+
case Consul::HTTPClientCertEnvName:
176+
$conf['CertFile'] = $v;
177+
break;
178+
case Consul::HTTPClientKeyEnvName:
179+
$conf['KeyFile'] = $v;
180+
break;
181+
case Consul::HTTPSSLEnvName:
182+
if ((bool)$v) {
183+
$conf['Scheme'] = 'https';
184+
}
185+
break;
186+
case Consul::HTTPSSLVerifyEnvName:
187+
if ((bool)$v) {
188+
$conf['InsecureSkipVerify'] = true;
189+
}
190+
break;
191+
}
133192
}
134193

135-
$conf->setHttpClient(new Client());
136-
137194
return $conf;
138195
}
139196

@@ -269,6 +326,54 @@ public function setHttpAuth($HttpAuth) {
269326
));
270327
}
271328

329+
/**
330+
* @return string
331+
*/
332+
public function getCAFile() {
333+
return $this->CAFile;
334+
}
335+
336+
/**
337+
* @param string $CAFile
338+
* @return \DCarbone\PHPConsulAPI\Config
339+
*/
340+
public function setCAFile($CAFile) {
341+
$this->CAFile = $CAFile;
342+
return $this;
343+
}
344+
345+
/**
346+
* @return string
347+
*/
348+
public function getCertFile() {
349+
return $this->CertFile;
350+
}
351+
352+
/**
353+
* @param string $CertFile
354+
* @return \DCarbone\PHPConsulAPI\Config
355+
*/
356+
public function setCertFile($CertFile) {
357+
$this->CertFile = $CertFile;
358+
return $this;
359+
}
360+
361+
/**
362+
* @return string
363+
*/
364+
public function getKeyFile() {
365+
return $this->KeyFile;
366+
}
367+
368+
/**
369+
* @param string $KeyFile
370+
* @return \DCarbone\PHPConsulAPI\Config
371+
*/
372+
public function setKeyFile($KeyFile) {
373+
$this->KeyFile = $KeyFile;
374+
return $this;
375+
}
376+
272377
/**
273378
* @return \GuzzleHttp\ClientInterface
274379
*/
@@ -319,15 +424,42 @@ public function intToMillisecond($in) {
319424
return sprintf('%dms', $ms);
320425
}
321426

427+
/**
428+
* @return array
429+
*/
430+
public function getGuzzleRequestOptions() {
431+
// TODO: Define once?
432+
$opts = [
433+
RequestOptions::HTTP_ERRORS => false,
434+
RequestOptions::DECODE_CONTENT => false,
435+
];
436+
437+
if (!$this->isInsecureSkipVerify()) {
438+
$opts[RequestOptions::VERIFY] = false;
439+
} else if ('' !== ($b = $this->getCAFile())) {
440+
$opts[RequestOptions::VERIFY] = $b;
441+
}
442+
443+
if ('' !== ($c = $this->getCertFile())) {
444+
$opts[RequestOptions::CERT] = $c;
445+
$opts[RequestOptions::SSL_KEY] = $this->getKeyFile();
446+
}
447+
448+
return $opts;
449+
}
450+
322451
/**
323452
* @return array
324453
*/
325454
public static function getEnvironmentConfig() {
326455
return array_filter([
327-
'CONSUL_HTTP_ADDR' => static::_tryGetEnvParam('CONSUL_HTTP_ADDR'),
328-
'CONSUL_HTTP_AUTH' => static::_tryGetEnvParam('CONSUL_HTTP_AUTH'),
329-
'CONSUL_HTTP_SSL' => static::_tryGetEnvParam('CONSUL_HTTP_SSL'),
330-
'CONSUL_HTTP_SSL_VERIFY' => static::_tryGetEnvParam('CONSUL_HTTP_SSL_VERIFY')
456+
Consul::HTTPAddrEnvName => static::_tryGetEnvParam(Consul::HTTPAddrEnvName),
457+
Consul::HTTPAuthEnvName => static::_tryGetEnvParam(Consul::HTTPAuthEnvName),
458+
Consul::HTTPCAFileEnvName => static::_tryGetEnvParam(Consul::HTTPCAFileEnvName),
459+
Consul::HTTPClientCertEnvName => static::_tryGetEnvParam(Consul::HTTPClientCertEnvName),
460+
Consul::HTTPClientKeyEnvName => static::_tryGetEnvParam(Consul::HTTPClientKeyEnvName),
461+
Consul::HTTPSSLEnvName => static::_tryGetEnvParam(Consul::HTTPSSLEnvName),
462+
Consul::HTTPSSLVerifyEnvName => static::_tryGetEnvParam(Consul::HTTPSSLVerifyEnvName),
331463
],
332464
function ($val) {
333465
return null !== $val;
@@ -339,6 +471,10 @@ function ($val) {
339471
* @return string|null
340472
*/
341473
protected static function _tryGetEnvParam($param) {
474+
if (isset($_ENV[$param])) {
475+
return $_ENV[$param];
476+
}
477+
342478
if (false !== ($value = getenv($param))) {
343479
return $value;
344480
}

src/Consul.php

+3
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ class Consul {
3636
const HTTPAddrEnvName = 'CONSUL_HTTP_ADDR';
3737
const HTTPTokenEnvName = 'CONSUL_HTTP_TOKEN';
3838
const HTTPAuthEnvName = 'CONSUL_HTTP_AUTH';
39+
const HTTPCAFileEnvName = "CONSUL_CACERT";
40+
const HTTPClientCertEnvName = "CONSUL_CLIENT_CERT";
41+
const HTTPClientKeyEnvName = "CONSUL_CLIENT_KEY";
3942
const HTTPSSLEnvName = 'CONSUL_HTTP_SSL';
4043
const HTTPSSLVerifyEnvName = 'CONSUL_HTTP_SSL_VERIFY';
4144

tests/Definition/ConfigDefinitionTest.php

+8-2
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,14 @@ class ConfigDefinitionTest extends AbstractDefinitionTestCases
2727
/**
2828
* @inheritDoc
2929
*/
30-
protected function getSubjectClassName()
31-
{
30+
protected function getSubjectClassName() {
3231
return Config::class;
3332
}
33+
34+
/**
35+
* @return object
36+
*/
37+
protected function getEmptyInstance() {
38+
return $this->createMock($this->getSubjectClassName());
39+
}
3440
}

0 commit comments

Comments
 (0)