summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrea Diamantini <adjam7@gmail.com>2011-01-07 18:53:20 +0100
committerAndrea Diamantini <adjam7@gmail.com>2011-01-07 18:53:20 +0100
commit39413862a2d2355d3765d986073b29c1c2a1b7d7 (patch)
tree5be5777239fc6031b0fbc4f92ff668c31ca68f08
parentThis GCI task adds a combobox with different settings to choice when hovering... (diff)
downloadrekonq-39413862a2d2355d3765d986073b29c1c2a1b7d7.tar.xz
Put ioslaves on hold.
This patch couples those merged in KIO & KDEWebKit in SC 4.6. I have to say it is probably NOT perfect and ready to merge, but I'd like to because it is anyway a nice step over actual behavior. It basically holds and (re)publish slave for apps needing it, letting us fixing a long standing bug against the infamous TWO connections to do ONE thing (download, move, etc...) It also gave me the possibility to and/or improve these things: - better handling filenames, studying content disposition header for "attachment" and "inline" values - better history handling, when working with kparts (also if this part needs a proper fix, IMHO reimplementing QWebHistory class...) - a (proper?) fix for POST operations returning content. I admit I am dubious with this part and I need more testing. The nice thing is that this patch "circumscribes" this problem, letting it easy eventually fix it again I also copied from kdewebkit a check for exec text files mimetypes (converted to text/plain) and cleaned-up some kDebugs (and as usual, added a lot..) Last, sorry for the big commit message and the big/not so big patch here. It is a special case. commit 29f3021d94e26b39f3e8172a980a6cafcebe5095 Author: Andrea Diamantini <adjam7@gmail.com> Date: Wed Jan 5 12:17:45 2011 +0100 cleanup comments commit fc88a37322810fd25c5bfcd16880fc617e7de9f5 Author: Andrea Diamantini <adjam7@gmail.com> Date: Wed Jan 5 12:06:55 2011 +0100 content-disposition: inline commit 7c2789a1733e1089b9c66cd6c553185792ec3a72 Author: Andrea Diamantini <adjam7@gmail.com> Date: Tue Jan 4 12:04:03 2011 +0100 Fix history handling. For a proper fix here, I think we need to reimplement the tab history, otherwise we cannot manage tab history browsing on the so called "rekonq" pages... commit 892c4d8dc78fda43f67566a3e359bd9805ee3282 Author: Andrea Diamantini <adjam7@gmail.com> Date: Tue Jan 4 11:57:29 2011 +0100 Two cases here: 1) POST operations returning content 2) right file names commit 3b1d5873b7eb743406f3b8c5abb79ce6728d0103 Author: Andrea Diamantini <adjam7@gmail.com> Date: Tue Jan 4 03:24:21 2011 +0100 Stupid kDebugs... commit 73d038a757185816f40795d4dd4a68e11659c971 Author: Andrea Diamantini <adjam7@gmail.com> Date: Tue Jan 4 02:32:45 2011 +0100 It needs testing from people (just) having last KDE SC 4.6 code on...
-rw-r--r--src/mainwindow.cpp30
-rw-r--r--src/webpage.cpp244
-rw-r--r--src/webpage.h9
3 files changed, 175 insertions, 108 deletions
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp
index 11c00c28..599295f7 100644
--- a/src/mainwindow.cpp
+++ b/src/mainwindow.cpp
@@ -619,26 +619,28 @@ void MainWindow::openLocation()
void MainWindow::fileSaveAs()
{
- KUrl srcUrl;
WebTab *w = currentTab();
- if (w->page()->isOnRekonqPage())
- {
- QWebElement el = w->page()->mainFrame()->documentElement();
- srcUrl = KUrl( el.findFirst("object").attribute("data") );
- }
- else
+ KUrl srcUrl = w->url();
+
+ // First, try with suggested file name...
+ QString name = w->page()->suggestedFileName();
+
+ // Second, with KUrl fileName...
+ if (name.isEmpty())
{
- srcUrl = w->url();
+ name = srcUrl.fileName();
}
- kDebug() << "URL to save: " << srcUrl;
-
- QString name = srcUrl.fileName();
- if (name.isNull())
+
+ // Last chance...
+ if(name.isEmpty())
{
name = srcUrl.host() + QString(".html");
}
+
const QString destUrl = KFileDialog::getSaveFileName(name, QString(), this);
- if (destUrl.isEmpty()) return;
+ if (destUrl.isEmpty())
+ return;
+
KIO::Job *job = KIO::file_copy(srcUrl, KUrl(destUrl), -1, KIO::Overwrite);
job->addMetaData("MaxCacheSize", "0"); // Don't store in http cache.
job->addMetaData("cache", "cache"); // Use entry from cache if available.
@@ -984,7 +986,6 @@ void MainWindow::openPrevious(Qt::MouseButtons mouseButtons, Qt::KeyboardModifie
if (currentTab()->page()->isOnRekonqPage())
{
item = new QWebHistoryItem(history->currentItem());
- currentTab()->view()->page()->setIsOnRekonqPage(false);
}
else
{
@@ -1018,7 +1019,6 @@ void MainWindow::openNext(Qt::MouseButtons mouseButtons, Qt::KeyboardModifiers k
if (currentTab()->view()->page()->isOnRekonqPage())
{
item = new QWebHistoryItem(history->currentItem());
- currentTab()->view()->page()->setIsOnRekonqPage(false);
}
else
{
diff --git a/src/webpage.cpp b/src/webpage.cpp
index b04c5e89..c7ddfd5b 100644
--- a/src/webpage.cpp
+++ b/src/webpage.cpp
@@ -54,6 +54,9 @@
// KDE Includes
#include <KIO/Job>
#include <KIO/RenameDialog>
+#include <KIO/JobUiDelegate>
+
+#include <KTemporaryFile>
#include <KStandardDirs>
#include <KFileDialog>
#include <KJobUiDelegate>
@@ -66,6 +69,8 @@
#include <kparts/browseropenorsavequestion.h>
+#include <kio/scheduler.h>
+
// Qt Includes
#include <QtCore/QFileInfo>
@@ -99,10 +104,67 @@ static bool domainSchemeMatch(const QUrl& u1, const QUrl& u2)
// NOTE
-// This is heavily based on the one from KdeWebKit and
-// extended to provide the extra functionality we need:
+// These 2 functions have been copied from the KWebPage class to implement a local version of the downloadResponse method.
+// In this way, we can easily provide the extra functionality we need:
// 1. KGet Integration
// 2. Save downloads history
+static void extractSuggestedFileName(const QNetworkReply* reply, QString& fileName)
+{
+ fileName.clear();
+ const KIO::MetaData& metaData = reply->attribute(static_cast<QNetworkRequest::Attribute>(KIO::AccessManager::MetaData)).toMap();
+ if (metaData.value(QL1S("content-disposition-type")).compare(QL1S("attachment"), Qt::CaseInsensitive) == 0)
+ fileName = metaData.value(QL1S("content-disposition-filename"));
+
+ if (!fileName.isEmpty())
+ return;
+
+ if (!reply->hasRawHeader("Content-Disposition"))
+ return;
+
+ const QString value (QL1S(reply->rawHeader("Content-Disposition").simplified().constData()));
+ if (value.startsWith(QL1S("attachment"), Qt::CaseInsensitive) || value.startsWith(QL1S("inline"), Qt::CaseInsensitive))
+ {
+ const int length = value.size();
+ int pos = value.indexOf(QL1S("filename"), 0, Qt::CaseInsensitive);
+ if (pos > -1)
+ {
+ pos += 9;
+ while (pos < length && (value.at(pos) == QL1C(' ') || value.at(pos) == QL1C('=') || value.at(pos) == QL1C('"')))
+ pos++;
+
+ int endPos = pos;
+ while (endPos < length && value.at(endPos) != QL1C('"') && value.at(endPos) != QL1C(';'))
+ endPos++;
+
+ if (endPos > pos)
+ fileName = value.mid(pos, (endPos-pos)).trimmed();
+ }
+ }
+}
+
+
+static void extractMimeType(const QNetworkReply* reply, QString& mimeType)
+{
+ mimeType.clear();
+ const KIO::MetaData& metaData = reply->attribute(static_cast<QNetworkRequest::Attribute>(KIO::AccessManager::MetaData)).toMap();
+ if (metaData.contains(QL1S("content-type")))
+ mimeType = metaData.value(QL1S("content-type"));
+
+ if (!mimeType.isEmpty())
+ return;
+
+ if (!reply->hasRawHeader("Content-Type"))
+ return;
+
+ const QString value (QL1S(reply->rawHeader("Content-Type").simplified().constData()));
+ const int index = value.indexOf(QL1C(';'));
+ if (index == -1)
+ mimeType = value;
+ else
+ mimeType = value.left(index);
+}
+
+
static bool downloadResource (const KUrl& srcUrl, const KIO::MetaData& metaData = KIO::MetaData(),
QWidget* parent = 0, const QString& suggestedName = QString())
{
@@ -237,6 +299,9 @@ bool WebPage::acceptNavigationRequest(QWebFrame *frame, const QNetworkRequest &r
_isOnRekonqPage = false;
tab->setPart(0, KUrl()); // re-enable the view page
}
+
+ // reset webpage values
+ _suggestedFileName.clear();
_loadingUrl = request.url();
KIO::AccessManager *manager = qobject_cast<KIO::AccessManager*>(networkAccessManager());
@@ -289,15 +354,6 @@ bool WebPage::acceptNavigationRequest(QWebFrame *frame, const QNetworkRequest &r
default:
break;
}
-
- if (frame == mainFrame())
- {
- setRequestMetaData("main_frame_request", "TRUE");
- }
- else
- {
- setRequestMetaData("main_frame_request", "FALSE");
- }
}
return KWebPage::acceptNavigationRequest(frame, request, type);
}
@@ -325,11 +381,10 @@ WebPage *WebPage::createWindow(QWebPage::WebWindowType type)
void WebPage::handleUnsupportedContent(QNetworkReply *reply)
{
Q_ASSERT (reply);
- // NOTE:
- // Until kio implements a way to resume/continue a network
- // request. We must abort the reply to prevent a zombie process
- // from continuing to download the unsupported content!
- reply->abort();
+
+ // Put the job on hold...
+ kDebug() << "PUT REPLY ON HOLD...";
+ KIO::Integration::AccessManager::putReplyOnHold(reply);
// This is probably needed just in ONE stupid case..
if (_protHandler.postHandling(reply->request(), mainFrame()))
@@ -338,78 +393,24 @@ void WebPage::handleUnsupportedContent(QNetworkReply *reply)
if (reply->error() != QNetworkReply::NoError)
return;
+ // get reply url...
KUrl replyUrl = reply->url();
- // HACK -------------------------------------------
- // This is done to fix #231204 && #212808
-
- QString mimeType;
- QString suggestedFileName;
+ // Get suggested file name...
+ extractSuggestedFileName(reply, _suggestedFileName);
- QString app = reply->header(QNetworkRequest::ContentTypeHeader).toString();
- QStringList headerList = app.split( ';' );
-
- if(headerList.count() > 0)
- {
- mimeType = headerList.takeFirst().trimmed();
- Q_FOREACH(const QString &head, headerList)
- {
- if( head.contains( QL1S("name") ) )
- {
- // this is not so sure.. :)
- suggestedFileName = head;
- suggestedFileName = suggestedFileName.remove( QL1S("name=") );
- suggestedFileName = suggestedFileName.remove( '"' );
- suggestedFileName = suggestedFileName.trimmed();
- break;
- }
- }
- }
- else
- {
- mimeType = reply->header(QNetworkRequest::ContentTypeHeader).toString();
- }
-
- // NOTE
- // This part has been copied from KWebPage::downloadResponse code
- if (reply->hasRawHeader("Content-Disposition"))
- {
- KIO::MetaData metaData = reply->attribute(static_cast<QNetworkRequest::Attribute>(KIO::AccessManager::MetaData)).toMap();
- if (metaData.value(QL1S("content-disposition-type")).compare(QL1S("attachment"), Qt::CaseInsensitive) == 0)
- {
- suggestedFileName = metaData.value(QL1S("content-disposition-filename"));
- }
- else
- {
- const QString value = QL1S(reply->rawHeader("Content-Disposition").simplified());
- if (value.startsWith(QL1S("attachment"), Qt::CaseInsensitive))
- {
- const int length = value.size();
- int pos = value.indexOf(QL1S("filename"), 0, Qt::CaseInsensitive);
- if (pos > -1)
- {
- pos += 9;
- while (pos < length && (value.at(pos) == QL1C(' ') || value.at(pos) == QL1C('=') || value.at(pos) == QL1C('"')))
- pos++;
-
- int endPos = pos;
- while (endPos < length && value.at(endPos) != QL1C('"') && value.at(endPos) != QL1C(';'))
- endPos++;
-
- if (endPos > pos)
- {
- suggestedFileName = value.mid(pos, (endPos-pos)).trimmed();
- }
- }
- }
- }
- }
-
- kDebug() << "Detected MimeType = " << mimeType;
- kDebug() << "Suggested File Name = " << suggestedFileName;
+ // Get mimeType...
+ extractMimeType(reply, _mimeType);
+
+ // Convert executable text files to plain text...
+ if (KParts::BrowserRun::isTextExecutable(_mimeType))
+ _mimeType = QL1S("text/plain");
+
+ kDebug() << "Detected MimeType = " << _mimeType;
+ kDebug() << "Suggested File Name = " << _suggestedFileName;
// ------------------------------------------------
- KService::Ptr appService = KMimeTypeTrader::self()->preferredService(mimeType);
+ KService::Ptr appService = KMimeTypeTrader::self()->preferredService(_mimeType);
bool isLocal = replyUrl.isLocalFile();
@@ -419,22 +420,22 @@ void WebPage::handleUnsupportedContent(QNetworkReply *reply)
isLocal
? KMessageBox::sorry(view(), i18n("No service can handle this file."))
- : downloadReply(reply, suggestedFileName);
+ : downloadReply(reply, _suggestedFileName);
return;
}
if (!isLocal)
{
- KParts::BrowserOpenOrSaveQuestion dlg(Application::instance()->mainWindow(), replyUrl, mimeType);
- if(!suggestedFileName.isEmpty())
- dlg.setSuggestedFileName(suggestedFileName);
+ KParts::BrowserOpenOrSaveQuestion dlg(Application::instance()->mainWindow(), replyUrl, _mimeType);
+ if(!_suggestedFileName.isEmpty())
+ dlg.setSuggestedFileName(_suggestedFileName);
switch (dlg.askEmbedOrSave())
{
case KParts::BrowserOpenOrSaveQuestion::Save:
kDebug() << "user choice: no services, just download!";
- downloadReply(reply, suggestedFileName);
+ downloadReply(reply, _suggestedFileName);
return;
case KParts::BrowserOpenOrSaveQuestion::Cancel:
@@ -445,10 +446,46 @@ void WebPage::handleUnsupportedContent(QNetworkReply *reply)
}
}
+ // Handle Post operations that return content...
+ if (reply->operation() == QNetworkAccessManager::PostOperation)
+ {
+ kDebug() << "POST OPERATION: downloading file...";
+ QFileInfo finfo (_suggestedFileName.isEmpty() ? _loadingUrl.fileName() : _suggestedFileName);
+ KTemporaryFile tempFile;
+ tempFile.setSuffix(QL1C('.') + finfo.suffix());
+ tempFile.setAutoRemove(false);
+ tempFile.open();
+ KUrl destUrl;
+ destUrl.setPath(tempFile.fileName());
+ kDebug() << "First save content to" << destUrl;
+ KIO::Job *job = KIO::file_copy(_loadingUrl, destUrl, 0600, KIO::Overwrite);
+ job->ui()->setWindow(Application::instance()->mainWindow());
+ connect(job, SIGNAL(result(KJob *)), this, SLOT(copyToTempFileResult(KJob*)));
+ return;
+ }
+
+ // HACK: The check below is necessary to break an infinite
+ // recursion that occurs whenever this function is called as a result
+ // of receiving content that can be rendered by the app using this engine.
+ // For example a text/html header that containing a content-disposition
+ // header is received by the app using this class.
+ const QString& appName = QCoreApplication::applicationName();
+
+ if (appName == appService->desktopEntryName() || appService->exec().trimmed().startsWith(appName))
+ {
+ kDebug() << "SELF...";
+ QNetworkRequest req (reply->request());
+ req.setRawHeader("x-kdewebkit-ignore-disposition", "true");
+ currentFrame()->load(req);
+ return;
+ }
+
// case KParts::BrowserRun::Embed
- KParts::ReadOnlyPart *pa = KMimeTypeTrader::createPartInstanceFromQuery<KParts::ReadOnlyPart>(mimeType, view(), this, QString());
+ KParts::ReadOnlyPart *pa = KMimeTypeTrader::createPartInstanceFromQuery<KParts::ReadOnlyPart>(_mimeType, view(), this, QString());
if (pa)
{
+ kDebug() << "EMBEDDING CONTENT...";
+
_isOnRekonqPage = true;
WebView *view = qobject_cast<WebView *>(parent());
@@ -463,9 +500,21 @@ void WebPage::handleUnsupportedContent(QNetworkReply *reply)
else
{
// No parts, just app services. Load it!
- KRun::run(*appService, replyUrl, 0);
+ // If the app is a KDE one, publish the slave on hold to let it use it.
+ // Otherwise, run the app and remove it (the io slave...)
+ if (appService->categories().contains(QL1S("KDE"), Qt::CaseInsensitive))
+ {
+ KIO::Scheduler::publishSlaveOnHold();
+ KRun::run(*appService, replyUrl, 0, false, _suggestedFileName);
+ return;
+ }
+ KRun::run(*appService, replyUrl, 0, false, _suggestedFileName);
}
+ // Remove any ioslave that was put on hold...
+ kDebug() << "REMOVE SLAVES ON HOLD...";
+ KIO::Scheduler::removeSlaveOnHold();
+
return;
}
@@ -499,8 +548,6 @@ void WebPage::loadFinished(bool ok)
{
wallet()->fillFormData(mainFrame());
}
- kDebug() << "rekonq page: " << _isOnRekonqPage;
- kDebug() << "loading url: " << _loadingUrl;
}
@@ -508,6 +555,10 @@ void WebPage::manageNetworkErrors(QNetworkReply *reply)
{
Q_ASSERT(reply);
+ // check suggested file name
+ if(_suggestedFileName.isEmpty())
+ extractSuggestedFileName(reply, _suggestedFileName);
+
QWebFrame* frame = qobject_cast<QWebFrame *>(reply->request().originatingObject());
const bool isMainFrameRequest = (frame == mainFrame());
@@ -725,3 +776,12 @@ void WebPage::updateImage(bool ok)
p.snapFinished();
}
}
+
+
+void WebPage::copyToTempFileResult(KJob* job)
+{
+ if ( job->error() )
+ job->uiDelegate()->showErrorMessage();
+ else
+ (void)KRun::runUrl(static_cast<KIO::FileCopyJob *>(job)->destUrl(), _mimeType, Application::instance()->mainWindow());
+}
diff --git a/src/webpage.h b/src/webpage.h
index 41ddd877..7633b26d 100644
--- a/src/webpage.h
+++ b/src/webpage.h
@@ -59,6 +59,7 @@ public:
inline void setIsOnRekonqPage(bool b) { _isOnRekonqPage = b; };
inline KUrl loadingUrl() { return _loadingUrl; };
+ inline QString suggestedFileName() { return _suggestedFileName; };
public Q_SLOTS:
void downloadAllContentsWithKGet(QPoint);
@@ -81,15 +82,21 @@ private Q_SLOTS:
void showSSLInfo(QPoint);
void updateImage(bool ok);
+ void copyToTempFileResult(KJob*);
+
+private:
void downloadReply(const QNetworkReply *reply, const QString &suggestedFileName = QString());
private:
QString errorPage(QNetworkReply *reply);
- QUrl _loadingUrl;
+ KUrl _loadingUrl;
ProtocolHandler _protHandler;
WebSslInfo _sslInfo;
+ QString _mimeType;
+ QString _suggestedFileName;
+
bool _networkAnalyzer;
bool _isOnRekonqPage;
};