[Qt] Uploading images to Google+ using QtWebKit does not work.
authorallan.jensen@digia.com <allan.jensen@digia.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 9 Oct 2012 13:00:45 +0000 (13:00 +0000)
committerallan.jensen@digia.com <allan.jensen@digia.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 9 Oct 2012 13:00:45 +0000 (13:00 +0000)
https://bugs.webkit.org/show_bug.cgi?id=72329

Reviewed by Jocelyn Turcotte.

Source/WebCore:

Implement handling of Blob FormData, including its extensions to the File FormData.

* platform/network/qt/QNetworkReplyHandler.cpp:
(WebCore::FormDataIODevice::FormDataIODevice):
(WebCore::appendBlobResolved):
(WebCore::FormDataIODevice::prepareFormElements):
(WebCore::FormDataIODevice::computeSize):
(WebCore::FormDataIODevice::moveToNextElement):
(WebCore::FormDataIODevice::prepareCurrentElement):
(WebCore::FormDataIODevice::openFileForCurrentElement):
(WebCore::FormDataIODevice::readData):
(WebCore::QNetworkReplyHandler::sendNetworkRequest):
* platform/network/qt/QNetworkReplyHandler.h:
(FormDataIODevice):

LayoutTests:

Unskip the two BLOB tests that now passes. The rest of the BLOB tests unfortunately depend
on features we do not have.

* platform/qt/TestExpectations:

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

LayoutTests/ChangeLog
LayoutTests/platform/qt/TestExpectations
Source/WebCore/ChangeLog
Source/WebCore/platform/network/qt/QNetworkReplyHandler.cpp
Source/WebCore/platform/network/qt/QNetworkReplyHandler.h

index e780a2f..86ea282 100644 (file)
@@ -1,3 +1,15 @@
+2012-10-09  Allan Sandfeld Jensen  <allan.jensen@digia.com>
+
+        [Qt] Uploading images to Google+ using QtWebKit does not work.
+        https://bugs.webkit.org/show_bug.cgi?id=72329
+
+        Reviewed by Jocelyn Turcotte.
+
+        Unskip the two BLOB tests that now passes. The rest of the BLOB tests unfortunately depend
+        on features we do not have.
+
+        * platform/qt/TestExpectations:
+
 2012-10-09  Csaba Osztrogon√°c  <ossy@webkit.org>
 
         [Qt] Unskip and rebase now passing tests.
index 9157cb1..1cc2389 100644 (file)
@@ -629,7 +629,6 @@ fast/forms/file/input-file-re-render.html
 fast/forms/file/input-file-write-files.html
 fast/forms/file/selected-files-from-history-state.html
 http/tests/local/blob/send-hybrid-blob.html
-http/tests/local/blob/send-sliced-data-blob.html
 http/tests/local/formdata
 http/tests/security/clipboard/clipboard-file-access.html
 
@@ -763,9 +762,6 @@ http/tests/navigation/timerredirect-goback.html
 http/tests/security/401-logout/401-logout.php
 http/tests/xmlhttprequest/remember-bad-password.html
 
-# BlodBuilder is not enabled
-http/tests/local/blob/send-data-blob.html
-
 # new test introduced in r94828, but fails on Qt.
 # https://bugs.webkit.org/show_bug.cgi?id=66588
 http/tests/security/xssAuditor/script-tag-with-16bit-unicode4.html
index 4769a1d..88a051f 100644 (file)
@@ -1,3 +1,25 @@
+2012-10-09  Allan Sandfeld Jensen  <allan.jensen@digia.com>
+
+        [Qt] Uploading images to Google+ using QtWebKit does not work.
+        https://bugs.webkit.org/show_bug.cgi?id=72329
+
+        Reviewed by Jocelyn Turcotte.
+
+        Implement handling of Blob FormData, including its extensions to the File FormData.
+
+        * platform/network/qt/QNetworkReplyHandler.cpp:
+        (WebCore::FormDataIODevice::FormDataIODevice):
+        (WebCore::appendBlobResolved):
+        (WebCore::FormDataIODevice::prepareFormElements):
+        (WebCore::FormDataIODevice::computeSize):
+        (WebCore::FormDataIODevice::moveToNextElement):
+        (WebCore::FormDataIODevice::prepareCurrentElement):
+        (WebCore::FormDataIODevice::openFileForCurrentElement):
+        (WebCore::FormDataIODevice::readData):
+        (WebCore::QNetworkReplyHandler::sendNetworkRequest):
+        * platform/network/qt/QNetworkReplyHandler.h:
+        (FormDataIODevice):
+
 2012-10-09  Arpita Bahuguna  <arpitabahuguna@gmail.com>
 
         Text decorations specified on the containing block are not properly applied when ::first-line is present.
