29 #define QT_NO_CAST_FROM_ASCII
43 #include <QtXml/qdom.h>
44 #include <QtCore/QFile>
45 #include <QtCore/QRegExp>
46 #include <QtCore/QDate>
47 #include <QtCore/QBuffer>
48 #include <QtCore/QIODevice>
49 #include <QtDBus/QtDBus>
50 #include <QtNetwork/QAuthenticator>
51 #include <QtNetwork/QNetworkProxy>
52 #include <QtNetwork/QTcpSocket>
74 #include <solid/networking.h>
94 rich.reserve(
int(plain.length() * 1.1));
95 for (
int i = 0; i < plain.length(); ++i) {
96 if (plain.at(i) == QLatin1Char(
'<'))
97 rich += QLatin1String(
"<");
98 else if (plain.at(i) == QLatin1Char(
'>'))
99 rich += QLatin1String(
">");
100 else if (plain.at(i) == QLatin1Char(
'&'))
101 rich += QLatin1String(
"&");
102 else if (plain.at(i) == QLatin1Char(
'"'))
103 rich += QLatin1String(
""");
114 return (scheme.startsWith(QLatin1String(
"http"))
115 || scheme == QLatin1String(
"socks"));
128 QCoreApplication app( argc, argv );
130 (void) KGlobal::locale();
134 fprintf(stderr,
"Usage: kio_http protocol domain-socket1 domain-socket2\n");
139 slave.dispatchLoop();
147 return QString::fromLatin1(value.constData(), value.size());
153 if (originURL == QLatin1String(
"true"))
156 KUrl url ( originURL );
166 QStringList la = a.split(QLatin1Char(
'.'), QString::SkipEmptyParts);
167 QStringList lb = b.split(QLatin1Char(
'.'), QString::SkipEmptyParts);
169 if (qMin(la.count(), lb.count()) < 2) {
173 while(la.count() > 2)
175 while(lb.count() > 2)
187 const QStringList headers = _header.split(QRegExp(QLatin1String(
"[\r\n]")));
189 for(QStringList::ConstIterator it = headers.begin(); it != headers.end(); ++it)
193 if (!(*it).contains(QLatin1Char(
':')) ||
194 (*it).startsWith(QLatin1String(
"host"), Qt::CaseInsensitive) ||
195 (*it).startsWith(QLatin1String(
"proxy-authorization"), Qt::CaseInsensitive) ||
196 (*it).startsWith(QLatin1String(
"via"), Qt::CaseInsensitive))
199 sanitizedHeaders += (*it);
200 sanitizedHeaders += QLatin1String(
"\r\n");
202 sanitizedHeaders.chop(2);
204 return sanitizedHeaders;
210 if (config->
readEntry(
"no-spoof-check",
false)) {
214 if (request.
url.
user().isEmpty()) {
219 if (config->
readEntry(QLatin1String(
"cached-www-auth"),
false)) {
250 if (responseCode >= 100 && responseCode < 200) {
253 switch (responseCode) {
259 Q_ASSERT(method != HTTP_HEAD);
269 return method != HTTP_HEAD;
274 return p ==
"https" || p ==
"webdavs";
279 return u.isValid() && u.
hasHost();
293 device =
new QBuffer;
295 if (!device->open(QIODevice::ReadWrite))
303 if (!methodStringOverride.isEmpty())
304 return (methodStringOverride + QLatin1Char(
' ')).toLatin1();
337 case DAV_UNSUBSCRIBE:
338 return "UNSUBSCRIBE ";
358 if (!dt.
time().second()) {
359 ret.append(QLatin1String(
":00"));
361 ret.append(QLatin1String(
" GMT"));
367 return (responseCode == 401) || (responseCode == 407);
370 #define NO_SIZE ((KIO::filesize_t) -1)
373 #define STRTOLL strtoll
375 #define STRTOLL strtol
383 const QByteArray &app )
391 , m_protocol(protocol)
394 , m_socketProxyAuth(0)
396 , m_isLoadingErrorPage(false)
398 , m_iEOFRetryCount(0)
402 connect(
socket(), SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
422 TCPSlaveBase::reparseConfiguration();
450 setMetaData(QLatin1String(
"request-id"),
m_request.
id);
465 const bool noAuth =
config()->readEntry(
"no-auth",
false);
475 kDebug(7113) <<
"ssl_was_in_use =" << metaData(QLatin1String(
"ssl_was_in_use"));
483 KUrl refUrl(metaData(QLatin1String(
"referrer")));
484 if (refUrl.isValid()) {
487 if (protocol.startsWith(QLatin1String(
"webdav"))) {
488 protocol.replace(0, 6, QLatin1String(
"http"));
492 if (protocol.startsWith(QLatin1String(
"http"))) {
498 if (
config()->readEntry(
"SendLanguageSettings",
true)) {
510 QString resumeOffset = metaData(QLatin1String(
"resume"));
511 if (!resumeOffset.isEmpty()) {
517 QString resumeEndOffset = metaData(QLatin1String(
"resume_until"));
518 if (!resumeEndOffset.isEmpty()) {
526 m_request.
id = metaData(QLatin1String(
"request-id"));
572 if (host.indexOf(QLatin1Char(
':')) == -1) {
575 int pos = host.indexOf(QLatin1Char(
'%'));
601 if (u.host().isEmpty()) {
602 error( KIO::ERR_UNKNOWN_HOST,
i18n(
"No host specified."));
606 if (u.
path().isEmpty()) {
608 newUrl.
setPath(QLatin1String(
"/"));
631 if (dataInternal || !status) {
690 setMetaData(QLatin1String(
"content-type"),
m_mimeType);
708 QString statSide = metaData(QLatin1String(
"statSide"));
709 if (statSide != QLatin1String(
"source"))
756 QString query = metaData(QLatin1String(
"davSearchQuery"));
757 if ( !query.isEmpty() )
759 QByteArray request =
"<?xml version=\"1.0\"?>\r\n";
760 request.append(
"<D:searchrequest xmlns:D=\"DAV:\">\r\n" );
761 request.append( query.toUtf8() );
762 request.append(
"</D:searchrequest>\r\n" );
768 request =
"<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
769 "<D:propfind xmlns:D=\"DAV:\">";
772 if ( hasMetaData(QLatin1String(
"davRequestResponse")) )
773 request += metaData(QLatin1String(
"davRequestResponse")).toUtf8();
776 request +=
"<D:prop>"
778 "<D:getcontentlength/>"
781 "<D:getcontentlanguage/>"
782 "<D:getcontenttype/>"
783 "<D:getlastmodified/>"
790 request +=
"</D:propfind>";
804 infoMessage(QLatin1String(
""));
814 QDomDocument multiResponse;
817 bool hasResponse =
false;
821 for ( QDomNode n = multiResponse.documentElement().firstChild();
822 !n.isNull(); n = n.nextSibling()) {
823 QDomElement thisResponse = n.toElement();
824 if (thisResponse.isNull())
829 QDomElement href = thisResponse.namedItem(QLatin1String(
"href")).toElement();
830 if ( !href.isNull() ) {
833 QString urlStr = QUrl::fromPercentEncoding(href.text().toUtf8());
834 #if 0 // qt4/kde4 say: it's all utf8...
835 int encoding = remoteEncoding()->encodingMib();
836 if ((encoding == 106) && (!KStringHandler::isUtf8(
KUrl::decode_string(urlStr, 4).toLatin1())))
839 KUrl thisURL ( urlStr, encoding );
841 KUrl thisURL( urlStr );
844 if ( thisURL.isValid() ) {
849 name = QLatin1Char(
'.');
854 QDomNodeList propstats = thisResponse.elementsByTagName(QLatin1String(
"propstat"));
865 if (mime && !mime->isDefault() && accuracy == 100) {
866 kDebug(7113) <<
"Setting" << mime->name() <<
"as guessed mime type for" << thisURL.
fileName();
878 listEntry( entry,
false );
880 kDebug(7113) <<
"Error: no URL contained in response to PROPFIND on" << url;
884 if ( stat || !hasResponse ) {
889 listEntry( entry,
true );
916 const int firstSpace = response.indexOf( QLatin1Char(
' ') );
917 const int secondSpace = response.indexOf( QLatin1Char(
' '), firstSpace + 1 );
918 return response.mid( firstSpace + 1, secondSpace - firstSpace - 1 ).toInt();
924 bool foundExecutable =
false;
925 bool isDirectory =
false;
927 uint supportedLockCount = 0;
929 for (
int i = 0; i < propstats.count(); i++)
931 QDomElement propstat = propstats.item(i).toElement();
933 QDomElement status = propstat.namedItem(QLatin1String(
"status")).toElement();
934 if ( status.isNull() )
937 kDebug(7113) <<
"Error, no status code in this propstat";
945 kDebug(7113) <<
"Got status code" << code <<
"(this may mean that some properties are unavailable)";
949 QDomElement prop = propstat.namedItem( QLatin1String(
"prop") ).toElement();
952 kDebug(7113) <<
"Error: no prop segment in this propstat.";
956 if ( hasMetaData( QLatin1String(
"davRequestResponse") ) )
959 doc.appendChild(prop);
963 for ( QDomNode n = prop.firstChild(); !n.isNull(); n = n.nextSibling() )
965 QDomElement
property = n.toElement();
966 if (property.isNull())
969 if ( property.namespaceURI() != QLatin1String(
"DAV:") )
975 if ( property.tagName() == QLatin1String(
"creationdate") )
980 else if ( property.tagName() == QLatin1String(
"getcontentlength") )
985 else if ( property.tagName() == QLatin1String(
"displayname") )
988 setMetaData( QLatin1String(
"davDisplayName"), property.text() );
990 else if ( property.tagName() == QLatin1String(
"source") )
993 QDomElement source =
property.namedItem( QLatin1String(
"link") ).toElement()
994 .namedItem( QLatin1String(
"dst") ).toElement();
995 if ( !source.isNull() )
996 setMetaData( QLatin1String(
"davSource"), source.text() );
998 else if ( property.tagName() == QLatin1String(
"getcontentlanguage") )
1001 setMetaData( QLatin1String(
"davContentLanguage"), property.text() );
1003 else if ( property.tagName() == QLatin1String(
"getcontenttype") )
1008 if ( property.text() == QLatin1String(
"httpd/unix-directory") )
1014 mimeType =
property.text();
1017 else if ( property.tagName() == QLatin1String(
"executable") )
1020 if ( property.text() == QLatin1String(
"T") )
1021 foundExecutable =
true;
1024 else if ( property.tagName() == QLatin1String(
"getlastmodified") )
1029 else if ( property.tagName() == QLatin1String(
"getetag") )
1032 setMetaData( QLatin1String(
"davEntityTag"), property.text() );
1034 else if ( property.tagName() == QLatin1String(
"supportedlock") )
1037 for ( QDomNode n2 = property.firstChild(); !n2.isNull(); n2 = n2.nextSibling() )
1039 QDomElement lockEntry = n2.toElement();
1040 if ( lockEntry.tagName() == QLatin1String(
"lockentry") )
1042 QDomElement lockScope = lockEntry.namedItem( QLatin1String(
"lockscope") ).toElement();
1043 QDomElement lockType = lockEntry.namedItem( QLatin1String(
"locktype") ).toElement();
1044 if ( !lockScope.isNull() && !lockType.isNull() )
1047 supportedLockCount++;
1048 const QString lockCountStr = QString::number(supportedLockCount);
1049 const QString scope = lockScope.firstChild().toElement().tagName();
1050 const QString type = lockType.firstChild().toElement().tagName();
1052 setMetaData( QLatin1String(
"davSupportedLockScope") + lockCountStr, scope );
1053 setMetaData( QLatin1String(
"davSupportedLockType") + lockCountStr, type );
1058 else if ( property.tagName() == QLatin1String(
"lockdiscovery") )
1061 davParseActiveLocks( property.elementsByTagName( QLatin1String(
"activelock") ), lockCount );
1063 else if ( property.tagName() == QLatin1String(
"resourcetype") )
1066 if ( !property.namedItem( QLatin1String(
"collection") ).toElement().isNull() )
1074 kDebug(7113) <<
"Found unknown webdav property:" <<
property.tagName();
1079 setMetaData( QLatin1String(
"davLockCount"), QString::number(lockCount) );
1080 setMetaData( QLatin1String(
"davSupportedLockCount"), QString::number(supportedLockCount) );
1084 if ( foundExecutable || isDirectory )
1094 if ( !isDirectory && !mimeType.isEmpty() )
1103 for (
int i = 0; i < activeLocks.count(); i++ )
1105 const QDomElement activeLock = activeLocks.item(i).toElement();
1109 const QDomElement lockScope = activeLock.namedItem( QLatin1String(
"lockscope") ).toElement();
1110 const QDomElement lockType = activeLock.namedItem( QLatin1String(
"locktype") ).toElement();
1111 const QDomElement lockDepth = activeLock.namedItem( QLatin1String(
"depth") ).toElement();
1113 const QDomElement lockOwner = activeLock.namedItem( QLatin1String(
"owner") ).toElement();
1114 const QDomElement lockTimeout = activeLock.namedItem( QLatin1String(
"timeout") ).toElement();
1115 const QDomElement lockToken = activeLock.namedItem( QLatin1String(
"locktoken") ).toElement();
1117 if ( !lockScope.isNull() && !lockType.isNull() && !lockDepth.isNull() )
1121 const QString lockCountStr = QString::number(lockCount);
1122 const QString scope = lockScope.firstChild().toElement().tagName();
1123 const QString type = lockType.firstChild().toElement().tagName();
1124 const QString depth = lockDepth.text();
1126 setMetaData( QLatin1String(
"davLockScope") + lockCountStr, scope );
1127 setMetaData( QLatin1String(
"davLockType") + lockCountStr, type );
1128 setMetaData( QLatin1String(
"davLockDepth") + lockCountStr, depth );
1130 if ( !lockOwner.isNull() )
1131 setMetaData( QLatin1String(
"davLockOwner") + lockCountStr, lockOwner.text() );
1133 if ( !lockTimeout.isNull() )
1134 setMetaData( QLatin1String(
"davLockTimeout") + lockCountStr, lockTimeout.text() );
1136 if ( !lockToken.isNull() )
1138 QDomElement tokenVal = lockScope.namedItem( QLatin1String(
"href") ).toElement();
1139 if ( !tokenVal.isNull() )
1140 setMetaData( QLatin1String(
"davLockToken") + lockCountStr, tokenVal.text() );
1148 if ( type == QLatin1String(
"dateTime.tz") )
1152 else if ( type == QLatin1String(
"dateTime.rfc1123") )
1167 if ( hasMetaData( QLatin1String(
"davLockCount") ) )
1169 QString response = QLatin1String(
"If:");
1170 int numLocks = metaData( QLatin1String(
"davLockCount") ).toInt();
1171 bool bracketsOpen =
false;
1172 for (
int i = 0; i < numLocks; i++ )
1174 const QString countStr = QString::number(i);
1175 if ( hasMetaData( QLatin1String(
"davLockToken") + countStr ) )
1177 if ( hasMetaData( QLatin1String(
"davLockURL") + countStr ) )
1181 response += QLatin1Char(
')');
1182 bracketsOpen =
false;
1184 response += QLatin1String(
" <") + metaData( QLatin1String(
"davLockURL") + countStr ) + QLatin1Char(
'>');
1187 if ( !bracketsOpen )
1189 response += QLatin1String(
" (");
1190 bracketsOpen =
true;
1194 response += QLatin1Char(
' ');
1197 if ( hasMetaData( QLatin1String(
"davLockNot") + countStr ) )
1198 response += QLatin1String(
"Not ");
1200 response += QLatin1Char(
'<') + metaData( QLatin1String(
"davLockToken") + countStr ) + QLatin1Char(
'>');
1205 response += QLatin1Char(
')');
1207 response += QLatin1String(
"\r\n");
1227 kDebug(7113) <<
" false";
1250 if (ok && verNo > 0 && verNo < 3)
1253 kDebug(7113) <<
"Server supports DAV version" << verNo;
1305 QString tmp(metaData(QLatin1String(
"cache")));
1325 if (!(flags & KIO::Overwrite)) {
1330 const QByteArray request (
"<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
1331 "<D:propfind xmlns:D=\"DAV:\"><D:prop>"
1333 "<D:getcontentlength/>"
1336 "</D:prop></D:propfind>");
1372 kDebug(7113) << src <<
"->" << dest;
1379 KUrl newDest = dest;
1380 if (newDest.
protocol() == QLatin1String(
"webdavs"))
1382 else if (newDest.
protocol() == QLatin1String(
"webdav"))
1402 kDebug(7113) << src <<
"->" << dest;
1409 KUrl newDest = dest;
1410 if (newDest.
protocol() == QLatin1String(
"webdavs"))
1412 else if (newDest.
protocol() == QLatin1String(
"webdav"))
1506 QDomDocument lockReq;
1508 QDomElement lockInfo = lockReq.createElementNS( QLatin1String(
"DAV:"), QLatin1String(
"lockinfo") );
1509 lockReq.appendChild( lockInfo );
1511 QDomElement lockScope = lockReq.createElement( QLatin1String(
"lockscope") );
1512 lockInfo.appendChild( lockScope );
1514 lockScope.appendChild( lockReq.createElement( scope ) );
1516 QDomElement lockType = lockReq.createElement( QLatin1String(
"locktype") );
1517 lockInfo.appendChild( lockType );
1519 lockType.appendChild( lockReq.createElement( type ) );
1521 if ( !owner.isNull() ) {
1522 QDomElement ownerElement = lockReq.createElement( QLatin1String(
"owner") );
1523 lockReq.appendChild( ownerElement );
1525 QDomElement ownerHref = lockReq.createElement( QLatin1String(
"href") );
1526 ownerElement.appendChild( ownerHref );
1528 ownerHref.appendChild( lockReq.createTextNode( owner ) );
1538 QDomDocument multiResponse;
1541 QDomElement prop = multiResponse.documentElement().namedItem( QLatin1String(
"prop") ).toElement();
1543 QDomElement lockdiscovery = prop.namedItem( QLatin1String(
"lockdiscovery") ).toElement();
1546 davParseActiveLocks( lockdiscovery.elementsByTagName( QLatin1String(
"activelock") ), lockCount );
1548 setMetaData( QLatin1String(
"davLockCount"), QString::number( lockCount ) );
1578 bool callError =
false;
1588 if ( !url.isNull() )
1595 QString ow =
i18n(
"Otherwise, the request would have succeeded." );
1599 action =
i18nc(
"request type",
"retrieve property values" );
1602 action =
i18nc(
"request type",
"set property values" );
1605 action =
i18nc(
"request type",
"create the requested folder" );
1608 action =
i18nc(
"request type",
"copy the specified file or folder" );
1611 action =
i18nc(
"request type",
"move the specified file or folder" );
1614 action =
i18nc(
"request type",
"search in the specified folder" );
1617 action =
i18nc(
"request type",
"lock the specified file or folder" );
1620 action =
i18nc(
"request type",
"unlock the specified file or folder" );
1623 action =
i18nc(
"request type",
"delete the specified file or folder" );
1626 action =
i18nc(
"request type",
"query the server's capabilities" );
1629 action =
i18nc(
"request type",
"retrieve the contents of the specified file or folder" );
1632 action =
i18nc(
"request type",
"run a report in the specified folder" );
1643 errorString =
i18nc(
"%1: code, %2: request type",
"An unexpected error (%1) occurred "
1644 "while attempting to %2.", code, action);
1651 errorString =
i18n(
"The server does not support the WebDAV protocol.");
1665 QDomDocument multiResponse;
1669 QDomElement multistatus = multiResponse.documentElement().namedItem( QLatin1String(
"multistatus") ).toElement();
1671 QDomNodeList responses = multistatus.elementsByTagName( QLatin1String(
"response") );
1673 for (
int i = 0; i < responses.count(); i++)
1678 QDomElement response = responses.item(i).toElement();
1679 QDomElement code = response.namedItem( QLatin1String(
"status") ).toElement();
1681 if ( !code.isNull() )
1684 QDomElement href = response.namedItem( QLatin1String(
"href") ).toElement();
1685 if ( !href.isNull() )
1686 errUrl = href.text();
1687 errors <<
davError( errCode, errUrl );
1692 errorString =
i18nc(
"%1: request type, %2: url",
1693 "An error occurred while attempting to %1, %2. A "
1694 "summary of the reasons is below.", action, url );
1696 errorString += QLatin1String(
"<ul>");
1699 errorString += QLatin1String(
"<li>") + error + QLatin1String(
"</li>");
1701 errorString += QLatin1String(
"</ul>");
1707 errorString =
i18nc(
"%1: request type",
"Access was denied while attempting to %1.", action );
1720 errorString =
i18n(
"A resource cannot be created at the destination "
1721 "until one or more intermediate collections (folders) "
1722 "have been created.");
1728 errorString =
i18n(
"The server was unable to maintain the liveness of "
1729 "the properties listed in the propertybehavior XML "
1730 "element or you attempted to overwrite a file while "
1731 "requesting that files are not overwritten. %1",
1736 errorString =
i18n(
"The requested lock could not be granted. %1", ow );
1742 errorString =
i18n(
"The server does not support the request type of the body.");
1747 errorString =
i18nc(
"%1: request type",
"Unable to %1 because the resource is locked.", action );
1751 errorString =
i18n(
"This action was prevented by another error.");
1757 errorString =
i18nc(
"%1: request type",
"Unable to %1 because the destination server refuses "
1758 "to accept the file or folder.", action );
1764 errorString =
i18n(
"The destination resource does not have sufficient space "
1765 "to record the state of the resource after the execution "
1776 error( errorCode, errorString );
1784 Q_ASSERT(errorString);
1787 errorString->clear();
1799 Q_ASSERT(errorString);
1803 errorString->clear();
1805 switch (responseCode) {
1814 && (responseCode < 200 || responseCode > 400)
1815 && responseCode != 404) {
1817 *errorString =
i18n(
"The resource cannot be deleted." );
1826 Q_ASSERT(errorString);
1832 switch (responseCode) {
1839 *errorString =
i18nc(
"%1: request type",
"Access was denied while attempting to %1.", action );
1845 *errorString =
i18n(
"A resource cannot be created at the destination "
1846 "until one or more intermediate collections (folders) "
1847 "have been created.");
1853 *errorString =
i18nc(
"%1: request type",
"Unable to %1 because the resource is locked.", action );
1859 *errorString =
i18nc(
"%1: request type",
"Unable to %1 because the destination server refuses "
1860 "to accept the file or folder.", action );
1866 *errorString =
i18n(
"The destination resource does not have sufficient space "
1867 "to record the state of the resource after the execution "
1876 && (responseCode < 200 || responseCode > 400)
1877 && responseCode != 404) {
1879 *errorString =
i18nc(
"%1: response code, %2: request type",
1880 "An unexpected error (%1) occurred while attempting to %2.",
1881 responseCode, action);
1908 infoMessage(QLatin1String(
""));
1911 error( errorCode, errorString );
1924 kWarning(7113) <<
"called twice during one request, something is probably wrong.";
1927 SlaveBase::errorPage();
1937 Solid::Networking::Status status = Solid::Networking::status();
1939 kDebug(7113) <<
"networkstatus:" << status;
1942 return status == Solid::Networking::Unconnected;
1947 QDataStream stream(data);
1959 for (
unsigned i = 0; i < n; ++i) {
1961 stream >> url >> mIncomingMetaData;
1974 QString tmp = metaData(QLatin1String(
"cache"));
1989 while (it.hasNext()) {
2001 while (it.hasNext()) {
2018 setMetaData(QLatin1String(
"request-id"), QString::number(requestId++));
2019 sendAndKeepMetaData();
2038 const char* buf =
static_cast<const char*
>(_buf);
2039 while (sent < nbytes)
2041 int n = TCPSlaveBase::write(buf + sent, nbytes - sent);
2066 for (
size_t i = 0; i < size; i++) {
2077 size_t bytesRead = 0;
2080 bytesRead = qMin((
int)size, bufSize);
2082 for (
size_t i = 0; i < bytesRead; i++) {
2083 buf[i] =
m_unreadBuf.constData()[bufSize - i - 1];
2094 if (bytesRead < size) {
2095 int rawRead = TCPSlaveBase::read(buf + bytesRead, size - bytesRead);
2100 bytesRead += rawRead;
2111 Q_ASSERT(numNewlines >=1 && numNewlines <= 2);
2114 while (pos < end && !
m_isEOF) {
2115 int step = qMin((
int)
sizeof(mybuf), end - pos);
2124 for (
size_t i = 0; i < bufferFill ; ++i, ++pos) {
2127 buf[pos] = mybuf[i];
2132 if (buf[pos] ==
'\n') {
2133 bool found = numNewlines == 1;
2136 found = ((pos >= 1 && buf[pos - 1] ==
'\n') ||
2137 (pos >= 2 && buf[pos - 2] ==
'\n' && buf[pos - 1] ==
'\r'));
2141 unread(&mybuf[i], bufferFill - i);
2154 if (previous.host() != now.host() || previous.port() != now.port()) {
2157 if (previous.
user().isEmpty() && previous.
pass().isEmpty()) {
2173 if (url != QLatin1String(
"DIRECT")) {
2192 disconnect(
socket(), SIGNAL(connected()),
2197 int connectError = 0;
2207 QNetworkProxy::setApplicationProxy(QNetworkProxy::NoProxy);
2212 if (proxyUrl == QLatin1String(
"DIRECT")) {
2213 QNetworkProxy::setApplicationProxy(QNetworkProxy::NoProxy);
2215 if (connectError == 0) {
2223 const KUrl url(proxyUrl);
2227 errorString = url.
url();
2228 badProxyUrls << url;
2232 QNetworkProxy::ProxyType proxyType = QNetworkProxy::NoProxy;
2233 if (proxyScheme == QLatin1String(
"socks")) {
2234 proxyType = QNetworkProxy::Socks5Proxy;
2236 proxyType = QNetworkProxy::HttpProxy;
2239 kDebug(7113) <<
"Connecting to proxy: address=" << proxyUrl <<
"type=" << proxyType;
2241 if (proxyType == QNetworkProxy::NoProxy) {
2242 QNetworkProxy::setApplicationProxy(QNetworkProxy::NoProxy);
2243 connectError =
connectToHost(url.host(), url.port(), &errorString);
2244 if (connectError == 0) {
2246 kDebug(7113) <<
"Connected to proxy: host=" << url.host() <<
"port=" << url.port();
2252 kDebug(7113) <<
"Failed to connect to proxy:" << proxyUrl;
2253 badProxyUrls << url;
2256 QNetworkProxy proxy(proxyType, url.host(), url.port(), url.
user(), url.
pass());
2257 QNetworkProxy::setApplicationProxy(proxy);
2259 if (connectError == 0) {
2260 kDebug(7113) <<
"Tunneling thru proxy: host=" << url.host() <<
"port=" << url.port();
2266 kDebug(7113) <<
"Failed to connect to proxy:" << proxyUrl;
2267 badProxyUrls << url;
2268 QNetworkProxy::setApplicationProxy(QNetworkProxy::NoProxy);
2273 if (!badProxyUrls.isEmpty()) {
2278 if (connectError != 0) {
2279 error(connectError, errorString);
2309 bool openForReading =
false;
2313 if (!openForReading && (isCacheOnly || offline)) {
2315 *cacheHasPage =
false;
2318 }
else if (offline) {
2325 if (openForReading) {
2327 *cacheHasPage =
true;
2332 *cacheHasPage =
false;
2345 if (protocol.startsWith(QLatin1String(
"webdav"))) {
2346 protocol.replace(0, qstrlen(
"webdav"), QLatin1String(
"http"));
2403 kDebug(7113) <<
"Couldn't connect, oopsie!";
2415 bool hasBodyData =
false;
2416 bool hasDavData =
false;
2426 bool cacheHasPage =
false;
2428 kDebug(7113) <<
"cacheHasPage =" << cacheHasPage;
2429 return cacheHasPage;
2431 if (!cacheHasPage) {
2448 davHeader = QLatin1String(
"Depth: ");
2449 if ( hasMetaData( QLatin1String(
"davDepth") ) )
2451 kDebug(7113) <<
"Reading DAV depth from metadata:" << metaData( QLatin1String(
"davDepth") );
2452 davHeader += metaData( QLatin1String(
"davDepth") );
2457 davHeader += QLatin1String(
"infinity");
2461 davHeader += QLatin1String(
"\r\n");
2473 davHeader += QLatin1String(
"\r\nDepth: infinity\r\nOverwrite: ");
2475 davHeader += QLatin1String(
"\r\n");
2478 davHeader = QLatin1String(
"Timeout: ");
2481 if ( hasMetaData( QLatin1String(
"davTimeout") ) )
2482 timeout = metaData( QLatin1String(
"davTimeout") ).toUInt();
2484 davHeader += QLatin1String(
"Infinite");
2486 davHeader += QLatin1String(
"Seconds-") + QString::number(timeout);
2488 davHeader += QLatin1String(
"\r\n");
2492 davHeader = QLatin1String(
"Lock-token: ") + metaData(QLatin1String(
"davLockToken")) + QLatin1String(
"\r\n");
2499 case DAV_UNSUBSCRIBE:
2513 header += QLatin1Char(
':') + QString::number(
m_request.
url.port());
2515 header += QLatin1String(
"\r\n");
2522 header += QLatin1String(
"Proxy-Connection: ");
2524 header += QLatin1String(
"Connection: ");
2527 header += QLatin1String(
"keep-alive\r\n");
2529 header += QLatin1String(
"close\r\n");
2534 header += QLatin1String(
"User-Agent: ");
2536 header += QLatin1String(
"\r\n");
2541 header += QLatin1String(
"Referer: ");
2543 header += QLatin1String(
"\r\n");
2548 header += QLatin1String(
"Range: bytes=");
2550 header += QLatin1Char(
'-');
2552 header += QLatin1String(
"\r\n");
2558 header += QLatin1String(
"Range: bytes=");
2560 header += QLatin1String(
"-\r\n");
2567 header += QLatin1String(
"Pragma: no-cache\r\n");
2568 header += QLatin1String(
"Cache-control: no-cache\r\n");
2572 kDebug(7113) <<
"needs validation, performing conditional get.";
2579 header += QLatin1String(
"If-Modified-Since: ") + httpDate + QLatin1String(
"\r\n");
2580 setMetaData(QLatin1String(
"modified"), httpDate);
2584 header += QLatin1String(
"Accept: ");
2585 const QString acceptHeader = metaData(QLatin1String(
"accept"));
2586 if (!acceptHeader.isEmpty())
2587 header += acceptHeader;
2590 header += QLatin1String(
"\r\n");
2593 header += QLatin1String(
"Accept-Encoding: gzip, deflate, x-gzip, x-deflate\r\n");
2596 header += QLatin1String(
"Accept-Charset: ") +
m_request.
charsets + QLatin1String(
"\r\n");
2599 header += QLatin1String(
"Accept-Language: ") +
m_request.
languages + QLatin1String(
"\r\n");
2602 const QString cookieMode = metaData(QLatin1String(
"cookies")).toLower();
2604 if (cookieMode == QLatin1String(
"none"))
2608 else if (cookieMode == QLatin1String(
"manual"))
2611 cookieStr = metaData(QLatin1String(
"setcookies"));
2620 if (!cookieStr.isEmpty())
2621 header += cookieStr + QLatin1String(
"\r\n");
2623 const QString customHeader = metaData( QLatin1String(
"customHTTPHeader") );
2624 if (!customHeader.isEmpty())
2627 header += QLatin1String(
"\r\n");
2630 const QString contentType = metaData(QLatin1String(
"content-type"));
2631 if (!contentType.isEmpty())
2633 if (!contentType.startsWith(QLatin1String(
"content-type"), Qt::CaseInsensitive))
2634 header += QLatin1String(
"Content-Type: ");
2635 header += contentType;
2636 header += QLatin1String(
"\r\n");
2641 header += QLatin1String(
"DNT: 1\r\n");
2654 davHeader += metaData(QLatin1String(
"davHeader"));
2658 davHeader += QLatin1String(
"Content-Type: text/xml; charset=utf-8\r\n");
2661 header += davHeader;
2665 kDebug(7103) <<
"============ Sending Header:";
2666 Q_FOREACH (
const QString &s, header.split(QLatin1String(
"\r\n"), QString::SkipEmptyParts)) {
2672 if (!hasBodyData && !hasDavData)
2673 header += QLatin1String(
"\r\n");
2682 const QByteArray headerBytes = header.toLatin1();
2683 ssize_t written =
write(headerBytes.constData(), headerBytes.length());
2684 bool sendOk = (written == (ssize_t) headerBytes.length());
2688 <<
" -- intended to write" << headerBytes.length()
2689 <<
"bytes but wrote" << (int)written <<
".";
2699 kDebug(7113) <<
"sendOk == false. Connection broken !"
2700 <<
" -- intended to write" << headerBytes.length()
2701 <<
"bytes but wrote" << (int)written <<
".";
2706 kDebug(7113) <<
"sent it!";
2709 if (hasBodyData || hasDavData)
2712 infoMessage(
i18n(
"%1 contacted. Waiting for reply...",
m_request.
url.host()));
2725 if (forwardImmediately)
2738 if (header.startsWith(QLatin1String(
"content-type:"), Qt::CaseInsensitive)) {
2739 int pos = header.indexOf(QLatin1String(
"charset="), Qt::CaseInsensitive);
2741 const QString charset = header.mid(pos + 8).toLower();
2743 setMetaData(QLatin1String(
"charset"), charset);
2745 }
else if (header.startsWith(QLatin1String(
"content-language:"), Qt::CaseInsensitive)) {
2746 const QString language = header.mid(17).trimmed().toLower();
2747 setMetaData(QLatin1String(
"content-language"), language);
2748 }
else if (header.startsWith(QLatin1String(
"content-disposition:"), Qt::CaseInsensitive)) {
2775 if (
m_mimeType == QLatin1String(
"application/x-targz"))
2776 m_mimeType = QLatin1String(
"application/x-compressed-tar");
2777 else if (
m_mimeType == QLatin1String(
"image/x-png"))
2781 else if (
m_mimeType == QLatin1String(
"audio/microsoft-wave"))
2783 else if (
m_mimeType == QLatin1String(
"image/x-ms-bmp"))
2787 else if (
m_mimeType == QLatin1String(
"application/pkix-cert") ||
2788 m_mimeType == QLatin1String(
"application/binary-certificate")) {
2789 m_mimeType = QLatin1String(
"application/x-x509-ca-cert");
2793 else if (
m_mimeType == QLatin1String(
"application/x-gzip")) {
2796 m_mimeType = QLatin1String(
"application/x-compressed-tar");
2798 m_mimeType = QLatin1String(
"application/x-gzpostscript");
2803 else if(
m_mimeType == QLatin1String(
"application/x-xz")) {
2806 m_mimeType = QLatin1String(
"application/x-xz-compressed-tar");
2811 else if ((
m_mimeType == QLatin1String(
"text/plain")) || (
m_mimeType == QLatin1String(
"application/octet-stream"))) {
2813 if (ext == QLatin1String(
"BZ2"))
2814 m_mimeType = QLatin1String(
"application/x-bzip");
2815 else if (ext == QLatin1String(
"PEM"))
2816 m_mimeType = QLatin1String(
"application/x-x509-ca-cert");
2817 else if (ext == QLatin1String(
"SWF"))
2818 m_mimeType = QLatin1String(
"application/x-shockwave-flash");
2819 else if (ext == QLatin1String(
"PLS"))
2821 else if (ext == QLatin1String(
"WMV"))
2822 m_mimeType = QLatin1String(
"video/x-ms-wmv");
2823 else if (ext == QLatin1String(
"WEBM"))
2825 else if (ext == QLatin1String(
"DEB"))
2826 m_mimeType = QLatin1String(
"application/x-deb");
2840 if (
m_mimeType == QLatin1String(
"application/x-tar")) {
2842 m_mimeType = QLatin1String(
"application/x-compressed-tar");
2843 }
else if (
m_mimeType == QLatin1String(
"application/postscript")) {
2847 m_mimeType = QLatin1String(
"application/x-gzpostscript");
2852 m_mimeType != QLatin1String(
"application/x-compressed-tar") &&
2853 m_mimeType != QLatin1String(
"application/x-tgz") &&
2854 m_mimeType != QLatin1String(
"application/x-targz") &&
2855 m_mimeType != QLatin1String(
"application/x-gzip"))) {
2859 m_mimeType = QLatin1String(
"application/x-gzip");
2871 m_mimeType = QLatin1String(
"application/x-bzip");
2878 static bool consume(
const char input[],
int *pos,
int end,
const char *term)
2882 if (idx + (
int)strlen(term) >= end) {
2886 if (strncasecmp(&input[idx], term, strlen(term)) == 0) {
2887 *pos = idx + strlen(term);
2911 bool upgradeRequired =
false;
2915 bool noHeadersFound =
false;
2920 static const int maxHeaderSize = 128 * 1024;
2922 char buffer[maxHeaderSize];
2924 bool bCanResume =
false;
2927 kDebug(7113) <<
"No connection.";
2937 kDebug(7113) <<
"Got socket error:" <<
socket()->errorString();
2946 if (!foundDelimiter && bufPos < maxHeaderSize) {
2947 kDebug(7113) <<
"EOF while waiting for header start.";
2964 kDebug(7113) <<
"Connection broken !";
2968 if (!foundDelimiter) {
2973 kDebug(7103) <<
"============ Received Status Response:";
2974 kDebug(7103) << QByteArray(buffer, bufPos).trimmed();
2979 if (idx != bufPos && buffer[idx] ==
'<') {
2980 kDebug(7103) <<
"No valid HTTP header found! Document starts with XML/HTML tag";
2986 noHeadersFound =
true;
2993 if (
consume(buffer, &idx, bufPos,
"ICY ")) {
2996 }
else if (
consume(buffer, &idx, bufPos,
"HTTP/")) {
2997 if (
consume(buffer, &idx, bufPos,
"1.0")) {
3000 }
else if (
consume(buffer, &idx, bufPos,
"1.1")) {
3005 if (httpRev ==
HTTP_None && bufPos != 0) {
3008 kDebug(7113) <<
"DO NOT WANT." << bufPos;
3016 noHeadersFound =
true;
3027 if (idx != bufPos) {
3043 messageBox(WarningYesNo,
3044 i18nc(
"@info Security check on url being accessed",
3045 "<p>You are about to log in to the site \"%1\" "
3046 "with the username \"%2\", but the website "
3047 "does not require authentication. "
3048 "This may be an attempt to trick you.</p>"
3049 "<p>Is \"%1\" the site you want to visit?</p>",
3051 i18nc(
"@title:window",
"Confirm Website Access"));
3056 setMetaData(QLatin1String(
"{internal~currenthost}LastSpoofedUserName"),
m_request.
url.
user());
3078 upgradeRequired =
true;
3092 setMetaData(QLatin1String(
"permanent-redirect"), QLatin1String(
"true"));
3126 infoMessage(
i18n(
"Server processing request, please wait..." ) );
3135 bool authRequiresAnotherRoundtrip =
false;
3138 if (!noHeadersFound) {
3143 kDebug(7113) <<
"wasAuthError=" << wasAuthError <<
"isAuthError=" << isAuthError
3144 <<
"sameAuthError=" << sameAuthError;
3156 kDebug(7113) <<
" -- full response:" << endl << QByteArray(buffer, bufPos).trimmed();
3159 Q_ASSERT(foundDelimiter);
3166 tokenizer.
tokenize(idx,
sizeof(buffer));
3171 if (tIt.
hasNext() && tIt.
next().toLower().startsWith(
"none")) {
3175 tIt = tokenizer.iterator(
"keep-alive");
3177 QByteArray ka = tIt.
next().trimmed().toLower();
3178 if (ka.startsWith(
"timeout=")) {
3179 int ka_timeout = ka.mid(qstrlen(
"timeout=")).trimmed().toInt();
3191 tIt = tokenizer.iterator(
"content-length");
3196 tIt = tokenizer.iterator(
"content-location");
3198 setMetaData(QLatin1String(
"content-location"),
toQString(tIt.
next().trimmed()));
3204 tIt = tokenizer.iterator(
"content-type");
3210 if (
m_mimeType.startsWith(QLatin1Char(
'"'))) {
3222 Q_FOREACH (
const QByteArray &statement, l) {
3223 const int index = statement.indexOf(
'=');
3225 mediaAttribute =
toQString(statement.mid(0, index));
3227 mediaAttribute =
toQString(statement.mid(0, index));
3228 mediaValue =
toQString(statement.mid(index+1));
3230 mediaAttribute = mediaAttribute.trimmed();
3231 mediaValue = mediaValue.trimmed();
3233 bool quoted =
false;
3234 if (mediaValue.startsWith(QLatin1Char(
'"'))) {
3236 mediaValue.remove(0, 1);
3239 if (mediaValue.endsWith(QLatin1Char(
'"'))) {
3243 kDebug (7113) <<
"Encoding-type:" << mediaAttribute <<
"=" << mediaValue;
3245 if (mediaAttribute == QLatin1String(
"charset")) {
3246 mediaValue = mediaValue.toLower();
3248 setMetaData(QLatin1String(
"charset"), mediaValue);
3250 setMetaData(QLatin1String(
"media-") + mediaAttribute, mediaValue);
3252 setMetaData(QLatin1String(
"media-") + mediaAttribute + QLatin1String(
"-kio-quoted"),
3253 QLatin1String(
"true"));
3260 tIt = tokenizer.iterator(
"content-encoding");
3278 tIt = tokenizer.iterator(
"content-disposition");
3282 tIt = tokenizer.iterator(
"content-language");
3285 if (!language.isEmpty()) {
3286 setMetaData(QLatin1String(
"content-language"), language);
3290 tIt = tokenizer.iterator(
"proxy-connection");
3292 QByteArray pc = tIt.
next().toLower();
3293 if (pc.startsWith(
"close")) {
3295 }
else if (pc.startsWith(
"keep-alive")) {
3300 tIt = tokenizer.iterator(
"link");
3304 if (link.count() == 2) {
3305 QString rel = link[1].trimmed();
3306 if (rel.startsWith(QLatin1String(
"rel=\""))) {
3307 rel = rel.mid(5, rel.length() - 6);
3308 if (rel.toLower() == QLatin1String(
"pageservices")) {
3310 QString url = link[0].remove(QRegExp(QLatin1String(
"[<>]"))).trimmed();
3311 setMetaData(QLatin1String(
"PageServices"), url);
3317 tIt = tokenizer.iterator(
"p3p");
3323 .split(QLatin1Char(
'='), QString::SkipEmptyParts);
3324 if (policy.count() == 2) {
3325 if (policy[0].toLower() == QLatin1String(
"policyref")) {
3326 policyrefs << policy[1].remove(QRegExp(QLatin1String(
"[\")\']"))).trimmed();
3327 }
else if (policy[0].toLower() == QLatin1String(
"cp")) {
3331 const QString s = policy[1].remove(QRegExp(QLatin1String(
"[\")\']")));
3332 const QStringList cps = s.split(QLatin1Char(
' '), QString::SkipEmptyParts);
3337 if (!policyrefs.isEmpty()) {
3338 setMetaData(QLatin1String(
"PrivacyPolicy"), policyrefs.join(QLatin1String(
"\n")));
3340 if (!compact.isEmpty()) {
3341 setMetaData(QLatin1String(
"PrivacyCompactPolicy"), compact.join(QLatin1String(
"\n")));
3348 tIt = tokenizer.iterator(
"connection");
3350 QByteArray connection = tIt.
next().toLower();
3352 if (connection.startsWith(
"close")) {
3354 }
else if (connection.startsWith(
"keep-alive")) {
3358 if (connection.startsWith(
"upgrade")) {
3361 upgradeRequired =
true;
3362 }
else if (upgradeRequired) {
3368 tIt = tokenizer.iterator(
"transfer-encoding");
3377 tIt = tokenizer.iterator(
"content-md5");
3384 tIt = tokenizer.iterator(
"dav");
3394 tIt = tokenizer.iterator(
"upgrade");
3398 upgradeOffers = offered.split(QRegExp(QLatin1String(
"[ \n,\r\t]")), QString::SkipEmptyParts);
3400 Q_FOREACH (
const QString &opt, upgradeOffers) {
3401 if (opt == QLatin1String(
"TLS/1.0")) {
3402 if (!
startSsl() && upgradeRequired) {
3406 }
else if (opt == QLatin1String(
"HTTP/1.1")) {
3408 }
else if (upgradeRequired) {
3416 QByteArray cookieStr;
3417 tIt = tokenizer.iterator(
"set-cookie");
3419 cookieStr +=
"Set-Cookie: ";
3420 cookieStr += tIt.
next();
3423 if (!cookieStr.isEmpty()) {
3428 cookieStr =
"Cross-Domain\n" + cookieStr;
3433 setMetaData(QLatin1String(
"setcookies"), QString::fromUtf8(cookieStr));
3441 kDebug(7113) <<
"cont; returning to mark try_again";
3447 kDebug(7113) <<
"Ignoring keep-alive: otherwise unable to determine response body length.";
3462 authRequiresAnotherRoundtrip =
false;
3467 tIt = tokenizer.iterator(
"location");
3469 locationStr = QString::fromUtf8(tIt.
next().trimmed());
3472 if (!locationStr.isEmpty())
3499 if(u.
protocol() == QLatin1String(
"http")){
3501 }
else if(u.
protocol() == QLatin1String(
"https")){
3541 kDebug(7113) <<
"Reading resource from cache even though the cache plan is not "
3542 "UseCached; the server is probably sending wrong expiry information.";
3552 int nextLinePos = 0;
3553 int prevLinePos = 0;
3554 bool haveMore =
true;
3556 haveMore =
nextLine(buffer, &nextLinePos, bufPos);
3557 int prevLineEnd = nextLinePos;
3558 while (buffer[prevLineEnd - 1] ==
'\r' || buffer[prevLineEnd - 1] ==
'\n') {
3563 prevLineEnd - prevLinePos));
3564 prevLinePos = nextLinePos;
3591 return !authRequiresAnotherRoundtrip;
3599 while (i != parameters.constEnd()) {
3600 setMetaData(QLatin1String(
"content-disposition-") + i.key(), i.value());
3601 kDebug(7113) <<
"Content-Disposition:" << i.key() <<
"=" << i.value();
3608 QString encoding = _encoding.trimmed().toLower();
3610 if (encoding == QLatin1String(
"identity")) {
3612 }
else if (encoding == QLatin1String(
"8bit")) {
3615 }
else if (encoding == QLatin1String(
"chunked")) {
3620 }
else if ((encoding == QLatin1String(
"x-gzip")) || (encoding == QLatin1String(
"gzip"))) {
3621 encs.append(QLatin1String(
"gzip"));
3622 }
else if ((encoding == QLatin1String(
"x-bzip2")) || (encoding == QLatin1String(
"bzip2"))) {
3623 encs.append(QLatin1String(
"bzip2"));
3624 }
else if ((encoding == QLatin1String(
"x-deflate")) || (encoding == QLatin1String(
"deflate"))) {
3625 encs.append(QLatin1String(
"deflate"));
3627 kDebug(7113) <<
"Unknown encoding encountered. "
3628 <<
"Please write code. Encoding =" << encoding;
3647 const qint64 currentDate = time(0);
3664 tIt = tokenizer.iterator(
"date");
3671 tIt = tokenizer.iterator(
"age");
3673 ageHeader = tIt.
next().toLongLong();
3677 if (dateHeader != -1) {
3679 }
else if (ageHeader) {
3686 bool hasCacheDirective =
false;
3691 tIt = tokenizer.iterator(
"cache-control");
3693 QByteArray cacheStr = tIt.
next().toLower();
3694 if (cacheStr.startsWith(
"no-cache") || cacheStr.startsWith(
"no-store")) {
3697 hasCacheDirective =
true;
3698 }
else if (cacheStr.startsWith(
"max-age=")) {
3699 QByteArray ba = cacheStr.mid(qstrlen(
"max-age=")).trimmed();
3701 maxAgeHeader = ba.toLongLong(&ok);
3703 hasCacheDirective =
true;
3708 qint64 expiresHeader = -1;
3709 tIt = tokenizer.iterator(
"expires");
3712 kDebug(7113) <<
"parsed expire date from 'expires' header:" << tIt.
current();
3717 }
else if (expiresHeader != -1) {
3726 expAge = qMin(expAge,
qint64(3600 * 24));
3739 tIt = tokenizer.iterator(
"etag");
3744 kDebug(7103) <<
"304 Not Modified but new entity tag - I don't think this is legal HTTP.";
3749 tIt = tokenizer.iterator(
"warning");
3757 tIt = tokenizer.iterator(
"pragma");
3759 if (tIt.
next().toLower().startsWith(
"no-cache")) {
3761 hasCacheDirective =
true;
3766 tIt = tokenizer.iterator(
"refresh");
3769 setMetaData(QLatin1String(
"http-refresh"),
toQString(tIt.
next().trimmed()));
3773 if (
m_mimeType.startsWith(QLatin1String(
"text/")) && (
m_mimeType != QLatin1String(
"text/css")) &&
3774 (
m_mimeType != QLatin1String(
"text/x-javascript")) && !hasCacheDirective) {
3785 kDebug(7113) <<
"Cache needs validation";
3787 kDebug(7113) <<
"...was revalidated by response code but not by updated expire times. "
3788 "We're going to set the expire date to 60 seconds in the future...";
3794 kDebug(7113) <<
"this proxy or server apparently sends bogus expiry information.";
3811 kDebug(7113) <<
"This webserver is confused about the cacheability of the data it sends.";
3825 if (!cachingAllowed) {
3826 setMetaData(QLatin1String(
"no-cache"), QLatin1String(
"true"));
3827 setMetaData(QLatin1String(
"expire-date"), QLatin1String(
"1"));
3831 setMetaData(QLatin1String(
"expire-date"), tmp);
3834 setMetaData(QLatin1String(
"cache-creation-date"), tmp);
3842 QByteArray cLength (
"Content-Length: ");
3843 cLength += QByteArray::number(
m_POSTbuf->size());
3844 cLength +=
"\r\n\r\n";
3846 kDebug(7113) <<
"sending cached data (size=" <<
m_POSTbuf->size() <<
")";
3849 bool sendOk = (
write(cLength.data(), cLength.size()) == (ssize_t) cLength.size());
3851 kDebug( 7113 ) <<
"Connection broken when sending "
3863 sendOk = (
write(buffer.data(), buffer.size()) == (ssize_t) buffer.size());
3865 kDebug(7113) <<
"Connection broken when sending message body: ("
3896 QByteArray cLength (
"Content-Length: ");
3898 cLength +=
"\r\n\r\n";
3900 kDebug(7113) << cLength.trimmed();
3903 bool sendOk = (
write(cLength.data(), cLength.size()) == (ssize_t) cLength.size());
3913 kDebug(7113) <<
"Connection broken while sending POST content size to" <<
m_request.
url.host();
3926 KIO::filesize_t bytesSent = 0;
3932 const int bytesRead = readData(buffer);
3935 if (bytesRead == 0) {
3941 if (bytesRead < 0) {
3955 if (
write(buffer.data(), bytesRead) == static_cast<ssize_t>(bytesRead)) {
3956 bytesSent += bytesRead;
3957 processedSize(bytesSent);
3961 kDebug(7113) <<
"Connection broken while sending POST content to" <<
m_request.
url.host();
3971 kDebug(7113) <<
"keepAlive =" << keepAlive;
3987 QDataStream stream( &data, QIODevice::WriteOnly );
4009 setTimeoutSpecialCommand(-1);
4046 QDataStream stream(data);
4054 stream >> url >> size;
4063 stream >> url >> no_cache >> expireDate;
4069 QFile::remove(filename);
4090 stream >> url >> scope >> type >> owner;
4091 davLock( url, scope, type, owner );
4106 stream >> url >> method >> size;
4107 davGeneric( url, (KIO::HTTP_METHOD) method, size );
4136 if (foundCrLf && bufPos == 2) {
4143 kDebug(7113) <<
"Failed to read chunk header.";
4146 Q_ASSERT(bufPos > 2);
4149 if (nextChunkSize < 0)
4151 kDebug(7113) <<
"Negative chunk size";
4168 int trashBufPos = 2;
4171 if (trashBufPos > 3) {
4173 for (
int i = 0; i < 3; i++) {
4174 trash[i] = trash[trashBufPos - 3 + i];
4181 kDebug(7113) <<
"Failed to read chunk trailer.";
4193 return bytesReceived;
4211 if (bytesReceived <= 0)
4215 return bytesReceived;
4222 kDebug(7113) <<
"Unbounded datastream on a Keep-alive connection!";
4262 kDebug(7113) <<
"Determining mime-type from content...";
4276 if( mime && !mime->isDefault() )
4357 if ( !dataInternal ) {
4360 infoMessage(
i18n(
"Retrieving %1 from %2...", KIO::convertSize(
m_iSize),
4368 kDebug(7113) <<
"reading data from cache...";
4380 if (!dataInternal) {
4387 if (!dataInternal) {
4415 QObject::connect(&chain, SIGNAL(
output(QByteArray)),
4425 if ( enc == QLatin1String(
"gzip") )
4427 else if ( enc == QLatin1String(
"deflate") )
4455 if ( enc == QLatin1String(
"gzip") )
4457 else if ( enc == QLatin1String(
"deflate") )
4476 if (bytesReceived == -1)
4486 kDebug(7113) <<
"bytesReceived==-1 sz=" << (int)sz
4487 <<
" Connection broken !";
4494 if (bytesReceived > 0)
4505 sz += bytesReceived;
4507 processedSize( sz );
4531 kWarning(7113) <<
"MD5 checksum MISMATCH! Expected:"
4540 if (!dataInternal && sz <= 1)
4553 data( QByteArray() );
4560 error(KIO::ERR_SLAVE_DEFINED, text);
4581 SlaveBase::error( _err, _text );
4589 QDBusInterface kcookiejar( QLatin1String(
"org.kde.kded"), QLatin1String(
"/modules/kcookiejar"), QLatin1String(
"org.kde.KCookieServer") );
4590 (void)kcookiejar.call( QDBus::NoBlock, QLatin1String(
"addCookies"), url,
4591 cookieHeader, windowId );
4597 QDBusInterface kcookiejar( QLatin1String(
"org.kde.kded"), QLatin1String(
"/modules/kcookiejar"), QLatin1String(
"org.kde.KCookieServer") );
4598 QDBusReply<QString> reply = kcookiejar.call( QLatin1String(
"findCookies"), url, windowId );
4600 if ( !reply.isValid() )
4602 kWarning(7113) <<
"Can't communicate with kded_kcookiejar!";
4614 case KIO::CC_Refresh:
4621 case KIO::CC_Reload:
4623 case KIO::CC_CacheOnly:
4631 time_t currentDate = time(0);
4644 struct BinaryCacheFileHeader
4656 static const int size = 36;
4668 BinaryCacheFileHeader
header;
4677 QDataStream stream(&ret, QIODevice::WriteOnly);
4678 stream << quint8(
'A');
4679 stream << quint8(
'\n');
4680 stream << quint8(0);
4681 stream << quint8(0);
4683 stream << fileUseCount;
4686 stream <<
qint64(servedDate);
4687 stream << qint64(lastModifiedDate);
4688 stream << qint64(expireDate);
4690 stream << bytesCached;
4691 Q_ASSERT(ret.size() == BinaryCacheFileHeader::size);
4700 return byte == value;
4703 static bool readTime(QDataStream *stream, time_t *time)
4707 *time =
static_cast<time_t
>(intTime);
4710 return check == intTime;
4719 if (d.size() != BinaryCacheFileHeader::size) {
4722 QDataStream stream(d);
4723 stream.setVersion(QDataStream::Qt_4_5);
4734 stream >> fileUseCount;
4737 ok = ok &&
readTime(&stream, &servedDate);
4738 ok = ok &&
readTime(&stream, &lastModifiedDate);
4739 ok = ok &&
readTime(&stream, &expireDate);
4744 stream >> bytesCached;
4769 static const char linefeed =
'\n';
4771 dev->write(&linefeed, 1);
4778 Q_ASSERT(file->openMode() & QIODevice::WriteOnly);
4780 file->seek(BinaryCacheFileHeader::size);
4794 if (line->isEmpty() || !line->endsWith(
'\n')) {
4806 Q_ASSERT(file->openMode() == QIODevice::ReadOnly);
4810 if (
storableUrl(desiredUrl).toEncoded() != readBuf) {
4811 kDebug(7103) <<
"You have witnessed a very improbable hash collision!";
4825 Q_ASSERT(file->openMode() == QIODevice::ReadOnly);
4831 qint64 oldPos = file->pos();
4832 file->seek(BinaryCacheFileHeader::size);
4835 Q_ASSERT(file->pos() == oldPos);
4844 if (ok && !readBuf.isEmpty()) {
4855 QCryptographicHash hash(QCryptographicHash::Sha1);
4857 return toQString(hash.result().toHex());
4863 if (!filePath.endsWith(QLatin1Char(
'/'))) {
4864 filePath.append(QLatin1Char(
'/'));
4877 kDebug(7113) <<
"File unexpectedly open; old file is" << file->fileName()
4878 <<
"new name is" << filename;
4879 Q_ASSERT(file->fileName() == filename);
4882 file =
new QFile(filename);
4883 if (file->open(QIODevice::ReadOnly)) {
4884 QByteArray
header = file->read(BinaryCacheFileHeader::size);
4886 kDebug(7103) <<
"Cache file header is invalid.";
4896 if (!file->isOpen()) {
4914 Q_ASSERT(!qobject_cast<QTemporaryFile *>(file));
4915 Q_ASSERT((file->openMode() & QIODevice::WriteOnly) == 0);
4916 Q_ASSERT(file->fileName() == filename);
4917 kDebug(7113) <<
"deleting expired cache entry and recreating.";
4925 file->open(QIODevice::WriteOnly);
4931 if ((file->openMode() & QIODevice::WriteOnly) == 0) {
4932 kDebug(7113) <<
"Could not open file for writing:" << file->fileName()
4933 <<
"due to error" << file->error();
4944 QDataStream stream(&ret, QIODevice::WriteOnly);
4945 stream.setVersion(QDataStream::Qt_4_5);
4947 stream.skipRawData(BinaryCacheFileHeader::size);
4952 int basenameStart = fileName.lastIndexOf(QLatin1Char(
'/')) + 1;
4954 stream.writeRawData(baseName.constData(), baseName.size());
4956 Q_ASSERT(ret.size() == BinaryCacheFileHeader::size +
sizeof(quint32) +
s_hashedUrlNibbles);
4972 QByteArray ccCommand;
4975 if (file->openMode() & QIODevice::WriteOnly) {
4981 tempFile->write(header);
4985 QString oldName = tempFile->fileName();
4987 int basenameStart = newName.lastIndexOf(QLatin1Char(
'/')) + 1;
4990 kDebug(7113) <<
"Renaming temporary file" << oldName <<
"to" << newName;
4993 tempFile->setAutoRemove(
false);
4997 if (!QFile::rename(oldName, newName)) {
5000 kDebug(7113) <<
"Renaming temporary file failed, deleting it instead.";
5001 QFile::remove(oldName);
5008 }
else if (file->openMode() == QIODevice::ReadOnly) {
5009 Q_ASSERT(!tempFile);
5015 if (!ccCommand.isEmpty()) {
5026 if (attempts == 2) {
5040 kDebug(7113) <<
"Could not connect to cache cleaner, not updating stats of this cache file.";
5050 if (ret.isEmpty()) {
5067 kDebug(7113) <<
"Caching disabled because content size is too big.";
5097 m_POSTbuf->write (data.constData(), data.size());
5123 const int bytesRead = readData(buffer);
5125 if (bytesRead < 0) {
5130 if (bytesRead == 0) {
5134 m_POSTbuf->write(buffer.constData(), buffer.size());
5162 if (useCachedAuth && checkCachedAuthentication(authinfo)) {
5163 const QByteArray cachedChallenge =
config()->readEntry(
"www-auth-challenge", QByteArray());
5164 if (!cachedChallenge.isEmpty()) {
5167 kDebug(7113) <<
"creating www authentcation header from cached info";
5185 if (checkCachedAuthentication(authinfo)) {
5186 const QByteArray cachedChallenge =
config()->readEntry(
"proxy-auth-challenge", QByteArray());
5187 if (!cachedChallenge.isEmpty()) {
5190 kDebug(7113) <<
"creating proxy authentcation header from cached info";
5200 ret +=
"Authorization: ";
5205 ret +=
"Proxy-Authorization: ";
5215 case QNetworkProxy::DefaultProxy:
5217 case QNetworkProxy::Socks5Proxy:
5218 return QLatin1String(
"socks");
5219 case QNetworkProxy::NoProxy:
5221 case QNetworkProxy::HttpProxy:
5222 case QNetworkProxy::HttpCachingProxy:
5223 case QNetworkProxy::FtpCachingProxy:
5228 return QLatin1String(
"http");
5233 kDebug(7113) <<
"realm:" << authenticator->realm() <<
"user:" << authenticator->user();
5244 info.
username = authenticator->user();
5247 const bool haveCachedCredentials = checkCachedAuthentication(info);
5252 if (!haveCachedCredentials || retryAuth) {
5255 connect(
socket(), SIGNAL(connected()),
5258 info.
prompt =
i18n(
"You need to supply a username and a password for "
5259 "the proxy server listed below before you are allowed "
5260 "to access any sites.");
5265 const QString errMsg ((retryAuth ?
i18n(
"Proxy Authentication Failed.") :
QString()));
5267 if (!openPasswordDialog(info, errMsg)) {
5268 kDebug(7113) <<
"looks like the user canceled proxy authentication.";
5275 authenticator->setUser(info.
username);
5276 authenticator->setPassword(info.
password);
5277 authenticator->setOption(QLatin1String(
"keepalive"), info.
keepPassword);
5292 kDebug(7113) <<
"Saving authenticator";
5293 disconnect(
socket(), SIGNAL(connected()),
5305 cacheAuthentication(a);
5314 bool alreadyCached =
false;
5319 alreadyCached =
config()->readEntry(
"cached-www-auth",
false);
5323 alreadyCached =
config()->readEntry(
"cached-proxy-auth",
false);
5330 if (auth && (!auth->
realm().isEmpty() || !alreadyCached)) {
5333 setMetaData(QLatin1String(
"{internal~currenthost}cached-www-auth"), QLatin1String(
"true"));
5335 setMetaData(QLatin1String(
"{internal~currenthost}www-auth-realm"), authinfo.
realmValue);
5337 setMetaData(QLatin1String(
"{internal~currenthost}www-auth-challenge"), authinfo.
digestInfo);
5339 setMetaData(QLatin1String(
"{internal~allhosts}cached-proxy-auth"), QLatin1String(
"true"));
5341 setMetaData(QLatin1String(
"{internal~allhosts}proxy-auth-realm"), authinfo.
realmValue);
5343 setMetaData(QLatin1String(
"{internal~allhosts}proxy-auth-challenge"), authinfo.
digestInfo);
5349 cacheAuthentication(authinfo);
5365 authTokens = tokenizer->iterator(
"www-authenticate").all();
5368 authinfo.
prompt =
i18n(
"You need to supply a username and a "
5369 "password to access this site.");
5375 Q_ASSERT(QNetworkProxy::applicationProxy().type() == QNetworkProxy::NoProxy);
5377 authTokens = tokenizer->iterator(
"proxy-authenticate").all();
5380 authinfo.
prompt =
i18n(
"You need to supply a username and a password for "
5381 "the proxy server listed below before you are allowed "
5382 "to access any sites." );
5386 bool authRequiresAnotherRoundtrip =
false;
5391 if (!authTokens.isEmpty()) {
5393 authRequiresAnotherRoundtrip =
true;
5397 if ((*auth)->wasFinalStage()) {
5399 i18n(
"Authentication Failed.") :
5400 i18n(
"Proxy Authentication Failed."));
5408 QMutableListIterator<QByteArray> it (authTokens);
5409 const QByteArray authScheme ((*auth)->scheme().trimmed());
5410 while (it.hasNext()) {
5411 if (qstrnicmp(authScheme.constData(), it.next().constData(), authScheme.length()) != 0) {
5418 try_next_auth_scheme:
5421 const QByteArray authScheme ((*auth)->scheme().trimmed());
5422 if (qstrnicmp(authScheme.constData(), bestOffer.constData(), authScheme.length()) != 0) {
5434 kDebug(7113) <<
"Trying authentication scheme:" << (*auth)->scheme();
5440 bool generateAuthHeader =
true;
5441 if ((*auth)->needCredentials()) {
5452 if (authinfo.
realmValue.isEmpty() && !(*auth)->supportsPathMatching())
5453 authinfo.
realmValue = QLatin1String((*auth)->scheme());
5458 const KUrl reqUrl = authinfo.
url;
5459 if (!errorMsg.isEmpty() || !checkCachedAuthentication(authinfo)) {
5461 authinfo.
url = reqUrl;
5466 if (!openPasswordDialog(authinfo, errorMsg)) {
5467 generateAuthHeader =
false;
5468 authRequiresAnotherRoundtrip =
false;
5472 kDebug(7113) <<
"looks like the user canceled the authentication dialog";
5482 if (generateAuthHeader) {
5483 (*auth)->generateResponse(username, password);
5484 (*auth)->setCachePasswordEnabled(authinfo.
keepPassword);
5486 kDebug(7113) <<
"isError=" << (*auth)->isError()
5487 <<
"needCredentials=" << (*auth)->needCredentials()
5488 <<
"forceKeepAlive=" << (*auth)->forceKeepAlive()
5489 <<
"forceDisconnect=" << (*auth)->forceDisconnect();
5491 if ((*auth)->isError()) {
5492 authTokens.removeOne(bestOffer);
5493 if (!authTokens.isEmpty()) {
5494 goto try_next_auth_scheme;
5497 authRequiresAnotherRoundtrip =
false;
5500 }
else if ((*auth)->forceKeepAlive()) {
5503 }
else if ((*auth)->forceDisconnect()) {
5510 authRequiresAnotherRoundtrip =
false;
5517 return authRequiresAnotherRoundtrip;