Changeset 66452 in webkit
- Timestamp:
- Aug 30, 2010 9:45:21 PM (14 years ago)
- Location:
- trunk
- Files:
-
- 8 added
- 3 deleted
- 33 edited
- 1 copied
- 1 moved
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r66449 r66452 1 2010-08-30 Jian Li <jianli@chromium.org> 2 3 Reviewed by Darin Fisher. 4 5 Switch the Blob implementation to using the blob data registration model 6 https://bugs.webkit.org/show_bug.cgi?id=44389 7 8 Add a new test and change an existing test. Both tests are written in 9 better organized utility files and modules. 10 11 * fast/files/file-reader-expected.txt: Removed. 12 * fast/files/file-reader.html: Removed. 13 * fast/files/read-blob-async-expected.txt: Added. 14 * fast/files/read-blob-async.html: Added. 15 * fast/files/read-file-async-expected.txt: Added. 16 * fast/files/read-file-async.html: Added. 17 * fast/files/resources/UTF8-2.txt: Added. 18 * fast/files/resources/UTF8-3.txt: Added. 19 * fast/files/resources/read-blob-test-cases.js: Added. 20 * fast/files/resources/read-common.js: Added. 21 * fast/files/resources/read-file-test-cases.js: Added. 22 * fast/files/resources/setup-for-read-common.js: Added. 23 * platform/gtk/Skipped: Account to the test changes for gtk. 24 * platform/mac-wk2/Skipped: Account to the test changes for mac-wk2. 25 * platform/qt/Skipped: Account to the test changes for qt. 26 * platform/win/Skipped: Account to the test changes for win. 27 1 28 2010-08-30 Eric Seidel <eric@webkit.org> 2 29 -
trunk/LayoutTests/fast/files/read-blob-async-expected.txt
r66450 r66452 1 1 2 Test reading a non-existent file2 Test reading a blob containing non-existent file 3 3 readyState: 0 4 4 Received error event … … 6 6 error code: 8 7 7 Received loadend event 8 Test reading an empty file as binary string 8 Test reading a blob containing existent and non-existent file 9 readyState: 0 10 Received error event 11 readyState: 2 12 error code: 8 13 Received loadend event 14 Test reading a blob containing empty file 9 15 readyState: 0 10 16 Received loadstart event … … 15 21 result: 16 22 Received loadend event 17 Test reading a n empty file astext23 Test reading a blob containing empty text 18 24 readyState: 0 19 25 Received loadstart event … … 24 30 result: 25 31 Received loadend event 26 Test reading a n empty file as data URL32 Test reading a blob containing empty files and empty texts 27 33 readyState: 0 28 34 Received loadstart event … … 30 36 Received load event 31 37 readyState: 2 32 result size: 533 result: data:38 result size: 0 39 result: 34 40 Received loadend event 35 Test reading a UTF-8 file as binary string41 Test reading a blob containing single file 36 42 readyState: 0 37 43 Received loadstart event … … 42 48 result: Hello 43 49 Received loadend event 44 Test reading a binary file as binary string 45 readyState: 0 46 Received loadstart event 47 readyState: 1 48 Received load event 49 readyState: 2 50 result size: 9 51 result: 0x0 0x1 0x2 0x80 0x81 0x82 0xfd 0xfe 0xff 52 Received loadend event 53 Test reading a UTF-8 file as text 50 Test reading a blob containing single text 54 51 readyState: 0 55 52 Received loadstart event … … 58 55 readyState: 2 59 56 result size: 5 60 result: Hello57 result: First 61 58 Received loadend event 62 Test reading a UTF-16BE BOM file as text59 Test reading a blob containing sliced file 63 60 readyState: 0 64 61 Received loadstart event … … 67 64 readyState: 2 68 65 result size: 5 69 result: Hello66 result: onder 70 67 Received loadend event 71 Test reading a UTF-16LE BOM file astext68 Test reading a blob containing sliced text 72 69 readyState: 0 73 70 Received loadstart event … … 75 72 Received load event 76 73 readyState: 2 77 result size: 578 result: Hello74 result size: 4 75 result: irst 79 76 Received loadend event 80 Test reading a UTF-8 BOM file as text77 Test reading a blob containing multiple files 81 78 readyState: 0 82 79 Received loadstart event … … 84 81 Received load event 85 82 readyState: 2 86 result size: 587 result: Hello 83 result size: 19 84 result: HelloWonderfulWorld 88 85 Received loadend event 89 Test reading a UTF-16BE file as text with UTF-16BE encoding86 Test reading a blob containing multiple texts 90 87 readyState: 0 91 88 Received loadstart event … … 93 90 Received load event 94 91 readyState: 2 95 result size: 596 result: Hello92 result size: 16 93 result: FirstSecondThird 97 94 Received loadend event 98 Test reading a UTF-16BE BOM file as text with UTF8 encoding95 Test reading a hybrid blob 99 96 readyState: 0 100 97 Received loadstart event … … 102 99 Received load event 103 100 readyState: 2 104 result size: 5105 result: Hello101 result size: 35 102 result: FirstHelloSecondWonderfulWorldThird 106 103 Received loadend event 107 Test reading a UTF-16BE BOM file as text with invalid encoding104 Test reading a sliced hybrid blob 108 105 readyState: 0 109 106 Received loadstart event … … 111 108 Received load event 112 109 readyState: 2 113 result size: 5114 result: Hello110 result size: 12 111 result: lloSecondWon 115 112 Received loadend event 116 Test reading a UTF-8 file as data URL113 Test reading a triple-sliced hybrid blob 117 114 readyState: 0 118 115 Received loadstart event … … 120 117 Received load event 121 118 readyState: 2 122 result size: 31 123 result: data:text/plain;base64,SGVsbG8= 124 Received loadend event 125 Test calling multiple read methods and only last one is processed 126 readyState: 0 127 Received loadstart event 128 readyState: 1 129 Received load event 130 readyState: 2 131 result size: 31 132 result: data:text/plain;base64,SGVsbG8= 119 result size: 30 120 result: ondWonderfulWorldThirdFooloSec 133 121 Received loadend event 134 122 DONE -
trunk/LayoutTests/fast/files/read-file-async-expected.txt
r66450 r66452 1 1 2 Test reading a non-existent file 2 Test reading a non-existent file as binary string 3 readyState: 0 4 Received error event 5 readyState: 2 6 error code: 8 7 Received loadend event 8 Test reading a non-existent file as text 9 readyState: 0 10 Received error event 11 readyState: 2 12 error code: 8 13 Received loadend event 14 Test reading a non-existent file as data URL 3 15 readyState: 0 4 16 Received error event -
trunk/LayoutTests/platform/gtk/Skipped
r66400 r66452 3147 3147 http/tests/local/formdata/send-form-data-with-sliced-file.html 3148 3148 http/tests/local/formdata/upload-events.html 3149 fast/files/file-reader.html 3149 fast/files/read-blob-async.html 3150 fast/files/read-file-async.html 3150 3151 http/tests/media/video-play-stall-seek.html 3151 3152 http/tests/media/video-play-stall.html -
trunk/LayoutTests/platform/mac-wk2/Skipped
r66325 r66452 365 365 fast/events/window-events-capture.html 366 366 fast/events/zoom-dblclick.html 367 fast/files/file-reader.html 367 fast/files/read-blob-async.html 368 fast/files/read-file-async.html 368 369 fast/forms/25153.html 369 370 fast/forms/access-key.html -
trunk/LayoutTests/platform/qt/Skipped
r66408 r66452 782 782 # Missing eventSender.beginDragWithFiles() 783 783 fast/dom/Window/window-postmessage-clone-frames.html 784 fast/files/file-reader.html 784 fast/files/read-blob-async.html 785 fast/files/read-file-async.html 785 786 786 787 # Missing layoutTestController.setAlwaysAcceptCookies() -
trunk/LayoutTests/platform/win/Skipped
r66392 r66452 196 196 fast/events/drag-file-crash.html 197 197 fast/dom/Window/window-postmessage-clone.html 198 fast/files/file-reader.html 198 fast/files/read-blob-async.html 199 fast/files/read-file-async.html 199 200 200 201 # Need to add functionality to DumpRenderTree to test IDN <rdar://problem/5301954> -
trunk/WebCore/CMakeLists.txt
r66417 r66452 1220 1220 platform/Arena.cpp 1221 1221 platform/AsyncFileSystem.cpp 1222 platform/BlobItem.cpp1223 1222 platform/ContentType.cpp 1224 1223 platform/ContextMenu.cpp -
trunk/WebCore/ChangeLog
r66449 r66452 1 2010-08-30 Jian Li <jianli@chromium.org> 2 3 Reviewed by Darin Fisher. 4 5 Switch the Blob implementation to using the blob data registration model 6 https://bugs.webkit.org/show_bug.cgi?id=44389 7 8 Tests: fast/files/read-blob-async.html 9 fast/files/read-file-async.html 10 11 With this switch, File/Blob/BlobBuilder are changed to register the blob 12 data. FileReader is changed to route through loading the blob resource. 13 FormData is also updated to take BlobData. The WebKit mac implementation 14 is updated to resolve the blob references in the BlobData. 15 16 * CMakeLists.txt: Update the project file to remove BlobItem.*. 17 * GNUmakefile.am: Update the project file to remove BlobItem.*. 18 * WebCore.gypi: Update the project file to remove BlobItem.*. 19 * WebCore.pro: Update the project file to remove BlobItem.*. 20 * WebCore.vcproj/WebCore.vcproj: Update the project file to remove BlobItem.*. 21 * WebCore.xcodeproj/project.pbxproj: Update the project file to remove BlobItem.*. 22 * fileapi/Blob.cpp: Switch to using BlobData. 23 (WebCore::Blob::Blob): 24 (WebCore::Blob::slice): 25 * fileapi/Blob.h: Switch to using BlobData. 26 (WebCore::Blob::create): 27 (WebCore::Blob::size): 28 (WebCore::Blob::isFile): 29 * fileapi/BlobBuilder.cpp: Switch to using BlobData. 30 (WebCore::BlobBuilder::BlobBuilder): 31 (WebCore::BlobBuilder::append): 32 (WebCore::BlobBuilder::getBlob): 33 * fileapi/BlobBuilder.h: Switch to using BlobData. 34 * fileapi/BlobURL.cpp: Add a new helper method used in FormData. 35 (WebCore::BlobURL::getIdentifier): 36 * fileapi/BlobURL.h: 37 * fileapi/File.cpp: Switch to using BlobData. 38 (WebCore::createBlobDataForFile): 39 (WebCore::File::File): 40 (WebCore::File::size): 41 (WebCore::File::captureSnapshot): 42 * fileapi/File.h: Switch to using BlobData. 43 (WebCore::File::create): 44 (WebCore::File::path): 45 (WebCore::File::name): 46 (WebCore::File::webkitRelativePath): 47 * fileapi/FileReader.cpp: Change the reading to route through blob resource loading. 48 (WebCore::FileReader::FileReader): 49 (WebCore::FileReader::readAsBinaryString): 50 (WebCore::FileReader::readAsText): 51 (WebCore::FileReader::readAsDataURL): 52 (WebCore::delayedStart): 53 (WebCore::FileReader::readInternal): 54 (WebCore::FileReader::terminate): 55 (WebCore::FileReader::start): 56 (WebCore::FileReader::didReceiveResponse): 57 (WebCore::FileReader::didReceiveData): 58 (WebCore::FileReader::didFinishLoading): 59 (WebCore::FileReader::didFail): 60 (WebCore::FileReader::failed): 61 (WebCore::FileReader::httpStatusCodeToExceptionCode): 62 (WebCore::FileReader::result): 63 (WebCore::FileReader::convertToDataURL): 64 * fileapi/FileReader.h: 65 * html/FormDataList.cpp: Account to BlobData change. 66 (WebCore::FormDataList::appendString): 67 (WebCore::FormDataList::appendBlob): 68 * html/FormDataList.h: Account to BlobData change. 69 (WebCore::FormDataList::appendBlob): 70 (WebCore::FormDataList::Item::Item): 71 (WebCore::FormDataList::Item::data): 72 (WebCore::FormDataList::Item::blob): 73 (WebCore::FormDataList::items): 74 * loader/FormSubmission.cpp: Account to BlobData change. 75 (WebCore::FormSubmission::create): 76 * platform/BlobItem.cpp: Removed. 77 * platform/BlobItem.h: Removed. 78 * platform/network/BlobRegistryImpl.cpp: Add the implementations for resource loading. 79 (WebCore::BlobRegistryImpl::createResourceHandle): 80 (WebCore::BlobRegistryImpl::loadResourceSynchronously): 81 * platform/network/BlobResourceHandle.cpp: Fix a bug that the ref is not added. 82 (WebCore::BlobResourceHandle::BlobResourceHandle): 83 * platform/network/FormData.cpp: Account to BlobData change. 84 (WebCore::FormData::create): 85 (WebCore::FormData::createMultiPart): 86 (WebCore::FormData::deepCopy): 87 (WebCore::FormData::appendFile): 88 (WebCore::FormData::appendKeyValuePairItems): 89 * platform/network/FormData.h: Account to BlobData change. 90 * platform/network/mac/FormDataStreamMac.mm: Resolve blob references in the form data. 91 (WebCore::closeCurrentStream): 92 (WebCore::advanceCurrentStream): 93 (WebCore::formCreate): 94 (WebCore::formRead): 95 (WebCore::setHTTPBody): 96 * xml/XMLHttpRequest.cpp: Account to BlobData change. 97 (WebCore::XMLHttpRequest::send): 98 1 99 2010-08-30 Eric Seidel <eric@webkit.org> 2 100 -
trunk/WebCore/GNUmakefile.am
r66398 r66452 1879 1879 WebCore/platform/AsyncFileStream.h \ 1880 1880 WebCore/platform/AutodrainedPool.h \ 1881 WebCore/platform/BlobItem.cpp \1882 WebCore/platform/BlobItem.h \1883 1881 WebCore/platform/ContentType.cpp \ 1884 1882 WebCore/platform/ContentType.h \ -
trunk/WebCore/WebCore.gypi
r66369 r66452 3055 3055 'platform/AsyncFileSystemCallbacks.h', 3056 3056 'platform/AutodrainedPool.h', 3057 'platform/BlobItem.cpp',3058 'platform/BlobItem.h',3059 3057 'platform/ContentType.cpp', 3060 3058 'platform/ContentType.h', -
trunk/WebCore/WebCore.pro
r66384 r66452 878 878 platform/Arena.cpp \ 879 879 platform/AsyncFileSystem.cpp \ 880 platform/BlobItem.cpp \881 880 platform/text/Base64.cpp \ 882 881 platform/text/BidiContext.cpp \ … … 1683 1682 platform/AsyncFileSystem.h \ 1684 1683 platform/AsyncFileSystemCallbacks.h \ 1685 platform/BlobItem.h \1686 1684 platform/ContentType.h \ 1687 1685 platform/ContextMenu.h \ -
trunk/WebCore/WebCore.vcproj/WebCore.vcproj
r66365 r66452 23998 23998 </File> 23999 23999 <File 24000 RelativePath="..\platform\BlobItem.cpp"24001 >24002 </File>24003 <File24004 RelativePath="..\platform\BlobItem.h"24005 >24006 </File>24007 <File24008 24000 RelativePath="..\platform\ContentType.cpp" 24009 24001 > -
trunk/WebCore/WebCore.xcodeproj/project.pbxproj
r66365 r66452 2389 2389 898783D312232A13003AABDA /* LocalFileSystem.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 898783D112232A13003AABDA /* LocalFileSystem.cpp */; }; 2390 2390 898783D412232A13003AABDA /* LocalFileSystem.h in Headers */ = {isa = PBXBuildFile; fileRef = 898783D212232A13003AABDA /* LocalFileSystem.h */; }; 2391 8988E10E11A3508B00DB732E /* BlobItem.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8988E10C11A3508B00DB732E /* BlobItem.cpp */; };2392 8988E10F11A3508B00DB732E /* BlobItem.h in Headers */ = {isa = PBXBuildFile; fileRef = 8988E10D11A3508B00DB732E /* BlobItem.h */; settings = {ATTRIBUTES = (Private, ); }; };2393 2391 899ABC261215E4A300F9F219 /* DirectoryEntry.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 899ABC201215E4A300F9F219 /* DirectoryEntry.cpp */; }; 2394 2392 899ABC271215E4A300F9F219 /* DirectoryEntry.h in Headers */ = {isa = PBXBuildFile; fileRef = 899ABC211215E4A300F9F219 /* DirectoryEntry.h */; }; … … 8290 8288 898783D112232A13003AABDA /* LocalFileSystem.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LocalFileSystem.cpp; sourceTree = "<group>"; }; 8291 8289 898783D212232A13003AABDA /* LocalFileSystem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LocalFileSystem.h; sourceTree = "<group>"; }; 8292 8988E10C11A3508B00DB732E /* BlobItem.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BlobItem.cpp; sourceTree = "<group>"; };8293 8988E10D11A3508B00DB732E /* BlobItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BlobItem.h; sourceTree = "<group>"; };8294 8290 899ABC201215E4A300F9F219 /* DirectoryEntry.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DirectoryEntry.cpp; sourceTree = "<group>"; }; 8295 8291 899ABC211215E4A300F9F219 /* DirectoryEntry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DirectoryEntry.h; sourceTree = "<group>"; }; … … 16657 16653 89D08D9E12228451001241DF /* AsyncFileSystemCallbacks.h */, 16658 16654 51E1ECB10C91C55600DC255B /* AutodrainedPool.h */, 16659 8988E10C11A3508B00DB732E /* BlobItem.cpp */,16660 8988E10D11A3508B00DB732E /* BlobItem.h */,16661 16655 BCC8CFCA0986CD2400140BF2 /* ColorData.gperf */, 16662 16656 41D015C90F4B5C71004A662F /* ContentType.cpp */, … … 17772 17766 938192050F87E1EC00D5352A /* BinaryPropertyList.h in Headers */, 17773 17767 A89943280B42338800D7C802 /* BitmapImage.h in Headers */, 17774 8988E10F11A3508B00DB732E /* BlobItem.h in Headers */,17775 17768 93F199BE08245E59001E9ABC /* BlockExceptions.h in Headers */, 17776 17769 BC5EB5E10E81BE8700B25965 /* BorderData.h in Headers */, … … 20796 20789 938192030F87E1E600D5352A /* BinaryPropertyList.cpp in Sources */, 20797 20790 A89943290B42338800D7C802 /* BitmapImage.cpp in Sources */, 20798 8988E10E11A3508B00DB732E /* BlobItem.cpp in Sources */,20799 20791 93F19AE108245E59001E9ABC /* BlockExceptions.mm in Sources */, 20800 20792 BCEA4854097D93020094C9E4 /* break_lines.cpp in Sources */, -
trunk/WebCore/fileapi/Blob.cpp
r66365 r66452 32 32 #include "Blob.h" 33 33 34 #include "BlobData.h"35 #include "BlobItem.h"36 34 #include "BlobURL.h" 37 #include "File System.h"35 #include "File.h" 38 36 #include "ScriptExecutionContext.h" 39 37 #include "ThreadableBlobRegistry.h" 40 38 41 39 namespace WebCore { 42 43 // FIXME: To be removed when we switch to using BlobData.44 Blob::Blob(ScriptExecutionContext* scriptExecutionContext, const String& type, const BlobItemList& items)45 : m_scriptExecutionContext(scriptExecutionContext)46 , m_type(type)47 , m_size(0)48 {49 m_scriptExecutionContext->addBlob(this);50 for (size_t i = 0; i < items.size(); ++i)51 m_items.append(items[i]);52 }53 54 // FIXME: To be removed when we switch to using BlobData.55 Blob::Blob(ScriptExecutionContext* scriptExecutionContext, const PassRefPtr<BlobItem>& item)56 : m_scriptExecutionContext(scriptExecutionContext)57 , m_size(0)58 {59 m_scriptExecutionContext->addBlob(this);60 m_items.append(item);61 }62 63 // FIXME: To be removed when we switch to using BlobData.64 Blob::Blob(ScriptExecutionContext* scriptExecutionContext, const String& path)65 : m_scriptExecutionContext(scriptExecutionContext)66 , m_size(0)67 {68 m_scriptExecutionContext->addBlob(this);69 // Note: this doesn't initialize the type unlike File(path).70 m_items.append(FileBlobItem::create(path));71 }72 40 73 41 Blob::Blob(ScriptExecutionContext* scriptExecutionContext, PassOwnPtr<BlobData> blobData, long long size) … … 76 44 , m_size(size) 77 45 { 78 ASSERT(blobData .get() && !blobData->items().isEmpty());46 ASSERT(blobData); 79 47 80 48 m_scriptExecutionContext->addBlob(this); … … 90 58 , m_size(size) 91 59 { 92 m_scriptExecutionContext->addBlob(this); 93 94 // FIXME: To be removed when we switch to using BlobData. 95 if (srcURL.isEmpty()) 96 return; 60 m_scriptExecutionContext->addBlob(this); 97 61 98 62 // Create a new internal URL and register it with the same blob data as the source URL. … … 119 83 } 120 84 121 unsigned long long Blob::size() const122 {123 // FIXME: JavaScript cannot represent sizes as large as unsigned long long, we need to124 // come up with an exception to throw if file size is not represetable.125 unsigned long long size = 0;126 for (size_t i = 0; i < m_items.size(); ++i)127 size += m_items[i]->size();128 return size;129 }130 131 // FIXME: To be removed when we switch to using BlobData.132 const String& Blob::path() const133 {134 ASSERT(m_items.size() == 1 && m_items[0]->toFileBlobItem());135 return m_items[0]->toFileBlobItem()->path();136 }137 138 85 #if ENABLE(BLOB) 139 86 PassRefPtr<Blob> Blob::slice(ScriptExecutionContext* scriptExecutionContext, long long start, long long length, const String& contentType) const 140 87 { 88 // When we slice a file for the first time, we obtain a snapshot of the file by capturing its current size and modification time. 89 // The modification time will be used to verify if the file has been changed or not, when the underlying data are accessed. 90 long long size; 91 double modificationTime; 92 if (isFile()) 93 // FIXME: This involves synchronous file operation. We need to figure out how to make it asynchronous. 94 static_cast<const File*>(this)->captureSnapshot(size, modificationTime); 95 else { 96 ASSERT(m_size != -1); 97 size = m_size; 98 } 99 100 // Clamp the range if it exceeds the size limit. 141 101 if (start < 0) 142 102 start = 0; … … 144 104 length = 0; 145 105 146 // Clamp the range if it exceeds the size limit. 147 unsigned long long totalSize = size(); 148 if (static_cast<unsigned long long>(start) > totalSize) { 106 if (start >= size) { 149 107 start = 0; 150 108 length = 0; 151 } else if (sta tic_cast<unsigned long long>(start + length) > totalSize)152 length = totalSize - start;109 } else if (start + length > size) 110 length = size - start; 153 111 154 size_t i = 0; 155 BlobItemList items; 156 for (; i < m_items.size() && static_cast<unsigned long long>(start) >= m_items[i]->size(); ++i) 157 start -= m_items[i]->size(); 158 for (; length > 0 && i < m_items.size(); ++i) { 159 items.append(m_items[i]->slice(start, length)); 160 length -= items.last()->size(); 161 start = 0; 162 } 163 return Blob::create(scriptExecutionContext, contentType, items); 112 OwnPtr<BlobData> blobData = BlobData::create(); 113 blobData->setContentType(contentType); 114 if (isFile()) 115 blobData->appendFile(static_cast<const File*>(this)->path(), start, length, modificationTime); 116 else 117 blobData->appendBlob(m_url, start, length); 118 119 return Blob::create(scriptExecutionContext, blobData.release(), length); 164 120 } 165 #endif // ENABLE(BLOB)121 #endif 166 122 167 123 } // namespace WebCore -
trunk/WebCore/fileapi/Blob.h
r66365 r66452 32 32 #define Blob_h 33 33 34 #include "Blob Item.h"34 #include "BlobData.h" 35 35 #include "KURL.h" 36 36 #include "PlatformString.h" … … 42 42 namespace WebCore { 43 43 44 class BlobData;45 44 class ScriptExecutionContext; 46 45 47 46 class Blob : public RefCounted<Blob> { 48 47 public: 49 // FIXME: To be removed when we switch to using BlobData. 50 static PassRefPtr<Blob> create(ScriptExecutionContext* scriptExecutionContext, const String& type, const BlobItemList& items) 48 static PassRefPtr<Blob> create(ScriptExecutionContext* scriptExecutionContext, PassOwnPtr<BlobData> blobData, long long size) 51 49 { 52 return adoptRef(new Blob(scriptExecutionContext, type, items));50 return adoptRef(new Blob(scriptExecutionContext, blobData, size)); 53 51 } 54 52 … … 64 62 65 63 const KURL& url() const { return m_url; } 66 unsigned long long size() const;67 64 const String& type() const { return m_type; } 65 66 virtual unsigned long long size() const { return static_cast<unsigned long long>(m_size); } 68 67 virtual bool isFile() const { return false; } 69 70 // FIXME: To be removed when we switch to using BlobData.71 const String& path() const;72 73 // FIXME: To be removed when we switch to using BlobData.74 const BlobItemList& items() const { return m_items; }75 68 76 69 #if ENABLE(BLOB) … … 79 72 80 73 protected: 81 // FIXME: To be removed when we switch to using BlobData.82 Blob(ScriptExecutionContext*, const String& type, const BlobItemList&);83 Blob(ScriptExecutionContext*, const PassRefPtr<BlobItem>&);84 Blob(ScriptExecutionContext*, const String& path);85 86 74 Blob(ScriptExecutionContext*, PassOwnPtr<BlobData>, long long size); 87 75 … … 89 77 Blob(ScriptExecutionContext*, const KURL& srcURL, const String& type, long long size); 90 78 91 // FIXME: To be removed when we switch to using BlobData.92 BlobItemList m_items;93 94 79 // This is an internal URL referring to the blob data associated with this object. 95 80 // It is only used by FileReader to read the blob data via loading from the blob URL resource. 96 81 KURL m_url; 97 82 98 83 ScriptExecutionContext* m_scriptExecutionContext; 99 84 String m_type; -
trunk/WebCore/fileapi/BlobBuilder.cpp
r66365 r66452 35 35 #include "Blob.h" 36 36 #include "ExceptionCode.h" 37 #include "File.h" 37 38 #include "LineEnding.h" 38 39 #include "TextEncoding.h" … … 57 58 } 58 59 60 BlobBuilder::BlobBuilder() 61 : m_size(0) 62 { 63 } 64 59 65 bool BlobBuilder::append(const String& text, const String& endingType, ExceptionCode& ec) 60 66 { … … 63 69 return false; 64 70 65 m_items.append(StringBlobItem::create(cstr)); 71 m_size += cstr.length(); 72 m_items.append(BlobDataItem(cstr)); 66 73 return true; 67 74 } … … 74 81 bool BlobBuilder::append(PassRefPtr<Blob> blob) 75 82 { 76 if (blob) { 77 for (size_t i = 0; i < blob->items().size(); ++i) 78 m_items.append(blob->items()[i]); 79 return true; 83 if (blob->isFile()) { 84 // If the blob is file that is not snapshoted, capture the snapshot now. 85 // FIXME: This involves synchronous file operation. We need to figure out how to make it asynchronous. 86 File* file = static_cast<File*>(blob.get()); 87 long long snapshotSize; 88 double snapshotModificationTime; 89 file->captureSnapshot(snapshotSize, snapshotModificationTime); 90 91 m_size += snapshotSize; 92 m_items.append(BlobDataItem(file->path(), 0, snapshotSize, snapshotModificationTime)); 93 } else { 94 long long blobSize = static_cast<long long>(blob->size()); 95 m_size += blobSize; 96 m_items.append(BlobDataItem(blob->url(), 0, blobSize)); 80 97 } 81 return false;98 return true; 82 99 } 83 100 84 PassRefPtr<Blob> BlobBuilder::getBlob(ScriptExecutionContext* scriptExecutionContext, const String& contentType) const101 PassRefPtr<Blob> BlobBuilder::getBlob(ScriptExecutionContext* scriptExecutionContext, const String& contentType) 85 102 { 86 return Blob::create(scriptExecutionContext, contentType, m_items); 103 OwnPtr<BlobData> blobData = BlobData::create(); 104 blobData->setContentType(contentType); 105 blobData->swapItems(m_items); 106 107 RefPtr<Blob> blob = Blob::create(scriptExecutionContext, blobData.release(), m_size); 108 109 // After creating a blob from the current blob data, we do not need to keep the data around any more. Instead, we only 110 // need to keep a reference to the URL of the blob just created. 111 m_items.append(BlobDataItem(blob->url(), 0, m_size)); 112 113 return blob; 87 114 } 88 115 -
trunk/WebCore/fileapi/BlobBuilder.h
r66365 r66452 32 32 #define BlobBuilder_h 33 33 34 #include "BlobItem.h" 34 #include "BlobData.h" 35 #include "PlatformString.h" 35 36 #include <wtf/PassRefPtr.h> 36 37 #include <wtf/RefCounted.h> 38 #include <wtf/Vector.h> 39 #include <wtf/text/CString.h> 37 40 38 41 namespace WebCore { … … 40 43 class Blob; 41 44 class ScriptExecutionContext; 45 class TextEncoding; 42 46 43 47 typedef int ExceptionCode; … … 51 55 bool append(const String& text, const String& ending, ExceptionCode&); 52 56 53 PassRefPtr<Blob> getBlob(ScriptExecutionContext*, const String& contentType = String()) const;57 PassRefPtr<Blob> getBlob(ScriptExecutionContext*, const String& contentType = String()); 54 58 55 59 private: 56 BlobItemList m_items; 60 BlobBuilder(); 61 62 long long m_size; 63 BlobDataItemList m_items; 57 64 }; 58 65 -
trunk/WebCore/fileapi/BlobURL.cpp
r66365 r66452 64 64 } 65 65 66 String BlobURL::getIdentifier(const KURL& url) 67 { 68 ASSERT(url.protocolIs("blob")); 69 70 unsigned startIndex = url.pathAfterLastSlash(); 71 return url.string().substring(startIndex); 72 } 73 66 74 } // namespace WebCore -
trunk/WebCore/fileapi/BlobURL.h
r66365 r66452 42 42 static KURL createURL(ScriptExecutionContext*); 43 43 static KURL getOrigin(const KURL&); 44 static String getIdentifier(const KURL& url); 44 45 }; 45 46 -
trunk/WebCore/fileapi/File.cpp
r66365 r66452 27 27 #include "File.h" 28 28 29 #include "Blob Data.h"29 #include "BlobRegistry.h" 30 30 #include "FileSystem.h" 31 31 #include "MIMETypeRegistry.h" … … 33 33 namespace WebCore { 34 34 35 static PassOwnPtr<BlobData> createBlobDataForFile(const String& path) 36 { 37 String type; 38 int index = path.reverseFind('.'); 39 if (index != -1) 40 type = MIMETypeRegistry::getMIMETypeForExtension(path.substring(index + 1)); 41 42 OwnPtr<BlobData> blobData = BlobData::create(); 43 blobData->setContentType(type); 44 blobData->appendFile(path); 45 return blobData.release(); 46 } 47 35 48 File::File(ScriptExecutionContext* scriptExecutionContext, const String& path) 36 : Blob(scriptExecutionContext, path) 49 : Blob(scriptExecutionContext, createBlobDataForFile(path), -1) 50 , m_path(path) 51 , m_name(pathGetFileName(path)) 37 52 { 38 Init();39 53 } 40 54 41 55 File::File(ScriptExecutionContext* scriptExecutionContext, const String& path, const KURL& url, const String& type) 42 : Blob(scriptExecutionContext, url, type, BlobDataItem::toEndOfFile) 56 : Blob(scriptExecutionContext, url, type, -1) 57 , m_path(path) 43 58 { 44 // FIXME: To be removed when we switch to using BlobData. 45 m_items.append(FileBlobItem::create(path)); 59 m_name = pathGetFileName(path); 46 60 } 47 61 48 62 #if ENABLE(DIRECTORY_UPLOAD) 49 File::File(ScriptExecutionContext* scriptExecutionContext, const String& relativePath, const String& filePath) 50 : Blob(scriptExecutionContext, FileBlobItem::create(filePath, relativePath)) 63 File::File(ScriptExecutionContext* scriptExecutionContext, const String& relativePath, const String& path) 64 : Blob(scriptExecutionContext, createBlobDataForFile(path), -1) 65 , m_path(path) 66 , m_relativePath(relativePath) 51 67 { 52 Init();53 68 } 54 69 #endif 55 70 56 void File::Init() 71 unsigned long long File::size() const 57 72 { 58 // We don't use MIMETypeRegistry::getMIMETypeForPath() because it returns "application/octet-stream" upon failure. 59 const String& fileName = name(); 60 size_t index = fileName.reverseFind('.'); 61 if (index != notFound) 62 m_type = MIMETypeRegistry::getMIMETypeForExtension(fileName.substring(index + 1)); 73 // FIXME: JavaScript cannot represent sizes as large as unsigned long long, we need to 74 // come up with an exception to throw if file size is not representable. 75 long long size; 76 if (!getFileSize(m_path, size)) 77 return 0; 78 return static_cast<unsigned long long>(size); 63 79 } 64 80 65 const String& File::name() const81 void File::captureSnapshot(long long& snapshotSize, double& snapshotModificationTime) const 66 82 { 67 return items().at(0)->toFileBlobItem()->name(); 83 // 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. 84 // If we fail to retrieve the size or modification time, probably due to that the file has been deleted, 0 size is returned. 85 // FIXME: Combine getFileSize and getFileModificationTime into one file system call. 86 time_t modificationTime; 87 if (!getFileSize(m_path, snapshotSize) || !getFileModificationTime(m_path, modificationTime)) { 88 snapshotSize = 0; 89 snapshotModificationTime = 0; 90 } else 91 snapshotModificationTime = modificationTime; 68 92 } 69 93 70 #if ENABLE(DIRECTORY_UPLOAD)71 const String& File::webkitRelativePath() const72 {73 return items().at(0)->toFileBlobItem()->relativePath();74 }75 #endif76 77 94 } // namespace WebCore -
trunk/WebCore/fileapi/File.h
r66365 r66452 28 28 29 29 #include "Blob.h" 30 #include "PlatformString.h" 30 31 #include <wtf/PassRefPtr.h> 31 32 #include <wtf/RefCounted.h> 32 33 33 34 namespace WebCore { 35 36 class KURL; 37 class ScriptExecutionContext; 34 38 35 39 class File : public Blob { … … 41 45 42 46 // For deserialization. 43 static PassRefPtr<File> create(ScriptExecutionContext* scriptExecutionContext, const String& path, const KURL& url, const String& type)47 static PassRefPtr<File> create(ScriptExecutionContext* scriptExecutionContext, const String& path, const KURL& srcURL, const String& type) 44 48 { 45 return adoptRef(new File(scriptExecutionContext, path, url, type));49 return adoptRef(new File(scriptExecutionContext, path, srcURL, type)); 46 50 } 47 51 … … 53 57 #endif 54 58 59 virtual unsigned long long size() const; 55 60 virtual bool isFile() const { return true; } 56 61 57 const String& name() const; 62 const String& path() const { return m_path; } 63 const String& name() const { return m_name; } 58 64 #if ENABLE(DIRECTORY_UPLOAD) 59 65 // Returns the relative path of this file in the context of a directory selection. 60 const String& webkitRelativePath() const ;66 const String& webkitRelativePath() const { return m_relativePath; } 61 67 #endif 68 69 // Note that this involves synchronous file operation. Think twice before calling this function. 70 void captureSnapshot(long long& snapshotSize, double& snapshotModificationTime) const; 62 71 63 72 // FIXME: obsolete attributes. To be removed. … … 67 76 private: 68 77 File(ScriptExecutionContext*, const String& path); 69 78 70 79 // For deserialization. 71 File(ScriptExecutionContext*, const String& path, const KURL& , const String& type);80 File(ScriptExecutionContext*, const String& path, const KURL& srcURL, const String& type); 72 81 73 82 #if ENABLE(DIRECTORY_UPLOAD) … … 75 84 #endif 76 85 77 void Init(); 86 String m_path; 87 String m_name; 88 #if ENABLE(DIRECTORY_UPLOAD) 89 String m_relativePath; 90 #endif 78 91 }; 79 92 -
trunk/WebCore/fileapi/FileReader.cpp
r66365 r66452 37 37 #include "Base64.h" 38 38 #include "Blob.h" 39 #include "CrossThreadTask.h" 39 40 #include "File.h" 40 #include "FileStreamProxy.h"41 41 #include "Logging.h" 42 42 #include "ProgressEvent.h" 43 #include "ResourceError.h" 44 #include "ResourceRequest.h" 43 45 #include "ScriptExecutionContext.h" 44 46 #include "TextResourceDecoder.h" 47 #include "ThreadableLoader.h" 45 48 #include <wtf/CurrentTime.h> 46 49 47 50 namespace WebCore { 48 51 49 const unsigned bufferSize = 1024;50 52 const double progressNotificationIntervalMS = 50; 51 53 … … 60 62 , m_lastProgressNotificationTimeMS(0) 61 63 { 62 m_buffer.resize(bufferSize);63 64 } 64 65 … … 84 85 } 85 86 86 void FileReader::readAsBinaryString(Blob* fileBlob) 87 { 88 if (!fileBlob) 89 return; 90 91 // FIXME: needs to handle non-file blobs. 92 LOG(FileAPI, "FileReader: reading as binary: %s\n", fileBlob->path().utf8().data()); 93 94 readInternal(fileBlob, ReadFileAsBinaryString); 95 } 96 97 void FileReader::readAsText(Blob* fileBlob, const String& encoding) 98 { 99 if (!fileBlob) 100 return; 101 102 // FIXME: needs to handle non-file blobs. 103 LOG(FileAPI, "FileReader: reading as text: %s\n", fileBlob->path().utf8().data()); 87 void FileReader::readAsBinaryString(Blob* blob) 88 { 89 if (!blob) 90 return; 91 92 LOG(FileAPI, "FileReader: reading as binary: %s %s\n", blob->url().string().utf8().data(), blob->isFile() ? static_cast<File*>(blob)->path().utf8().data() : ""); 93 94 readInternal(blob, ReadFileAsBinaryString); 95 } 96 97 void FileReader::readAsText(Blob* blob, const String& encoding) 98 { 99 if (!blob) 100 return; 101 102 LOG(FileAPI, "FileReader: reading as text: %s %s\n", blob->url().string().utf8().data(), blob->isFile() ? static_cast<File*>(blob)->path().utf8().data() : ""); 104 103 105 104 if (!encoding.isEmpty()) 106 105 m_encoding = TextEncoding(encoding); 107 readInternal(fileBlob, ReadFileAsText); 108 } 109 110 void FileReader::readAsDataURL(File* file) 111 { 112 if (!file) 113 return; 114 115 LOG(FileAPI, "FileReader: reading as data URL: %s\n", file->path().utf8().data()); 116 117 m_fileType = file->type(); 118 readInternal(file, ReadFileAsDataURL); 119 } 120 121 void FileReader::readInternal(Blob* fileBlob, ReadType type) 106 readInternal(blob, ReadFileAsText); 107 } 108 109 void FileReader::readAsDataURL(Blob* blob) 110 { 111 if (!blob) 112 return; 113 114 LOG(FileAPI, "FileReader: reading as data URL: %s %s\n", blob->url().string().utf8().data(), blob->isFile() ? static_cast<File*>(blob)->path().utf8().data() : ""); 115 116 m_fileType = blob->type(); 117 readInternal(blob, ReadFileAsDataURL); 118 } 119 120 static void delayedStart(ScriptExecutionContext*, FileReader* reader) 121 { 122 reader->start(); 123 } 124 125 void FileReader::readInternal(Blob* blob, ReadType type) 122 126 { 123 127 // readAs*** methods() can be called multiple times. Only the last call before the actual reading happens is processed. … … 125 129 return; 126 130 127 m_fileBlob = fileBlob; 131 if (m_state == None) 132 scriptExecutionContext()->postTask(createCallbackTask(&delayedStart, this)); 133 134 m_blob = blob; 128 135 m_readType = type; 129 136 m_state = Starting; 130 131 // When FileStreamProxy is created, FileReader::didStart() will get notified on the File thread and we will start132 // opening and reading the file since then.133 if (!m_streamProxy.get())134 m_streamProxy = FileStreamProxy::create(scriptExecutionContext(), this);135 137 } 136 138 … … 151 153 void FileReader::terminate() 152 154 { 153 if (m_ streamProxy) {154 m_ streamProxy->stop();155 m_ streamProxy= 0;155 if (m_loader) { 156 m_loader->cancel(); 157 m_loader = 0; 156 158 } 157 159 m_state = Completed; 158 160 } 159 161 160 void FileReader:: didStart()162 void FileReader::start() 161 163 { 162 164 m_state = Opening; 163 165 164 ASSERT(m_fileBlob->items().size() == 1 && m_fileBlob->items().at(0)->toFileBlobItem()); 165 const FileRangeBlobItem* fileRangeItem = m_fileBlob->items().at(0)->toFileRangeBlobItem(); 166 double expectedModificationTime = fileRangeItem ? fileRangeItem->snapshotModificationTime() : 0; 167 168 m_streamProxy->getSize(m_fileBlob->path(), expectedModificationTime); 169 } 170 171 void FileReader::didGetSize(long long size) 172 { 173 // If the size is -1, it means the file has been moved or changed. Fail now. 174 if (size == -1) { 175 didFail(NOT_FOUND_ERR); 166 // The blob is read by routing through the request handling layer given the blob url. 167 ResourceRequest request(m_blob->url()); 168 request.setHTTPMethod("GET"); 169 170 ThreadableLoaderOptions options; 171 options.sendLoadCallbacks = true; 172 options.sniffContent = false; 173 options.forcePreflight = false; 174 options.allowCredentials = true; 175 options.crossOriginRequestPolicy = DenyCrossOriginRequests; 176 177 m_loader = ThreadableLoader::create(scriptExecutionContext(), this, request, options); 178 } 179 180 void FileReader::didReceiveResponse(const ResourceResponse& response) 181 { 182 if (response.httpStatusCode() != 200) { 183 failed(response.httpStatusCode()); 176 184 return; 177 185 } … … 180 188 fireEvent(eventNames().loadstartEvent); 181 189 182 ASSERT(m_fileBlob->items().size() == 1 && m_fileBlob->items().at(0)->toFileBlobItem()); 183 const FileRangeBlobItem* fileRangeItem = m_fileBlob->items().at(0)->toFileRangeBlobItem(); 184 long long start = fileRangeItem ? fileRangeItem->start() : 0; 185 186 // 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. 187 m_totalBytes = fileRangeItem ? fileRangeItem->size() : size; 188 189 m_streamProxy->openForRead(m_fileBlob->path(), start, m_totalBytes); 190 } 191 192 void FileReader::didOpen(bool success) 193 { 194 if (!success) { 195 didFail(NOT_READABLE_ERR); 196 return; 197 } 198 199 m_streamProxy->read(m_buffer.data(), m_buffer.size()); 200 } 201 202 void FileReader::didRead(int bytesRead) 203 { 190 m_totalBytes = response.expectedContentLength(); 191 } 192 193 void FileReader::didReceiveData(const char* data, int lengthReceived) 194 { 195 ASSERT(data && lengthReceived); 196 204 197 // Bail out if we have aborted the reading. 205 198 if (m_state == Completed) 206 199 return; 207 200 208 // If bytesRead is -1, it means an error happens.209 if (bytesRead == -1) {210 didFail(NOT_READABLE_ERR);211 return;212 }213 214 // If bytesRead is 0, it means the reading is done.215 if (!bytesRead) {216 didFinish();217 return;218 }219 220 201 switch (m_readType) { 221 202 case ReadFileAsBinaryString: 222 m_result += String( m_buffer.data(), static_cast<unsigned>(bytesRead));203 m_result += String(data, static_cast<unsigned>(lengthReceived)); 223 204 break; 224 205 case ReadFileAsText: 225 206 case ReadFileAsDataURL: 226 m_rawData.append( m_buffer.data(), static_cast<unsigned>(bytesRead));207 m_rawData.append(data, static_cast<unsigned>(lengthReceived)); 227 208 m_isRawDataConverted = false; 228 209 break; … … 231 212 } 232 213 233 m_bytesLoaded += bytesRead;214 m_bytesLoaded += lengthReceived; 234 215 235 216 // Fire the progress event at least every 50ms. … … 241 222 m_lastProgressNotificationTimeMS = now; 242 223 } 243 244 // Continue reading. 245 m_streamProxy->read(m_buffer.data(), m_buffer.size()); 246 } 247 248 void FileReader::didFinish() 224 } 225 226 void FileReader::didFinishLoading(unsigned long) 249 227 { 250 228 m_state = Completed; 251 252 m_streamProxy->close();253 229 254 230 fireEvent(eventNames().loadEvent); 255 231 fireEvent(eventNames().loadendEvent); 256 } 257 258 void FileReader::didFail(ExceptionCode ec) 232 233 m_loader = 0; 234 } 235 236 void FileReader::didFail(const ResourceError&) 237 { 238 // Treat as internal error. 239 failed(500); 240 } 241 242 void FileReader::failed(int httpStatusCode) 259 243 { 260 244 m_state = Completed; 261 m_error = FileError::create(ec); 262 263 m_streamProxy->close(); 264 245 246 m_error = FileError::create(httpStatusCodeToExceptionCode(httpStatusCode)); 265 247 fireEvent(eventNames().errorEvent); 266 248 fireEvent(eventNames().loadendEvent); 249 250 m_loader = 0; 251 } 252 253 ExceptionCode FileReader::httpStatusCodeToExceptionCode(int httpStatusCode) 254 { 255 switch (httpStatusCode) { 256 case 403: 257 return SECURITY_ERR; 258 case 404: 259 return NOT_FOUND_ERR; 260 default: 261 return NOT_READABLE_ERR; 262 } 267 263 } 268 264 … … 304 300 // For data URL, we only do the coversion until we receive all the raw data. 305 301 else if (m_readType == ReadFileAsDataURL && m_state == Completed) 306 convertToDataURL( );302 convertToDataURL(m_rawData, m_fileType, m_result); 307 303 308 304 return m_result; … … 329 325 } 330 326 331 void FileReader::convertToDataURL( )332 { 333 m_result = "data:";334 335 if (! m_rawData.size())336 return; 337 338 m_result += m_fileType;339 if (! m_fileType.isEmpty())340 m_result += ";";341 m_result += "base64,";327 void FileReader::convertToDataURL(const Vector<char>& rawData, const String& fileType, ScriptString& result) 328 { 329 result = "data:"; 330 331 if (!rawData.size()) 332 return; 333 334 result += fileType; 335 if (!fileType.isEmpty()) 336 result += ";"; 337 result += "base64,"; 342 338 343 339 Vector<char> out; 344 base64Encode( m_rawData, out);340 base64Encode(rawData, out); 345 341 out.append('\0'); 346 m_result += out.data();342 result += out.data(); 347 343 } 348 344 -
trunk/WebCore/fileapi/FileReader.h
r66365 r66452 37 37 #include "EventTarget.h" 38 38 #include "FileError.h" 39 #include "FileStreamClient.h"40 39 #include "PlatformString.h" 41 40 #include "ScriptString.h" 42 41 #include "TextEncoding.h" 42 #include "ThreadableLoaderClient.h" 43 43 #include <wtf/PassRefPtr.h> 44 44 #include <wtf/RefCounted.h> … … 49 49 50 50 class Blob; 51 class File;52 class FileStreamProxy;53 51 class ScriptExecutionContext; 54 52 class TextResourceDecoder; 53 class ThreadableLoader; 55 54 56 class FileReader : public RefCounted<FileReader>, public ActiveDOMObject, public EventTarget, public FileStreamClient {55 class FileReader : public RefCounted<FileReader>, public ActiveDOMObject, public EventTarget, public ThreadableLoaderClient { 57 56 public: 58 57 static PassRefPtr<FileReader> create(ScriptExecutionContext* context) … … 71 70 void readAsBinaryString(Blob*); 72 71 void readAsText(Blob*, const String& encoding = ""); 73 void readAsDataURL( File*);72 void readAsDataURL(Blob*); 74 73 void abort(); 74 75 void start(); 75 76 76 77 ReadyState readyState() const; 77 78 PassRefPtr<FileError> error() { return m_error; } 78 79 const ScriptString& result(); 80 81 // Helper methods, also used by FileReaderSync. 82 static ExceptionCode httpStatusCodeToExceptionCode(int httpStatusCode); 83 static void convertToDataURL(const Vector<char>& rawData, const String& fileType, ScriptString& result); 79 84 80 85 // ActiveDOMObject … … 87 92 virtual ScriptExecutionContext* scriptExecutionContext() const { return ActiveDOMObject::scriptExecutionContext(); } 88 93 89 // FileStreamClient90 virtual void did Start();91 virtual void did GetSize(long long);92 virtual void did Open(bool);93 virtual void did Read(int);94 // ThreadableLoaderClient 95 virtual void didReceiveResponse(const ResourceResponse&); 96 virtual void didReceiveData(const char*, int); 97 virtual void didFinishLoading(unsigned long identifier); 98 virtual void didFail(const ResourceError&); 94 99 95 100 using RefCounted<FileReader>::ref; … … 127 132 void terminate(); 128 133 void readInternal(Blob*, ReadType); 134 void failed(int httpStatusCode); 135 void fireErrorEvent(int httpStatusCode); 129 136 void fireEvent(const AtomicString& type); 130 137 void convertToText(); 131 138 void convertToDataURL(); 132 void didFinish();133 void didFail(ExceptionCode);134 139 135 140 InternalState m_state; 136 141 EventTargetData m_eventTargetData; 137 142 138 RefPtr<Blob> m_ fileBlob;143 RefPtr<Blob> m_blob; 139 144 ReadType m_readType; 140 145 TextEncoding m_encoding; … … 158 163 String m_fileType; 159 164 160 RefPtr<FileStreamProxy> m_streamProxy; 161 Vector<char> m_buffer; 165 RefPtr<ThreadableLoader> m_loader; 162 166 RefPtr<FileError> m_error; 163 167 long long m_bytesLoaded; -
trunk/WebCore/html/FormDataList.cpp
r63343 r66452 34 34 { 35 35 CString cstr = m_encoding.encode(s.characters(), s.length(), EntitiesForUnencodables); 36 m_items.append( StringBlobItem::create(normalizeLineEndingsToCRLF(cstr)));36 m_items.append(normalizeLineEndingsToCRLF(cstr)); 37 37 } 38 38 39 39 void FormDataList::appendString(const CString& s) 40 40 { 41 m_items.append( StringBlobItem::create(s));41 m_items.append(s); 42 42 } 43 43 44 void FormDataList::appendBlob( const String& key,PassRefPtr<Blob> blob)44 void FormDataList::appendBlob(PassRefPtr<Blob> blob) 45 45 { 46 appendString(key); 47 const BlobItemList& items = blob->items(); 48 for (size_t i = 0; i < items.size(); ++i) 49 m_items.append(items.at(i)); 46 m_items.append(blob); 50 47 } 51 48 -
trunk/WebCore/html/FormDataList.h
r65021 r66452 31 31 class FormDataList { 32 32 public: 33 class Item { 34 public: 35 Item() { } 36 Item(const WTF::CString& data) : m_data(data) { } 37 Item(PassRefPtr<Blob> blob) : m_blob(blob) { } 38 39 const WTF::CString& data() const { return m_data; } 40 Blob* blob() const { return m_blob.get(); } 41 42 private: 43 WTF::CString m_data; 44 RefPtr<Blob> m_blob; 45 }; 46 33 47 FormDataList(const TextEncoding&); 34 48 … … 48 62 appendString(String::number(value)); 49 63 } 50 void appendBlob(const String& key, PassRefPtr<Blob>); 64 void appendBlob(const String& key, PassRefPtr<Blob> blob) 65 { 66 appendString(key); 67 appendBlob(blob); 68 } 51 69 52 const BlobItemList& items() const { return m_items; }70 const Vector<Item>& items() const { return m_items; } 53 71 const TextEncoding& encoding() const { return m_encoding; } 54 72 … … 56 74 void appendString(const CString&); 57 75 void appendString(const String&); 76 void appendBlob(PassRefPtr<Blob>); 58 77 59 78 TextEncoding m_encoding; 60 BlobItemListm_items;79 Vector<Item> m_items; 61 80 }; 62 81 -
trunk/WebCore/loader/FormSubmission.cpp
r65340 r66452 163 163 164 164 if (isMultiPartForm) { 165 formData = FormData::createMultiPart( domFormData->items(), domFormData->encoding(), document);165 formData = FormData::createMultiPart(*(static_cast<FormDataList*>(domFormData.get())), domFormData->encoding(), document); 166 166 boundary = formData->boundary().data(); 167 167 } else { 168 formData = FormData::create( domFormData->items(), domFormData->encoding());168 formData = FormData::create(*(static_cast<FormDataList*>(domFormData.get())), domFormData->encoding()); 169 169 if (attributes.method() == PostMethod && isMailtoForm) { 170 170 // Convert the form data into a string that we put into the URL. -
trunk/WebCore/platform/network/BlobRegistryImpl.cpp
r65827 r66452 33 33 #include "BlobRegistryImpl.h" 34 34 35 #include "BlobResourceHandle.h" 35 36 #include "ResourceError.h" 36 37 #include "ResourceHandle.h" … … 61 62 } 62 63 63 PassRefPtr<ResourceHandle> BlobRegistryImpl::createResourceHandle(const ResourceRequest& request, ResourceHandleClient* )64 PassRefPtr<ResourceHandle> BlobRegistryImpl::createResourceHandle(const ResourceRequest& request, ResourceHandleClient* client) 64 65 { 65 66 if (!shouldLoadResource(request)) 66 67 return 0; 67 68 68 // FIXME: To be implemented. 69 return 0; 69 return BlobResourceHandle::create(m_blobs.get(request.url().string()), request, client); 70 70 } 71 71 72 bool BlobRegistryImpl::loadResourceSynchronously(const ResourceRequest& request, ResourceError& , ResourceResponse&, Vector<char>&)72 bool BlobRegistryImpl::loadResourceSynchronously(const ResourceRequest& request, ResourceError& error, ResourceResponse& response, Vector<char>& data) 73 73 { 74 74 if (!shouldLoadResource(request)) 75 75 return false; 76 76 77 // FIXME: To be implemented.78 return false;77 BlobResourceHandle::loadResourceSynchronously(m_blobs.get(request.url().string()), request, error, response, data); 78 return true; 79 79 } 80 80 -
trunk/WebCore/platform/network/BlobResourceHandle.cpp
r65827 r66452 160 160 { 161 161 if (m_async) { 162 m_asyncStream = adoptRef(client->createAsyncFileStream(this)); 162 // We need to take a ref. 163 m_asyncStream = client->createAsyncFileStream(this); 163 164 callOnMainThread(delayedStart, this); 164 165 } else -
trunk/WebCore/platform/network/FormData.cpp
r65786 r66452 23 23 #include "FormData.h" 24 24 25 #include "BlobItem.h" 25 #include "BlobData.h" 26 #include "BlobURL.h" 26 27 #include "Chrome.h" 27 28 #include "ChromeClient.h" 28 29 #include "Document.h" 30 #include "File.h" 29 31 #include "FileSystem.h" 30 32 #include "FormDataBuilder.h" 33 #include "FormDataList.h" 31 34 #include "MIMETypeRegistry.h" 32 35 #include "Page.h" … … 34 37 35 38 namespace WebCore { 36 37 #if ENABLE(BLOB)38 const long long FormDataElement::toEndOfFile = -1;39 const double FormDataElement::doNotCheckFileChange = 0;40 #endif41 39 42 40 inline FormData::FormData() … … 100 98 } 101 99 102 PassRefPtr<FormData> FormData::create(const BlobItemList& items, const TextEncoding& encoding)103 { 104 RefPtr<FormData> result = create(); 105 result->appendKeyValuePairItems( items, encoding, false, 0);106 return result.release(); 107 } 108 109 PassRefPtr<FormData> FormData::createMultiPart(const BlobItemList& items, const TextEncoding& encoding, Document* document)110 { 111 RefPtr<FormData> result = create(); 112 result->appendKeyValuePairItems( items, encoding, true, document);100 PassRefPtr<FormData> FormData::create(const FormDataList& list, const TextEncoding& encoding) 101 { 102 RefPtr<FormData> result = create(); 103 result->appendKeyValuePairItems(list, encoding, false, 0); 104 return result.release(); 105 } 106 107 PassRefPtr<FormData> FormData::createMultiPart(const FormDataList& list, const TextEncoding& encoding, Document* document) 108 { 109 RefPtr<FormData> result = create(); 110 result->appendKeyValuePairItems(list, encoding, true, document); 113 111 return result.release(); 114 112 } … … 163 161 { 164 162 #if ENABLE(BLOB) 165 m_elements.append(FormDataElement(filename, 0, FormDataElement::toEndOfFile, FormDataElement::doNotCheckFileChange, shouldGenerateFile));163 m_elements.append(FormDataElement(filename, 0, BlobDataItem::toEndOfFile, BlobDataItem::doNotCheckFileChange, shouldGenerateFile)); 166 164 #else 167 165 m_elements.append(FormDataElement(filename, shouldGenerateFile)); … … 169 167 } 170 168 171 void FormData::appendItems(const BlobItemList& items)172 {173 for (BlobItemList::const_iterator iter(items.begin()); iter != items.end(); ++iter)174 appendItem(iter->get(), false);175 }176 177 void FormData::appendItem(const BlobItem* item, bool shouldGenerateFile)178 {179 const DataBlobItem* dataItem = item->toDataBlobItem();180 if (dataItem) {181 appendData(dataItem->data(), static_cast<size_t>(dataItem->size()));182 return;183 }184 185 const FileBlobItem* fileItem = item->toFileBlobItem();186 ASSERT(fileItem);187 if (fileItem->path().isEmpty()) {188 // If the path is empty do not add the item.189 return;190 }191 192 #if ENABLE(BLOB)193 const FileRangeBlobItem* fileRangeItem = item->toFileRangeBlobItem();194 if (fileRangeItem) {195 appendFileRange(fileItem->path(), fileRangeItem->start(), fileRangeItem->size(), fileRangeItem->snapshotModificationTime(), shouldGenerateFile);196 return;197 }198 #endif199 200 appendFile(fileItem->path(), shouldGenerateFile);201 }202 203 169 #if ENABLE(BLOB) 204 170 void FormData::appendFileRange(const String& filename, long long start, long long length, double expectedModificationTime, bool shouldGenerateFile) … … 213 179 #endif 214 180 215 void FormData::appendKeyValuePairItems(const BlobItemList& items, const TextEncoding& encoding, bool isMultiPartForm, Document* document)181 void FormData::appendKeyValuePairItems(const FormDataList& list, const TextEncoding& encoding, bool isMultiPartForm, Document* document) 216 182 { 217 183 if (isMultiPartForm) … … 220 186 Vector<char> encodedData; 221 187 188 const Vector<FormDataList::Item>& items = list.items(); 222 189 size_t formDataListSize = items.size(); 223 190 ASSERT(!(formDataListSize % 2)); 224 191 for (size_t i = 0; i < formDataListSize; i += 2) { 225 const StringBlobItem* key = items[i]->toStringBlobItem(); 226 const BlobItem* value = items[i + 1].get(); 227 ASSERT(key); 192 const FormDataList::Item& key = items[i]; 193 const FormDataList::Item& value = items[i + 1]; 228 194 if (isMultiPartForm) { 229 195 Vector<char> header; 230 FormDataBuilder::beginMultiPartHeader(header, m_boundary.data(), key ->cstr());196 FormDataBuilder::beginMultiPartHeader(header, m_boundary.data(), key.data()); 231 197 232 198 bool shouldGenerateFile = false; 233 // If the current type is FILE, then we also need to include the filename 234 const FileBlobItem* fileItem = value->toFileBlobItem(); 235 if (fileItem) { 236 const String& path = fileItem->path(); 237 238 #if ENABLE(DIRECTORY_UPLOAD) 239 String fileName = !fileItem->relativePath().isEmpty() ? fileItem->relativePath() : fileItem->name(); 199 200 // If the current type is blob, then we also need to include the filename 201 if (value.blob()) { 202 String name; 203 if (value.blob()->isFile()) { 204 // For file blob, use the filename (or relative path if it is present) as the name. 205 File* file = static_cast<File*>(value.blob()); 206 #if ENABLE(DIRECTORY_UPLOAD) 207 name = file->webkitRelativePath().isEmpty() ? file->name() : file->webkitRelativePath(); 240 208 #else 241 String fileName = fileItem->name(); 242 #endif 243 244 // Let the application specify a filename if it's going to generate a replacement file for the upload. 245 if (!path.isEmpty()) { 209 name = file->name(); 210 #endif 211 212 // Let the application specify a filename if it's going to generate a replacement file for the upload. 246 213 if (Page* page = document->page()) { 247 214 String generatedFileName; 248 shouldGenerateFile = page->chrome()->client()->shouldReplaceWithGeneratedFileForUpload( path, generatedFileName);215 shouldGenerateFile = page->chrome()->client()->shouldReplaceWithGeneratedFileForUpload(file->path(), generatedFileName); 249 216 if (shouldGenerateFile) 250 fileName = generatedFileName;217 name = generatedFileName; 251 218 } 219 } else { 220 // For non-file blob, use the identifier part of the URL as the name. 221 name = "Blob" + BlobURL::getIdentifier(value.blob()->url()); 222 name = name.replace("-", ""); // For safety, remove '-' from the filename since some servers may not like it. 252 223 } 253 224 254 225 // We have to include the filename=".." part in the header, even if the filename is empty 255 FormDataBuilder::addFilenameToMultiPartHeader(header, encoding, fileName); 256 257 // If the item is sliced from a file, do not add the content type. 258 #if ENABLE(BLOB) 259 if (!fileName.isEmpty() && !value->toFileRangeBlobItem()) { 260 #else 261 if (!fileName.isEmpty()) { 262 #endif 263 // FIXME: The MIMETypeRegistry function's name makes it sound like it takes a path, 264 // not just a basename. But filename is not the path. But note that it's not safe to 265 // just use path instead since in the generated-file case it will not reflect the 266 // MIME type of the generated file. 267 String mimeType = MIMETypeRegistry::getMIMETypeForPath(fileName); 268 if (!mimeType.isEmpty()) 269 FormDataBuilder::addContentTypeToMultiPartHeader(header, mimeType.latin1()); 270 } 226 FormDataBuilder::addFilenameToMultiPartHeader(header, encoding, name); 227 228 // Add the content type if it is available. 229 if (value.blob()->type().isEmpty()) 230 FormDataBuilder::addContentTypeToMultiPartHeader(header, value.blob()->type().latin1()); 271 231 } 272 232 … … 275 235 // Append body 276 236 appendData(header.data(), header.size()); 277 appendItem(value, shouldGenerateFile); 237 if (value.blob()) { 238 if (value.blob()->isFile()) { 239 // Do not add the file if the path is empty. 240 if (!static_cast<File*>(value.blob())->path().isEmpty()) 241 appendFile(static_cast<File*>(value.blob())->path(), shouldGenerateFile); 242 } 243 #if ENABLE(BLOB) 244 else 245 appendBlob(value.blob()->url()); 246 #endif 247 } else 248 appendData(value.data().data(), value.data().length()); 278 249 appendData("\r\n", 2); 279 250 } else { 280 251 // Omit the name "isindex" if it's the first form data element. 281 252 // FIXME: Why is this a good rule? Is this obsolete now? 282 const StringBlobItem* stringValue = value->toStringBlobItem(); 283 if (!stringValue) 284 continue; 285 if (encodedData.isEmpty() && key->cstr() == "isindex") 286 FormDataBuilder::encodeStringAsFormData(encodedData, stringValue->cstr()); 253 if (encodedData.isEmpty() && key.data() == "isindex") 254 FormDataBuilder::encodeStringAsFormData(encodedData, value.data()); 287 255 else 288 FormDataBuilder::addKeyValuePairAsFormData(encodedData, key ->cstr(), stringValue->cstr());256 FormDataBuilder::addKeyValuePairAsFormData(encodedData, key.data(), value.data()); 289 257 } 290 258 } -
trunk/WebCore/platform/network/FormData.h
r65786 r66452 29 29 namespace WebCore { 30 30 31 class BlobItem;32 31 class Document; 32 class FormDataList; 33 33 class TextEncoding; 34 typedef Vector<RefPtr<BlobItem> > BlobItemList;35 34 36 35 class FormDataElement { … … 63 62 String m_generatedFilename; 64 63 bool m_shouldGenerateFile; 65 66 #if ENABLE(BLOB)67 static const long long toEndOfFile;68 static const double doNotCheckFileChange;69 #endif70 64 }; 71 65 … … 102 96 static PassRefPtr<FormData> create(const CString&); 103 97 static PassRefPtr<FormData> create(const Vector<char>&); 104 static PassRefPtr<FormData> create(const BlobItemList&, const TextEncoding&);105 static PassRefPtr<FormData> createMultiPart(const BlobItemList&, const TextEncoding&, Document*);98 static PassRefPtr<FormData> create(const FormDataList&, const TextEncoding&); 99 static PassRefPtr<FormData> createMultiPart(const FormDataList&, const TextEncoding&, Document*); 106 100 PassRefPtr<FormData> copy() const; 107 101 PassRefPtr<FormData> deepCopy() const; … … 109 103 110 104 void appendData(const void* data, size_t); 111 void appendItems(const BlobItemList&); 112 void appendFile(const String& filename, bool shouldGenerateFile = false); 105 void appendFile(const String& filePath, bool shouldGenerateFile = false); 113 106 #if ENABLE(BLOB) 114 107 void appendFileRange(const String& filename, long long start, long long length, double expectedModificationTime, bool shouldGenerateFile = false); … … 138 131 FormData(const FormData&); 139 132 140 void appendItem(const BlobItem*, bool shouldGenerateFile); 141 void appendKeyValuePairItems(const BlobItemList&, const TextEncoding&, bool isMultiPartForm, Document*); 133 void appendKeyValuePairItems(const FormDataList&, const TextEncoding&, bool isMultiPartForm, Document*); 142 134 143 135 Vector<FormDataElement> m_elements; -
trunk/WebCore/platform/network/mac/FormDataStreamMac.mm
r64763 r66452 32 32 #import "FormDataStreamMac.h" 33 33 34 #import "BlobRegistryImpl.h" 34 35 #import "FileSystem.h" 35 36 #import "FormData.h" … … 142 143 form->currentStream = NULL; 143 144 #if ENABLE(BLOB) 144 form->currentStreamRangeLength = FormDataElement::toEndOfFile;145 form->currentStreamRangeLength = BlobDataItem::toEndOfFile; 145 146 #endif 146 147 } … … 170 171 #if ENABLE(BLOB) 171 172 // Check if the file has been changed or not if required. 172 if (nextInput.m_expectedFileModificationTime != FormDataElement::doNotCheckFileChange) {173 if (nextInput.m_expectedFileModificationTime != BlobDataItem::doNotCheckFileChange) { 173 174 time_t fileModificationTime; 174 175 if (!getFileModificationTime(nextInput.m_filename, fileModificationTime) || fileModificationTime != static_cast<time_t>(nextInput.m_expectedFileModificationTime)) … … 226 227 newInfo->currentStream = NULL; 227 228 #if ENABLE(BLOB) 228 newInfo->currentStreamRangeLength = FormDataElement::toEndOfFile;229 newInfo->currentStreamRangeLength = BlobDataItem::toEndOfFile; 229 230 #endif 230 231 newInfo->currentData = 0; … … 274 275 CFIndex bytesToRead = bufferLength; 275 276 #if ENABLE(BLOB) 276 if (form->currentStreamRangeLength != FormDataElement::toEndOfFile && form->currentStreamRangeLength < bytesToRead)277 if (form->currentStreamRangeLength != BlobDataItem::toEndOfFile && form->currentStreamRangeLength < bytesToRead) 277 278 bytesToRead = static_cast<CFIndex>(form->currentStreamRangeLength); 278 279 #endif … … 287 288 form->bytesSent += bytesRead; 288 289 #if ENABLE(BLOB) 289 if (form->currentStreamRangeLength != FormDataElement::toEndOfFile)290 if (form->currentStreamRangeLength != BlobDataItem::toEndOfFile) 290 291 form->currentStreamRangeLength -= bytesRead; 291 292 #endif … … 395 396 } 396 397 398 #if ENABLE(BLOB) 399 // Check if there is a blob in the form data. 400 bool hasBlob = false; 401 for (size_t i = 0; i < count; ++i) { 402 const FormDataElement& element = formData->elements()[i]; 403 if (element.m_type == FormDataElement::encodedBlob) { 404 hasBlob = true; 405 break; 406 } 407 } 408 409 // If yes, we have to resolve all the blob references and regenerate the form data with only data and file types. 410 if (hasBlob) { 411 RefPtr<FormData> newFormData = FormData::create(); 412 newFormData->setAlwaysStream(formData->alwaysStream()); 413 newFormData->setIdentifier(formData->identifier()); 414 for (size_t i = 0; i < count; ++i) { 415 const FormDataElement& element = formData->elements()[i]; 416 if (element.m_type == FormDataElement::data) 417 newFormData->appendData(element.m_data.data(), element.m_data.size()); 418 else if (element.m_type == FormDataElement::encodedFile) 419 newFormData->appendFile(element.m_filename, element.m_shouldGenerateFile); 420 else { 421 ASSERT(element.m_type == FormDataElement::encodedBlob); 422 RefPtr<BlobStorageData> blobData = static_cast<BlobRegistryImpl&>(blobRegistry()).getBlobDataFromURL(KURL(ParsedURLString, element.m_blobURL)); 423 if (blobData) { 424 for (size_t j = 0; j < blobData->items().size(); ++j) { 425 const BlobDataItem& blobItem = blobData->items()[j]; 426 if (blobItem.type == BlobDataItem::Data) { 427 newFormData->appendData(blobItem.data.data() + static_cast<int>(blobItem.offset), static_cast<int>(blobItem.length)); 428 } else { 429 ASSERT(blobItem.type == BlobDataItem::File); 430 newFormData->appendFileRange(blobItem.path, blobItem.offset, blobItem.length, blobItem.expectedModificationTime); 431 } 432 } 433 } 434 } 435 } 436 formData = newFormData; 437 count = formData->elements().size(); 438 } 439 #endif 440 397 441 // Precompute the content length so NSURLConnection doesn't use chunked mode. 398 442 long long length = 0; … … 404 448 #if ENABLE(BLOB) 405 449 // 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. 406 if (element.m_fileLength != FormDataElement::toEndOfFile) {450 if (element.m_fileLength != BlobDataItem::toEndOfFile) { 407 451 length += element.m_fileLength; 408 452 continue; -
trunk/WebCore/xml/XMLHttpRequest.cpp
r66243 r66452 523 523 // FIXME: add support for uploading bundles. 524 524 m_requestEntityBody = FormData::create(); 525 m_requestEntityBody->append Items(body->items());525 m_requestEntityBody->appendBlob(body->url()); 526 526 } 527 527 … … 535 535 536 536 if (m_method != "GET" && m_method != "HEAD" && m_url.protocolInHTTPFamily()) { 537 m_requestEntityBody = FormData::createMultiPart( body->items(), body->encoding(), document());537 m_requestEntityBody = FormData::createMultiPart(*(static_cast<FormDataList*>(body)), body->encoding(), document()); 538 538 539 539 // We need to ask the client to provide the generated file names if needed. When FormData fills the element -
trunk/WebKit/chromium/ChangeLog
r66450 r66452 1 2010-08-31 Jian Li <jianli@chromium.org> 2 3 Reviewed by Darin Fisher. 4 5 Switch the Blob implementation to using the blob data registration model 6 https://bugs.webkit.org/show_bug.cgi?id=44389 7 8 * src/WebSearchableFormData.cpp: 9 (WebCore::HasSuitableTextElement): 10 1 11 2010-08-30 Nat Duca <nduca@chromium.org> 2 12 -
trunk/WebKit/chromium/src/WebSearchableFormData.cpp
r60799 r66452 188 188 continue; 189 189 190 const BlobItemList& items = dataList.items();190 const Vector<FormDataList::Item>& items = dataList.items(); 191 191 if (isTextElement && !items.isEmpty()) { 192 192 if (textElement) { … … 197 197 textElement = static_cast<HTMLInputElement*>(formElement); 198 198 } 199 for (BlobItemList::const_iterator j(items.begin()); j != items.end(); ++j) { 200 const StringBlobItem* item = (*j)->toStringBlobItem(); 201 ASSERT(item); 199 for (Vector<FormDataList::Item>::const_iterator j(items.begin()); j != items.end(); ++j) { 202 200 // Handle ISINDEX / <input name=isindex> specially, but only if it's 203 201 // the first entry. 204 if (!encodedString->isEmpty() || item->cstr() != "isindex") {202 if (!encodedString->isEmpty() || j->data() != "isindex") { 205 203 if (!encodedString->isEmpty()) 206 204 encodedString->append('&'); 207 FormDataBuilder::encodeStringAsFormData(*encodedString, item->cstr());205 FormDataBuilder::encodeStringAsFormData(*encodedString, j->data()); 208 206 encodedString->append('='); 209 207 } … … 212 210 encodedString->append("{searchTerms}", 13); 213 211 else 214 FormDataBuilder::encodeStringAsFormData(*encodedString, item->cstr());212 FormDataBuilder::encodeStringAsFormData(*encodedString, j->data()); 215 213 } 216 214 }
Note: See TracChangeset
for help on using the changeset viewer.