index d632c23..8abcf8c 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+    Copyright (C) 2008, 2012 Digia Plc. and/or its subsidiary(-ies)
     Copyright (C) 2007 Staikos Computing Services Inc.  <info@staikos.net>
     Copyright (C) 2008 Holger Hans Peter Freyther
 
@@ -21,6 +21,7 @@
 #include "config.h"
 #include "QNetworkReplyHandler.h"
 
+#include "BlobRegistryImpl.h"
 #include "HTTPParsers.h"
 #include "MIMETypeRegistry.h"
 #include "ResourceHandle.h"
 #include <wtf/text/CString.h>
 
 #include <QCoreApplication>
-#include <QDebug>
-
-// In Qt 4.8, the attribute for sending a request synchronously will be made public,
-// for now, use this hackish solution for setting the internal attribute.
-const QNetworkRequest::Attribute gSynchronousNetworkRequestAttribute = static_cast<QNetworkRequest::Attribute>(QNetworkRequest::HttpPipeliningWasUsedAttribute + 7);
 
 static const int gMaxRedirections = 10;
 
 namespace WebCore {
 
-// Take a deep copy of the FormDataElement
 FormDataIODevice::FormDataIODevice(FormData* data)
-    : m_formElements(data ? data->elements() : Vector<FormDataElement>())
-    , m_currentFile(0)
+    : m_currentFile(0)
     , m_currentDelta(0)
     , m_fileSize(0)
     , m_dataSize(0)
 {
     setOpenMode(FormDataIODevice::ReadOnly);
 
-    if (!m_formElements.isEmpty() && m_formElements[0].m_type == FormDataElement::encodedFile)
-        openFileForCurrentElement();
+    prepareFormElements(data);
+    prepareCurrentElement();
     computeSize();
 }
 
@@ -67,6 +61,71 @@ FormDataIODevice::~FormDataIODevice()
     delete m_currentFile;
 }
 
+#if ENABLE(BLOB)
+static void appendBlobResolved(FormData* formData, const KURL& url)
+{
+    RefPtr<BlobStorageData> blobData = static_cast<BlobRegistryImpl&>(blobRegistry()).getBlobDataFromURL(KURL(ParsedURLString, url));
+    if (blobData) {
+        BlobDataItemList::const_iterator it = blobData->items().begin();
+        const BlobDataItemList::const_iterator itend = blobData->items().end();
+        for (; it != itend; ++it) {
+            const BlobDataItem& blobItem = *it;
+            if (blobItem.type == BlobDataItem::Data)
+                formData->appendData(blobItem.data->data() + static_cast<int>(blobItem.offset), static_cast<int>(blobItem.length));
+            else if (blobItem.type == BlobDataItem::File)
+                formData->appendFileRange(blobItem.path, blobItem.offset, blobItem.length, blobItem.expectedModificationTime);
+            else if (blobItem.type == BlobDataItem::Blob)
+                appendBlobResolved(formData, blobItem.url);
+            else
+                ASSERT_NOT_REACHED();
+        }
+    }
+}
+#endif
+
+void FormDataIODevice::prepareFormElements(FormData* formData)
+{
+    if (!formData)
+        return;
+
+#if ENABLE(BLOB)
+    bool hasBlob = false;
+    Vector<FormDataElement>::const_iterator it = formData->elements().begin();
+    const Vector<FormDataElement>::const_iterator itend = formData->elements().end();
+    for (; it != itend; ++it) {
+        if (it->m_type == FormDataElement::encodedBlob) {
+            hasBlob = true;
+            break;
+        }
+    }
+
+    // Resolve all blobs so we only have file and data.
+    if (hasBlob) {
+        RefPtr<FormData> newFormData = FormData::create();
+        newFormData->setAlwaysStream(formData->alwaysStream());
+        newFormData->setIdentifier(formData->identifier());
+        it = formData->elements().begin();
+        for (; it != itend; ++it) {
+            const FormDataElement& element = *it;
+            if (element.m_type == FormDataElement::data)
+                newFormData->appendData(element.m_data.data(), element.m_data.size());
+            else if (element.m_type == FormDataElement::encodedFile)
+                newFormData->appendFileRange(element.m_filename, element.m_fileStart, element.m_fileLength, element.m_expectedFileModificationTime, element.m_shouldGenerateFile);
+            else if (element.m_type == FormDataElement::encodedBlob)
+                appendBlobResolved(newFormData.get(), element.m_url);
+            else
+                ASSERT_NOT_REACHED();
+        }
+        m_formElements = newFormData->elements();
+        return;
+    }
+#endif
+
+    // Take a deep copy of the FormDataElements
+    m_formElements = formData->elements();
+}
+
+
 qint64 FormDataIODevice::computeSize() 
 {
     for (int i = 0; i < m_formElements.size(); ++i) {
@@ -75,7 +134,14 @@ qint64 FormDataIODevice::computeSize()
             m_dataSize += element.m_data.size();
         else {
             QFileInfo fi(element.m_filename);
+#if ENABLE(BLOB)
+            qint64 fileEnd = fi.size();
+            if (element.m_fileLength != BlobDataItem::toEndOfFile)
+                fileEnd = qMin<qint64>(fi.size(), element.m_fileStart + element.m_fileLength);
+            m_fileSize += qMax<qint64>(0, fileEnd - element.m_fileStart);
+#else
             m_fileSize += fi.size();
+#endif
         }
     }
     return m_dataSize + m_fileSize;
@@ -89,10 +155,24 @@ void FormDataIODevice::moveToNextElement()
 
     m_formElements.remove(0);
 
-    if (m_formElements.isEmpty() || m_formElements[0].m_type == FormDataElement::data)
+    prepareCurrentElement();
+}
+
+void FormDataIODevice::prepareCurrentElement()
+{
+    if (m_formElements.isEmpty())
         return;
 
-    openFileForCurrentElement();
+    switch (m_formElements[0].m_type) {
+    case FormDataElement::data:
+        return;
+    case FormDataElement::encodedFile:
+        openFileForCurrentElement();
+        break;
+    default:
+        // At this point encodedBlob should already have been handled.
+        ASSERT_NOT_REACHED();
+    }
 }
 
 void FormDataIODevice::openFileForCurrentElement()
