Skip to content

Commit

Permalink
bug symfony#57224 [Mime] Use streams instead of loading raw message g…
Browse files Browse the repository at this point in the history
…enerator into memory (bytestream)

This PR was squashed before being merged into the 6.4 branch.

Discussion
----------

[Mime] Use streams instead of loading raw message generator into memory

| Q             | A
| ------------- | ---
| Branch?       | 6.4
| Bug fix?      | yes
| New feature?  | no
| Deprecations? | no
| Issues        | Fix symfony#51764
| License       | MIT

Generators can only be used once and so the previous iteration of the code loaded the contents of the generator into memory. That results in OOM errors when sending large e-mails.

This PR changes the behaviour so that the generator contents are loaded into a `php://temp` stream. By default 2MB is stored in memory and the rest is written to temporary files to prevent OOM issues.

Commits
-------

5471940 [Mime] Use streams instead of loading raw message generator into memory
  • Loading branch information
fabpot committed Jun 3, 2024
2 parents 9972537 + 5471940 commit b358048
Showing 1 changed file with 24 additions and 3 deletions.
27 changes: 24 additions & 3 deletions src/Symfony/Component/Mime/RawMessage.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,32 @@
*/
class RawMessage
{
private iterable|string $message;
/** @var iterable|string|resource */
private $message;
private bool $isGeneratorClosed;

public function __construct(iterable|string $message)
{
$this->message = $message;
}

public function __destruct()
{
if (\is_resource($this->message)) {
fclose($this->message);
}
}

public function toString(): string
{
if (\is_string($this->message)) {
return $this->message;
}

if (\is_resource($this->message)) {
return stream_get_contents($this->message, -1, 0);
}

$message = '';
foreach ($this->message as $chunk) {
$message .= $chunk;
Expand All @@ -53,10 +65,19 @@ public function toIterable(): iterable
return;
}

if (\is_resource($this->message)) {
rewind($this->message);
while ($line = fgets($this->message)) {
yield $line;
}

return;
}

if ($this->message instanceof \Generator) {
$message = '';
$message = fopen('php://temp', 'w+');
foreach ($this->message as $chunk) {
$message .= $chunk;
fwrite($message, $chunk);
yield $chunk;
}
$this->isGeneratorClosed = !$this->message->valid();
Expand Down

0 comments on commit b358048

Please sign in to comment.