Escape % sign if form valid percent-encoding in fragment identifiers
Currently if you combine a valid percent encoding and a non escaped character that is reserved in urls in a headline, the toc link does not work. E.g. ==`%41== needs #`%2541 but we currently generate #`%41 which matches ==`A== instead. Tested in firefox and chrome Bug: T238385 Change-Id: Ice2bbf79bed612d488ed6feb7510035e9dfb33af
This commit is contained in:
parent
a18d0fe181
commit
28d44262aa
3 changed files with 33 additions and 14 deletions
|
|
@ -1291,7 +1291,7 @@ class Sanitizer {
|
|||
|
||||
$mode = $wgFragmentMode[self::ID_PRIMARY];
|
||||
|
||||
$id = self::escapeIdInternal( $id, $mode );
|
||||
$id = self::escapeIdInternalUrl( $id, $mode );
|
||||
|
||||
return $id;
|
||||
}
|
||||
|
|
@ -1308,11 +1308,28 @@ class Sanitizer {
|
|||
public static function escapeIdForExternalInterwiki( $id ) {
|
||||
global $wgExternalInterwikiFragmentMode;
|
||||
|
||||
$id = self::escapeIdInternal( $id, $wgExternalInterwikiFragmentMode );
|
||||
$id = self::escapeIdInternalUrl( $id, $wgExternalInterwikiFragmentMode );
|
||||
|
||||
return $id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Do percent encoding of percent signs for href (but not id) attributes
|
||||
*
|
||||
* @since 1.35
|
||||
* @see https://phabricator.wikimedia.org/T238385
|
||||
* @param string $id String to escape
|
||||
* @param string $mode One of modes from $wgFragmentMode
|
||||
* @return string
|
||||
*/
|
||||
private static function escapeIdInternalUrl( $id, $mode ) {
|
||||
$id = self::escapeIdInternal( $id, $mode );
|
||||
if ( $mode === 'html5' ) {
|
||||
$id = preg_replace( '/%([a-fA-F0-9]{2})/', '%25$1', $id );
|
||||
}
|
||||
return $id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper for escapeIdFor*() functions. Performs most of the actual escaping.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -22858,7 +22858,7 @@ wgFragmentMode=[ 'html5', 'legacy' ]
|
|||
__NOEDITSECTION__
|
||||
!! html/php
|
||||
<h3><span id=".2B:.3A.253A_.26.26.5D.5D_x"></span><span class="mw-headline" id="+:.3A%3A_&&]]_x">_ +:.3A%3A _ &&]] x</span></h3>
|
||||
<p>+:.3A%3A_&&]]_x
|
||||
<p>+:.3A%253A_&&]]_x
|
||||
</p>
|
||||
!! html/parsoid
|
||||
<h3 id="+:.3A%3A_&&]]_x"><span id=".2B:.3A.253A_.26.26.5D.5D_x" typeof="mw:FallbackId"></span>_ +:.3A%3A _ &<span typeof="mw:Entity" data-parsoid='{"src":"&amp;","srcContent":"&","dsr":[18,23,null,null]}'>&</span>]] x</h3>
|
||||
|
|
|
|||
|
|
@ -173,6 +173,7 @@ class SanitizerTest extends MediaWikiTestCase {
|
|||
* @covers Sanitizer::escapeIdForLink()
|
||||
* @covers Sanitizer::escapeIdForExternalInterwiki()
|
||||
* @covers Sanitizer::escapeIdInternal()
|
||||
* @covers Sanitizer::escapeIdInternalUrl()
|
||||
*
|
||||
* @param string $stuff
|
||||
* @param string[] $config
|
||||
|
|
@ -193,10 +194,11 @@ class SanitizerTest extends MediaWikiTestCase {
|
|||
|
||||
public function provideEscapeIdForStuff() {
|
||||
// Test inputs and outputs
|
||||
$text = 'foo тест_#%!\'()[]:<>&&&amp;';
|
||||
$text = 'foo тест_#%!\'()[]:<>&&&amp;%F0';
|
||||
$legacyEncoded = 'foo_.D1.82.D0.B5.D1.81.D1.82_.23.25.21.27.28.29.5B.5D:.3C.3E' .
|
||||
'.26.26amp.3B.26amp.3Bamp.3B';
|
||||
$html5Encoded = 'foo_тест_#%!\'()[]:<>&&&amp;';
|
||||
'.26.26amp.3B.26amp.3Bamp.3B.25F0';
|
||||
$html5EncodedId = 'foo_тест_#%!\'()[]:<>&&&amp;%F0';
|
||||
$html5EncodedHref = 'foo_тест_#%!\'()[]:<>&&&amp;%25F0';
|
||||
|
||||
// Settings: last element is $wgExternalInterwikiFragmentMode, the rest is $wgFragmentMode
|
||||
$legacy = [ 'legacy', 'legacy' ];
|
||||
|
|
@ -214,27 +216,27 @@ class SanitizerTest extends MediaWikiTestCase {
|
|||
|
||||
// Transition to a new world: legacy links with HTML5 fallback
|
||||
[ 'Attribute', $legacyNew, $text, $legacyEncoded, Sanitizer::ID_PRIMARY ],
|
||||
[ 'Attribute', $legacyNew, $text, $html5Encoded, Sanitizer::ID_FALLBACK ],
|
||||
[ 'Attribute', $legacyNew, $text, $html5EncodedId, Sanitizer::ID_FALLBACK ],
|
||||
[ 'Link', $legacyNew, $text, $legacyEncoded ],
|
||||
[ 'ExternalInterwiki', $legacyNew, $text, $legacyEncoded ],
|
||||
|
||||
// New world: HTML5 links, legacy fallbacks
|
||||
[ 'Attribute', $newLegacy, $text, $html5Encoded, Sanitizer::ID_PRIMARY ],
|
||||
[ 'Attribute', $newLegacy, $text, $html5EncodedId, Sanitizer::ID_PRIMARY ],
|
||||
[ 'Attribute', $newLegacy, $text, $legacyEncoded, Sanitizer::ID_FALLBACK ],
|
||||
[ 'Link', $newLegacy, $text, $html5Encoded ],
|
||||
[ 'Link', $newLegacy, $text, $html5EncodedHref ],
|
||||
[ 'ExternalInterwiki', $newLegacy, $text, $legacyEncoded ],
|
||||
|
||||
// Distant future: no legacy fallbacks, but still linking to leagacy wikis
|
||||
[ 'Attribute', $new, $text, $html5Encoded, Sanitizer::ID_PRIMARY ],
|
||||
[ 'Attribute', $new, $text, $html5EncodedId, Sanitizer::ID_PRIMARY ],
|
||||
[ 'Attribute', $new, $text, false, Sanitizer::ID_FALLBACK ],
|
||||
[ 'Link', $new, $text, $html5Encoded ],
|
||||
[ 'Link', $new, $text, $html5EncodedHref ],
|
||||
[ 'ExternalInterwiki', $new, $text, $legacyEncoded ],
|
||||
|
||||
// Just before the heat death of universe: external interwikis are also HTML5 \m/
|
||||
[ 'Attribute', $allNew, $text, $html5Encoded, Sanitizer::ID_PRIMARY ],
|
||||
[ 'Attribute', $allNew, $text, $html5EncodedId, Sanitizer::ID_PRIMARY ],
|
||||
[ 'Attribute', $allNew, $text, false, Sanitizer::ID_FALLBACK ],
|
||||
[ 'Link', $allNew, $text, $html5Encoded ],
|
||||
[ 'ExternalInterwiki', $allNew, $text, $html5Encoded ],
|
||||
[ 'Link', $allNew, $text, $html5EncodedHref ],
|
||||
[ 'ExternalInterwiki', $allNew, $text, $html5EncodedHref ],
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue