Index: includes/file.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/file.inc,v
retrieving revision 1.128
diff -u -8 -p -r1.128 file.inc
--- includes/file.inc	14 Aug 2008 12:10:47 -0000	1.128
+++ includes/file.inc	14 Aug 2008 20:59:43 -0000
@@ -78,17 +78,17 @@ define('FILE_STATUS_PERMANENT', 1);
  */
 function file_create_url($path) {
   // Strip file_directory_path from $path. We only include relative paths in urls.
   if (strpos($path, file_directory_path() . '/') === 0) {
     $path = trim(substr($path, strlen(file_directory_path())), '\\/');
   }
   switch (variable_get('file_downloads', FILE_DOWNLOADS_PUBLIC)) {
     case FILE_DOWNLOADS_PUBLIC:
-      return $GLOBALS['base_url'] . '/' . file_directory_path() . '/' . str_replace('\\', '/', $path);
+      return $GLOBALS['base_url'] . '/' . file_directory_path() . '/' . str_replace(array('%2F', '%5C'), '/', rawurlencode($path));
     case FILE_DOWNLOADS_PRIVATE:
       return url('system/files/' . $path, array('absolute' => TRUE));
   }
 }
 
 /**
  * Make sure the destination is a complete path and resides in the file system
  * directory, if it is not prepend the file system directory.
Index: modules/simpletest/tests/file.test
===================================================================
RCS file: modules/simpletest/tests/file.test
diff -N modules/simpletest/tests/file.test
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ modules/simpletest/tests/file.test	14 Aug 2008 20:59:43 -0000
@@ -0,0 +1,53 @@
+<?php
+// $Id: file.test,v 1.1 2008/08/08 08:08:08 nobody Exp $
+
+/**
+ * @file
+ * Unit tests for the Drupal File API.
+ */
+
+class FileCreateUrlTestCase extends DrupalWebTestCase {
+
+  function getInfo() {
+    return array(
+      'name' => t('URL generation'),
+      'description' => t('Verify that URLs generated by file_create_url() point to the right file on the webserver'),
+      'group' => t('File API'),
+    );
+  }
+
+  /**
+   * Test file_create_url().
+   */
+  function testFileCreateUrl() {
+    $files = array(
+      'foo.txt',
+      'dir/file',
+      'dir/subdir/file',
+      ' -._~%!$',
+      '\'"()*@[]',
+      '?&+%#',
+      ',;=:',
+      '¤£^§½|`´',
+      '%23%26%2F%3F',
+      'æøåéüöï',
+    );
+    foreach ($files as $file) {
+      file_check_directory(file_create_path(dirname($file)), FILE_CREATE_DIRECTORY);
+      $path = file_create_path($file);
+      $this->assertTrue($path, t('Got valid path for file ' . $file));
+
+      $content = 'Generated by ' . __METHOD__ . '() at ' . microtime(true) . ': ' . $path;
+      $ok = file_put_contents($path, $content);
+      $this->assertTrue($ok, 'Saved file ' . $path);
+
+      $url = file_create_url($path);
+      $this->assertFalse(preg_match('@(?<=^|/)\.{1,2}(?=/|$)@', $url), 'No /./ or /../ segments');
+      $this->drupalGet($url);
+
+      if ($this->assertNoRaw(t('Page not found'), t('File found')) == 'pass') {
+        $this->assertEqual($content, $this->drupalGetContent());
+      }
+    }
+  }
+}
