Skip to content

[Mailer] Stream timeout not detected due to checking only string result of function fgets #48074

Closed
@Sezil

Description

@Sezil

Symfony version(s) affected

5.4

Description

If stream timeouts on some network that is blocking the connection, PHP function fgets(resource $stream, ?int $length = null): string|false returns false instead of empty string '' so the 'timed_out' metadata check will not be executed and you will end up with the error Expected response code "220" but got empty code..
AbstractStream.php#L77

$line = fgets($this->out);
if ('' === $line) {
    $metas = stream_get_meta_data($this->out);
    if ($metas['timed_out']) {
        throw new TransportException(sprintf('Connection to "%s" timed out.', $this->getReadConnectionDescription()));
    }
    if ($metas['eof']) {
        throw new TransportException(sprintf('Connection to "%s" has been closed unexpectedly.', $this->getReadConnectionDescription()));
    }
}

How to reproduce

In my case, there is a blocked port 587 so when I try to connect to any XOauth2 SMTP servers it will wait for the amount of time set by the timeout setting and then throw Expected response code "220" but got empty code. instead of Connection to "SMTP" timed out..

Since the PHP documentation clearly states that fgets can return false I don't see the point in trying to reproduce it, stream metadata should be checked even if $line = false.

Possible Solution

stream metadata should be checked even if $line = false.

$line = fgets($this->out);
if ('' === $line || false === $line) {
    $metas = stream_get_meta_data($this->out);
    if ($metas['timed_out']) {
        throw new TransportException(sprintf('Connection to "%s" timed out.', $this->getReadConnectionDescription()));
    }
    if ($metas['eof']) {
        throw new TransportException(sprintf('Connection to "%s" has been closed unexpectedly.', $this->getReadConnectionDescription()));
    }
}

Additional Context

EXCEPTION
Class: Symfony\Component\Mailer\Exception\TransportException
Message: Expected response code "220" but got empty code.
Code: 0
Stack trace:

  • 0 ...\vendor\symfony\mailer\Transport\Smtp\SmtpTransport.php(252): Symfony\Component\Mailer\Transport\Smtp\SmtpTransport->assertResponseCode('', Array)
  • 1 ...\vendor\symfony\mailer\Transport\Smtp\SmtpTransport.php(194): Symfony\Component\Mailer\Transport\Smtp\SmtpTransport->start()
  • 2 ...\vendor\symfony\mailer\Transport\AbstractTransport.php(71): Symfony\Component\Mailer\Transport\Smtp\SmtpTransport->doSend(Object(Symfony\Component\Mailer\SentMessage))

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions