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(
""");
113 return (scheme.startsWith(QLatin1String(
"http"), Qt::CaseInsensitive)
114 || scheme == QLatin1String(
"socks"));
127 QCoreApplication app( argc, argv );
129 (void) KGlobal::locale();
133 fprintf(stderr,
"Usage: kio_http protocol domain-socket1 domain-socket2\n");
138 slave.dispatchLoop();
146 return QString::fromLatin1(value.constData(), value.size());
152 if (originURL == QLatin1String(
"true"))
155 KUrl url ( originURL );
165 QStringList la = a.split(QLatin1Char(
'.'), QString::SkipEmptyParts);
166 QStringList lb = b.split(QLatin1Char(
'.'), QString::SkipEmptyParts);
168 if (qMin(la.count(), lb.count()) < 2) {
172 while(la.count() > 2)
174 while(lb.count() > 2)
186 const QStringList headers = _header.split(QRegExp(QLatin1String(
"[\r\n]")));
188 for(QStringList::ConstIterator it = headers.begin(); it != headers.end(); ++it)
192 if (!(*it).contains(QLatin1Char(
':')) ||
193 (*it).startsWith(QLatin1String(
"host"), Qt::CaseInsensitive) ||
194 (*it).startsWith(QLatin1String(
"proxy-authorization"), Qt::CaseInsensitive) ||
195 (*it).startsWith(QLatin1String(
"via"), Qt::CaseInsensitive))
198 sanitizedHeaders += (*it);
199 sanitizedHeaders += QLatin1String(
"\r\n");
201 sanitizedHeaders.chop(2);
203 return sanitizedHeaders;
209 if (config->
readEntry(
"no-spoof-check",
false)) {
213 if (request.
url.
user().isEmpty()) {
218 if (config->
readEntry(QLatin1String(
"cached-www-auth"),
false)) {
249 if (responseCode >= 100 && responseCode < 200) {
252 switch (responseCode) {
258 Q_ASSERT(method != HTTP_HEAD);
268 return method != HTTP_HEAD;
273 return p ==
"https" || p ==
"webdavs";
278 return u.isValid() && u.
hasHost();
292 device =
new QBuffer;
294 if (!device->open(QIODevice::ReadWrite))
302 if (!methodStringOverride.isEmpty())
303 return (methodStringOverride + QLatin1Char(
' ')).toLatin1();
336 case DAV_UNSUBSCRIBE:
337 return "UNSUBSCRIBE ";
357 if (!dt.
time().second()) {
358 ret.append(QLatin1String(
":00"));
360 ret.append(QLatin1String(
" GMT"));
366 return (responseCode == 401) || (responseCode == 407);
369 #define NO_SIZE ((KIO::filesize_t) -1)
372 #define STRTOLL strtoll
374 #define STRTOLL strtol
382 const QByteArray &app )
390 , m_protocol(protocol)
393 , m_socketProxyAuth(0)
395 , m_isLoadingErrorPage(false)
400 connect(
socket(), SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
420 TCPSlaveBase::reparseConfiguration();
448 setMetaData(QLatin1String(
"request-id"),
m_request.
id);
463 const bool noAuth =
config()->readEntry(
"no-auth",
false);
473 kDebug(7113) <<
"ssl_was_in_use =" << metaData(QLatin1String(
"ssl_was_in_use"));
481 KUrl refUrl(metaData(QLatin1String(
"referrer")));
482 if (refUrl.isValid()) {
485 if (protocol.startsWith(QLatin1String(
"webdav"))) {
486 protocol.replace(0, 6, QLatin1String(
"http"));
490 if (protocol.startsWith(QLatin1String(
"http"))) {
496 if (
config()->readEntry(
"SendLanguageSettings",
true)) {
508 QString resumeOffset = metaData(QLatin1String(
"resume"));
509 if (!resumeOffset.isEmpty()) {
515 QString resumeEndOffset = metaData(QLatin1String(
"resume_until"));
516 if (!resumeEndOffset.isEmpty()) {
524 m_request.
id = metaData(QLatin1String(
"request-id"));
567 if (host.indexOf(QLatin1Char(
':')) == -1) {
570 int pos = host.indexOf(QLatin1Char(
'%'));
596 if (u.host().isEmpty()) {
597 error( KIO::ERR_UNKNOWN_HOST,
i18n(
"No host specified."));
601 if (u.
path().isEmpty()) {
603 newUrl.
setPath(QLatin1String(
"/"));
626 if (dataInternal || !status) {
685 setMetaData(QLatin1String(
"content-type"),
m_mimeType);
703 QString statSide = metaData(QLatin1String(
"statSide"));
704 if (statSide != QLatin1String(
"source"))
751 QString query = metaData(QLatin1String(
"davSearchQuery"));
752 if ( !query.isEmpty() )
754 QByteArray request =
"<?xml version=\"1.0\"?>\r\n";
755 request.append(
"<D:searchrequest xmlns:D=\"DAV:\">\r\n" );
756 request.append( query.toUtf8() );
757 request.append(
"</D:searchrequest>\r\n" );
763 request =
"<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
764 "<D:propfind xmlns:D=\"DAV:\">";
767 if ( hasMetaData(QLatin1String(
"davRequestResponse")) )
768 request += metaData(QLatin1String(
"davRequestResponse")).toUtf8();
771 request +=
"<D:prop>"
773 "<D:getcontentlength/>"
776 "<D:getcontentlanguage/>"
777 "<D:getcontenttype/>"
778 "<D:getlastmodified/>"
785 request +=
"</D:propfind>";
799 infoMessage(QLatin1String(
""));
809 QDomDocument multiResponse;
812 bool hasResponse =
false;
816 for ( QDomNode n = multiResponse.documentElement().firstChild();
817 !n.isNull(); n = n.nextSibling()) {
818 QDomElement thisResponse = n.toElement();
819 if (thisResponse.isNull())
824 QDomElement href = thisResponse.namedItem(QLatin1String(
"href")).toElement();
825 if ( !href.isNull() ) {
828 QString urlStr = QUrl::fromPercentEncoding(href.text().toUtf8());
829 #if 0 // qt4/kde4 say: it's all utf8...
830 int encoding = remoteEncoding()->encodingMib();
831 if ((encoding == 106) && (!KStringHandler::isUtf8(
KUrl::decode_string(urlStr, 4).toLatin1())))
834 KUrl thisURL ( urlStr, encoding );
836 KUrl thisURL( urlStr );
839 if ( thisURL.isValid() ) {
844 name = QLatin1Char(
'.');
849 QDomNodeList propstats = thisResponse.elementsByTagName(QLatin1String(
"propstat"));
860 if (mime && !mime->isDefault() && accuracy == 100) {
861 kDebug(7113) <<
"Setting" << mime->name() <<
"as guessed mime type for" << thisURL.
fileName();
873 listEntry( entry,
false );
875 kDebug(7113) <<
"Error: no URL contained in response to PROPFIND on" << url;
879 if ( stat || !hasResponse ) {
884 listEntry( entry,
true );
911 const int firstSpace = response.indexOf( QLatin1Char(
' ') );
912 const int secondSpace = response.indexOf( QLatin1Char(
' '), firstSpace + 1 );
913 return response.mid( firstSpace + 1, secondSpace - firstSpace - 1 ).toInt();
919 bool foundExecutable =
false;
920 bool isDirectory =
false;
922 uint supportedLockCount = 0;
924 for (
int i = 0; i < propstats.count(); i++)
926 QDomElement propstat = propstats.item(i).toElement();
928 QDomElement status = propstat.namedItem(QLatin1String(
"status")).toElement();
929 if ( status.isNull() )
932 kDebug(7113) <<
"Error, no status code in this propstat";
940 kDebug(7113) <<
"Got status code" << code <<
"(this may mean that some properties are unavailable)";
944 QDomElement prop = propstat.namedItem( QLatin1String(
"prop") ).toElement();
947 kDebug(7113) <<
"Error: no prop segment in this propstat.";
951 if ( hasMetaData( QLatin1String(
"davRequestResponse") ) )
954 doc.appendChild(prop);
958 for ( QDomNode n = prop.firstChild(); !n.isNull(); n = n.nextSibling() )
960 QDomElement
property = n.toElement();
961 if (property.isNull())
964 if ( property.namespaceURI() != QLatin1String(
"DAV:") )
970 if ( property.tagName() == QLatin1String(
"creationdate") )
975 else if ( property.tagName() == QLatin1String(
"getcontentlength") )
980 else if ( property.tagName() == QLatin1String(
"displayname") )
983 setMetaData( QLatin1String(
"davDisplayName"), property.text() );
985 else if ( property.tagName() == QLatin1String(
"source") )
988 QDomElement source =
property.namedItem( QLatin1String(
"link") ).toElement()
989 .namedItem( QLatin1String(
"dst") ).toElement();
990 if ( !source.isNull() )
991 setMetaData( QLatin1String(
"davSource"), source.text() );
993 else if ( property.tagName() == QLatin1String(
"getcontentlanguage") )
996 setMetaData( QLatin1String(
"davContentLanguage"), property.text() );
998 else if ( property.tagName() == QLatin1String(
"getcontenttype") )
1003 if ( property.text() == QLatin1String(
"httpd/unix-directory") )
1009 mimeType =
property.text();
1012 else if ( property.tagName() == QLatin1String(
"executable") )
1015 if ( property.text() == QLatin1String(
"T") )
1016 foundExecutable =
true;
1019 else if ( property.tagName() == QLatin1String(
"getlastmodified") )
1024 else if ( property.tagName() == QLatin1String(
"getetag") )
1027 setMetaData( QLatin1String(
"davEntityTag"), property.text() );
1029 else if ( property.tagName() == QLatin1String(
"supportedlock") )
1032 for ( QDomNode n2 = property.firstChild(); !n2.isNull(); n2 = n2.nextSibling() )
1034 QDomElement lockEntry = n2.toElement();
1035 if ( lockEntry.tagName() == QLatin1String(
"lockentry") )
1037 QDomElement lockScope = lockEntry.namedItem( QLatin1String(
"lockscope") ).toElement();
1038 QDomElement lockType = lockEntry.namedItem( QLatin1String(
"locktype") ).toElement();
1039 if ( !lockScope.isNull() && !lockType.isNull() )
1042 supportedLockCount++;
1043 const QString lockCountStr = QString::number(supportedLockCount);
1044 const QString scope = lockScope.firstChild().toElement().tagName();
1045 const QString type = lockType.firstChild().toElement().tagName();
1047 setMetaData( QLatin1String(
"davSupportedLockScope") + lockCountStr, scope );
1048 setMetaData( QLatin1String(
"davSupportedLockType") + lockCountStr, type );
1053 else if ( property.tagName() == QLatin1String(
"lockdiscovery") )
1056 davParseActiveLocks( property.elementsByTagName( QLatin1String(
"activelock") ), lockCount );
1058 else if ( property.tagName() == QLatin1String(
"resourcetype") )
1061 if ( !property.namedItem( QLatin1String(
"collection") ).toElement().isNull() )
1069 kDebug(7113) <<
"Found unknown webdav property:" <<
property.tagName();
1074 setMetaData( QLatin1String(
"davLockCount"), QString::number(lockCount) );
1075 setMetaData( QLatin1String(
"davSupportedLockCount"), QString::number(supportedLockCount) );
1079 if ( foundExecutable || isDirectory )
1089 if ( !isDirectory && !mimeType.isEmpty() )
1098 for (
int i = 0; i < activeLocks.count(); i++ )
1100 const QDomElement activeLock = activeLocks.item(i).toElement();
1104 const QDomElement lockScope = activeLock.namedItem( QLatin1String(
"lockscope") ).toElement();
1105 const QDomElement lockType = activeLock.namedItem( QLatin1String(
"locktype") ).toElement();
1106 const QDomElement lockDepth = activeLock.namedItem( QLatin1String(
"depth") ).toElement();
1108 const QDomElement lockOwner = activeLock.namedItem( QLatin1String(
"owner") ).toElement();
1109 const QDomElement lockTimeout = activeLock.namedItem( QLatin1String(
"timeout") ).toElement();
1110 const QDomElement lockToken = activeLock.namedItem( QLatin1String(
"locktoken") ).toElement();
1112 if ( !lockScope.isNull() && !lockType.isNull() && !lockDepth.isNull() )
1116 const QString lockCountStr = QString::number(lockCount);
1117 const QString scope = lockScope.firstChild().toElement().tagName();
1118 const QString type = lockType.firstChild().toElement().tagName();
1119 const QString depth = lockDepth.text();
1121 setMetaData( QLatin1String(
"davLockScope") + lockCountStr, scope );
1122 setMetaData( QLatin1String(
"davLockType") + lockCountStr, type );
1123 setMetaData( QLatin1String(
"davLockDepth") + lockCountStr, depth );
1125 if ( !lockOwner.isNull() )
1126 setMetaData( QLatin1String(
"davLockOwner") + lockCountStr, lockOwner.text() );
1128 if ( !lockTimeout.isNull() )
1129 setMetaData( QLatin1String(
"davLockTimeout") + lockCountStr, lockTimeout.text() );
1131 if ( !lockToken.isNull() )
1133 QDomElement tokenVal = lockScope.namedItem( QLatin1String(
"href") ).toElement();
1134 if ( !tokenVal.isNull() )
1135 setMetaData( QLatin1String(
"davLockToken") + lockCountStr, tokenVal.text() );
1143 if ( type == QLatin1String(
"dateTime.tz") )
1147 else if ( type == QLatin1String(
"dateTime.rfc1123") )
1162 if ( hasMetaData( QLatin1String(
"davLockCount") ) )
1164 QString response = QLatin1String(
"If:");
1165 int numLocks = metaData( QLatin1String(
"davLockCount") ).toInt();
1166 bool bracketsOpen =
false;
1167 for (
int i = 0; i < numLocks; i++ )
1169 const QString countStr = QString::number(i);
1170 if ( hasMetaData( QLatin1String(
"davLockToken") + countStr ) )
1172 if ( hasMetaData( QLatin1String(
"davLockURL") + countStr ) )
1176 response += QLatin1Char(
')');
1177 bracketsOpen =
false;
1179 response += QLatin1String(
" <") + metaData( QLatin1String(
"davLockURL") + countStr ) + QLatin1Char(
'>');
1182 if ( !bracketsOpen )
1184 response += QLatin1String(
" (");
1185 bracketsOpen =
true;
1189 response += QLatin1Char(
' ');
1192 if ( hasMetaData( QLatin1String(
"davLockNot") + countStr ) )
1193 response += QLatin1String(
"Not ");
1195 response += QLatin1Char(
'<') + metaData( QLatin1String(
"davLockToken") + countStr ) + QLatin1Char(
'>');
1200 response += QLatin1Char(
')');
1202 response += QLatin1String(
"\r\n");
1222 kDebug(7113) <<
" false";
1245 if (ok && verNo > 0 && verNo < 3)
1248 kDebug(7113) <<
"Server supports DAV version" << verNo;
1300 QString tmp(metaData(QLatin1String(
"cache")));
1320 if (!(flags & KIO::Overwrite)) {
1325 const QByteArray request (
"<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
1326 "<D:propfind xmlns:D=\"DAV:\"><D:prop>"
1328 "<D:getcontentlength/>"
1331 "</D:prop></D:propfind>");
1367 kDebug(7113) << src <<
"->" << dest;
1374 KUrl newDest = dest;
1375 if (newDest.
protocol() == QLatin1String(
"webdavs"))
1377 else if (newDest.
protocol() == QLatin1String(
"webdav"))
1397 kDebug(7113) << src <<
"->" << dest;
1404 KUrl newDest = dest;
1405 if (newDest.
protocol() == QLatin1String(
"webdavs"))
1407 else if (newDest.
protocol() == QLatin1String(
"webdav"))
1501 QDomDocument lockReq;
1503 QDomElement lockInfo = lockReq.createElementNS( QLatin1String(
"DAV:"), QLatin1String(
"lockinfo") );
1504 lockReq.appendChild( lockInfo );
1506 QDomElement lockScope = lockReq.createElement( QLatin1String(
"lockscope") );
1507 lockInfo.appendChild( lockScope );
1509 lockScope.appendChild( lockReq.createElement( scope ) );
1511 QDomElement lockType = lockReq.createElement( QLatin1String(
"locktype") );
1512 lockInfo.appendChild( lockType );
1514 lockType.appendChild( lockReq.createElement( type ) );
1516 if ( !owner.isNull() ) {
1517 QDomElement ownerElement = lockReq.createElement( QLatin1String(
"owner") );
1518 lockReq.appendChild( ownerElement );
1520 QDomElement ownerHref = lockReq.createElement( QLatin1String(
"href") );
1521 ownerElement.appendChild( ownerHref );
1523 ownerHref.appendChild( lockReq.createTextNode( owner ) );
1533 QDomDocument multiResponse;
1536 QDomElement prop = multiResponse.documentElement().namedItem( QLatin1String(
"prop") ).toElement();
1538 QDomElement lockdiscovery = prop.namedItem( QLatin1String(
"lockdiscovery") ).toElement();
1541 davParseActiveLocks( lockdiscovery.elementsByTagName( QLatin1String(
"activelock") ), lockCount );
1543 setMetaData( QLatin1String(
"davLockCount"), QString::number( lockCount ) );
1573 bool callError =
false;
1583 if ( !url.isNull() )
1590 QString ow =
i18n(
"Otherwise, the request would have succeeded." );
1594 action =
i18nc(
"request type",
"retrieve property values" );
1597 action =
i18nc(
"request type",
"set property values" );
1600 action =
i18nc(
"request type",
"create the requested folder" );
1603 action =
i18nc(
"request type",
"copy the specified file or folder" );
1606 action =
i18nc(
"request type",
"move the specified file or folder" );
1609 action =
i18nc(
"request type",
"search in the specified folder" );
1612 action =
i18nc(
"request type",
"lock the specified file or folder" );
1615 action =
i18nc(
"request type",
"unlock the specified file or folder" );
1618 action =
i18nc(
"request type",
"delete the specified file or folder" );
1621 action =
i18nc(
"request type",
"query the server's capabilities" );
1624 action =
i18nc(
"request type",
"retrieve the contents of the specified file or folder" );
1627 action =
i18nc(
"request type",
"run a report in the specified folder" );
1638 errorString =
i18nc(
"%1: code, %2: request type",
"An unexpected error (%1) occurred "
1639 "while attempting to %2.", code, action);
1646 errorString =
i18n(
"The server does not support the WebDAV protocol.");
1660 QDomDocument multiResponse;
1664 QDomElement multistatus = multiResponse.documentElement().namedItem( QLatin1String(
"multistatus") ).toElement();
1666 QDomNodeList responses = multistatus.elementsByTagName( QLatin1String(
"response") );
1668 for (
int i = 0; i < responses.count(); i++)
1673 QDomElement response = responses.item(i).toElement();
1674 QDomElement code = response.namedItem( QLatin1String(
"status") ).toElement();
1676 if ( !code.isNull() )
1679 QDomElement href = response.namedItem( QLatin1String(
"href") ).toElement();
1680 if ( !href.isNull() )
1681 errUrl = href.text();
1682 errors <<
davError( errCode, errUrl );
1687 errorString =
i18nc(
"%1: request type, %2: url",
1688 "An error occurred while attempting to %1, %2. A "
1689 "summary of the reasons is below.", action, url );
1691 errorString += QLatin1String(
"<ul>");
1694 errorString += QLatin1String(
"<li>") + error + QLatin1String(
"</li>");
1696 errorString += QLatin1String(
"</ul>");
1702 errorString =
i18nc(
"%1: request type",
"Access was denied while attempting to %1.", action );
1715 errorString =
i18n(
"A resource cannot be created at the destination "
1716 "until one or more intermediate collections (folders) "
1717 "have been created.");
1723 errorString =
i18n(
"The server was unable to maintain the liveness of "
1724 "the properties listed in the propertybehavior XML "
1725 "element or you attempted to overwrite a file while "
1726 "requesting that files are not overwritten. %1",
1731 errorString =
i18n(
"The requested lock could not be granted. %1", ow );
1737 errorString =
i18n(
"The server does not support the request type of the body.");
1742 errorString =
i18nc(
"%1: request type",
"Unable to %1 because the resource is locked.", action );
1746 errorString =
i18n(
"This action was prevented by another error.");
1752 errorString =
i18nc(
"%1: request type",
"Unable to %1 because the destination server refuses "
1753 "to accept the file or folder.", action );
1759 errorString =
i18n(
"The destination resource does not have sufficient space "
1760 "to record the state of the resource after the execution "
1771 error( errorCode, errorString );
1779 Q_ASSERT(errorString);
1782 errorString->clear();
1794 Q_ASSERT(errorString);
1798 errorString->clear();
1800 switch (responseCode) {
1809 && (responseCode < 200 || responseCode > 400)
1810 && responseCode != 404) {
1812 *errorString =
i18n(
"The resource cannot be deleted." );
1821 Q_ASSERT(errorString);
1827 switch (responseCode) {
1834 *errorString =
i18nc(
"%1: request type",
"Access was denied while attempting to %1.", action );
1840 *errorString =
i18n(
"A resource cannot be created at the destination "
1841 "until one or more intermediate collections (folders) "
1842 "have been created.");
1848 *errorString =
i18nc(
"%1: request type",
"Unable to %1 because the resource is locked.", action );
1854 *errorString =
i18nc(
"%1: request type",
"Unable to %1 because the destination server refuses "
1855 "to accept the file or folder.", action );
1861 *errorString =
i18n(
"The destination resource does not have sufficient space "
1862 "to record the state of the resource after the execution "
1871 && (responseCode < 200 || responseCode > 400)
1872 && responseCode != 404) {
1874 *errorString =
i18nc(
"%1: response code, %2: request type",
1875 "An unexpected error (%1) occurred while attempting to %2.",
1876 responseCode, action);
1903 infoMessage(QLatin1String(
""));
1906 error( errorCode, errorString );
1919 kWarning(7113) <<
"called twice during one request, something is probably wrong.";
1922 SlaveBase::errorPage();
1932 Solid::Networking::Status status = Solid::Networking::status();
1934 kDebug(7113) <<
"networkstatus:" << status;
1937 return status == Solid::Networking::Unconnected;
1942 QDataStream stream(data);
1954 for (
unsigned i = 0; i < n; ++i) {
1956 stream >> url >> mIncomingMetaData;
1969 QString tmp = metaData(QLatin1String(
"cache"));
1984 while (it.hasNext()) {
1996 while (it.hasNext()) {
2013 setMetaData(QLatin1String(
"request-id"), QString::number(requestId++));
2014 sendAndKeepMetaData();
2033 const char* buf =
static_cast<const char*
>(_buf);
2034 while (sent < nbytes)
2036 int n = TCPSlaveBase::write(buf + sent, nbytes - sent);
2061 for (
size_t i = 0; i < size; i++) {
2072 size_t bytesRead = 0;
2075 bytesRead = qMin((
int)size, bufSize);
2077 for (
size_t i = 0; i < bytesRead; i++) {
2078 buf[i] =
m_unreadBuf.constData()[bufSize - i - 1];
2089 if (bytesRead < size) {
2090 int rawRead = TCPSlaveBase::read(buf + bytesRead, size - bytesRead);
2095 bytesRead += rawRead;
2106 Q_ASSERT(numNewlines >=1 && numNewlines <= 2);
2109 while (pos < end && !
m_isEOF) {
2110 int step = qMin((
int)
sizeof(mybuf), end - pos);
2119 for (
size_t i = 0; i < bufferFill ; ++i, ++pos) {
2122 buf[pos] = mybuf[i];
2127 if (buf[pos] ==
'\n') {
2128 bool found = numNewlines == 1;
2131 found = ((pos >= 1 && buf[pos - 1] ==
'\n') ||
2132 (pos >= 2 && buf[pos - 2] ==
'\n' && buf[pos - 1] ==
'\r'));
2136 unread(&mybuf[i], bufferFill - i);
2149 if (previous.host() != now.host() || previous.port() != now.port()) {
2152 if (previous.
user().isEmpty() && previous.
pass().isEmpty()) {
2168 if (url != QLatin1String(
"DIRECT")) {
2187 disconnect(
socket(), SIGNAL(connected()),
2192 int connectError = 0;
2206 const KUrl url (proxyUrl);
2211 errorString = url.
url();
2215 const bool isDirectConnect = (proxyUrl == QLatin1String(
"DIRECT"));
2216 QNetworkProxy::ProxyType proxyType = QNetworkProxy::NoProxy;
2217 if (url.
protocol() == QLatin1String(
"socks")) {
2218 proxyType = QNetworkProxy::Socks5Proxy;
2219 }
else if (!isDirectConnect &&
isAutoSsl()) {
2220 proxyType = QNetworkProxy::HttpProxy;
2223 kDebug(7113) <<
"Connecting to proxy: address=" << proxyUrl <<
"type=" << proxyType;
2225 if (proxyType == QNetworkProxy::NoProxy) {
2228 if (isDirectConnect) {
2232 connectError =
connectToHost(url.host(), url.port(), &errorString);
2233 if (connectError == 0) {
2235 kDebug(7113) <<
"Connected to proxy: host=" << url.host() <<
"port=" << url.port();
2239 kDebug(7113) <<
"Failed to connect to proxy:" << proxyUrl;
2240 badProxyUrls << url;
2243 if (connectError == 0) {
2247 QNetworkProxy proxy (proxyType, url.host(), url.port(), url.
user(), url.
pass());
2248 QNetworkProxy::setApplicationProxy(proxy);
2250 if (connectError == 0) {
2251 kDebug(7113) <<
"Tunneling thru proxy: host=" << url.host() <<
"port=" << url.port();
2256 kDebug(7113) <<
"Failed to connect to proxy:" << proxyUrl;
2257 badProxyUrls << url;
2258 QNetworkProxy::setApplicationProxy(QNetworkProxy::NoProxy);
2263 if (!badProxyUrls.isEmpty()) {
2268 if (connectError != 0) {
2269 error (connectError, errorString);
2299 bool openForReading =
false;
2303 if (!openForReading && (isCacheOnly || offline)) {
2305 *cacheHasPage =
false;
2308 }
else if (offline) {
2315 if (openForReading) {
2317 *cacheHasPage =
true;
2322 *cacheHasPage =
false;
2335 if (protocol.startsWith(QLatin1String(
"webdav"))) {
2336 protocol.replace(0, qstrlen(
"webdav"), QLatin1String(
"http"));
2393 kDebug(7113) <<
"Couldn't connect, oopsie!";
2405 bool hasBodyData =
false;
2406 bool hasDavData =
false;
2416 bool cacheHasPage =
false;
2418 kDebug(7113) <<
"cacheHasPage =" << cacheHasPage;
2419 return cacheHasPage;
2421 if (!cacheHasPage) {
2438 davHeader = QLatin1String(
"Depth: ");
2439 if ( hasMetaData( QLatin1String(
"davDepth") ) )
2441 kDebug(7113) <<
"Reading DAV depth from metadata:" << metaData( QLatin1String(
"davDepth") );
2442 davHeader += metaData( QLatin1String(
"davDepth") );
2447 davHeader += QLatin1String(
"infinity");
2451 davHeader += QLatin1String(
"\r\n");
2463 davHeader += QLatin1String(
"\r\nDepth: infinity\r\nOverwrite: ");
2465 davHeader += QLatin1String(
"\r\n");
2468 davHeader = QLatin1String(
"Timeout: ");
2471 if ( hasMetaData( QLatin1String(
"davTimeout") ) )
2472 timeout = metaData( QLatin1String(
"davTimeout") ).toUInt();
2474 davHeader += QLatin1String(
"Infinite");
2476 davHeader += QLatin1String(
"Seconds-") + QString::number(timeout);
2478 davHeader += QLatin1String(
"\r\n");
2482 davHeader = QLatin1String(
"Lock-token: ") + metaData(QLatin1String(
"davLockToken")) + QLatin1String(
"\r\n");
2489 case DAV_UNSUBSCRIBE:
2503 header += QLatin1Char(
':') + QString::number(
m_request.
url.port());
2505 header += QLatin1String(
"\r\n");
2512 header += QLatin1String(
"Proxy-Connection: ");
2514 header += QLatin1String(
"Connection: ");
2517 header += QLatin1String(
"keep-alive\r\n");
2519 header += QLatin1String(
"close\r\n");
2524 header += QLatin1String(
"User-Agent: ");
2526 header += QLatin1String(
"\r\n");
2531 header += QLatin1String(
"Referer: ");
2533 header += QLatin1String(
"\r\n");
2538 header += QLatin1String(
"Range: bytes=");
2540 header += QLatin1Char(
'-');
2542 header += QLatin1String(
"\r\n");
2548 header += QLatin1String(
"Range: bytes=");
2550 header += QLatin1String(
"-\r\n");
2557 header += QLatin1String(
"Pragma: no-cache\r\n");
2558 header += QLatin1String(
"Cache-control: no-cache\r\n");
2562 kDebug(7113) <<
"needs validation, performing conditional get.";
2569 header += QLatin1String(
"If-Modified-Since: ") + httpDate + QLatin1String(
"\r\n");
2570 setMetaData(QLatin1String(
"modified"), httpDate);
2574 header += QLatin1String(
"Accept: ");
2575 const QString acceptHeader = metaData(QLatin1String(
"accept"));
2576 if (!acceptHeader.isEmpty())
2577 header += acceptHeader;
2580 header += QLatin1String(
"\r\n");
2583 header += QLatin1String(
"Accept-Encoding: gzip, deflate, x-gzip, x-deflate\r\n");
2586 header += QLatin1String(
"Accept-Charset: ") +
m_request.
charsets + QLatin1String(
"\r\n");
2589 header += QLatin1String(
"Accept-Language: ") +
m_request.
languages + QLatin1String(
"\r\n");
2592 const QString cookieMode = metaData(QLatin1String(
"cookies")).toLower();
2594 if (cookieMode == QLatin1String(
"none"))
2598 else if (cookieMode == QLatin1String(
"manual"))
2601 cookieStr = metaData(QLatin1String(
"setcookies"));
2610 if (!cookieStr.isEmpty())
2611 header += cookieStr + QLatin1String(
"\r\n");
2613 const QString customHeader = metaData( QLatin1String(
"customHTTPHeader") );
2614 if (!customHeader.isEmpty())
2617 header += QLatin1String(
"\r\n");
2620 const QString contentType = metaData(QLatin1String(
"content-type"));
2621 if (!contentType.isEmpty())
2623 if (!contentType.startsWith(QLatin1String(
"content-type"), Qt::CaseInsensitive))
2624 header += QLatin1String(
"Content-Type: ");
2625 header += contentType;
2626 header += QLatin1String(
"\r\n");
2631 header += QLatin1String(
"DNT: 1\r\n");
2644 davHeader += metaData(QLatin1String(
"davHeader"));
2648 davHeader += QLatin1String(
"Content-Type: text/xml; charset=utf-8\r\n");
2651 header += davHeader;
2655 kDebug(7103) <<
"============ Sending Header:";
2656 Q_FOREACH (
const QString &s, header.split(QLatin1String(
"\r\n"), QString::SkipEmptyParts)) {
2662 if (!hasBodyData && !hasDavData)
2663 header += QLatin1String(
"\r\n");
2672 ssize_t written =
write(header.toLatin1(), header.length());
2673 bool sendOk = (written == (ssize_t) header.length());
2677 <<
" -- intended to write" << header.length()
2678 <<
"bytes but wrote" << (int)written <<
".";
2688 kDebug(7113) <<
"sendOk == false. Connection broken !"
2689 <<
" -- intended to write" << header.length()
2690 <<
"bytes but wrote" << (int)written <<
".";
2695 kDebug(7113) <<
"sent it!";
2698 if (hasBodyData || hasDavData)
2701 infoMessage(
i18n(
"%1 contacted. Waiting for reply...",
m_request.
url.host()));
2714 if (forwardImmediately)
2727 if (header.startsWith(QLatin1String(
"content-type:"), Qt::CaseInsensitive)) {
2728 int pos = header.indexOf(QLatin1String(
"charset="), Qt::CaseInsensitive);
2730 const QString charset = header.mid(pos + 8).toLower();
2732 setMetaData(QLatin1String(
"charset"), charset);
2734 }
else if (header.startsWith(QLatin1String(
"content-language:"), Qt::CaseInsensitive)) {
2735 const QString language = header.mid(17).trimmed().toLower();
2736 setMetaData(QLatin1String(
"content-language"), language);
2737 }
else if (header.startsWith(QLatin1String(
"content-disposition:"), Qt::CaseInsensitive)) {
2764 if (
m_mimeType == QLatin1String(
"application/x-targz"))
2765 m_mimeType = QLatin1String(
"application/x-compressed-tar");
2766 else if (
m_mimeType == QLatin1String(
"image/x-png"))
2770 else if (
m_mimeType == QLatin1String(
"audio/microsoft-wave"))
2772 else if (
m_mimeType == QLatin1String(
"image/x-ms-bmp"))
2776 else if (
m_mimeType == QLatin1String(
"application/pkix-cert") ||
2777 m_mimeType == QLatin1String(
"application/binary-certificate")) {
2778 m_mimeType = QLatin1String(
"application/x-x509-ca-cert");
2782 else if (
m_mimeType == QLatin1String(
"application/x-gzip")) {
2785 m_mimeType = QLatin1String(
"application/x-compressed-tar");
2787 m_mimeType = QLatin1String(
"application/x-gzpostscript");
2792 else if(
m_mimeType == QLatin1String(
"application/x-xz")) {
2795 m_mimeType = QLatin1String(
"application/x-xz-compressed-tar");
2800 else if ((
m_mimeType == QLatin1String(
"text/plain")) || (
m_mimeType == QLatin1String(
"application/octet-stream"))) {
2802 if (ext == QLatin1String(
"BZ2"))
2803 m_mimeType = QLatin1String(
"application/x-bzip");
2804 else if (ext == QLatin1String(
"PEM"))
2805 m_mimeType = QLatin1String(
"application/x-x509-ca-cert");
2806 else if (ext == QLatin1String(
"SWF"))
2807 m_mimeType = QLatin1String(
"application/x-shockwave-flash");
2808 else if (ext == QLatin1String(
"PLS"))
2810 else if (ext == QLatin1String(
"WMV"))
2811 m_mimeType = QLatin1String(
"video/x-ms-wmv");
2812 else if (ext == QLatin1String(
"WEBM"))
2814 else if (ext == QLatin1String(
"DEB"))
2815 m_mimeType = QLatin1String(
"application/x-deb");
2829 if (
m_mimeType == QLatin1String(
"application/x-tar")) {
2831 m_mimeType = QLatin1String(
"application/x-compressed-tar");
2832 }
else if (
m_mimeType == QLatin1String(
"application/postscript")) {
2836 m_mimeType = QLatin1String(
"application/x-gzpostscript");
2841 m_mimeType != QLatin1String(
"application/x-compressed-tar") &&
2842 m_mimeType != QLatin1String(
"application/x-tgz") &&
2843 m_mimeType != QLatin1String(
"application/x-targz") &&
2844 m_mimeType != QLatin1String(
"application/x-gzip"))) {
2848 m_mimeType = QLatin1String(
"application/x-gzip");
2860 m_mimeType = QLatin1String(
"application/x-bzip");
2867 static bool consume(
const char input[],
int *pos,
int end,
const char *term)
2871 if (idx + (
int)strlen(term) >= end) {
2875 if (strncasecmp(&input[idx], term, strlen(term)) == 0) {
2876 *pos = idx + strlen(term);
2900 bool upgradeRequired =
false;
2904 bool noHeadersFound =
false;
2909 static const int maxHeaderSize = 128 * 1024;
2911 char buffer[maxHeaderSize];
2913 bool bCanResume =
false;
2916 kDebug(7113) <<
"No connection.";
2926 kDebug(7113) <<
"Got socket error:" <<
socket()->errorString();
2935 if (!foundDelimiter && bufPos < maxHeaderSize) {
2936 kDebug(7113) <<
"EOF while waiting for header start.";
2953 kDebug(7113) <<
"Connection broken !";
2957 if (!foundDelimiter) {
2962 kDebug(7103) <<
"============ Received Status Response:";
2963 kDebug(7103) << QByteArray(buffer, bufPos).trimmed();
2968 if (idx != bufPos && buffer[idx] ==
'<') {
2969 kDebug(7103) <<
"No valid HTTP header found! Document starts with XML/HTML tag";
2975 noHeadersFound =
true;
2982 if (
consume(buffer, &idx, bufPos,
"ICY ")) {
2985 }
else if (
consume(buffer, &idx, bufPos,
"HTTP/")) {
2986 if (
consume(buffer, &idx, bufPos,
"1.0")) {
2989 }
else if (
consume(buffer, &idx, bufPos,
"1.1")) {
2994 if (httpRev ==
HTTP_None && bufPos != 0) {
2997 kDebug(7113) <<
"DO NOT WANT." << bufPos;
3005 noHeadersFound =
true;
3016 if (idx != bufPos) {
3032 messageBox(WarningYesNo,
3033 i18nc(
"@info Security check on url being accessed",
3034 "<p>You are about to log in to the site \"%1\" "
3035 "with the username \"%2\", but the website "
3036 "does not require authentication. "
3037 "This may be an attempt to trick you.</p>"
3038 "<p>Is \"%1\" the site you want to visit?</p>",
3040 i18nc(
"@title:window",
"Confirm Website Access"));
3045 setMetaData(QLatin1String(
"{internal~currenthost}LastSpoofedUserName"),
m_request.
url.
user());
3069 upgradeRequired =
true;
3083 setMetaData(QLatin1String(
"permanent-redirect"), QLatin1String(
"true"));
3117 infoMessage(
i18n(
"Server processing request, please wait..." ) );
3125 bool authRequiresAnotherRoundtrip =
false;
3128 if (!noHeadersFound) {
3133 kDebug(7113) <<
"wasAuthError=" << wasAuthError <<
"isAuthError=" << isAuthError
3134 <<
"sameAuthError=" << sameAuthError;
3146 kDebug(7113) <<
" -- full response:" << endl << QByteArray(buffer, bufPos).trimmed();
3149 Q_ASSERT(foundDelimiter);
3156 tokenizer.
tokenize(idx,
sizeof(buffer));
3161 if (tIt.
hasNext() && tIt.
next().toLower().startsWith(
"none")) {
3165 tIt = tokenizer.iterator(
"keep-alive");
3167 QByteArray ka = tIt.
next().trimmed().toLower();
3168 if (ka.startsWith(
"timeout=")) {
3169 int ka_timeout = ka.mid(qstrlen(
"timeout=")).trimmed().toInt();
3181 tIt = tokenizer.iterator(
"content-length");
3186 tIt = tokenizer.iterator(
"content-location");
3188 setMetaData(QLatin1String(
"content-location"),
toQString(tIt.
next().trimmed()));
3194 tIt = tokenizer.iterator(
"content-type");
3200 if (
m_mimeType.startsWith(QLatin1Char(
'"'))) {
3212 Q_FOREACH (
const QByteArray &statement, l) {
3213 const int index = statement.indexOf(
'=');
3215 mediaAttribute =
toQString(statement.mid(0, index));
3217 mediaAttribute =
toQString(statement.mid(0, index));
3218 mediaValue =
toQString(statement.mid(index+1));
3220 mediaAttribute = mediaAttribute.trimmed();
3221 mediaValue = mediaValue.trimmed();
3223 bool quoted =
false;
3224 if (mediaValue.startsWith(QLatin1Char(
'"'))) {
3226 mediaValue.remove(0, 1);
3229 if (mediaValue.endsWith(QLatin1Char(
'"'))) {
3233 kDebug (7113) <<
"Encoding-type:" << mediaAttribute <<
"=" << mediaValue;
3235 if (mediaAttribute == QLatin1String(
"charset")) {
3236 mediaValue = mediaValue.toLower();
3238 setMetaData(QLatin1String(
"charset"), mediaValue);
3240 setMetaData(QLatin1String(
"media-") + mediaAttribute, mediaValue);
3242 setMetaData(QLatin1String(
"media-") + mediaAttribute + QLatin1String(
"-kio-quoted"),
3243 QLatin1String(
"true"));
3250 tIt = tokenizer.iterator(
"content-encoding");
3268 tIt = tokenizer.iterator(
"content-disposition");
3272 tIt = tokenizer.iterator(
"content-language");
3275 if (!language.isEmpty()) {
3276 setMetaData(QLatin1String(
"content-language"), language);
3280 tIt = tokenizer.iterator(
"proxy-connection");
3282 QByteArray pc = tIt.
next().toLower();
3283 if (pc.startsWith(
"close")) {
3285 }
else if (pc.startsWith(
"keep-alive")) {
3290 tIt = tokenizer.iterator(
"link");
3294 if (link.count() == 2) {
3295 QString rel = link[1].trimmed();
3296 if (rel.startsWith(QLatin1String(
"rel=\""))) {
3297 rel = rel.mid(5, rel.length() - 6);
3298 if (rel.toLower() == QLatin1String(
"pageservices")) {
3300 QString url = link[0].remove(QRegExp(QLatin1String(
"[<>]"))).trimmed();
3301 setMetaData(QLatin1String(
"PageServices"), url);
3307 tIt = tokenizer.iterator(
"p3p");
3313 .split(QLatin1Char(
'='), QString::SkipEmptyParts);
3314 if (policy.count() == 2) {
3315 if (policy[0].toLower() == QLatin1String(
"policyref")) {
3316 policyrefs << policy[1].remove(QRegExp(QLatin1String(
"[\")\']"))).trimmed();
3317 }
else if (policy[0].toLower() == QLatin1String(
"cp")) {
3321 const QString s = policy[1].remove(QRegExp(QLatin1String(
"[\")\']")));
3322 const QStringList cps = s.split(QLatin1Char(
' '), QString::SkipEmptyParts);
3327 if (!policyrefs.isEmpty()) {
3328 setMetaData(QLatin1String(
"PrivacyPolicy"), policyrefs.join(QLatin1String(
"\n")));
3330 if (!compact.isEmpty()) {
3331 setMetaData(QLatin1String(
"PrivacyCompactPolicy"), compact.join(QLatin1String(
"\n")));
3338 tIt = tokenizer.iterator(
"connection");
3340 QByteArray connection = tIt.
next().toLower();
3342 if (connection.startsWith(
"close")) {
3344 }
else if (connection.startsWith(
"keep-alive")) {
3348 if (connection.startsWith(
"upgrade")) {
3351 upgradeRequired =
true;
3352 }
else if (upgradeRequired) {
3358 tIt = tokenizer.iterator(
"transfer-encoding");
3367 tIt = tokenizer.iterator(
"content-md5");
3374 tIt = tokenizer.iterator(
"dav");
3384 tIt = tokenizer.iterator(
"upgrade");
3388 upgradeOffers = offered.split(QRegExp(QLatin1String(
"[ \n,\r\t]")), QString::SkipEmptyParts);
3390 Q_FOREACH (
const QString &opt, upgradeOffers) {
3391 if (opt == QLatin1String(
"TLS/1.0")) {
3392 if (!
startSsl() && upgradeRequired) {
3396 }
else if (opt == QLatin1String(
"HTTP/1.1")) {
3398 }
else if (upgradeRequired) {
3406 QByteArray cookieStr;
3407 tIt = tokenizer.iterator(
"set-cookie");
3409 cookieStr +=
"Set-Cookie: ";
3410 cookieStr += tIt.
next();
3413 if (!cookieStr.isEmpty()) {
3418 cookieStr =
"Cross-Domain\n" + cookieStr;
3423 setMetaData(QLatin1String(
"setcookies"), QString::fromUtf8(cookieStr));
3431 kDebug(7113) <<
"cont; returning to mark try_again";
3437 kDebug(7113) <<
"Ignoring keep-alive: otherwise unable to determine response body length.";
3452 authRequiresAnotherRoundtrip =
false;
3457 tIt = tokenizer.iterator(
"location");
3459 locationStr = QString::fromUtf8(tIt.
next().trimmed());
3462 if (!locationStr.isEmpty())
3489 if(u.
protocol() == QLatin1String(
"http")){
3491 }
else if(u.
protocol() == QLatin1String(
"https")){
3531 kDebug(7113) <<
"Reading resource from cache even though the cache plan is not "
3532 "UseCached; the server is probably sending wrong expiry information.";
3542 int nextLinePos = 0;
3543 int prevLinePos = 0;
3544 bool haveMore =
true;
3546 haveMore =
nextLine(buffer, &nextLinePos, bufPos);
3547 int prevLineEnd = nextLinePos;
3548 while (buffer[prevLineEnd - 1] ==
'\r' || buffer[prevLineEnd - 1] ==
'\n') {
3553 prevLineEnd - prevLinePos));
3554 prevLinePos = nextLinePos;
3581 return !authRequiresAnotherRoundtrip;
3589 while (i != parameters.constEnd()) {
3590 setMetaData(QLatin1String(
"content-disposition-") + i.key(), i.value());
3591 kDebug(7113) <<
"Content-Disposition:" << i.key() <<
"=" << i.value();
3598 QString encoding = _encoding.trimmed().toLower();
3600 if (encoding == QLatin1String(
"identity")) {
3602 }
else if (encoding == QLatin1String(
"8bit")) {
3605 }
else if (encoding == QLatin1String(
"chunked")) {
3610 }
else if ((encoding == QLatin1String(
"x-gzip")) || (encoding == QLatin1String(
"gzip"))) {
3611 encs.append(QLatin1String(
"gzip"));
3612 }
else if ((encoding == QLatin1String(
"x-bzip2")) || (encoding == QLatin1String(
"bzip2"))) {
3613 encs.append(QLatin1String(
"bzip2"));
3614 }
else if ((encoding == QLatin1String(
"x-deflate")) || (encoding == QLatin1String(
"deflate"))) {
3615 encs.append(QLatin1String(
"deflate"));
3617 kDebug(7113) <<
"Unknown encoding encountered. "
3618 <<
"Please write code. Encoding =" << encoding;
3637 const qint64 currentDate = time(0);
3654 tIt = tokenizer.iterator(
"date");
3661 tIt = tokenizer.iterator(
"age");
3663 ageHeader = tIt.
next().toLongLong();
3667 if (dateHeader != -1) {
3669 }
else if (ageHeader) {
3676 bool hasCacheDirective =
false;
3681 tIt = tokenizer.iterator(
"cache-control");
3683 QByteArray cacheStr = tIt.
next().toLower();
3684 if (cacheStr.startsWith(
"no-cache") || cacheStr.startsWith(
"no-store")) {
3687 hasCacheDirective =
true;
3688 }
else if (cacheStr.startsWith(
"max-age=")) {
3689 QByteArray ba = cacheStr.mid(qstrlen(
"max-age=")).trimmed();
3691 maxAgeHeader = ba.toLongLong(&ok);
3693 hasCacheDirective =
true;
3698 qint64 expiresHeader = -1;
3699 tIt = tokenizer.iterator(
"expires");
3702 kDebug(7113) <<
"parsed expire date from 'expires' header:" << tIt.
current();
3707 }
else if (expiresHeader != -1) {
3716 expAge = qMin(expAge,
qint64(3600 * 24));
3729 tIt = tokenizer.iterator(
"etag");
3734 kDebug(7103) <<
"304 Not Modified but new entity tag - I don't think this is legal HTTP.";
3739 tIt = tokenizer.iterator(
"warning");
3747 tIt = tokenizer.iterator(
"pragma");
3749 if (tIt.
next().toLower().startsWith(
"no-cache")) {
3751 hasCacheDirective =
true;
3756 tIt = tokenizer.iterator(
"refresh");
3759 setMetaData(QLatin1String(
"http-refresh"),
toQString(tIt.
next().trimmed()));
3763 if (
m_mimeType.startsWith(QLatin1String(
"text/")) && (
m_mimeType != QLatin1String(
"text/css")) &&
3764 (
m_mimeType != QLatin1String(
"text/x-javascript")) && !hasCacheDirective) {
3775 kDebug(7113) <<
"Cache needs validation";
3777 kDebug(7113) <<
"...was revalidated by response code but not by updated expire times. "
3778 "We're going to set the expire date to 60 seconds in the future...";
3784 kDebug(7113) <<
"this proxy or server apparently sends bogus expiry information.";
3801 kDebug(7113) <<
"This webserver is confused about the cacheability of the data it sends.";
3815 if (!cachingAllowed) {
3816 setMetaData(QLatin1String(
"no-cache"), QLatin1String(
"true"));
3817 setMetaData(QLatin1String(
"expire-date"), QLatin1String(
"1"));
3821 setMetaData(QLatin1String(
"expire-date"), tmp);
3824 setMetaData(QLatin1String(
"cache-creation-date"), tmp);
3832 QByteArray cLength (
"Content-Length: ");
3833 cLength += QByteArray::number(
m_POSTbuf->size());
3834 cLength +=
"\r\n\r\n";
3836 kDebug(7113) <<
"sending cached data (size=" <<
m_POSTbuf->size() <<
")";
3839 bool sendOk = (
write(cLength.data(), cLength.size()) == (ssize_t) cLength.size());
3841 kDebug( 7113 ) <<
"Connection broken when sending "
3853 sendOk = (
write(buffer.data(), buffer.size()) == (ssize_t) buffer.size());
3855 kDebug(7113) <<
"Connection broken when sending message body: ("
3886 QByteArray cLength (
"Content-Length: ");
3888 cLength +=
"\r\n\r\n";
3890 kDebug(7113) << cLength.trimmed();
3893 bool sendOk = (
write(cLength.data(), cLength.size()) == (ssize_t) cLength.size());
3903 kDebug(7113) <<
"Connection broken while sending POST content size to" <<
m_request.
url.host();
3916 KIO::filesize_t bytesSent = 0;
3922 const int bytesRead = readData(buffer);
3925 if (bytesRead == 0) {
3931 if (bytesRead < 0) {
3945 if (
write(buffer.data(), bytesRead) == static_cast<ssize_t>(bytesRead)) {
3946 bytesSent += bytesRead;
3947 processedSize(bytesSent);
3951 kDebug(7113) <<
"Connection broken while sending POST content to" <<
m_request.
url.host();
3961 kDebug(7113) <<
"keepAlive =" << keepAlive;
3977 QDataStream stream( &data, QIODevice::WriteOnly );
3999 setTimeoutSpecialCommand(-1);
4036 QDataStream stream(data);
4044 stream >> url >> size;
4053 stream >> url >> no_cache >> expireDate;
4059 QFile::remove(filename);
4080 stream >> url >> scope >> type >> owner;
4081 davLock( url, scope, type, owner );
4096 stream >> url >> method >> size;
4097 davGeneric( url, (KIO::HTTP_METHOD) method, size );
4126 if (foundCrLf && bufPos == 2) {
4133 kDebug(7113) <<
"Failed to read chunk header.";
4136 Q_ASSERT(bufPos > 2);
4139 if (nextChunkSize < 0)
4141 kDebug(7113) <<
"Negative chunk size";
4158 int trashBufPos = 2;
4161 if (trashBufPos > 3) {
4163 for (
int i = 0; i < 3; i++) {
4164 trash[i] = trash[trashBufPos - 3 + i];
4171 kDebug(7113) <<
"Failed to read chunk trailer.";
4183 return bytesReceived;
4201 if (bytesReceived <= 0)
4205 return bytesReceived;
4212 kDebug(7113) <<
"Unbounded datastream on a Keep-alive connection!";
4252 kDebug(7113) <<
"Determining mime-type from content...";
4266 if( mime && !mime->isDefault() )
4347 if ( !dataInternal ) {
4350 infoMessage(
i18n(
"Retrieving %1 from %2...", KIO::convertSize(
m_iSize),
4358 kDebug(7113) <<
"reading data from cache...";
4370 if (!dataInternal) {
4377 if (!dataInternal) {
4405 QObject::connect(&chain, SIGNAL(
output(QByteArray)),
4415 if ( enc == QLatin1String(
"gzip") )
4417 else if ( enc == QLatin1String(
"deflate") )
4445 if ( enc == QLatin1String(
"gzip") )
4447 else if ( enc == QLatin1String(
"deflate") )
4466 if (bytesReceived == -1)
4476 kDebug(7113) <<
"bytesReceived==-1 sz=" << (int)sz
4477 <<
" Connection broken !";
4484 if (bytesReceived > 0)
4495 sz += bytesReceived;
4497 processedSize( sz );
4521 kWarning(7113) <<
"MD5 checksum MISMATCH! Expected:"
4530 if (!dataInternal && sz <= 1)
4543 data( QByteArray() );
4550 error(KIO::ERR_SLAVE_DEFINED, text);
4571 SlaveBase::error( _err, _text );
4579 QDBusInterface kcookiejar( QLatin1String(
"org.kde.kded"), QLatin1String(
"/modules/kcookiejar"), QLatin1String(
"org.kde.KCookieServer") );
4580 (void)kcookiejar.call( QDBus::NoBlock, QLatin1String(
"addCookies"), url,
4581 cookieHeader, windowId );
4587 QDBusInterface kcookiejar( QLatin1String(
"org.kde.kded"), QLatin1String(
"/modules/kcookiejar"), QLatin1String(
"org.kde.KCookieServer") );
4588 QDBusReply<QString> reply = kcookiejar.call( QLatin1String(
"findCookies"), url, windowId );
4590 if ( !reply.isValid() )
4592 kWarning(7113) <<
"Can't communicate with kded_kcookiejar!";
4604 case KIO::CC_Refresh:
4611 case KIO::CC_Reload:
4613 case KIO::CC_CacheOnly:
4621 time_t currentDate = time(0);
4634 struct BinaryCacheFileHeader
4646 static const int size = 36;
4658 BinaryCacheFileHeader
header;
4667 QDataStream stream(&ret, QIODevice::WriteOnly);
4668 stream << quint8(
'A');
4669 stream << quint8(
'\n');
4670 stream << quint8(0);
4671 stream << quint8(0);
4673 stream << fileUseCount;
4676 stream <<
qint64(servedDate);
4677 stream << qint64(lastModifiedDate);
4678 stream << qint64(expireDate);
4680 stream << bytesCached;
4681 Q_ASSERT(ret.size() == BinaryCacheFileHeader::size);
4690 return byte == value;
4693 static bool readTime(QDataStream *stream, time_t *time)
4697 *time =
static_cast<time_t
>(intTime);
4700 return check == intTime;
4709 if (d.size() != BinaryCacheFileHeader::size) {
4712 QDataStream stream(d);
4713 stream.setVersion(QDataStream::Qt_4_5);
4724 stream >> fileUseCount;
4727 ok = ok &&
readTime(&stream, &servedDate);
4728 ok = ok &&
readTime(&stream, &lastModifiedDate);
4729 ok = ok &&
readTime(&stream, &expireDate);
4734 stream >> bytesCached;
4759 static const char linefeed =
'\n';
4761 dev->write(&linefeed, 1);
4768 Q_ASSERT(file->openMode() & QIODevice::WriteOnly);
4770 file->seek(BinaryCacheFileHeader::size);
4784 if (line->isEmpty() || !line->endsWith(
'\n')) {
4796 Q_ASSERT(file->openMode() == QIODevice::ReadOnly);
4800 if (
storableUrl(desiredUrl).toEncoded() != readBuf) {
4801 kDebug(7103) <<
"You have witnessed a very improbable hash collision!";
4815 Q_ASSERT(file->openMode() == QIODevice::ReadOnly);
4821 qint64 oldPos = file->pos();
4822 file->seek(BinaryCacheFileHeader::size);
4825 Q_ASSERT(file->pos() == oldPos);
4834 if (ok && !readBuf.isEmpty()) {
4845 QCryptographicHash hash(QCryptographicHash::Sha1);
4847 return toQString(hash.result().toHex());
4853 if (!filePath.endsWith(QLatin1Char(
'/'))) {
4854 filePath.append(QLatin1Char(
'/'));
4867 kDebug(7113) <<
"File unexpectedly open; old file is" << file->fileName()
4868 <<
"new name is" << filename;
4869 Q_ASSERT(file->fileName() == filename);
4872 file =
new QFile(filename);
4873 if (file->open(QIODevice::ReadOnly)) {
4874 QByteArray
header = file->read(BinaryCacheFileHeader::size);
4876 kDebug(7103) <<
"Cache file header is invalid.";
4886 if (!file->isOpen()) {
4904 Q_ASSERT(!qobject_cast<QTemporaryFile *>(file));
4905 Q_ASSERT((file->openMode() & QIODevice::WriteOnly) == 0);
4906 Q_ASSERT(file->fileName() == filename);
4907 kDebug(7113) <<
"deleting expired cache entry and recreating.";
4915 file->open(QIODevice::WriteOnly);
4921 if ((file->openMode() & QIODevice::WriteOnly) == 0) {
4922 kDebug(7113) <<
"Could not open file for writing:" << file->fileName()
4923 <<
"due to error" << file->error();
4934 QDataStream stream(&ret, QIODevice::WriteOnly);
4935 stream.setVersion(QDataStream::Qt_4_5);
4937 stream.skipRawData(BinaryCacheFileHeader::size);
4942 int basenameStart = fileName.lastIndexOf(QLatin1Char(
'/')) + 1;
4944 stream.writeRawData(baseName.constData(), baseName.size());
4946 Q_ASSERT(ret.size() == BinaryCacheFileHeader::size +
sizeof(quint32) +
s_hashedUrlNibbles);
4962 QByteArray ccCommand;
4965 if (file->openMode() & QIODevice::WriteOnly) {
4971 tempFile->write(header);
4975 QString oldName = tempFile->fileName();
4977 int basenameStart = newName.lastIndexOf(QLatin1Char(
'/')) + 1;
4980 kDebug(7113) <<
"Renaming temporary file" << oldName <<
"to" << newName;
4983 tempFile->setAutoRemove(
false);
4987 if (!QFile::rename(oldName, newName)) {
4990 kDebug(7113) <<
"Renaming temporary file failed, deleting it instead.";
4991 QFile::remove(oldName);
4998 }
else if (file->openMode() == QIODevice::ReadOnly) {
4999 Q_ASSERT(!tempFile);
5005 if (!ccCommand.isEmpty()) {
5016 if (attempts == 2) {
5030 kDebug(7113) <<
"Could not connect to cache cleaner, not updating stats of this cache file.";
5040 if (ret.isEmpty()) {
5057 kDebug(7113) <<
"Caching disabled because content size is too big.";
5087 m_POSTbuf->write (data.constData(), data.size());
5113 const int bytesRead = readData(buffer);
5115 if (bytesRead < 0) {
5120 if (bytesRead == 0) {
5124 m_POSTbuf->write(buffer.constData(), buffer.size());
5152 if (useCachedAuth && checkCachedAuthentication(authinfo)) {
5153 const QByteArray cachedChallenge =
config()->readEntry(
"www-auth-challenge", QByteArray());
5154 if (!cachedChallenge.isEmpty()) {
5157 kDebug(7113) <<
"creating www authentcation header from cached info";
5175 if (checkCachedAuthentication(authinfo)) {
5176 const QByteArray cachedChallenge =
config()->readEntry(
"proxy-auth-challenge", QByteArray());
5177 if (!cachedChallenge.isEmpty()) {
5180 kDebug(7113) <<
"creating proxy authentcation header from cached info";
5190 ret +=
"Authorization: ";
5195 ret +=
"Proxy-Authorization: ";
5205 case QNetworkProxy::DefaultProxy:
5207 case QNetworkProxy::Socks5Proxy:
5208 return QLatin1String(
"socks");
5209 case QNetworkProxy::NoProxy:
5211 case QNetworkProxy::HttpProxy:
5212 case QNetworkProxy::HttpCachingProxy:
5213 case QNetworkProxy::FtpCachingProxy:
5218 return QLatin1String(
"http");
5223 kDebug(7113) <<
"realm:" << authenticator->realm() <<
"user:" << authenticator->user();
5234 info.
username = authenticator->user();
5237 const bool haveCachedCredentials = checkCachedAuthentication(info);
5242 if (!haveCachedCredentials || retryAuth) {
5245 connect(
socket(), SIGNAL(connected()),
5248 info.
prompt =
i18n(
"You need to supply a username and a password for "
5249 "the proxy server listed below before you are allowed "
5250 "to access any sites.");
5255 const QString errMsg ((retryAuth ?
i18n(
"Proxy Authentication Failed.") :
QString()));
5257 if (!openPasswordDialog(info, errMsg)) {
5258 kDebug(7113) <<
"looks like the user canceled proxy authentication.";
5265 authenticator->setUser(info.
username);
5266 authenticator->setPassword(info.
password);
5267 authenticator->setOption(QLatin1String(
"keepalive"), info.
keepPassword);
5282 kDebug(7113) <<
"Saving authenticator";
5283 disconnect(
socket(), SIGNAL(connected()),
5295 cacheAuthentication(a);
5304 bool alreadyCached =
false;
5309 alreadyCached =
config()->readEntry(
"cached-www-auth",
false);
5313 alreadyCached =
config()->readEntry(
"cached-proxy-auth",
false);
5320 if (auth && (!auth->
realm().isEmpty() || !alreadyCached)) {
5323 setMetaData(QLatin1String(
"{internal~currenthost}cached-www-auth"), QLatin1String(
"true"));
5325 setMetaData(QLatin1String(
"{internal~currenthost}www-auth-realm"), authinfo.
realmValue);
5327 setMetaData(QLatin1String(
"{internal~currenthost}www-auth-challenge"), authinfo.
digestInfo);
5329 setMetaData(QLatin1String(
"{internal~allhosts}cached-proxy-auth"), QLatin1String(
"true"));
5331 setMetaData(QLatin1String(
"{internal~allhosts}proxy-auth-realm"), authinfo.
realmValue);
5333 setMetaData(QLatin1String(
"{internal~allhosts}proxy-auth-challenge"), authinfo.
digestInfo);
5339 cacheAuthentication(authinfo);
5355 authTokens = tokenizer->iterator(
"www-authenticate").all();
5358 authinfo.
prompt =
i18n(
"You need to supply a username and a "
5359 "password to access this site.");
5365 Q_ASSERT(QNetworkProxy::applicationProxy().type() == QNetworkProxy::NoProxy);
5367 authTokens = tokenizer->iterator(
"proxy-authenticate").all();
5370 authinfo.
prompt =
i18n(
"You need to supply a username and a password for "
5371 "the proxy server listed below before you are allowed "
5372 "to access any sites." );
5376 bool authRequiresAnotherRoundtrip =
false;
5381 if (!authTokens.isEmpty()) {
5383 authRequiresAnotherRoundtrip =
true;
5387 if ((*auth)->wasFinalStage()) {
5389 i18n(
"Authentication Failed.") :
5390 i18n(
"Proxy Authentication Failed."));
5398 QMutableListIterator<QByteArray> it (authTokens);
5399 const QByteArray authScheme ((*auth)->scheme().trimmed());
5400 while (it.hasNext()) {
5401 if (qstrnicmp(authScheme.constData(), it.next().constData(), authScheme.length()) != 0) {
5408 try_next_auth_scheme:
5411 const QByteArray authScheme ((*auth)->scheme().trimmed());
5412 if (qstrnicmp(authScheme.constData(), bestOffer.constData(), authScheme.length()) != 0) {
5424 kDebug(7113) <<
"Trying authentication scheme:" << (*auth)->scheme();
5430 bool generateAuthHeader =
true;
5431 if ((*auth)->needCredentials()) {
5442 if (authinfo.
realmValue.isEmpty() && !(*auth)->supportsPathMatching())
5443 authinfo.
realmValue = QLatin1String((*auth)->scheme());
5448 const KUrl reqUrl = authinfo.
url;
5449 if (!errorMsg.isEmpty() || !checkCachedAuthentication(authinfo)) {
5451 authinfo.
url = reqUrl;
5456 if (!openPasswordDialog(authinfo, errorMsg)) {
5457 generateAuthHeader =
false;
5458 authRequiresAnotherRoundtrip =
false;
5462 kDebug(7113) <<
"looks like the user canceled the authentication dialog";
5472 if (generateAuthHeader) {
5473 (*auth)->generateResponse(username, password);
5474 (*auth)->setCachePasswordEnabled(authinfo.
keepPassword);
5476 kDebug(7113) <<
"isError=" << (*auth)->isError()
5477 <<
"needCredentials=" << (*auth)->needCredentials()
5478 <<
"forceKeepAlive=" << (*auth)->forceKeepAlive()
5479 <<
"forceDisconnect=" << (*auth)->forceDisconnect();
5481 if ((*auth)->isError()) {
5482 authTokens.removeOne(bestOffer);
5483 if (!authTokens.isEmpty()) {
5484 goto try_next_auth_scheme;
5487 authRequiresAnotherRoundtrip =
false;
5490 }
else if ((*auth)->forceKeepAlive()) {
5493 }
else if ((*auth)->forceDisconnect()) {
5500 authRequiresAnotherRoundtrip =
false;
5507 return authRequiresAnotherRoundtrip;