Admin/HTTP API: add suggested filename support to `download_url()`.

This change allows for external clients to supply a suggested filename via a `Content-Disposition` response header. This filename is processed through `sanitize_file_name()` to ensure it is allowable (on the server, MIME's, etc...) and `validate_file()` to prevent directory traversal.

If the suggested filename fails the above processing/checks, that suggestion is discarded and the standard temporary filename (generated by WordPress) is used.

If no `Content-Disposition` header is found in the response headers, the standard temporary filename continues to be used as per normal.

Included in this change are 6 additional PHPUnit tests with 9 assertions. These tests confirm that valid filename values are correctly saved, and invalid filename values are correctly rejected.

Props cklosows, costdev, dd32, johnjamesjacoby, ocean90, psrpinto.

Fixes #38231.
Built from https://develop.svn.wordpress.org/trunk@51939


git-svn-id: http://core.svn.wordpress.org/trunk@51528 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
johnjamesjacoby 2021-10-27 15:00:01 +00:00
parent b8e6a3c334
commit 7a0a07d691
2 changed files with 25 additions and 1 deletions

View File

@ -1112,6 +1112,7 @@ function wp_handle_sideload( &$file, $overrides = false, $time = null ) {
* *
* @since 2.5.0 * @since 2.5.0
* @since 5.2.0 Signature Verification with SoftFail was added. * @since 5.2.0 Signature Verification with SoftFail was added.
* @since 5.9.0 Support for Content-Disposition filename was added.
* *
* @param string $url The URL of the file to download. * @param string $url The URL of the file to download.
* @param int $timeout The timeout for the request to download the file. * @param int $timeout The timeout for the request to download the file.
@ -1182,6 +1183,29 @@ function download_url( $url, $timeout = 300, $signature_verification = false ) {
return new WP_Error( 'http_404', trim( wp_remote_retrieve_response_message( $response ) ), $data ); return new WP_Error( 'http_404', trim( wp_remote_retrieve_response_message( $response ) ), $data );
} }
$content_disposition = wp_remote_retrieve_header( $response, 'content-disposition' );
if ( $content_disposition ) {
$content_disposition = strtolower( $content_disposition );
if ( 0 === strpos( $content_disposition, 'attachment; filename=' ) ) {
$tmpfname_disposition = sanitize_file_name( substr( $content_disposition, 21 ) );
} else {
$tmpfname_disposition = '';
}
// Potential file name must be valid string
if ( $tmpfname_disposition && is_string( $tmpfname_disposition ) && ( 0 === validate_file( $tmpfname_disposition ) ) ) {
if ( rename( $tmpfname, $tmpfname_disposition ) ) {
$tmpfname = $tmpfname_disposition;
}
if ( ( $tmpfname !== $tmpfname_disposition ) && file_exists( $tmpfname_disposition ) ) {
unlink( $tmpfname_disposition );
}
}
}
$content_md5 = wp_remote_retrieve_header( $response, 'content-md5' ); $content_md5 = wp_remote_retrieve_header( $response, 'content-md5' );
if ( $content_md5 ) { if ( $content_md5 ) {

View File

@ -16,7 +16,7 @@
* *
* @global string $wp_version * @global string $wp_version
*/ */
$wp_version = '5.9-alpha-51938'; $wp_version = '5.9-alpha-51939';
/** /**
* 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.