Switch the Blob implementation to using the blob data registration model
authorjianli@chromium.org <jianli@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 31 Aug 2010 04:45:21 +0000 (04:45 +0000)
committerjianli@chromium.org <jianli@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 31 Aug 2010 04:45:21 +0000 (04:45 +0000)
https://bugs.webkit.org/show_bug.cgi?id=44389

Reviewed by Darin Fisher.

WebCore:

Tests: fast/files/read-blob-async.html
       fast/files/read-file-async.html

With this switch, File/Blob/BlobBuilder are changed to register the blob
data. FileReader is changed to route through loading the blob resource.
FormData is also updated to take BlobData. The WebKit mac implementation
is updated to resolve the blob references in the BlobData.

* CMakeLists.txt: Update the project file to remove BlobItem.*.
* GNUmakefile.am: Update the project file to remove BlobItem.*.
* WebCore.gypi: Update the project file to remove BlobItem.*.
* WebCore.pro: Update the project file to remove BlobItem.*.
* WebCore.vcproj/WebCore.vcproj: Update the project file to remove BlobItem.*.
* WebCore.xcodeproj/project.pbxproj: Update the project file to remove BlobItem.*.
* fileapi/Blob.cpp: Switch to using BlobData.
(WebCore::Blob::Blob):
(WebCore::Blob::slice):
* fileapi/Blob.h: Switch to using BlobData.
(WebCore::Blob::create):
(WebCore::Blob::size):
(WebCore::Blob::isFile):
* fileapi/BlobBuilder.cpp: Switch to using BlobData.
(WebCore::BlobBuilder::BlobBuilder):
(WebCore::BlobBuilder::append):
(WebCore::BlobBuilder::getBlob):
* fileapi/BlobBuilder.h: Switch to using BlobData.
* fileapi/BlobURL.cpp: Add a new helper method used in FormData.
(WebCore::BlobURL::getIdentifier):
* fileapi/BlobURL.h:
* fileapi/File.cpp: Switch to using BlobData.
(WebCore::createBlobDataForFile):
(WebCore::File::File):
(WebCore::File::size):
(WebCore::File::captureSnapshot):
* fileapi/File.h: Switch to using BlobData.
(WebCore::File::create):
(WebCore::File::path):
(WebCore::File::name):
(WebCore::File::webkitRelativePath):
* fileapi/FileReader.cpp: Change the reading to route through blob resource loading.
(WebCore::FileReader::FileReader):
(WebCore::FileReader::readAsBinaryString):
(WebCore::FileReader::readAsText):
(WebCore::FileReader::readAsDataURL):
(WebCore::delayedStart):
(WebCore::FileReader::readInternal):
(WebCore::FileReader::terminate):
(WebCore::FileReader::start):
(WebCore::FileReader::didReceiveResponse):
(WebCore::FileReader::didReceiveData):
(WebCore::FileReader::didFinishLoading):
(WebCore::FileReader::didFail):
(WebCore::FileReader::failed):
(WebCore::FileReader::httpStatusCodeToExceptionCode):
(WebCore::FileReader::result):
(WebCore::FileReader::convertToDataURL):
* fileapi/FileReader.h:
* html/FormDataList.cpp: Account to BlobData change.
(WebCore::FormDataList::appendString):
(WebCore::FormDataList::appendBlob):
* html/FormDataList.h: Account to BlobData change.
(WebCore::FormDataList::appendBlob):
(WebCore::FormDataList::Item::Item):
(WebCore::FormDataList::Item::data):
(WebCore::FormDataList::Item::blob):
(WebCore::FormDataList::items):
* loader/FormSubmission.cpp: Account to BlobData change.
(WebCore::FormSubmission::create):
* platform/BlobItem.cpp: Removed.
* platform/BlobItem.h: Removed.
* platform/network/BlobRegistryImpl.cpp: Add the implementations for resource loading.
(WebCore::BlobRegistryImpl::createResourceHandle):
(WebCore::BlobRegistryImpl::loadResourceSynchronously):
* platform/network/BlobResourceHandle.cpp: Fix a bug that the ref is not added.
(WebCore::BlobResourceHandle::BlobResourceHandle):
* platform/network/FormData.cpp: Account to BlobData change.
(WebCore::FormData::create):
(WebCore::FormData::createMultiPart):
(WebCore::FormData::deepCopy):
(WebCore::FormData::appendFile):
(WebCore::FormData::appendKeyValuePairItems):
* platform/network/FormData.h: Account to BlobData change.
* platform/network/mac/FormDataStreamMac.mm: Resolve blob references in the form data.
(WebCore::closeCurrentStream):
(WebCore::advanceCurrentStream):
(WebCore::formCreate):
(WebCore::formRead):
(WebCore::setHTTPBody):
* xml/XMLHttpRequest.cpp: Account to BlobData change.
(WebCore::XMLHttpRequest::send):

WebKit/chromium:

* src/WebSearchableFormData.cpp:
(WebCore::HasSuitableTextElement):

LayoutTests:

Add a new test and change an existing test. Both tests are written in
better organized utility files and modules.

* fast/files/file-reader-expected.txt: Removed.
* fast/files/file-reader.html: Removed.
* fast/files/read-blob-async-expected.txt: Added.
* fast/files/read-blob-async.html: Added.
* fast/files/read-file-async-expected.txt: Added.
* fast/files/read-file-async.html: Added.
* fast/files/resources/UTF8-2.txt: Added.
* fast/files/resources/UTF8-3.txt: Added.
* fast/files/resources/read-blob-test-cases.js: Added.
* fast/files/resources/read-common.js: Added.
* fast/files/resources/read-file-test-cases.js: Added.
* fast/files/resources/setup-for-read-common.js: Added.
* platform/gtk/Skipped: Account to the test changes for gtk.
* platform/mac-wk2/Skipped: Account to the test changes for mac-wk2.
* platform/qt/Skipped: Account to the test changes for qt.
* platform/win/Skipped: Account to the test changes for win.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@66452 268f45cc-cd09-0410-ab3c-d52691b4dbfc

46 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/files/file-reader.html [deleted file]
LayoutTests/fast/files/read-blob-async-expected.txt [new file with mode: 0644]
LayoutTests/fast/files/read-blob-async.html [new file with mode: 0644]
LayoutTests/fast/files/read-file-async-expected.txt [moved from LayoutTests/fast/files/file-reader-expected.txt with 89% similarity]
LayoutTests/fast/files/read-file-async.html [new file with mode: 0644]
LayoutTests/fast/files/resources/UTF8-2.txt [new file with mode: 0644]
LayoutTests/fast/files/resources/UTF8-3.txt [new file with mode: 0644]
LayoutTests/fast/files/resources/read-blob-test-cases.js [new file with mode: 0644]
LayoutTests/fast/files/resources/read-common.js [new file with mode: 0644]
LayoutTests/fast/files/resources/read-file-test-cases.js [new file with mode: 0644]
LayoutTests/fast/files/resources/setup-for-read-common.js [new file with mode: 0644]
LayoutTests/platform/gtk/Skipped
LayoutTests/platform/mac-wk2/Skipped
LayoutTests/platform/qt/Skipped
LayoutTests/platform/win/Skipped
WebCore/CMakeLists.txt
WebCore/ChangeLog
WebCore/GNUmakefile.am
WebCore/WebCore.gypi
WebCore/WebCore.pro
WebCore/WebCore.vcproj/WebCore.vcproj
WebCore/WebCore.xcodeproj/project.pbxproj
WebCore/fileapi/Blob.cpp
WebCore/fileapi/Blob.h
WebCore/fileapi/BlobBuilder.cpp
WebCore/fileapi/BlobBuilder.h
WebCore/fileapi/BlobURL.cpp
WebCore/fileapi/BlobURL.h
WebCore/fileapi/File.cpp
WebCore/fileapi/File.h
WebCore/fileapi/FileReader.cpp
WebCore/fileapi/FileReader.h
WebCore/html/FormDataList.cpp
WebCore/html/FormDataList.h
WebCore/loader/FormSubmission.cpp
WebCore/platform/BlobItem.cpp [deleted file]
WebCore/platform/BlobItem.h [deleted file]
WebCore/platform/network/BlobRegistryImpl.cpp
WebCore/platform/network/BlobResourceHandle.cpp
WebCore/platform/network/FormData.cpp
WebCore/platform/network/FormData.h
WebCore/platform/network/mac/FormDataStreamMac.mm
WebCore/xml/XMLHttpRequest.cpp
WebKit/chromium/ChangeLog
WebKit/chromium/src/WebSearchableFormData.cpp

index 6602e711e0d7a89fc76a9c65a3ed0a030164d252..7002ebb4ff8edbd9be22680e9346d9679a7a96f3 100644 (file)
@@ -1,3 +1,30 @@
+2010-08-30  Jian Li  <jianli@chromium.org>
+
+        Reviewed by Darin Fisher.
+
+        Switch the Blob implementation to using the blob data registration model
+        https://bugs.webkit.org/show_bug.cgi?id=44389
+
+        Add a new test and change an existing test. Both tests are written in
+        better organized utility files and modules.
+
+        * fast/files/file-reader-expected.txt: Removed.
+        * fast/files/file-reader.html: Removed.
+        * fast/files/read-blob-async-expected.txt: Added.
+        * fast/files/read-blob-async.html: Added.
+        * fast/files/read-file-async-expected.txt: Added.
+        * fast/files/read-file-async.html: Added.
+        * fast/files/resources/UTF8-2.txt: Added.
+        * fast/files/resources/UTF8-3.txt: Added.
+        * fast/files/resources/read-blob-test-cases.js: Added.
+        * fast/files/resources/read-common.js: Added.
+        * fast/files/resources/read-file-test-cases.js: Added.
+        * fast/files/resources/setup-for-read-common.js: Added.
+        * platform/gtk/Skipped: Account to the test changes for gtk.
+        * platform/mac-wk2/Skipped: Account to the test changes for mac-wk2.
+        * platform/qt/Skipped: Account to the test changes for qt.
+        * platform/win/Skipped: Account to the test changes for win.
+
 2010-08-30  Eric Seidel  <eric@webkit.org>
 
         Unreviewed, rolling out r66418.
diff --git a/LayoutTests/fast/files/file-reader.html b/LayoutTests/fast/files/file-reader.html
deleted file mode 100644 (file)
index 7babbb1..0000000
+++ /dev/null
@@ -1,257 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<input type="file" name="file" id="file" onchange="onInputFileChange()" multiple>
-<pre id='console'></pre>
-
-<script>
-var testCases = [
-    "testReadingNonExistentFile",
-    "testReadingEmptyFileAsBinaryString",
-    "testReadingEmptyFileAsText",
-    "testReadingEmptyFileAsDataURL",
-    "testReadingUTF8EncodedFileAsBinaryString",
-    "testReadingBinaryFileAsBinaryString",
-    "testReadingUTF8EncodedFileAsText",
-    "testReadingUTF16BEBOMEncodedFileAsText",
-    "testReadingUTF16LEBOMEncodedFileAsText",
-    "testReadingUTF8BOMEncodedFileAsText",
-    "testReadingUTF16BEEncodedFileAsTextWithUTF16Encoding",
-    "testReadingUTF16BEBOMEncodedFileAsTextWithUTF8Encoding",
-    "testReadingUTF16BEBOMEncodedFileAsTextWithInvalidEncoding",
-    "testReadingUTF8EncodedFileAsDataURL",
-    "testMultipleReads",
-];
-var testIndex = 0;
-
-var testFileInfoList = [
-    { 'name': 'non-existent', 'path': 'resources/non-existent' },
-    { 'name': 'empty-file', 'path': 'resources/empty-file' },
-    { 'name': 'UTF8-file', 'path': 'resources/UTF8.txt' },
-    { 'name': 'UTF16BE-BOM-file', 'path': 'resources/UTF16BE-BOM.txt' },
-    { 'name': 'UTF16LE-BOM-file', 'path': 'resources/UTF16LE-BOM.txt' },
-    { 'name': 'UTF8-BOM-file', 'path': 'resources/UTF8-BOM.txt' },
-    { 'name': 'UTF16BE-file', 'path': 'resources/UTF16BE.txt' },
-    { 'name': 'binary-file', 'path': 'resources/binary-file' },
-];
-var testFiles = { };
-
-function log(message)
-{
-    document.getElementById('console').appendChild(document.createTextNode(message + "\n"));
-}
-
-function isASCIIString(str)
-{
-    for (var i = 0; i < str.length; ++i) {
-        if (str.charCodeAt(i) >= 128)
-            return false;
-    }
-    return true;
-}
-
-function toHexadecimal(str)
-{
-    var result = "";
-    for (var i = 0; i < str.length; ++i) {
-        var hex = "0x" + (str.charCodeAt(i) & 0xFF).toString(16);
-        if (i > 0)
-            result += " ";
-        result += hex;
-    }
-    return result;
-}
-
-function createFileReader()
-{
-    var reader = new FileReader();
-
-    reader.onloadstart = loadStarted;
-    reader.onload = loaded;
-    reader.onabort = logEvent;
-    reader.onloadend = loadEnded;
-    reader.onerror = loadFailed;
-
-    log("readyState: " + reader.readyState);
-    return reader;
-}
-
-function logEvent(event)
-{
-    log("Received " + event.type + " event");
-}
-
-function loadStarted(event)
-{
-    logEvent(event);
-    log("readyState: " + event.target.readyState);
-}
-
-function loaded(event)
-{
-    logEvent(event);
-    log("readyState: " + event.target.readyState);
-    log("result size: " + event.target.result.length);
-
-    var result = event.target.result;
-    var resultOutput = isASCIIString(result) ? result : toHexadecimal(result);
-    log("result: " + resultOutput);
-}
-
-function loadFailed(event)
-{
-    logEvent(event);
-    log("readyState: " + event.target.readyState);
-    log("error code: " + event.target.error.code);
-}
-
-function loadEnded(event)
-{
-    logEvent(event);
-    runNextTest();
-}
-
-function onInputFileChange()
-{
-    var files = document.getElementById("file").files;
-    for (var i = 0; i < files.length; i++)
-        testFiles[testFileInfoList[i]['name']] = files[i];
-
-    runNextTest();
-}
-
-function runNextTest()
-{
-    if (testIndex < testCases.length) {
-        testIndex++;
-        window[testCases[testIndex - 1]]();
-    } else {
-        log("DONE");
-        if (window.layoutTestController)
-            layoutTestController.notifyDone();
-    }
-}
-
-function testReadingNonExistentFile()
-{
-    log("Test reading a non-existent file");
-    var reader = createFileReader();
-    reader.readAsBinaryString(testFiles['non-existent']);
-}
-
-function testReadingEmptyFileAsBinaryString()
-{
-    log("Test reading an empty file as binary string");
-    var reader = createFileReader();
-    reader.readAsBinaryString(testFiles['empty-file']);
-}
-
-function testReadingEmptyFileAsText()
-{
-    log("Test reading an empty file as text");
-    var reader = createFileReader();
-    reader.readAsText(testFiles['empty-file']);
-}
-
-function testReadingEmptyFileAsDataURL()
-{
-    log("Test reading an empty file as data URL");
-    var reader = createFileReader();
-    reader.readAsDataURL(testFiles['empty-file']);
-}
-
-function testReadingUTF8EncodedFileAsBinaryString()
-{
-    log("Test reading a UTF-8 file as binary string");
-    var reader = createFileReader();
-    reader.readAsBinaryString(testFiles['UTF8-file']);
-}
-
-function testReadingBinaryFileAsBinaryString()
-{
-    log("Test reading a binary file as binary string");
-    var reader = createFileReader();
-    reader.readAsBinaryString(testFiles['binary-file']);
-}
-
-function testReadingUTF8EncodedFileAsText()
-{
-    log("Test reading a UTF-8 file as text");
-    var reader = createFileReader();
-    reader.readAsText(testFiles['UTF8-file']);
-}
-
-function testReadingUTF16BEBOMEncodedFileAsText()
-{
-    log("Test reading a UTF-16BE BOM file as text");
-    var reader = createFileReader();
-    reader.readAsText(testFiles['UTF16BE-BOM-file']);
-}
-
-function testReadingUTF16LEBOMEncodedFileAsText()
-{
-    log("Test reading a UTF-16LE BOM file as text");
-    var reader = createFileReader();
-    reader.readAsText(testFiles['UTF16LE-BOM-file']);
-}
-
-function testReadingUTF8BOMEncodedFileAsText()
-{
-    log("Test reading a UTF-8 BOM file as text");
-    var reader = createFileReader();
-    reader.readAsText(testFiles['UTF8-BOM-file']);
-}
-
-function testReadingUTF16BEEncodedFileAsTextWithUTF16Encoding()
-{
-    log("Test reading a UTF-16BE file as text with UTF-16BE encoding");
-    var reader = createFileReader();
-    reader.readAsText(testFiles['UTF16BE-file'], "UTF-16BE");
-}
-
-function testReadingUTF16BEBOMEncodedFileAsTextWithUTF8Encoding()
-{
-    log("Test reading a UTF-16BE BOM file as text with UTF8 encoding");
-    var reader = createFileReader();
-    reader.readAsText(testFiles['UTF16BE-BOM-file'], "UTF-8");
-}
-
-function testReadingUTF16BEBOMEncodedFileAsTextWithInvalidEncoding()
-{
-    log("Test reading a UTF-16BE BOM file as text with invalid encoding");
-    var reader = createFileReader();
-    reader.readAsText(testFiles['UTF16BE-BOM-file'], "AnyInvalidEncoding");
-}
-
-function testReadingUTF8EncodedFileAsDataURL()
-{
-    log("Test reading a UTF-8 file as data URL");
-    var reader = createFileReader();
-    reader.readAsDataURL(testFiles['UTF8-file']);
-}
-
-function testMultipleReads()
-{
-    log("Test calling multiple read methods and only last one is processed");
-    var reader = createFileReader();
-    reader.readAsBinaryString(testFiles['UTF8-file']);
-    reader.readAsText(testFiles['UTF8-file']);
-    reader.readAsDataURL(testFiles['UTF8-file']);
-}
-
-function runTests()
-{
-    var pathsOnly = testFileInfoList.map(function(fileSpec) { return fileSpec['path']; });
-    eventSender.beginDragWithFiles(pathsOnly);
-    eventSender.mouseMoveTo(10, 10);
-    eventSender.mouseUp();
-}
-
-if (window.eventSender) {
-    layoutTestController.dumpAsText();
-    layoutTestController.waitUntilDone();
-    window.onload = runTests;
-}
-</script>
-</body>
-</html>
diff --git a/LayoutTests/fast/files/read-blob-async-expected.txt b/LayoutTests/fast/files/read-blob-async-expected.txt
new file mode 100644 (file)
index 0000000..0c10d5d
--- /dev/null
@@ -0,0 +1,123 @@
+
+Test reading a blob containing non-existent file
+readyState: 0
+Received error event
+readyState: 2
+error code: 8
+Received loadend event
+Test reading a blob containing existent and non-existent file
+readyState: 0
+Received error event
+readyState: 2
+error code: 8
+Received loadend event
+Test reading a blob containing empty file
+readyState: 0
+Received loadstart event
+readyState: 1
+Received load event
+readyState: 2
+result size: 0
+result: 
+Received loadend event
+Test reading a blob containing empty text
+readyState: 0
+Received loadstart event
+readyState: 1
+Received load event
+readyState: 2
+result size: 0
+result: 
+Received loadend event
+Test reading a blob containing empty files and empty texts
+readyState: 0
+Received loadstart event
+readyState: 1
+Received load event
+readyState: 2
+result size: 0
+result: 
+Received loadend event
+Test reading a blob containing single file
+readyState: 0
+Received loadstart event
+readyState: 1
+Received load event
+readyState: 2
+result size: 5
+result: Hello
+Received loadend event
+Test reading a blob containing single text
+readyState: 0
+Received loadstart event
+readyState: 1
+Received load event
+readyState: 2
+result size: 5
+result: First
+Received loadend event
+Test reading a blob containing sliced file
+readyState: 0
+Received loadstart event
+readyState: 1
+Received load event
+readyState: 2
+result size: 5
+result: onder
+Received loadend event
+Test reading a blob containing sliced text
+readyState: 0
+Received loadstart event
+readyState: 1
+Received load event
+readyState: 2
+result size: 4
+result: irst
+Received loadend event
+Test reading a blob containing multiple files
+readyState: 0
+Received loadstart event
+readyState: 1
+Received load event
+readyState: 2
+result size: 19
+result: HelloWonderfulWorld
+Received loadend event
+Test reading a blob containing multiple texts
+readyState: 0
+Received loadstart event
+readyState: 1
+Received load event
+readyState: 2
+result size: 16
+result: FirstSecondThird
+Received loadend event
+Test reading a hybrid blob
+readyState: 0
+Received loadstart event
+readyState: 1
+Received load event
+readyState: 2
+result size: 35
+result: FirstHelloSecondWonderfulWorldThird
+Received loadend event
+Test reading a sliced hybrid blob
+readyState: 0
+Received loadstart event
+readyState: 1
+Received load event
+readyState: 2
+result size: 12
+result: lloSecondWon
+Received loadend event
+Test reading a triple-sliced hybrid blob
+readyState: 0
+Received loadstart event
+readyState: 1
+Received load event
+readyState: 2
+result size: 30
+result: ondWonderfulWorldThirdFooloSec
+Received loadend event
+DONE
+
diff --git a/LayoutTests/fast/files/read-blob-async.html b/LayoutTests/fast/files/read-blob-async.html
new file mode 100644 (file)
index 0000000..8070123
--- /dev/null
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html>
+<body>
+<input type="file" name="file" id="file" onchange="onInputFileChange(testFileInfoList)" multiple>
+<pre id='console'></pre>
+
+<script src="resources/setup-for-read-common.js"></script>
+<script src="resources/read-common.js"></script>
+<script src="resources/read-blob-test-cases.js"></script>
+<script>
+var testFileInfoList = [
+    { 'name': 'non-existent', 'path': 'resources/non-existent' },
+    { 'name': 'empty-file', 'path': 'resources/empty-file' },
+    { 'name': 'file1', 'path': 'resources/UTF8.txt' },
+    { 'name': 'file2', 'path': 'resources/UTF8-2.txt' },
+    { 'name': 'file3', 'path': 'resources/UTF8-3.txt' },
+];
+
+function startTest(testFiles)
+{
+    runNextTest(testFiles);
+}
+
+if (window.eventSender) {
+    layoutTestController.dumpAsText();
+    layoutTestController.waitUntilDone();
+    window.onload = function() { runTests(testFileInfoList); }
+}
+</script>
+</body>
+</html>
similarity index 89%
rename from LayoutTests/fast/files/file-reader-expected.txt
rename to LayoutTests/fast/files/read-file-async-expected.txt
index dae90b523565dac76e20569be38564c77419c027..76fd55ffdca845c5f574702e69829145c29f699d 100644 (file)
@@ -1,5 +1,17 @@
 
-Test reading a non-existent file
+Test reading a non-existent file as binary string
+readyState: 0
+Received error event
+readyState: 2
+error code: 8
+Received loadend event
+Test reading a non-existent file as text
+readyState: 0
+Received error event
+readyState: 2
+error code: 8
+Received loadend event
+Test reading a non-existent file as data URL
 readyState: 0
 Received error event
 readyState: 2
diff --git a/LayoutTests/fast/files/read-file-async.html b/LayoutTests/fast/files/read-file-async.html
new file mode 100644 (file)
index 0000000..c614dfd
--- /dev/null
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html>
+<body>
+<input type="file" name="file" id="file" onchange="onInputFileChange(testFileInfoList)" multiple>
+<pre id='console'></pre>
+
+<script src="resources/setup-for-read-common.js"></script>
+<script src="resources/read-common.js"></script>
+<script src="resources/read-file-test-cases.js"></script>
+<script>
+var testFileInfoList = [
+    { 'name': 'non-existent', 'path': 'resources/non-existent' },
+    { 'name': 'empty-file', 'path': 'resources/empty-file' },
+    { 'name': 'UTF8-file', 'path': 'resources/UTF8.txt' },
+    { 'name': 'UTF16BE-BOM-file', 'path': 'resources/UTF16BE-BOM.txt' },
+    { 'name': 'UTF16LE-BOM-file', 'path': 'resources/UTF16LE-BOM.txt' },
+    { 'name': 'UTF8-BOM-file', 'path': 'resources/UTF8-BOM.txt' },
+    { 'name': 'UTF16BE-file', 'path': 'resources/UTF16BE.txt' },
+    { 'name': 'binary-file', 'path': 'resources/binary-file' },
+];
+
+function startTest(testFiles)
+{
+    runNextTest(testFiles);
+}
+
+if (window.eventSender) {
+    layoutTestController.dumpAsText();
+    layoutTestController.waitUntilDone();
+    window.onload = function() { runTests(testFileInfoList); }
+}
+</script>
+</body>
+</html>
diff --git a/LayoutTests/fast/files/resources/UTF8-2.txt b/LayoutTests/fast/files/resources/UTF8-2.txt
new file mode 100644 (file)
index 0000000..1601e9f
--- /dev/null
@@ -0,0 +1 @@
+Wonderful
\ No newline at end of file
diff --git a/LayoutTests/fast/files/resources/UTF8-3.txt b/LayoutTests/fast/files/resources/UTF8-3.txt
new file mode 100644 (file)
index 0000000..beef906
--- /dev/null
@@ -0,0 +1 @@
+World
\ No newline at end of file
diff --git a/LayoutTests/fast/files/resources/read-blob-test-cases.js b/LayoutTests/fast/files/resources/read-blob-test-cases.js
new file mode 100644 (file)
index 0000000..c14fa4e
--- /dev/null
@@ -0,0 +1,134 @@
+var testCases = [
+    "testReadingNonExistentFileBlob",
+    "testReadingNonExistentFileBlob2",
+    "testReadingEmptyFileBlob",
+    "testReadingEmptyTextBlob",
+    "testReadingEmptyFileAndTextBlob",
+    "testReadingSingleFileBlob",
+    "testReadingSingleTextBlob",
+    "testReadingSlicedFileBlob",
+    "testReadingSlicedTextBlob",
+    "testReadingMultipleFileBlob",
+    "testReadingMultipleTextBlob",
+    "testReadingHybridBlob",
+    "testReadingSlicedHybridBlob",
+    "testReadingTripleSlicedHybridBlob",
+];
+var testIndex = 0;
+
+function runNextTest(testFiles)
+{
+    if (testIndex < testCases.length) {
+        testIndex++;
+        self[testCases[testIndex - 1]](testFiles);
+    } else {
+        log("DONE");
+        if (window && window.layoutTestController)
+            layoutTestController.notifyDone();
+    }
+}
+
+function testReadingNonExistentFileBlob(testFiles)
+{
+    log("Test reading a blob containing non-existent file");
+    var blob = buildBlob([testFiles['non-existent']]);
+    readBlobAsBinaryString(testFiles, blob);
+}
+
+function testReadingNonExistentFileBlob2(testFiles)
+{
+    log("Test reading a blob containing existent and non-existent file");
+    var blob = buildBlob([testFiles['file1'], testFiles['non-existent'], testFiles['empty-file']]);
+    readBlobAsBinaryString(testFiles, blob);
+}
+
+function testReadingEmptyFileBlob(testFiles)
+{
+    log("Test reading a blob containing empty file");
+    var blob = buildBlob([testFiles['empty-file']]);
+    readBlobAsBinaryString(testFiles, blob);
+}
+
+function testReadingEmptyTextBlob(testFiles)
+{
+    log("Test reading a blob containing empty text");
+    var blob = buildBlob(['']);
+    readBlobAsBinaryString(testFiles, blob);
+}
+
+function testReadingEmptyFileAndTextBlob(testFiles)
+{
+    log("Test reading a blob containing empty files and empty texts");
+    var blob = buildBlob(['', testFiles['empty-file'], '', testFiles['empty-file']]);
+    readBlobAsBinaryString(testFiles, blob);
+}
+
+function testReadingSingleFileBlob(testFiles)
+{
+    log("Test reading a blob containing single file");
+    var blob = buildBlob([testFiles['file1']]);
+    readBlobAsBinaryString(testFiles, blob);
+}
+
+function testReadingSingleTextBlob(testFiles)
+{
+    log("Test reading a blob containing single text");
+    var blob = buildBlob(['First']);
+    readBlobAsBinaryString(testFiles, blob);
+}
+
+function testReadingSlicedFileBlob(testFiles)
+{
+    log("Test reading a blob containing sliced file");
+    var blob = buildBlob([testFiles['file2'].slice(1, 5)]);
+    readBlobAsBinaryString(testFiles, blob);
+}
+
+function testReadingSlicedTextBlob(testFiles)
+{
+    log("Test reading a blob containing sliced text");
+    var blob = buildBlob(['First'])
+    blob = blob.slice(1, 10);
+    readBlobAsBinaryString(testFiles, blob);
+}
+
+function testReadingMultipleFileBlob(testFiles)
+{
+    log("Test reading a blob containing multiple files");
+    var blob = buildBlob([testFiles['file1'], testFiles['file2'], testFiles['file3']]);
+    readBlobAsBinaryString(testFiles, blob);
+}
+
+function testReadingMultipleTextBlob(testFiles)
+{
+    log("Test reading a blob containing multiple texts");
+    var blob = buildBlob(['First', 'Second', 'Third']);
+    readBlobAsBinaryString(testFiles, blob);
+}
+
+function testReadingHybridBlob(testFiles)
+{
+    log("Test reading a hybrid blob");
+    var blob = buildBlob(['First', testFiles['file1'], 'Second', testFiles['file2'], testFiles['file3'], 'Third']);
+    readBlobAsBinaryString(testFiles, blob);
+}
+
+function testReadingSlicedHybridBlob(testFiles)
+{
+    log("Test reading a sliced hybrid blob");
+    var blob = buildBlob(['First', testFiles['file1'], 'Second', testFiles['file2'], testFiles['file3'], 'Third']);
+    var blob = blob.slice(7, 12);
+    readBlobAsBinaryString(testFiles, blob);
+}
+
+function testReadingTripleSlicedHybridBlob(testFiles)
+{
+    log("Test reading a triple-sliced hybrid blob");
+    var builder = new BlobBuilder();
+    var blob = buildBlob(['First', testFiles['file1'].slice(1, 10), testFiles['empty-file'], 'Second', testFiles['file2'], testFiles['file3'], 'Third'], builder);
+    var blob = blob.slice(7, 12);
+    var blob2 = buildBlob(['Foo', blob, 'Bar'], builder);
+    var blob2 = blob2.slice(12, 30);
+    readBlobAsBinaryString(testFiles, blob2);
+}
+
diff --git a/LayoutTests/fast/files/resources/read-common.js b/LayoutTests/fast/files/resources/read-common.js
new file mode 100644 (file)
index 0000000..e5d27f3
--- /dev/null
@@ -0,0 +1,99 @@
+// Builds a blob from a list of items.
+// If the 'builder' argument is not provided, create a new one.
+function buildBlob(items, builder)
+{
+    if (builder === undefined)
+        builder = new BlobBuilder();
+    for (var i = 0; i < items.length; i++)
+        builder.append(items[i]);
+    return builder.getBlob();
+}
+
+function readBlobAsBinaryString(testFiles, blob)
+{
+    var reader = createReader(testFiles);
+    reader.readAsBinaryString(blob)
+}
+
+function readBlobAsText(testFiles, blob, encoding)
+{
+    var reader = createReader(testFiles);
+    reader.readAsText(blob, encoding)
+}
+
+function readBlobAsDataURL(testFiles, blob)
+{
+    var reader = createReader(testFiles);
+    reader.readAsDataURL(blob)
+}
+
+function createReader(testFiles)
+{
+    var reader = new FileReader();
+
+    reader.onloadstart = loadStarted;
+    reader.onload = loaded;
+    reader.onabort = logEvent;
+    reader.onloadend = function(event) { loadEnded(testFiles, event); }
+    reader.onerror = loadFailed;
+
+    log("readyState: " + reader.readyState);
+    return reader;
+}
+
+function logEvent(event)
+{
+    log("Received " + event.type + " event");
+}
+
+function loadStarted(event)
+{
+    logEvent(event);
+    log("readyState: " + event.target.readyState);
+}
+
+function loaded(event)
+{
+    logEvent(event);
+    log("readyState: " + event.target.readyState);
+    log("result size: " + event.target.result.length);
+
+    var result = event.target.result;
+    var resultOutput = _isASCIIString(result) ? result : _toHexadecimal(result);
+    log("result: " + resultOutput);
+}
+
+function loadFailed(event)
+{
+    logEvent(event);
+    log("readyState: " + event.target.readyState);
+    log("error code: " + event.target.error.code);
+}
+
+function loadEnded(testFiles, event)
+{
+    logEvent(event);
+    runNextTest(testFiles);
+}
+
+// Helper functions.
+function _isASCIIString(str)
+{
+    for (var i = 0; i < str.length; ++i) {
+        if (str.charCodeAt(i) >= 128)
+            return false;
+    }
+    return true;
+}
+
+function _toHexadecimal(str)
+{
+    var result = "";
+    for (var i = 0; i < str.length; ++i) {
+        var hex = "0x" + (str.charCodeAt(i) & 0xFF).toString(16);
+        if (i > 0)
+            result += " ";
+        result += hex;
+    }
+    return result;
+}
diff --git a/LayoutTests/fast/files/resources/read-file-test-cases.js b/LayoutTests/fast/files/resources/read-file-test-cases.js
new file mode 100644 (file)
index 0000000..519db41
--- /dev/null
@@ -0,0 +1,137 @@
+var testCases = [
+    "testReadingNonExistentFileAsBinaryString",
+    "testReadingNonExistentFileAsText",
+    "testReadingNonExistentFileAsDataURL",
+    "testReadingEmptyFileAsBinaryString",
+    "testReadingEmptyFileAsText",
+    "testReadingEmptyFileAsDataURL",
+    "testReadingUTF8EncodedFileAsBinaryString",
+    "testReadingBinaryFileAsBinaryString",
+    "testReadingUTF8EncodedFileAsText",
+    "testReadingUTF16BEBOMEncodedFileAsText",
+    "testReadingUTF16LEBOMEncodedFileAsText",
+    "testReadingUTF8BOMEncodedFileAsText",
+    "testReadingUTF16BEEncodedFileAsTextWithUTF16Encoding",
+    "testReadingUTF16BEBOMEncodedFileAsTextWithUTF8Encoding",
+    "testReadingUTF16BEBOMEncodedFileAsTextWithInvalidEncoding",
+    "testReadingUTF8EncodedFileAsDataURL",
+    "testMultipleReads",
+];
+var testIndex = 0;
+
+function runNextTest(testFiles)
+{
+    if (testIndex < testCases.length) {
+        testIndex++;
+        self[testCases[testIndex - 1]](testFiles);
+    } else {
+        log("DONE");
+        if (window && window.layoutTestController)
+            layoutTestController.notifyDone();
+    }
+}
+
+function testReadingNonExistentFileAsBinaryString(testFiles)
+{
+    log("Test reading a non-existent file as binary string");
+    readBlobAsBinaryString(testFiles, testFiles['non-existent']);
+}
+
+function testReadingNonExistentFileAsText(testFiles)
+{
+    log("Test reading a non-existent file as text");
+    readBlobAsText(testFiles, testFiles['non-existent']);
+}
+
+function testReadingNonExistentFileAsDataURL(testFiles)
+{
+    log("Test reading a non-existent file as data URL");
+    readBlobAsDataURL(testFiles, testFiles['non-existent']);
+}
+
+function testReadingEmptyFileAsBinaryString(testFiles)
+{
+    log("Test reading an empty file as binary string");
+    readBlobAsBinaryString(testFiles, testFiles['empty-file']);
+}
+
+function testReadingEmptyFileAsText(testFiles)
+{
+    log("Test reading an empty file as text");
+    readBlobAsText(testFiles, testFiles['empty-file']);
+}
+
+function testReadingEmptyFileAsDataURL(testFiles)
+{
+    log("Test reading an empty file as data URL");
+    readBlobAsDataURL(testFiles, testFiles['empty-file']);
+}
+
+function testReadingUTF8EncodedFileAsBinaryString(testFiles)
+{
+    log("Test reading a UTF-8 file as binary string");
+    readBlobAsBinaryString(testFiles, testFiles['UTF8-file']);
+}
+
+function testReadingBinaryFileAsBinaryString(testFiles)
+{
+    log("Test reading a binary file as binary string");
+    readBlobAsBinaryString(testFiles, testFiles['binary-file']);
+}
+
+function testReadingUTF8EncodedFileAsText(testFiles)
+{
+    log("Test reading a UTF-8 file as text");
+    readBlobAsText(testFiles, testFiles['UTF8-file']);
+}
+
+function testReadingUTF16BEBOMEncodedFileAsText(testFiles)
+{
+    log("Test reading a UTF-16BE BOM file as text");
+    readBlobAsText(testFiles, testFiles['UTF16BE-BOM-file']);
+}
+
+function testReadingUTF16LEBOMEncodedFileAsText(testFiles)
+{
+    log("Test reading a UTF-16LE BOM file as text");
+    readBlobAsText(testFiles, testFiles['UTF16LE-BOM-file']);
+}
+
+function testReadingUTF8BOMEncodedFileAsText(testFiles)
+{
+    log("Test reading a UTF-8 BOM file as text");
+    readBlobAsText(testFiles, testFiles['UTF8-BOM-file']);
+}
+
+function testReadingUTF16BEEncodedFileAsTextWithUTF16Encoding(testFiles)
+{
+    log("Test reading a UTF-16BE file as text with UTF-16BE encoding");
+    readBlobAsText(testFiles, testFiles['UTF16BE-file'], "UTF-16BE");
+}
+
+function testReadingUTF16BEBOMEncodedFileAsTextWithUTF8Encoding(testFiles)
+{
+    log("Test reading a UTF-16BE BOM file as text with UTF8 encoding");
+    readBlobAsText(testFiles, testFiles['UTF16BE-BOM-file'], "UTF-8");
+}
+
+function testReadingUTF16BEBOMEncodedFileAsTextWithInvalidEncoding(testFiles)
+{
+    log("Test reading a UTF-16BE BOM file as text with invalid encoding");
+    readBlobAsText(testFiles, testFiles['UTF16BE-BOM-file'], "AnyInvalidEncoding");
+}
+
+function testReadingUTF8EncodedFileAsDataURL(testFiles)
+{
+    log("Test reading a UTF-8 file as data URL");
+    readBlobAsDataURL(testFiles, testFiles['UTF8-file']);
+}
+
+function testMultipleReads(testFiles)
+{
+    log("Test calling multiple read methods and only last one is processed");
+    var reader = createReader();
+    reader.readAsBinaryString(testFiles['UTF8-file']);
+    reader.readAsText(testFiles['UTF8-file']);
+    reader.readAsDataURL(testFiles['UTF8-file']);
+}
diff --git a/LayoutTests/fast/files/resources/setup-for-read-common.js b/LayoutTests/fast/files/resources/setup-for-read-common.js
new file mode 100644 (file)
index 0000000..6398a7c
--- /dev/null
@@ -0,0 +1,22 @@
+function log(message)
+{
+    document.getElementById('console').appendChild(document.createTextNode(message + "\n"));
+}
+
+function onInputFileChange(testFileInfoList)
+{
+    var files = document.getElementById("file").files;
+    var testFiles = { };
+    for (var i = 0; i < files.length; i++)
+        testFiles[testFileInfoList[i]['name']] = files[i];
+
+    startTest(testFiles);
+}
+
+function runTests(testFileInfoList)
+{
+    var pathsOnly = testFileInfoList.map(function(fileSpec) { return fileSpec['path']; });
+    eventSender.beginDragWithFiles(pathsOnly);
+    eventSender.mouseMoveTo(10, 10);
+    eventSender.mouseUp();
+}
index c0b2a5826cd2ead5be19595d2cd6563f398a82d1..f25dddc7e40a1dbe9782fabdd665a174aa636fc7 100644 (file)
@@ -3146,7 +3146,8 @@ http/tests/local/blob/send-sliced-data-blob.html
 http/tests/local/formdata/send-form-data.html
 http/tests/local/formdata/send-form-data-with-sliced-file.html
 http/tests/local/formdata/upload-events.html
