Reviewed by Zack.
authorlars <lars@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 21 May 2007 12:33:59 +0000 (12:33 +0000)
committerlars <lars@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 21 May 2007 12:33:59 +0000 (12:33 +0000)
        Add an API layer for network downloads. Basically QWebnetworkInterface
        is an interface class for downloading resources. QWebnetworkJob describes
        the actual object to download.

        QWebNetworkInterface has a default implementation that replaces the
        old ResourceHandleManager class in the Qt port.

        Remove the ResourceHandleManager class, it is now part of
        QWebNetworkInterface. Adapt ResourceHandle to the new way
        of things.

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

12 files changed:
WebCore/ChangeLog
WebCore/WebCore.pro
WebCore/platform/network/ResourceHandleInternal.h
WebCore/platform/network/qt/ResourceHandleManagerKDE.cpp [deleted file]
WebCore/platform/network/qt/ResourceHandleManagerKDE.h [deleted file]
WebCore/platform/network/qt/ResourceHandleManagerQt.cpp [deleted file]
WebCore/platform/network/qt/ResourceHandleManagerQt.h [deleted file]
WebCore/platform/network/qt/ResourceHandleQt.cpp
WebKitQt/Api/qwebnetworkinterface.cpp [new file with mode: 0644]
WebKitQt/Api/qwebnetworkinterface.h [new file with mode: 0644]
WebKitQt/Api/qwebnetworkinterface_p.h [new file with mode: 0644]
WebKitQt/ChangeLog

index 26f33932ece06fecd47590d16759308a126f12f8..c005b4f67216da06de82589579ef56664da81fef 100644 (file)
@@ -1,3 +1,23 @@
+2007-05-21  Lars Knoll <lars@trolltech.com>
+
+        Reviewed by Zack.
+
+        Remove the ResourceHandleManager class, it is now part of 
+        QWebNetworkInterface. Adapt ResourceHandle to the new way 
+        of things.
+
+        * WebCore.pro:
+        * platform/network/ResourceHandleInternal.h:
+        (WebCore::ResourceHandleInternal::ResourceHandleInternal):
+        * platform/network/qt/ResourceHandleManagerKDE.cpp: Removed.
+        * platform/network/qt/ResourceHandleManagerKDE.h: Removed.
+        * platform/network/qt/ResourceHandleManagerQt.cpp: Removed.
+        * platform/network/qt/ResourceHandleManagerQt.h: Removed.
+        * platform/network/qt/ResourceHandleQt.cpp:
+        (WebCore::ResourceHandle::~ResourceHandle):
+        (WebCore::ResourceHandle::start):
+        (WebCore::ResourceHandle::cancel):
+
 2007-05-21  David Hyatt  <hyatt@apple.com>
 
         Second half of fix for 13793, make sure rules=groups works properly with
index 24d98cfe50398df6b66b7acb236ac6da1e293553..b0f86b1cb82c2a4c315966b72dcaf62a3af96f81 100644 (file)
@@ -136,11 +136,12 @@ STYLESHEETS_EMBED = $$PWD/css/html4.css
 
 MANUALMOC =
 qt-port:MANUALMOC += \
-    $$PWD/platform/network/qt/ResourceHandleManagerQt.h \
     $$PWD/platform/qt/QWebPopup.h \
     $$PWD/platform/qt/SharedTimerQt.h \
     $$PWD/../WebKitQt/Api/qwebframe.h \
     $$PWD/../WebKitQt/Api/qwebpage.h \
+    $$PWD/../WebKitQt/Api/qwebnetworkinterface.h \
+    $$PWD/../WebKitQt/Api/qwebnetworkinterface_p.h \
     $$PWD/../WebKitQt/Api/qcookiejar.h \
     $$PWD/../WebKitQt/WebCoreSupport/FrameLoaderClientQt.h
 
@@ -709,7 +710,6 @@ qt-port:SOURCES += \
     platform/graphics/qt/IntRectQt.cpp \
     platform/graphics/qt/IntSizeQt.cpp \
     platform/graphics/qt/PathQt.cpp \
-    platform/network/qt/ResourceHandleManagerQt.cpp \
     platform/network/qt/ResourceHandleQt.cpp \
     editing/qt/EditorQt.cpp \
     history/qt/CachedPageQt.cpp \
@@ -754,6 +754,7 @@ qt-port:SOURCES += \
     ../WebKitQt/WebCoreSupport/EditCommandQt.cpp \
     ../WebKitQt/WebCoreSupport/FrameLoaderClientQt.cpp \
     ../WebKitQt/Api/qwebframe.cpp \
+    ../WebKitQt/Api/qwebnetworkinterface.cpp \
     ../WebKitQt/Api/qcookiejar.cpp \
     ../WebKitQt/Api/qwebpage.cpp \
     ../WebKitQt/Api/qwebpagehistory.cpp
index 8fa164b0d8bc1097120be63e4a44640197e0d990..5c0af01109d40a991b525c5ac0deeb7575d4c920 100644 (file)
@@ -45,7 +45,7 @@
 #endif
 
 #if PLATFORM(QT)
-#include <QString>
+class QWebNetworkJob;
 #endif
 
 #if PLATFORM(MAC)
@@ -93,6 +93,9 @@ namespace WebCore {
             , m_url(0)
             , m_customHeaders(0)
 #endif
+#if PLATFORM(QT)
+            , m_job(0)
+#endif
 #if PLATFORM(MAC)
             , m_currentMacChallenge(nil)
 #elif USE(CFNETWORK)
@@ -139,6 +142,9 @@ namespace WebCore {
         char* m_url;
         struct curl_slist* m_customHeaders;        
 #endif
+#if PLATFORM(QT)
+        QWebNetworkJob *m_job;
+#endif
 #if PLATFORM(MAC)
         NSURLAuthenticationChallenge *m_currentMacChallenge;
 #endif
diff --git a/WebCore/platform/network/qt/ResourceHandleManagerKDE.cpp b/WebCore/platform/network/qt/ResourceHandleManagerKDE.cpp
deleted file mode 100644 (file)
index 9a95e58..0000000
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org>
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. 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.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-
-#include <kio/job.h>
-
-#include <QEvent>
-#include <QFile>
-
-#include "FrameQt.h"
-#include "ResourceHandleManager.h"
-#include "ResourceHandleInternal.h"
-
-namespace WebCore {
-
-static ResourceHandleManager* s_self = 0;
-
-
-ResourceHandleManager* ResourceHandleManager::self()
-{
-    if (!s_self)
-        s_self = new ResourceHandleManager();
-
-    return s_self;
-}
-
-
-ResourceHandleManager::ResourceHandleManager()
-    : m_jobToKioMap()
-    , m_kioToJobMap()
-    , m_frameClient(0)
-{
-}
-
-ResourceHandleManager::~ResourceHandleManager()
-{
-}
-
-void ResourceHandleManager::slotData(KIO::Job* kioJob, const QByteArray& data)
-{
-    ResourceHandle* job = 0;
-
-    // Check if we know about 'kioJob'...
-    QMap<KIO::Job*, ResourceHandle*>::const_iterator it = m_kioToJobMap.find(kioJob);
-    if (it != m_kioToJobMap.end())
-        job = it.value();
-
-    if (!job)
-        return;
-
-    ResourceHandleInternal* d = job->getInternal();
-    if (!d || !d->m_client)
-        return;
-
-    d->m_client->didReceiveData(job, data.data(), data.size());
-}
-
-void ResourceHandleManager::slotMimetype(KIO::Job* kioJob, const QString& type)
-{
-    ResourceHandle* job = 0;
-
-    // Check if we know about 'kioJob'...
-    QMap<KIO::Job*, ResourceHandle*>::const_iterator it = m_kioToJobMap.find(kioJob);
-    if (it != m_kioToJobMap.end())
-        job = it.value();
-
-    if (!job)
-        return;
-
-    ResourceHandleInternal* d = job->getInternal();
-    if (!d || !d->m_client)
-        return;
-
-    d->m_mimetype = type;
-}
-
-void ResourceHandleManager::slotResult(KJob* kjob)
-{
-    KIO::Job* kioJob = qobject_cast<KIO::Job*>(kjob);
-    if (!kioJob)
-        return;
-
-    ResourceHandle* job = 0;
-
-    // Check if we know about 'kioJob'...
-    QMap<KIO::Job*, ResourceHandle*>::const_iterator it = m_kioToJobMap.find(kioJob);
-    if (it != m_kioToJobMap.end())
-        job = it.value();
-
-    if (!job)
-        return;
-
-    job->setError(kjob->error());
-    remove(job);
-
-    ASSERT(m_frameClient);
-    m_frameClient->checkLoaded();
-}
-
-void ResourceHandleManager::remove(ResourceHandle* job)
-{
-    ResourceHandleInternal* d = job->getInternal();
-    if (!d || !d->m_client)
-        return;
-
-    KIO::Job* kioJob = 0;
-
-    // Check if we know about 'job'...
-    QMap<ResourceHandle*, KIO::Job*>::const_iterator it = m_jobToKioMap.find(job);
-    if (it != m_jobToKioMap.end())
-        kioJob = it.value();
-
-    if (!kioJob)
-        return;
-
-    QString headers = kioJob->queryMetaData("HTTP-Headers");
-    if (job->method() == "GET")
-        d->m_charset = job->extractCharsetFromHeaders(headers);
-    else if (job->method() == "POST") {
-        // Will take care of informing our client...
-        // This must be called before didFinishLoading(),
-        // otherwhise assembleResponseHeaders() is called too early...
-        RefPtr<PlatformResponseQt> response(new PlatformResponseQt());
-        response->data = headers;
-        response->url = job->url().url();
-
-        job->receivedResponse(response);
-    }
-
-    d->m_client->receivedAllData(job, 0);
-    d->m_client->didFinishLoading(job);
-
-    m_jobToKioMap.remove(job);
-    m_kioToJobMap.remove(kioJob);
-}
-
-void ResourceHandleManager::add(ResourceHandle* job, FrameQtClient* frameClient)
-{
-    ResourceHandleInternal* d = job->getInternal();
-    DeprecatedString url = d->m_request.url().url();
-
-    KIO::Job* kioJob = 0;
-
-    if (job->method() == "POST") {
-        DeprecatedString postData = job->postData().flattenToString().deprecatedString();
-        QByteArray postDataArray(postData.ascii(), postData.length());
-
-        kioJob = KIO::http_post(KUrl(url), postDataArray, false);
-        kioJob->addMetaData("PropagateHttpHeader", "true");
-        kioJob->addMetaData("content-type", "Content-Type: application/x-www-form-urlencoded");
-    } else
-        kioJob = KIO::get(KUrl(url), false, false);
-
-    Q_ASSERT(kioJob != 0);
-
-    QObject::connect(kioJob, SIGNAL(data(KIO::Job*, const QByteArray&)), this, SLOT(slotData(KIO::Job*, const QByteArray&)));
-    QObject::connect(kioJob, SIGNAL(mimetype(KIO::Job*, const QString&)), this, SLOT(slotMimetype(KIO::Job*, const QString&)));
-    QObject::connect(kioJob, SIGNAL(result(KJob*)), this, SLOT(slotResult(KJob*)));
-
-    m_jobToKioMap.insert(job, kioJob);
-    m_kioToJobMap.insert(kioJob, job);
-
-    if (!m_frameClient)
-        m_frameClient = frameClient;
-    else
-        ASSERT(m_frameClient == frameClient);
-}
-
-void ResourceHandleManager::cancel(ResourceHandle* job)
-{
-    remove(job);
-    job->setError(1);
-}
-
-} // namespace WebCore
-
-#include "ResourceHandleManager.moc"
diff --git a/WebCore/platform/network/qt/ResourceHandleManagerKDE.h b/WebCore/platform/network/qt/ResourceHandleManagerKDE.h
deleted file mode 100644 (file)
index 6ce8543..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org>
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. 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.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 ResourceHandleManagerKDE_h
-#define ResourceHandleManagerKDE_h
-
-#include <QMap>
-#include <QObject>
-
-#include "ResourceHandle.h"
-
-namespace KIO {
-class Job;
-}
-class KJob;
-
-namespace WebCore {
-
-class FrameQtClient;
-
-class ResourceHandleManager : public QObject
-{
-    Q_OBJECT
-public:
-    static ResourceHandleManager* self();
-
-    void add(ResourceHandle*, FrameQtClient*);
-    void cancel(ResourceHandle*);
-
-public Q_SLOTS:
-    void slotData(KIO::Job*, const QByteArray& data);
-    void slotMimetype(KIO::Job*, const QString& type);
-    void slotResult(KJob*);
-    void deliverJobData(QtJob* , const QByteArray&);
-
-private:
-    ResourceHandleManager();
-    ~ResourceHandleManager();
-
-    void remove(ResourceHandle*);
-
-    // KIO Job <-> WebKit Job mapping
-    QMap<ResourceHandle*, KIO::Job*> m_jobToKioMap;
-    QMap<KIO::Job*, ResourceHandle*> m_kioToJobMap;
-
-    FrameQtClient* m_frameClient;
-};
-
-}
-
-#endif
diff --git a/WebCore/platform/network/qt/ResourceHandleManagerQt.cpp b/WebCore/platform/network/qt/ResourceHandleManagerQt.cpp
deleted file mode 100644 (file)
index 76d9d04..0000000
+++ /dev/null
@@ -1,674 +0,0 @@
-/*
- * Copyright (C) 2006 Enrico Ros <enrico.ros@m31engineering.it>
- * Copyright (C) 2006 Trolltech ASA
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. 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.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-
-#include "CString.h"
-#include "CookieJar.h"
-#include "ResourceHandle.h"
-#include "ResourceHandleClient.h"
-#include "ResourceResponse.h"
-#include "ResourceHandleManagerQt.h"
-#include "ResourceHandleInternal.h"
-#include "ResourceError.h"
-#include "MimeTypeRegistry.h"
-
-#include <QCoreApplication>
-#include <QHttpRequestHeader>
-#include <QFile>
-#include <QMap>
-#include <QByteArray>
-#include <QUrl>
-#include <qdebug.h>
-
-#define notImplemented() qDebug("FIXME: UNIMPLEMENTED: %s:%d (%s)", __FILE__, __LINE__, __FUNCTION__)
-
-#if 0
-#define DEBUG qDebug
-#else
-#define DEBUG if (1) {} else qDebug
-#endif
-
-namespace WebCore {
-
-static ResourceHandleManager* s_self = 0;
-
-ResourceHandleManager::ResourceHandleManager()
-{
-    m_fileLoader = new LoaderThread(this, LoaderThread::File);
-    m_fileLoader->start();
-    m_networkLoader = new LoaderThread(this, LoaderThread::Network);
-    m_networkLoader->start();
-
-    m_fileLoader->waitForSetup();
-    m_networkLoader->waitForSetup();
-}
-
-ResourceHandleManager::~ResourceHandleManager()
-{
-    m_networkLoader->quit();
-    m_fileLoader->quit();
-}
-
-ResourceHandleManager* ResourceHandleManager::self()
-{
-    if (!s_self)
-        s_self = new ResourceHandleManager();
-
-    return s_self;
-}
-
-RequestQt::RequestQt(ResourceHandle* res)
-    : resource(res), redirected(false), cancelled(false)
-{
-    setURL(res->url());
-    request = QHttpRequestHeader(resource->method(), url.path() + url.query());
-    request.setValue(QLatin1String("User-Agent"),
-                           QLatin1String("Mozilla/5.0 (PC; U; Intel; Linux; en) AppleWebKit/420+ (KHTML, like Gecko)"));
-    request.setValue(QLatin1String("Connection"), QLatin1String("Keep-Alive"));
-    QString cookies = WebCore::cookies(url);
-    if (!cookies.isEmpty())
-        request.setValue(QLatin1String("Cookie"), cookies);
-
-    const HTTPHeaderMap& loaderHeaders = resource->requestHeaders();
-    HTTPHeaderMap::const_iterator end = loaderHeaders.end();
-    for (HTTPHeaderMap::const_iterator it = loaderHeaders.begin(); it != end; ++it)
-        request.setValue(it->first, it->second);
-
-    int port = url.port();
-    if (port && port != 80)
-        request.setValue(QLatin1String("Host"), url.host() + QLatin1Char(':') + QString::number(port));
-    else
-        request.setValue(QLatin1String("Host"), url.host());
-
-    int id;
-    // handle and perform a 'POST' request
-    if (resource->method() == "POST") {
-        request.setValue(QLatin1String("PropagateHttpHeader"), QLatin1String("true"));
-        request.setValue(QLatin1String("content-type"), QLatin1String("Content-Type: application/x-www-form-urlencoded"));
-
-        DeprecatedString pd = resource->postData()->flattenToString().deprecatedString();
-        postData = QByteArray(pd.ascii(), pd.length());
-        request.setValue(QLatin1String("content-length"), QString::number(postData.size()));
-    } else if (resource->method() != "GET") {
-        // or.. don't know what to do! (probably a request error!!)
-        // but treat it like a 'GET' request
-        notImplemented();
-        qWarning("REQUEST: [%s]\n", qPrintable(request.toString()));
-    }
-//     DEBUG() << "RequestQt::RequestQt: http header:";
-//     DEBUG() << request.toString();
-}
-
-
-void RequestQt::setURL(const KURL &u)
-{
-    url = u;
-    int port = url.port();
-    if (port && port != 80)
-        request.setValue(QLatin1String("Host"), url.host() + QLatin1Char(':') + QString::number(port));
-    else
-        request.setValue(QLatin1String("Host"), url.host());
-    hostInfo = HostInfo(u);
-    qurl = url.url();
-}
-
-void ResourceHandleManager::add(ResourceHandle* resource)
-{
-    ASSERT(resource);
-
-    // check for (probably) broken requests
-    if (resource->method() != "GET" && resource->method() != "POST") {
-        notImplemented();
-        return;
-    }
-
-    RequestQt* request = new RequestQt(resource);
-    add(request);
-}
-
-void ResourceHandleManager::add(RequestQt* request)
-{
-    Q_ASSERT(!pendingRequests.value(request->resource));
-
-    pendingRequests[request->resource] = request;
-
-    //DEBUG() << "ResourceHandleManager::add" << request->hostInfo.protocol << request->hostInfo.host;
-    // check for not implemented protocols
-    String protocol = request->hostInfo.protocol;
-    if (protocol == "http") {
-        //DEBUG() << "networkRequest";
-        emit networkRequest(request);
-        return;
-    }
-
-    // "file", "data" and all unhandled stuff go through here
-    //DEBUG() << "fileRequest";
-    emit fileRequest(request);
-    return;
-}
-
-
-void ResourceHandleManager::cancel(ResourceHandle* resource)
-{
-    ResourceHandleClient* client = resource->client();
-    if (!client)
-        return;
-    RequestQt *req = pendingRequests.value(resource);
-    if (!req)
-        return;
-
-    DEBUG() << "ResourceHandleManager::cancel" << resource->url().path();
-    
-    RequestQt* request = pendingRequests.take(resource);
-    if (!request)
-        return;
-    request->cancelled = true;
-
-    String protocol = request->hostInfo.protocol;
-    if (protocol == "http") 
-        emit networkCancel(request);
-}
-
-
-void ResourceHandleManager::receivedResponse(RequestQt* request)
-{
-    if (request->cancelled)
-        return;
-    Q_ASSERT(pendingRequests.value(request->resource) == request);
-    DEBUG() << "ResourceHandleManager::receivedResponse:";
-    DEBUG() << request->response.toString();
-
-    ResourceHandleClient* client = request->resource->client();
-    if (!client)
-        return;
-
-    QStringList cookies = request->response.allValues("Set-Cookie");
-    foreach (QString c, cookies) {
-        setCookies(request->url, request->url, c);
-    }
-    QString contentType = request->response.value("Content-Type");
-    QString encoding;
-    int idx = contentType.indexOf(QLatin1Char(';'));
-    if (idx > 0) {
-        QString remainder = contentType.mid(idx + 1).toLower();
-        contentType = contentType.left(idx).trimmed();
-
-        idx = remainder.indexOf("charset");
-        if (idx >= 0) {
-            idx = remainder.indexOf(QLatin1Char('='), idx);
-            if (idx >= 0)
-                encoding = remainder.mid(idx + 1).trimmed();
-        }
-    }
-    if (contentType.isEmpty()) {
-        // let's try to guess from the extension
-        QString extension = request->qurl.path();
-        int index = extension.lastIndexOf(QLatin1Char('.'));
-        if (index > 0) {
-            extension = extension.mid(index + 1);
-            contentType = MimeTypeRegistry::getMIMETypeForExtension(extension);
-        }
-    }
-//     qDebug() << "Content-Type=" << contentType;
-//     qDebug() << "Encoding=" << encoding;
-
-
-    ResourceResponse response(request->url, contentType,
-                              0 /* FIXME */,
-                              encoding,
-                              String() /* FIXME */);
-
-    int statusCode = request->response.statusCode();
-    response.setHTTPStatusCode(statusCode);
-    /* Fill in the other fields */
-
-    if (statusCode >= 300 && statusCode < 400) {
-        // we're on a redirect page! if the 'Location:' field is valid, we redirect
-        QString location = request->response.value("location");
-        DEBUG() << "Redirection";
-        if (!location.isEmpty()) {
-            ResourceRequest newRequest = request->resource->request();
-            newRequest.setURL(DeprecatedString(location));
-            client->willSendRequest(request->resource, newRequest, response);
-            request->request.setRequest(request->request.method(), newRequest.url().path() + newRequest.url().query());
-            request->setURL(newRequest.url());
-            request->redirected = true;
-            return;
-        }
-    }
-
-
-    client->didReceiveResponse(request->resource, response);
-}
-
-void ResourceHandleManager::receivedData(RequestQt* request, const QByteArray& data)
-{
-    if (request->cancelled || request->redirected)
-        return;
-    Q_ASSERT(pendingRequests.value(request->resource) == request);
-
-    ResourceHandleClient* client = request->resource->client();
-    if (!client)
-        return;
-
-    DEBUG() << "receivedData" << request->url.path();
-    client->didReceiveData(request->resource, data.constData(), data.length(), data.length() /*FixMe*/);
-}
-
-void ResourceHandleManager::receivedFinished(RequestQt* request, int errorCode)
-{
-    if (request->cancelled) {
-        delete request;
-        return;
-    }
-    DEBUG() << "receivedFinished" << errorCode << request->url.path();
-    Q_ASSERT(pendingRequests.value(request->resource) == request);
-
-    pendingRequests.remove(request->resource);
-
-    if (request->redirected) {
-        request->redirected = false;
-        add(request);
-        return;
-    }
-
-    ResourceHandleClient* client = request->resource->client();
-    if (!client)
-        return;
-
-    if (errorCode) {
-        //FIXME: error setting error was removed from ResourceHandle
-        client->didFail(request->resource,
-                        ResourceError(request->qurl.host(), request->response.statusCode(),
-                                      request->qurl.toString(), String()));
-    } else {
-        client->didFinishLoading(request->resource);
-    }
-    DEBUG() << "receivedFinished done" << request->url.path();
-    delete request;
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-LoaderThread::LoaderThread(ResourceHandleManager *manager, Type type)
-    : QThread(manager), m_type(type), m_loader(0), m_manager(manager), m_setup(false)
-{
-}
-
-void LoaderThread::run()
-{
-    switch (m_type) {
-    case Network:
-        m_loader = new NetworkLoader;
-        connect(m_manager, SIGNAL(networkRequest(RequestQt*)),
-                m_loader, SLOT(request(RequestQt*)));
-        connect(m_manager, SIGNAL(networkCancel(RequestQt*)),
-                m_loader, SLOT(cancel(RequestQt*)));
-        break;
-    case File:
-        m_loader = new FileLoader;
-        connect(m_manager, SIGNAL(fileRequest(RequestQt*)),
-                m_loader, SLOT(request(RequestQt*)));
-        break;
-    }
-    connect(m_loader, SIGNAL(receivedResponse(RequestQt*)),
-            m_manager, SLOT(receivedResponse(RequestQt*)));
-    connect(m_loader, SIGNAL(receivedData(RequestQt*, QByteArray)),
-            m_manager, SLOT(receivedData(RequestQt*, QByteArray)));
-    connect(m_loader, SIGNAL(receivedFinished(RequestQt*, int)),
-            m_manager, SLOT(receivedFinished(RequestQt*, int)));
-    DEBUG() << "calling exec";
-    m_setup = true;
-    exec();
-    DEBUG() << "done exec";
-    delete m_loader;
-}
-
-/////////////////////////////////////////////////////////////////////////////
-FileLoader::FileLoader()
-    : QObject(0)
-{
-    DEBUG() << "FileLoader::FileLoader";
-}
-
-
-void FileLoader::request(RequestQt* request)
-{
-    DEBUG() << "FileLoader::request" << request->request.path();
-
-    if (request->cancelled) {
-        sendData(request, 400, QByteArray());
-        return;
-    }
-    
-    if (request->hostInfo.protocol == QLatin1String("data")) {
-        parseDataUrl(request);
-        return;
-    }
-
-    int statusCode = 200;
-    QByteArray data;
-    if (!request->hostInfo.isLocalFile()) {
-        statusCode = 404;
-    } else if (request->postData.isEmpty()) {
-        QFile f(QString(request->qurl.path()));
-        DEBUG() << "opening" << QString(request->qurl.path());
-
-        if (f.open(QIODevice::ReadOnly)) {
-            request->response.setStatusLine(200);        
-            data = f.readAll();
-        } else {
-            statusCode = 404;
-        }
-    } else {
-        statusCode = 404;
-    }
-    sendData(request, statusCode, data);
-}
-
-void FileLoader::sendData(RequestQt* request, int statusCode, const QByteArray &data)
-{
-    int error = statusCode >= 400 ? 1 : 0;
-    if (!request->cancelled) {
-        request->response.setStatusLine(statusCode);
-        emit receivedResponse(request);
-        if (!data.isEmpty())
-            emit receivedData(request, data);
-    }
-    emit receivedFinished(request, error);
-}
-
-void FileLoader::parseDataUrl(RequestQt* request)
-{
-    QByteArray data = request->qurl.toString().toLatin1();
-    //qDebug() << "handling data url:" << data; 
-
-    ASSERT(data.startsWith("data:"));
-
-    // Here's the syntax of data URLs:
-    // dataurl    := "data:" [ mediatype ] [ ";base64" ] "," data
-    // mediatype  := [ type "/" subtype ] *( ";" parameter )
-    // data       := *urlchar
-    // parameter  := attribute "=" value
-    QByteArray header;
-    bool base64 = false;
-
-    int index = data.indexOf(',');
-    if (index != -1) {
-        header = data.mid(5, index - 5);
-        header = header.toLower();
-        //qDebug() << "header=" << header;
-        data = data.mid(index+1);
-        //qDebug() << "data=" << data;
-
-        if (header.endsWith(";base64")) {
-            //qDebug() << "base64";
-            base64 = true;
-            header = header.left(header.length() - 7);
-            //qDebug() << "mime=" << header;
-        }        
-    } else {
-        data = QByteArray();
-    }
-    if (base64) {
-        data = QByteArray::fromBase64(data);
-    } else {
-        data = QUrl::fromPercentEncoding(data).toLatin1();
-    }
-
-    if (header.isEmpty()) 
-        header = "text/plain;charset=US-ASCII";
-    int statusCode = data.isEmpty() ? 404 : 200;
-    request->response.setContentType(header);
-    request->response.setContentLength(data.size());
-
-    sendData(request, statusCode, data);
-}
-
-
-/////////////////////////////////////////////////////////////////////////////
-WebCoreHttp::WebCoreHttp(NetworkLoader* parent, const HostInfo &hi)
-    : info(hi),
-      m_loader(parent),
-      m_inCancel(false)
-{
-    for (int i = 0; i < 2; ++i) {
-        connection[i].http = new QHttp(info.host, info.port);
-        connection[i].current = 0;
-        connect(connection[i].http, SIGNAL(responseHeaderReceived(const QHttpResponseHeader&)),
-                this, SLOT(onResponseHeaderReceived(const QHttpResponseHeader&)));
-        connect(connection[i].http, SIGNAL(readyRead(const QHttpResponseHeader&)),
-                this, SLOT(onReadyRead()));
-        connect(connection[i].http, SIGNAL(requestFinished(int, bool)),
-                this, SLOT(onRequestFinished(int, bool)));
-        connect(connection[i].http, SIGNAL(stateChanged(int)),
-                this, SLOT(onStateChanged(int)));
-    }
-}
-
-WebCoreHttp::~WebCoreHttp()
-{
-}
-
-void WebCoreHttp::request(RequestQt *req)
-{
-    DEBUG() << ">>>>>>>>>>>>>> WebCoreHttp::request";
-    DEBUG() << req->request.toString() << "\n";
-    m_pendingRequests.append(req);
-
-    scheduleNextRequest();
-}
-
-void WebCoreHttp::scheduleNextRequest()
-{
-    int c = 0;
-    for (; c < 2; ++c) {
-        if (!connection[c].current)
-            break;
-    }
-    if (c >= 2)
-        return;
-
-    RequestQt *req = 0;
-    while (!req && !m_pendingRequests.isEmpty()) {
-        req = m_pendingRequests.takeFirst();
-        if (req->cancelled) {
-            emit m_loader->receivedFinished(req, 1);
-            req = 0;
-        }
-    }
-    if (!req)
-        return;
-    
-    QHttp *http = connection[c].http;
-    if (!req->postData.isEmpty())
-        http->request(req->request, req->postData);
-    else
-        http->request(req->request);
-    connection[c].current = req;
-
-    DEBUG() << "WebCoreHttp::scheduleNextRequest: using connection" << c;
-//     DEBUG() << req->request.toString();
-}
-
-int WebCoreHttp::getConnection()
-{
-    QObject *o = sender();
-    int c;
-    if (o == connection[0].http) {
-        c = 0;
-    } else {
-        Q_ASSERT(o == connection[1].http);
-        c = 1;
-    }
-    //Q_ASSERT(connection[c].current);
-    return c;
-}
-
-void WebCoreHttp::onResponseHeaderReceived(const QHttpResponseHeader &resp)
-{
-    int c = getConnection();
-    RequestQt *req = connection[c].current;
-    DEBUG() << "WebCoreHttp::slotResponseHeaderReceived connection=" << c;
-
-    req->response = resp;
-
-    emit m_loader->receivedResponse(req);
-}
-
-void WebCoreHttp::onReadyRead()
-{
-    int c = getConnection();
-    RequestQt *req = connection[c].current;
-    QHttp *http = connection[c].http;
-    DEBUG() << "WebCoreHttp::slotReadyRead connection=" << c;
-
-    QByteArray data;
-    data.resize(http->bytesAvailable());
-    http->read(data.data(), data.length());
-    emit m_loader->receivedData(req, data);
-}
-
-void WebCoreHttp::onRequestFinished(int, bool error)
-{
-    int c = getConnection();
-    RequestQt *req = connection[c].current;
-    if (!req) {
-        scheduleNextRequest();
-        return;
-    }
-    QHttp *http = connection[c].http;
-    DEBUG() << "WebCoreHttp::slotFinished connection=" << c << error << req;
-
-    if (error)
-        DEBUG() << "   error: " << http->errorString();
-
-    if (!error && http->bytesAvailable()) {
-        QByteArray data;
-        data.resize(http->bytesAvailable());
-        http->read(data.data(), data.length());
-        emit m_loader->receivedData(req, data);
-    }
-    emit m_loader->receivedFinished(req, error ? 1 : 0);
-
-    connection[c].current = 0;
-    scheduleNextRequest();
-}
-
-void WebCoreHttp::onStateChanged(int state)
-{
-    if (state == QHttp::Closing || state == QHttp::Unconnected) {
-        if (!m_inCancel && m_pendingRequests.isEmpty()
-            && !connection[0].current && !connection[1].current)
-            emit connectionClosed(info);
-    }
-}
-
-void WebCoreHttp::cancel(RequestQt* request)
-{
-    bool doEmit = true;
-    m_inCancel = true;
-    for (int i = 0; i < 2; ++i) {
-        if (request == connection[i].current) {
-            connection[i].http->abort();
-            doEmit = false;
-        }
-    }
-    m_pendingRequests.removeAll(request);
-    m_inCancel = false;
-
-    if (doEmit)
-        emit m_loader->receivedFinished(request, 1);
-
-    if (m_pendingRequests.isEmpty()
-        && !connection[0].current && !connection[1].current)
-        emit connectionClosed(info);
-}
-
-
-static uint qHash(const HostInfo &info)
-{
-    return qHash(info.host) + info.port;
-}
-
-static bool operator==(const HostInfo &i1, const HostInfo &i2)
-{
-    return i1.port == i2.port && i1.host == i2.host;
-}
-
-HostInfo::HostInfo(const KURL& url)
-    : protocol(url.protocol())
-    , host(url.host())
-    , port(url.port())
-{
-    if (!port)
-        port = 80;
-}
-
-NetworkLoader::NetworkLoader()
-    : QObject(0)
-{
-}
-
-NetworkLoader::~NetworkLoader()
-{
-}
-
-void NetworkLoader::request(RequestQt* request)
-{
-    DEBUG() << "NetworkLoader::request";
-    WebCoreHttp *httpConnection = m_hostMapping.value(request->hostInfo);
-    if (!httpConnection) {
-        // #### fix custom ports
-        DEBUG() << "   new connection to" << request->hostInfo.host << request->hostInfo.port;
-        httpConnection = new WebCoreHttp(this, request->hostInfo);
-        connect(httpConnection, SIGNAL(connectionClosed(const HostInfo&)),
-                this, SLOT(connectionClosed(const HostInfo&)));
-
-        m_hostMapping[request->hostInfo] = httpConnection;
-    }
-    httpConnection->request(request);
-}
-void NetworkLoader::connectionClosed(const HostInfo& info)
-{
-    DEBUG() << "Disconnected";
-    WebCoreHttp *connection = m_hostMapping.take(info);
-    delete connection;
-}
-
-void NetworkLoader::cancel(RequestQt* request)
-{
-    DEBUG() << "NetworkLoader::cancel";
-    WebCoreHttp *httpConnection = m_hostMapping.value(request->hostInfo);
-    if (httpConnection)
-        httpConnection->cancel(request);
-}
-
-} // namespace WebCore
-
-#include "ResourceHandleManagerQt.moc"
diff --git a/WebCore/platform/network/qt/ResourceHandleManagerQt.h b/WebCore/platform/network/qt/ResourceHandleManagerQt.h
deleted file mode 100644 (file)
index be37c54..0000000
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- * Copyright (C) 2006 Enrico Ros <enrico.ros@m31engineering.it>
- * Copyright (C) 2006 Trolltech ASA
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. 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.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 ResourceHandleManagerQt_H
-#define ResourceHandleManagerQt_H
-
-#include <QHash>
-#include <QHttp>
-#include <QBuffer>
-#include <QObject>
-#include <QThread>
-#include <QString>
-#include <QEvent>
-#include <QUrl>
-
-namespace WebCore {
-
-class LoaderThread;
-class ResourceHandle;
-class NetworkLoader;
-
-struct HostInfo {
-    HostInfo() {}
-    HostInfo(const KURL& url);
-    QString protocol;
-    QString host;
-    int port;
-    bool isLocalFile() { return protocol.isEmpty() || protocol == QLatin1String("file"); }
-};
-    
-class RequestQt
-{
-public:
-    RequestQt(ResourceHandle*);
-    void setURL(const KURL &url);
-    // not thread safe, don't use in other threads
-    KURL url;
-
-    QUrl qurl;
-    ResourceHandle* resource;
-
-    // to be used by other threads
-    HostInfo hostInfo;
-    QByteArray postData;
-    QHttpRequestHeader request;
-    QHttpResponseHeader response;
-    bool redirected;
-    bool cancelled;
-};
-
-/**
- * @class ResourceHandleManager
- * @short Download Controller: handle ResourceHandles using a pool of threads
- */
-class ResourceHandleManager : public QObject {
-    Q_OBJECT
-public:
-    static ResourceHandleManager* self();
-
-    void add(ResourceHandle*);
-    void add(RequestQt* request);
-    void cancel(ResourceHandle*);
-
-public slots:
-    void receivedResponse(RequestQt*);
-    void receivedData(RequestQt*, const QByteArray& data);
-    void receivedFinished(RequestQt*, int errorCode);
-signals:
-    void networkRequest(RequestQt*);
-    void networkCancel(RequestQt*);
-    void fileRequest(RequestQt*);
-
-private:
-    ResourceHandleManager();
-    ~ResourceHandleManager();
-
-    LoaderThread *m_networkLoader;
-    LoaderThread *m_fileLoader;
-
-    QHash<ResourceHandle *, RequestQt *> pendingRequests;
-};
-
-
-class LoaderThread : public QThread {
-    Q_OBJECT
-public:
-    enum Type {
-        Network,
-        File
-    };
-    LoaderThread(ResourceHandleManager *manager, Type type);
-
-    void waitForSetup() { while (!m_setup); }
-protected:
-    void run();
-private:
-    Type m_type;
-    QObject* m_loader;
-    ResourceHandleManager* m_manager;
-    volatile bool m_setup;
-};
-
-class FileLoader : public QObject {
-    Q_OBJECT
-public:
-    FileLoader();
-
-public slots:
-    void request(RequestQt*);
-
-signals:
-    void receivedResponse(RequestQt* resource);
-    void receivedData(RequestQt* resource, const QByteArray &data);
-    void receivedFinished(RequestQt* resource, int errorCode);
-
-private:
-    void parseDataUrl(RequestQt* request);
-    void sendData(RequestQt* request, int statusCode, const QByteArray &data);
-};
-
-
-class WebCoreHttp : public QObject
-{
-    Q_OBJECT
-public:
-    WebCoreHttp(NetworkLoader* parent, const HostInfo&);
-    ~WebCoreHttp();
-
-    void request(RequestQt* resource);
-    void cancel(RequestQt*);
-
-signals:
-    void connectionClosed(const HostInfo &);
-
-private slots:
-    void onResponseHeaderReceived(const QHttpResponseHeader& resp);
-    void onReadyRead();
-    void onRequestFinished(int, bool);
-    void onStateChanged(int);
-
-    void scheduleNextRequest();
-
-    int getConnection();
-
-public:
-    HostInfo info;
-private:
-    NetworkLoader* m_loader;
-    QList<RequestQt*> m_pendingRequests;
-    struct HttpConnection {
-        QHttp *http;
-        RequestQt *current;
-    };
-    HttpConnection connection[2];
-    bool m_inCancel;
-};
-
-class NetworkLoader : public QObject {
-    Q_OBJECT
-public:
-    NetworkLoader();
-    ~NetworkLoader();
-
-
-public slots:
-    void request(RequestQt*);
-    void cancel(RequestQt*);
-    void connectionClosed(const HostInfo &);
-
-signals:
-    void receivedResponse(RequestQt* resource);
-    void receivedData(RequestQt* resource, const QByteArray &data);
-    void receivedFinished(RequestQt* resource, int errorCode);
-private:
-    friend class WebCoreHttp;
-    QHash<HostInfo, WebCoreHttp *> m_hostMapping;
-};
-
-
-}
-
-#endif
index 2c2a86d76be8f22674fb2a31be31edc1195ec7cb..86cab69bd4d28246a8afcd7fcac303e4c9b7e725 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2007 Trolltech AS
  *
  * All rights reserved.
  *
 
 #include "config.h"
 
