Avoid stripping square brackets from URLs, and instead correctly encode them. Square brackets must be encoded in the path, path parameters, query parameters, and fragment, but must not be encoded in anything up to the domain and port.

Adds tests.

Fixes #16859

Built from https://develop.svn.wordpress.org/trunk@34920


git-svn-id: http://core.svn.wordpress.org/trunk@34885 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
John Blackbourn 2015-10-07 23:39:23 +00:00
parent 846510ea6f
commit 6d21ed0d99
2 changed files with 45 additions and 6 deletions

View File

@ -2137,15 +2137,17 @@ function _make_web_ftp_clickable_cb( $matches ) {
$ret = ''; $ret = '';
$dest = $matches[2]; $dest = $matches[2];
$dest = 'http://' . $dest; $dest = 'http://' . $dest;
$dest = esc_url($dest);
if ( empty($dest) )
return $matches[0];
// removed trailing [.,;:)] from URL // removed trailing [.,;:)] from URL
if ( in_array( substr($dest, -1), array('.', ',', ';', ':', ')') ) === true ) { if ( in_array( substr($dest, -1), array('.', ',', ';', ':', ')') ) === true ) {
$ret = substr($dest, -1); $ret = substr($dest, -1);
$dest = substr($dest, 0, strlen($dest)-1); $dest = substr($dest, 0, strlen($dest)-1);
} }
$dest = esc_url($dest);
if ( empty($dest) )
return $matches[0];
return $matches[1] . "<a href=\"$dest\" rel=\"nofollow\">$dest</a>$ret"; return $matches[1] . "<a href=\"$dest\" rel=\"nofollow\">$dest</a>$ret";
} }
@ -3352,7 +3354,7 @@ function esc_url( $url, $protocols = null, $_context = 'display' ) {
return $url; return $url;
$url = str_replace( ' ', '%20', $url ); $url = str_replace( ' ', '%20', $url );
$url = preg_replace('|[^a-z0-9-~+_.?#=!&;,/:%@$\|*\'()\\x80-\\xff]|i', '', $url); $url = preg_replace('|[^a-z0-9-~+_.?#=!&;,/:%@$\|*\'()\[\]\\x80-\\xff]|i', '', $url);
if ( '' === $url ) { if ( '' === $url ) {
return $url; return $url;
@ -3365,7 +3367,7 @@ function esc_url( $url, $protocols = null, $_context = 'display' ) {
$url = str_replace(';//', '://', $url); $url = str_replace(';//', '://', $url);
/* If the URL doesn't appear to contain a scheme, we /* If the URL doesn't appear to contain a scheme, we
* presume it needs http:// appended (unless a relative * presume it needs http:// prepended (unless a relative
* link starting with /, # or ? or a php file). * link starting with /, # or ? or a php file).
*/ */
if ( strpos($url, ':') === false && ! in_array( $url[0], array( '/', '#', '?' ) ) && if ( strpos($url, ':') === false && ! in_array( $url[0], array( '/', '#', '?' ) ) &&
@ -3379,6 +3381,43 @@ function esc_url( $url, $protocols = null, $_context = 'display' ) {
$url = str_replace( "'", '&#039;', $url ); $url = str_replace( "'", '&#039;', $url );
} }
if ( ( false !== strpos( $url, '[' ) ) || ( false !== strpos( $url, ']' ) ) ) {
$parsed = parse_url( $url );
$front = '';
if ( isset( $parsed['scheme'] ) ) {
$front .= $parsed['scheme'] . '://';
} elseif ( '/' === $url[0] ) {
$front .= '//';
}
if ( isset( $parsed['user'] ) ) {
$front .= $parsed['user'];
}
if ( isset( $parsed['pass'] ) ) {
$front .= ':' . $parsed['pass'];
}
if ( isset( $parsed['user'] ) || isset( $parsed['pass'] ) ) {
$front .= '@';
}
if ( isset( $parsed['host'] ) ) {
$front .= $parsed['host'];
}
if ( isset( $parsed['port'] ) ) {
$front .= ':' . $parsed['port'];
}
$end_dirty = str_replace( $front, '', $url );
$end_clean = str_replace( array( '[', ']' ), array( '%5B', '%5D' ), $end_dirty );
$url = str_replace( $end_dirty, $end_clean, $url );
}
if ( '/' === $url[0] ) { if ( '/' === $url[0] ) {
$good_protocol_url = $url; $good_protocol_url = $url;
} else { } else {

View File

@ -4,7 +4,7 @@
* *
* @global string $wp_version * @global string $wp_version
*/ */
$wp_version = '4.4-alpha-34919'; $wp_version = '4.4-alpha-34920';
/** /**
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema. * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.