-fast/files/file-reader.html
+fast/files/read-blob-async.html
+fast/files/read-file-async.html
 http/tests/media/video-play-stall-seek.html
 http/tests/media/video-play-stall.html
 http/tests/media/video-seekable-stall.html
index 00c595884f5fc8151fa45000111fb6a2c49f6e18..732b33aed5871de1969d1dacc00d96dc4b999227 100644 (file)
@@ -364,7 +364,8 @@ fast/events/window-events-bubble.html
 fast/events/window-events-bubble2.html
 fast/events/window-events-capture.html
 fast/events/zoom-dblclick.html
-fast/files/file-reader.html
+fast/files/read-blob-async.html
+fast/files/read-file-async.html
 fast/forms/25153.html
 fast/forms/access-key.html
 fast/forms/button-enter-click.html
index 85a351e3bb41555f2d787145a604d4f90864d8e4..c058372880ee81b0bd345a4819063cc703d21f43 100644 (file)
@@ -781,7 +781,8 @@ http/tests/security/isolatedWorld/world-reuse.html
 
 # Missing eventSender.beginDragWithFiles()
 fast/dom/Window/window-postmessage-clone-frames.html
-fast/files/file-reader.html
+fast/files/read-blob-async.html
+fast/files/read-file-async.html
 
 # Missing layoutTestController.setAlwaysAcceptCookies()
 http/tests/plugins/third-party-cookie-accept-policy.html
index 4d70004303354813f05d8da3b35b856040882fbd..da9a748467105a31763c69a34e1db25e1fdd135f 100644 (file)
@@ -195,7 +195,8 @@ fast/forms/input-file-re-render.html
 http/tests/security/clipboard/clipboard-file-access.html
 fast/events/drag-file-crash.html
 fast/dom/Window/window-postmessage-clone.html
-fast/files/file-reader.html
+fast/files/read-blob-async.html
+fast/files/read-file-async.html
 
 # Need to add functionality to DumpRenderTree to test IDN <rdar://problem/5301954>
 fast/encoding/idn-security.html
index b8b8b8e0c8a24dbfb19ff99e557106f7a211d0c3..3995ebde3b97f0561653a1b85b9e94281c1745d5 100644 (file)
@@ -1219,7 +1219,6 @@ SET(WebCore_SOURCES
 
     platform/Arena.cpp
     platform/AsyncFileSystem.cpp
-    platform/BlobItem.cpp
     platform/ContentType.cpp
     platform/ContextMenu.cpp
     platform/CrossThreadCopier.cpp
index e874cd3b68e5f4937f34bc0508c9c8cadceca942..14c760abc02ff1d714c4fe72663b5d86a3895f51 100644 (file)
@@ -1,3 +1,101 @@
+2010-08-30  Jian Li  <jianli@chromium.org>
+
+        Reviewed by Darin Fisher.
+
+        Switch the Blob implementation to using the blob data registration model
+        https://bugs.webkit.org/show_bug.cgi?id=44389
+
+        Tests: fast/files/read-blob-async.html
+               fast/files/read-file-async.html
+
+        With this switch, File/Blob/BlobBuilder are changed to register the blob
+        data. FileReader is changed to route through loading the blob resource.
+        FormData is also updated to take BlobData. The WebKit mac implementation
+        is updated to resolve the blob references in the BlobData.
+
+        * CMakeLists.txt: Update the project file to remove BlobItem.*.
+        * GNUmakefile.am: Update the project file to remove BlobItem.*.
+        * WebCore.gypi: Update the project file to remove BlobItem.*.
+        * WebCore.pro: Update the project file to remove BlobItem.*.
+        * WebCore.vcproj/WebCore.vcproj: Update the project file to remove BlobItem.*.
+        * WebCore.xcodeproj/project.pbxproj: Update the project file to remove BlobItem.*.
+        * fileapi/Blob.cpp: Switch to using BlobData.
+        (WebCore::Blob::Blob):
+        (WebCore::Blob::slice):
+        * fileapi/Blob.h: Switch to using BlobData.
+        (WebCore::Blob::create):
+        (WebCore::Blob::size):
+        (WebCore::Blob::isFile):
+        * fileapi/BlobBuilder.cpp: Switch to using BlobData.
+        (WebCore::BlobBuilder::BlobBuilder):
+        (WebCore::BlobBuilder::append):
+        (WebCore::BlobBuilder::getBlob):
+        * fileapi/BlobBuilder.h: Switch to using BlobData.
+        * fileapi/BlobURL.cpp: Add a new helper method used in FormData.
+        (WebCore::BlobURL::getIdentifier):
+        * fileapi/BlobURL.h:
+        * fileapi/File.cpp: Switch to using BlobData.
+        (WebCore::createBlobDataForFile):
+        (WebCore::File::File):
+        (WebCore::File::size):
+        (WebCore::File::captureSnapshot):
+        * fileapi/File.h: Switch to using BlobData.
+        (WebCore::File::create):
+        (WebCore::File::path):
+        (WebCore::File::name):
+        (WebCore::File::webkitRelativePath):
+        * fileapi/FileReader.cpp: Change the reading to route through blob resource loading.
+        (WebCore::FileReader::FileReader):
+        (WebCore::FileReader::readAsBinaryString):
+        (WebCore::FileReader::readAsText):
+        (WebCore::FileReader::readAsDataURL):
+        (WebCore::delayedStart):
+        (WebCore::FileReader::readInternal):
+        (WebCore::FileReader::terminate):
+        (WebCore::FileReader::start):
+        (WebCore::FileReader::didReceiveResponse):
+        (WebCore::FileReader::didReceiveData):
+        (WebCore::FileReader::didFinishLoading):
+        (WebCore::FileReader::didFail):
+        (WebCore::FileReader::failed):
+        (WebCore::FileReader::httpStatusCodeToExceptionCode):
+        (WebCore::FileReader::result):
+        (WebCore::FileReader::convertToDataURL):
+        * fileapi/FileReader.h:
+        * html/FormDataList.cpp: Account to BlobData change.
+        (WebCore::FormDataList::appendString):
+        (WebCore::FormDataList::appendBlob):
+        * html/FormDataList.h: Account to BlobData change.
+        (WebCore::FormDataList::appendBlob):
+        (WebCore::FormDataList::Item::Item):
+        (WebCore::FormDataList::Item::data):
+        (WebCore::FormDataList::Item::blob):
+        (WebCore::FormDataList::items):
+        * loader/FormSubmission.cpp: Account to BlobData change.
+        (WebCore::FormSubmission::create):
+        * platform/BlobItem.cpp: Removed.
+        * platform/BlobItem.h: Removed.
+        * platform/network/BlobRegistryImpl.cpp: Add the implementations for resource loading.
+        (WebCore::BlobRegistryImpl::createResourceHandle):
+        (WebCore::BlobRegistryImpl::loadResourceSynchronously):
+        * platform/network/BlobResourceHandle.cpp: Fix a bug that the ref is not added.
+        (WebCore::BlobResourceHandle::BlobResourceHandle):
+        * platform/network/FormData.cpp: Account to BlobData change.
+        (WebCore::FormData::create):
+        (WebCore::FormData::createMultiPart):
+        (WebCore::FormData::deepCopy):
+        (WebCore::FormData::appendFile):
+        (WebCore::FormData::appendKeyValuePairItems):
+        * platform/network/FormData.h: Account to BlobData change.
+        * platform/network/mac/FormDataStreamMac.mm: Resolve blob references in the form data.
+        (WebCore::closeCurrentStream):
+        (WebCore::advanceCurrentStream):
+        (WebCore::formCreate):
+        (WebCore::formRead):
+        (WebCore::setHTTPBody):
+        * xml/XMLHttpRequest.cpp: Account to BlobData change.
+        (WebCore::XMLHttpRequest::send):
+
 2010-08-30  Eric Seidel  <eric@webkit.org>
 
         Unreviewed, rolling out r66418.
index 1e1de0350b8c0cb923a27ccb878b9635e199a6f8..43948e9d7eb998d5a27cb80803b476b2a952ceda 100644 (file)
@@ -1878,8 +1878,6 @@ webcore_sources += \
        WebCore/platform/Arena.h \
        WebCore/platform/AsyncFileStream.h \
        WebCore/platform/AutodrainedPool.h \
-       WebCore/platform/BlobItem.cpp \
-       WebCore/platform/BlobItem.h \
        WebCore/platform/ContentType.cpp \
        WebCore/platform/ContentType.h \
        WebCore/platform/ContextMenu.cpp \
index e5b57ba08e3a00d8d598cd2be4073d70a9a0bdf7..4784689ab3498125449cc6ff62f30aecd1330885 100644 (file)
             'platform/AsyncFileSystem.h',
             'platform/AsyncFileSystemCallbacks.h',
             'platform/AutodrainedPool.h',
-            'platform/BlobItem.cpp',
-            'platform/BlobItem.h',
             'platform/ContentType.cpp',
             'platform/ContentType.h',
             'platform/ContextMenu.cpp',
index 38100a9441b01b5c1ea7939cf7df7283c309bfc1..f14bdf54a6b86e0861b51eb32f6e00c5c0739619 100644 (file)
@@ -877,7 +877,6 @@ SOURCES += \
     platform/animation/AnimationList.cpp \
     platform/Arena.cpp \
     platform/AsyncFileSystem.cpp \
-    platform/BlobItem.cpp \
     platform/text/Base64.cpp \
     platform/text/BidiContext.cpp \
     platform/text/Hyphenation.cpp \
@@ -1682,7 +1681,6 @@ HEADERS += \
     platform/AsyncFileStream.h \
     platform/AsyncFileSystem.h \
     platform/AsyncFileSystemCallbacks.h \
-    platform/BlobItem.h \
     platform/ContentType.h \
     platform/ContextMenu.h \
     platform/CrossThreadCopier.h \
index 98358dea30d20a9182bf75f8a3955b3c851a85c5..65aebb622bc0097f79a70b68dbf70d23133fab0f 100644 (file)
                                RelativePath="..\platform\AutodrainedPool.h"\r
                                >\r
                        </File>\r
-                       <File\r
-                               RelativePath="..\platform\BlobItem.cpp"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="..\platform\BlobItem.h"\r
-                               >\r
-                       </File>\r
                        <File\r
                                RelativePath="..\platform\ContentType.cpp"\r
                                >\r
index 91bf44e62704bd3e28a794c78acf03f61e9ab1c5..f741dbdb675bd9b7b686e9071dc65b2accc659c3 100644 (file)
                89686CA0122244A00076EAA4 /* DOMFilePath.h in Headers */ = {isa = PBXBuildFile; fileRef = 89686C9E122244A00076EAA4 /* DOMFilePath.h */; };
                898783D312232A13003AABDA /* LocalFileSystem.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 898783D112232A13003AABDA /* LocalFileSystem.cpp */; };
                898783D412232A13003AABDA /* LocalFileSystem.h in Headers */ = {isa = PBXBuildFile; fileRef = 898783D212232A13003AABDA /* LocalFileSystem.h */; };