@@ -102,6 +182,17 @@ void FormDataIODevice::openFileForCurrentElement()
 
     m_currentFile->setFileName(m_formElements[0].m_filename);
     m_currentFile->open(QFile::ReadOnly);
+#if ENABLE(BLOB)
+    if (isValidFileTime(m_formElements[0].m_expectedFileModificationTime)) {
+        QFileInfo info(*m_currentFile);
+        if (!info.exists() || static_cast<time_t>(m_formElements[0].m_expectedFileModificationTime) < info.lastModified().toTime_t()) {
+            moveToNextElement();
+            return;
+        }
+    }
+    if (m_formElements[0].m_fileStart)
+        m_currentFile->seek(m_formElements[0].m_fileStart);
+#endif
 }
 
 // m_formElements[0] is the current item. If the destination buffer is
@@ -124,13 +215,23 @@ qint64 FormDataIODevice::readData(char* destination, qint64 size)
 
             if (m_currentDelta == element.m_data.size())
                 moveToNextElement();
-        } else {
-            const QByteArray data = m_currentFile->read(available);
+        } else if (element.m_type == FormDataElement::encodedFile) {
+            quint64 toCopy = available;
+#if ENABLE(BLOB)
+            if (element.m_fileLength != BlobDataItem::toEndOfFile)
+                toCopy = qMin<qint64>(toCopy, element.m_fileLength - m_currentDelta);
+#endif
+            const QByteArray data = m_currentFile->read(toCopy);
             memcpy(destination+copied, data.constData(), data.size());
+            m_currentDelta += data.size();
             copied += data.size();
 
             if (m_currentFile->atEnd() || !m_currentFile->isOpen())
                 moveToNextElement();
+#if ENABLE(BLOB)
+            else if (element.m_fileLength != BlobDataItem::toEndOfFile && m_currentDelta == element.m_fileLength)
+                moveToNextElement();
+#endif
         }
     }
 
@@ -612,7 +713,7 @@ FormDataIODevice* QNetworkReplyHandler::getIODevice(const ResourceRequest& reque
 QNetworkReply* QNetworkReplyHandler::sendNetworkRequest(QNetworkAccessManager* manager, const ResourceRequest& request)
 {
     if (m_loadType == SynchronousLoad)
-        m_request.setAttribute(gSynchronousNetworkRequestAttribute, true);
+        m_request.setAttribute(QNetworkRequest::SynchronousRequestAttribute, true);
 
     if (!manager)
         return 0;
index 4771e88..0c46f2f 100644 (file)
@@ -179,9 +179,11 @@ protected:
     qint64 writeData(const char*, qint64);
 
 private:
+    void prepareFormElements(FormData*);
     void moveToNextElement();
     qint64 computeSize();
     void openFileForCurrentElement();
+    void prepareCurrentElement();
 
 private:
     Vector<FormDataElement> m_formElements;