-#if PLATFORM(KDE)
-#include <kio/job.h>
-#endif
-
 #include <QRegExp>
 
 #include "Frame.h"
 #include "DocLoader.h"
 #include "ResourceHandle.h"
 #include "DeprecatedString.h"
-#include "ResourceHandleManagerQt.h"
 #include "ResourceHandleInternal.h"
+#include "qwebnetworkinterface_p.h"
+
 
 #define notImplemented() qDebug("FIXME: UNIMPLEMENTED: %s:%d (%s)", __FILE__, __LINE__, __FUNCTION__)
 
@@ -50,20 +48,32 @@ ResourceHandleInternal::~ResourceHandleInternal()
 
 ResourceHandle::~ResourceHandle()
 {
-    cancel();
+    if (d->m_job)
+        cancel();
 }
 
 bool ResourceHandle::start(Frame* frame)
 {
-    ASSERT(frame);
+    if (!frame)
+        return false;
+
+    // If we are no longer attached to a Page, this must be an attempted load from an
+    // onUnload handler, so let's just block it.
+    if (!frame->page())
+        return false;
+
+    // check for (probably) broken requests
+    if (method() != "GET" && method() != "POST") {
+        notImplemented();
+        return false;
+    }
 
-    ResourceHandleManager::self()->add(this);
-    return true;
+    return QWebNetworkManager::self()->add(this);
 }
 
 void ResourceHandle::cancel()
 {
-    ResourceHandleManager::self()->cancel(this);
+    QWebNetworkManager::self()->cancel(this);
 }
 
 bool ResourceHandle::loadsBlocked()
diff --git a/WebKitQt/Api/qwebnetworkinterface.cpp b/WebKitQt/Api/qwebnetworkinterface.cpp
new file mode 100644 (file)
index 0000000..fe018fb
--- /dev/null
@@ -0,0 +1,880 @@
+/*
+  Copyright (C) 2006 Enrico Ros <enrico.ros@m31engineering.it>
+  Copyright (C) 2007 Trolltech ASA
+  
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+  
+  This library is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Library General Public License for more details.
+  
+  You should have received a copy of the GNU Library General Public License
+  along with this library; see the file COPYING.LIB.  If not, write to
+  the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+  Boston, MA 02111-1307, USA.
+  
+  This class provides all functionality needed for loading images, style sheets and html
+  pages from the web. It has a memory cache for these objects.
+*/
+#include <qglobal.h>
+namespace WebCore {
+    class HostInfo;
+}
+uint qHash(const WebCore::HostInfo &info);
+#include "qwebnetworkinterface.h"
+#include "qwebnetworkinterface_p.h"
+#include <qdebug.h>
+#include <qfile.h>
+
+#include "ResourceHandle.h"
+#include "ResourceHandleClient.h"
+#include "ResourceHandleInternal.h"
+#include "MimeTypeRegistry.h"
+#include "CookieJar.h"
+
+#define notImplemented() qDebug("FIXME: UNIMPLEMENTED: %s:%d (%s)", __FILE__, __LINE__, __FUNCTION__)
+
+#if 0
+#define DEBUG qDebug
+#else
+#define DEBUG if (1) {} else qDebug
+#endif
+
+static QWebNetworkInterface *default_interface = 0;
+static QWebNetworkManager *manager = 0;
+
+using namespace WebCore;
+
+void QWebNetworkJobPrivate::setURL(const QUrl &u)
+{
+    url = u;
+    int port = url.port();
+    if (port && port != 80)
+        request.setValue(QLatin1String("Host"), url.host() + QLatin1Char(':') + QString::number(port));
+    else
+        request.setValue(QLatin1String("Host"), url.host());
+}
+
+/*!
+  \class QWebNetworkJob
+
+  The QWebNetworkJob class represents a network job, that needs to be
+  processed by the QWebNetworkInterface.
+
+  This class is only required when implementing a new network layer (or
+  support for a special protocol) using QWebNetworkInterface.
+
+  QWebNetworkJob objects are created and owned by the QtWebKit library.
+  Most of it's properties are read-only.
+
+  The job is reference counted. This can be used to ensure that the job doesn't
+  get deleted while it's still stored in some data structure.
+*/
+
+/*!
+  \internal
+*/
+QWebNetworkJob::QWebNetworkJob()
+    : d(new QWebNetworkJobPrivate)
+{
+    d->ref = 1;
+    d->redirected = false;
+}
+
+/*!
+  \internal
+*/
+QWebNetworkJob::~QWebNetworkJob()
+{
+    delete d;
+}
+
+/*!
+  The requested URL
+*/
+QUrl QWebNetworkJob::url() const
+{
+    return d->url;
+}
+
+/*!
+  Post data associated with the job
+*/
+QByteArray QWebNetworkJob::postData() const
+{
+    return d->postData;
+}
+
+/*!
+  The HTTP request header that should be used to download the job.
+*/
+QHttpRequestHeader QWebNetworkJob::request() const
+{
+    return d->request;
+}
+
+/*!
+  The HTTP response header received from the network.
+*/
+QHttpResponseHeader QWebNetworkJob::response() const
+{
+    return d->response;
+}
+
+/*!
+  Sets the HTTP reponse header. The response header has to be called before
+  emitting QWebNetworkInterface::started.
+*/
+void QWebNetworkJob::setResponse(const QHttpResponseHeader &response)
+{
+    d->response = response;
+}
+
+/*!
+  returns true if the job has been cancelled by the WebKit framework
+*/
+bool QWebNetworkJob::cancelled() const
+{
+    return !d->resourceHandle;
+}
+
+/*!
+  reference the job.
+*/
+void QWebNetworkJob::ref()
+{
+    ++d->ref;
+}
+
+/*!
+  derefence the job.
+
+  If the reference count drops to 0 this method also deletes the job.
+
+  Returns false if the reference count has dropped to 0.
+*/
+bool QWebNetworkJob::deref()
+{
+    if (!--d->ref) {
+        delete this;
+        return false;
+    }
+    return true;
+}
+
+/*!
+  \internal
+*/
+void QWebNetworkJob::setUserHandle(void *handle)
+{
+    d->userHandle = handle;
+}
+
+/*!
+  \internal
+*/
+void *QWebNetworkJob::userHandle() const
+{
+    return d->userHandle;
+}
+
+
+/*!
+  \class QWebNetworkManager
+  \internal
+*/
+QWebNetworkManager::QWebNetworkManager()
+    : QObject(0)
+{
+}
+
+QWebNetworkManager *QWebNetworkManager::self()
+{
+    // ensure everything's constructed and connected
+    QWebNetworkInterface::defaultInterface();
+
+    return manager;
+}
+
+bool QWebNetworkManager::add(ResourceHandle *handle)
+{
+    ASSERT(resource);
+
+    QWebNetworkJob *job = new QWebNetworkJob();
+    handle->getInternal()->m_job = job;
+    job->d->resourceHandle = handle;
+
+    KURL url = handle->url();
+    QUrl qurl = QString(url.url());
+    qDebug() << QString(url.path() + url.query());
+    job->d->request = QHttpRequestHeader(handle->method(), url.path() + url.query());
+    job->d->request.setValue(QLatin1String("User-Agent"),
+                             QLatin1String("Mozilla/5.0 (PC; U; Intel; Linux; en) AppleWebKit/420+ (KHTML, like Gecko)"));
+    job->d->request.setValue(QLatin1String("Connection"), QLatin1String("Keep-Alive"));
+
+    job->d->setURL(qurl);
+
+    QString cookies = WebCore::cookies(handle->url());
+    if (!cookies.isEmpty())
+        job->d->request.setValue(QLatin1String("Cookie"), cookies);
+
+    const HTTPHeaderMap& loaderHeaders = handle->requestHeaders();
+    HTTPHeaderMap::const_iterator end = loaderHeaders.end();
+    for (HTTPHeaderMap::const_iterator it = loaderHeaders.begin(); it != end; ++it)
+        job->d->request.setValue(it->first, it->second);
+
+    int id;
+    // handle and perform a 'POST' request
+    if (handle->method() == "POST") {
+        job->d->request.setValue(QLatin1String("PropagateHttpHeader"), QLatin1String("true"));
+        job->d->request.setValue(QLatin1String("content-type"), QLatin1String("Content-Type: application/x-www-form-urlencoded"));
+
+        DeprecatedString pd = handle->postData()->flattenToString().deprecatedString();
+        job->d->postData = QByteArray(pd.ascii(), pd.length());
+        job->d->request.setValue(QLatin1String("content-length"), QString::number(job->d->postData.size()));
+    } else if (handle->method() != "GET") {
+        // or.. don't know what to do! (probably a request error!!)
+        // but treat it like a 'GET' request
+        qWarning("REQUEST: [%s]\n", qPrintable(job->d->request.toString()));
+    }
+
+    qDebug() << "QWebNetworkManager::add:" <<  job->d->request.toString();
+
+    default_interface->addJob(job);
+    
+    return true;
+}
+
+void QWebNetworkManager::cancel(ResourceHandle *handle)
+{
+    QWebNetworkJob *job = handle->getInternal()->m_job;
+    if (!job)
+        return;
+    job->d->resourceHandle = 0;
+    default_interface->cancelJob(job);
+    handle->getInternal()->m_job = 0;
+}
+
+void QWebNetworkManager::started(QWebNetworkJob *job)
+{
+    if (!job->d->resourceHandle)
+        return;
+
+    DEBUG() << "ResourceHandleManager::receivedResponse:";
+    DEBUG() << job->d->response.toString();
+
+    ResourceHandleClient* client = job->d->resourceHandle->client();
+    if (!client)
+        return;
+
+    QStringList cookies = job->d->response.allValues("Set-Cookie");
+    KURL url = job->d->resourceHandle->url();
+    foreach (QString c, cookies) {
+        setCookies(url, url, c);
+    }
+    QString contentType = job->d->response.value("Content-Type");
+    QString encoding;
+    int idx = contentType.indexOf(QLatin1Char(';'));
+    if (idx > 0) {
+        QString remainder = contentType.mid(idx + 1).toLower();
+        contentType = contentType.left(idx).trimmed();
+
+        idx = remainder.indexOf("charset");
+        if (idx >= 0) {
+            idx = remainder.indexOf(QLatin1Char('='), idx);
+            if (idx >= 0)
+                encoding = remainder.mid(idx + 1).trimmed();
+        }
+    }
+    if (contentType.isEmpty()) {
+        // let's try to guess from the extension
+        QString extension = job->d->url.path();
+        int index = extension.lastIndexOf(QLatin1Char('.'));
+        if (index > 0) {
+            extension = extension.mid(index + 1);
+            contentType = MimeTypeRegistry::getMIMETypeForExtension(extension);
+        }
+    }
+//     qDebug() << "Content-Type=" << contentType;
+//     qDebug() << "Encoding=" << encoding;
+
+
+    ResourceResponse response(url, contentType,
+                              0 /* FIXME */,
+                              encoding,
+                              String() /* FIXME */);
+
+    int statusCode = job->d->response.statusCode();
+    response.setHTTPStatusCode(statusCode);
+    /* Fill in the other fields */
+
+    if (statusCode >= 300 && statusCode < 400) {
+        // we're on a redirect page! if the 'Location:' field is valid, we redirect
+        QString location = job->d->response.value("location");
+        DEBUG() << "Redirection";
+        if (!location.isEmpty()) {
+            ResourceRequest newRequest = job->d->resourceHandle->request();
+            newRequest.setURL(DeprecatedString(location));
+            client->willSendRequest(job->d->resourceHandle, newRequest, response);
+            job->d->request.setRequest(job->d->request.method(), newRequest.url().path() + newRequest.url().query());
+            job->d->setURL(QString(newRequest.url().url()));
+            job->d->redirected = true;
+            return;
+        }
+    }
+
+    client->didReceiveResponse(job->d->resourceHandle, response);
+    
+}
+
+void QWebNetworkManager::data(QWebNetworkJob *job, const QByteArray &data)
+{
+    if (!job->d->resourceHandle)
+        return;
+
+    ResourceHandleClient* client = job->d->resourceHandle->client();
+    if (!client)
+        return;
+
+    DEBUG() << "receivedData" << job->d->url.path();
+    client->didReceiveData(job->d->resourceHandle, data.constData(), data.length(), data.length() /*FixMe*/);
+    
+}
+
+void QWebNetworkManager::finished(QWebNetworkJob *job, int errorCode)
+{
+    if (!job->d->resourceHandle) {
+        job->deref();
+        return;
+    }
+
+    DEBUG() << "receivedFinished" << errorCode << job->url();
+
+    if (job->d->redirected) {
+        job->d->redirected = false;
+        default_interface->addJob(job);
+        return;
+    }
+    job->d->resourceHandle->getInternal()->m_job = 0;
+
+    ResourceHandleClient* client = job->d->resourceHandle->client();
+    if (!client)
+        return;
+
+    if (errorCode) {
+        //FIXME: error setting error was removed from ResourceHandle
+        client->didFail(job->d->resourceHandle,
+                        ResourceError(job->d->url.host(), job->d->response.statusCode(),
+                                      job->d->url.toString(), String()));
+    } else {
+        client->didFinishLoading(job->d->resourceHandle);
+    }
+    DEBUG() << "receivedFinished done" << job->d->url;
+
+    job->deref();
+}
+
+
+/*!
+  \class QWebNetworkInterface
+
+  The QWebNetworkInterface class provides an abstraction layer for
+  WebKit's network interface.  It allows to completely replace or
+  extend the builtin network layer.
+
+  QWebNetworkInterface contains two virtual methods, addJob and
+  cancelJob that have to be reimplemented when implementing your own
+  networking layer.
+
+  QWebNetworkInterface can by default handle the http, https, file and
+  data URI protocols.
+  
+*/
+
+/*!
+  Sets a new default interface that will be used by all of WebKit
+  for downloading data from the internet.
+*/
+void QWebNetworkInterface::setDefaultInterface(QWebNetworkInterface *defaultInterface)
+{
+    if (default_interface == defaultInterface)
+        return;
+    if (default_interface)
+        delete default_interface;
+    default_interface = defaultInterface;
+    QObject::connect(default_interface, SIGNAL(started(QWebNetworkJob*)),
+                     manager, SLOT(started(QWebNetworkJob*)), Qt::QueuedConnection);
+    QObject::connect(default_interface, SIGNAL(data(QWebNetworkJob*, const QByteArray &)),
+                     manager, SLOT(data(QWebNetworkJob*, const QByteArray &)), Qt::QueuedConnection);
+    QObject::connect(default_interface, SIGNAL(finished(QWebNetworkJob*, int)),
+                     manager, SLOT(finished(QWebNetworkJob*, int)), Qt::QueuedConnection);
+}
+
+/*!
+  Returns the default interface that will be used by WebKit. If no
+  default interface has been set, QtWebkit will create an instance of
+  QWebNetworkInterface to do the work.
+*/
+QWebNetworkInterface *QWebNetworkInterface::defaultInterface()
+{
+    if (!default_interface)
+        setDefaultInterface(new QWebNetworkInterface);
+    return default_interface;
+}
+
+
+/*!
+  Constructs a QWebNetworkInterface object.
+*/
+QWebNetworkInterface::QWebNetworkInterface()
+    : QObject(0)
+{
+    d = new QWebNetworkInterfacePrivate;
+    if (!manager)
+        manager = new QWebNetworkManager;
+    d->fileLoader = new LoaderThread(this, LoaderThread::File);
+    d->fileLoader->start();
+    d->networkLoader = new LoaderThread(this, LoaderThread::Network);
+    d->networkLoader->start();
+
+    d->fileLoader->waitForSetup();
+    d->networkLoader->waitForSetup();
+}
+
+/*!
+  Destructs the QWebNetworkInterface object.
+*/
+QWebNetworkInterface::~QWebNetworkInterface()
+{
+    delete d;
+}
+
+/*!
+  This virtual method gets called whenever QtWebkit needs to add a
+  new job to download.
+
+  The QWebNetworkInterface should process this job, by first emitting
+  the started signal, then emitting data repeatedly as new data for
+  the Job is available, and finally ending the job with emitting a
+  finished signal.
+
+  After the finished signal has been emitted, the QWebNetworkInterface
+  is not allowed to access the job anymore.
+*/
+void QWebNetworkInterface::addJob(QWebNetworkJob *job)
+{
+    job->ref();
+    QString protocol = job->url().scheme();
+    if (protocol == QLatin1String("http")) {
+        //DEBUG() << "networkRequest";
+        emit manager->networkRequest(job);
+        return;
+    }
+
+    // "file", "data" and all unhandled stuff go through here
+    //DEBUG() << "fileRequest";
+    emit manager->fileRequest(job);
+}
+
+/*!
+  This virtual method gets called whenever QtWebkit needs to cancel a
+  new job.
+
+  The QWebNetworkInterface acknowledge the canceling of the job, by
+  emitting the finished signal with an error code of 1. After emitting
+  the finished signal, the interface should not access the job
+  anymore.
+*/
+void QWebNetworkInterface::cancelJob(QWebNetworkJob *job)
+{
+    QString protocol = job->url().scheme();
+    if (protocol == QLatin1String("http")) {
+        job->ref();
+        emit manager->networkCancel(job);
+    }
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+LoaderThread::LoaderThread(QWebNetworkInterface *manager, Type type)
+    : QThread(manager), m_type(type), m_loader(0), m_manager(manager), m_setup(false)
+{
+}
+
+void LoaderThread::run()
+{
+    switch (m_type) {
+    case Network:
+        m_loader = new NetworkLoader;
+        connect(manager, SIGNAL(networkRequest(QWebNetworkJob*)),
+                m_loader, SLOT(request(QWebNetworkJob*)));
+        connect(manager, SIGNAL(networkCancel(QWebNetworkJob*)),
+                m_loader, SLOT(cancel(QWebNetworkJob*)));
+        break;
+    case File:
+        m_loader = new FileLoader;
+        connect(manager, SIGNAL(fileRequest(QWebNetworkJob*)),
+                m_loader, SLOT(request(QWebNetworkJob*)));
+        break;
+    }
+    connect(m_loader, SIGNAL(receivedResponse(QWebNetworkJob*)),
+            m_manager, SIGNAL(started(QWebNetworkJob*)));
+    connect(m_loader, SIGNAL(receivedData(QWebNetworkJob*, QByteArray)),
+            m_manager, SIGNAL(data(QWebNetworkJob*, QByteArray)));
+    connect(m_loader, SIGNAL(receivedFinished(QWebNetworkJob*, int)),
+            m_manager, SIGNAL(finished(QWebNetworkJob*, int)));
+    DEBUG() << "calling exec";
+    m_setup = true;
+    exec();
+    DEBUG() << "done exec";
+    delete m_loader;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+FileLoader::FileLoader()
+    : QObject(0)
+{
+    DEBUG() << "FileLoader::FileLoader";
+}
+
+
+void FileLoader::request(QWebNetworkJob* job)
+{
+    if (!job->deref())
+        return;
+    
+    DEBUG() << "FileLoader::request" << job->url();
+
+    if (job->cancelled()) {
+        sendData(job, 400, QByteArray());
+        return;
+    }
+
+    QUrl url = job->url();
+    QString protocol = url.scheme();
+    if (protocol == QLatin1String("data")) {
+        parseDataUrl(job);
+        return;
+    }
+
+    int statusCode = 200;
+    QByteArray data;
+    if (!(protocol.isEmpty() || protocol == QLatin1String("file"))) {
+        statusCode = 404;
+    } else if (job->postData().isEmpty()) {
+        QFile f(url.path());
+        DEBUG() << "opening" << QString(url.path());
+
+        if (f.open(QIODevice::ReadOnly)) {
+            QHttpResponseHeader response;
+            response.setStatusLine(200);
+            job->setResponse(response);
+            data = f.readAll();
+        } else {
+            statusCode = 404;
+        }
+    } else {
+        statusCode = 404;
+    }
+    sendData(job, statusCode, data);
+}
+
+void FileLoader::sendData(QWebNetworkJob* job, int statusCode, const QByteArray &data)
+{
+    int error = statusCode >= 400 ? 1 : 0;
+    if (!job->cancelled()) {
+        QHttpResponseHeader response;
+        response.setStatusLine(statusCode);
+        emit receivedResponse(job);
+        if (!data.isEmpty())
+            emit receivedData(job, data);
+    }
+    emit receivedFinished(job, error);
+}
+
+void FileLoader::parseDataUrl(QWebNetworkJob* job)
+{
+    QByteArray data = job->url().toString().toLatin1();
+    //qDebug() << "handling data url:" << data; 
+
+    ASSERT(data.startsWith("data:"));
+
+    // Here's the syntax of data URLs:
+    // dataurl    := "data:" [ mediatype ] [ ";base64" ] "," data
+    // mediatype  := [ type "/" subtype ] *( ";" parameter )
+    // data       := *urlchar
+    // parameter  := attribute "=" value
+    QByteArray header;
+    bool base64 = false;
+
+    int index = data.indexOf(',');
+    if (index != -1) {
+        header = data.mid(5, index - 5);
+        header = header.toLower();
+        //qDebug() << "header=" << header;
+        data = data.mid(index+1);
+        //qDebug() << "data=" << data;
+
+        if (header.endsWith(";base64")) {
+            //qDebug() << "base64";
+            base64 = true;
+            header = header.left(header.length() - 7);
+            //qDebug() << "mime=" << header;
+        }        
+    } else {
+        data = QByteArray();
+    }
+    if (base64) {
+        data = QByteArray::fromBase64(data);
+    } else {
+        data = QUrl::fromPercentEncoding(data).toLatin1();
+    }
+
+    if (header.isEmpty()) 
+        header = "text/plain;charset=US-ASCII";
+    int statusCode = data.isEmpty() ? 404 : 200;
+    QHttpResponseHeader response;
+    response.setContentType(header);
+    response.setContentLength(data.size());
+    job->setResponse(response);
+
+    sendData(job, statusCode, data);
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+WebCoreHttp::WebCoreHttp(NetworkLoader* parent, const HostInfo &hi)
+    : info(hi),
+      m_loader(parent),
+      m_inCancel(false)
+{
+    for (int i = 0; i < 2; ++i) {
+        connection[i].http = new QHttp(info.host, info.port);
+        connection[i].current = 0;
+        connect(connection[i].http, SIGNAL(responseHeaderReceived(const QHttpResponseHeader&)),
+                this, SLOT(onResponseHeaderReceived(const QHttpResponseHeader&)));
+        connect(connection[i].http, SIGNAL(readyRead(const QHttpResponseHeader&)),
+                this, SLOT(onReadyRead()));
+        connect(connection[i].http, SIGNAL(requestFinished(int, bool)),
+                this, SLOT(onRequestFinished(int, bool)));
+        connect(connection[i].http, SIGNAL(stateChanged(int)),
+                this, SLOT(onStateChanged(int)));
+    }
+}
+
+WebCoreHttp::~WebCoreHttp()
+{
+}
+
+void WebCoreHttp::request(QWebNetworkJob *job)
+{
+    DEBUG() << ">>>>>>>>>>>>>> WebCoreHttp::request";
+    DEBUG() << job->request().toString() << "\n";
+    m_pendingRequests.append(job);
+
+    scheduleNextRequest();
+}
+
+void WebCoreHttp::scheduleNextRequest()
+{
+    int c = 0;
+    for (; c < 2; ++c) {
+        if (!connection[c].current)
+            break;
+    }
+    if (c >= 2)
+        return;
+
+    QWebNetworkJob *job = 0;
+    while (!job && !m_pendingRequests.isEmpty()) {
+        job = m_pendingRequests.takeFirst();
+        if (job->cancelled()) {
+            emit m_loader->receivedFinished(job, 1);
+            job = 0;
+        }
+    }
+    if (!job)
+        return;
+    
+    QHttp *http = connection[c].http;
+    QByteArray postData = job->postData();
+    if (!postData.isEmpty())
+        http->request(job->request(), postData);
+    else
+        http->request(job->request());
+    connection[c].current = job;
+
+    DEBUG() << "WebCoreHttp::scheduleNextRequest: using connection" << c;
+//     DEBUG() << job->request.toString();
+}
+
+int WebCoreHttp::getConnection()
+{
+    QObject *o = sender();
+    int c;
+    if (o == connection[0].http) {
+        c = 0;
+    } else {
+        Q_ASSERT(o == connection[1].http);
+        c = 1;
+    }
+    //Q_ASSERT(connection[c].current);
+    return c;
+}
+
+void WebCoreHttp::onResponseHeaderReceived(const QHttpResponseHeader &resp)
+{
+    int c = getConnection();
+    QWebNetworkJob *job = connection[c].current;
+    DEBUG() << "WebCoreHttp::slotResponseHeaderReceived connection=" << c;
+
+    job->setResponse(resp);
+
+    emit m_loader->receivedResponse(job);
+}
+
+void WebCoreHttp::onReadyRead()
+{
+    int c = getConnection();
+    QWebNetworkJob *req = connection[c].current;
+    QHttp *http = connection[c].http;
+    DEBUG() << "WebCoreHttp::slotReadyRead connection=" << c;
+
+    QByteArray data;
+    data.resize(http->bytesAvailable());
+    http->read(data.data(), data.length());
+    emit m_loader->receivedData(req, data);
+}
+
+void WebCoreHttp::onRequestFinished(int, bool error)
+{
+    int c = getConnection();
+    QWebNetworkJob *req = connection[c].current;
+    if (!req) {
+        scheduleNextRequest();
+        return;
+    }
+    QHttp *http = connection[c].http;
+    DEBUG() << "WebCoreHttp::slotFinished connection=" << c << error << req;
+
+    if (error)
+        DEBUG() << "   error: " << http->errorString();
+
+    if (!error && http->bytesAvailable()) {
+        QByteArray data;
+        data.resize(http->bytesAvailable());
+        http->read(data.data(), data.length());
+        emit m_loader->receivedData(req, data);
+    }
+    emit m_loader->receivedFinished(req, error ? 1 : 0);
+
+    connection[c].current = 0;
+    scheduleNextRequest();
+}
+
+void WebCoreHttp::onStateChanged(int state)
+{
+    if (state == QHttp::Closing || state == QHttp::Unconnected) {
+        if (!m_inCancel && m_pendingRequests.isEmpty()
+            && !connection[0].current && !connection[1].current)
+            emit connectionClosed(info);
+    }
+}
+
+void WebCoreHttp::cancel(QWebNetworkJob* request)
+{
+    bool doEmit = true;
+    m_inCancel = true;
+    for (int i = 0; i < 2; ++i) {
+        if (request == connection[i].current) {
+            connection[i].http->abort();
+            doEmit = false;
+        }
+    }
+    m_pendingRequests.removeAll(request);
+    m_inCancel = false;
+
+    if (doEmit)
+        emit m_loader->receivedFinished(request, 1);
+
+    if (m_pendingRequests.isEmpty()
+        && !connection[0].current && !connection[1].current)
+        emit connectionClosed(info);
+}
+
+HostInfo::HostInfo(const QUrl& url)
+    : protocol(url.scheme())
+    , host(url.host())
+    , port(url.port())
+{
+    if (port < 0) {
+        if (protocol == QLatin1String("http"))
+            port = 80;
+        else if (protocol == QLatin1String("https"))
+            port = 443;
+    }
+}
+
+
+uint qHash(const HostInfo &info)
+{
+    return qHash(info.host) + info.port;
+}
+
+static bool operator==(const HostInfo &i1, const HostInfo &i2)
+{
+    return i1.port == i2.port && i1.host == i2.host;
+}
+
+
+NetworkLoader::NetworkLoader()
+    : QObject(0)
+{
+}
+
+NetworkLoader::~NetworkLoader()
+{
+}
+
+void NetworkLoader::request(QWebNetworkJob* job)
+{
+    if (!job->deref())
+        return;
+    DEBUG() << "NetworkLoader::request";
+    HostInfo hostInfo(job->url());
+    WebCoreHttp *httpConnection = m_hostMapping.value(hostInfo);
+    if (!httpConnection) {
+        // #### fix custom ports
+        DEBUG() << "   new connection to" << hostInfo.host << hostInfo.port;
+        httpConnection = new WebCoreHttp(this, hostInfo);
+        connect(httpConnection, SIGNAL(connectionClosed(const HostInfo&)),
+                this, SLOT(connectionClosed(const HostInfo&)));
+
+        m_hostMapping[hostInfo] = httpConnection;
+    }
+    httpConnection->request(job);
+}
+void NetworkLoader::connectionClosed(const HostInfo& info)
+{
+    DEBUG() << "Disconnected";
+    WebCoreHttp *connection = m_hostMapping.take(info);
+    delete connection;
+}
+
+void NetworkLoader::cancel(QWebNetworkJob* job)
+{
+    DEBUG() << "NetworkLoader::cancel";
+    WebCoreHttp *httpConnection = m_hostMapping.value(job->url());
+    if (httpConnection)
+        httpConnection->cancel(job);
+    job->deref();
+}
+
+#include "qwebnetworkinterface_p.moc"
+#include "qwebnetworkinterface.moc"
+
diff --git a/WebKitQt/Api/qwebnetworkinterface.h b/WebKitQt/Api/qwebnetworkinterface.h
new file mode 100644 (file)
index 0000000..4e89837
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+  Copyright (C) 2007 Trolltech ASA
+  
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+  
+  This library is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Library General Public License for more details.
+  
+  You should have received a copy of the GNU Library General Public License
+  along with this library; see the file COPYING.LIB.  If not, write to
+  the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+  Boston, MA 02111-1307, USA.
+  
+  This class provides all functionality needed for loading images, style sheets and html
+  pages from the web. It has a memory cache for these objects.
+*/
+#ifndef QWEBNETWORKINTERFACE_H
+#define QWEBNETWORKINTERFACE_H
+
+#include <qobject.h>
+#include <qurl.h>
+#include <qhttp.h>
+#include <qbytearray.h>
+
+class QWebNetworkJobPrivate;
+
+class QWebNetworkJob
+{
+public:
+    QUrl url() const;
+    QByteArray postData() const;
+    QHttpRequestHeader request() const;
+
+    QHttpResponseHeader response() const;
+    void setResponse(const QHttpResponseHeader &response);
+
+    bool cancelled() const;
+
+    void ref();
+    bool deref();
+    
+    template <typename T>
+    void setHandle(T *t);
+    template <typename T>
+    T *handle() const;
+
+private:
+    QWebNetworkJob();
+    ~QWebNetworkJob();
+
+    void setUserHandle(void *);
+    void *userHandle() const;
+
+    friend class QWebNetworkManager;
+    QWebNetworkJobPrivate *d;
+};
+
+template <typename T>
+void QWebNetworkJob::setHandle(T *t)
+{
+    setUserHandle(t);
+}
+
+template <typename T>
+T *QWebNetworkJob::handle() const
+{
+    return static_cast<T *>(userHandle());
+}
+
+class QWebNetworkInterfacePrivate;
+
+class QWebNetworkInterface : public QObject
+{
+    Q_OBJECT
+public:
+    QWebNetworkInterface();
+    ~QWebNetworkInterface();
+
+    static void setDefaultInterface(QWebNetworkInterface *defaultInterface);
+    static QWebNetworkInterface *defaultInterface();
+
+    virtual void addJob(QWebNetworkJob *job);
+    virtual void cancelJob(QWebNetworkJob *job);
+    
+signals:
+    void started(QWebNetworkJob*);
+    void data(QWebNetworkJob*, const QByteArray &data);
+    void finished(QWebNetworkJob*, int errorCode);
+
+private:
+    friend class QWebNetworkInterfacePrivate;
+    QWebNetworkInterfacePrivate *d;
+};
+
+#endif
diff --git a/WebKitQt/Api/qwebnetworkinterface_p.h b/WebKitQt/Api/qwebnetworkinterface_p.h
new file mode 100644 (file)
index 0000000..4249355
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+  Copyright (C) 2007 Trolltech ASA
+  
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+  
+  This library is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Library General Public License for more details.
+  
+  You should have received a copy of the GNU Library General Public License
+  along with this library; see the file COPYING.LIB.  If not, write to
+  the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+  Boston, MA 02111-1307, USA.
+  
+  This class provides all functionality needed for loading images, style sheets and html
+  pages from the web. It has a memory cache for these objects.
+*/
+#ifndef QWEBNETWORKINTERFACE_P_H
+#define QWEBNETWORKINTERFACE_P_H
+
+#include "qwebnetworkinterface.h"
+#include <qthread.h>
+#include <qhash.h>
+
+namespace WebCore {
+    class ResourceHandle;
+}
+
+class QWebNetworkJobPrivate
+{
+public:
+    int ref;
+    QUrl url;
+    QHttpRequestHeader request;
+    QByteArray postData;
+
+    QHttpResponseHeader response;
+
+    WebCore::ResourceHandle *resourceHandle;
+    void *userHandle;
+    bool redirected;
+
+    void setURL(const QUrl &u);
+};
+
+
+class QWebNetworkManager : public QObject
+{
+    Q_OBJECT
+public:
+    static QWebNetworkManager *self();
+
+    bool add(WebCore::ResourceHandle *resourceHandle);
+    void cancel(WebCore::ResourceHandle *resourceHandle);
+
+public slots:
+    void started(QWebNetworkJob *);
+    void data(QWebNetworkJob *, const QByteArray &data);
+    void finished(QWebNetworkJob *, int errorCode);
+
+signals:
+    void networkRequest(QWebNetworkJob*);
+    void networkCancel(QWebNetworkJob*);
+    void fileRequest(QWebNetworkJob*);
+
+private:
+    friend class QWebNetworkInterface;
+    QWebNetworkManager();
+};
+
+
+namespace WebCore {
+    
+    class LoaderThread : public QThread {
+        Q_OBJECT
+    public:
+        enum Type {
+            Network,
+            File
+        };
+        LoaderThread(QWebNetworkInterface *manager, Type type);
+
+        void waitForSetup() { while (!m_setup); }
+    protected:
+        void run();
+    private:
+        Type m_type;
+        QObject* m_loader;
+        QWebNetworkInterface* m_manager;
+        volatile bool m_setup;
+    };
+
+    class FileLoader : public QObject {
+        Q_OBJECT
+    public:
+        FileLoader();
+
+            public slots:
+            void request(QWebNetworkJob*);
+
+        signals:
+        void receivedResponse(QWebNetworkJob* resource);
+        void receivedData(QWebNetworkJob* resource, const QByteArray &data);
+        void receivedFinished(QWebNetworkJob* resource, int errorCode);
+
+    private:
+        void parseDataUrl(QWebNetworkJob* request);
+        void sendData(QWebNetworkJob* request, int statusCode, const QByteArray &data);
+    };
+
+    class NetworkLoader;
+
+    struct HostInfo {
+        HostInfo() {}
+        HostInfo(const QUrl& url);
+        QString protocol;
+        QString host;
+        int port;
+    };
+
+    
+    class WebCoreHttp : public QObject
+    {
+        Q_OBJECT
+    public:
+        WebCoreHttp(NetworkLoader* parent, const HostInfo&);
+        ~WebCoreHttp();
+
+        void request(QWebNetworkJob* resource);
+        void cancel(QWebNetworkJob*);
+
+        signals:
+        void connectionClosed(const HostInfo &);
+
+             private slots:
+             void onResponseHeaderReceived(const QHttpResponseHeader& resp);
+        void onReadyRead();
+        void onRequestFinished(int, bool);
+        void onStateChanged(int);
+
+        void scheduleNextRequest();
+
+        int getConnection();
+
+    public:
+        HostInfo info;
+    private:
+        NetworkLoader* m_loader;
+        QList<QWebNetworkJob*> m_pendingRequests;
+        struct HttpConnection {
+            QHttp *http;
+            QWebNetworkJob *current;
+        };
+        HttpConnection connection[2];
+        bool m_inCancel;
+    };
+
+    class NetworkLoader : public QObject {
+        Q_OBJECT
+    public:
+        NetworkLoader();
+        ~NetworkLoader();
+
+
+            public slots:
+            void request(QWebNetworkJob*);
+        void cancel(QWebNetworkJob*);
+        void connectionClosed(const HostInfo &);
+
+        signals:
+        void receivedResponse(QWebNetworkJob* resource);
+        void receivedData(QWebNetworkJob* resource, const QByteArray &data);
+        void receivedFinished(QWebNetworkJob* resource, int errorCode);
+    private:
+        friend class WebCoreHttp;
+        QHash<HostInfo, WebCoreHttp *> m_hostMapping;
+    };
+
+}
+
+class QWebNetworkInterfacePrivate
+{
+public:
+    WebCore::LoaderThread *networkLoader;
+    WebCore::LoaderThread *fileLoader;
+};
+
+#endif
index a069834766360dd1292a3505e69748dffc330628..0c6c52c9e1049a05689f01f4c4e74040ef5f702b 100644 (file)
@@ -1,3 +1,73 @@
+2007-05-21  Lars Knoll <lars@trolltech.com>
+
+        Reviewed by Zack.
+
+        Add an API layer for network downloads. Basically QWebnetworkInterface
+        is an interface class for downloading resources. QWebnetworkJob describes
+        the actual object to download.
+
+        QWebNetworkInterface has a default implementation that replaces the
+        old ResourceHandleManager class in the Qt port.
+
+        * Api/qwebnetworkinterface.cpp: Added.
+        (QWebNetworkJobPrivate::setURL):
+        (QWebNetworkJob::QWebNetworkJob):
+        (QWebNetworkJob::~QWebNetworkJob):
+        (QWebNetworkJob::url):
+        (QWebNetworkJob::postData):
+        (QWebNetworkJob::request):
+        (QWebNetworkJob::response):
+        (QWebNetworkJob::setResponse):
+        (QWebNetworkJob::cancelled):
+        (QWebNetworkJob::ref):
+        (QWebNetworkJob::deref):
+        (QWebNetworkJob::setUserHandle):
+        (QWebNetworkJob::userHandle):
+        (QWebNetworkManager::QWebNetworkManager):
+        (QWebNetworkManager::self):
+        (QWebNetworkManager::add):
+        (QWebNetworkManager::cancel):
+        (QWebNetworkManager::started):
+        (QWebNetworkManager::data):
+        (QWebNetworkManager::finished):
+        (QWebNetworkInterface::setDefaultInterface):
+        (QWebNetworkInterface::defaultInterface):
+        (QWebNetworkInterface::QWebNetworkInterface):
+        (QWebNetworkInterface::~QWebNetworkInterface):
+        (QWebNetworkInterface::addJob):
+        (QWebNetworkInterface::cancelJob):
+        (LoaderThread::LoaderThread):
+        (LoaderThread::run):
+        (FileLoader::FileLoader):
+        (FileLoader::request):
+        (FileLoader::sendData):
+        (FileLoader::parseDataUrl):
+        (WebCoreHttp::WebCoreHttp):
+        (WebCoreHttp::~WebCoreHttp):
+        (WebCoreHttp::request):
+        (WebCoreHttp::scheduleNextRequest):
+        (WebCoreHttp::getConnection):
+        (WebCoreHttp::onResponseHeaderReceived):
+        (WebCoreHttp::onReadyRead):
+        (WebCoreHttp::onRequestFinished):
+        (WebCoreHttp::onStateChanged):
+        (WebCoreHttp::cancel):
+        (HostInfo::HostInfo):
+        (qHash):
+        (operator==):
+        (NetworkLoader::NetworkLoader):
+        (NetworkLoader::~NetworkLoader):
+        (NetworkLoader::request):
+        (NetworkLoader::connectionClosed):
+        (NetworkLoader::cancel):
+        * Api/qwebnetworkinterface.h: Added.
+        (QWebNetworkJob::setHandle):
+        (QWebNetworkJob::handle):
+        * Api/qwebnetworkinterface_p.h: Added.
+        (WebCore::LoaderThread::):
+        (WebCore::LoaderThread::waitForSetup):
+        (WebCore::HostInfo::HostInfo):
+
 2007-05-18  Simon Hausmann  <hausmann@kde.org>
 
         Reviewed by Nikolas.