Commit 4237d014 authored by webchick's avatar webchick
Browse files

#874326 by rfay, pwolanin, chx: Fixed Invalid scheme fails to halt processing of a stream request.

parent d5a1c652
......@@ -814,7 +814,7 @@ public function escapeField($field) {
*
* Force all alias names to be strictly alphanumeric-plus-underscore. In
* contrast to DatabaseConnection::escapeField() /
* DatabaseConnection::escapeTable(), this doesn't allow the period (".")
* DatabaseConnection::escapeTable(), this doesn't allow the period (".")
*
* @return
* The sanitized field name string.
......
......@@ -202,6 +202,7 @@ function file_stream_wrapper_valid_scheme($scheme) {
}
}
/**
* Returns the part of an URI after the schema.
*
......@@ -257,6 +258,10 @@ function file_stream_wrapper_uri_normalize($uri) {
$uri = $scheme . '://' . $target;
}
}
else {
// The default scheme is file://
$url = 'file://' . $uri;
}
return $uri;
}
......@@ -594,9 +599,9 @@ function file_usage_list(stdClass $file) {
* @param $module
* The name of the module using the file.
* @param $type
* The type of the object that contains the referenced file.
* The type of the object that contains the referenced file.
* @param $id
* The unique, numeric ID of the object containing the referenced file.
* The unique, numeric ID of the object containing the referenced file.
* @param $count
* (optional) The number of references to add to the object. Defaults to 1.
*
......@@ -710,6 +715,12 @@ function file_usage_delete(stdClass $file, $module, $type = NULL, $id = NULL, $c
* @see hook_file_copy()
*/
function file_copy(stdClass $source, $destination = NULL, $replace = FILE_EXISTS_RENAME) {
if (!file_valid_uri($destination)) {
watchdog('file', 'File %file (%realpath) could not be copied, because the destination %destination is invalid. This is often caused by improper use of file_copy() or a missing stream wrapper.', array('%file' => $source->uri, '%realpath' => drupal_realpath($source->uri), '%destination' => $destination));
drupal_set_message(t('The specified file %file could not be copied, because the destination is invalid. More information is available in the system log.', array('%file' => $source->uri)), 'error');
return FALSE;
}
if ($uri = file_unmanaged_copy($source->uri, $destination, $replace)) {
$file = clone $source;
$file->fid = NULL;
......@@ -740,6 +751,28 @@ function file_copy(stdClass $source, $destination = NULL, $replace = FILE_EXISTS
return FALSE;
}
/**
* Determine whether the URI has a valid scheme for file API operations.
*
* There must be a scheme and it must be a Drupal-provided scheme like
* 'public', 'private', 'temporary', or an extension provided with
* hook_stream_wrappers().
*
* @param $uri
* The URI to be tested.
*
* @return
* TRUE if the URI is allowed.
*/
function file_valid_uri($uri) {
// Assert that the URI has an allowed scheme. Barepaths are not allowed.
$uri_scheme = file_uri_scheme($uri);
if (empty($uri_scheme) || !file_stream_wrapper_valid_scheme($uri_scheme)) {
return FALSE;
}
return TRUE;
}
/**
* Copies a file to a new location without invoking the file API.
*
......@@ -752,11 +785,12 @@ function file_copy(stdClass $source, $destination = NULL, $replace = FILE_EXISTS
* replace the file or rename the file based on the $replace parameter.
*
* @param $source
* A string specifying the filepath or URI of the original file.
* A string specifying the filepath or URI of the source file.
* @param $destination
* A URI containing the destination that $source should be copied to.
* This must be a stream wrapper URI. If this value is omitted, Drupal's
* default files scheme will be used, usually "public://".
* A URI containing the destination that $source should be copied to. The
* URI may be a bare filepath (without a scheme) and in that case the default
* scheme (file://) will be used. If this value is omitted, Drupal's default
* files scheme will be used, usually "public://".
* @param $replace
* Replace behavior when the destination file already exists:
* - FILE_EXISTS_REPLACE - Replace the existing file.
......@@ -778,6 +812,7 @@ function file_unmanaged_copy($source, $destination = NULL, $replace = FILE_EXIST
if (!file_exists($source)) {
// @todo Replace drupal_set_message() calls with exceptions instead.
drupal_set_message(t('The specified file %file could not be copied, because no file by that name exists. Please check that you supplied the correct filename.', array('%file' => $original_source)), 'error');
watchdog('file', 'File %file (%realpath) could not be copied because it does not exist.', array('%file' => $original_source, '%realpath' => drupal_realpath($original_source)));
return FALSE;
}
......@@ -786,11 +821,6 @@ function file_unmanaged_copy($source, $destination = NULL, $replace = FILE_EXIST
$destination = file_build_uri(basename($source));
}
// Assert that the destination contains a valid stream.
$destination_scheme = file_uri_scheme($destination);
if (!$destination_scheme || !file_stream_wrapper_valid_scheme($destination_scheme)) {
drupal_set_message(t('The specified file %file could not be copied, because the destination %destination is invalid. This is often caused by improper use of file_unmanaged_copy() or a missing stream wrapper.', array('%file' => $original_source, '%destination' => $destination)), 'error');
}
// Prepare the destination directory.
if (file_prepare_directory($destination)) {
......@@ -802,7 +832,8 @@ function file_unmanaged_copy($source, $destination = NULL, $replace = FILE_EXIST
$dirname = drupal_dirname($destination);
if (!file_prepare_directory($dirname)) {
// The destination is not valid.
drupal_set_message(t('The specified file %file could not be copied, because the destination %directory is not properly configured. This is often caused by a problem with file or directory permissions.', array('%file' => $original_source, '%directory' => $destination)), 'error');
watchdog('file', 'File %file could not be copied, because the destination directory %directory is not configured correctly.', array('%file' => $original_source, '%destination' => drupal_realpath($dirname)));
drupal_set_message(t('The specified file %file could not be copied, because the destination directory is not properly configured. This may be caused by a problem with file or directory permissions. More information is available in the system log.', array('%file' => $original_source)), 'error');
return FALSE;
}
}
......@@ -810,20 +841,23 @@ function file_unmanaged_copy($source, $destination = NULL, $replace = FILE_EXIST
// Determine whether we can perform this operation based on overwrite rules.
$destination = file_destination($destination, $replace);
if ($destination === FALSE) {
drupal_set_message(t('The file %file could not be copied because a file by that name already exists in the destination directory (%directory)', array('%file' => $source, '%directory' => $destination)), 'error');
drupal_set_message(t('The file %file could not be copied because a file by that name already exists in the destination directory.', array('%file' => $original_source)), 'error');
watchdog('file', 'File %file could not be copied because a file by that name already exists in the destination directory (%directory)', array('%file' => $original_source, '%destination' => drupal_realpath($destination)));
return FALSE;
}
// Assert that the source and destination filenames are not the same.
if (drupal_realpath($source) == drupal_realpath($destination)) {
drupal_set_message(t('The specified file %file was not copied because it would overwrite itself.', array('%file' => $source)), 'error');
watchdog('file', 'File %file could not be copied because it would overwrite itself.', array('%file' => $source));
return FALSE;
}
// Make sure the .htaccess files are present.
file_ensure_htaccess();
// Perform the copy operation.
if (!@copy($source, $destination)) {
watchdog('file', 'The specified file %file could not be copied to %destination.', array('%file' => $source, '%destination' => $destination), WATCHDOG_ERROR);
drupal_set_message(t('The specified file %file could not be copied.', array('%file' => $source)), 'error');
watchdog('file', 'The specified file %file could not be copied to %destination.', array('%file' => $source, '%destination' => drupal_realpath($destination)), WATCHDOG_ERROR);
return FALSE;
}
......@@ -914,6 +948,12 @@ function file_destination($destination, $replace) {
* @see hook_file_move()
*/
function file_move(stdClass $source, $destination = NULL, $replace = FILE_EXISTS_RENAME) {
if (!file_valid_uri($destination)) {
watchdog('file', 'File %file (%realpath) could not be moved, because the destination %destination is invalid. This may be caused by improper use of file_move() or a missing stream wrapper.', array('%file' => $source->uri, '%realpath' => drupal_realpath($source->uri), '%destination' => $destination));
drupal_set_message(t('The specified file %file could not be moved, because the destination is invalid. More information is available in the system log.', array('%file' => $source->uri)), 'error');
return FALSE;
}
if ($uri = file_unmanaged_move($source->uri, $destination, $replace)) {
$delete_source = FALSE;
......@@ -1134,6 +1174,12 @@ function file_create_filename($basename, $directory) {
* @see hook_file_delete()
*/
function file_delete(stdClass $file, $force = FALSE) {
if (!file_valid_uri($file->uri)) {
watchdog('file', 'File %file (%realpath) could not be deleted because it is not a valid URI. This may be caused by improper use of file_delete() or a missing stream wrapper.', array('%file' => $file->uri, '%realpath' => drupal_realpath($file->uri)));
drupal_set_message(t('The specified file %file could not be deleted, because it is not a valid URI. More information is available in the system log.', array('%file' => $file->uri)), 'error');
return FALSE;
}
// If any module still has a usage entry in the file_usage table, the file
// will not be deleted, but file_delete() will return a populated array
// that tests as TRUE.
......@@ -1689,6 +1735,15 @@ function file_validate_image_resolution(stdClass $file, $maximum_dimensions = 0,
function file_save_data($data, $destination = NULL, $replace = FILE_EXISTS_RENAME) {
global $user;
if (empty($destination)) {
$destination = file_default_scheme() . '://';
}
if (!file_valid_uri($destination)) {
watchdog('file', 'The data could not be saved because the destination %destination is invalid. This may be caused by improper use of file_save_data() or a missing stream wrapper.', array('%destination' => $destination));
drupal_set_message(t('The data could not be saved, because the destination is invalid. More information is available in the system log.'), 'error');
return FALSE;
}
if ($uri = file_unmanaged_save_data($data, $destination, $replace)) {
// Create a file object.
$file = new stdClass();
......
......@@ -116,11 +116,11 @@ class FileFieldTestCase extends DrupalWebTestCase {
if (is_numeric($nid_or_type)) {
$node = node_load($nid_or_type);
$delta = isset($node->$field_name) ? count($node->$field_name) : 0;
$edit['files[' . $field_name . '_' . LANGUAGE_NONE . '_' . $delta . ']'] = realpath($file->uri);
$edit['files[' . $field_name . '_' . LANGUAGE_NONE . '_' . $delta . ']'] = drupal_realpath($file->uri);
$this->drupalPost('node/' . $nid_or_type . '/edit', $edit, t('Save'));
}
else {
$edit['files[' . $field_name . '_' . LANGUAGE_NONE . '_0]'] = realpath($file->uri);
$edit['files[' . $field_name . '_' . LANGUAGE_NONE . '_0]'] = drupal_realpath($file->uri);
$type_name = str_replace('_', '-', $nid_or_type);
$this->drupalPost('node/add/' . $type_name, $edit, t('Save'));
}
......@@ -149,7 +149,7 @@ class FileFieldTestCase extends DrupalWebTestCase {
*/
function replaceNodeFile($file, $field_name, $nid, $new_revision = TRUE) {
$edit = array(
'files[' . $field_name . '_' . LANGUAGE_NONE . '_0]' => realpath($file->uri),
'files[' . $field_name . '_' . LANGUAGE_NONE . '_0]' => drupal_realpath($file->uri),
'revision' => (string) (int) $new_revision,
);
......@@ -336,7 +336,7 @@ class FileFieldWidgetTestCase extends FileFieldTestCase {
// Add a comment with a file.
$text_file = $this->getTestFile('text');
$edit = array(
'files[field_' . $name . '_' . LANGUAGE_NONE . '_' . 0 . ']' => realpath($text_file->uri),
'files[field_' . $name . '_' . LANGUAGE_NONE . '_' . 0 . ']' => drupal_realpath($text_file->uri),
'comment_body[' . LANGUAGE_NONE . '][0][value]' => $comment_body = $this->randomName(),
);
$this->drupalPost(NULL, $edit, t('Save'));
......@@ -566,6 +566,8 @@ class FileFieldValidateTestCase extends FileFieldTestCase {
// Create a new node with the uploaded file.
$nid = $this->uploadNodeFile($test_file, $field_name, $type_name);
$this->assertTrue($nid !== FALSE, t('uploadNodeFile(@test_file, @field_name, @type_name) succeeded', array('@test_file' => $test_file->uri, '@field_name' => $field_name, '@type_name' => $type_name)));
$node = node_load($nid, NULL, TRUE);
$node_file = (object) $node->{$field_name}[LANGUAGE_NONE][0];
......
......@@ -94,7 +94,7 @@ class ImageFieldTestCase extends DrupalWebTestCase {
$edit = array(
'title' => $this->randomName(),
);
$edit['files[' . $field_name . '_' . LANGUAGE_NONE . '_0]'] = realpath($image->uri);
$edit['files[' . $field_name . '_' . LANGUAGE_NONE . '_0]'] = drupal_realpath($image->uri);
$this->drupalPost('node/add/' . $type, $edit, t('Save'));
// Retrieve ID of the newly created node from the current URL.
......@@ -786,7 +786,7 @@ class ImageFieldDisplayTestCase extends ImageFieldTestCase {
// Add a default image to the imagefield instance.
$images = $this->drupalGetTestFiles('image');
$edit = array(
'files[field_settings_default_image]' => realpath($images[0]->uri),
'files[field_settings_default_image]' => drupal_realpath($images[0]->uri),
);
$this->drupalPost('admin/structure/types/manage/article/fields/' . $field_name, $edit, t('Save settings'));
// Clear field info cache so the new default image is detected.
......
......@@ -939,7 +939,7 @@ protected function drupalGetTestFiles($type, $size = NULL) {
$files = array();
// Make sure type is valid.
if (in_array($type, array('binary', 'html', 'image', 'javascript', 'php', 'sql', 'text'))) {
$files = file_scan_directory(variable_get('file_public_path', conf_path() . '/files'), '/' . $type . '\-.*/');
$files = file_scan_directory('public://', '/' . $type . '\-.*/');
// If size is set then remove any files that are not of that size.
if ($size !== NULL) {
......
......@@ -575,7 +575,9 @@ class FileSaveUploadTest extends FileHookTestCase {
$account = $this->drupalCreateUser(array('access content'));
$this->drupalLogin($account);
$this->image = current($this->drupalGetTestFiles('image'));
$image_files = $this->drupalGetTestFiles('image');
$this->image = current($image_files);
list(, $this->image_extension) = explode('.', $this->image->filename);
$this->assertTrue(is_file($this->image->uri), t("The image file we're going to upload exists."));
......
......@@ -1299,13 +1299,14 @@ class SystemThemeFunctionalTest extends DrupalWebTestCase {
function testThemeSettings() {
// Specify a filesystem path to be used for the logo.
$file = current($this->drupalGetTestFiles('image'));
$fullpath = drupal_realpath($file->uri);
$edit = array(
'default_logo' => FALSE,
'logo_path' => $file->uri,
'logo_path' => $fullpath,
);
$this->drupalPost('admin/appearance/settings', $edit, t('Save configuration'));
$this->drupalGet('node');
$this->assertRaw($file->uri, t('Logo path successfully changed.'));
$this->assertRaw($fullpath, t('Logo path successfully changed.'));
// Upload a file to use for the logo.
$file = current($this->drupalGetTestFiles('image'));
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment