diff --git a/CHANGELOG b/CHANGELOG index 8be44a41b..4ecd740c1 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ CHANGELOG Roundcube Webmail =========================== +- Fix bug in handling of base href and inline content (#1488290) - Fix SQL Error when saving a contact with many email addresses (#1488286) - Fix strict email address searching if contact has more than one address - Use proper timezones from PHP's internal timezonedb (#1485592) diff --git a/program/include/main.inc b/program/include/main.inc index ad41a13e7..b16f0202a 100644 --- a/program/include/main.inc +++ b/program/include/main.inc @@ -2093,7 +2093,68 @@ class rcube_base_replacer public function callback($matches) { - return $matches[1] . '="' . make_absolute_url($matches[3], $this->base_url) . '"'; + return $matches[1] . '="' . self::absolute_url($matches[3], $this->base_url) . '"'; + } + + public function replace($body) + { + return preg_replace_callback(array( + '/(src|background|href)=(["\']?)([^"\'\s]+)(\2|\s|>)/Ui', + '/(url\s*\()(["\']?)([^"\'\)\s]+)(\2)\)/Ui', + ), + array($this, 'callback'), $body); + } + + /** + * Convert paths like ../xxx to an absolute path using a base url + * + * @param string $path Relative path + * @param string $base_url Base URL + * + * @return string Absolute URL + */ + public static function absolute_url($path, $base_url) + { + $host_url = $base_url; + $abs_path = $path; + + // check if path is an absolute URL + if (preg_match('/^[fhtps]+:\/\//', $path)) { + return $path; + } + + // check if path is a content-id scheme + if (strpos($path, 'cid:') === 0) { + return $path; + } + + // cut base_url to the last directory + if (strrpos($base_url, '/') > 7) { + $host_url = substr($base_url, 0, strpos($base_url, '/', 7)); + $base_url = substr($base_url, 0, strrpos($base_url, '/')); + } + + // $path is absolute + if ($path[0] == '/') { + $abs_path = $host_url.$path; + } + else { + // strip './' because its the same as '' + $path = preg_replace('/^\.\//', '', $path); + + if (preg_match_all('/\.\.\//', $path, $matches, PREG_SET_ORDER)) { + foreach ($matches as $a_match) { + if (strrpos($base_url, '/')) { + $base_url = substr($base_url, 0, strrpos($base_url, '/')); + } + $path = substr($path, 3); + } + } + + $abs_path = $base_url.'/'.$path; + } + + return $abs_path; } } diff --git a/program/include/rcube_shared.inc b/program/include/rcube_shared.inc index abaa8aa03..aef08341d 100644 --- a/program/include/rcube_shared.inc +++ b/program/include/rcube_shared.inc @@ -163,52 +163,6 @@ function show_bytes($bytes) return $str; } -/** - * Convert paths like ../xxx to an absolute path using a base url - * - * @param string Relative path - * @param string Base URL - * @return string Absolute URL - */ -function make_absolute_url($path, $base_url) -{ - $host_url = $base_url; - $abs_path = $path; - - // check if path is an absolute URL - if (preg_match('/^[fhtps]+:\/\//', $path)) - return $path; - - // cut base_url to the last directory - if (strrpos($base_url, '/')>7) - { - $host_url = substr($base_url, 0, strpos($base_url, '/', 7)); - $base_url = substr($base_url, 0, strrpos($base_url, '/')); - } - - // $path is absolute - if ($path[0] == '/') - $abs_path = $host_url.$path; - else - { - // strip './' because its the same as '' - $path = preg_replace('/^\.\//', '', $path); - - if (preg_match_all('/\.\.\//', $path, $matches, PREG_SET_ORDER)) - foreach ($matches as $a_match) - { - if (strrpos($base_url, '/')) - $base_url = substr($base_url, 0, strrpos($base_url, '/')); - - $path = substr($path, 3); - } - - $abs_path = $base_url.'/'.$path; - } - - return $abs_path; -} - /** * Wrapper function for wordwrap */ diff --git a/program/steps/mail/func.inc b/program/steps/mail/func.inc index 3784456c7..f791f7033 100644 --- a/program/steps/mail/func.inc +++ b/program/steps/mail/func.inc @@ -1110,15 +1110,13 @@ function rcmail_resolve_base($body) // check for if (preg_match('!()/Ui', array($replacer, 'callback'), $body); - $body = preg_replace_callback('/(url\s*\()(["\']?)([^"\'\)\s]+)(\2)\)/Ui', array($replacer, 'callback'), $body); + $body = $replacer->replace($body); } return $body; } + /** * modify a HTML message that it can be displayed inside a HTML page */ diff --git a/tests/mailfunc.php b/tests/mailfunc.php index 1b1bbdf38..2e55d331d 100644 --- a/tests/mailfunc.php +++ b/tests/mailfunc.php @@ -166,5 +166,9 @@ class rcube_test_mailfunc extends UnitTestCase $this->assertPattern('|src="http://alec\.pl/dir/img1\.gif"|', $html, "URI base resolving [1]"); $this->assertPattern('|src="http://alec\.pl/dir/img2\.gif"|', $html, "URI base resolving [2]"); $this->assertPattern('|src="http://alec\.pl/img3\.gif"|', $html, "URI base resolving [3]"); + + // base resolving exceptions + $this->assertPattern('|src="cid:theCID"|', $html, "URI base resolving exception [1]"); + $this->assertPattern('|src="http://other\.domain\.tld/img3\.gif"|', $html, "URI base resolving exception [2]"); } } diff --git a/tests/src/htmlbase.txt b/tests/src/htmlbase.txt index d1ddd5406..eb590748b 100644 --- a/tests/src/htmlbase.txt +++ b/tests/src/htmlbase.txt @@ -6,5 +6,7 @@ + +