Unverified Commit f2915d9a authored by larowlan's avatar larowlan

Issue #2704597 by Neograph734, Berdir, izus, alexpott, TR: Relative URLs in...

Issue #2704597 by Neograph734, Berdir, izus, alexpott, TR: Relative URLs in mails should be converted to absolute ones

(cherry picked from commit 530f7ac5)
parent 531be499
......@@ -2,7 +2,9 @@
namespace Drupal\Core\Mail;
use Drupal\Component\Render\MarkupInterface;
use Drupal\Component\Render\PlainTextOutput;
use Drupal\Component\Utility\Html;
use Drupal\Component\Utility\Unicode;
use Drupal\Core\Logger\LoggerChannelFactoryInterface;
use Drupal\Core\Messenger\MessengerTrait;
......@@ -10,6 +12,7 @@
use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Render\Markup;
use Drupal\Core\Render\RenderContext;
use Drupal\Core\Render\RendererInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
......@@ -277,6 +280,13 @@ public function doMail($module, $key, $to, $langcode, $params = [], $reply = NUL
// Retrieve the responsible implementation for this message.
$system = $this->getInstance(['module' => $module, 'key' => $key]);
// Attempt to convert relative URLs to absolute.
foreach ($message['body'] as &$body_part) {
if ($body_part instanceof MarkupInterface) {
$body_part = Markup::create(Html::transformRootRelativeUrlsToAbsolute((string) $body_part, \Drupal::request()->getSchemeAndHttpHost()));
}
}
// Format the message body.
$message = $system->format($message);
......
name: 'HTML mail test support'
description: 'Test if HTML in mails works as expected.'
type: module
package: Testing
version: VERSION
core: 8.x
<?php
/**
* @file
* Helper module for the html mail and url conversion tests.
*/
/**
* Implements hook_mail().
*/
function mail_html_test_mail($key, &$message, $params) {
switch ($key) {
case 'render_from_message_param':
$message['body'][] = \Drupal::service('renderer')->renderPlain($params['message']);
break;
}
}
<?php
namespace Drupal\mail_html_test\Plugin\Mail;
use Drupal\Core\Mail\MailFormatHelper;
use Drupal\Core\Mail\Plugin\Mail\TestMailCollector;
/**
* Defines a mail backend that captures sent HTML messages in the state system.
*
* This class is for running tests or for development and does not convert HTML
* to plaintext.
*
* @Mail(
* id = "test_html_mail_collector",
* label = @Translation("HTML mail collector"),
* description = @Translation("Does not send the message, but stores its HTML in Drupal within the state system. Used for testing.")
* )
*/
class TestHtmlMailCollector extends TestMailCollector {
/**
* {@inheritdoc}
*/
public function format(array $message) {
// Join the body array into one string.
$message['body'] = implode(PHP_EOL, $message['body']);
// Wrap the mail body for sending.
$message['body'] = MailFormatHelper::wrapMail($message['body']);
return $message;
}
}
......@@ -2,8 +2,13 @@
namespace Drupal\Tests\system\Functional\Mail;
use Drupal\Component\Utility\Random;
use Drupal\Component\Utility\Unicode;
use Drupal\Core\Mail\MailFormatHelper;
use Drupal\Core\Mail\Plugin\Mail\TestMailCollector;
use Drupal\Core\Render\Markup;
use Drupal\Core\Url;
use Drupal\file\Entity\File;
use Drupal\Tests\BrowserTestBase;
use Drupal\system_mail_failure_test\Plugin\Mail\TestPhpMailFailure;
......@@ -19,7 +24,7 @@ class MailTest extends BrowserTestBase {
*
* @var array
*/
public static $modules = ['simpletest', 'system_mail_failure_test'];
public static $modules = ['simpletest', 'system_mail_failure_test', 'mail_html_test', 'file', 'image'];
/**
* Assert that the pluggable mail system is functional.
......@@ -104,4 +109,178 @@ public function testFromAndReplyToHeader() {
$this->assertFalse(isset($sent_message['headers']['Errors-To']), 'Errors-to header must not be set, it is deprecated.');
}
/**
* Checks that relative paths in mails are converted into absolute URLs.
*/
public function testConvertRelativeUrlsIntoAbsolute() {
$language_interface = \Drupal::languageManager()->getCurrentLanguage();
// Use the HTML compatible state system collector mail backend.
$this->config('system.mail')->set('interface.default', 'test_html_mail_collector')->save();
// Fetch the hostname and port for matching against.
$http_host = \Drupal::request()->getSchemeAndHttpHost();
// Random generator.
$random = new Random();
// One random tag name.
$tag_name = strtolower($random->name(8, TRUE));
// Test root relative urls.
foreach (['href', 'src'] as $attribute) {
// Reset the state variable that holds sent messages.
\Drupal::state()->set('system.test_mail_collector', []);
$html = "<$tag_name $attribute=\"/root-relative\">root relative url in mail test</$tag_name>";
$expected_html = "<$tag_name $attribute=\"{$http_host}/root-relative\">root relative url in mail test</$tag_name>";
// Prepare render array.
$render = ['#markup' => Markup::create($html)];
// Send a test message that simpletest_mail_alter should cancel.
\Drupal::service('plugin.manager.mail')->mail('mail_html_test', 'render_from_message_param', 'relative_url@example.com', $language_interface->getId(), ['message' => $render]);
// Retrieve sent message.
$captured_emails = \Drupal::state()->get('system.test_mail_collector');
$sent_message = end($captured_emails);
// Wrap the expected HTML and assert.
$expected_html = MailFormatHelper::wrapMail($expected_html);
$this->assertSame($expected_html, $sent_message['body'], "Asserting that {$attribute} is properly converted for mails.");
}
// Test protocol relative urls.
foreach (['href', 'src'] as $attribute) {
// Reset the state variable that holds sent messages.
\Drupal::state()->set('system.test_mail_collector', []);
$html = "<$tag_name $attribute=\"//example.com/protocol-relative\">protocol relative url in mail test</$tag_name>";
$expected_html = "<$tag_name $attribute=\"//example.com/protocol-relative\">protocol relative url in mail test</$tag_name>";
// Prepare render array.
$render = ['#markup' => Markup::create($html)];
// Send a test message that simpletest_mail_alter should cancel.
\Drupal::service('plugin.manager.mail')->mail('mail_html_test', 'render_from_message_param', 'relative_url@example.com', $language_interface->getId(), ['message' => $render]);
// Retrieve sent message.
$captured_emails = \Drupal::state()->get('system.test_mail_collector');
$sent_message = end($captured_emails);
// Wrap the expected HTML and assert.
$expected_html = MailFormatHelper::wrapMail($expected_html);
$this->assertSame($expected_html, $sent_message['body'], "Asserting that {$attribute} is properly converted for mails.");
}
// Test absolute urls.
foreach (['href', 'src'] as $attribute) {
// Reset the state variable that holds sent messages.
\Drupal::state()->set('system.test_mail_collector', []);
$html = "<$tag_name $attribute=\"http://example.com/absolute\">absolute url in mail test</$tag_name>";
$expected_html = "<$tag_name $attribute=\"http://example.com/absolute\">absolute url in mail test</$tag_name>";
// Prepare render array.
$render = ['#markup' => Markup::create($html)];
// Send a test message that simpletest_mail_alter should cancel.
\Drupal::service('plugin.manager.mail')->mail('mail_html_test', 'render_from_message_param', 'relative_url@example.com', $language_interface->getId(), ['message' => $render]);
// Retrieve sent message.
$captured_emails = \Drupal::state()->get('system.test_mail_collector');
$sent_message = end($captured_emails);
// Wrap the expected HTML and assert.
$expected_html = MailFormatHelper::wrapMail($expected_html);
$this->assertSame($expected_html, $sent_message['body'], "Asserting that {$attribute} is properly converted for mails.");
}
}
/**
* Checks that mails built from render arrays contain absolute paths.
*
* By default Drupal uses relative paths for images and links. When sending
* emails, absolute paths should be used instead.
*/
public function testRenderedElementsUseAbsolutePaths() {
$language_interface = \Drupal::languageManager()->getCurrentLanguage();
// Use the HTML compatible state system collector mail backend.
$this->config('system.mail')->set('interface.default', 'test_html_mail_collector')->save();
// Fetch the hostname and port for matching against.
$http_host = \Drupal::request()->getSchemeAndHttpHost();
// Random generator.
$random = new Random();
$image_name = $random->name();
// Create an image file.
$file = File::create(['uri' => "public://{$image_name}.png", 'filename' => "{$image_name}.png"]);
$file->save();
$base_path = base_path();
$path_pairs = [
'root relative' => [$file->getFileUri(), "{$http_host}{$base_path}{$this->publicFilesDirectory}/{$image_name}.png"],
'protocol relative' => ['//example.com/image.png', '//example.com/image.png'],
'absolute' => ['http://example.com/image.png', 'http://example.com/image.png'],
];
// Test images.
foreach ($path_pairs as $test_type => $paths) {
list($input_path, $expected_path) = $paths;
// Reset the state variable that holds sent messages.
\Drupal::state()->set('system.test_mail_collector', []);
// Build the render array.
$render = [
'#theme' => 'image',
'#uri' => $input_path,
];
$expected_html = "<img src=\"$expected_path\" alt=\"\" />";
// Send a test message that simpletest_mail_alter should cancel.
\Drupal::service('plugin.manager.mail')->mail('mail_html_test', 'render_from_message_param', 'relative_url@example.com', $language_interface->getId(), ['message' => $render]);
// Retrieve sent message.
$captured_emails = \Drupal::state()->get('system.test_mail_collector');
$sent_message = end($captured_emails);
// Wrap the expected HTML and assert.
$expected_html = MailFormatHelper::wrapMail($expected_html);
$this->assertSame($expected_html, $sent_message['body'], "Asserting that {$test_type} paths are converted properly.");
}
// Test links.
$path_pairs = [
'root relative' => [Url::fromUserInput('/path/to/something'), "{$http_host}{$base_path}path/to/something"],
'protocol relative' => [Url::fromUri('//example.com/image.png'), '//example.com/image.png'],
'absolute' => [Url::fromUri('http://example.com/image.png'), 'http://example.com/image.png'],
];
foreach ($path_pairs as $paths) {
list($input_path, $expected_path) = $paths;
// Reset the state variable that holds sent messages.
\Drupal::state()->set('system.test_mail_collector', []);
// Build the render array.
$render = [
'#title' => 'Link',
'#type' => 'link',
'#url' => $input_path,
];
$expected_html = "<a href=\"$expected_path\">Link</a>";
// Send a test message that simpletest_mail_alter should cancel.
\Drupal::service('plugin.manager.mail')->mail('mail_html_test', 'render_from_message_param', 'relative_url@example.com', $language_interface->getId(), ['message' => $render]);
// Retrieve sent message.
$captured_emails = \Drupal::state()->get('system.test_mail_collector');
$sent_message = end($captured_emails);
// Wrap the expected HTML and assert.
$expected_html = MailFormatHelper::wrapMail($expected_html);
$this->assertSame($expected_html, $sent_message['body']);
}
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment