+2006-08-23 Nikolas Zimmermann <zimmermann@kde.org>
+
+ Reviewed by Anders. Landed by rwlbuis.
+
+ Fixes parts of: http://bugzilla.opendarwin.org/show_bug.cgi?id=10467
+ WebKit should have Qt platform support
+
+ * platform/qt/ResourceLoaderCurl.cpp: Added.
+ (WebCore::ResourceLoaderInternal::~ResourceLoaderInternal):
+ (WebCore::ResourceLoader::~ResourceLoader):
+ (WebCore::ResourceLoader::start):
+ (WebCore::ResourceLoader::cancel):
+ (WebCore::ResourceLoader::assembleResponseHeaders):
+ (WebCore::ResourceLoader::retrieveCharset):
+ (WebCore::ResourceLoader::receivedResponse):
+ * platform/qt/ResourceLoaderManager.cpp: Added.
+ (WebCore::ResourceLoaderManager::ResourceLoaderManager):
+ (WebCore::ResourceLoaderManager::get):
+ (WebCore::ResourceLoaderManager::useSimpleTransfer):
+ (WebCore::writeCallback):
+ (WebCore::headerCallback):
+ (WebCore::ResourceLoaderManager::downloadTimerCallback):
+ (WebCore::ResourceLoaderManager::remove):
+ (WebCore::ResourceLoaderManager::add):
+ (WebCore::ResourceLoaderManager::cancel):
+ * platform/qt/ResourceLoaderManager.h: Added.
+ * platform/qt/StringQt.cpp: Added.
+ (WebCore::String::String):
+ (WebCore::String::operator QString):
+ (WebCore::DeprecatedString::operator QString):
+
2006-08-23 Brady Eidson <beidson@apple.com>
Reviewed by Maciej
--- /dev/null
+/*
+ * Copyright (C) 2004, 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2005, 2006 Michael Emmel mike.emmel@gmail.com
+ * 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 <QDebug>
+#include "config.h"
+#include "ResourceLoader.h"
+
+#include "DocLoader.h"
+#include "ResourceLoaderInternal.h"
+#include "ResourceLoaderManager.h"
+
+#define notImplemented() do { fprintf(stderr, "FIXME: UNIMPLEMENTED: %s:%d\n", __FILE__, __LINE__); } while(0)
+
+namespace WebCore {
+
+ResourceLoaderInternal::~ResourceLoaderInternal()
+{
+}
+
+ResourceLoader::~ResourceLoader()
+{
+ cancel();
+}
+
+bool ResourceLoader::start(DocLoader* docLoader)
+{
+ ResourceLoaderManager::get()->add(this);
+ return true;
+}
+
+void ResourceLoader::cancel()
+{
+ ResourceLoaderManager::get()->cancel(this);
+}
+
+void ResourceLoader::assembleResponseHeaders() const
+{
+ if (!d->assembledResponseHeaders) {
+ d->responseHeaders = DeprecatedString::fromUtf8(d->response.toUtf8(), d->response.length());
+ d->assembledResponseHeaders = true;
+
+ // TODO: Move the client activation to receivedResponse(), once
+ // we use KIO, and receivedResponse() is called only once.
+ if (d->client) {
+ d->client->receivedResponse(const_cast<ResourceLoader *>(this), (char *) d->response.data());
+ }
+
+ d->response = QString(); // Reset
+ }
+}
+
+void ResourceLoader::retrieveCharset() const
+{
+ if (!d->retrievedCharset) {
+ d->retrievedCharset = true;
+ }
+
+ // TODO: We can just parse the headers here, but once we use KIO
+ // we can set the response parameter to sth. else than a "char*".
+ // I save my time but not implementing it for now :-)
+ notImplemented();
+}
+
+void ResourceLoader::receivedResponse(char* response)
+{
+ Q_ASSERT(method() == "POST");
+
+ d->assembledResponseHeaders = false;
+ d->retrievedCharset = false;
+
+ // TODO: This is flawed:
+ // - usually receivedResponse() should be called _once_, when the
+ // response is available - seems very unflexible to do that with libcurl
+ // (so let's wait until it dies and do it properly with KIO then.)
+ // - QString::fromLatin1() is also wrong, of course.
+ //
+ // Anyway, let's collect the response data here, as the ResourceLoaderManager
+ // calls us for every line of the header it receives.
+ d->response += QString::fromLatin1(response);
+}
+
+} // namespace WebCore
+
+// vim: ts=4 sw=4 et
--- /dev/null
+/*
+ * Copyright (C) 2004, 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com
+ * 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 "ResourceLoaderManager.h"
+
+#include "ResourceLoader.h"
+#include "ResourceLoaderInternal.h"
+
+namespace WebCore {
+
+const int selectTimeoutMS = 5;
+const double pollTimeSeconds = 0.05;
+
+ResourceLoaderManager::ResourceLoaderManager()
+ : m_useSimple(false)
+ , jobs(new HashSet<ResourceLoader*>)
+ , m_downloadTimer(this, &ResourceLoaderManager::downloadTimerCallback)
+{
+ curl_global_init(CURL_GLOBAL_ALL);
+ curlMultiHandle = curl_multi_init();
+}
+
+ResourceLoaderManager* ResourceLoaderManager::get()
+{
+ static ResourceLoaderManager* s_singleton;
+
+ if (!s_singleton)
+ s_singleton = new ResourceLoaderManager;
+
+ return s_singleton;
+}
+
+void ResourceLoaderManager::useSimpleTransfer(bool useSimple)
+{
+ m_useSimple = useSimple;
+}
+
+static size_t writeCallback(void* ptr, size_t size, size_t nmemb, void* obj)
+{
+ ResourceLoader* job = static_cast<ResourceLoader*>(obj);
+ ResourceLoaderInternal* d = job->getInternal();
+ int totalSize = size * nmemb;
+ d->client->receivedData(job, static_cast<char*>(ptr), totalSize);
+ return totalSize;
+}
+
+static size_t headerCallback(char* ptr, size_t size, size_t nmemb, void* obj)
+{
+ ResourceLoader* job = static_cast<ResourceLoader*>(obj);
+ ResourceLoaderInternal* d = job->getInternal();
+
+ if (job->method() == "POST") {
+ job->receivedResponse(ptr);
+ }
+
+ int totalSize = size * nmemb;
+ return totalSize;
+}
+
+void ResourceLoaderManager::downloadTimerCallback(Timer<ResourceLoaderManager>* timer)
+{
+ if (jobs->isEmpty()) {
+ m_downloadTimer.stop();
+ return;
+ }
+
+ if (m_useSimple) {
+ for (HashSet<ResourceLoader*>::iterator it = jobs->begin(); it != jobs->end(); ++it) {
+ ResourceLoader* job = *it;
+ ResourceLoaderInternal* d = job->getInternal();
+ CURLcode res = curl_easy_perform(d->m_handle);
+ if (res != CURLE_OK)
+ printf("Error WITH JOB %d\n", res);
+ d->client->receivedAllData(job, 0);
+ d->client->receivedAllData(job);
+ curl_easy_cleanup(d->m_handle);
+ d->m_handle = 0;
+ }
+
+ jobs->clear();
+ m_downloadTimer.stop();
+ } else {
+ FD_ZERO(&fdread);
+ FD_ZERO(&fdwrite);
+ FD_ZERO(&fdexcep);
+ curl_multi_fdset(curlMultiHandle, &fdread, &fdwrite, &fdexcep, &maxfd);
+ int nrunning;
+ struct timeval timeout;
+ int retval;
+ timeout.tv_sec = 0;
+ timeout.tv_usec = selectTimeoutMS * 1000; // select waits microseconds
+ retval = ::select(maxfd + 1, &fdread, &fdwrite, &fdexcep, &timeout);
+ switch (retval) {
+ case -1: // select error
+#ifndef NDEBUG
+ printf("%s, select error(%d)\n", __PRETTY_FUNCTION__,retval);
+#endif
+ /* fallthrough*/
+ case 0: // select timeout
+#ifndef NDEBUG
+ printf("%s, select timeout %d\n", __PRETTY_FUNCTION__,retval);
+#endif
+ /* fallthrough. this can be the first perform to be made */
+ default: // 1+ descriptors have data
+ while (CURLM_CALL_MULTI_PERFORM == curl_multi_perform(curlMultiHandle, &nrunning))
+ { }
+ }
+
+ // check the curl messages indicating completed transfers
+ // and free their resources
+ ResourceLoader* job;
+ int nmsgs;
+ while (CURLMsg* msg = curl_multi_info_read(curlMultiHandle, &nmsgs)) {
+ if (msg->msg == CURLMSG_DONE) {
+ // find the node which has same d->m_handle as completed transfer
+ CURL* chandle = msg->easy_handle;
+ assert(chandle);
+ ResourceLoader *job;
+ curl_easy_getinfo(chandle, CURLINFO_PRIVATE, &job);
+ assert(job); //fixme: assert->if ?
+ // if found, delete it
+ if (job) {
+ ResourceLoaderInternal *d = job->getInternal();
+ switch (msg->data.result) {
+ case CURLE_OK: {
+ // use this to authenticate
+ long respCode = -1;
+ curl_easy_getinfo(d->m_handle, CURLINFO_RESPONSE_CODE, &respCode);
+ remove(job);
+ break;
+ }
+ default:
+ printf("Curl ERROR %s\n", curl_easy_strerror(msg->data.result));
+ job->setError(msg->data.result);
+ remove(job);
+ break;
+ }
+ } else {
+ printf("CurlRequest not found, eventhough curl d->m_handle finished\n");
+ assert(0);
+ }
+ }
+
+ }
+ }
+ if (!jobs->isEmpty())
+ m_downloadTimer.startOneShot(pollTimeSeconds);
+}
+
+void ResourceLoaderManager::remove(ResourceLoader* job)
+{
+ ResourceLoaderInternal* d = job->getInternal();
+ if (!d->m_handle)
+ return;
+ if (jobs->contains(job))
+ jobs->remove(job);
+ if (jobs->isEmpty())
+ m_downloadTimer.stop();
+ d->client->receivedAllData(job, 0);
+ d->client->receivedAllData(job);
+ if (d->m_handle) {
+ curl_multi_remove_handle(curlMultiHandle, d->m_handle);
+ curl_easy_cleanup(d->m_handle);
+ d->m_handle = NULL;
+ }
+}
+
+void ResourceLoaderManager::add(ResourceLoader* job)
+{
+ bool startTimer = jobs->isEmpty();
+ ResourceLoaderInternal* d = job->getInternal();
+ DeprecatedString url = d->URL.url();
+ d->m_handle = curl_easy_init();
+ curl_easy_setopt(d->m_handle, CURLOPT_PRIVATE, job);
+ curl_easy_setopt(d->m_handle, CURLOPT_ERRORBUFFER, error_buffer);
+ curl_easy_setopt(d->m_handle, CURLOPT_WRITEFUNCTION, writeCallback);
+ curl_easy_setopt(d->m_handle, CURLOPT_WRITEDATA, job);
+ curl_easy_setopt(d->m_handle, CURLOPT_HEADERFUNCTION, headerCallback);
+ curl_easy_setopt(d->m_handle, CURLOPT_WRITEHEADER, job);
+ curl_easy_setopt(d->m_handle, CURLOPT_FOLLOWLOCATION, 1);
+ curl_easy_setopt(d->m_handle, CURLOPT_MAXREDIRS, 10);
+ curl_easy_setopt(d->m_handle, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
+ // url ptr must remain valid through the request
+ curl_easy_setopt(d->m_handle, CURLOPT_URL, url.ascii());
+
+ if (job->method() == "POST") {
+ DeprecatedString postData = job->postData().flattenToString();
+
+ char *postDataString = (char *) malloc(postData.length() + 1);
+ strncpy(postDataString, postData.ascii(), postData.length());
+ postDataString[postData.length()] = '\0';
+
+ // TODO: Do it properly after we got rid of libcurl! (also leaks the headerlist. hmpf.)
+ curl_easy_setopt(d->m_handle, CURLOPT_POSTFIELDS, postDataString);
+ }
+
+ if (m_useSimple)
+ jobs->add(job);
+ else {
+ CURLMcode ret = curl_multi_add_handle(curlMultiHandle, d->m_handle);
+ // don't call perform, because events must be async
+ // timeout will occur and do curl_multi_perform
+ if (ret && ret != CURLM_CALL_MULTI_PERFORM) {
+ printf("Error %d starting job %s\n", ret, d->URL.url().ascii());
+ job->setError(1);
+ startTimer =false;
+ } else
+ jobs->add(job);
+ }
+ if (startTimer)
+ m_downloadTimer.startOneShot(pollTimeSeconds);
+}
+
+void ResourceLoaderManager::cancel(ResourceLoader* job)
+{
+ remove(job);
+ job->setError(1);
+}
+
+} // namespace WebCore
+
+// vim: ts=4 sw=4 et
--- /dev/null
+/*
+ * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com
+ * 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 ResourceLoaderManager_H_
+#define ResourceLoaderManager_H_
+
+#include "Frame.h"
+#include "Timer.h"
+#include "ResourceLoaderClient.h"
+#include <curl/curl.h>
+
+namespace WebCore {
+
+class ResourceLoaderManager {
+public:
+ static ResourceLoaderManager* get();
+ void add(ResourceLoader*);
+ void cancel(ResourceLoader*);
+
+ // If true, don't multiplex downloads: download completely one at a time.
+ void useSimpleTransfer(bool useSimple);
+
+private:
+ ResourceLoaderManager();
+ void downloadTimerCallback(Timer<ResourceLoaderManager>*);
+ void remove(ResourceLoader*);
+
+ bool m_useSimple;
+ HashSet<ResourceLoader*>* jobs;
+ Timer<ResourceLoaderManager> m_downloadTimer;
+ CURLM* curlMultiHandle; // not freed
+
+ // curl filehandles to poll with select
+ fd_set fdread;
+ fd_set fdwrite;
+ fd_set fdexcep;
+
+ int maxfd;
+ char error_buffer[CURL_ERROR_SIZE];
+
+ // NULL-terminated list of supported protocols
+ const char* const* curl_protocols; // not freed
+};
+
+}
+
+#endif
+
+// vim: ts=4 sw=4 et
--- /dev/null
+/*
+ * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org>
+ *
+ * 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 "PlatformString.h"
+#include "DeprecatedString.h"
+
+#include <QString>
+
+namespace WebCore {
+
+String::String(const QString& qstr)
+{
+ unsigned int len = qstr.length();
+ const UChar* str = reinterpret_cast<const UChar*>(qstr.constData());
+
+ if (!str)
+ return;
+
+ if (len == 0)
+ m_impl = StringImpl::empty();
+ else
+ m_impl = new StringImpl(str, len);
+}
+
+String::operator QString() const
+{
+ return QString(reinterpret_cast<const QChar*>(characters()), length());
+}
+
+DeprecatedString::operator QString() const
+{
+ return QString(reinterpret_cast<const QChar*>(unicode()), length());
+}
+
+}
+
+// vim: ts=4 sw=4 et