Skip to content

Commit

Permalink
Merge branch '4.4' into 5.0
Browse files Browse the repository at this point in the history
* 4.4:
  Add missing symfony/mime to require-dev
  [Validator] Added the missing Mongolian translations
  [ErrorHandler] Never throw on warnings triggered by assert() and set assert.exception=1 in Debug::enable()
  refactor(Process): fromShellCommandLine
  [Mailer] Do not ping the SMTP server before sending every message
  • Loading branch information
nicolas-grekas committed Feb 8, 2020
2 parents 73f8c96 + 48272f0 commit 255a748
Show file tree
Hide file tree
Showing 9 changed files with 412 additions and 1 deletion.
5 changes: 5 additions & 0 deletions src/Symfony/Component/ErrorHandler/Debug.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ public static function enable(): ErrorHandler
ini_set('display_errors', 1);
}

ini_set('zend.assertions', 1);
ini_set('assert.active', 1);
ini_set('assert.warning', 0);
ini_set('assert.exception', 1);

DebugClassLoader::enable();

return ErrorHandler::register(new ErrorHandler(new BufferingLogger(), true));
Expand Down
5 changes: 5 additions & 0 deletions src/Symfony/Component/ErrorHandler/ErrorHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,11 @@ public function handleError(int $type, string $message, string $file, int $line)
$throw = $this->thrownErrors & $type & $level;
$type &= $level | $this->screamedErrors;

// Never throw on warnings triggered by assert()
if (E_WARNING === $type && 'a' === $message[0] && 0 === strncmp($message, 'assert(): ', 10)) {
$throw = 0;
}

if (!$type || (!$log && !$throw)) {
return !$silenced && $type && $log;
}
Expand Down
35 changes: 35 additions & 0 deletions src/Symfony/Component/ErrorHandler/Tests/ErrorHandlerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -615,4 +615,39 @@ public function errorHandlerWhenLoggingProvider(): iterable
}
}
}

public function testAssertQuietEval()
{
$ini = [
ini_set('zend.assertions', 1),
ini_set('assert.active', 1),
ini_set('assert.bail', 0),
ini_set('assert.warning', 1),
ini_set('assert.callback', null),
ini_set('assert.exception', 0),
];

$logger = new BufferingLogger();
$handler = new ErrorHandler($logger);
$handler = ErrorHandler::register($handler);

try {
\assert(false);
} finally {
restore_error_handler();
restore_exception_handler();

ini_set('zend.assertions', $ini[0]);
ini_set('assert.active', $ini[1]);
ini_set('assert.bail', $ini[2]);
ini_set('assert.warning', $ini[3]);
ini_set('assert.callback', $ini[4]);
ini_set('assert.exception', $ini[5]);
}

$logs = $logger->cleanLogs();

$this->assertSame('warning', $logs[0][0]);
$this->assertSame('Warning: assert(): assert(false) failed', $logs[0][1]);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,12 @@
namespace Symfony\Component\Mailer\Tests\Transport\Smtp;

use PHPUnit\Framework\TestCase;
use Symfony\Component\Mailer\Envelope;
use Symfony\Component\Mailer\Transport\Smtp\SmtpTransport;
use Symfony\Component\Mailer\Transport\Smtp\Stream\AbstractStream;
use Symfony\Component\Mailer\Transport\Smtp\Stream\SocketStream;
use Symfony\Component\Mime\Address;
use Symfony\Component\Mime\RawMessage;

class SmtpTransportTest extends TestCase
{
Expand All @@ -25,4 +29,95 @@ public function testToString()
$t = new SmtpTransport((new SocketStream())->setHost('127.0.0.1')->setPort(2525)->disableTls());
$this->assertEquals('smtp://127.0.0.1:2525', (string) $t);
}

public function testSendDoesNotPingBelowThreshold(): void
{
$stream = new DummyStream();
$envelope = new Envelope(new Address('sender@example.org'), [new Address('recipient@example.org')]);

$transport = new SmtpTransport($stream);
$transport->send(new RawMessage('Message 1'), $envelope);
$transport->send(new RawMessage('Message 2'), $envelope);
$transport->send(new RawMessage('Message 3'), $envelope);

$this->assertNotContains("NOOP\r\n", $stream->getCommands());
}

public function testSendDoesPingAboveThreshold(): void
{
$stream = new DummyStream();
$envelope = new Envelope(new Address('sender@example.org'), [new Address('recipient@example.org')]);

$transport = new SmtpTransport($stream);
$transport->setPingThreshold(1);

$transport->send(new RawMessage('Message 1'), $envelope);
$transport->send(new RawMessage('Message 2'), $envelope);

$this->assertNotContains("NOOP\r\n", $stream->getCommands());

$stream->clearCommands();
sleep(1);

$transport->send(new RawMessage('Message 3'), $envelope);
$this->assertContains("NOOP\r\n", $stream->getCommands());
}
}

