# Constants needed for external link processing
# Everything except bracket, space, or control characters
- const EXT_LINK_URL_CLASS = '[^][<>"\\x00-\\x20\\x7F]';
+ const EXT_LINK_URL_CLASS = '(?:[^\]\[<>"\\x00-\\x20\\x7F]|(?:\[\]))';
const EXT_IMAGE_REGEX = '/^(http:\/\/|https:\/\/)([^][<>"\\x00-\\x20\\x7F]+)
\\/([A-Za-z0-9_.,~%\\-+&;#*?!=()@\\x80-\\xFF]+)\\.((?i)gif|png|jpg|jpeg)$/Sx';
$this->mConf = $conf;
$this->mUrlProtocols = wfUrlProtocols();
$this->mExtLinkBracketedRegex = '/\[(\b(' . wfUrlProtocols() . ')'.
- '[^][<>"\\x00-\\x20\\x7F]+) *([^\]\\x00-\\x08\\x0a-\\x1F]*?)\]/S';
+ '(?:[^\]\[<>"\x00-\x20\x7F]|\[\])+) *([^\]\\x00-\\x08\\x0a-\\x1F]*?)\]/S';
if ( isset( $conf['preprocessorClass'] ) ) {
$this->mPreprocessorClass = $conf['preprocessorClass'];
} elseif ( extension_loaded( 'domxml' ) ) {
</p>
!! end
+!! test
+External links: links containing empty bracket pair []
+!! input
+[http://example.com?parameter[]=foo link]
+!! result
+<p><a rel="nofollow" class="external text" href="http://example.com?parameter%5B%5D=foo">link</a>
+</p>
+!! end
+
+!! test
+External links: links ending in empty bracket pair []
+!! input
+[http://example.com?parameter[]=foo&option[]]
+!! result
+<p><a rel="nofollow" class="external autonumber" href="http://example.com?parameter%5B%5D=foo&option%5B%5D">[1]</a>
+</p>
+!! end
+
+!! test
+External links: bare links ending in empty bracket pair []
+!! input
+http://example.com?parameter[]=foo&option[]
+!! result
+<p><a rel="nofollow" class="external free" href="http://example.com?parameter%5B%5D=foo&option%5B%5D">http://example.com?parameter%5B%5D=foo&option%5B%5D</a>
+</p>
+!! end
+
!! test
BUG 787: Links with one slash after the url protocol are invalid
!! input