summaryrefslogtreecommitdiffstats
path: root/WebCore/platform/network
diff options
context:
space:
mode:
authorSteve Block <steveblock@google.com>2010-08-27 11:02:25 +0100
committerSteve Block <steveblock@google.com>2010-09-02 17:17:20 +0100
commite8b154fd68f9b33be40a3590e58347f353835f5c (patch)
tree0733ce26384183245aaa5656af26c653636fe6c1 /WebCore/platform/network
parentda56157816334089526a7a115a85fd85a6e9a1dc (diff)
downloadexternal_webkit-e8b154fd68f9b33be40a3590e58347f353835f5c.zip
external_webkit-e8b154fd68f9b33be40a3590e58347f353835f5c.tar.gz
external_webkit-e8b154fd68f9b33be40a3590e58347f353835f5c.tar.bz2
Merge WebKit at r66079 : Initial merge by git
Change-Id: Ie2e1440fb9d487d24e52c247342c076fecaecac7
Diffstat (limited to 'WebCore/platform/network')
-rw-r--r--WebCore/platform/network/BlobData.cpp5
-rw-r--r--WebCore/platform/network/BlobData.h28
-rw-r--r--WebCore/platform/network/BlobRegistry.h11
-rw-r--r--WebCore/platform/network/BlobRegistryImpl.cpp62
-rw-r--r--WebCore/platform/network/BlobRegistryImpl.h4
-rw-r--r--WebCore/platform/network/BlobResourceHandle.cpp589
-rw-r--r--WebCore/platform/network/BlobResourceHandle.h116
-rw-r--r--WebCore/platform/network/BlobStorageData.h69
-rw-r--r--WebCore/platform/network/CredentialStorage.cpp1
-rw-r--r--WebCore/platform/network/FormData.cpp10
-rw-r--r--WebCore/platform/network/FormData.h24
-rw-r--r--WebCore/platform/network/HTTPParsers.cpp57
-rw-r--r--WebCore/platform/network/HTTPParsers.h3
-rw-r--r--WebCore/platform/network/ResourceHandle.cpp9
-rw-r--r--WebCore/platform/network/ResourceHandle.h3
-rw-r--r--WebCore/platform/network/ResourceHandleClient.h5
-rw-r--r--WebCore/platform/network/ResourceHandleInternal.h2
-rw-r--r--WebCore/platform/network/mac/ResourceHandleMac.mm7
-rw-r--r--WebCore/platform/network/win/ResourceHandleWin.cpp168
19 files changed, 1042 insertions, 131 deletions
diff --git a/WebCore/platform/network/BlobData.cpp b/WebCore/platform/network/BlobData.cpp
index bb256d0..21e8917 100644
--- a/WebCore/platform/network/BlobData.cpp
+++ b/WebCore/platform/network/BlobData.cpp
@@ -64,6 +64,11 @@ void BlobData::appendData(const CString& data)
m_items.append(BlobDataItem(data));
}
+void BlobData::appendData(const CString& data, long long offset, long long length)
+{
+ m_items.append(BlobDataItem(data, offset, length));
+}
+
void BlobData::appendFile(const String& path)
{
m_items.append(BlobDataItem(path));
diff --git a/WebCore/platform/network/BlobData.h b/WebCore/platform/network/BlobData.h
index 17cdfdd..13e3b9c 100644
--- a/WebCore/platform/network/BlobData.h
+++ b/WebCore/platform/network/BlobData.h
@@ -45,14 +45,15 @@ struct BlobDataItem {
// Default constructor.
BlobDataItem()
- : offset(0)
+ : type(Data)
+ , offset(0)
, length(toEndOfFile)
, expectedModificationTime(doNotCheckFileChange)
{
}
- // Constructor for String type.
- BlobDataItem(const CString& data)
+ // Constructor for String type (complete string).
+ explicit BlobDataItem(const CString& data)
: type(Data)
, data(data)
, offset(0)
@@ -61,8 +62,18 @@ struct BlobDataItem {
{
}
+ // Constructor for String type (partial string).
+ BlobDataItem(const CString& data, long long offset, long long length)
+ : type(Data)
+ , data(data)
+ , offset(offset)
+ , length(length)
+ , expectedModificationTime(doNotCheckFileChange)
+ {
+ }
+
// Constructor for File type (complete file).
- BlobDataItem(const String& path)
+ explicit BlobDataItem(const String& path)
: type(File)
, path(path)
, offset(0)
@@ -105,11 +116,8 @@ struct BlobDataItem {
// For Blob type.
KURL url;
- // For File and Blob type.
long long offset;
long long length;
-
- // For File type only.
double expectedModificationTime;
};
@@ -140,8 +148,14 @@ public:
void appendBlob(const KURL&, long long offset, long long length);
private:
+ friend class BlobRegistryImpl;
+ friend class BlobStorageData;
+
BlobData() { }
+ // This is only exposed to BlobStorageData.
+ void appendData(const CString&, long long offset, long long length);
+
String m_contentType;
String m_contentDisposition;
BlobDataItemList m_items;
diff --git a/WebCore/platform/network/BlobRegistry.h b/WebCore/platform/network/BlobRegistry.h
index fcd7b1c..7e64233 100644
--- a/WebCore/platform/network/BlobRegistry.h
+++ b/WebCore/platform/network/BlobRegistry.h
@@ -38,6 +38,7 @@
namespace WebCore {
class BlobData;
+class BlobRegistry;
class KURL;
class ResourceError;
class ResourceHandle;
@@ -45,17 +46,23 @@ class ResourceHandleClient;
class ResourceRequest;
class ResourceResponse;
+// Returns a single instance of BlobRegistry.
+BlobRegistry& blobRegistry();
+
// BlobRegistry is not thread-safe. It should only be called from main thread.
class BlobRegistry {
public:
- static BlobRegistry& instance();
-
+ // Registers a blob URL referring to the specified blob data.
virtual void registerBlobURL(const KURL&, PassOwnPtr<BlobData>) = 0;
+
+ // Registers a blob URL referring to the blob data identified by the specified srcURL.
virtual void registerBlobURL(const KURL&, const KURL& srcURL) = 0;
+
virtual void unregisterBlobURL(const KURL&) = 0;
virtual PassRefPtr<ResourceHandle> createResourceHandle(const ResourceRequest&, ResourceHandleClient*) = 0;
virtual bool loadResourceSynchronously(const ResourceRequest&, ResourceError&, ResourceResponse&, Vector<char>& data) = 0;
+protected:
virtual ~BlobRegistry() { }
};
diff --git a/WebCore/platform/network/BlobRegistryImpl.cpp b/WebCore/platform/network/BlobRegistryImpl.cpp
index bbbb8f0..ee872e6 100644
--- a/WebCore/platform/network/BlobRegistryImpl.cpp
+++ b/WebCore/platform/network/BlobRegistryImpl.cpp
@@ -32,9 +32,6 @@
#include "BlobRegistryImpl.h"
-#include "FileStream.h"
-#include "FileStreamProxy.h"
-#include "FileSystem.h"
#include "ResourceError.h"
#include "ResourceHandle.h"
#include "ResourceLoader.h"
@@ -45,6 +42,15 @@
namespace WebCore {
+#if !PLATFORM(CHROMIUM)
+BlobRegistry& blobRegistry()
+{
+ ASSERT(isMainThread());
+ DEFINE_STATIC_LOCAL(BlobRegistryImpl, instance, ());
+ return instance;
+}
+#endif
+
bool BlobRegistryImpl::shouldLoadResource(const ResourceRequest& request) const
{
// If the resource is not fetched using the GET method, bail out.
@@ -72,30 +78,23 @@ bool BlobRegistryImpl::loadResourceSynchronously(const ResourceRequest& request,
return false;
}
-BlobRegistry& BlobRegistry::instance()
-{
- ASSERT(isMainThread());
- DEFINE_STATIC_LOCAL(BlobRegistryImpl, instance, ());
- return instance;
-}
-
-void BlobRegistryImpl::appendStorageItems(BlobStorageData* blobStorageData, const BlobStorageDataItemList& items)
+void BlobRegistryImpl::appendStorageItems(BlobStorageData* blobStorageData, const BlobDataItemList& items)
{
- for (BlobStorageDataItemList::const_iterator iter = items.begin(); iter != items.end(); ++iter) {
- if (iter->type == BlobStorageDataItem::Data)
- blobStorageData->appendData(iter->data, iter->offset, iter->length);
+ for (BlobDataItemList::const_iterator iter = items.begin(); iter != items.end(); ++iter) {
+ if (iter->type == BlobDataItem::Data)
+ blobStorageData->m_data.appendData(iter->data, iter->offset, iter->length);
else {
- ASSERT(iter->type == BlobStorageDataItem::File);
- blobStorageData->appendFile(iter->path, iter->offset, iter->length, iter->expectedModificationTime);
+ ASSERT(iter->type == BlobDataItem::File);
+ blobStorageData->m_data.appendFile(iter->path, iter->offset, iter->length, iter->expectedModificationTime);
}
}
}
-void BlobRegistryImpl::appendStorageItems(BlobStorageData* blobStorageData, const BlobStorageDataItemList& items, long long offset, long long length)
+void BlobRegistryImpl::appendStorageItems(BlobStorageData* blobStorageData, const BlobDataItemList& items, long long offset, long long length)
{
ASSERT(length != BlobDataItem::toEndOfFile);
- BlobStorageDataItemList::const_iterator iter = items.begin();
+ BlobDataItemList::const_iterator iter = items.begin();
if (offset) {
for (; iter != items.end(); ++iter) {
if (offset >= iter->length)
@@ -108,12 +107,13 @@ void BlobRegistryImpl::appendStorageItems(BlobStorageData* blobStorageData, cons
for (; iter != items.end() && length > 0; ++iter) {
long long currentLength = iter->length - offset;
long long newLength = currentLength > length ? length : currentLength;
- if (iter->type == BlobStorageDataItem::Data)
- blobStorageData->appendData(iter->data, iter->offset + offset, newLength);
+ if (iter->type == BlobDataItem::Data)
+ blobStorageData->m_data.appendData(iter->data, iter->offset + offset, newLength);
else {
- ASSERT(iter->type == BlobStorageDataItem::File);
- blobStorageData->appendFile(iter->path, iter->offset + offset, newLength, iter->expectedModificationTime);
+ ASSERT(iter->type == BlobDataItem::File);
+ blobStorageData->m_data.appendFile(iter->path, iter->offset + offset, newLength, iter->expectedModificationTime);
}
+ length -= newLength;
offset = 0;
}
}
@@ -122,17 +122,20 @@ void BlobRegistryImpl::registerBlobURL(const KURL& url, PassOwnPtr<BlobData> blo
{
ASSERT(isMainThread());
- RefPtr<BlobStorageData> blobStorageData = BlobStorageData::create();
- blobStorageData->setContentType(blobData->contentType());
- blobStorageData->setContentDisposition(blobData->contentDisposition());
+ RefPtr<BlobStorageData> blobStorageData = BlobStorageData::create(blobData->contentType(), blobData->contentDisposition());
+
+ // The blob data is stored in the "canonical" way. That is, it only contains a list of Data and File items.
+ // 1) The Data item is denoted by the raw data and the range.
+ // 2) The File item is denoted by the file path, the range and the expected modification time.
+ // All the Blob items in the passing blob data are resolved and expanded into a set of Data and File items.
for (BlobDataItemList::const_iterator iter = blobData->items().begin(); iter != blobData->items().end(); ++iter) {
switch (iter->type) {
case BlobDataItem::Data:
- blobStorageData->appendData(iter->data, 0, iter->data.length());
+ blobStorageData->m_data.appendData(iter->data, 0, iter->data.length());
break;
case BlobDataItem::File:
- blobStorageData->appendFile(iter->path, iter->offset, iter->length, iter->expectedModificationTime);
+ blobStorageData->m_data.appendFile(iter->path, iter->offset, iter->length, iter->expectedModificationTime);
break;
case BlobDataItem::Blob:
if (m_blobs.contains(iter->url.string()))
@@ -141,7 +144,6 @@ void BlobRegistryImpl::registerBlobURL(const KURL& url, PassOwnPtr<BlobData> blo
}
}
-
m_blobs.set(url.string(), blobStorageData);
}
@@ -154,9 +156,7 @@ void BlobRegistryImpl::registerBlobURL(const KURL& url, const KURL& srcURL)
if (!src)
return;
- RefPtr<BlobStorageData> blobStorageData = BlobStorageData::create();
- blobStorageData->setContentType(src->contentType());
- blobStorageData->setContentDisposition(src->contentDisposition());
+ RefPtr<BlobStorageData> blobStorageData = BlobStorageData::create(src->contentType(), src->contentDisposition());
appendStorageItems(blobStorageData.get(), src->items());
m_blobs.set(url.string(), blobStorageData);
diff --git a/WebCore/platform/network/BlobRegistryImpl.h b/WebCore/platform/network/BlobRegistryImpl.h
index 42693bc..f616664 100644
--- a/WebCore/platform/network/BlobRegistryImpl.h
+++ b/WebCore/platform/network/BlobRegistryImpl.h
@@ -63,8 +63,8 @@ public:
private:
bool shouldLoadResource(const ResourceRequest& request) const;
- void appendStorageItems(BlobStorageData*, const BlobStorageDataItemList&);
- void appendStorageItems(BlobStorageData*, const BlobStorageDataItemList&, long long offset, long long length);
+ void appendStorageItems(BlobStorageData*, const BlobDataItemList&);
+ void appendStorageItems(BlobStorageData*, const BlobDataItemList&, long long offset, long long length);
HashMap<String, RefPtr<BlobStorageData> > m_blobs;
};
diff --git a/WebCore/platform/network/BlobResourceHandle.cpp b/WebCore/platform/network/BlobResourceHandle.cpp
new file mode 100644
index 0000000..63335f6
--- /dev/null
+++ b/WebCore/platform/network/BlobResourceHandle.cpp
@@ -0,0 +1,589 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if ENABLE(BLOB)
+
+#include "BlobResourceHandle.h"
+
+#include "AsyncFileStream.h"
+#include "BlobRegistryImpl.h"
+#include "FileStream.h"
+#include "FileSystem.h"
+#include "HTTPParsers.h"
+#include "KURL.h"
+#include "ResourceError.h"
+#include "ResourceLoader.h"
+#include "ResourceRequest.h"
+#include "ResourceResponse.h"
+
+namespace WebCore {
+
+static const unsigned bufferSize = 1024;
+static const int maxVectorLength = 0x7fffffff;
+static const long long positionNotSpecified = -1;
+
+static const int httpOK = 200;
+static const int httpPartialContent = 206;
+static const int httpNotAllowed = 403;
+static const int httpNotFound = 404;
+static const int httpRequestedRangeNotSatisfiable = 416;
+static const int httpInternalError = 500;
+static const char* httpOKText = "OK";
+static const char* httpPartialContentText = "Partial Content";
+static const char* httpNotAllowedText = "Not Allowed";
+static const char* httpNotFoundText = "Not Found";
+static const char* httpRequestedRangeNotSatisfiableText = "Requested Range Not Satisfiable";
+static const char* httpInternalErrorText = "Internal Server Error";
+
+static const int notFoundError = 1;
+static const int securityError = 2;
+static const int rangeError = 3;
+static const int notReadableError = 4;
+
+///////////////////////////////////////////////////////////////////////////////
+// BlobResourceSynchronousLoader
+
+namespace {
+
+class BlobResourceSynchronousLoader : public ResourceHandleClient {
+public:
+ BlobResourceSynchronousLoader(ResourceError&, ResourceResponse&, Vector<char>&);
+
+ virtual void didReceiveResponse(ResourceHandle*, const ResourceResponse&);
+ virtual void didReceiveData(ResourceHandle*, const char*, int, int /*lengthReceived*/);
+ virtual void didFinishLoading(ResourceHandle*);
+ virtual void didFail(ResourceHandle*, const ResourceError&);
+
+private:
+ ResourceError& m_error;
+ ResourceResponse& m_response;
+ Vector<char>& m_data;
+};
+
+BlobResourceSynchronousLoader::BlobResourceSynchronousLoader(ResourceError& error, ResourceResponse& response, Vector<char>& data)
+ : m_error(error)
+ , m_response(response)
+ , m_data(data)
+{
+}
+
+void BlobResourceSynchronousLoader::didReceiveResponse(ResourceHandle* handle, const ResourceResponse& response)
+{
+ // We cannot handle the size that is more than maximum integer.
+ const int intMaxForLength = 0x7fffffff;
+ if (response.expectedContentLength() > intMaxForLength) {
+ m_error = ResourceError(String(), notReadableError, response.url(), String());
+ return;
+ }
+
+ m_response = response;
+
+ // Read all the data.
+ m_data.resize(static_cast<size_t>(response.expectedContentLength()));
+ static_cast<BlobResourceHandle*>(handle)->readSync(m_data.data(), static_cast<int>(m_data.size()));
+}
+
+void BlobResourceSynchronousLoader::didReceiveData(ResourceHandle*, const char*, int, int)
+{
+}
+
+void BlobResourceSynchronousLoader::didFinishLoading(ResourceHandle*)
+{
+}
+
+void BlobResourceSynchronousLoader::didFail(ResourceHandle*, const ResourceError& error)
+{
+ m_error = error;
+}
+
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// BlobResourceHandle
+
+// static
+void BlobResourceHandle::loadResourceSynchronously(PassRefPtr<BlobStorageData> blobData, const ResourceRequest& request, ResourceError& error, ResourceResponse& response, Vector<char>& data)
+{
+ BlobResourceSynchronousLoader loader(error, response, data);
+ RefPtr<BlobResourceHandle> handle = BlobResourceHandle::create(blobData, request, &loader, false);
+ handle->start();
+}
+
+static void delayedStart(void* context)
+{
+ static_cast<BlobResourceHandle*>(context)->start();
+}
+
+BlobResourceHandle::BlobResourceHandle(PassRefPtr<BlobStorageData> blobData, const ResourceRequest& request, ResourceHandleClient* client, bool async)
+ : ResourceHandle(request, client, false, false)
+ , m_blobData(blobData)
+ , m_async(async)
+ , m_errorCode(0)
+ , m_aborted(false)
+ , m_rangeOffset(positionNotSpecified)
+ , m_rangeEnd(positionNotSpecified)
+ , m_rangeSuffixLength(positionNotSpecified)
+ , m_totalRemainingSize(0)
+ , m_currentItemReadSize(0)
+ , m_sizeItemCount(0)
+ , m_readItemCount(0)
+ , m_fileOpened(false)
+{
+ if (m_async) {
+ m_asyncStream = adoptRef(client->createAsyncFileStream(this));
+ callOnMainThread(delayedStart, this);
+ } else
+ m_stream = FileStream::create();
+}
+
+BlobResourceHandle::~BlobResourceHandle()
+{
+ if (m_async) {
+ if (m_asyncStream)
+ m_asyncStream->stop();
+ } else {
+ if (m_stream)
+ m_stream->stop();
+ }
+}
+
+void BlobResourceHandle::cancel()
+{
+ if (m_async) {
+ if (m_asyncStream) {
+ m_asyncStream->stop();
+ m_asyncStream = 0;
+ }
+ }
+
+ m_aborted = true;
+}
+
+void BlobResourceHandle::start()
+{
+ // Do not continue if the request is aborted or an error occurs.
+ if (m_aborted || m_errorCode)
+ return;
+
+ // If the blob data is not found, fail now.
+ if (!m_blobData) {
+ m_errorCode = notFoundError;
+ notifyResponse();
+ return;
+ }
+
+ // Parse the "Range" header we care about.
+ String range = firstRequest().httpHeaderField("Range");
+ if (!range.isEmpty() && !parseRange(range, m_rangeOffset, m_rangeEnd, m_rangeSuffixLength)) {
+ m_errorCode = rangeError;
+ notifyResponse();
+ return;
+ }
+
+ if (m_async)
+ getSizeForNext();
+ else {
+ for (size_t i = 0; i < m_blobData->items().size() && !m_aborted && !m_errorCode; ++i)
+ getSizeForNext();
+ notifyResponse();
+ }
+}
+
+void BlobResourceHandle::getSizeForNext()
+{
+ // Do we finish validating and counting size for all items?
+ if (m_sizeItemCount >= m_blobData->items().size()) {
+ seek();
+
+ // Start reading if in asynchronous mode.
+ if (m_async) {
+ notifyResponse();
+ m_buffer.resize(bufferSize);
+ readAsync();
+ }
+ return;
+ }
+
+ const BlobDataItem& item = m_blobData->items().at(m_sizeItemCount);
+ switch (item.type) {
+ case BlobDataItem::Data:
+ didGetSize(item.length);
+ break;
+ case BlobDataItem::File:
+ if (m_async)
+ m_asyncStream->getSize(item.path, item.expectedModificationTime);
+ else
+ didGetSize(m_stream->getSize(item.path, item.expectedModificationTime));
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+}
+
+void BlobResourceHandle::didGetSize(long long size)
+{
+ // Do not continue if the request is aborted or an error occurs.
+ if (m_aborted || m_errorCode)
+ return;
+
+ // If the size is -1, it means the file has been moved or changed. Fail now.
+ if (size == -1) {
+ m_errorCode = notFoundError;
+ notifyResponse();
+ return;
+ }
+
+ // 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.
+ const BlobDataItem& item = m_blobData->items().at(m_sizeItemCount);
+ if (item.type == BlobDataItem::File && item.length != BlobDataItem::toEndOfFile)
+ size = item.length;
+
+ // Cache the size.
+ m_itemLengthList.append(size);
+
+ // Count the size.
+ m_totalRemainingSize += size;
+ m_sizeItemCount++;
+
+ // Continue with the next item.
+ getSizeForNext();
+}
+
+void BlobResourceHandle::seek()
+{
+ // Convert from the suffix length to the range.
+ if (m_rangeSuffixLength != positionNotSpecified) {
+ m_rangeOffset = m_totalRemainingSize - m_rangeSuffixLength;
+ m_rangeEnd = m_rangeOffset + m_rangeSuffixLength - 1;
+ }
+
+ // Bail out if the range is not provided.
+ if (m_rangeOffset == positionNotSpecified)
+ return;
+
+ // Skip the initial items that are not in the range.
+ long long offset = m_rangeOffset;
+ for (m_readItemCount = 0; m_readItemCount < m_blobData->items().size() && offset >= m_itemLengthList[m_readItemCount]; ++m_readItemCount)
+ offset -= m_itemLengthList[m_readItemCount];
+
+ // Set the offset that need to jump to for the first item in the range.
+ m_currentItemReadSize = offset;
+
+ // Adjust the total remaining size in order not to go beyond the range.
+ if (m_rangeEnd != positionNotSpecified) {
+ long long rangeSize = m_rangeEnd - m_rangeOffset + 1;
+ if (m_totalRemainingSize > rangeSize)
+ m_totalRemainingSize = rangeSize;
+ } else
+ m_totalRemainingSize -= m_rangeOffset;
+}
+
+int BlobResourceHandle::readSync(char* buf, int length)
+{
+ ASSERT(!m_async);
+
+ int offset = 0;
+ int remaining = length;
+ while (remaining) {
+ // Do not continue if the request is aborted or an error occurs.
+ if (m_aborted || m_errorCode)
+ break;
+
+ // If there is no more remaining data to read, we are done.
+ if (!m_totalRemainingSize || m_readItemCount >= m_blobData->items().size())
+ break;
+
+ const BlobDataItem& item = m_blobData->items().at(m_readItemCount);
+ int bytesRead = 0;
+ if (item.type == BlobDataItem::Data)
+ bytesRead = readDataSync(item, buf + offset, remaining);
+ else if (item.type == BlobDataItem::File)
+ bytesRead = readFileSync(item, buf + offset, remaining);
+ else
+ ASSERT_NOT_REACHED();
+
+ if (bytesRead > 0) {
+ offset += bytesRead;
+ remaining -= bytesRead;
+ }
+ }
+
+ int result;
+ if (m_aborted || m_errorCode)
+ result = -1;
+ else
+ result = length - remaining;
+
+ notifyReceiveData(buf, result);
+ if (!result)
+ notifyFinish();
+
+ return result;
+}
+
+int BlobResourceHandle::readDataSync(const BlobDataItem& item, char* buf, int length)
+{
+ ASSERT(!m_async);
+
+ long long remaining = item.length - m_currentItemReadSize;
+ int bytesToRead = (length > remaining) ? static_cast<int>(remaining) : length;
+ if (bytesToRead > m_totalRemainingSize)
+ bytesToRead = static_cast<int>(m_totalRemainingSize);
+ memcpy(buf, item.data.data() + item.offset + m_currentItemReadSize, bytesToRead);
+ m_totalRemainingSize -= bytesToRead;
+
+ m_currentItemReadSize += bytesToRead;
+ if (m_currentItemReadSize == item.length) {
+ m_readItemCount++;
+ m_currentItemReadSize = 0;
+ }
+
+ return bytesToRead;
+}
+
+int BlobResourceHandle::readFileSync(const BlobDataItem& item, char* buf, int length)
+{
+ ASSERT(!m_async);
+
+ if (!m_fileOpened) {
+ long long bytesToRead = m_itemLengthList[m_readItemCount] - m_currentItemReadSize;
+ if (bytesToRead > m_totalRemainingSize)
+ bytesToRead = m_totalRemainingSize;
+ bool success = m_stream->openForRead(item.path, item.offset + m_currentItemReadSize, bytesToRead);
+ m_currentItemReadSize = 0;
+ if (!success) {
+ m_errorCode = notReadableError;
+ return 0;
+ }
+
+ m_fileOpened = true;
+ }
+
+ int bytesRead = m_stream->read(buf, length);
+ if (bytesRead < 0) {
+ m_errorCode = notReadableError;
+ return 0;
+ }
+ if (!bytesRead) {
+ m_stream->close();
+ m_fileOpened = false;
+ m_readItemCount++;
+ } else
+ m_totalRemainingSize -= bytesRead;
+
+ return bytesRead;
+}
+
+void BlobResourceHandle::readAsync()
+{
+ ASSERT(m_async);
+
+ // Do not continue if the request is aborted or an error occurs.
+ if (m_aborted || m_errorCode)
+ return;
+
+ // If there is no more remaining data to read, we are done.
+ if (!m_totalRemainingSize || m_readItemCount >= m_blobData->items().size()) {
+ notifyFinish();
+ return;
+ }
+
+ const BlobDataItem& item = m_blobData->items().at(m_readItemCount);
+ if (item.type == BlobDataItem::Data)
+ readDataAsync(item);
+ else if (item.type == BlobDataItem::File)
+ readFileAsync(item);
+ else
+ ASSERT_NOT_REACHED();
+}
+
+void BlobResourceHandle::readDataAsync(const BlobDataItem& item)
+{
+ ASSERT(m_async);
+
+ long long bytesToRead = item.length - m_currentItemReadSize;
+ if (bytesToRead > m_totalRemainingSize)
+ bytesToRead = m_totalRemainingSize;
+ consumeData(item.data.data() + item.offset + m_currentItemReadSize, static_cast<int>(bytesToRead));
+ m_currentItemReadSize = 0;
+}
+
+void BlobResourceHandle::readFileAsync(const BlobDataItem& item)
+{
+ ASSERT(m_async);
+
+ if (m_fileOpened) {
+ m_asyncStream->read(m_buffer.data(), m_buffer.size());
+ return;
+ }
+
+ long long bytesToRead = m_itemLengthList[m_readItemCount] - m_currentItemReadSize;
+ if (bytesToRead > m_totalRemainingSize)
+ bytesToRead = static_cast<int>(m_totalRemainingSize);
+ m_asyncStream->openForRead(item.path, item.offset + m_currentItemReadSize, bytesToRead);
+ m_fileOpened = true;
+ m_currentItemReadSize = 0;
+}
+
+void BlobResourceHandle::didOpen(bool success)
+{
+ ASSERT(m_async);
+
+ if (!success) {
+ failed(notReadableError);
+ return;
+ }
+
+ // Continue the reading.
+ readAsync();
+}
+
+void BlobResourceHandle::didRead(int bytesRead)
+{
+ consumeData(m_buffer.data(), bytesRead);
+}
+
+void BlobResourceHandle::consumeData(const char* data, int bytesRead)
+{
+ ASSERT(m_async);
+
+ m_totalRemainingSize -= bytesRead;
+
+ // Notify the client.
+ if (bytesRead)
+ notifyReceiveData(data, bytesRead);
+
+ if (m_fileOpened) {
+ // When the current item is a file item, the reading is completed only if bytesRead is 0.
+ if (!bytesRead) {
+ // Close the file.
+ m_fileOpened = false;
+ m_asyncStream->close();
+
+ // Move to the next item.
+ m_readItemCount++;
+ }
+ } else {
+ // Otherwise, we read the current text item as a whole and move to the next item.
+ m_readItemCount++;
+ }
+
+ // Continue the reading.
+ readAsync();
+}
+
+void BlobResourceHandle::failed(int errorCode)
+{
+ ASSERT(m_async);
+
+ // Notify the client.
+ notifyFail(errorCode);
+
+ // Close the file if needed.
+ if (m_fileOpened) {
+ m_fileOpened = false;
+ m_asyncStream->close();
+ }
+}
+
+void BlobResourceHandle::notifyResponse()
+{
+ if (!client())
+ return;
+
+ if (m_errorCode) {
+ notifyResponseOnError();
+ notifyFinish();
+ } else
+ notifyResponseOnSuccess();
+}
+
+void BlobResourceHandle::notifyResponseOnSuccess()
+{
+ bool isRangeRequest = m_rangeOffset != positionNotSpecified;
+ ResourceResponse response(firstRequest().url(), m_blobData->contentType(), m_totalRemainingSize, String(), String());
+ response.setExpectedContentLength(m_totalRemainingSize);
+ response.setHTTPStatusCode(isRangeRequest ? httpPartialContent : httpOK);
+ response.setHTTPStatusText(isRangeRequest ? httpPartialContentText : httpOKText);
+ if (!m_blobData->contentDisposition().isEmpty())
+ response.setHTTPHeaderField("Content-Disposition", m_blobData->contentDisposition());
+ client()->didReceiveResponse(this, response);
+}
+
+void BlobResourceHandle::notifyResponseOnError()
+{
+ ASSERT(m_errorCode);
+
+ ResourceResponse response(firstRequest().url(), String(), 0, String(), String());
+ switch (m_errorCode) {
+ case rangeError:
+ response.setHTTPStatusCode(httpRequestedRangeNotSatisfiable);
+ response.setHTTPStatusText(httpRequestedRangeNotSatisfiableText);
+ break;
+ case notFoundError:
+ response.setHTTPStatusCode(httpNotFound);
+ response.setHTTPStatusText(httpNotFoundText);
+ break;
+ case securityError:
+ response.setHTTPStatusCode(httpNotAllowed);
+ response.setHTTPStatusText(httpNotAllowedText);
+ break;
+ default:
+ response.setHTTPStatusCode(httpInternalError);
+ response.setHTTPStatusText(httpInternalErrorText);
+ break;
+ }
+ client()->didReceiveResponse(this, response);
+}
+
+void BlobResourceHandle::notifyReceiveData(const char* data, int bytesRead)
+{
+ if (client())
+ client()->didReceiveData(this, data, bytesRead, bytesRead);
+}
+
+void BlobResourceHandle::notifyFail(int errorCode)
+{
+ if (client())
+ client()->didFail(this, ResourceError(String(), errorCode, firstRequest().url(), String()));
+}
+
+void BlobResourceHandle::notifyFinish()
+{
+ if (client())
+ client()->didFinishLoading(this);
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(BLOB)
+
diff --git a/WebCore/platform/network/BlobResourceHandle.h b/WebCore/platform/network/BlobResourceHandle.h
new file mode 100644
index 0000000..b2a0854
--- /dev/null
+++ b/WebCore/platform/network/BlobResourceHandle.h
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef BlobResourceHandle_h
+#define BlobResourceHandle_h
+
+#if ENABLE(BLOB)
+
+#include "FileStreamClient.h"
+#include "PlatformString.h"
+#include "ResourceHandle.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class AsyncFileStream;
+class BlobDataItem;
+class BlobStorageData;
+class FileStream;
+class ResourceHandleClient;
+class ResourceRequest;
+
+class BlobResourceHandle : public FileStreamClient, public ResourceHandle {
+public:
+ static PassRefPtr<BlobResourceHandle> create(PassRefPtr<BlobStorageData> blobData, const ResourceRequest& request, ResourceHandleClient* client, bool async = true)
+ {
+ return adoptRef(new BlobResourceHandle(blobData, request, client, async));
+ }
+
+ static void loadResourceSynchronously(PassRefPtr<BlobStorageData> blobData, const ResourceRequest& request, ResourceError& error, ResourceResponse& response, Vector<char>& data);
+
+ // FileStreamClient methods.
+ virtual void didGetSize(long long);
+ virtual void didOpen(bool);
+ virtual void didRead(int);
+
+ // ResourceHandle methods.
+ virtual void cancel();
+
+ void start();
+ int readSync(char*, int);
+
+private:
+ BlobResourceHandle(PassRefPtr<BlobStorageData>, const ResourceRequest&, ResourceHandleClient*, bool async);
+ virtual ~BlobResourceHandle();
+
+ void getSizeForNext();
+ void seek();
+ void consumeData(const char* data, int bytesRead);
+ void failed(int errorCode);
+
+ void readAsync();
+ void readDataAsync(const BlobDataItem&);
+ void readFileAsync(const BlobDataItem&);
+
+ int readDataSync(const BlobDataItem&, char*, int);
+ int readFileSync(const BlobDataItem&, char*, int);
+
+ void notifyResponse();
+ void notifyResponseOnSuccess();
+ void notifyResponseOnError();
+ void notifyReceiveData(const char*, int);
+ void notifyFail(int errorCode);
+ void notifyFinish();
+
+ RefPtr<BlobStorageData> m_blobData;
+ bool m_async;
+ RefPtr<AsyncFileStream> m_asyncStream; // For asynchronous loading.
+ RefPtr<FileStream> m_stream; // For synchronous loading.
+ Vector<char> m_buffer;
+ Vector<long long> m_itemLengthList;
+ int m_errorCode;
+ bool m_aborted;
+ long long m_rangeOffset;
+ long long m_rangeEnd;
+ long long m_rangeSuffixLength;
+ long long m_totalRemainingSize;
+ long long m_currentItemReadSize;
+ unsigned m_sizeItemCount;
+ unsigned m_readItemCount;
+ bool m_fileOpened;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(BLOB)
+
+#endif // BlobResourceHandle_h
diff --git a/WebCore/platform/network/BlobStorageData.h b/WebCore/platform/network/BlobStorageData.h
index f4125a4..6535e62 100644
--- a/WebCore/platform/network/BlobStorageData.h
+++ b/WebCore/platform/network/BlobStorageData.h
@@ -31,76 +31,33 @@
#ifndef BlobStorageData_h
#define BlobStorageData_h
-#include "PlatformString.h"
+#include "BlobData.h"
#include <wtf/PassRefPtr.h>
-#include <wtf/Vector.h>
-#include <wtf/text/CString.h>
+#include <wtf/RefCounted.h>
namespace WebCore {
-struct BlobStorageDataItem {
- enum BlobStoreDataItemType { Data, File };
- BlobStoreDataItemType type;
- long long offset;
- long long length;
-
- // For string data.
- CString data;
-
- // For file data.
- String path;
- double expectedModificationTime;
-
- BlobStorageDataItem(const CString& data, long long offset, long long length)
- : type(Data)
- , offset(offset)
- , length(length)
- , data(data)
- , expectedModificationTime(0)
- {
- }
-
- BlobStorageDataItem(const String& path, long long offset, long long length, double expectedModificationTime)
- : type(File)
- , offset(offset)
- , length(length)
- , path(path)
- , expectedModificationTime(expectedModificationTime)
- {
- }
-};
-
-typedef Vector<BlobStorageDataItem> BlobStorageDataItemList;
-
class BlobStorageData : public RefCounted<BlobStorageData> {
public:
- static PassRefPtr<BlobStorageData> create()
+ static PassRefPtr<BlobStorageData> create(const String& contentType, const String& contentDisposition)
{
- return adoptRef(new BlobStorageData());
+ return adoptRef(new BlobStorageData(contentType, contentDisposition));
}
- const String& contentType() const { return m_contentType; }
- void setContentType(const String& contentType) { m_contentType = contentType; }
-
- const String& contentDisposition() const { return m_contentDisposition; }
- void setContentDisposition(const String& contentDisposition) { m_contentDisposition = contentDisposition; }
-
- const BlobStorageDataItemList& items() const { return m_items; }
+ const String& contentType() const { return m_data.contentType(); }
+ const String& contentDisposition() const { return m_data.contentDisposition(); }
+ const BlobDataItemList& items() const { return m_data.items(); }
- void appendData(const CString& data, long long offset, long long length)
- {
- m_items.append(BlobStorageDataItem(data, offset, length));
- }
+private:
+ friend class BlobRegistryImpl;
- void appendFile(const String& path, long long offset, long long length, double expectedModificationTime)
+ BlobStorageData(const String& contentType, const String& contentDisposition)
{
- m_items.append(BlobStorageDataItem(path, offset, length, expectedModificationTime));
+ m_data.setContentType(contentType);
+ m_data.setContentDisposition(contentDisposition);
}
-private:
- String m_contentType;
- String m_contentDisposition;
- BlobStorageDataItemList m_items;
+ BlobData m_data;
};
} // namespace WebCore
diff --git a/WebCore/platform/network/CredentialStorage.cpp b/WebCore/platform/network/CredentialStorage.cpp
index 4fb7799..38f71a4 100644
--- a/WebCore/platform/network/CredentialStorage.cpp
+++ b/WebCore/platform/network/CredentialStorage.cpp
@@ -79,7 +79,6 @@ static String protectionSpaceMapKeyFromURL(const KURL& url)
ASSERT(index != notFound);
directoryURL = directoryURL.substring(0, (index != directoryURLPathStart) ? index : directoryURLPathStart + 1);
}
- ASSERT(directoryURL.length() == directoryURLPathStart + 1 || directoryURL[directoryURL.length() - 1] != '/');
return directoryURL;
}
diff --git a/WebCore/platform/network/FormData.cpp b/WebCore/platform/network/FormData.cpp
index 31506ea..4f2b365 100644
--- a/WebCore/platform/network/FormData.cpp
+++ b/WebCore/platform/network/FormData.cpp
@@ -139,6 +139,11 @@ PassRefPtr<FormData> FormData::deepCopy() const
formData->m_elements.append(FormDataElement(e.m_filename, e.m_shouldGenerateFile));
#endif
break;
+#if ENABLE(BLOB)
+ case FormDataElement::encodedBlob:
+ formData->m_elements.append(FormDataElement(e.m_blobURL));
+ break;
+#endif
}
}
return formData.release();
@@ -200,6 +205,11 @@ void FormData::appendFileRange(const String& filename, long long start, long lon
{
m_elements.append(FormDataElement(filename, start, length, expectedModificationTime, shouldGenerateFile));
}
+
+void FormData::appendBlob(const KURL& blobURL)
+{
+ m_elements.append(FormDataElement(blobURL));
+}
#endif
void FormData::appendKeyValuePairItems(const BlobItemList& items, const TextEncoding& encoding, bool isMultiPartForm, Document* document)
diff --git a/WebCore/platform/network/FormData.h b/WebCore/platform/network/FormData.h
index a1964e3..d7faa89 100644
--- a/WebCore/platform/network/FormData.h
+++ b/WebCore/platform/network/FormData.h
@@ -20,6 +20,7 @@
#ifndef FormData_h
#define FormData_h
+#include "KURL.h"
#include "PlatformString.h"
#include <wtf/Forward.h>
#include <wtf/RefCounted.h>
@@ -39,17 +40,25 @@ public:
#if ENABLE(BLOB)
FormDataElement(const String& filename, long long fileStart, long long fileLength, double expectedFileModificationTime, bool shouldGenerateFile) : m_type(encodedFile), m_filename(filename), m_fileStart(fileStart), m_fileLength(fileLength), m_expectedFileModificationTime(expectedFileModificationTime), m_shouldGenerateFile(shouldGenerateFile) { }
+ FormDataElement(const KURL& blobURL) : m_type(encodedBlob), m_blobURL(blobURL) { }
#else
FormDataElement(const String& filename, bool shouldGenerateFile) : m_type(encodedFile), m_filename(filename), m_shouldGenerateFile(shouldGenerateFile) { }
#endif
- enum { data, encodedFile } m_type;
+ enum {
+ data,
+ encodedFile
+#if ENABLE(BLOB)
+ , encodedBlob
+#endif
+ } m_type;
Vector<char> m_data;
String m_filename;
#if ENABLE(BLOB)
long long m_fileStart;
long long m_fileLength;
double m_expectedFileModificationTime;
+ KURL m_blobURL;
#endif
String m_generatedFilename;
bool m_shouldGenerateFile;
@@ -67,14 +76,16 @@ inline bool operator==(const FormDataElement& a, const FormDataElement& b)
if (a.m_type != b.m_type)
return false;
- if (a.m_data != b.m_data)
- return false;
+ if (a.m_type == FormDataElement::data)
+ return a.m_data == b.m_data;
+ if (a.m_type == FormDataElement::encodedFile)
#if ENABLE(BLOB)
- if (a.m_filename != b.m_filename || a.m_fileStart != b.m_fileStart || a.m_fileLength != b.m_fileLength || a.m_expectedFileModificationTime != b.m_expectedFileModificationTime)
+ return a.m_filename == b.m_filename && a.m_fileStart == b.m_fileStart && a.m_fileLength == b.m_fileLength && a.m_expectedFileModificationTime == b.m_expectedFileModificationTime;
+ if (a.m_type == FormDataElement::encodedBlob)
+ return a.m_blobURL == b.m_blobURL;
#else
- if (a.m_filename != b.m_filename)
+ return a.m_filename == b.m_filename;
#endif
- return false;
return true;
}
@@ -101,6 +112,7 @@ public:
void appendFile(const String& filename, bool shouldGenerateFile = false);
#if ENABLE(BLOB)
void appendFileRange(const String& filename, long long start, long long length, double expectedModificationTime, bool shouldGenerateFile = false);
+ void appendBlob(const KURL& blobURL);
#endif
void flatten(Vector<char>&) const; // omits files
diff --git a/WebCore/platform/network/HTTPParsers.cpp b/WebCore/platform/network/HTTPParsers.cpp
index b3f3d45..a1ba9d3 100644
--- a/WebCore/platform/network/HTTPParsers.cpp
+++ b/WebCore/platform/network/HTTPParsers.cpp
@@ -315,4 +315,61 @@ String extractReasonPhraseFromHTTPStatusLine(const String& statusLine)
return statusLine.substring(spacePos + 1);
}
+bool parseRange(const String& range, long long& rangeOffset, long long& rangeEnd, long long& rangeSuffixLength)
+{
+ // The format of "Range" header is defined in RFC 2616 Section 14.35.1.
+ // http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35.1
+ // We don't support multiple range requests.
+
+ rangeOffset = rangeEnd = rangeSuffixLength = -1;
+
+ // The "bytes" unit identifier should be present.
+ static const char bytesStart[] = "bytes=";
+ if (!range.startsWith(bytesStart, false))
+ return false;
+ String byteRange = range.substring(sizeof(bytesStart) - 1);
+
+ // The '-' character needs to be present.
+ int index = byteRange.find('-');
+ if (index == -1)
+ return false;
+
+ // If the '-' character is at the beginning, the suffix length, which specifies the last N bytes, is provided.
+ // Example:
+ // -500
+ if (!index) {
+ String suffixLengthString = byteRange.substring(index + 1).stripWhiteSpace();
+ bool ok;
+ long long value = suffixLengthString.toInt64Strict(&ok);
+ if (ok)
+ rangeSuffixLength = value;
+ return true;
+ }
+
+ // Otherwise, the first-byte-position and the last-byte-position are provied.
+ // Examples:
+ // 0-499
+ // 500-
+ String firstBytePosStr = byteRange.left(index).stripWhiteSpace();
+ bool ok;
+ long long firstBytePos = firstBytePosStr.toInt64Strict(&ok);
+ if (!ok)
+ return false;
+
+ String lastBytePosStr = byteRange.substring(index + 1).stripWhiteSpace();
+ long long lastBytePos = -1;
+ if (!lastBytePosStr.isEmpty()) {
+ lastBytePos = lastBytePosStr.toInt64Strict(&ok);
+ if (!ok)
+ return false;
+ }
+
+ if (firstBytePos < 0 || !(lastBytePos == -1 || lastBytePos >= firstBytePos))
+ return false;
+
+ rangeOffset = firstBytePos;
+ rangeEnd = lastBytePos;
+ return true;
+}
+
}
diff --git a/WebCore/platform/network/HTTPParsers.h b/WebCore/platform/network/HTTPParsers.h
index 9d6971b..55b8c7b 100644
--- a/WebCore/platform/network/HTTPParsers.h
+++ b/WebCore/platform/network/HTTPParsers.h
@@ -59,6 +59,9 @@ void findCharsetInMediaType(const String& mediaType, unsigned int& charsetPos, u
XSSProtectionDisposition parseXSSProtectionHeader(const String&);
String extractReasonPhraseFromHTTPStatusLine(const String&);
+// -1 could be set to one of the return parameters to indicate the value is not specified.
+bool parseRange(const String&, long long& rangeOffset, long long& rangeEnd, long long& rangeSuffixLength);
+
}
#endif
diff --git a/WebCore/platform/network/ResourceHandle.cpp b/WebCore/platform/network/ResourceHandle.cpp
index 0575523..2da1d77 100644
--- a/WebCore/platform/network/ResourceHandle.cpp
+++ b/WebCore/platform/network/ResourceHandle.cpp
@@ -27,6 +27,7 @@
#include "ResourceHandle.h"
#include "ResourceHandleInternal.h"
+#include "BlobRegistry.h"
#include "DNS.h"
#include "Logging.h"
#include "ResourceHandleClient.h"
@@ -54,6 +55,14 @@ ResourceHandle::ResourceHandle(const ResourceRequest& request, ResourceHandleCli
PassRefPtr<ResourceHandle> ResourceHandle::create(const ResourceRequest& request, ResourceHandleClient* client,
Frame* frame, bool defersLoading, bool shouldContentSniff)
{
+#if ENABLE(BLOB)
+ if (request.url().protocolIs("blob")) {
+ PassRefPtr<ResourceHandle> handle = blobRegistry().createResourceHandle(request, client);
+ if (handle)
+ return handle;
+ }
+#endif
+
RefPtr<ResourceHandle> newHandle(adoptRef(new ResourceHandle(request, client, defersLoading, shouldContentSniff)));
if (newHandle->d->m_scheduledFailureType != NoFailure)
diff --git a/WebCore/platform/network/ResourceHandle.h b/WebCore/platform/network/ResourceHandle.h
index 3dc38f8..1167715 100644
--- a/WebCore/platform/network/ResourceHandle.h
+++ b/WebCore/platform/network/ResourceHandle.h
@@ -98,9 +98,10 @@ class ResourceHandle : public RefCounted<ResourceHandle>
, public AuthenticationClient
#endif
{
-private:
+protected:
ResourceHandle(const ResourceRequest&, ResourceHandleClient*, bool defersLoading, bool shouldContentSniff);
+private:
enum FailureType {
NoFailure,
BlockedFailure,
diff --git a/WebCore/platform/network/ResourceHandleClient.h b/WebCore/platform/network/ResourceHandleClient.h
index 0098010..97c0f54 100644
--- a/WebCore/platform/network/ResourceHandleClient.h
+++ b/WebCore/platform/network/ResourceHandleClient.h
@@ -44,8 +44,10 @@ class NSCachedURLResponse;
#endif
namespace WebCore {
+ class AsyncFileStream;
class AuthenticationChallenge;
class Credential;
+ class FileStreamClient;
class KURL;
class ProtectionSpace;
class ResourceHandle;
@@ -92,6 +94,9 @@ namespace WebCore {
#if USE(CFNETWORK)
virtual bool shouldCacheResponse(ResourceHandle*, CFCachedURLResponseRef response) { return true; }
#endif
+#if ENABLE(BLOB)
+ virtual AsyncFileStream* createAsyncFileStream(FileStreamClient*) { return 0; }
+#endif
};
}
diff --git a/WebCore/platform/network/ResourceHandleInternal.h b/WebCore/platform/network/ResourceHandleInternal.h
index 7b6e960..24b00bf 100644
--- a/WebCore/platform/network/ResourceHandleInternal.h
+++ b/WebCore/platform/network/ResourceHandleInternal.h
@@ -92,7 +92,6 @@ namespace WebCore {
, m_connection(0)
#endif
#if USE(WININET)
- , m_fileHandle(INVALID_HANDLE_VALUE)
, m_fileLoadTimer(loader, &ResourceHandle::fileLoadTimer)
, m_resourceHandle(0)
, m_secondaryHandle(0)
@@ -170,7 +169,6 @@ namespace WebCore {
bool m_needsSiteSpecificQuirks;
#endif
#if USE(WININET)
- HANDLE m_fileHandle;
Timer<ResourceHandle> m_fileLoadTimer;
HINTERNET m_resourceHandle;
HINTERNET m_secondaryHandle;
diff --git a/WebCore/platform/network/mac/ResourceHandleMac.mm b/WebCore/platform/network/mac/ResourceHandleMac.mm
index f7161ec..d014bb3 100644
--- a/WebCore/platform/network/mac/ResourceHandleMac.mm
+++ b/WebCore/platform/network/mac/ResourceHandleMac.mm
@@ -29,6 +29,7 @@
#import "AuthenticationChallenge.h"
#import "AuthenticationMac.h"
#import "Base64.h"
+#import "BlobRegistry.h"
#import "BlockExceptions.h"
#import "CredentialStorage.h"
#import "DocLoader.h"
@@ -464,6 +465,12 @@ void ResourceHandle::loadResourceSynchronously(const ResourceRequest& request, S
{
LOG(Network, "ResourceHandle::loadResourceSynchronously:%@ allowStoredCredentials:%u", request.nsURLRequest(), storedCredentials);
+#if ENABLE(BLOB)
+ if (request.url().protocolIs("blob"))
+ if (blobRegistry().loadResourceSynchronously(request, error, response, data))
+ return;
+#endif
+
NSError *nsError = nil;
NSURLResponse *nsURLResponse = nil;
NSData *result = nil;
diff --git a/WebCore/platform/network/win/ResourceHandleWin.cpp b/WebCore/platform/network/win/ResourceHandleWin.cpp
index 63c84a9..3dabd91 100644
--- a/WebCore/platform/network/win/ResourceHandleWin.cpp
+++ b/WebCore/platform/network/win/ResourceHandleWin.cpp
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2004, 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2010 Patrick Gansterer <paroga@paroga.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -63,6 +64,20 @@ static const ResourceHandleEventHandler messageHandlers[] = {
&ResourceHandle::onRequestComplete
};
+static String queryHTTPHeader(HINTERNET requestHandle, DWORD infoLevel)
+{
+ DWORD bufferSize = 0;
+ HttpQueryInfoW(requestHandle, infoLevel, 0, &bufferSize, 0);
+
+ Vector<UChar> characters(bufferSize / sizeof(UChar));
+
+ if (!HttpQueryInfoW(requestHandle, infoLevel, characters.data(), &bufferSize, 0))
+ return String();
+
+ characters.removeLast(); // Remove NullTermination.
+ return String::adopt(characters);
+}
+
static int addToOutstandingJobs(ResourceHandle* job)
{
if (!jobIdMap)
@@ -122,6 +137,49 @@ static void initializeOffScreenResourceHandleWindow()
HWND_MESSAGE, 0, WebCore::instanceHandle(), 0);
}
+
+class WebCoreSynchronousLoader : public ResourceHandleClient, public Noncopyable {
+public:
+ WebCoreSynchronousLoader(ResourceError&, ResourceResponse&, Vector<char>&, const String& userAgent);
+
+ virtual void didReceiveResponse(ResourceHandle*, const ResourceResponse&);
+ virtual void didReceiveData(ResourceHandle*, const char*, int, int lengthReceived);
+ virtual void didFinishLoading(ResourceHandle*);
+ virtual void didFail(ResourceHandle*, const ResourceError&);
+
+private:
+ ResourceError& m_error;
+ ResourceResponse& m_response;
+ Vector<char>& m_data;
+};
+
+WebCoreSynchronousLoader::WebCoreSynchronousLoader(ResourceError& error, ResourceResponse& response, Vector<char>& data, const String& userAgent)
+ : m_error(error)
+ , m_response(response)
+ , m_data(data)
+{
+}
+
+void WebCoreSynchronousLoader::didReceiveResponse(ResourceHandle*, const ResourceResponse& response)
+{
+ m_response = response;
+}
+
+void WebCoreSynchronousLoader::didReceiveData(ResourceHandle*, const char* data, int length, int)
+{
+ m_data.append(data, length);
+}
+
+void WebCoreSynchronousLoader::didFinishLoading(ResourceHandle*)
+{
+}
+
+void WebCoreSynchronousLoader::didFail(ResourceHandle*, const ResourceError& error)
+{
+ m_error = error;
+}
+
+
ResourceHandleInternal::~ResourceHandleInternal()
{
if (m_fileHandle != INVALID_HANDLE_VALUE)
@@ -225,7 +283,6 @@ void ResourceHandle::onRequestComplete(LPARAM lParam)
}
HINTERNET handle = (request().httpMethod() == "POST") ? d->m_secondaryHandle : d->m_resourceHandle;
- BOOL ok = FALSE;
static const int bufferSize = 32768;
char buffer[bufferSize];
@@ -234,11 +291,31 @@ void ResourceHandle::onRequestComplete(LPARAM lParam)
buffers.lpvBuffer = buffer;
buffers.dwBufferLength = bufferSize;
- bool receivedAnyData = false;
+ BOOL ok = FALSE;
while ((ok = InternetReadFileExA(handle, &buffers, IRF_NO_WAIT, (DWORD_PTR)this)) && buffers.dwBufferLength) {
if (!hasReceivedResponse()) {
setHasReceivedResponse();
ResourceResponse response;
+ response.setURL(firstRequest().url());
+
+ String httpStatusText = queryHTTPHeader(d->m_requestHandle, HTTP_QUERY_STATUS_TEXT);
+ if (!httpStatusText.isNull())
+ response.setHTTPStatusText(httpStatusText);
+
+ String httpStatusCode = queryHTTPHeader(d->m_requestHandle, HTTP_QUERY_STATUS_CODE);
+ if (!httpStatusCode.isNull())
+ response.setHTTPStatusCode(httpStatusCode.toInt());
+
+ String httpContentLength = queryHTTPHeader(d->m_requestHandle, HTTP_QUERY_CONTENT_LENGTH);
+ if (!httpContentLength.isNull())
+ response.setExpectedContentLength(httpContentLength.toInt());
+
+ String httpContentType = queryHTTPHeader(d->m_requestHandle, HTTP_QUERY_CONTENT_TYPE);
+ if (!httpContentType.isNull()) {
+ response.setMimeType(extractMIMETypeFromMediaType(httpContentType));
+ response.setTextEncodingName(extractCharsetFromMediaType(httpContentType));
+ }
+
client()->didReceiveResponse(this, response);
}
client()->didReceiveData(this, buffer, buffers.dwBufferLength, 0);
@@ -333,20 +410,6 @@ bool ResourceHandle::start(Frame* frame)
{
ref();
if (request().url().isLocalFile()) {
- String path = request().url().path();
- // windows does not enjoy a leading slash on paths
- if (path[0] == '/')
- path = path.substring(1);
- // FIXME: This is wrong. Need to use wide version of this call.
- d->m_fileHandle = CreateFileA(path.utf8().data(), GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
-
- // FIXME: perhaps this error should be reported asynchronously for
- // consistency.
- if (d->m_fileHandle == INVALID_HANDLE_VALUE) {
- delete this;
- return false;
- }
-
d->m_fileLoadTimer.startOneShot(0.0);
return true;
} else {
@@ -409,9 +472,29 @@ bool ResourceHandle::start(Frame* frame)
}
}
-void ResourceHandle::fileLoadTimer(Timer<ResourceHandle>* timer)
+void ResourceHandle::fileLoadTimer(Timer<ResourceHandle>*)
{
+ RefPtr<ResourceHandle> protector(this);
+ deref(); // balances ref in start
+
+ String fileName = firstRequest().url().fileSystemPath();
+ HANDLE fileHandle = CreateFileW(fileName.charactersWithNullTermination(), GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
+
+ if (fileHandle == INVALID_HANDLE_VALUE) {
+ client()->didFail(this, ResourceError());
+ return;
+ }
+
ResourceResponse response;
+
+ int dotPos = fileName.reverseFind('.');
+ int slashPos = fileName.reverseFind('/');
+
+ if (slashPos < dotPos && dotPos != -1) {
+ String ext = fileName.substring(dotPos + 1);
+ response.setMimeType(MIMETypeRegistry::getMIMETypeForExtension(ext));
+ }
+
client()->didReceiveResponse(this, response);
bool result = false;
@@ -420,16 +503,13 @@ void ResourceHandle::fileLoadTimer(Timer<ResourceHandle>* timer)
do {
const int bufferSize = 8192;
char buffer[bufferSize];
- result = ReadFile(d->m_fileHandle, &buffer, bufferSize, &bytesRead, NULL);
+ result = ReadFile(fileHandle, &buffer, bufferSize, &bytesRead, 0);
if (result && bytesRead)
client()->didReceiveData(this, buffer, bytesRead, 0);
- // Check for end of file.
+ // Check for end of file.
} while (result && bytesRead);
- // FIXME: handle errors better
-
- CloseHandle(d->m_fileHandle);
- d->m_fileHandle = INVALID_HANDLE_VALUE;
+ CloseHandle(fileHandle);
client()->didFinishLoading(this);
}
@@ -449,6 +529,16 @@ void ResourceHandle::cancel()
client()->didFail(this, ResourceError());
}
+void ResourceHandle::loadResourceSynchronously(const ResourceRequest& request, StoredCredentials storedCredentials, ResourceError& error, ResourceResponse& response, Vector<char>& data, Frame* frame)
+{
+ UNUSED_PARAM(storedCredentials);
+
+ WebCoreSynchronousLoader syncLoader(error, response, data, request.httpUserAgent());
+ ResourceHandle handle(request, &syncLoader, true, false);
+
+ handle.start(frame);
+}
+
void ResourceHandle::setHasReceivedResponse(bool b)
{
d->m_hasReceivedResponse = b;
@@ -459,4 +549,36 @@ bool ResourceHandle::hasReceivedResponse() const
return d->m_hasReceivedResponse;
}
+bool ResourceHandle::willLoadFromCache(ResourceRequest&, Frame*)
+{
+ notImplemented();
+ return false;
+}
+
+void prefetchDNS(const String&)
+{
+ notImplemented();
+}
+
+PassRefPtr<SharedBuffer> ResourceHandle::bufferedData()
+{
+ ASSERT_NOT_REACHED();
+ return 0;
+}
+
+bool ResourceHandle::supportsBufferedData()
+{
+ return false;
+}
+
+bool ResourceHandle::loadsBlocked()
+{
+ return false;
+}
+
+void ResourceHandle::platformSetDefersLoading(bool)
+{
+ notImplemented();
+}
+
} // namespace WebCore