summaryrefslogtreecommitdiff
path: root/Source/WebCore/fileapi
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/fileapi')
-rw-r--r--Source/WebCore/fileapi/AsyncFileStream.cpp73
-rw-r--r--Source/WebCore/fileapi/AsyncFileStream.h9
-rw-r--r--Source/WebCore/fileapi/Blob.cpp73
-rw-r--r--Source/WebCore/fileapi/Blob.h11
-rw-r--r--Source/WebCore/fileapi/Blob.idl7
-rw-r--r--Source/WebCore/fileapi/File.cpp17
-rw-r--r--Source/WebCore/fileapi/File.h7
-rw-r--r--Source/WebCore/fileapi/File.idl4
-rw-r--r--Source/WebCore/fileapi/FileError.idl3
-rw-r--r--Source/WebCore/fileapi/FileException.idl4
-rw-r--r--Source/WebCore/fileapi/FileList.idl6
-rw-r--r--Source/WebCore/fileapi/FileReader.cpp2
-rw-r--r--Source/WebCore/fileapi/FileReader.idl32
-rw-r--r--Source/WebCore/fileapi/FileReaderLoader.cpp80
-rw-r--r--Source/WebCore/fileapi/FileReaderLoader.h16
-rw-r--r--Source/WebCore/fileapi/FileReaderSync.idl13
-rw-r--r--Source/WebCore/fileapi/FileThread.cpp6
-rw-r--r--Source/WebCore/fileapi/ThreadableBlobRegistry.cpp2
-rw-r--r--Source/WebCore/fileapi/WebKitBlobBuilder.cpp8
-rw-r--r--Source/WebCore/fileapi/WebKitBlobBuilder.h4
20 files changed, 268 insertions, 109 deletions
diff --git a/Source/WebCore/fileapi/AsyncFileStream.cpp b/Source/WebCore/fileapi/AsyncFileStream.cpp
index e948a7a42..64252670d 100644
--- a/Source/WebCore/fileapi/AsyncFileStream.cpp
+++ b/Source/WebCore/fileapi/AsyncFileStream.cpp
@@ -36,32 +36,47 @@
#include "AsyncFileStream.h"
#include "Blob.h"
-#include "CrossThreadTask.h"
#include "FileStream.h"
#include "FileStreamClient.h"
#include "FileThread.h"
#include "FileThreadTask.h"
-#include "ScriptExecutionContext.h"
+#include "MainThreadTask.h"
+#include <wtf/MainThread.h>
#include <wtf/text/WTFString.h>
namespace WebCore {
-inline AsyncFileStream::AsyncFileStream(ScriptExecutionContext* context, FileStreamClient* client)
- : m_context(context)
- , m_stream(FileStream::create())
+static PassRefPtr<FileThread> createFileThread()
+{
+ RefPtr<FileThread> thread = FileThread::create();
+ if (!thread->start())
+ return 0;
+ return thread.release();
+}
+
+static FileThread* fileThread()
+{
+ ASSERT(isMainThread());
+ static FileThread* thread = createFileThread().leakRef();
+ return thread;
+}
+
+inline AsyncFileStream::AsyncFileStream(FileStreamClient* client)
+ : m_stream(FileStream::create())
, m_client(client)
{
+ ASSERT(isMainThread());
}
-PassRefPtr<AsyncFileStream> AsyncFileStream::create(ScriptExecutionContext* context, FileStreamClient* client)
+PassRefPtr<AsyncFileStream> AsyncFileStream::create(FileStreamClient* client)
{
- RefPtr<AsyncFileStream> proxy = adoptRef(new AsyncFileStream(context, client));
+ RefPtr<AsyncFileStream> proxy = adoptRef(new AsyncFileStream(client));
// Hold a reference so that the instance will not get deleted while there are tasks on the file thread.
// This is balanced by the deref in derefProxyOnContext below.
proxy->ref();
- proxy->fileThread()->postTask(createFileThreadTask(proxy.get(), &AsyncFileStream::startOnFileThread));
+ fileThread()->postTask(createFileThreadTask(proxy.get(), &AsyncFileStream::startOnFileThread));
return proxy.release();
}
@@ -70,14 +85,7 @@ AsyncFileStream::~AsyncFileStream()
{
}
-FileThread* AsyncFileStream::fileThread()
-{
- ASSERT(m_context->isContextThread());
- ASSERT(m_context->fileThread());
- return m_context->fileThread();
-}
-
-static void didStart(ScriptExecutionContext*, AsyncFileStream* proxy)
+static void didStart(AsyncFileStream* proxy)
{
if (proxy->client())
proxy->client()->didStart();
@@ -85,22 +93,23 @@ static void didStart(ScriptExecutionContext*, AsyncFileStream* proxy)
void AsyncFileStream::startOnFileThread()
{
- if (!client())
+ // FIXME: It is not correct to check m_client from a secondary thread - stop() could be racing with this check.
+ if (!m_client)
return;
m_stream->start();
- m_context->postTask(createCallbackTask(&didStart, AllowCrossThreadAccess(this)));
+ callOnMainThread(didStart, AllowCrossThreadAccess(this));
}
void AsyncFileStream::stop()
{
- // Clear the client so that we won't be calling callbacks on the client.
+ // Clear the client so that we won't be invoking callbacks on the client.
setClient(0);
fileThread()->unscheduleTasks(m_stream.get());
fileThread()->postTask(createFileThreadTask(this, &AsyncFileStream::stopOnFileThread));
}
-static void derefProxyOnContext(ScriptExecutionContext*, AsyncFileStream* proxy)
+static void derefProxyOnMainThread(AsyncFileStream* proxy)
{
ASSERT(proxy->hasOneRef());
proxy->deref();
@@ -109,10 +118,10 @@ static void derefProxyOnContext(ScriptExecutionContext*, AsyncFileStream* proxy)
void AsyncFileStream::stopOnFileThread()
{
m_stream->stop();
- m_context->postTask(createCallbackTask(&derefProxyOnContext, AllowCrossThreadAccess(this)));
+ callOnMainThread(derefProxyOnMainThread, AllowCrossThreadAccess(this));
}
-static void didGetSize(ScriptExecutionContext*, AsyncFileStream* proxy, long long size)
+static void didGetSize(AsyncFileStream* proxy, long long size)
{
if (proxy->client())
proxy->client()->didGetSize(size);
@@ -126,10 +135,10 @@ void AsyncFileStream::getSize(const String& path, double expectedModificationTim
void AsyncFileStream::getSizeOnFileThread(const String& path, double expectedModificationTime)
{
long long size = m_stream->getSize(path, expectedModificationTime);
- m_context->postTask(createCallbackTask(&didGetSize, AllowCrossThreadAccess(this), size));
+ callOnMainThread(didGetSize, AllowCrossThreadAccess(this), size);
}
-static void didOpen(ScriptExecutionContext*, AsyncFileStream* proxy, bool success)
+static void didOpen(AsyncFileStream* proxy, bool success)
{
if (proxy->client())
proxy->client()->didOpen(success);
@@ -143,7 +152,7 @@ void AsyncFileStream::openForRead(const String& path, long long offset, long lon
void AsyncFileStream::openForReadOnFileThread(const String& path, long long offset, long long length)
{
bool success = m_stream->openForRead(path, offset, length);
- m_context->postTask(createCallbackTask(&didOpen, AllowCrossThreadAccess(this), success));
+ callOnMainThread(didOpen, AllowCrossThreadAccess(this), success);
}
void AsyncFileStream::openForWrite(const String& path)
@@ -156,7 +165,7 @@ void AsyncFileStream::openForWrite(const String& path)
void AsyncFileStream::openForWriteOnFileThread(const String& path)
{
bool success = m_stream->openForWrite(path);
- m_context->postTask(createCallbackTask(&didOpen, AllowCrossThreadAccess(this), success));
+ callOnMainThread(didOpen, AllowCrossThreadAccess(this), success);
}
void AsyncFileStream::close()
@@ -169,7 +178,7 @@ void AsyncFileStream::closeOnFileThread()
m_stream->close();
}
-static void didRead(ScriptExecutionContext*, AsyncFileStream* proxy, int bytesRead)
+static void didRead(AsyncFileStream* proxy, int bytesRead)
{
if (proxy->client())
proxy->client()->didRead(bytesRead);
@@ -185,10 +194,10 @@ void AsyncFileStream::read(char* buffer, int length)
void AsyncFileStream::readOnFileThread(char* buffer, int length)
{
int bytesRead = m_stream->read(buffer, length);
- m_context->postTask(createCallbackTask(&didRead, AllowCrossThreadAccess(this), bytesRead));
+ callOnMainThread(didRead, AllowCrossThreadAccess(this), bytesRead);
}
-static void didWrite(ScriptExecutionContext*, AsyncFileStream* proxy, int bytesWritten)
+static void didWrite(AsyncFileStream* proxy, int bytesWritten)
{
if (proxy->client())
proxy->client()->didWrite(bytesWritten);
@@ -202,10 +211,10 @@ void AsyncFileStream::write(const KURL& blobURL, long long position, int length)
void AsyncFileStream::writeOnFileThread(const KURL& blobURL, long long position, int length)
{
int bytesWritten = m_stream->write(blobURL, position, length);
- m_context->postTask(createCallbackTask(&didWrite, AllowCrossThreadAccess(this), bytesWritten));
+ callOnMainThread(didWrite, AllowCrossThreadAccess(this), bytesWritten);
}
-static void didTruncate(ScriptExecutionContext*, AsyncFileStream* proxy, bool success)
+static void didTruncate(AsyncFileStream* proxy, bool success)
{
if (proxy->client())
proxy->client()->didTruncate(success);
@@ -219,7 +228,7 @@ void AsyncFileStream::truncate(long long position)
void AsyncFileStream::truncateOnFileThread(long long position)
{
bool success = m_stream->truncate(position);
- m_context->postTask(createCallbackTask(&didTruncate, AllowCrossThreadAccess(this), success));
+ callOnMainThread(didTruncate, AllowCrossThreadAccess(this), success);
}
} // namespace WebCore
diff --git a/Source/WebCore/fileapi/AsyncFileStream.h b/Source/WebCore/fileapi/AsyncFileStream.h
index 04be2db0c..68f23e99c 100644
--- a/Source/WebCore/fileapi/AsyncFileStream.h
+++ b/Source/WebCore/fileapi/AsyncFileStream.h
@@ -42,13 +42,11 @@ namespace WebCore {
class FileStreamClient;
class FileStream;
-class FileThread;
class KURL;
-class ScriptExecutionContext;
class AsyncFileStream : public RefCounted<AsyncFileStream> {
public:
- static PassRefPtr<AsyncFileStream> create(ScriptExecutionContext*, FileStreamClient*);
+ static PassRefPtr<AsyncFileStream> create(FileStreamClient*);
~AsyncFileStream();
void getSize(const String& path, double expectedModificationTime);
@@ -67,9 +65,7 @@ public:
void setClient(FileStreamClient* client) { m_client = client; }
private:
- AsyncFileStream(ScriptExecutionContext*, FileStreamClient*);
-
- FileThread* fileThread();
+ AsyncFileStream(FileStreamClient*);
// Called on File thread.
void startOnFileThread();
@@ -82,7 +78,6 @@ private:
void writeOnFileThread(const KURL& blobURL, long long position, int length);
void truncateOnFileThread(long long position);
- RefPtr<ScriptExecutionContext> m_context;
RefPtr<FileStream> m_stream;
FileStreamClient* m_client;
diff --git a/Source/WebCore/fileapi/Blob.cpp b/Source/WebCore/fileapi/Blob.cpp
index 291a22729..7640f5f50 100644
--- a/Source/WebCore/fileapi/Blob.cpp
+++ b/Source/WebCore/fileapi/Blob.cpp
@@ -37,6 +37,7 @@
#include "ScriptCallStack.h"
#include "ScriptExecutionContext.h"
#include "ThreadableBlobRegistry.h"
+#include <wtf/text/CString.h>
namespace WebCore {
@@ -73,7 +74,7 @@ Blob::Blob(PassOwnPtr<BlobData> blobData, long long size)
}
Blob::Blob(const KURL& srcURL, const String& type, long long size)
- : m_type(type)
+ : m_type(Blob::normalizedContentType(type))
, m_size(size)
{
// Create a new internal URL and register it with the same blob data as the source URL.
@@ -86,6 +87,74 @@ Blob::~Blob()
ThreadableBlobRegistry::unregisterBlobURL(m_internalURL);
}
+bool Blob::isValidContentType(const String& contentType)
+{
+ if (contentType.isNull())
+ return true;
+
+ size_t length = contentType.length();
+ if (contentType.is8Bit()) {
+ const LChar* characters = contentType.characters8();
+ for (size_t i = 0; i < length; ++i) {
+ if (characters[i] < 0x20 || characters[i] > 0x7e)
+ return false;
+ }
+ } else {
+ const UChar* characters = contentType.characters16();
+ for (size_t i = 0; i < length; ++i) {
+ if (characters[i] < 0x20 || characters[i] > 0x7e)
+ return false;
+ }
+ }
+ return true;
+}
+
+String Blob::normalizedContentType(const String& contentType)
+{
+ if (Blob::isValidContentType(contentType))
+ return contentType.lower();
+ return emptyString();
+}
+
+bool Blob::isNormalizedContentType(const String& contentType)
+{
+ if (contentType.isNull())
+ return true;
+
+ size_t length = contentType.length();
+ if (contentType.is8Bit()) {
+ const LChar* characters = contentType.characters8();
+ for (size_t i = 0; i < length; ++i) {
+ if (characters[i] < 0x20 || characters[i] > 0x7e)
+ return false;
+ if (characters[i] >= 'A' && characters[i] <= 'Z')
+ return false;
+ }
+ } else {
+ const UChar* characters = contentType.characters16();
+ for (size_t i = 0; i < length; ++i) {
+ if (characters[i] < 0x20 || characters[i] > 0x7e)
+ return false;
+ if (characters[i] >= 'A' && characters[i] <= 'Z')
+ return false;
+ }
+ }
+ return true;
+}
+
+bool Blob::isNormalizedContentType(const CString& contentType)
+{
+ size_t length = contentType.length();
+ const char* characters = contentType.data();
+ for (size_t i = 0; i < length; ++i) {
+ if (characters[i] < 0x20 || characters[i] > 0x7e)
+ return false;
+ if (characters[i] >= 'A' && characters[i] <= 'Z')
+ return false;
+ }
+ return true;
+}
+
#if ENABLE(BLOB)
PassRefPtr<Blob> Blob::slice(long long start, long long end, const String& contentType) const
{
@@ -122,7 +191,7 @@ PassRefPtr<Blob> Blob::slice(long long start, long long end, const String& conte
long long length = end - start;
OwnPtr<BlobData> blobData = BlobData::create();
- blobData->setContentType(contentType);
+ blobData->setContentType(Blob::normalizedContentType(contentType));
if (isFile()) {
#if ENABLE(FILE_SYSTEM)
if (!toFile(this)->fileSystemURL().isEmpty())
diff --git a/Source/WebCore/fileapi/Blob.h b/Source/WebCore/fileapi/Blob.h
index f4a01af89..bf4a2851d 100644
--- a/Source/WebCore/fileapi/Blob.h
+++ b/Source/WebCore/fileapi/Blob.h
@@ -37,7 +37,6 @@
#include <wtf/PassOwnPtr.h>
#include <wtf/PassRefPtr.h>
#include <wtf/RefCounted.h>
-#include <wtf/Vector.h>
#include <wtf/text/WTFString.h>
namespace WebCore {
@@ -59,6 +58,7 @@ public:
// For deserialization.
static PassRefPtr<Blob> create(const KURL& srcURL, const String& type, long long size)
{
+ ASSERT(Blob::isNormalizedContentType(type));
return adoptRef(new Blob(srcURL, type, size));
}
@@ -70,6 +70,14 @@ public:
virtual unsigned long long size() const { return static_cast<unsigned long long>(m_size); }
virtual bool isFile() const { return false; }
+ // The checks described in the File API spec.
+ static bool isValidContentType(const String&);
+ // The normalization procedure described in the File API spec.
+ static String normalizedContentType(const String&);
+ // Intended for use in ASSERT statements.
+ static bool isNormalizedContentType(const String&);
+ static bool isNormalizedContentType(const CString&);
+
#if ENABLE(BLOB)
PassRefPtr<Blob> slice(long long start = 0, long long end = std::numeric_limits<long long>::max(), const String& contentType = String()) const;
#endif
@@ -93,3 +101,4 @@ protected:
} // namespace WebCore
#endif // Blob_h
+
diff --git a/Source/WebCore/fileapi/Blob.idl b/Source/WebCore/fileapi/Blob.idl
index 15babb788..17cd5e2ba 100644
--- a/Source/WebCore/fileapi/Blob.idl
+++ b/Source/WebCore/fileapi/Blob.idl
@@ -29,18 +29,19 @@
*/
[
- JSGenerateIsReachable=Impl,
+ GlobalContext=DOMWindow&WorkerGlobalScope,
+ GenerateIsReachable=Impl,
CustomToJSObject,
JSNoStaticTables,
CustomConstructor,
- ConstructorParameters=2
+ CustomConstructor(sequence<any> blobParts, optional BlobPropertyBag options)
] interface Blob {
readonly attribute unsigned long long size;
readonly attribute DOMString type;
#if !defined(LANGUAGE_OBJECTIVE_C)
#if defined(ENABLE_BLOB) && ENABLE_BLOB
- Blob slice(in [Optional] long long start, in [Optional] long long end, in [Optional, TreatNullAs=NullString, TreatUndefinedAs=NullString] DOMString contentType);
+ Blob slice(optional long long start, optional long long end, [TreatNullAs=NullString, TreatUndefinedAs=NullString] optional DOMString contentType);
#endif
#endif
};
diff --git a/Source/WebCore/fileapi/File.cpp b/Source/WebCore/fileapi/File.cpp
index 692bde1ac..54e5a9001 100644
--- a/Source/WebCore/fileapi/File.cpp
+++ b/Source/WebCore/fileapi/File.cpp
@@ -20,7 +20,7 @@
* 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.
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
@@ -30,6 +30,7 @@
#include "FileSystem.h"
#include "MIMETypeRegistry.h"
#include <wtf/CurrentTime.h>
+#include <wtf/DateMath.h>
#include <wtf/text/WTFString.h>
namespace WebCore {
@@ -52,6 +53,7 @@ static String getContentTypeFromFileName(const String& name, File::ContentTypeLo
static PassOwnPtr<BlobData> createBlobDataForFileWithType(const String& path, const String& contentType)
{
OwnPtr<BlobData> blobData = BlobData::create();
+ ASSERT(Blob::isNormalizedContentType(contentType));
blobData->setContentType(contentType);
blobData->appendFile(path);
return blobData.release();
@@ -116,7 +118,7 @@ File::File(const String& path, const KURL& url, const String& type)
m_name = pathGetFileName(path);
// FIXME: File object serialization/deserialization does not include
// newer file object data members: m_name and m_relativePath.
- // See SerializedScriptValue.cpp for js and v8.
+ // See SerializedScriptValue.cpp
}
File::File(const String& path, const String& name, ContentTypeLookupPolicy policy)
@@ -152,16 +154,15 @@ File::File(const KURL& fileSystemURL, const FileMetadata& metadata)
double File::lastModifiedDate() const
{
#if ENABLE(FILE_SYSTEM)
- if (hasValidSnapshotMetadata())
- return m_snapshotModificationTime * 1000.0;
+ if (hasValidSnapshotMetadata() && isValidFileTime(m_snapshotModificationTime))
+ return m_snapshotModificationTime * msPerSecond;
#endif
time_t modificationTime;
- if (!getFileModificationTime(m_path, modificationTime))
- return invalidFileTime();
+ if (getFileModificationTime(m_path, modificationTime) && isValidFileTime(modificationTime))
+ return modificationTime * msPerSecond;
- // Needs to return epoch time in milliseconds for Date.
- return modificationTime * 1000.0;
+ return currentTime() * msPerSecond;
}
unsigned long long File::size() const
diff --git a/Source/WebCore/fileapi/File.h b/Source/WebCore/fileapi/File.h
index d466adce8..abe5544e3 100644
--- a/Source/WebCore/fileapi/File.h
+++ b/Source/WebCore/fileapi/File.h
@@ -28,7 +28,6 @@
#include "Blob.h"
#include <wtf/PassRefPtr.h>
-#include <wtf/RefCounted.h>
#include <wtf/text/WTFString.h>
namespace WebCore {
@@ -91,7 +90,7 @@ public:
const String& path() const { return m_path; }
const String& name() const { return m_name; }
- // This may return NaN (which is converted to null Date in javascript layer) if getFileModificationTime() platform call has failed or the information is not available.
+ // This returns the current date and time if the file's last modifiecation date is not known (per spec: http://www.w3.org/TR/FileAPI/#dfn-lastModifiedDate).
double lastModifiedDate() const;
#if ENABLE(DIRECTORY_UPLOAD)
@@ -136,13 +135,13 @@ private:
inline File* toFile(Blob* blob)
{
- ASSERT(!blob || blob->isFile());
+ ASSERT_WITH_SECURITY_IMPLICATION(!blob || blob->isFile());
return static_cast<File*>(blob);
}
inline const File* toFile(const Blob* blob)
{
- ASSERT(!blob || blob->isFile());
+ ASSERT_WITH_SECURITY_IMPLICATION(!blob || blob->isFile());
return static_cast<const File*>(blob);
}
diff --git a/Source/WebCore/fileapi/File.idl b/Source/WebCore/fileapi/File.idl
index ddfb9a24e..1d9dc51fc 100644
--- a/Source/WebCore/fileapi/File.idl
+++ b/Source/WebCore/fileapi/File.idl
@@ -32,8 +32,6 @@
#if !defined(LANGUAGE_GOBJECT) || !LANGUAGE_GOBJECT
readonly attribute Date lastModifiedDate;
#endif
-#if defined(ENABLE_DIRECTORY_UPLOAD) && ENABLE_DIRECTORY_UPLOAD
- readonly attribute DOMString webkitRelativePath;
-#endif
+ [Conditional=DIRECTORY_UPLOAD] readonly attribute DOMString webkitRelativePath;
};
diff --git a/Source/WebCore/fileapi/FileError.idl b/Source/WebCore/fileapi/FileError.idl
index 70a2768d5..c588100d0 100644
--- a/Source/WebCore/fileapi/FileError.idl
+++ b/Source/WebCore/fileapi/FileError.idl
@@ -30,7 +30,8 @@
[
Conditional=BLOB|FILE_SYSTEM,
- JSNoStaticTables
+ JSNoStaticTables,
+ ImplementationLacksVTable
] interface FileError {
#if !defined(LANGUAGE_OBJECTIVE_C)
// FIXME: Some of constant names are already defined in DOMException.h for Objective-C binding and we cannot have the same names here (they are translated into a enum in the same namespace).
diff --git a/Source/WebCore/fileapi/FileException.idl b/Source/WebCore/fileapi/FileException.idl
index 6059d22aa..97ca308c7 100644
--- a/Source/WebCore/fileapi/FileException.idl
+++ b/Source/WebCore/fileapi/FileException.idl
@@ -29,9 +29,11 @@
*/
[
+ NoInterfaceObject,
Conditional=BLOB|FILE_SYSTEM,
DoNotCheckConstants,
- JSNoStaticTables
+ JSNoStaticTables,
+ ImplementationLacksVTable
] exception FileException {
readonly attribute unsigned short code;
diff --git a/Source/WebCore/fileapi/FileList.idl b/Source/WebCore/fileapi/FileList.idl
index 6b790f73f..f0d4ce482 100644
--- a/Source/WebCore/fileapi/FileList.idl
+++ b/Source/WebCore/fileapi/FileList.idl
@@ -24,10 +24,10 @@
*/
[
- IndexedGetter,
- JSNoStaticTables
+ JSNoStaticTables,
+ ImplementationLacksVTable
] interface FileList {
readonly attribute unsigned long length;
- File item(in unsigned long index);
+ getter File item(unsigned long index);
};
diff --git a/Source/WebCore/fileapi/FileReader.cpp b/Source/WebCore/fileapi/FileReader.cpp
index 128eb645c..bf8c33d96 100644
--- a/Source/WebCore/fileapi/FileReader.cpp
+++ b/Source/WebCore/fileapi/FileReader.cpp
@@ -56,7 +56,7 @@ PassRefPtr<FileReader> FileReader::create(ScriptExecutionContext* context)
}
FileReader::FileReader(ScriptExecutionContext* context)
- : ActiveDOMObject(context, this)
+ : ActiveDOMObject(context)
, m_state(EMPTY)
, m_aborting(false)
, m_readType(FileReaderLoader::ReadAsBinaryString)
diff --git a/Source/WebCore/fileapi/FileReader.idl b/Source/WebCore/fileapi/FileReader.idl
index 14baf07b4..0d5af4f27 100644
--- a/Source/WebCore/fileapi/FileReader.idl
+++ b/Source/WebCore/fileapi/FileReader.idl
@@ -30,10 +30,11 @@
*/
[
+ GlobalContext=DOMWindow&WorkerGlobalScope,
Conditional=BLOB,
ActiveDOMObject,
Constructor,
- CallWith=ScriptExecutionContext,
+ ConstructorCallWith=ScriptExecutionContext,
EventTarget,
JSNoStaticTables
] interface FileReader {
@@ -44,31 +45,26 @@
readonly attribute unsigned short readyState;
// async read methods
- void readAsArrayBuffer(in Blob blob)
- raises(DOMException);
- void readAsBinaryString(in Blob blob)
- raises(DOMException);
- void readAsText(in Blob blob, in [Optional] DOMString encoding)
- raises(DOMException);
- void readAsDataURL(in Blob blob)
- raises(DOMException);
+ [RaisesException] void readAsArrayBuffer(Blob blob);
+ [RaisesException] void readAsBinaryString(Blob blob);
+ [RaisesException] void readAsText(Blob blob, optional DOMString encoding);
+ [RaisesException] void readAsDataURL(Blob blob);
void abort();
// file data
- [Custom] readonly attribute DOMObject result;
+ [Custom] readonly attribute any result;
readonly attribute FileError error;
// EventTarget interface
- void addEventListener(in DOMString type,
- in EventListener listener,
- in [Optional] boolean useCapture);
- void removeEventListener(in DOMString type,
- in EventListener listener,
- in [Optional] boolean useCapture);
- boolean dispatchEvent(in Event evt)
- raises(EventException);
+ void addEventListener(DOMString type,
+ EventListener listener,
+ optional boolean useCapture);
+ void removeEventListener(DOMString type,
+ EventListener listener,
+ optional boolean useCapture);
+ [RaisesException] boolean dispatchEvent(Event evt);
attribute EventListener onloadstart;
attribute EventListener onprogress;
diff --git a/Source/WebCore/fileapi/FileReaderLoader.cpp b/Source/WebCore/fileapi/FileReaderLoader.cpp
index f24cdc82f..77c05fe81 100644
--- a/Source/WebCore/fileapi/FileReaderLoader.cpp
+++ b/Source/WebCore/fileapi/FileReaderLoader.cpp
@@ -54,13 +54,19 @@ using namespace std;
namespace WebCore {
+const int defaultBufferLength = 32768;
+
FileReaderLoader::FileReaderLoader(ReadType readType, FileReaderLoaderClient* client)
: m_readType(readType)
, m_client(client)
, m_isRawDataConverted(false)
, m_stringResult("")
+ , m_variableLength(false)
, m_bytesLoaded(0)
, m_totalBytes(0)
+ , m_hasRange(false)
+ , m_rangeStart(0)
+ , m_rangeEnd(0)
, m_errorCode(0)
{
}
@@ -85,6 +91,8 @@ void FileReaderLoader::start(ScriptExecutionContext* scriptExecutionContext, Blo
// Construct and load the request.
ResourceRequest request(m_urlForReading);
request.setHTTPMethod("GET");
+ if (m_hasRange)
+ request.setHTTPHeaderField("Range", String::format("bytes=%d-%d", m_rangeStart, m_rangeEnd));
ThreadableLoaderOptions options;
options.sendLoadCallbacks = SendCallbacks;
@@ -133,6 +141,16 @@ void FileReaderLoader::didReceiveResponse(unsigned long, const ResourceResponse&
unsigned long long length = response.expectedContentLength();
+ // A value larger than INT_MAX means that the content length wasn't
+ // specified, so the buffer will need to be dynamically grown.
+ if (length > INT_MAX) {
+ m_variableLength = true;
+ if (m_hasRange)
+ length = 1 + m_rangeEnd - m_rangeStart;
+ else
+ length = defaultBufferLength;
+ }
+
// Check that we can cast to unsigned since we have to do
// so to call ArrayBuffer's create function.
// FIXME: Support reading more than the current size limit of ArrayBuffer.
@@ -166,8 +184,25 @@ void FileReaderLoader::didReceiveData(const char* data, int dataLength)
int length = dataLength;
unsigned remainingBufferSpace = m_totalBytes - m_bytesLoaded;
- if (length > static_cast<long long>(remainingBufferSpace))
- length = static_cast<int>(remainingBufferSpace);
+ if (length > static_cast<long long>(remainingBufferSpace)) {
+ // If the buffer has hit maximum size, it can't be grown any more.
+ if (m_totalBytes >= numeric_limits<unsigned>::max()) {
+ failed(FileError::NOT_READABLE_ERR);
+ return;
+ }
+ if (m_variableLength) {
+ unsigned long long newLength = m_totalBytes * 2;
+ if (newLength > numeric_limits<unsigned>::max())
+ newLength = numeric_limits<unsigned>::max();
+ RefPtr<ArrayBuffer> newData =
+ ArrayBuffer::create(static_cast<unsigned>(newLength), 1);
+ memcpy(static_cast<char*>(newData->data()), static_cast<char*>(m_rawData->data()), m_bytesLoaded);
+
+ m_rawData = newData;
+ m_totalBytes = static_cast<unsigned>(newLength);
+ } else
+ length = remainingBufferSpace;
+ }
if (length <= 0)
return;
@@ -183,6 +218,12 @@ void FileReaderLoader::didReceiveData(const char* data, int dataLength)
void FileReaderLoader::didFinishLoading(unsigned long, double)
{
+ if (m_variableLength && m_totalBytes > m_bytesLoaded) {
+ RefPtr<ArrayBuffer> newData = m_rawData->slice(0, m_bytesLoaded);
+
+ m_rawData = newData;
+ m_totalBytes = m_bytesLoaded;
+ }
cleanup();
if (m_client)
m_client->didFinishLoading();
@@ -233,9 +274,32 @@ PassRefPtr<ArrayBuffer> FileReaderLoader::arrayBufferResult() const
return ArrayBuffer::create(m_rawData.get());
}
+#if ENABLE(STREAM)
+PassRefPtr<Blob> FileReaderLoader::blobResult()
+{
+ ASSERT(m_readType == ReadAsBlob);
+
+ // If the loading is not finished or an error occurs, return an empty result.
+ if (!m_rawData || m_errorCode || !isCompleted())
+ return 0;
+
+ if (!m_blobResult) {
+ OwnPtr<BlobData> blobData = BlobData::create();
+ size_t size = 0;
+ RefPtr<RawData> rawData = RawData::create();
+ size = m_rawData->byteLength();
+ rawData->mutableData()->append(static_cast<char*>(m_rawData->data()), size);
+ blobData->appendData(rawData, 0, size);
+ blobData->setContentType(m_dataType);
+ m_blobResult = Blob::create(blobData.release(), size);
+ }
+ return m_blobResult;
+}
+#endif // ENABLE(STREAM)
+
String FileReaderLoader::stringResult()
{
- ASSERT(m_readType != ReadAsArrayBuffer);
+ ASSERT(m_readType != ReadAsArrayBuffer && m_readType != ReadAsBlob);
// If the loading is not started or an error occurs, return an empty result.
if (!m_rawData || m_errorCode)
@@ -320,6 +384,16 @@ void FileReaderLoader::setEncoding(const String& encoding)
m_encoding = TextEncoding(encoding);
}
+#if ENABLE(STREAM)
+void FileReaderLoader::setRange(unsigned start, unsigned length)
+{
+ ASSERT(length > 0);
+ m_hasRange = true;
+ m_rangeStart = start;
+ m_rangeEnd = start + length - 1;
+}
+#endif // ENABLE(STREAM)
+
} // namespace WebCore
#endif // ENABLE(BLOB)
diff --git a/Source/WebCore/fileapi/FileReaderLoader.h b/Source/WebCore/fileapi/FileReaderLoader.h
index 34f54387b..ec1bdfdb2 100644
--- a/Source/WebCore/fileapi/FileReaderLoader.h
+++ b/Source/WebCore/fileapi/FileReaderLoader.h
@@ -53,6 +53,7 @@ public:
enum ReadType {
ReadAsArrayBuffer,
ReadAsBinaryString,
+ ReadAsBlob,
ReadAsText,
ReadAsDataURL
};
@@ -72,13 +73,19 @@ public:
String stringResult();
PassRefPtr<ArrayBuffer> arrayBufferResult() const;
+#if ENABLE(STREAM)
+ PassRefPtr<Blob> blobResult();
+#endif // ENABLE(STREAM)
unsigned bytesLoaded() const { return m_bytesLoaded; }
unsigned totalBytes() const { return m_totalBytes; }
int errorCode() const { return m_errorCode; }
void setEncoding(const String&);
void setDataType(const String& dataType) { m_dataType = dataType; }
-
+#if ENABLE(STREAM)
+ void setRange(unsigned, unsigned);
+#endif // ENABLE(STREAM)
+
private:
void terminate();
void cleanup();
@@ -102,12 +109,19 @@ private:
bool m_isRawDataConverted;
String m_stringResult;
+ RefPtr<Blob> m_blobResult;
// The decoder used to decode the text data.
RefPtr<TextResourceDecoder> m_decoder;
+ bool m_variableLength;
unsigned m_bytesLoaded;
unsigned m_totalBytes;
+
+ bool m_hasRange;
+ unsigned m_rangeStart;
+ unsigned m_rangeEnd;
+
int m_errorCode;
};
diff --git a/Source/WebCore/fileapi/FileReaderSync.idl b/Source/WebCore/fileapi/FileReaderSync.idl
index bc3f86def..8ef0f6a56 100644
--- a/Source/WebCore/fileapi/FileReaderSync.idl
+++ b/Source/WebCore/fileapi/FileReaderSync.idl
@@ -29,16 +29,13 @@
*/
[
+ GlobalContext=WorkerGlobalScope,
Conditional=BLOB,
Constructor,
JSNoStaticTables
] interface FileReaderSync {
- [CallWith=ScriptExecutionContext] ArrayBuffer readAsArrayBuffer(in Blob blob)
- raises(FileException);
- [CallWith=ScriptExecutionContext] DOMString readAsBinaryString(in Blob blob)
- raises(FileException);
- [CallWith=ScriptExecutionContext] DOMString readAsText(in Blob blob, in [Optional] DOMString encoding)
- raises(FileException);
- [CallWith=ScriptExecutionContext] DOMString readAsDataURL(in Blob blob)
- raises(FileException);
+ [CallWith=ScriptExecutionContext, RaisesException] ArrayBuffer readAsArrayBuffer(Blob blob);
+ [CallWith=ScriptExecutionContext, RaisesException] DOMString readAsBinaryString(Blob blob);
+ [CallWith=ScriptExecutionContext, RaisesException] DOMString readAsText(Blob blob, optional DOMString encoding);
+ [CallWith=ScriptExecutionContext, RaisesException] DOMString readAsDataURL(Blob blob);
};
diff --git a/Source/WebCore/fileapi/FileThread.cpp b/Source/WebCore/fileapi/FileThread.cpp
index 4f4f473fd..ef280c8a3 100644
--- a/Source/WebCore/fileapi/FileThread.cpp
+++ b/Source/WebCore/fileapi/FileThread.cpp
@@ -34,8 +34,8 @@
#include "FileThread.h"
-#include "AutodrainedPool.h"
#include "Logging.h"
+#include <wtf/AutodrainedPool.h>
namespace WebCore {
@@ -98,10 +98,10 @@ void FileThread::runLoop()
LOG(FileAPI, "Started FileThread %p", this);
}
- AutodrainedPool pool;
while (OwnPtr<Task> task = m_queue.waitForMessage()) {
+ AutodrainedPool pool;
+
task->performTask();
- pool.cycle();
}
LOG(FileAPI, "About to detach thread %i and clear the ref to FileThread %p, which currently has %i ref(s)", m_threadID, this, refCount());
diff --git a/Source/WebCore/fileapi/ThreadableBlobRegistry.cpp b/Source/WebCore/fileapi/ThreadableBlobRegistry.cpp
index afe5b66cc..10bfb2ee0 100644
--- a/Source/WebCore/fileapi/ThreadableBlobRegistry.cpp
+++ b/Source/WebCore/fileapi/ThreadableBlobRegistry.cpp
@@ -155,7 +155,7 @@ void ThreadableBlobRegistry::unregisterBlobURL(const KURL&)
{
}
-PassRefPtr<SecurityOrigin> ThreadableBlobRegistry::getCachedOrigin(const KURL& url)
+PassRefPtr<SecurityOrigin> ThreadableBlobRegistry::getCachedOrigin(const KURL&)
{
return 0;
}
diff --git a/Source/WebCore/fileapi/WebKitBlobBuilder.cpp b/Source/WebCore/fileapi/WebKitBlobBuilder.cpp
index 8312a547c..1622e2fe4 100644
--- a/Source/WebCore/fileapi/WebKitBlobBuilder.cpp
+++ b/Source/WebCore/fileapi/WebKitBlobBuilder.cpp
@@ -39,7 +39,6 @@
#include "HistogramSupport.h"
#include "LineEnding.h"
#include "ScriptCallStack.h"
-#include "ScriptExecutionContext.h"
#include "TextEncoding.h"
#include <wtf/ArrayBuffer.h>
#include <wtf/ArrayBufferView.h>
@@ -89,11 +88,8 @@ void BlobBuilder::append(const String& text, const String& endingType)
}
#if ENABLE(BLOB)
-void BlobBuilder::append(ScriptExecutionContext* context, ArrayBuffer* arrayBuffer)
+void BlobBuilder::append(ArrayBuffer* arrayBuffer)
{
- String consoleMessage("ArrayBuffer values are deprecated in Blob Constructor. Use ArrayBufferView instead.");
- context->addConsoleMessage(JSMessageSource, LogMessageType, WarningMessageLevel, consoleMessage);
-
HistogramSupport::histogramEnumeration("WebCore.Blob.constructor.ArrayBufferOrView", BlobConstructorArrayBuffer, BlobConstructorArrayBufferOrViewMax);
if (!arrayBuffer)
@@ -150,7 +146,7 @@ void BlobBuilder::appendBytesData(const void* data, size_t length)
PassRefPtr<Blob> BlobBuilder::getBlob(const String& contentType)
{
OwnPtr<BlobData> blobData = BlobData::create();
- blobData->setContentType(contentType);
+ blobData->setContentType(Blob::normalizedContentType(contentType));
blobData->swapItems(m_items);
RefPtr<Blob> blob = Blob::create(blobData.release(), m_size);
diff --git a/Source/WebCore/fileapi/WebKitBlobBuilder.h b/Source/WebCore/fileapi/WebKitBlobBuilder.h
index 75090ba3e..335bc766d 100644
--- a/Source/WebCore/fileapi/WebKitBlobBuilder.h
+++ b/Source/WebCore/fileapi/WebKitBlobBuilder.h
@@ -33,14 +33,12 @@
#include "BlobData.h"
#include <wtf/Forward.h>
-#include <wtf/RefCounted.h>
namespace WebCore {
// FIXME: Move this file to BlobBuilder.h
class Blob;
-class ScriptExecutionContext;
class TextEncoding;
typedef int ExceptionCode;
@@ -52,7 +50,7 @@ public:
void append(Blob*);
void append(const String& text, const String& ending);
#if ENABLE(BLOB)
- void append(ScriptExecutionContext*, ArrayBuffer*);
+ void append(ArrayBuffer*);
void append(ArrayBufferView*);
#endif