Skip to content
This repository has been archived by the owner on Jan 30, 2020. It is now read-only.

Commit

Permalink
Merge branch 'hotfix/zf2-490'
Browse files Browse the repository at this point in the history
  • Loading branch information
weierophinney committed Aug 23, 2012
2 parents 3025666 + 7befdef commit 219c9ad
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 32 deletions.
114 changes: 87 additions & 27 deletions src/Client/Adapter/Socket.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,18 @@
*/
class Socket implements HttpAdapter, StreamInterface
{
/**
* Map SSL transport wrappers to stream crypto method constants
*
* @var array
*/
protected static $sslCryptoTypes = array(
'ssl' => STREAM_CRYPTO_METHOD_SSLv23_CLIENT,
'sslv2' => STREAM_CRYPTO_METHOD_SSLv2_CLIENT,
'sslv3' => STREAM_CRYPTO_METHOD_SSLv3_CLIENT,
'tls' => STREAM_CRYPTO_METHOD_TLS_CLIENT
);

/**
* The socket for server connection
*
Expand Down Expand Up @@ -174,50 +186,53 @@ public function getStreamContext()
*/
public function connect($host, $port = 80, $secure = false)
{
// If the URI should be accessed via SSL, prepend the Hostname with ssl://
$host = ($secure ? $this->config['ssltransport'] : 'tcp') . '://' . $host;

// If we are connected to the wrong host, disconnect first
if (($this->connected_to[0] != $host || $this->connected_to[1] != $port)) {
if (is_resource($this->socket)) $this->close();
if (is_resource($this->socket)) {
$this->close();
}
}

// Now, if we are not connected, connect
if (! is_resource($this->socket) || ! $this->config['keepalive']) {
if (!is_resource($this->socket) || ! $this->config['keepalive']) {
$context = $this->getStreamContext();

if ($secure || $this->config['sslusecontext']) {
if ($this->config['sslverifypeer'] !== null) {
if (! stream_context_set_option($context, 'ssl', 'verify_peer',
$this->config['sslverifypeer'])) {
if (!stream_context_set_option($context, 'ssl', 'verify_peer', $this->config['sslverifypeer'])) {
throw new AdapterException\RuntimeException('Unable to set sslverifypeer option');
}
if (! stream_context_set_option($context, 'ssl', 'capath',
$this->config['sslcapath'])) {
}

if ($this->config['sslcapath']) {
if (!stream_context_set_option($context, 'ssl', 'capath', $this->config['sslcapath'])) {
throw new AdapterException\RuntimeException('Unable to set sslcapath option');
}
if ($this->config['sslallowselfsigned'] !== null) {
if (! stream_context_set_option($context, 'ssl', 'allow_self_signed',
$this->config['sslallowselfsigned'])) {
throw new AdapterException\RuntimeException('Unable to set sslallowselfsigned option');
}
}

if ($this->config['sslallowselfsigned'] !== null) {
if (!stream_context_set_option($context, 'ssl', 'allow_self_signed', $this->config['sslallowselfsigned'])) {
throw new AdapterException\RuntimeException('Unable to set sslallowselfsigned option');
}
}

if ($this->config['sslcert'] !== null) {
if (! stream_context_set_option($context, 'ssl', 'local_cert',
$this->config['sslcert'])) {
if (!stream_context_set_option($context, 'ssl', 'local_cert', $this->config['sslcert'])) {
throw new AdapterException\RuntimeException('Unable to set sslcert option');
}
}

if ($this->config['sslpassphrase'] !== null) {
if (! stream_context_set_option($context, 'ssl', 'passphrase',
$this->config['sslpassphrase'])) {
if (!stream_context_set_option($context, 'ssl', 'passphrase', $this->config['sslpassphrase'])) {
throw new AdapterException\RuntimeException('Unable to set sslpassphrase option');
}
}
}

$flags = STREAM_CLIENT_CONNECT;
if ($this->config['persistent']) $flags |= STREAM_CLIENT_PERSISTENT;
if ($this->config['persistent']) {
$flags |= STREAM_CLIENT_PERSISTENT;
}

ErrorHandler::start();
$this->socket = stream_socket_client(
Expand All @@ -230,21 +245,66 @@ public function connect($host, $port = 80, $secure = false)
);
$error = ErrorHandler::stop();

if (! $this->socket) {
if (!$this->socket) {
$this->close();
throw new AdapterException\RuntimeException(sprintf(
'Unable to connect to %s:%d%s',
$host,
$port,
($error ? '. Error #' . $error->getCode() . ': ' . $error->getMessage() : '')
), 0, $error);
throw new AdapterException\RuntimeException(
sprintf(
'Unable to connect to %s:%d%s',
$host,
$port,
($error ? '. Error #' . $error->getCode() . ': ' . $error->getMessage() : '')
),
0,
$error
);
}

// Set the stream timeout
if (! stream_set_timeout($this->socket, (int) $this->config['timeout'])) {
if (!stream_set_timeout($this->socket, (int) $this->config['timeout'])) {
throw new AdapterException\RuntimeException('Unable to set the connection timeout');
}

if ($secure || $this->config['sslusecontext']) {
if ($this->config['ssltransport'] && isset(self::$sslCryptoTypes[$this->config['ssltransport']])) {
$sslCryptoMethod = self::$sslCryptoTypes[$this->config['ssltransport']];
} else {
$sslCryptoMethod = STREAM_CRYPTO_METHOD_SSLv23_CLIENT;
}

ErrorHandler::start();
$test = stream_socket_enable_crypto($this->socket, true, $sslCryptoMethod);
$error = ErrorHandler::stop();
if (!$test || $error) {
// Error handling is kind of difficult when it comes to SSL
$errorString = '';
while (($sslError = openssl_error_string()) != false) {
$errorString .= "; SSL error: $sslError";
}
$this->close();

if ((! $errorString) && $this->config['sslverifypeer']) {
// There's good chance our error is due to sslcapath not being properly set
if (! ($this->config['sslcapath'] && is_dir($this->config['sslcapath']))) {
$errorString = 'make sure the "sslcapath" option points to a valid SSL certificate directory';
}
}

if ($errorString) {
$errorString = ": $errorString";
}

throw new AdapterException\RuntimeException(sprintf(
'Unable to enable crypto on TCP connection %s%s',
$host,
$errorString
), 0, $error);
}

$host = $this->config['ssltransport'] . "://" . $host;
} else {
$host = 'tcp://' . $host;
}

// Update connected_to
$this->connected_to = array($host, $port);
}
Expand Down
15 changes: 10 additions & 5 deletions test/Client/SocketTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -130,15 +130,17 @@ public function testSetConfigInvalidConfig($config)

public function testGetNewStreamContext()
{
$adapter = new $this->config['adapter'];
$adapterClass = $this->config['adapter'];
$adapter = new $adapterClass;
$context = $adapter->getStreamContext();

$this->assertEquals('stream-context', get_resource_type($context));
}

public function testSetNewStreamContextResource()
{
$adapter = new $this->config['adapter'];
$adapterClass = $this->config['adapter'];
$adapter = new $adapterClass;
$context = stream_context_create();

$adapter->setStreamContext($context);
Expand All @@ -148,7 +150,8 @@ public function testSetNewStreamContextResource()

public function testSetNewStreamContextOptions()
{
$adapter = new $this->config['adapter'];
$adapterClass = $this->config['adapter'];
$adapter = new $adapterClass;
$options = array(
'socket' => array(
'bindto' => '1.2.3.4:0'
Expand Down Expand Up @@ -176,7 +179,8 @@ public function testSetInvalidContextOptions($invalid)
'Zend\Http\Client\Adapter\Exception\InvalidArgumentException',
'Expecting either a stream context resource or array');

$adapter = new $this->config['adapter'];
$adapterClass = $this->config['adapter'];
$adapter = new $adapterClass;
$adapter->setStreamContext($invalid);
}

Expand All @@ -186,7 +190,8 @@ public function testSetHttpsStreamContextParam()
$this->markTestSkipped();
}

$adapter = new $this->config['adapter'];
$adapterClass = $this->config['adapter'];
$adapter = new $adapterClass;
$adapter->setStreamContext(array(
'ssl' => array(
'capture_peer_cert' => true,
Expand Down

0 comments on commit 219c9ad

Please sign in to comment.