class DummyStream extends AbstractStream
{
/**
* @var string
*/
private $nextResponse;

/**
* @var string[]
*/
private $commands;

public function initialize(): void
{
$this->nextResponse = '220 localhost';
}

public function write(string $bytes, $debug = true): void
{
$this->commands[] = $bytes;

if (0 === strpos($bytes, 'DATA')) {
$this->nextResponse = '354 Enter message, ending with "." on a line by itself';
} elseif (0 === strpos($bytes, 'QUIT')) {
$this->nextResponse = '221 Goodbye';
} else {
$this->nextResponse = '250 OK';
}
}

public function readLine(): string
{
return $this->nextResponse;
}

public function flush(): void
{
}

/**
* @return string[]
*/
public function getCommands(): array
{
return $this->commands;
}

public function clearCommands(): void
{
$this->commands = [];
}

protected function getReadConnectionDescription(): string
{
return 'null';
}
}
32 changes: 31 additions & 1 deletion src/Symfony/Component/Mailer/Transport/Smtp/SmtpTransport.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ class SmtpTransport extends AbstractTransport
private $restartThreshold = 100;
private $restartThresholdSleep = 0;
private $restartCounter;
private $pingThreshold = 100;
private $lastMessageTime = 0;
private $stream;
private $domain = '[127.0.0.1]';

Expand Down Expand Up @@ -66,6 +68,28 @@ public function setRestartThreshold(int $threshold, int $sleep = 0): self
return $this;
}

/**
* Sets the minimum number of seconds required between two messages, before the server is pinged.
* If the transport wants to send a message and the time since the last message exceeds the specified threshold,
* the transport will ping the server first (NOOP command) to check if the connection is still alive.
* Otherwise the message will be sent without pinging the server first.
*
* Do not set the threshold too low, as the SMTP server may drop the connection if there are too many
* non-mail commands (like pinging the server with NOOP).
*
* By default, the threshold is set to 100 seconds.
*
* @param int $seconds The minimum number of seconds between two messages required to ping the server
*
* @return $this
*/
public function setPingThreshold(int $seconds): self
{
$this->pingThreshold = $seconds;

return $this;
}

/**
* Sets the name of the local domain that will be used in HELO.
*
Expand Down Expand Up @@ -160,7 +184,10 @@ public function executeCommand(string $command, array $codes): string

protected function doSend(SentMessage $message): void
{
$this->ping();
if (microtime(true) - $this->lastMessageTime > $this->pingThreshold) {
$this->ping();
}

if (!$this->started) {
$this->start();
}
Expand All @@ -183,6 +210,8 @@ protected function doSend(SentMessage $message): void
$e->appendDebug($this->stream->getDebug());

throw $e;
} finally {
$this->lastMessageTime = microtime(true);
}
}

Expand Down Expand Up @@ -213,6 +242,7 @@ private function start(): void
$this->assertResponseCode($this->getFullResponse(), [220]);
$this->doHeloCommand();
$this->started = true;
$this->lastMessageTime = 0;

$this->getLogger()->debug(sprintf('Email transport "%s" started', __CLASS__));
}
Expand Down
9 changes: 9 additions & 0 deletions src/Symfony/Component/Process/PhpProcess.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

namespace Symfony\Component\Process;

use Symfony\Component\Process\Exception\LogicException;
use Symfony\Component\Process\Exception\RuntimeException;

/**
Expand Down Expand Up @@ -49,6 +50,14 @@ public function __construct(string $script, string $cwd = null, array $env = nul
parent::__construct($php, $cwd, $env, $script, $timeout);
}

/**
* {@inheritdoc}
*/
public static function fromShellCommandline(string $command, string $cwd = null, array $env = null, $input = null, ?float $timeout = 60)
{
throw new LogicException(sprintf('The "%s()" method cannot be called when using "%s".', __METHOD__, self::class));
}

/**
* {@inheritdoc}
*/
Expand Down
11 changes: 11 additions & 0 deletions src/Symfony/Component/Process/Tests/PhpProcessTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
namespace Symfony\Component\Process\Tests;

use PHPUnit\Framework\TestCase;
use Symfony\Component\Process\Exception\LogicException;
use Symfony\Component\Process\PhpExecutableFinder;
use Symfony\Component\Process\PhpProcess;

Expand Down Expand Up @@ -60,4 +61,14 @@ public function testPassingPhpExplicitly()
$process->run();
$this->assertEquals($expected, $process->getOutput());
}

public function testProcessCannotBeCreatedUsingFromShellCommandLine()
{
static::expectException(LogicException::class);
static::expectExceptionMessage('The "Symfony\Component\Process\PhpProcess::fromShellCommandline()" method cannot be called when using "Symfony\Component\Process\PhpProcess".');
PhpProcess::fromShellCommandline(<<<PHP
<?php echo 'Hello World!';
PHP
);
}
}
Loading

0 comments on commit 255a748

Please sign in to comment.