-               8988E10E11A3508B00DB732E /* BlobItem.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8988E10C11A3508B00DB732E /* BlobItem.cpp */; };
-               8988E10F11A3508B00DB732E /* BlobItem.h in Headers */ = {isa = PBXBuildFile; fileRef = 8988E10D11A3508B00DB732E /* BlobItem.h */; settings = {ATTRIBUTES = (Private, ); }; };
                899ABC261215E4A300F9F219 /* DirectoryEntry.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 899ABC201215E4A300F9F219 /* DirectoryEntry.cpp */; };
                899ABC271215E4A300F9F219 /* DirectoryEntry.h in Headers */ = {isa = PBXBuildFile; fileRef = 899ABC211215E4A300F9F219 /* DirectoryEntry.h */; };
                899ABC291215E4A300F9F219 /* DirectoryReader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 899ABC231215E4A300F9F219 /* DirectoryReader.cpp */; };
                897A2D92120003760082740C /* JSFlags.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSFlags.h; sourceTree = "<group>"; };
                898783D112232A13003AABDA /* LocalFileSystem.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LocalFileSystem.cpp; sourceTree = "<group>"; };
                898783D212232A13003AABDA /* LocalFileSystem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LocalFileSystem.h; sourceTree = "<group>"; };
-               8988E10C11A3508B00DB732E /* BlobItem.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BlobItem.cpp; sourceTree = "<group>"; };
-               8988E10D11A3508B00DB732E /* BlobItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BlobItem.h; sourceTree = "<group>"; };
                899ABC201215E4A300F9F219 /* DirectoryEntry.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DirectoryEntry.cpp; sourceTree = "<group>"; };
                899ABC211215E4A300F9F219 /* DirectoryEntry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DirectoryEntry.h; sourceTree = "<group>"; };
                899ABC221215E4A300F9F219 /* DirectoryEntry.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = DirectoryEntry.idl; sourceTree = "<group>"; };
                                89D08D9D12228451001241DF /* AsyncFileSystem.h */,
                                89D08D9E12228451001241DF /* AsyncFileSystemCallbacks.h */,
                                51E1ECB10C91C55600DC255B /* AutodrainedPool.h */,
-                               8988E10C11A3508B00DB732E /* BlobItem.cpp */,
-                               8988E10D11A3508B00DB732E /* BlobItem.h */,
                                BCC8CFCA0986CD2400140BF2 /* ColorData.gperf */,
                                41D015C90F4B5C71004A662F /* ContentType.cpp */,
                                41D015C80F4B5C71004A662F /* ContentType.h */,
                                BCE789861120E7A60060ECE5 /* BidiRun.h in Headers */,
                                938192050F87E1EC00D5352A /* BinaryPropertyList.h in Headers */,
                                A89943280B42338800D7C802 /* BitmapImage.h in Headers */,
-                               8988E10F11A3508B00DB732E /* BlobItem.h in Headers */,
                                93F199BE08245E59001E9ABC /* BlockExceptions.h in Headers */,
                                BC5EB5E10E81BE8700B25965 /* BorderData.h in Headers */,
                                BC5EB5DB0E81B7EA00B25965 /* BorderValue.h in Headers */,
                                BCE7898B1120E8020060ECE5 /* BidiRun.cpp in Sources */,
                                938192030F87E1E600D5352A /* BinaryPropertyList.cpp in Sources */,
                                A89943290B42338800D7C802 /* BitmapImage.cpp in Sources */,
-                               8988E10E11A3508B00DB732E /* BlobItem.cpp in Sources */,
                                93F19AE108245E59001E9ABC /* BlockExceptions.mm in Sources */,
                                BCEA4854097D93020094C9E4 /* break_lines.cpp in Sources */,
                                93309DDA099E64920056E581 /* BreakBlockquoteCommand.cpp in Sources */,
index 3a62ab13385bd6514faf893487be5d95228455b6..5fed3276c667cad7459758c46215bd4a1ba7cb2d 100644 (file)
 #include "config.h"
 #include "Blob.h"
 
-#include "BlobData.h"
-#include "BlobItem.h"
 #include "BlobURL.h"
-#include "FileSystem.h"
+#include "File.h"
 #include "ScriptExecutionContext.h"
 #include "ThreadableBlobRegistry.h"
 
 namespace WebCore {
 
-// FIXME: To be removed when we switch to using BlobData.
-Blob::Blob(ScriptExecutionContext* scriptExecutionContext, const String& type, const BlobItemList& items)
-    : m_scriptExecutionContext(scriptExecutionContext)
-    , m_type(type)
-    , m_size(0)
-{
-    m_scriptExecutionContext->addBlob(this);
-    for (size_t i = 0; i < items.size(); ++i)
-        m_items.append(items[i]);
-}
-
-// FIXME: To be removed when we switch to using BlobData.
-Blob::Blob(ScriptExecutionContext* scriptExecutionContext, const PassRefPtr<BlobItem>& item)
-    : m_scriptExecutionContext(scriptExecutionContext)
-    , m_size(0)
-{
-    m_scriptExecutionContext->addBlob(this);
-    m_items.append(item);
-}
-
-// FIXME: To be removed when we switch to using BlobData.
-Blob::Blob(ScriptExecutionContext* scriptExecutionContext, const String& path)
-    : m_scriptExecutionContext(scriptExecutionContext)
-    , m_size(0)
-{
-    m_scriptExecutionContext->addBlob(this);
-    // Note: this doesn't initialize the type unlike File(path).
-    m_items.append(FileBlobItem::create(path));
-}
-
 Blob::Blob(ScriptExecutionContext* scriptExecutionContext, PassOwnPtr<BlobData> blobData, long long size)
     : m_scriptExecutionContext(scriptExecutionContext)
     , m_type(blobData->contentType())
     , m_size(size)
 {
-    ASSERT(blobData.get() && !blobData->items().isEmpty());
+    ASSERT(blobData);
 
     m_scriptExecutionContext->addBlob(this);
 
@@ -89,11 +57,7 @@ Blob::Blob(ScriptExecutionContext* scriptExecutionContext, const KURL& srcURL, c
     , m_type(type)
     , m_size(size)
 {
-    m_scriptExecutionContext->addBlob(this);
-
-    // FIXME: To be removed when we switch to using BlobData.
-    if (srcURL.isEmpty())
-        return;
+   m_scriptExecutionContext->addBlob(this);
 
     // Create a new internal URL and register it with the same blob data as the source URL.
     m_url = BlobURL::createURL(scriptExecutionContext);
@@ -118,50 +82,42 @@ void Blob::contextDestroyed()
     m_scriptExecutionContext = 0;
 }
 
-unsigned long long Blob::size() const
-{
-    // FIXME: JavaScript cannot represent sizes as large as unsigned long long, we need to
-    // come up with an exception to throw if file size is not represetable.
-    unsigned long long size = 0;
-    for (size_t i = 0; i < m_items.size(); ++i)
-        size += m_items[i]->size();
-    return size;
-}
-
-// FIXME: To be removed when we switch to using BlobData.
-const String& Blob::path() const
-{
-    ASSERT(m_items.size() == 1 && m_items[0]->toFileBlobItem());
-    return m_items[0]->toFileBlobItem()->path();
-}
-
 #if ENABLE(BLOB)
 PassRefPtr<Blob> Blob::slice(ScriptExecutionContext* scriptExecutionContext, long long start, long long length, const String& contentType) const
 {
+    // When we slice a file for the first time, we obtain a snapshot of the file by capturing its current size and modification time.
+    // The modification time will be used to verify if the file has been changed or not, when the underlying data are accessed.
+    long long size;
+    double modificationTime;
+    if (isFile())
+        // FIXME: This involves synchronous file operation. We need to figure out how to make it asynchronous.
+        static_cast<const File*>(this)->captureSnapshot(size, modificationTime);
+    else {
+        ASSERT(m_size != -1);
+        size = m_size;
+    }
+
+    // Clamp the range if it exceeds the size limit.
     if (start < 0)
         start = 0;
     if (length < 0)
         length = 0;
 
-    // Clamp the range if it exceeds the size limit.
-    unsigned long long totalSize = size();
-    if (static_cast<unsigned long long>(start) > totalSize) {
+    if (start >= size) {
         start = 0;
         length = 0;
-    } else if (static_cast<unsigned long long>(start + length) > totalSize)
-        length = totalSize - start;
-
-    size_t i = 0;
-    BlobItemList items;
-    for (; i < m_items.size() && static_cast<unsigned long long>(start) >= m_items[i]->size(); ++i)
-        start -= m_items[i]->size();
-    for (; length > 0 && i < m_items.size(); ++i) {
-        items.append(m_items[i]->slice(start, length));
-        length -= items.last()->size();
-        start = 0;
-    }
-    return Blob::create(scriptExecutionContext, contentType, items);
+    } else if (start + length > size)
+        length = size - start;
+
+    OwnPtr<BlobData> blobData = BlobData::create();
+    blobData->setContentType(contentType);
+    if (isFile())
+        blobData->appendFile(static_cast<const File*>(this)->path(), start, length, modificationTime);
+    else
+        blobData->appendBlob(m_url, start, length);
+
+    return Blob::create(scriptExecutionContext, blobData.release(), length);
 }
-#endif // ENABLE(BLOB)
+#endif
 
 } // namespace WebCore
index 374a4015e48ef79b0df78f2b62f61ab6a715f763..0d5649ce42b9e93c9cb93718f9879e95da53a489 100644 (file)
@@ -31,7 +31,7 @@
 #ifndef Blob_h
 #define Blob_h
 
-#include "BlobItem.h"
+#include "BlobData.h"
 #include "KURL.h"
 #include "PlatformString.h"
 #include <wtf/PassOwnPtr.h>
 
 namespace WebCore {
 
-class BlobData;
 class ScriptExecutionContext;
 
 class Blob : public RefCounted<Blob> {
 public:
-    // FIXME: To be removed when we switch to using BlobData.
-    static PassRefPtr<Blob> create(ScriptExecutionContext* scriptExecutionContext, const String& type, const BlobItemList& items)
+    static PassRefPtr<Blob> create(ScriptExecutionContext* scriptExecutionContext, PassOwnPtr<BlobData> blobData, long long size)
     {
-        return adoptRef(new Blob(scriptExecutionContext, type, items));
+        return adoptRef(new Blob(scriptExecutionContext, blobData, size));
     }
 
     // For deserialization.
@@ -63,38 +61,25 @@ public:
     void contextDestroyed();
 
     const KURL& url() const { return m_url; }
-    unsigned long long size() const;
     const String& type() const { return m_type; }
-    virtual bool isFile() const { return false; }
-
-    // FIXME: To be removed when we switch to using BlobData.
-    const String& path() const;
 
-    // FIXME: To be removed when we switch to using BlobData.
-    const BlobItemList& items() const { return m_items; }
+    virtual unsigned long long size() const { return static_cast<unsigned long long>(m_size); }
+    virtual bool isFile() const { return false; }
 
 #if ENABLE(BLOB)
     PassRefPtr<Blob> slice(ScriptExecutionContext*, long long start, long long length, const String& contentType = String()) const;
 #endif
 
 protected:
-    // FIXME: To be removed when we switch to using BlobData.
-    Blob(ScriptExecutionContext*, const String& type, const BlobItemList&);
-    Blob(ScriptExecutionContext*, const PassRefPtr<BlobItem>&);
-    Blob(ScriptExecutionContext*, const String& path);
-
     Blob(ScriptExecutionContext*, PassOwnPtr<BlobData>, long long size);
 
     // For deserialization.
     Blob(ScriptExecutionContext*, const KURL& srcURL, const String& type, long long size);
 
-    // FIXME: To be removed when we switch to using BlobData.
-    BlobItemList m_items;
-
     // This is an internal URL referring to the blob data associated with this object.
     // It is only used by FileReader to read the blob data via loading from the blob URL resource.
     KURL m_url;
-
+    
     ScriptExecutionContext* m_scriptExecutionContext;
     String m_type;
     long long m_size;
index 29a75950b42a2b2c200dcb36d729207534a6febe..08ded1be0b0070368fbfa664ecc0029f0b0e876c 100644 (file)
@@ -34,6 +34,7 @@
 
 #include "Blob.h"
 #include "ExceptionCode.h"
+#include "File.h"
 #include "LineEnding.h"
 #include "TextEncoding.h"
 #include <wtf/text/AtomicString.h>
@@ -56,13 +57,19 @@ static CString convertToCString(const String& text, const String& endingType, Ex
     return CString();
 }
 
+BlobBuilder::BlobBuilder()
+    : m_size(0)
+{
+}
+
 bool BlobBuilder::append(const String& text, const String& endingType, ExceptionCode& ec)
 {
     CString cstr = convertToCString(text, endingType, ec);
     if (ec)
         return false;
 
-    m_items.append(StringBlobItem::create(cstr));
+    m_size += cstr.length();
+    m_items.append(BlobDataItem(cstr));
     return true;
 }
 
@@ -73,17 +80,37 @@ bool BlobBuilder::append(const String& text, ExceptionCode& ec)
 
 bool BlobBuilder::append(PassRefPtr<Blob> blob)
 {
-    if (blob) {
-        for (size_t i = 0; i < blob->items().size(); ++i)
-            m_items.append(blob->items()[i]);
-        return true;
+    if (blob->isFile()) {
+        // If the blob is file that is not snapshoted, capture the snapshot now.
+        // FIXME: This involves synchronous file operation. We need to figure out how to make it asynchronous.
+        File* file = static_cast<File*>(blob.get());
+        long long snapshotSize;
+        double snapshotModificationTime;
+        file->captureSnapshot(snapshotSize, snapshotModificationTime);
+
+        m_size += snapshotSize;
+        m_items.append(BlobDataItem(file->path(), 0, snapshotSize, snapshotModificationTime));
+    } else {
+        long long blobSize = static_cast<long long>(blob->size());
+        m_size += blobSize;
+        m_items.append(BlobDataItem(blob->url(), 0, blobSize));
     }
-    return false;
+    return true;
 }
 
-PassRefPtr<Blob> BlobBuilder::getBlob(ScriptExecutionContext* scriptExecutionContext, const String& contentType) const
+PassRefPtr<Blob> BlobBuilder::getBlob(ScriptExecutionContext* scriptExecutionContext, const String& contentType)
 {
-    return Blob::create(scriptExecutionContext, contentType, m_items);
+    OwnPtr<BlobData> blobData = BlobData::create();
+    blobData->setContentType(contentType);
+    blobData->swapItems(m_items);
+
+    RefPtr<Blob> blob = Blob::create(scriptExecutionContext, blobData.release(), m_size);
+
+    // After creating a blob from the current blob data, we do not need to keep the data around any more. Instead, we only
+    // need to keep a reference to the URL of the blob just created.
+    m_items.append(BlobDataItem(blob->url(), 0, m_size));
+
+    return blob;
 }
 
 } // namespace WebCore
index 5d1700f8e022663d1216043ebddf06e47cbde299..20e510a756479dd68d10049c9a4432209a810a21 100644 (file)
 #ifndef BlobBuilder_h
 #define BlobBuilder_h
 
-#include "BlobItem.h"
+#include "BlobData.h"
+#include "PlatformString.h"
 #include <wtf/PassRefPtr.h>
 #include <wtf/RefCounted.h>
+#include <wtf/Vector.h>
+#include <wtf/text/CString.h>
 
 namespace WebCore {
 
 class Blob;
 class ScriptExecutionContext;
+class TextEncoding;
 
 typedef int ExceptionCode;
 
@@ -50,10 +54,13 @@ public:
     bool append(const String& text, ExceptionCode&);
     bool append(const String& text, const String& ending, ExceptionCode&);
 
-    PassRefPtr<Blob> getBlob(ScriptExecutionContext*, const String& contentType = String()) const;
+    PassRefPtr<Blob> getBlob(ScriptExecutionContext*, const String& contentType = String());
 
 private:
-    BlobItemList m_items;
+    BlobBuilder();
+
+    long long m_size;
+    BlobDataItemList m_items;
 };
 
 } // namespace WebCore
index 610aac45e385351680105cbc1030fb1082e00635..c5571a7e604ff00a7eb0babed41dd439c273da62 100644 (file)
@@ -63,4 +63,12 @@ KURL BlobURL::getOrigin(const KURL& url)
     return KURL(ParsedURLString, decodeURLEscapeSequences(origin));
 }
 
+String BlobURL::getIdentifier(const KURL& url)
+{
+    ASSERT(url.protocolIs("blob"));
+
+    unsigned startIndex = url.pathAfterLastSlash();
+    return url.string().substring(startIndex);
+}
+
 } // namespace WebCore
index 2ce2c85e374419ebb6e2ad2bb92cfe79465fa570..e73b771bb00e7ce2e442cb70accbff3f954df491 100644 (file)
@@ -41,6 +41,7 @@ class BlobURL {
 public:
     static KURL createURL(ScriptExecutionContext*);
     static KURL getOrigin(const KURL&);
+    static String getIdentifier(const KURL& url);
 };
 
 }
index 253cb4d6d99ee60528423cc5f1c5334ec1d0d7f1..6cc1393c189f5fd41974d5d50e5a4cfd7673b686 100644 (file)
 #include "config.h"
 #include "File.h"
 
-#include "BlobData.h"
+#include "BlobRegistry.h"
 #include "FileSystem.h"
 #include "MIMETypeRegistry.h"
 
 namespace WebCore {
 
+static PassOwnPtr<BlobData> createBlobDataForFile(const String& path)
+{
+    String type;
+    int index = path.reverseFind('.');
+    if (index != -1)
+        type = MIMETypeRegistry::getMIMETypeForExtension(path.substring(index + 1));
+
+    OwnPtr<BlobData> blobData = BlobData::create();
+    blobData->setContentType(type);
+    blobData->appendFile(path);
+    return blobData.release();
+}
+
 File::File(ScriptExecutionContext* scriptExecutionContext, const String& path)
-    : Blob(scriptExecutionContext, path)
+    : Blob(scriptExecutionContext, createBlobDataForFile(path), -1)
+    , m_path(path)
+    , m_name(pathGetFileName(path))
 {
-    Init();
 }
 
 File::File(ScriptExecutionContext* scriptExecutionContext, const String& path, const KURL& url, const String& type)
-    : Blob(scriptExecutionContext, url, type, BlobDataItem::toEndOfFile)
+    : Blob(scriptExecutionContext, url, type, -1)
+    , m_path(path)
 {
-    // FIXME: To be removed when we switch to using BlobData.
-     m_items.append(FileBlobItem::create(path));
+    m_name = pathGetFileName(path);
 }
 
 #if ENABLE(DIRECTORY_UPLOAD)
-File::File(ScriptExecutionContext* scriptExecutionContext, const String& relativePath, const String& filePath)
-    : Blob(scriptExecutionContext, FileBlobItem::create(filePath, relativePath))
+File::File(ScriptExecutionContext* scriptExecutionContext, const String& relativePath, const String& path)
+    : Blob(scriptExecutionContext, createBlobDataForFile(path), -1)
+    , m_path(path)
+    , m_relativePath(relativePath)
 {
-    Init();
 }
 #endif
 
-void File::Init()
+unsigned long long File::size() const
 {
-    // We don't use MIMETypeRegistry::getMIMETypeForPath() because it returns "application/octet-stream" upon failure.
-    const String& fileName = name();
-    size_t index = fileName.reverseFind('.');
-    if (index != notFound)
-        m_type = MIMETypeRegistry::getMIMETypeForExtension(fileName.substring(index + 1));
+    // FIXME: JavaScript cannot represent sizes as large as unsigned long long, we need to
+    // come up with an exception to throw if file size is not representable.
+    long long size;
+    if (!getFileSize(m_path, size))
+        return 0;
+    return static_cast<unsigned long long>(size);
 }
 
-const String& File::name() const
+void File::captureSnapshot(long long& snapshotSize, double& snapshotModificationTime) const
 {
-    return items().at(0)->toFileBlobItem()->name();
+    // Obtains a snapshot of the file by capturing its current size and modification time. This is used when we slice a file for the first time.
+    // If we fail to retrieve the size or modification time, probably due to that the file has been deleted, 0 size is returned.
+    // FIXME: Combine getFileSize and getFileModificationTime into one file system call.
+    time_t modificationTime;
+    if (!getFileSize(m_path, snapshotSize) || !getFileModificationTime(m_path, modificationTime)) {
+        snapshotSize = 0;
+        snapshotModificationTime = 0;
+    } else
+        snapshotModificationTime = modificationTime;
 }
 
-#if ENABLE(DIRECTORY_UPLOAD)
-const String& File::webkitRelativePath() const
-{
-    return items().at(0)->toFileBlobItem()->relativePath();
-}
-#endif
-
 } // namespace WebCore
index 06a73c5eb34009be6dc74161295b3b9e78f108fc..d6446d367fa4d4ce090dd3f65e3a859bb543279d 100644 (file)
 #define File_h
 
 #include "Blob.h"
+#include "PlatformString.h"
 #include <wtf/PassRefPtr.h>
 #include <wtf/RefCounted.h>
 
 namespace WebCore {
 
+class KURL;
+class ScriptExecutionContext;
+
 class File : public Blob {
 public:
     static PassRefPtr<File> create(ScriptExecutionContext* scriptExecutionContext, const String& path)
@@ -40,9 +44,9 @@ public:
     }
 
     // For deserialization.
-    static PassRefPtr<File> create(ScriptExecutionContext* scriptExecutionContext, const String& path, const KURL& url, const String& type)
+    static PassRefPtr<File> create(ScriptExecutionContext* scriptExecutionContext, const String& path, const KURL& srcURL, const String& type)
     {
-        return adoptRef(new File(scriptExecutionContext, path, url, type));
+        return adoptRef(new File(scriptExecutionContext, path, srcURL, type));
     }
 
 #if ENABLE(DIRECTORY_UPLOAD)
@@ -52,29 +56,38 @@ public:
     }
 #endif
 
+    virtual unsigned long long size() const;
     virtual bool isFile() const { return true; }
 
-    const String& name() const;
+    const String& path() const { return m_path; }
+    const String& name() const { return m_name; }
 #if ENABLE(DIRECTORY_UPLOAD)
     // Returns the relative path of this file in the context of a directory selection.
-    const String& webkitRelativePath() const;
+    const String& webkitRelativePath() const { return m_relativePath; }
 #endif
 
+    // Note that this involves synchronous file operation. Think twice before calling this function.
+    void captureSnapshot(long long& snapshotSize, double& snapshotModificationTime) const;
+
     // FIXME: obsolete attributes. To be removed.
     const String& fileName() const { return name(); }
     unsigned long long fileSize() const { return size(); }
 
 private:
     File(ScriptExecutionContext*, const String& path);
-
+    
     // For deserialization.
-    File(ScriptExecutionContext*, const String& path, const KURL&, const String& type);
+    File(ScriptExecutionContext*, const String& path, const KURL& srcURL, const String& type);
 
 #if ENABLE(DIRECTORY_UPLOAD)
     File(ScriptExecutionContext*, const String& relativePath, const String& path);
 #endif
 
-    void Init();
+    String m_path;
+    String m_name;
+#if ENABLE(DIRECTORY_UPLOAD)
+    String m_relativePath;
+#endif
 };
 
 } // namespace WebCore
index d600d40ffd77a0e8ef25bf692c894204eb6ef757..747b6fffc2067271e6b61d6cb18b62113b8f96b5 100644 (file)
 
 #include "Base64.h"
 #include "Blob.h"
+#include "CrossThreadTask.h"
 #include "File.h"
-#include "FileStreamProxy.h"
 #include "Logging.h"
 #include "ProgressEvent.h"
+#include "ResourceError.h"
+#include "ResourceRequest.h"
 #include "ScriptExecutionContext.h"
 #include "TextResourceDecoder.h"
+#include "ThreadableLoader.h"
 #include <wtf/CurrentTime.h>
 
 namespace WebCore {
 
-const unsigned bufferSize = 1024;
 const double progressNotificationIntervalMS = 50;
 
 FileReader::FileReader(ScriptExecutionContext* context)
@@ -59,7 +61,6 @@ FileReader::FileReader(ScriptExecutionContext* context)
     , m_totalBytes(0)
     , m_lastProgressNotificationTimeMS(0)
 {
-    m_buffer.resize(bufferSize);
 }
 
 FileReader::~FileReader()
@@ -83,55 +84,56 @@ void FileReader::stop()
     terminate();
 }
 
-void FileReader::readAsBinaryString(Blob* fileBlob)
+void FileReader::readAsBinaryString(Blob* blob)
 {
-    if (!fileBlob)
+    if (!blob)
         return;
 
-    // FIXME: needs to handle non-file blobs.
-    LOG(FileAPI, "FileReader: reading as binary: %s\n", fileBlob->path().utf8().data());
+    LOG(FileAPI, "FileReader: reading as binary: %s %s\n", blob->url().string().utf8().data(), blob->isFile() ? static_cast<File*>(blob)->path().utf8().data() : "");
 
-    readInternal(fileBlob, ReadFileAsBinaryString);
+    readInternal(blob, ReadFileAsBinaryString);
 }
 
-void FileReader::readAsText(Blob* fileBlob, const String& encoding)
+void FileReader::readAsText(Blob* blob, const String& encoding)
 {
-    if (!fileBlob)
+    if (!blob)
         return;
 
-    // FIXME: needs to handle non-file blobs.
-    LOG(FileAPI, "FileReader: reading as text: %s\n", fileBlob->path().utf8().data());
+    LOG(FileAPI, "FileReader: reading as text: %s %s\n", blob->url().string().utf8().data(), blob->isFile() ? static_cast<File*>(blob)->path().utf8().data() : "");
 
     if (!encoding.isEmpty())
         m_encoding = TextEncoding(encoding);
-    readInternal(fileBlob, ReadFileAsText);
+    readInternal(blob, ReadFileAsText);
 }
 
-void FileReader::readAsDataURL(File* file)
+void FileReader::readAsDataURL(Blob* blob)
 {
-    if (!file)
+    if (!blob)
         return;
 
-    LOG(FileAPI, "FileReader: reading as data URL: %s\n", file->path().utf8().data());
+    LOG(FileAPI, "FileReader: reading as data URL: %s %s\n", blob->url().string().utf8().data(), blob->isFile() ? static_cast<File*>(blob)->path().utf8().data() : "");
 
-    m_fileType = file->type();
-    readInternal(file, ReadFileAsDataURL);
+    m_fileType = blob->type();
+    readInternal(blob, ReadFileAsDataURL);
 }
 
-void FileReader::readInternal(Blob* fileBlob, ReadType type)
+static void delayedStart(ScriptExecutionContext*, FileReader* reader)
+{
+    reader->start();
+}
+
+void FileReader::readInternal(Blob* blob, ReadType type)
 {
     // readAs*** methods() can be called multiple times. Only the last call before the actual reading happens is processed.
     if (m_state != None && m_state != Starting)
         return;
 
-    m_fileBlob = fileBlob;
+    if (m_state == None)
+        scriptExecutionContext()->postTask(createCallbackTask(&delayedStart, this));
+
+    m_blob = blob;
     m_readType = type;
     m_state = Starting;
-
-    // When FileStreamProxy is created, FileReader::didStart() will get notified on the File thread and we will start
-    // opening and reading the file since then.
-    if (!m_streamProxy.get())
-        m_streamProxy = FileStreamProxy::create(scriptExecutionContext(), this);
 }
 
 void FileReader::abort()
