Make WordPress Core

Ticket #38231: 38231.6.diff

File 38231.6.diff, 3.4 KB (added by johnjamesjacoby, 3 years ago)

Alternate approach, using WP_REST_Attachments_Controller::get_filename_from_disposition()

  • src/wp-admin/includes/file.php

     
    11821182                return new WP_Error( 'http_404', trim( wp_remote_retrieve_response_message( $response ) ), $data );
    11831183        }
    11841184
     1185        $content_disposition = wp_remote_retrieve_header( $response, 'content-disposition' );
     1186
     1187        if ( $content_disposition ) {
     1188                $tmpfname_disposition = WP_REST_Attachments_Controller::get_filename_from_disposition( (array) $content_disposition );
     1189
     1190                if ( $tmpfname_disposition && rename( $tmpfname, $tmpfname_disposition ) ) {
     1191                        $tmpfname = $tmpfname_disposition;
     1192                }
     1193
     1194                if ( ( $tmpfname !== $tmpfname_disposition ) && file_exists( $tmpfname_disposition ) ) {
     1195                        unlink( $tmpfname_disposition );
     1196                }
     1197        }
     1198
    11851199        $content_md5 = wp_remote_retrieve_header( $response, 'content-md5' );
    11861200
    11871201        if ( $content_md5 ) {
  • tests/phpunit/tests/admin/includesFile.php

     
    7979        }
    8080
    8181        /**
     82         * @ticket 38231
     83         * @dataProvider data_download_url_filename_from_content_disposition_header
     84         */
     85        public function test_download_url_filename_from_content_disposition_header( $filter ) {
     86                add_filter( 'pre_http_request', array( $this, $filter ), 10, 3 );
     87
     88                $filename = download_url( 'url_with_content_disposition_header' );
     89                $this->assertMatchesRegularExpression( '/filename-from-content-disposition-header/', $filename );
     90                $this->assertFileExists( $filename );
     91                $this->unlink( $filename );
     92
     93                remove_filter( 'pre_http_request', array( $this, $filter ) );
     94        }
     95
     96        public function data_download_url_filename_from_content_disposition_header() {
     97                return array(
     98                        'quotes'         => array( '_fake_download_url_with_content_disposition_header' ),
     99                        'no quotes'      => array( '_fake_download_url_with_content_disposition_header_without_quotes' ),
     100                        'asterisk'       => array( '_fake_download_url_with_content_disposition_header_with_asterisk' ),
     101                        'path traversal' => array( '_fake_download_url_with_content_disposition_header_with_path_traversal' ),
     102                );
     103        }
     104
     105        public function _fake_download_url_with_content_disposition_header( $response, $args, $url ) {
     106                return array(
     107                        'response' => array(
     108                                'code' => 200,
     109                        ),
     110                        'headers'  => array(
     111                                'content-disposition' => 'filename="filename-from-content-disposition-header.txt"',
     112                        ),
     113                );
     114        }
     115
     116        public function _fake_download_url_with_content_disposition_header_without_quotes( $response, $args, $url ) {
     117                return array(
     118                        'response' => array(
     119                                'code' => 200,
     120                        ),
     121                        'headers'  => array(
     122                                'content-disposition' => 'filename=filename-from-content-disposition-header.txt',
     123                        ),
     124                );
     125        }
     126
     127        public function _fake_download_url_with_content_disposition_header_with_asterisk( $response, $args, $url ) {
     128                return array(
     129                        'response' => array(
     130                                'code' => 200,
     131                        ),
     132                        'headers'  => array(
     133                                'content-disposition' => 'filename*="filename-from-content-disposition-header.txt"',
     134                        ),
     135                );
     136        }
     137
     138        public function _fake_download_url_with_content_disposition_header_with_path_traversal( $response, $args, $url ) {
     139                return array(
     140                        'response' => array(
     141                                'code' => 200,
     142                        ),
     143                        'headers'  => array(
     144                                'content-disposition' => 'filename="../../filename-from-content-disposition-header.txt"',
     145                        ),
     146                );
     147        }
     148
     149        /**
    82150         * Verify that a WP_Error object is returned when invalid input is passed as the `$url` parameter.
    83151         *
    84152         * @covers ::download_url