Make WordPress Core


Ignore:
Timestamp:
10/27/2021 02:58:24 PM (3 years ago)
Author:
johnjamesjacoby
Message:

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.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-admin/includes/file.php

    r51899 r51939  
    11131113 * @since 2.5.0
    11141114 * @since 5.2.0 Signature Verification with SoftFail was added.
     1115 * @since 5.9.0 Support for Content-Disposition filename was added.
    11151116 *
    11161117 * @param string $url                    The URL of the file to download.
     
    11811182
    11821183        return new WP_Error( 'http_404', trim( wp_remote_retrieve_response_message( $response ) ), $data );
     1184    }
     1185
     1186    $content_disposition = wp_remote_retrieve_header( $response, 'content-disposition' );
     1187
     1188    if ( $content_disposition ) {
     1189        $content_disposition = strtolower( $content_disposition );
     1190
     1191        if ( 0 === strpos( $content_disposition, 'attachment; filename=' ) ) {
     1192            $tmpfname_disposition = sanitize_file_name( substr( $content_disposition, 21 ) );
     1193        } else {
     1194            $tmpfname_disposition = '';
     1195        }
     1196
     1197        // Potential file name must be valid string
     1198        if ( $tmpfname_disposition && is_string( $tmpfname_disposition ) && ( 0 === validate_file( $tmpfname_disposition ) ) ) {
     1199            if ( rename( $tmpfname, $tmpfname_disposition ) ) {
     1200                $tmpfname = $tmpfname_disposition;
     1201            }
     1202
     1203            if ( ( $tmpfname !== $tmpfname_disposition ) && file_exists( $tmpfname_disposition ) ) {
     1204                unlink( $tmpfname_disposition );
     1205            }
     1206        }
    11831207    }
    11841208
Note: See TracChangeset for help on using the changeset viewer.