@@ -150,87 +152,66 @@ void FileReader::abort()
 
 void FileReader::terminate()
 {
-    if (m_streamProxy) {
-        m_streamProxy->stop();
-        m_streamProxy = 0;
+    if (m_loader) {
+        m_loader->cancel();
+        m_loader = 0;
     }
     m_state = Completed;
 }
 
-void FileReader::didStart()
+void FileReader::start()
 {
     m_state = Opening;
 
-    ASSERT(m_fileBlob->items().size() == 1 && m_fileBlob->items().at(0)->toFileBlobItem());
-    const FileRangeBlobItem* fileRangeItem = m_fileBlob->items().at(0)->toFileRangeBlobItem();
-    double expectedModificationTime = fileRangeItem ? fileRangeItem->snapshotModificationTime() : 0;
+    // The blob is read by routing through the request handling layer given the blob url.
+    ResourceRequest request(m_blob->url());
+    request.setHTTPMethod("GET");
+
+    ThreadableLoaderOptions options;
+    options.sendLoadCallbacks = true;
+    options.sniffContent = false;
+    options.forcePreflight = false;
+    options.allowCredentials = true;
+    options.crossOriginRequestPolicy = DenyCrossOriginRequests;
 
-    m_streamProxy->getSize(m_fileBlob->path(), expectedModificationTime);
+    m_loader = ThreadableLoader::create(scriptExecutionContext(), this, request, options);
 }
 
-void FileReader::didGetSize(long long size)
+void FileReader::didReceiveResponse(const ResourceResponse& response)
 {
-    // If the size is -1, it means the file has been moved or changed. Fail now.
-    if (size == -1) {
-        didFail(NOT_FOUND_ERR);
+    if (response.httpStatusCode() != 200) {
+        failed(response.httpStatusCode());
         return;
     }
 
     m_state = Reading;
     fireEvent(eventNames().loadstartEvent);
 
-    ASSERT(m_fileBlob->items().size() == 1 && m_fileBlob->items().at(0)->toFileBlobItem());
-    const FileRangeBlobItem* fileRangeItem = m_fileBlob->items().at(0)->toFileRangeBlobItem();
-    long long start = fileRangeItem ? fileRangeItem->start() : 0;
-
-    // The size passed back is the size of the whole file. If the underlying item is a sliced file, we need to use the slice length.
-    m_totalBytes = fileRangeItem ? fileRangeItem->size() : size;
-
-    m_streamProxy->openForRead(m_fileBlob->path(), start, m_totalBytes);
+    m_totalBytes = response.expectedContentLength();
 }
 
-void FileReader::didOpen(bool success)
+void FileReader::didReceiveData(const char* data, int lengthReceived)
 {
-    if (!success) {
-        didFail(NOT_READABLE_ERR);
-        return;
-    }
-    
-    m_streamProxy->read(m_buffer.data(), m_buffer.size());
-}
+    ASSERT(data && lengthReceived);
 
-void FileReader::didRead(int bytesRead)
-{
     // Bail out if we have aborted the reading.
     if (m_state == Completed)
         return;
 
-    // If bytesRead is -1, it means an error happens.
-    if (bytesRead == -1) {
-        didFail(NOT_READABLE_ERR);
-        return;
-    }
-
-    // If bytesRead is 0, it means the reading is done.
-    if (!bytesRead) {
-        didFinish();
-        return;
-    }
-
     switch (m_readType) {
     case ReadFileAsBinaryString:
-        m_result += String(m_buffer.data(), static_cast<unsigned>(bytesRead));
+        m_result += String(data, static_cast<unsigned>(lengthReceived));
         break;
     case ReadFileAsText:
     case ReadFileAsDataURL:
-        m_rawData.append(m_buffer.data(), static_cast<unsigned>(bytesRead));
+        m_rawData.append(data, static_cast<unsigned>(lengthReceived));
         m_isRawDataConverted = false;
         break;
     default:
         ASSERT_NOT_REACHED();
     }
 
-    m_bytesLoaded += bytesRead;
+    m_bytesLoaded += lengthReceived;
 
     // Fire the progress event at least every 50ms.
     double now = WTF::currentTimeMS();
@@ -240,30 +221,45 @@ void FileReader::didRead(int bytesRead)
         fireEvent(eventNames().progressEvent);
         m_lastProgressNotificationTimeMS = now;
     }
-
-    // Continue reading.
-    m_streamProxy->read(m_buffer.data(), m_buffer.size());
 }
 
-void FileReader::didFinish()
+void FileReader::didFinishLoading(unsigned long)
 {
     m_state = Completed;
 
-    m_streamProxy->close();
-
     fireEvent(eventNames().loadEvent);
     fireEvent(eventNames().loadendEvent);
+
+    m_loader = 0;
 }
 
-void FileReader::didFail(ExceptionCode ec)
+void FileReader::didFail(const ResourceError&)
 {
-    m_state = Completed;
-    m_error = FileError::create(ec);
+    // Treat as internal error.
+    failed(500);
+}
 
-    m_streamProxy->close();
+void FileReader::failed(int httpStatusCode)
+{
+    m_state = Completed;
 
+     m_error = FileError::create(httpStatusCodeToExceptionCode(httpStatusCode));
     fireEvent(eventNames().errorEvent);
     fireEvent(eventNames().loadendEvent);
+
+    m_loader = 0;
+}
+
+ExceptionCode FileReader::httpStatusCodeToExceptionCode(int httpStatusCode)
+{
+    switch (httpStatusCode) {
+        case 403:
+            return SECURITY_ERR;
+        case 404:
+            return NOT_FOUND_ERR;
+        default:
+            return NOT_READABLE_ERR;
+    }
 }
 
 void FileReader::fireEvent(const AtomicString& type)
@@ -303,7 +299,7 @@ const ScriptString& FileReader::result()
         convertToText();
     // For data URL, we only do the coversion until we receive all the raw data.
     else if (m_readType == ReadFileAsDataURL && m_state == Completed)
-        convertToDataURL();
+        convertToDataURL(m_rawData, m_fileType, m_result);
 
     return m_result;
 }
@@ -328,22 +324,22 @@ void FileReader::convertToText()
         m_result += m_decoder->flush();
 }
 
-void FileReader::convertToDataURL()
+void FileReader::convertToDataURL(const Vector<char>& rawData, const String& fileType, ScriptString& result)
 {
-    m_result = "data:";
+    result = "data:";
 
-    if (!m_rawData.size())
+    if (!rawData.size())
         return;
 
-    m_result += m_fileType;
-    if (!m_fileType.isEmpty())
-        m_result += ";";
-    m_result += "base64,";
+    result += fileType;
+    if (!fileType.isEmpty())
+        result += ";";
+    result += "base64,";
 
     Vector<char> out;
-    base64Encode(m_rawData, out);
+    base64Encode(rawData, out);
     out.append('\0');
-    m_result += out.data();
+    result += out.data();
 }
 
 } // namespace WebCore
index ee15968a6bf735f3d55dc677f45f4e65190a8efb..48ce229215e0b4e848f0c80ae81e9ecff0e3ccdf 100644 (file)
 #include "ActiveDOMObject.h"
 #include "EventTarget.h"
 #include "FileError.h"
-#include "FileStreamClient.h"
 #include "PlatformString.h"
 #include "ScriptString.h"
 #include "TextEncoding.h"
+#include "ThreadableLoaderClient.h"
 #include <wtf/PassRefPtr.h>
 #include <wtf/RefCounted.h>
 #include <wtf/RefPtr.h>
 namespace WebCore {
 
 class Blob;
-class File;
-class FileStreamProxy;
 class ScriptExecutionContext;
 class TextResourceDecoder;
+class ThreadableLoader;
 
-class FileReader : public RefCounted<FileReader>, public ActiveDOMObject, public EventTarget, public FileStreamClient {
+class FileReader : public RefCounted<FileReader>, public ActiveDOMObject, public EventTarget, public ThreadableLoaderClient {
 public:
     static PassRefPtr<FileReader> create(ScriptExecutionContext* context)
     {
@@ -70,13 +69,19 @@ public:
 
     void readAsBinaryString(Blob*);
     void readAsText(Blob*, const String& encoding = "");
-    void readAsDataURL(File*);
+    void readAsDataURL(Blob*);
     void abort();
 
+    void start();
+
     ReadyState readyState() const;
     PassRefPtr<FileError> error() { return m_error; }
     const ScriptString& result();
 
+    // Helper methods, also used by FileReaderSync.
+    static ExceptionCode httpStatusCodeToExceptionCode(int httpStatusCode);
+    static void convertToDataURL(const Vector<char>& rawData, const String& fileType, ScriptString& result);
+
     // ActiveDOMObject
     virtual bool canSuspend() const;
     virtual void stop();
@@ -86,11 +91,11 @@ public:
     virtual FileReader* toFileReader() { return this; }
     virtual ScriptExecutionContext* scriptExecutionContext() const { return ActiveDOMObject::scriptExecutionContext(); }
 
-    // FileStreamClient
-    virtual void didStart();
-    virtual void didGetSize(long long);
-    virtual void didOpen(bool);
-    virtual void didRead(int);
+    // ThreadableLoaderClient
+    virtual void didReceiveResponse(const ResourceResponse&);
+    virtual void didReceiveData(const char*, int);
+    virtual void didFinishLoading(unsigned long identifier);
+    virtual void didFail(const ResourceError&);
 
     using RefCounted<FileReader>::ref;
     using RefCounted<FileReader>::deref;
@@ -126,16 +131,16 @@ private:
 
     void terminate();
     void readInternal(Blob*, ReadType);
+    void failed(int httpStatusCode);
+    void fireErrorEvent(int httpStatusCode);
     void fireEvent(const AtomicString& type);
     void convertToText();
     void convertToDataURL();
-    void didFinish();
-    void didFail(ExceptionCode);
 
     InternalState m_state;
     EventTargetData m_eventTargetData;
 
-    RefPtr<Blob> m_fileBlob;
+    RefPtr<Blob> m_blob;
     ReadType m_readType;
     TextEncoding m_encoding;
 
@@ -157,8 +162,7 @@ private:
     // Needed to create data URL.
     String m_fileType;
 
-    RefPtr<FileStreamProxy> m_streamProxy;
-    Vector<char> m_buffer;
+    RefPtr<ThreadableLoader> m_loader;
     RefPtr<FileError> m_error;
     long long m_bytesLoaded;
     long long m_totalBytes;
index 94d0031f7273c5b05dcdb0487998b440a8924eca..4503fd2f382e84961f2bc7aa1b793699682a2916 100644 (file)
@@ -33,20 +33,17 @@ FormDataList::FormDataList(const TextEncoding& c)
 void FormDataList::appendString(const String& s)
 {
     CString cstr = m_encoding.encode(s.characters(), s.length(), EntitiesForUnencodables);
-    m_items.append(StringBlobItem::create(normalizeLineEndingsToCRLF(cstr)));
+    m_items.append(normalizeLineEndingsToCRLF(cstr));
 }
 
 void FormDataList::appendString(const CString& s)
 {
-    m_items.append(StringBlobItem::create(s));
+    m_items.append(s);
 }
 
-void FormDataList::appendBlob(const String& key, PassRefPtr<Blob> blob)
+void FormDataList::appendBlob(PassRefPtr<Blob> blob)
 {
-    appendString(key);
-    const BlobItemList& items = blob->items();
-    for (size_t i = 0; i < items.size(); ++i)
-        m_items.append(items.at(i));
+    m_items.append(blob);
 }
 
 } // namespace
index 38b07f91081260e149643017006f85e268270b05..8e1a9378ee0161597052c70f9b1b1c8ddecb238d 100644 (file)
@@ -30,6 +30,20 @@ namespace WebCore {
 
 class FormDataList {
 public:
+    class Item {
+    public:
+        Item() { }
+        Item(const WTF::CString& data) : m_data(data) { }
+        Item(PassRefPtr<Blob> blob) : m_blob(blob) { }
+
+        const WTF::CString& data() const { return m_data; }
+        Blob* blob() const { return m_blob.get(); }
+
+    private:
+        WTF::CString m_data;
+        RefPtr<Blob> m_blob;
+    };
+
     FormDataList(const TextEncoding&);
 
     void appendData(const String& key, const String& value)
@@ -47,17 +61,22 @@ public:
         appendString(key);
         appendString(String::number(value));
     }
-    void appendBlob(const String& key, PassRefPtr<Blob>);
+    void appendBlob(const String& key, PassRefPtr<Blob> blob)
+    {
+        appendString(key);
+        appendBlob(blob);
+    }
 
-    const BlobItemList& items() const { return m_items; }
+    const Vector<Item>& items() const { return m_items; }
     const TextEncoding& encoding() const { return m_encoding; }
 
 private:
     void appendString(const CString&);
     void appendString(const String&);
+    void appendBlob(PassRefPtr<Blob>);
 
     TextEncoding m_encoding;
-    BlobItemList m_items;
+    Vector<Item> m_items;
 };
 
 } // namespace WebCore
index 22e89d7cd10603ae09ced75af361063f9940bee5..98a545e37013de05a887ca70491e72afc2b2ce7c 100644 (file)
@@ -162,10 +162,10 @@ PassRefPtr<FormSubmission> FormSubmission::create(HTMLFormElement* form, const A
     String boundary;
 
     if (isMultiPartForm) {
-        formData = FormData::createMultiPart(domFormData->items(), domFormData->encoding(), document);
+        formData = FormData::createMultiPart(*(static_cast<FormDataList*>(domFormData.get())), domFormData->encoding(), document);
         boundary = formData->boundary().data();
     } else {
-        formData = FormData::create(domFormData->items(), domFormData->encoding());
+        formData = FormData::create(*(static_cast<FormDataList*>(domFormData.get())), domFormData->encoding());
         if (attributes.method() == PostMethod && isMailtoForm) {
             // Convert the form data into a string that we put into the URL.
             appendMailtoPostFormDataToURL(actionURL, *formData, encodingType);
diff --git a/WebCore/platform/BlobItem.cpp b/WebCore/platform/BlobItem.cpp
deleted file mode 100644 (file)
index 591516d..0000000
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
- * Copyright (C) 2010 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "BlobItem.h"
-
-#include "FileSystem.h"
-#include "UUID.h"
-#include <wtf/Assertions.h>
-
-namespace WebCore {
-
-#if ENABLE(BLOB)
-static const double invalidModificationTime = 0;
-
-static double getFileSnapshotModificationTime(const String& path)
-{
-    // FIXME: synchronized file call
-    time_t modificationTime;
-    if (getFileModificationTime(path, modificationTime))
-        return static_cast<double>(modificationTime);
-    return invalidModificationTime;
-}
-#endif // ENABLE(BLOB)
-
-// DataBlobItem ----------------------------------------------------------------
-
-#if ENABLE(BLOB)
-PassRefPtr<BlobItem> DataBlobItem::slice(long long start, long long length)
-{
-    ASSERT(start >= 0 && length >= 0);
-    ASSERT(static_cast<unsigned long long>(start) < size());
-    if (!start && size() <= static_cast<unsigned long long>(length))
-        return this;
-    if (static_cast<unsigned long long>(start + length) > size())
-        length = size() - start;
-    return DataRangeBlobItem::create(this, start, length);
-}
-#endif
-
-// FileBlobItem ----------------------------------------------------------------
-
-PassRefPtr<BlobItem> FileBlobItem::create(const String& path)
-{
-    return adoptRef(static_cast<BlobItem*>(new FileBlobItem(path)));
-}
-
-FileBlobItem::FileBlobItem(const String& path)
-    : m_path(path)
-    , m_fileName(pathGetFileName(m_path))
-{
-}
-
-#if ENABLE(DIRECTORY_UPLOAD)
-PassRefPtr<BlobItem> FileBlobItem::create(const String& path, const String& relativePath)
-{
-    return adoptRef(static_cast<BlobItem*>(new FileBlobItem(path, relativePath)));
-}
-
-FileBlobItem::FileBlobItem(const String& path, const String& relativePath)
-    : m_path(path)
-    , m_fileName(pathGetFileName(m_path))
-    , m_relativePath(relativePath)
-{
-}
-#endif
-
-unsigned long long FileBlobItem::size() const
-{
-    // FIXME: synchronized file call
-    long long size;
-    if (!getFileSize(m_path, size))
-        return 0;
-    return static_cast<unsigned long long>(size);
-}
-
-#if ENABLE(BLOB)
-PassRefPtr<BlobItem> FileBlobItem::slice(long long start, long long length)
-{
-    ASSERT(start >= 0 && length >= 0);
-    long long fileSize = size();
-    ASSERT(start < fileSize);
-    if (!start && fileSize <= length)
-        return this;
-    if (start + length > fileSize)
-        length = fileSize - start;
-    const FileRangeBlobItem* fileRangeItem = toFileRangeBlobItem();
-    double modificationTime = fileRangeItem ? fileRangeItem->snapshotModificationTime() : getFileSnapshotModificationTime(path());
-    return FileRangeBlobItem::create(path(), start, length, modificationTime);
-}
-#endif // ENABLE(BLOB)
-
-// StringBlobItem --------------------------------------------------------------
-
-PassRefPtr<BlobItem> StringBlobItem::create(const CString& text)
-{
-    return adoptRef(static_cast<BlobItem*>(new StringBlobItem(text)));
-}
-
-StringBlobItem::StringBlobItem(const CString& text)
-    : m_data(text)
-{
-}
-
-// ByteArrayBlobItem ----------------------------------------------------------
-
-PassRefPtr<BlobItem> ByteArrayBlobItem::create(const char* data, size_t size)
-{
-    return adoptRef(static_cast<BlobItem*>(new ByteArrayBlobItem(data, size)));
-}
-
-ByteArrayBlobItem::ByteArrayBlobItem(const char* data, size_t size)
-{
-    m_bytesArray.append(data, size);
-}
-
-#if ENABLE(BLOB)
-
-// DataRangeBlobItem -----------------------------------------------------------
-
-PassRefPtr<BlobItem> DataRangeBlobItem::create(PassRefPtr<DataBlobItem> item, long long start, long long length)
-{
-    return adoptRef(static_cast<BlobItem*>(new DataRangeBlobItem(item, start, length)));
-}
-
-DataRangeBlobItem::DataRangeBlobItem(PassRefPtr<DataBlobItem> item, long long start, long long length)
-    : m_length(length)
-{
-    const DataRangeBlobItem* rangeItem = item->toDataRangeBlobItem();
-    if (rangeItem) {
-        m_item = rangeItem->m_item;
-        m_start = start + rangeItem->m_start;
-        ASSERT(!m_item->toDataRangeBlobItem());
-        ASSERT(static_cast<unsigned long long>(m_start + m_length) <= m_item->size());
-    } else {
-        m_item = item;
-        m_start = start;
-    }
-}
-
-const char* DataRangeBlobItem::data() const
-{
-    return m_item->data() + m_start;
-}
-
-// FileRangeBlobItem -----------------------------------------------------------
-
-PassRefPtr<BlobItem> FileRangeBlobItem::create(const String& path, long long start, long long length, double snapshotModificationTime)
-{
-    return adoptRef(static_cast<BlobItem*>(new FileRangeBlobItem(path, start, length, snapshotModificationTime)));
-}
-
-FileRangeBlobItem::FileRangeBlobItem(const String& path, long long start, long long length, double modificationTime)
-    : FileBlobItem(path)
-    , m_start(start)
-    , m_length(length)
-    , m_snapshotModificationTime(modificationTime)
-{
-    m_uniqueName = "Blob" + createCanonicalUUIDString();
-    m_uniqueName.replace("-", ""); // For safty, remove '-' from the filename snce some servers may not like it.
-}
-
-#endif // ENABLE(BLOB)
-
-} // namespace WebCore
diff --git a/WebCore/platform/BlobItem.h b/WebCore/platform/BlobItem.h
deleted file mode 100644 (file)
index 42ece92..0000000
+++ /dev/null
@@ -1,209 +0,0 @@
-/*
- * Copyright (C) 2010 Google Inc.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef BlobItem_h
-#define BlobItem_h
-
-#include "PlatformString.h"
-#include <wtf/OwnPtr.h>
-#include <wtf/PassRefPtr.h>
-#include <wtf/RefCounted.h>
-#include <wtf/Vector.h>
-#include <wtf/text/CString.h>
-
-namespace WebCore {
-
-class ByteArrayBlobItem;
-class DataBlobItem;
-class DataRangeBlobItem;
-class FileBlobItem;
-class FileRangeBlobItem;
-class StringBlobItem;
-
-// A base interface for all arbitrary-data-object component items.
-// The BlobItem and its subclasses are structured like the following:
-//    BlobItem
-//       |
-//       +-------> DataBlobItem
-//       |              |
-//       |              +---------> StringBlobItem
-//       |              +---------> ByteArrayBlobItem
-//       |              +---------> DataRangeBlobItem
-//       |
-//       +-------> FileBlobItem
-//                      |
-//                      +---------> FileRangeBlobItem
-//
-class BlobItem : public RefCounted<BlobItem> {
-public:
-    virtual ~BlobItem() { }
-    virtual unsigned long long size() const = 0;
-
-    virtual const DataBlobItem* toDataBlobItem() const { return 0; }
-    virtual const StringBlobItem* toStringBlobItem() const { return 0; }
-    virtual const ByteArrayBlobItem* toByteArrayBlobItem() const { return 0; }
-    virtual const FileBlobItem* toFileBlobItem() const { return 0; }
-#if ENABLE(BLOB)
-    virtual const DataRangeBlobItem* toDataRangeBlobItem() const { return 0; }
-    virtual const FileRangeBlobItem* toFileRangeBlobItem() const { return 0; }
-
-    // Note: no external methods except for Blob::slice should call this.
-    virtual PassRefPtr<BlobItem> slice(long long start, long long length) = 0;
-#endif // ENABLE(BLOB)
-
-protected:
-    BlobItem() { }
-};
-
-typedef Vector<RefPtr<BlobItem> > BlobItemList;
-
-class DataBlobItem : public BlobItem {
-public:
-    virtual const char* data() const = 0;
-
-    // BlobItem methods.
-    virtual const DataBlobItem* toDataBlobItem() const { return this; }
-#if ENABLE(BLOB)
-    virtual PassRefPtr<BlobItem> slice(long long start, long long length);
-#endif // ENABLE(BLOB)
-};
-
-class FileBlobItem : public BlobItem {
-public:
-    static PassRefPtr<BlobItem> create(const String& path);
-#if ENABLE(DIRECTORY_UPLOAD)
-    static PassRefPtr<BlobItem> create(const String& path, const String& relativePath);
-#endif
-    virtual const String& name() const { return m_fileName; }
-    virtual const String& path() const { return m_path; }
-#if ENABLE(DIRECTORY_UPLOAD)
-    const String& relativePath() const { return m_relativePath; }
-#endif
-
-    // BlobItem methods.
-    virtual unsigned long long size() const;
-    virtual const FileBlobItem* toFileBlobItem() const { return this; }
-#if ENABLE(BLOB)
-    virtual PassRefPtr<BlobItem> slice(long long start, long long length);
-#endif // ENABLE(BLOB)
-
-protected:
-    FileBlobItem(const String& path);
-#if ENABLE(DIRECTORY_UPLOAD)
-    FileBlobItem(const String& path, const String& relativePath);
-#endif
-    String m_path;
-    String m_fileName;
-#if ENABLE(DIRECTORY_UPLOAD)
-    String m_relativePath;
-#endif
-};
-
-class StringBlobItem : public DataBlobItem {
-public:
-    static PassRefPtr<BlobItem> create(const CString&);
-    const CString& cstr() const { return m_data; }
-
-    // BlobItem methods.
-    virtual unsigned long long size() const { return m_data.length(); }
-    virtual const StringBlobItem* toStringBlobItem() const { return this; }
-
-    // DataBlobItem methods.
-    virtual const char* data() const { return m_data.data(); }
-
-private:
-    StringBlobItem(const CString&);
-    CString m_data;
-};
-
-class ByteArrayBlobItem : public DataBlobItem {
-public:
-    static PassRefPtr<BlobItem> create(const char* data, size_t size);
-
-    // BlobItem methods.
-    virtual unsigned long long size() const { return m_bytesArray.size(); }
-    virtual const ByteArrayBlobItem* toByteArrayBlobItem() const { return this; }
-
-    // DataBlobItem methods.
-    virtual const char* data() const { return m_bytesArray.data(); }
-
-private:
-    ByteArrayBlobItem(const char* data, size_t size);
-    Vector<char> m_bytesArray;
-};
-
-#if ENABLE(BLOB)
-
-// BlobItem class for sliced data (string or bytes-array).
-class DataRangeBlobItem : public DataBlobItem {
-public:
-    static PassRefPtr<BlobItem> create(PassRefPtr<DataBlobItem>, long long start, long long length);
-
-    // BlobItem methods.
-    virtual unsigned long long size() const { return m_length; }
-    virtual const DataRangeBlobItem* toDataRangeBlobItem() const { return this; }
-
-    // DataBlobItem methods.
-    virtual const char* data() const;
-
-private:
-    DataRangeBlobItem(PassRefPtr<DataBlobItem>, long long start, long long length);
-    RefPtr<DataBlobItem> m_item;
-    long long m_start;
-    long long m_length;
-};
-
-class FileRangeBlobItem : public FileBlobItem {
-public:
-    static PassRefPtr<BlobItem> create(const String& path, long long start, long long length, double snapshotModificationTime);
-    long long start() const { return m_start; }
-    double snapshotModificationTime() const { return m_snapshotModificationTime; }
-
-    // BlobItem methods.
-    virtual unsigned long long size() const { return m_length; }
-    virtual const FileRangeBlobItem* toFileRangeBlobItem() const { return this; }
-
-    // FileBlobItem methods.
-    virtual const String& name() const { return m_uniqueName; }
-
-private:
-    FileRangeBlobItem(const String& path, long long start, long long length, double snapshotModificationTime);
-    long long m_start;
-    long long m_length;
-    String m_uniqueName;
-
-    double m_snapshotModificationTime;
-};
-
-#endif // ENABLE(BLOB)
-
-} // namespace WebCore
-
-#endif // BlobItem_h
index ee872e6c47ee76fff79ad28c8e593117478dc75e..fe1b09fe741eb077f3d4344a155dec3ad473984a 100644 (file)
@@ -32,6 +32,7 @@
 
 #include "BlobRegistryImpl.h"
 
+#include "BlobResourceHandle.h"
 #include "ResourceError.h"
 #include "ResourceHandle.h"
 #include "ResourceLoader.h"
@@ -60,22 +61,21 @@ bool BlobRegistryImpl::shouldLoadResource(const ResourceRequest& request) const
     return true;
 }
 
-PassRefPtr<ResourceHandle> BlobRegistryImpl::createResourceHandle(const ResourceRequest& request, ResourceHandleClient*)
+PassRefPtr<ResourceHandle> BlobRegistryImpl::createResourceHandle(const ResourceRequest& request, ResourceHandleClient* client)
 {
     if (!shouldLoadResource(request))
         return 0;
 
-    // FIXME: To be implemented.
-    return 0;
+    return BlobResourceHandle::create(m_blobs.get(request.url().string()), request, client);
 }
 
-bool BlobRegistryImpl::loadResourceSynchronously(const ResourceRequest& request, ResourceError&, ResourceResponse&, Vector<char>&)
+bool BlobRegistryImpl::loadResourceSynchronously(const ResourceRequest& request, ResourceError& error, ResourceResponse& response, Vector<char>& data)
 {
     if (!shouldLoadResource(request))
         return false;
 
-    // FIXME: To be implemented.
-    return false;
+    BlobResourceHandle::loadResourceSynchronously(m_blobs.get(request.url().string()), request, error, response, data);
+    return true;
 }
 
 void BlobRegistryImpl::appendStorageItems(BlobStorageData* blobStorageData, const BlobDataItemList& items)
index 63335f6382e152b24d66f63ac07e044cb92770c2..8767b558fc1442e379d16b83e01657d0e0e9b285 100644 (file)
@@ -159,7 +159,8 @@ BlobResourceHandle::BlobResourceHandle(PassRefPtr<BlobStorageData> blobData, con
     , m_fileOpened(false)
 {    
     if (m_async) {
-        m_asyncStream = adoptRef(client->createAsyncFileStream(this));
+        // We need to take a ref.
+        m_asyncStream = client->createAsyncFileStream(this);
         callOnMainThread(delayedStart, this);
     } else
         m_stream = FileStream::create();
index 4f2b3656f480202e4a2ef6debffe1160e5d2ca89..786f1b6365d001595b21399f5b52a36085a0c374 100644 (file)
 
 #include "FormData.h"
 
-#include "BlobItem.h"
+#include "BlobData.h"
+#include "BlobURL.h"
 #include "Chrome.h"
 #include "ChromeClient.h"
 #include "Document.h"
+#include "File.h"
 #include "FileSystem.h"
 #include "FormDataBuilder.h"
+#include "FormDataList.h"
 #include "MIMETypeRegistry.h"
 #include "Page.h"
 #include "TextEncoding.h"
 
 namespace WebCore {
 
-#if ENABLE(BLOB)
-const long long FormDataElement::toEndOfFile = -1;
-const double FormDataElement::doNotCheckFileChange = 0;
-#endif
-
 inline FormData::FormData()
     : m_identifier(0)
     , m_hasGeneratedFiles(false)
@@ -99,17 +97,17 @@ PassRefPtr<FormData> FormData::create(const Vector<char>& vector)
     return result.release();
 }
 
-PassRefPtr<FormData> FormData::create(const BlobItemList& items, const TextEncoding& encoding)
+PassRefPtr<FormData> FormData::create(const FormDataList& list, const TextEncoding& encoding)
 {
     RefPtr<FormData> result = create();
-    result->appendKeyValuePairItems(items, encoding, false, 0);
+    result->appendKeyValuePairItems(list, encoding, false, 0);
     return result.release();
 }
 
-PassRefPtr<FormData> FormData::createMultiPart(const BlobItemList& items, const TextEncoding& encoding, Document* document)
+PassRefPtr<FormData> FormData::createMultiPart(const FormDataList& list, const TextEncoding& encoding, Document* document)
 {
     RefPtr<FormData> result = create();
-    result->appendKeyValuePairItems(items, encoding, true, document);
+    result->appendKeyValuePairItems(list, encoding, true, document);
     return result.release();
 }
 
@@ -162,44 +160,12 @@ void FormData::appendData(const void* data, size_t size)
 void FormData::appendFile(const String& filename, bool shouldGenerateFile)
 {
 #if ENABLE(BLOB)
-    m_elements.append(FormDataElement(filename, 0, FormDataElement::toEndOfFile, FormDataElement::doNotCheckFileChange, shouldGenerateFile));
+    m_elements.append(FormDataElement(filename, 0, BlobDataItem::toEndOfFile, BlobDataItem::doNotCheckFileChange, shouldGenerateFile));
 #else
     m_elements.append(FormDataElement(filename, shouldGenerateFile));
 #endif
 }
 
-void FormData::appendItems(const BlobItemList& items)
-{
-    for (BlobItemList::const_iterator iter(items.begin()); iter != items.end(); ++iter)
-        appendItem(iter->get(), false);
-}
-
-void FormData::appendItem(const BlobItem* item, bool shouldGenerateFile)
-{
-    const DataBlobItem* dataItem = item->toDataBlobItem();
-    if (dataItem) {
-        appendData(dataItem->data(), static_cast<size_t>(dataItem->size()));
-        return;
-    }
-
-    const FileBlobItem* fileItem = item->toFileBlobItem();
-    ASSERT(fileItem);
-    if (fileItem->path().isEmpty()) {
-        // If the path is empty do not add the item.
-        return;
-    }
-
-#if ENABLE(BLOB)
-    const FileRangeBlobItem* fileRangeItem = item->toFileRangeBlobItem();
-    if (fileRangeItem) {
-        appendFileRange(fileItem->path(), fileRangeItem->start(), fileRangeItem->size(), fileRangeItem->snapshotModificationTime(), shouldGenerateFile);
-        return;
-    }
-#endif
-
-    appendFile(fileItem->path(), shouldGenerateFile);
-}
-
 #if ENABLE(BLOB)
 void FormData::appendFileRange(const String& filename, long long start, long long length, double expectedModificationTime, bool shouldGenerateFile)
 {
@@ -212,80 +178,82 @@ void FormData::appendBlob(const KURL& blobURL)
 }
 #endif
 
-void FormData::appendKeyValuePairItems(const BlobItemList& items, const TextEncoding& encoding, bool isMultiPartForm, Document* document)
+void FormData::appendKeyValuePairItems(const FormDataList& list, const TextEncoding& encoding, bool isMultiPartForm, Document* document)
 {
     if (isMultiPartForm)
         m_boundary = FormDataBuilder::generateUniqueBoundaryString();
 
     Vector<char> encodedData;
 
+    const Vector<FormDataList::Item>& items = list.items();
     size_t formDataListSize = items.size();
     ASSERT(!(formDataListSize % 2));
     for (size_t i = 0; i < formDataListSize; i += 2) {
-        const StringBlobItem* key = items[i]->toStringBlobItem();
-        const BlobItem* value = items[i + 1].get();
-        ASSERT(key);
+        const FormDataList::Item& key = items[i];
+        const FormDataList::Item& value = items[i + 1];
         if (isMultiPartForm) {
             Vector<char> header;
-            FormDataBuilder::beginMultiPartHeader(header, m_boundary.data(), key->cstr());
+            FormDataBuilder::beginMultiPartHeader(header, m_boundary.data(), key.data());
 
             bool shouldGenerateFile = false;
-            // If the current type is FILE, then we also need to include the filename
-            const FileBlobItem* fileItem = value->toFileBlobItem();
-            if (fileItem) {
-                const String& path = fileItem->path();
 
-#if ENABLE(DIRECTORY_UPLOAD)
-                String fileName = !fileItem->relativePath().isEmpty() ? fileItem->relativePath() : fileItem->name();
+            // If the current type is blob, then we also need to include the filename
+            if (value.blob()) {
+                String name;
+                if (value.blob()->isFile()) {
+                    // For file blob, use the filename (or relative path if it is present) as the name.
+                    File* file = static_cast<File*>(value.blob());
+#if ENABLE(DIRECTORY_UPLOAD)                
+                    name = file->webkitRelativePath().isEmpty() ? file->name() : file->webkitRelativePath();
 #else
-                String fileName = fileItem->name();
-#endif
+                    name = file->name();
+#endif                    
 
-                // Let the application specify a filename if it's going to generate a replacement file for the upload.
-                if (!path.isEmpty()) {
+                    // Let the application specify a filename if it's going to generate a replacement file for the upload.
                     if (Page* page = document->page()) {
                         String generatedFileName;
-                        shouldGenerateFile = page->chrome()->client()->shouldReplaceWithGeneratedFileForUpload(path, generatedFileName);
+                        shouldGenerateFile = page->chrome()->client()->shouldReplaceWithGeneratedFileForUpload(file->path(), generatedFileName);
                         if (shouldGenerateFile)
-                            fileName = generatedFileName;
+                            name = generatedFileName;
                     }
+                } else {
+                    // For non-file blob, use the identifier part of the URL as the name.
+                    name = "Blob" + BlobURL::getIdentifier(value.blob()->url());
+                    name = name.replace("-", ""); // For safety, remove '-' from the filename since some servers may not like it.
                 }
 
                 // We have to include the filename=".." part in the header, even if the filename is empty
-                FormDataBuilder::addFilenameToMultiPartHeader(header, encoding, fileName);
+                FormDataBuilder::addFilenameToMultiPartHeader(header, encoding, name);
 
-                // If the item is sliced from a file, do not add the content type.
-#if ENABLE(BLOB)
-                if (!fileName.isEmpty() && !value->toFileRangeBlobItem()) {
-#else
-                if (!fileName.isEmpty()) {
-#endif
-                    // FIXME: The MIMETypeRegistry function's name makes it sound like it takes a path,
-                    // not just a basename. But filename is not the path. But note that it's not safe to
-                    // just use path instead since in the generated-file case it will not reflect the
-                    // MIME type of the generated file.
-                    String mimeType = MIMETypeRegistry::getMIMETypeForPath(fileName);
-                    if (!mimeType.isEmpty())
-                        FormDataBuilder::addContentTypeToMultiPartHeader(header, mimeType.latin1());
-                }
+                // Add the content type if it is available.
+                if (value.blob()->type().isEmpty())
+                    FormDataBuilder::addContentTypeToMultiPartHeader(header, value.blob()->type().latin1());
             }
 
             FormDataBuilder::finishMultiPartHeader(header);
 
             // Append body
             appendData(header.data(), header.size());
-            appendItem(value, shouldGenerateFile);
+            if (value.blob()) {
+                if (value.blob()->isFile()) {
+                    // Do not add the file if the path is empty.
+                    if (!static_cast<File*>(value.blob())->path().isEmpty())
+                        appendFile(static_cast<File*>(value.blob())->path(), shouldGenerateFile);
+                }
+#if ENABLE(BLOB)
+                else
+                    appendBlob(value.blob()->url());
+#endif
+            } else
+                appendData(value.data().data(), value.data().length());
             appendData("\r\n", 2);
         } else {
             // Omit the name "isindex" if it's the first form data element.
             // FIXME: Why is this a good rule? Is this obsolete now?
-            const StringBlobItem* stringValue = value->toStringBlobItem();
-            if (!stringValue)
-                continue;
-            if (encodedData.isEmpty() && key->cstr() == "isindex")
-                FormDataBuilder::encodeStringAsFormData(encodedData, stringValue->cstr());
+            if (encodedData.isEmpty() && key.data() == "isindex")
+                FormDataBuilder::encodeStringAsFormData(encodedData, value.data());
             else
-                FormDataBuilder::addKeyValuePairAsFormData(encodedData, key->cstr(), stringValue->cstr());
+                FormDataBuilder::addKeyValuePairAsFormData(encodedData, key.data(), value.data());
         }
     }
 
index d7faa8987e00e70133a0c88bd23ed82b84e9200e..22ceb253f3c13e65348a6bae76e3855c9d032834 100644 (file)
 
 namespace WebCore {
 
-class BlobItem;
 class Document;
+class FormDataList;
 class TextEncoding;
-typedef Vector<RefPtr<BlobItem> > BlobItemList;
 
 class FormDataElement {
 public:
@@ -62,11 +61,6 @@ public:
 #endif
     String m_generatedFilename;
     bool m_shouldGenerateFile;
-
-#if ENABLE(BLOB)
-    static const long long toEndOfFile;
-    static const double doNotCheckFileChange;
-#endif
 };
 
 inline bool operator==(const FormDataElement& a, const FormDataElement& b)
@@ -101,15 +95,14 @@ public:
     static PassRefPtr<FormData> create(const void*, size_t);
     static PassRefPtr<FormData> create(const CString&);
     static PassRefPtr<FormData> create(const Vector<char>&);
-    static PassRefPtr<FormData> create(const BlobItemList&, const TextEncoding&);
-    static PassRefPtr<FormData> createMultiPart(const BlobItemList&, const TextEncoding&, Document*);
+    static PassRefPtr<FormData> create(const FormDataList&, const TextEncoding&);
+    static PassRefPtr<FormData> createMultiPart(const FormDataList&, const TextEncoding&, Document*);
     PassRefPtr<FormData> copy() const;
     PassRefPtr<FormData> deepCopy() const;
     ~FormData();
 
     void appendData(const void* data, size_t);
-    void appendItems(const BlobItemList&);
-    void appendFile(const String& filename, bool shouldGenerateFile = false);
+    void appendFile(const String& filePath, bool shouldGenerateFile = false);
 #if ENABLE(BLOB)
     void appendFileRange(const String& filename, long long start, long long length, double expectedModificationTime, bool shouldGenerateFile = false);
     void appendBlob(const KURL& blobURL);
@@ -137,8 +130,7 @@ private:
     FormData();
     FormData(const FormData&);
 
-    void appendItem(const BlobItem*, bool shouldGenerateFile);
-    void appendKeyValuePairItems(const BlobItemList&, const TextEncoding&, bool isMultiPartForm, Document*);
+    void appendKeyValuePairItems(const FormDataList&, const TextEncoding&, bool isMultiPartForm, Document*);
 
     Vector<FormDataElement> m_elements;
 
index c7bd2e749d9dec9e9b0afcf67915e922c9acc071..ed983566e8795ec26124dd3615195e3764b7379e 100644 (file)
@@ -31,6 +31,7 @@
 #import "config.h"
 #import "FormDataStreamMac.h"
 
+#import "BlobRegistryImpl.h"
 #import "FileSystem.h"
 #import "FormData.h"
 #import "ResourceHandle.h"
@@ -141,7 +142,7 @@ static void closeCurrentStream(FormStreamFields *form)
         CFRelease(form->currentStream);
         form->currentStream = NULL;
 #if ENABLE(BLOB)
-        form->currentStreamRangeLength = FormDataElement::toEndOfFile;
+        form->currentStreamRangeLength = BlobDataItem::toEndOfFile;
 #endif
     }
     if (form->currentData) {
@@ -169,7 +170,7 @@ static bool advanceCurrentStream(FormStreamFields* form)
     } else {
 #if ENABLE(BLOB)
         // Check if the file has been changed or not if required.
-        if (nextInput.m_expectedFileModificationTime != FormDataElement::doNotCheckFileChange) {
+        if (nextInput.m_expectedFileModificationTime != BlobDataItem::doNotCheckFileChange) {
             time_t fileModificationTime;
             if (!getFileModificationTime(nextInput.m_filename, fileModificationTime) || fileModificationTime != static_cast<time_t>(nextInput.m_expectedFileModificationTime))
                 return false;
@@ -225,7 +226,7 @@ static void* formCreate(CFReadStreamRef stream, void* context)
     FormStreamFields* newInfo = new FormStreamFields;
     newInfo->currentStream = NULL;
 #if ENABLE(BLOB)
-    newInfo->currentStreamRangeLength = FormDataElement::toEndOfFile;
+    newInfo->currentStreamRangeLength = BlobDataItem::toEndOfFile;
 #endif
     newInfo->currentData = 0;
     newInfo->formStream = stream; // Don't retain. That would create a reference cycle.
@@ -273,7 +274,7 @@ static CFIndex formRead(CFReadStreamRef stream, UInt8* buffer, CFIndex bufferLen
     while (form->currentStream) {
         CFIndex bytesToRead = bufferLength;
 #if ENABLE(BLOB)
-        if (form->currentStreamRangeLength != FormDataElement::toEndOfFile && form->currentStreamRangeLength < bytesToRead)
+        if (form->currentStreamRangeLength != BlobDataItem::toEndOfFile && form->currentStreamRangeLength < bytesToRead)
             bytesToRead = static_cast<CFIndex>(form->currentStreamRangeLength);
 #endif
         CFIndex bytesRead = CFReadStreamRead(form->currentStream, buffer, bytesToRead);
@@ -286,7 +287,7 @@ static CFIndex formRead(CFReadStreamRef stream, UInt8* buffer, CFIndex bufferLen
             *atEOF = FALSE;
             form->bytesSent += bytesRead;
 #if ENABLE(BLOB)
-            if (form->currentStreamRangeLength != FormDataElement::toEndOfFile)
+            if (form->currentStreamRangeLength != BlobDataItem::toEndOfFile)
                 form->currentStreamRangeLength -= bytesRead;
 #endif
 
@@ -394,6 +395,49 @@ void setHTTPBody(NSMutableURLRequest *request, PassRefPtr<FormData> formData)
         }
     }
 
+#if ENABLE(BLOB)
+    // Check if there is a blob in the form data.
+    bool hasBlob = false;
+    for (size_t i = 0; i < count; ++i) {
+        const FormDataElement& element = formData->elements()[i];
+        if (element.m_type == FormDataElement::encodedBlob) {
+            hasBlob = true;
+            break;
+        }
+    }
+
+    // If yes, we have to resolve all the blob references and regenerate the form data with only data and file types.
+    if (hasBlob) {
+        RefPtr<FormData> newFormData = FormData::create();
+        newFormData->setAlwaysStream(formData->alwaysStream());
+        newFormData->setIdentifier(formData->identifier());
+        for (size_t i = 0; i < count; ++i) {
+            const FormDataElement& element = formData->elements()[i];
+            if (element.m_type == FormDataElement::data)
+                newFormData->appendData(element.m_data.data(), element.m_data.size());
+            else if (element.m_type == FormDataElement::encodedFile)
+                newFormData->appendFile(element.m_filename, element.m_shouldGenerateFile);
+            else {
+                ASSERT(element.m_type == FormDataElement::encodedBlob);
+                RefPtr<BlobStorageData> blobData = static_cast<BlobRegistryImpl&>(blobRegistry()).getBlobDataFromURL(KURL(ParsedURLString, element.m_blobURL));
+                if (blobData) {
+                    for (size_t j = 0; j < blobData->items().size(); ++j) {
+                        const BlobDataItem& blobItem = blobData->items()[j];
+                        if (blobItem.type == BlobDataItem::Data) {
+                            newFormData->appendData(blobItem.data.data() + static_cast<int>(blobItem.offset), static_cast<int>(blobItem.length));
+                        } else {
+                            ASSERT(blobItem.type == BlobDataItem::File);
+                            newFormData->appendFileRange(blobItem.path, blobItem.offset, blobItem.length, blobItem.expectedModificationTime);
+                        }
+                    }
+                }
+            }
+        }
+        formData = newFormData;
+        count = formData->elements().size();
+    }
+#endif
+
     // Precompute the content length so NSURLConnection doesn't use chunked mode.
     long long length = 0;
     for (size_t i = 0; i < count; ++i) {
@@ -403,7 +447,7 @@ void setHTTPBody(NSMutableURLRequest *request, PassRefPtr<FormData> formData)
         else {
 #if ENABLE(BLOB)
             // If we're sending the file range, use the existing range length for now. We will detect if the file has been changed right before we read the file and abort the operation if necessary.
-            if (element.m_fileLength != FormDataElement::toEndOfFile) {
+            if (element.m_fileLength != BlobDataItem::toEndOfFile) {
                 length += element.m_fileLength;
                 continue;
             }
index c12dc168012e1b1921128eab6fda3fcf91b88f63..f3b8d64652be473ff74eb7979886ccfa2a706fb7 100644 (file)
@@ -522,7 +522,7 @@ void XMLHttpRequest::send(Blob* body, ExceptionCode& ec)
         // FIXME: Should we set a Content-Type if one is not set.
         // FIXME: add support for uploading bundles.
         m_requestEntityBody = FormData::create();
-        m_requestEntityBody->appendItems(body->items());
+        m_requestEntityBody->appendBlob(body->url());
     }
 
     createRequest(ec);
@@ -534,7 +534,7 @@ void XMLHttpRequest::send(DOMFormData* body, ExceptionCode& ec)
         return;
 
     if (m_method != "GET" && m_method != "HEAD" && m_url.protocolInHTTPFamily()) {
-        m_requestEntityBody = FormData::createMultiPart(body->items(), body->encoding(), document());
+        m_requestEntityBody = FormData::createMultiPart(*(static_cast<FormDataList*>(body)), body->encoding(), document());
 
         // We need to ask the client to provide the generated file names if needed. When FormData fills the element
         // for the file, it could set a flag to use the generated file name, i.e. a package file on Mac.
index 21454e82d961820f1bed191deb4bbbe6cfd7e0b2..fe8935d1420d38d7e1d2809a4763ad4b170fec5e 100644 (file)
@@ -1,3 +1,13 @@
+2010-08-31  Jian Li  <jianli@chromium.org>
+
+        Reviewed by Darin Fisher.
+
+        Switch the Blob implementation to using the blob data registration model
+        https://bugs.webkit.org/show_bug.cgi?id=44389
+
+        * src/WebSearchableFormData.cpp:
+        (WebCore::HasSuitableTextElement):
+
 2010-08-30  Nat Duca  <nduca@chromium.org>
 
         Reviewed by Adam Barth.
index 14ece133aeadb5cc6286c0e3a68827b050367eb4..1864514998ea3f65d3affa2822ad7b86f460ca0f 100644 (file)
@@ -187,7 +187,7 @@ bool HasSuitableTextElement(const HTMLFormElement* form, Vector<char>* encodedSt
       if (!formElement->appendFormData(dataList, false))
           continue;
 
-      const BlobItemList& items = dataList.items();
+      const Vector<FormDataList::Item>& items = dataList.items();
       if (isTextElement && !items.isEmpty()) {
           if (textElement) {
               // The auto-complete bar only knows how to fill in one value.
@@ -196,22 +196,20 @@ bool HasSuitableTextElement(const HTMLFormElement* form, Vector<char>* encodedSt
           }
           textElement = static_cast<HTMLInputElement*>(formElement);
       }
-      for (BlobItemList::const_iterator j(items.begin()); j != items.end(); ++j) {
-          const StringBlobItem* item = (*j)->toStringBlobItem();
-          ASSERT(item);
+      for (Vector<FormDataList::Item>::const_iterator j(items.begin()); j != items.end(); ++j) {
           // Handle ISINDEX / <input name=isindex> specially, but only if it's
           // the first entry.
-          if (!encodedString->isEmpty() || item->cstr() != "isindex") {
+          if (!encodedString->isEmpty() || j->data() != "isindex") {
               if (!encodedString->isEmpty())
                   encodedString->append('&');
-              FormDataBuilder::encodeStringAsFormData(*encodedString, item->cstr());
+              FormDataBuilder::encodeStringAsFormData(*encodedString, j->data());
               encodedString->append('=');
           }
           ++j;
           if (formElement == textElement)
               encodedString->append("{searchTerms}", 13);
           else
-              FormDataBuilder::encodeStringAsFormData(*encodedString, item->cstr());
+              FormDataBuilder::encodeStringAsFormData(*encodedString, j->data());
       }
     }