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)
397 , m_iEOFRetryCount(0)
401 connect(
socket(), SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
421 TCPSlaveBase::reparseConfiguration();
449 setMetaData(QLatin1String(
"request-id"),
m_request.
id);
464 const bool noAuth =
config()->readEntry(
"no-auth",
false);
474 kDebug(7113) <<
"ssl_was_in_use =" << metaData(QLatin1String(
"ssl_was_in_use"));
482 KUrl refUrl(metaData(QLatin1String(
"referrer")));
483 if (refUrl.isValid()) {
486 if (protocol.startsWith(QLatin1String(
"webdav"))) {
487 protocol.replace(0, 6, QLatin1String(
"http"));
491 if (protocol.startsWith(QLatin1String(
"http"))) {
497 if (
config()->readEntry(
"SendLanguageSettings",
true)) {
509 QString resumeOffset = metaData(QLatin1String(
"resume"));
510 if (!resumeOffset.isEmpty()) {
516 QString resumeEndOffset = metaData(QLatin1String(
"resume_until"));
517 if (!resumeEndOffset.isEmpty()) {
525 m_request.
id = metaData(QLatin1String(
"request-id"));
571 if (host.indexOf(QLatin1Char(
':')) == -1) {
574 int pos = host.indexOf(QLatin1Char(
'%'));
600 if (u.host().isEmpty()) {
601 error( KIO::ERR_UNKNOWN_HOST,
i18n(
"No host specified."));
605 if (u.
path().isEmpty()) {
607 newUrl.
setPath(QLatin1String(
"/"));
630 if (dataInternal || !status) {
689 setMetaData(QLatin1String(
"content-type"),
m_mimeType);
707 QString statSide = metaData(QLatin1String(
"statSide"));
708 if (statSide != QLatin1String(
"source"))
755 QString query = metaData(QLatin1String(
"davSearchQuery"));
756 if ( !query.isEmpty() )
758 QByteArray request =
"<?xml version=\"1.0\"?>\r\n";
759 request.append(
"<D:searchrequest xmlns:D=\"DAV:\">\r\n" );
760 request.append( query.toUtf8() );
761 request.append(
"</D:searchrequest>\r\n" );
767 request =
"<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
768 "<D:propfind xmlns:D=\"DAV:\">";
771 if ( hasMetaData(QLatin1String(
"davRequestResponse")) )
772 request += metaData(QLatin1String(
"davRequestResponse")).toUtf8();
775 request +=
"<D:prop>"
777 "<D:getcontentlength/>"
780 "<D:getcontentlanguage/>"
781 "<D:getcontenttype/>"
782 "<D:getlastmodified/>"
789 request +=
"</D:propfind>";
803 infoMessage(QLatin1String(
""));
813 QDomDocument multiResponse;
816 bool hasResponse =
false;
820 for ( QDomNode n = multiResponse.documentElement().firstChild();
821 !n.isNull(); n = n.nextSibling()) {
822 QDomElement thisResponse = n.toElement();
823 if (thisResponse.isNull())
828 QDomElement href = thisResponse.namedItem(QLatin1String(
"href")).toElement();
829 if ( !href.isNull() ) {
832 QString urlStr = QUrl::fromPercentEncoding(href.text().toUtf8());
833 #if 0 // qt4/kde4 say: it's all utf8...
834 int encoding = remoteEncoding()->encodingMib();
835 if ((encoding == 106) && (!KStringHandler::isUtf8(
KUrl::decode_string(urlStr, 4).toLatin1())))
838 KUrl thisURL ( urlStr, encoding );
840 KUrl thisURL( urlStr );
843 if ( thisURL.isValid() ) {
848 name = QLatin1Char(
'.');
853 QDomNodeList propstats = thisResponse.elementsByTagName(QLatin1String(
"propstat"));
864 if (mime && !mime->isDefault() && accuracy == 100) {
865 kDebug(7113) <<
"Setting" << mime->name() <<
"as guessed mime type for" << thisURL.
fileName();
877 listEntry( entry,
false );
879 kDebug(7113) <<
"Error: no URL contained in response to PROPFIND on" << url;
883 if ( stat || !hasResponse ) {
888 listEntry( entry,
true );
915 const int firstSpace = response.indexOf( QLatin1Char(
' ') );
916 const int secondSpace = response.indexOf( QLatin1Char(
' '), firstSpace + 1 );
917 return response.mid( firstSpace + 1, secondSpace - firstSpace - 1 ).toInt();
923 bool foundExecutable =
false;
924 bool isDirectory =
false;
926 uint supportedLockCount = 0;
928 for (
int i = 0; i < propstats.count(); i++)
930 QDomElement propstat = propstats.item(i).toElement();
932 QDomElement status = propstat.namedItem(QLatin1String(
"status")).toElement();
933 if ( status.isNull() )
936 kDebug(7113) <<
"Error, no status code in this propstat";
944 kDebug(7113) <<
"Got status code" << code <<
"(this may mean that some properties are unavailable)";
948 QDomElement prop = propstat.namedItem( QLatin1String(
"prop") ).toElement();
951 kDebug(7113) <<
"Error: no prop segment in this propstat.";
955 if ( hasMetaData( QLatin1String(
"davRequestResponse") ) )
958 doc.appendChild(prop);
962 for ( QDomNode n = prop.firstChild(); !n.isNull(); n = n.nextSibling() )
964 QDomElement
property = n.toElement();
965 if (property.isNull())
968 if ( property.namespaceURI() != QLatin1String(
"DAV:") )
974 if ( property.tagName() == QLatin1String(
"creationdate") )
979 else if ( property.tagName() == QLatin1String(
"getcontentlength") )
984 else if ( property.tagName() == QLatin1String(
"displayname") )
987 setMetaData( QLatin1String(
"davDisplayName"), property.text() );
989 else if ( property.tagName() == QLatin1String(
"source") )
992 QDomElement source =
property.namedItem( QLatin1String(
"link") ).toElement()
993 .namedItem( QLatin1String(
"dst") ).toElement();
994 if ( !source.isNull() )
995 setMetaData( QLatin1String(
"davSource"), source.text() );
997 else if ( property.tagName() == QLatin1String(
"getcontentlanguage") )
1000 setMetaData( QLatin1String(
"davContentLanguage"), property.text() );
1002 else if ( property.tagName() == QLatin1String(
"getcontenttype") )
1007 if ( property.text() == QLatin1String(
"httpd/unix-directory") )
1013 mimeType =
property.text();
1016 else if ( property.tagName() == QLatin1String(
"executable") )
1019 if ( property.text() == QLatin1String(
"T") )
1020 foundExecutable =
true;
1023 else if ( property.tagName() == QLatin1String(
"getlastmodified") )
1028 else if ( property.tagName() == QLatin1String(
"getetag") )
1031 setMetaData( QLatin1String(
"davEntityTag"), property.text() );
1033 else if ( property.tagName() == QLatin1String(
"supportedlock") )
1036 for ( QDomNode n2 = property.firstChild(); !n2.isNull(); n2 = n2.nextSibling() )
1038 QDomElement lockEntry = n2.toElement();
1039 if ( lockEntry.tagName() == QLatin1String(
"lockentry") )
1041 QDomElement lockScope = lockEntry.namedItem( QLatin1String(
"lockscope") ).toElement();
1042 QDomElement lockType = lockEntry.namedItem( QLatin1String(
"locktype") ).toElement();
1043 if ( !lockScope.isNull() && !lockType.isNull() )
1046 supportedLockCount++;
1047 const QString lockCountStr = QString::number(supportedLockCount);
1048 const QString scope = lockScope.firstChild().toElement().tagName();
1049 const QString type = lockType.firstChild().toElement().tagName();
1051 setMetaData( QLatin1String(
"davSupportedLockScope") + lockCountStr, scope );
1052 setMetaData( QLatin1String(
"davSupportedLockType") + lockCountStr, type );
1057 else if ( property.tagName() == QLatin1String(
"lockdiscovery") )
1060 davParseActiveLocks( property.elementsByTagName( QLatin1String(
"activelock") ), lockCount );
1062 else if ( property.tagName() == QLatin1String(
"resourcetype") )
1065 if ( !property.namedItem( QLatin1String(
"collection") ).toElement().isNull() )
1073 kDebug(7113) <<
"Found unknown webdav property:" <<
property.tagName();
1078 setMetaData( QLatin1String(
"davLockCount"), QString::number(lockCount) );
1079 setMetaData( QLatin1String(
"davSupportedLockCount"), QString::number(supportedLockCount) );
1083 if ( foundExecutable || isDirectory )
1093 if ( !isDirectory && !mimeType.isEmpty() )
1102 for (
int i = 0; i < activeLocks.count(); i++ )
1104 const QDomElement activeLock = activeLocks.item(i).toElement();
1108 const QDomElement lockScope = activeLock.namedItem( QLatin1String(
"lockscope") ).toElement();
1109 const QDomElement lockType = activeLock.namedItem( QLatin1String(
"locktype") ).toElement();
1110 const QDomElement lockDepth = activeLock.namedItem( QLatin1String(
"depth") ).toElement();
1112 const QDomElement lockOwner = activeLock.namedItem( QLatin1String(
"owner") ).toElement();
1113 const QDomElement lockTimeout = activeLock.namedItem( QLatin1String(
"timeout") ).toElement();
1114 const QDomElement lockToken = activeLock.namedItem( QLatin1String(
"locktoken") ).toElement();
1116 if ( !lockScope.isNull() && !lockType.isNull() && !lockDepth.isNull() )
1120 const QString lockCountStr = QString::number(lockCount);
1121 const QString scope = lockScope.firstChild().toElement().tagName();
1122 const QString type = lockType.firstChild().toElement().tagName();
1123 const QString depth = lockDepth.text();
1125 setMetaData( QLatin1String(
"davLockScope") + lockCountStr, scope );
1126 setMetaData( QLatin1String(
"davLockType") + lockCountStr, type );
1127 setMetaData( QLatin1String(
"davLockDepth") + lockCountStr, depth );
1129 if ( !lockOwner.isNull() )
1130 setMetaData( QLatin1String(
"davLockOwner") + lockCountStr, lockOwner.text() );
1132 if ( !lockTimeout.isNull() )
1133 setMetaData( QLatin1String(
"davLockTimeout") + lockCountStr, lockTimeout.text() );
1135 if ( !lockToken.isNull() )
1137 QDomElement tokenVal = lockScope.namedItem( QLatin1String(
"href") ).toElement();
1138 if ( !tokenVal.isNull() )
1139 setMetaData( QLatin1String(
"davLockToken") + lockCountStr, tokenVal.text() );
1147 if ( type == QLatin1String(
"dateTime.tz") )
1151 else if ( type == QLatin1String(
"dateTime.rfc1123") )
1166 if ( hasMetaData( QLatin1String(
"davLockCount") ) )
1168 QString response = QLatin1String(
"If:");
1169 int numLocks = metaData( QLatin1String(
"davLockCount") ).toInt();
1170 bool bracketsOpen =
false;
1171 for (
int i = 0; i < numLocks; i++ )
1173 const QString countStr = QString::number(i);
1174 if ( hasMetaData( QLatin1String(
"davLockToken") + countStr ) )
1176 if ( hasMetaData( QLatin1String(
"davLockURL") + countStr ) )
1180 response += QLatin1Char(
')');
1181 bracketsOpen =
false;
1183 response += QLatin1String(
" <") + metaData( QLatin1String(
"davLockURL") + countStr ) + QLatin1Char(
'>');
1186 if ( !bracketsOpen )
1188 response += QLatin1String(
" (");
1189 bracketsOpen =
true;
1193 response += QLatin1Char(
' ');
1196 if ( hasMetaData( QLatin1String(
"davLockNot") + countStr ) )
1197 response += QLatin1String(
"Not ");
1199 response += QLatin1Char(
'<') + metaData( QLatin1String(
"davLockToken") + countStr ) + QLatin1Char(
'>');
1204 response += QLatin1Char(
')');
1206 response += QLatin1String(
"\r\n");
1226 kDebug(7113) <<
" false";
1249 if (ok && verNo > 0 && verNo < 3)
1252 kDebug(7113) <<
"Server supports DAV version" << verNo;
1304 QString tmp(metaData(QLatin1String(
"cache")));
1324 if (!(flags & KIO::Overwrite)) {
1329 const QByteArray request (
"<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
1330 "<D:propfind xmlns:D=\"DAV:\"><D:prop>"
1332 "<D:getcontentlength/>"
1335 "</D:prop></D:propfind>");
1371 kDebug(7113) << src <<
"->" << dest;
1378 KUrl newDest = dest;
1379 if (newDest.
protocol() == QLatin1String(
"webdavs"))
1381 else if (newDest.
protocol() == QLatin1String(
"webdav"))
1401 kDebug(7113) << src <<
"->" << dest;
1408 KUrl newDest = dest;
1409 if (newDest.
protocol() == QLatin1String(
"webdavs"))
1411 else if (newDest.
protocol() == QLatin1String(
"webdav"))
1505 QDomDocument lockReq;
1507 QDomElement lockInfo = lockReq.createElementNS( QLatin1String(
"DAV:"), QLatin1String(
"lockinfo") );
1508 lockReq.appendChild( lockInfo );
1510 QDomElement lockScope = lockReq.createElement( QLatin1String(
"lockscope") );
1511 lockInfo.appendChild( lockScope );
1513 lockScope.appendChild( lockReq.createElement( scope ) );
1515 QDomElement lockType = lockReq.createElement( QLatin1String(
"locktype") );
1516 lockInfo.appendChild( lockType );
1518 lockType.appendChild( lockReq.createElement( type ) );
1520 if ( !owner.isNull() ) {
1521 QDomElement ownerElement = lockReq.createElement( QLatin1String(
"owner") );
1522 lockReq.appendChild( ownerElement );
1524 QDomElement ownerHref = lockReq.createElement( QLatin1String(
"href") );
1525 ownerElement.appendChild( ownerHref );
1527 ownerHref.appendChild( lockReq.createTextNode( owner ) );
1537 QDomDocument multiResponse;
1540 QDomElement prop = multiResponse.documentElement().namedItem( QLatin1String(
"prop") ).toElement();
1542 QDomElement lockdiscovery = prop.namedItem( QLatin1String(
"lockdiscovery") ).toElement();
1545 davParseActiveLocks( lockdiscovery.elementsByTagName( QLatin1String(
"activelock") ), lockCount );
1547 setMetaData( QLatin1String(
"davLockCount"), QString::number( lockCount ) );
1577 bool callError =
false;
1587 if ( !url.isNull() )
1594 QString ow =
i18n(
"Otherwise, the request would have succeeded." );
1598 action =
i18nc(
"request type",
"retrieve property values" );
1601 action =
i18nc(
"request type",
"set property values" );
1604 action =
i18nc(
"request type",
"create the requested folder" );
1607 action =
i18nc(
"request type",
"copy the specified file or folder" );
1610 action =
i18nc(
"request type",
"move the specified file or folder" );
1613 action =
i18nc(
"request type",
"search in the specified folder" );
1616 action =
i18nc(
"request type",
"lock the specified file or folder" );
1619 action =
i18nc(
"request type",
"unlock the specified file or folder" );
1622 action =
i18nc(
"request type",
"delete the specified file or folder" );
1625 action =
i18nc(
"request type",
"query the server's capabilities" );
1628 action =
i18nc(
"request type",
"retrieve the contents of the specified file or folder" );
1631 action =
i18nc(
"request type",
"run a report in the specified folder" );
1642 errorString =
i18nc(
"%1: code, %2: request type",
"An unexpected error (%1) occurred "
1643 "while attempting to %2.", code, action);
1650 errorString =
i18n(
"The server does not support the WebDAV protocol.");
1664 QDomDocument multiResponse;
1668 QDomElement multistatus = multiResponse.documentElement().namedItem( QLatin1String(
"multistatus") ).toElement();
1670 QDomNodeList responses = multistatus.elementsByTagName( QLatin1String(
"response") );
1672 for (
int i = 0; i < responses.count(); i++)
1677 QDomElement response = responses.item(i).toElement();
1678 QDomElement code = response.namedItem( QLatin1String(
"status") ).toElement();
1680 if ( !code.isNull() )
1683 QDomElement href = response.namedItem( QLatin1String(
"href") ).toElement();
1684 if ( !href.isNull() )
1685 errUrl = href.text();
1686 errors <<
davError( errCode, errUrl );
1691 errorString =
i18nc(
"%1: request type, %2: url",
1692 "An error occurred while attempting to %1, %2. A "
1693 "summary of the reasons is below.", action, url );
1695 errorString += QLatin1String(
"<ul>");
1698 errorString += QLatin1String(
"<li>") + error + QLatin1String(
"</li>");
1700 errorString += QLatin1String(
"</ul>");
1706 errorString =
i18nc(
"%1: request type",
"Access was denied while attempting to %1.", action );
1719 errorString =
i18n(
"A resource cannot be created at the destination "
1720 "until one or more intermediate collections (folders) "
1721 "have been created.");
1727 errorString =
i18n(
"The server was unable to maintain the liveness of "
1728 "the properties listed in the propertybehavior XML "
1729 "element or you attempted to overwrite a file while "
1730 "requesting that files are not overwritten. %1",
1735 errorString =
i18n(
"The requested lock could not be granted. %1", ow );
1741 errorString =
i18n(
"The server does not support the request type of the body.");
1746 errorString =
i18nc(
"%1: request type",
"Unable to %1 because the resource is locked.", action );
1750 errorString =
i18n(
"This action was prevented by another error.");
1756 errorString =
i18nc(
"%1: request type",
"Unable to %1 because the destination server refuses "
1757 "to accept the file or folder.", action );
1763 errorString =
i18n(
"The destination resource does not have sufficient space "
1764 "to record the state of the resource after the execution "
1775 error( errorCode, errorString );
1783 Q_ASSERT(errorString);
1786 errorString->clear();
1798 Q_ASSERT(errorString);
1802 errorString->clear();
1804 switch (responseCode) {
1813 && (responseCode < 200 || responseCode > 400)
1814 && responseCode != 404) {
1816 *errorString =
i18n(
"The resource cannot be deleted." );
1825 Q_ASSERT(errorString);
1831 switch (responseCode) {
1838 *errorString =
i18nc(
"%1: request type",
"Access was denied while attempting to %1.", action );
1844 *errorString =
i18n(
"A resource cannot be created at the destination "
1845 "until one or more intermediate collections (folders) "
1846 "have been created.");
1852 *errorString =
i18nc(
"%1: request type",
"Unable to %1 because the resource is locked.", action );
1858 *errorString =
i18nc(
"%1: request type",
"Unable to %1 because the destination server refuses "
1859 "to accept the file or folder.", action );
1865 *errorString =
i18n(
"The destination resource does not have sufficient space "
1866 "to record the state of the resource after the execution "
1875 && (responseCode < 200 || responseCode > 400)
1876 && responseCode != 404) {
1878 *errorString =
i18nc(
"%1: response code, %2: request type",
1879 "An unexpected error (%1) occurred while attempting to %2.",
1880 responseCode, action);
1907 infoMessage(QLatin1String(
""));
1910 error( errorCode, errorString );
1923 kWarning(7113) <<
"called twice during one request, something is probably wrong.";
1926 SlaveBase::errorPage();
1936 Solid::Networking::Status status = Solid::Networking::status();
1938 kDebug(7113) <<
"networkstatus:" << status;
1941 return status == Solid::Networking::Unconnected;
1946 QDataStream stream(data);
1958 for (
unsigned i = 0; i < n; ++i) {
1960 stream >> url >> mIncomingMetaData;
1973 QString tmp = metaData(QLatin1String(
"cache"));
1988 while (it.hasNext()) {
2000 while (it.hasNext()) {
2017 setMetaData(QLatin1String(
"request-id"), QString::number(requestId++));
2018 sendAndKeepMetaData();
2037 const char* buf =
static_cast<const char*
>(_buf);
2038 while (sent < nbytes)
2040 int n = TCPSlaveBase::write(buf + sent, nbytes - sent);
2065 for (
size_t i = 0; i < size; i++) {
2076 size_t bytesRead = 0;
2079 bytesRead = qMin((
int)size, bufSize);
2081 for (
size_t i = 0; i < bytesRead; i++) {
2082 buf[i] =
m_unreadBuf.constData()[bufSize - i - 1];
2093 if (bytesRead < size) {
2094 int rawRead = TCPSlaveBase::read(buf + bytesRead, size - bytesRead);
2099 bytesRead += rawRead;
2110 Q_ASSERT(numNewlines >=1 && numNewlines <= 2);
2113 while (pos < end && !
m_isEOF) {
2114 int step = qMin((
int)
sizeof(mybuf), end - pos);
2123 for (
size_t i = 0; i < bufferFill ; ++i, ++pos) {
2126 buf[pos] = mybuf[i];
2131 if (buf[pos] ==
'\n') {
2132 bool found = numNewlines == 1;
2135 found = ((pos >= 1 && buf[pos - 1] ==
'\n') ||
2136 (pos >= 2 && buf[pos - 2] ==
'\n' && buf[pos - 1] ==
'\r'));
2140 unread(&mybuf[i], bufferFill - i);
2153 if (previous.host() != now.host() || previous.port() != now.port()) {
2156 if (previous.
user().isEmpty() && previous.
pass().isEmpty()) {
2172 if (url != QLatin1String(
"DIRECT")) {
2191 disconnect(
socket(), SIGNAL(connected()),
2196 int connectError = 0;
2210 const KUrl url (proxyUrl);
2215 errorString = url.
url();
2219 const bool isDirectConnect = (proxyUrl == QLatin1String(
"DIRECT"));
2220 QNetworkProxy::ProxyType proxyType = QNetworkProxy::NoProxy;
2221 if (url.
protocol() == QLatin1String(
"socks")) {
2222 proxyType = QNetworkProxy::Socks5Proxy;
2223 }
else if (!isDirectConnect &&
isAutoSsl()) {
2224 proxyType = QNetworkProxy::HttpProxy;
2227 kDebug(7113) <<
"Connecting to proxy: address=" << proxyUrl <<
"type=" << proxyType;
2229 if (proxyType == QNetworkProxy::NoProxy) {
2232 if (isDirectConnect) {
2236 connectError =
connectToHost(url.host(), url.port(), &errorString);
2237 if (connectError == 0) {
2239 kDebug(7113) <<
"Connected to proxy: host=" << url.host() <<
"port=" << url.port();
2243 kDebug(7113) <<
"Failed to connect to proxy:" << proxyUrl;
2244 badProxyUrls << url;
2247 if (connectError == 0) {
2251 QNetworkProxy proxy (proxyType, url.host(), url.port(), url.
user(), url.
pass());
2252 QNetworkProxy::setApplicationProxy(proxy);
2254 if (connectError == 0) {
2255 kDebug(7113) <<
"Tunneling thru proxy: host=" << url.host() <<
"port=" << url.port();
2260 kDebug(7113) <<
"Failed to connect to proxy:" << proxyUrl;
2261 badProxyUrls << url;
2262 QNetworkProxy::setApplicationProxy(QNetworkProxy::NoProxy);
2267 if (!badProxyUrls.isEmpty()) {
2272 if (connectError != 0) {
2273 error (connectError, errorString);
2303 bool openForReading =
false;
2307 if (!openForReading && (isCacheOnly || offline)) {
2309 *cacheHasPage =
false;
2312 }
else if (offline) {
2319 if (openForReading) {
2321 *cacheHasPage =
true;
2326 *cacheHasPage =
false;
2339 if (protocol.startsWith(QLatin1String(
"webdav"))) {
2340 protocol.replace(0, qstrlen(
"webdav"), QLatin1String(
"http"));
2397 kDebug(7113) <<
"Couldn't connect, oopsie!";
2409 bool hasBodyData =
false;
2410 bool hasDavData =
false;
2420 bool cacheHasPage =
false;
2422 kDebug(7113) <<
"cacheHasPage =" << cacheHasPage;
2423 return cacheHasPage;
2425 if (!cacheHasPage) {
2442 davHeader = QLatin1String(
"Depth: ");
2443 if ( hasMetaData( QLatin1String(
"davDepth") ) )
2445 kDebug(7113) <<
"Reading DAV depth from metadata:" << metaData( QLatin1String(
"davDepth") );
2446 davHeader += metaData( QLatin1String(
"davDepth") );
2451 davHeader += QLatin1String(
"infinity");
2455 davHeader += QLatin1String(
"\r\n");
2467 davHeader += QLatin1String(
"\r\nDepth: infinity\r\nOverwrite: ");
2469 davHeader += QLatin1String(
"\r\n");
2472 davHeader = QLatin1String(
"Timeout: ");
2475 if ( hasMetaData( QLatin1String(
"davTimeout") ) )
2476 timeout = metaData( QLatin1String(
"davTimeout") ).toUInt();
2478 davHeader += QLatin1String(
"Infinite");
2480 davHeader += QLatin1String(
"Seconds-") + QString::number(timeout);
2482 davHeader += QLatin1String(
"\r\n");
2486 davHeader = QLatin1String(
"Lock-token: ") + metaData(QLatin1String(
"davLockToken")) + QLatin1String(
"\r\n");
2493 case DAV_UNSUBSCRIBE:
2507 header += QLatin1Char(
':') + QString::number(
m_request.
url.port());
2509 header += QLatin1String(
"\r\n");
2516 header += QLatin1String(
"Proxy-Connection: ");
2518 header += QLatin1String(
"Connection: ");
2521 header += QLatin1String(
"keep-alive\r\n");
2523 header += QLatin1String(
"close\r\n");
2528 header += QLatin1String(
"User-Agent: ");
2530 header += QLatin1String(
"\r\n");
2535 header += QLatin1String(
"Referer: ");
2537 header += QLatin1String(
"\r\n");
2542 header += QLatin1String(
"Range: bytes=");
2544 header += QLatin1Char(
'-');
2546 header += QLatin1String(
"\r\n");
2552 header += QLatin1String(
"Range: bytes=");
2554 header += QLatin1String(
"-\r\n");
2561 header += QLatin1String(
"Pragma: no-cache\r\n");
2562 header += QLatin1String(
"Cache-control: no-cache\r\n");
2566 kDebug(7113) <<
"needs validation, performing conditional get.";
2573 header += QLatin1String(
"If-Modified-Since: ") + httpDate + QLatin1String(
"\r\n");
2574 setMetaData(QLatin1String(
"modified"), httpDate);
2578 header += QLatin1String(
"Accept: ");
2579 const QString acceptHeader = metaData(QLatin1String(
"accept"));
2580 if (!acceptHeader.isEmpty())
2581 header += acceptHeader;
2584 header += QLatin1String(
"\r\n");
2587 header += QLatin1String(
"Accept-Encoding: gzip, deflate, x-gzip, x-deflate\r\n");
2590 header += QLatin1String(
"Accept-Charset: ") +
m_request.
charsets + QLatin1String(
"\r\n");
2593 header += QLatin1String(
"Accept-Language: ") +
m_request.
languages + QLatin1String(
"\r\n");
2596 const QString cookieMode = metaData(QLatin1String(
"cookies")).toLower();
2598 if (cookieMode == QLatin1String(
"none"))
2602 else if (cookieMode == QLatin1String(
"manual"))
2605 cookieStr = metaData(QLatin1String(
"setcookies"));
2614 if (!cookieStr.isEmpty())
2615 header += cookieStr + QLatin1String(
"\r\n");
2617 const QString customHeader = metaData( QLatin1String(
"customHTTPHeader") );
2618 if (!customHeader.isEmpty())
2621 header += QLatin1String(
"\r\n");
2624 const QString contentType = metaData(QLatin1String(
"content-type"));
2625 if (!contentType.isEmpty())
2627 if (!contentType.startsWith(QLatin1String(
"content-type"), Qt::CaseInsensitive))
2628 header += QLatin1String(
"Content-Type: ");
2629 header += contentType;
2630 header += QLatin1String(
"\r\n");
2635 header += QLatin1String(
"DNT: 1\r\n");
2648 davHeader += metaData(QLatin1String(
"davHeader"));
2652 davHeader += QLatin1String(
"Content-Type: text/xml; charset=utf-8\r\n");
2655 header += davHeader;
2659 kDebug(7103) <<
"============ Sending Header:";
2660 Q_FOREACH (
const QString &s, header.split(QLatin1String(
"\r\n"), QString::SkipEmptyParts)) {
2666 if (!hasBodyData && !hasDavData)
2667 header += QLatin1String(
"\r\n");
2676 ssize_t written =
write(header.toLatin1(), header.length());
2677 bool sendOk = (written == (ssize_t) header.length());
2681 <<
" -- intended to write" << header.length()
2682 <<
"bytes but wrote" << (int)written <<
".";
2692 kDebug(7113) <<
"sendOk == false. Connection broken !"
2693 <<
" -- intended to write" << header.length()
2694 <<
"bytes but wrote" << (int)written <<
".";
2699 kDebug(7113) <<
"sent it!";
2702 if (hasBodyData || hasDavData)
2705 infoMessage(
i18n(
"%1 contacted. Waiting for reply...",
m_request.
url.host()));
2718 if (forwardImmediately)
2731 if (header.startsWith(QLatin1String(
"content-type:"), Qt::CaseInsensitive)) {
2732 int pos = header.indexOf(QLatin1String(
"charset="), Qt::CaseInsensitive);
2734 const QString charset = header.mid(pos + 8).toLower();
2736 setMetaData(QLatin1String(
"charset"), charset);
2738 }
else if (header.startsWith(QLatin1String(
"content-language:"), Qt::CaseInsensitive)) {
2739 const QString language = header.mid(17).trimmed().toLower();
2740 setMetaData(QLatin1String(
"content-language"), language);
2741 }
else if (header.startsWith(QLatin1String(
"content-disposition:"), Qt::CaseInsensitive)) {
2768 if (
m_mimeType == QLatin1String(
"application/x-targz"))
2769 m_mimeType = QLatin1String(
"application/x-compressed-tar");
2770 else if (
m_mimeType == QLatin1String(
"image/x-png"))
2774 else if (
m_mimeType == QLatin1String(
"audio/microsoft-wave"))
2776 else if (
m_mimeType == QLatin1String(
"image/x-ms-bmp"))
2780 else if (
m_mimeType == QLatin1String(
"application/pkix-cert") ||
2781 m_mimeType == QLatin1String(
"application/binary-certificate")) {
2782 m_mimeType = QLatin1String(
"application/x-x509-ca-cert");
2786 else if (
m_mimeType == QLatin1String(
"application/x-gzip")) {
2789 m_mimeType = QLatin1String(
"application/x-compressed-tar");
2791 m_mimeType = QLatin1String(
"application/x-gzpostscript");
2796 else if(
m_mimeType == QLatin1String(
"application/x-xz")) {
2799 m_mimeType = QLatin1String(
"application/x-xz-compressed-tar");
2804 else if ((
m_mimeType == QLatin1String(
"text/plain")) || (
m_mimeType == QLatin1String(
"application/octet-stream"))) {
2806 if (ext == QLatin1String(
"BZ2"))
2807 m_mimeType = QLatin1String(
"application/x-bzip");
2808 else if (ext == QLatin1String(
"PEM"))
2809 m_mimeType = QLatin1String(
"application/x-x509-ca-cert");
2810 else if (ext == QLatin1String(
"SWF"))
2811 m_mimeType = QLatin1String(
"application/x-shockwave-flash");
2812 else if (ext == QLatin1String(
"PLS"))
2814 else if (ext == QLatin1String(
"WMV"))
2815 m_mimeType = QLatin1String(
"video/x-ms-wmv");
2816 else if (ext == QLatin1String(
"WEBM"))
2818 else if (ext == QLatin1String(
"DEB"))
2819 m_mimeType = QLatin1String(
"application/x-deb");
2833 if (
m_mimeType == QLatin1String(
"application/x-tar")) {
2835 m_mimeType = QLatin1String(
"application/x-compressed-tar");
2836 }
else if (
m_mimeType == QLatin1String(
"application/postscript")) {
2840 m_mimeType = QLatin1String(
"application/x-gzpostscript");
2845 m_mimeType != QLatin1String(
"application/x-compressed-tar") &&
2846 m_mimeType != QLatin1String(
"application/x-tgz") &&
2847 m_mimeType != QLatin1String(
"application/x-targz") &&
2848 m_mimeType != QLatin1String(
"application/x-gzip"))) {
2852 m_mimeType = QLatin1String(
"application/x-gzip");
2864 m_mimeType = QLatin1String(
"application/x-bzip");
2871 static bool consume(
const char input[],
int *pos,
int end,
const char *term)
2875 if (idx + (
int)strlen(term) >= end) {
2879 if (strncasecmp(&input[idx], term, strlen(term)) == 0) {
2880 *pos = idx + strlen(term);
2904 bool upgradeRequired =
false;
2908 bool noHeadersFound =
false;
2913 static const int maxHeaderSize = 128 * 1024;
2915 char buffer[maxHeaderSize];
2917 bool bCanResume =
false;
2920 kDebug(7113) <<
"No connection.";
2930 kDebug(7113) <<
"Got socket error:" <<
socket()->errorString();
2939 if (!foundDelimiter && bufPos < maxHeaderSize) {
2940 kDebug(7113) <<
"EOF while waiting for header start.";
2957 kDebug(7113) <<
"Connection broken !";
2961 if (!foundDelimiter) {
2966 kDebug(7103) <<
"============ Received Status Response:";
2967 kDebug(7103) << QByteArray(buffer, bufPos).trimmed();
2972 if (idx != bufPos && buffer[idx] ==
'<') {
2973 kDebug(7103) <<
"No valid HTTP header found! Document starts with XML/HTML tag";
2979 noHeadersFound =
true;
2986 if (
consume(buffer, &idx, bufPos,
"ICY ")) {
2989 }
else if (
consume(buffer, &idx, bufPos,
"HTTP/")) {
2990 if (
consume(buffer, &idx, bufPos,
"1.0")) {
2993 }
else if (
consume(buffer, &idx, bufPos,
"1.1")) {
2998 if (httpRev ==
HTTP_None && bufPos != 0) {
3001 kDebug(7113) <<
"DO NOT WANT." << bufPos;
3009 noHeadersFound =
true;
3020 if (idx != bufPos) {
3036 messageBox(WarningYesNo,
3037 i18nc(
"@info Security check on url being accessed",
3038 "<p>You are about to log in to the site \"%1\" "
3039 "with the username \"%2\", but the website "
3040 "does not require authentication. "
3041 "This may be an attempt to trick you.</p>"
3042 "<p>Is \"%1\" the site you want to visit?</p>",
3044 i18nc(
"@title:window",
"Confirm Website Access"));
3049 setMetaData(QLatin1String(
"{internal~currenthost}LastSpoofedUserName"),
m_request.
url.
user());
3073 upgradeRequired =
true;
3087 setMetaData(QLatin1String(
"permanent-redirect"), QLatin1String(
"true"));
3121 infoMessage(
i18n(
"Server processing request, please wait..." ) );
3129 bool authRequiresAnotherRoundtrip =
false;
3132 if (!noHeadersFound) {
3137 kDebug(7113) <<
"wasAuthError=" << wasAuthError <<
"isAuthError=" << isAuthError
3138 <<
"sameAuthError=" << sameAuthError;
3150 kDebug(7113) <<
" -- full response:" << endl << QByteArray(buffer, bufPos).trimmed();
3153 Q_ASSERT(foundDelimiter);
3160 tokenizer.
tokenize(idx,
sizeof(buffer));
3165 if (tIt.
hasNext() && tIt.
next().toLower().startsWith(
"none")) {
3169 tIt = tokenizer.iterator(
"keep-alive");
3171 QByteArray ka = tIt.
next().trimmed().toLower();
3172 if (ka.startsWith(
"timeout=")) {
3173 int ka_timeout = ka.mid(qstrlen(
"timeout=")).trimmed().toInt();
3185 tIt = tokenizer.iterator(
"content-length");
3190 tIt = tokenizer.iterator(
"content-location");
3192 setMetaData(QLatin1String(
"content-location"),
toQString(tIt.
next().trimmed()));
3198 tIt = tokenizer.iterator(
"content-type");
3204 if (
m_mimeType.startsWith(QLatin1Char(
'"'))) {
3216 Q_FOREACH (
const QByteArray &statement, l) {
3217 const int index = statement.indexOf(
'=');
3219 mediaAttribute =
toQString(statement.mid(0, index));
3221 mediaAttribute =
toQString(statement.mid(0, index));
3222 mediaValue =
toQString(statement.mid(index+1));
3224 mediaAttribute = mediaAttribute.trimmed();
3225 mediaValue = mediaValue.trimmed();
3227 bool quoted =
false;
3228 if (mediaValue.startsWith(QLatin1Char(
'"'))) {
3230 mediaValue.remove(0, 1);
3233 if (mediaValue.endsWith(QLatin1Char(
'"'))) {
3237 kDebug (7113) <<
"Encoding-type:" << mediaAttribute <<
"=" << mediaValue;
3239 if (mediaAttribute == QLatin1String(
"charset")) {
3240 mediaValue = mediaValue.toLower();
3242 setMetaData(QLatin1String(
"charset"), mediaValue);
3244 setMetaData(QLatin1String(
"media-") + mediaAttribute, mediaValue);
3246 setMetaData(QLatin1String(
"media-") + mediaAttribute + QLatin1String(
"-kio-quoted"),
3247 QLatin1String(
"true"));
3254 tIt = tokenizer.iterator(
"content-encoding");
3272 tIt = tokenizer.iterator(
"content-disposition");
3276 tIt = tokenizer.iterator(
"content-language");
3279 if (!language.isEmpty()) {
3280 setMetaData(QLatin1String(
"content-language"), language);
3284 tIt = tokenizer.iterator(
"proxy-connection");
3286 QByteArray pc = tIt.
next().toLower();
3287 if (pc.startsWith(
"close")) {
3289 }
else if (pc.startsWith(
"keep-alive")) {
3294 tIt = tokenizer.iterator(
"link");
3298 if (link.count() == 2) {
3299 QString rel = link[1].trimmed();
3300 if (rel.startsWith(QLatin1String(
"rel=\""))) {
3301 rel = rel.mid(5, rel.length() - 6);
3302 if (rel.toLower() == QLatin1String(
"pageservices")) {
3304 QString url = link[0].remove(QRegExp(QLatin1String(
"[<>]"))).trimmed();
3305 setMetaData(QLatin1String(
"PageServices"), url);
3311 tIt = tokenizer.iterator(
"p3p");
3317 .split(QLatin1Char(
'='), QString::SkipEmptyParts);
3318 if (policy.count() == 2) {
3319 if (policy[0].toLower() == QLatin1String(
"policyref")) {
3320 policyrefs << policy[1].remove(QRegExp(QLatin1String(
"[\")\']"))).trimmed();
3321 }
else if (policy[0].toLower() == QLatin1String(
"cp")) {
3325 const QString s = policy[1].remove(QRegExp(QLatin1String(
"[\")\']")));
3326 const QStringList cps = s.split(QLatin1Char(
' '), QString::SkipEmptyParts);
3331 if (!policyrefs.isEmpty()) {
3332 setMetaData(QLatin1String(
"PrivacyPolicy"), policyrefs.join(QLatin1String(
"\n")));
3334 if (!compact.isEmpty()) {
3335 setMetaData(QLatin1String(
"PrivacyCompactPolicy"), compact.join(QLatin1String(
"\n")));
3342 tIt = tokenizer.iterator(
"connection");
3344 QByteArray connection = tIt.
next().toLower();
3346 if (connection.startsWith(
"close")) {
3348 }
else if (connection.startsWith(
"keep-alive")) {
3352 if (connection.startsWith(
"upgrade")) {
3355 upgradeRequired =
true;
3356 }
else if (upgradeRequired) {
3362 tIt = tokenizer.iterator(
"transfer-encoding");
3371 tIt = tokenizer.iterator(
"content-md5");
3378 tIt = tokenizer.iterator(
"dav");
3388 tIt = tokenizer.iterator(
"upgrade");
3392 upgradeOffers = offered.split(QRegExp(QLatin1String(
"[ \n,\r\t]")), QString::SkipEmptyParts);
3394 Q_FOREACH (
const QString &opt, upgradeOffers) {
3395 if (opt == QLatin1String(
"TLS/1.0")) {
3396 if (!
startSsl() && upgradeRequired) {
3400 }
else if (opt == QLatin1String(
"HTTP/1.1")) {
3402 }
else if (upgradeRequired) {
3410 QByteArray cookieStr;
3411 tIt = tokenizer.iterator(
"set-cookie");
3413 cookieStr +=
"Set-Cookie: ";
3414 cookieStr += tIt.
next();
3417 if (!cookieStr.isEmpty()) {
3422 cookieStr =
"Cross-Domain\n" + cookieStr;
3427 setMetaData(QLatin1String(
"setcookies"), QString::fromUtf8(cookieStr));
3435 kDebug(7113) <<
"cont; returning to mark try_again";
3441 kDebug(7113) <<
"Ignoring keep-alive: otherwise unable to determine response body length.";
3456 authRequiresAnotherRoundtrip =
false;
3461 tIt = tokenizer.iterator(
"location");
3463 locationStr = QString::fromUtf8(tIt.
next().trimmed());
3466 if (!locationStr.isEmpty())
3493 if(u.
protocol() == QLatin1String(
"http")){
3495 }
else if(u.
protocol() == QLatin1String(
"https")){
3535 kDebug(7113) <<
"Reading resource from cache even though the cache plan is not "
3536 "UseCached; the server is probably sending wrong expiry information.";
3546 int nextLinePos = 0;
3547 int prevLinePos = 0;
3548 bool haveMore =
true;
3550 haveMore =
nextLine(buffer, &nextLinePos, bufPos);
3551 int prevLineEnd = nextLinePos;
3552 while (buffer[prevLineEnd - 1] ==
'\r' || buffer[prevLineEnd - 1] ==
'\n') {
3557 prevLineEnd - prevLinePos));
3558 prevLinePos = nextLinePos;
3585 return !authRequiresAnotherRoundtrip;
3593 while (i != parameters.constEnd()) {
3594 setMetaData(QLatin1String(
"content-disposition-") + i.key(), i.value());
3595 kDebug(7113) <<
"Content-Disposition:" << i.key() <<
"=" << i.value();
3602 QString encoding = _encoding.trimmed().toLower();
3604 if (encoding == QLatin1String(
"identity")) {
3606 }
else if (encoding == QLatin1String(
"8bit")) {
3609 }
else if (encoding == QLatin1String(
"chunked")) {
3614 }
else if ((encoding == QLatin1String(
"x-gzip")) || (encoding == QLatin1String(
"gzip"))) {
3615 encs.append(QLatin1String(
"gzip"));
3616 }
else if ((encoding == QLatin1String(
"x-bzip2")) || (encoding == QLatin1String(
"bzip2"))) {
3617 encs.append(QLatin1String(
"bzip2"));
3618 }
else if ((encoding == QLatin1String(
"x-deflate")) || (encoding == QLatin1String(
"deflate"))) {
3619 encs.append(QLatin1String(
"deflate"));
3621 kDebug(7113) <<
"Unknown encoding encountered. "
3622 <<
"Please write code. Encoding =" << encoding;
3641 const qint64 currentDate = time(0);
3658 tIt = tokenizer.iterator(
"date");
3665 tIt = tokenizer.iterator(
"age");
3667 ageHeader = tIt.
next().toLongLong();
3671 if (dateHeader != -1) {
3673 }
else if (ageHeader) {
3680 bool hasCacheDirective =
false;
3685 tIt = tokenizer.iterator(
"cache-control");
3687 QByteArray cacheStr = tIt.
next().toLower();
3688 if (cacheStr.startsWith(
"no-cache") || cacheStr.startsWith(
"no-store")) {
3691 hasCacheDirective =
true;
3692 }
else if (cacheStr.startsWith(
"max-age=")) {
3693 QByteArray ba = cacheStr.mid(qstrlen(
"max-age=")).trimmed();
3695 maxAgeHeader = ba.toLongLong(&ok);
3697 hasCacheDirective =
true;
3702 qint64 expiresHeader = -1;
3703 tIt = tokenizer.iterator(
"expires");
3706 kDebug(7113) <<
"parsed expire date from 'expires' header:" << tIt.
current();
3711 }
else if (expiresHeader != -1) {
3720 expAge = qMin(expAge,
qint64(3600 * 24));
3733 tIt = tokenizer.iterator(
"etag");
3738 kDebug(7103) <<
"304 Not Modified but new entity tag - I don't think this is legal HTTP.";
3743 tIt = tokenizer.iterator(
"warning");
3751 tIt = tokenizer.iterator(
"pragma");
3753 if (tIt.
next().toLower().startsWith(
"no-cache")) {
3755 hasCacheDirective =
true;
3760 tIt = tokenizer.iterator(
"refresh");
3763 setMetaData(QLatin1String(
"http-refresh"),
toQString(tIt.
next().trimmed()));
3767 if (
m_mimeType.startsWith(QLatin1String(
"text/")) && (
m_mimeType != QLatin1String(
"text/css")) &&
3768 (
m_mimeType != QLatin1String(
"text/x-javascript")) && !hasCacheDirective) {
3779 kDebug(7113) <<
"Cache needs validation";
3781 kDebug(7113) <<
"...was revalidated by response code but not by updated expire times. "
3782 "We're going to set the expire date to 60 seconds in the future...";
3788 kDebug(7113) <<
"this proxy or server apparently sends bogus expiry information.";
3805 kDebug(7113) <<
"This webserver is confused about the cacheability of the data it sends.";
3819 if (!cachingAllowed) {
3820 setMetaData(QLatin1String(
"no-cache"), QLatin1String(
"true"));
3821 setMetaData(QLatin1String(
"expire-date"), QLatin1String(
"1"));
3825 setMetaData(QLatin1String(
"expire-date"), tmp);
3828 setMetaData(QLatin1String(
"cache-creation-date"), tmp);
3836 QByteArray cLength (
"Content-Length: ");
3837 cLength += QByteArray::number(
m_POSTbuf->size());
3838 cLength +=
"\r\n\r\n";
3840 kDebug(7113) <<
"sending cached data (size=" <<
m_POSTbuf->size() <<
")";
3843 bool sendOk = (
write(cLength.data(), cLength.size()) == (ssize_t) cLength.size());
3845 kDebug( 7113 ) <<
"Connection broken when sending "
3857 sendOk = (
write(buffer.data(), buffer.size()) == (ssize_t) buffer.size());
3859 kDebug(7113) <<
"Connection broken when sending message body: ("
3890 QByteArray cLength (
"Content-Length: ");
3892 cLength +=
"\r\n\r\n";
3894 kDebug(7113) << cLength.trimmed();
3897 bool sendOk = (
write(cLength.data(), cLength.size()) == (ssize_t) cLength.size());
3907 kDebug(7113) <<
"Connection broken while sending POST content size to" <<
m_request.
url.host();
3920 KIO::filesize_t bytesSent = 0;
3926 const int bytesRead = readData(buffer);
3929 if (bytesRead == 0) {
3935 if (bytesRead < 0) {
3949 if (
write(buffer.data(), bytesRead) == static_cast<ssize_t>(bytesRead)) {
3950 bytesSent += bytesRead;
3951 processedSize(bytesSent);
3955 kDebug(7113) <<
"Connection broken while sending POST content to" <<
m_request.
url.host();
3965 kDebug(7113) <<
"keepAlive =" << keepAlive;
3981 QDataStream stream( &data, QIODevice::WriteOnly );
4003 setTimeoutSpecialCommand(-1);
4040 QDataStream stream(data);
4048 stream >> url >> size;
4057 stream >> url >> no_cache >> expireDate;
4063 QFile::remove(filename);
4084 stream >> url >> scope >> type >> owner;
4085 davLock( url, scope, type, owner );
4100 stream >> url >> method >> size;
4101 davGeneric( url, (KIO::HTTP_METHOD) method, size );
4130 if (foundCrLf && bufPos == 2) {
4137 kDebug(7113) <<
"Failed to read chunk header.";
4140 Q_ASSERT(bufPos > 2);
4143 if (nextChunkSize < 0)
4145 kDebug(7113) <<
"Negative chunk size";
4162 int trashBufPos = 2;
4165 if (trashBufPos > 3) {
4167 for (
int i = 0; i < 3; i++) {
4168 trash[i] = trash[trashBufPos - 3 + i];
4175 kDebug(7113) <<
"Failed to read chunk trailer.";
4187 return bytesReceived;
4205 if (bytesReceived <= 0)
4209 return bytesReceived;
4216 kDebug(7113) <<
"Unbounded datastream on a Keep-alive connection!";
4256 kDebug(7113) <<
"Determining mime-type from content...";
4270 if( mime && !mime->isDefault() )
4351 if ( !dataInternal ) {
4354 infoMessage(
i18n(
"Retrieving %1 from %2...", KIO::convertSize(
m_iSize),
4362 kDebug(7113) <<
"reading data from cache...";
4374 if (!dataInternal) {
4381 if (!dataInternal) {
4409 QObject::connect(&chain, SIGNAL(
output(QByteArray)),
4419 if ( enc == QLatin1String(
"gzip") )
4421 else if ( enc == QLatin1String(
"deflate") )
4449 if ( enc == QLatin1String(
"gzip") )
4451 else if ( enc == QLatin1String(
"deflate") )
4470 if (bytesReceived == -1)
4480 kDebug(7113) <<
"bytesReceived==-1 sz=" << (int)sz
4481 <<
" Connection broken !";
4488 if (bytesReceived > 0)
4499 sz += bytesReceived;
4501 processedSize( sz );
4525 kWarning(7113) <<
"MD5 checksum MISMATCH! Expected:"
4534 if (!dataInternal && sz <= 1)
4547 data( QByteArray() );
4554 error(KIO::ERR_SLAVE_DEFINED, text);
4575 SlaveBase::error( _err, _text );
4583 QDBusInterface kcookiejar( QLatin1String(
"org.kde.kded"), QLatin1String(
"/modules/kcookiejar"), QLatin1String(
"org.kde.KCookieServer") );
4584 (void)kcookiejar.call( QDBus::NoBlock, QLatin1String(
"addCookies"), url,
4585 cookieHeader, windowId );
4591 QDBusInterface kcookiejar( QLatin1String(
"org.kde.kded"), QLatin1String(
"/modules/kcookiejar"), QLatin1String(
"org.kde.KCookieServer") );
4592 QDBusReply<QString> reply = kcookiejar.call( QLatin1String(
"findCookies"), url, windowId );
4594 if ( !reply.isValid() )
4596 kWarning(7113) <<
"Can't communicate with kded_kcookiejar!";
4608 case KIO::CC_Refresh:
4615 case KIO::CC_Reload:
4617 case KIO::CC_CacheOnly:
4625 time_t currentDate = time(0);
4638 struct BinaryCacheFileHeader
4650 static const int size = 36;
4662 BinaryCacheFileHeader
header;
4671 QDataStream stream(&ret, QIODevice::WriteOnly);
4672 stream << quint8(
'A');
4673 stream << quint8(
'\n');
4674 stream << quint8(0);
4675 stream << quint8(0);
4677 stream << fileUseCount;
4680 stream <<
qint64(servedDate);
4681 stream << qint64(lastModifiedDate);
4682 stream << qint64(expireDate);
4684 stream << bytesCached;
4685 Q_ASSERT(ret.size() == BinaryCacheFileHeader::size);
4694 return byte == value;
4697 static bool readTime(QDataStream *stream, time_t *time)
4701 *time =
static_cast<time_t
>(intTime);
4704 return check == intTime;
4713 if (d.size() != BinaryCacheFileHeader::size) {
4716 QDataStream stream(d);
4717 stream.setVersion(QDataStream::Qt_4_5);
4728 stream >> fileUseCount;
4731 ok = ok &&
readTime(&stream, &servedDate);
4732 ok = ok &&
readTime(&stream, &lastModifiedDate);
4733 ok = ok &&
readTime(&stream, &expireDate);
4738 stream >> bytesCached;
4763 static const char linefeed =
'\n';
4765 dev->write(&linefeed, 1);
4772 Q_ASSERT(file->openMode() & QIODevice::WriteOnly);
4774 file->seek(BinaryCacheFileHeader::size);
4788 if (line->isEmpty() || !line->endsWith(
'\n')) {
4800 Q_ASSERT(file->openMode() == QIODevice::ReadOnly);
4804 if (
storableUrl(desiredUrl).toEncoded() != readBuf) {
4805 kDebug(7103) <<
"You have witnessed a very improbable hash collision!";
4819 Q_ASSERT(file->openMode() == QIODevice::ReadOnly);
4825 qint64 oldPos = file->pos();
4826 file->seek(BinaryCacheFileHeader::size);
4829 Q_ASSERT(file->pos() == oldPos);
4838 if (ok && !readBuf.isEmpty()) {
4849 QCryptographicHash hash(QCryptographicHash::Sha1);
4851 return toQString(hash.result().toHex());
4857 if (!filePath.endsWith(QLatin1Char(
'/'))) {
4858 filePath.append(QLatin1Char(
'/'));
4871 kDebug(7113) <<
"File unexpectedly open; old file is" << file->fileName()
4872 <<
"new name is" << filename;
4873 Q_ASSERT(file->fileName() == filename);
4876 file =
new QFile(filename);
4877 if (file->open(QIODevice::ReadOnly)) {
4878 QByteArray
header = file->read(BinaryCacheFileHeader::size);
4880 kDebug(7103) <<
"Cache file header is invalid.";
4890 if (!file->isOpen()) {
4908 Q_ASSERT(!qobject_cast<QTemporaryFile *>(file));
4909 Q_ASSERT((file->openMode() & QIODevice::WriteOnly) == 0);
4910 Q_ASSERT(file->fileName() == filename);
4911 kDebug(7113) <<
"deleting expired cache entry and recreating.";
4919 file->open(QIODevice::WriteOnly);
4925 if ((file->openMode() & QIODevice::WriteOnly) == 0) {
4926 kDebug(7113) <<
"Could not open file for writing:" << file->fileName()
4927 <<
"due to error" << file->error();
4938 QDataStream stream(&ret, QIODevice::WriteOnly);
4939 stream.setVersion(QDataStream::Qt_4_5);
4941 stream.skipRawData(BinaryCacheFileHeader::size);
4946 int basenameStart = fileName.lastIndexOf(QLatin1Char(
'/')) + 1;
4948 stream.writeRawData(baseName.constData(), baseName.size());
4950 Q_ASSERT(ret.size() == BinaryCacheFileHeader::size +
sizeof(quint32) +
s_hashedUrlNibbles);
4966 QByteArray ccCommand;
4969 if (file->openMode() & QIODevice::WriteOnly) {
4975 tempFile->write(header);
4979 QString oldName = tempFile->fileName();
4981 int basenameStart = newName.lastIndexOf(QLatin1Char(
'/')) + 1;
4984 kDebug(7113) <<
"Renaming temporary file" << oldName <<
"to" << newName;
4987 tempFile->setAutoRemove(
false);
4991 if (!QFile::rename(oldName, newName)) {
4994 kDebug(7113) <<
"Renaming temporary file failed, deleting it instead.";
4995 QFile::remove(oldName);
5002 }
else if (file->openMode() == QIODevice::ReadOnly) {
5003 Q_ASSERT(!tempFile);
5009 if (!ccCommand.isEmpty()) {
5020 if (attempts == 2) {
5034 kDebug(7113) <<
"Could not connect to cache cleaner, not updating stats of this cache file.";
5044 if (ret.isEmpty()) {
5061 kDebug(7113) <<
"Caching disabled because content size is too big.";
5091 m_POSTbuf->write (data.constData(), data.size());
5117 const int bytesRead = readData(buffer);
5119 if (bytesRead < 0) {
5124 if (bytesRead == 0) {
5128 m_POSTbuf->write(buffer.constData(), buffer.size());
5156 if (useCachedAuth && checkCachedAuthentication(authinfo)) {
5157 const QByteArray cachedChallenge =
config()->readEntry(
"www-auth-challenge", QByteArray());
5158 if (!cachedChallenge.isEmpty()) {
5161 kDebug(7113) <<
"creating www authentcation header from cached info";
5179 if (checkCachedAuthentication(authinfo)) {
5180 const QByteArray cachedChallenge =
config()->readEntry(
"proxy-auth-challenge", QByteArray());
5181 if (!cachedChallenge.isEmpty()) {
5184 kDebug(7113) <<
"creating proxy authentcation header from cached info";
5194 ret +=
"Authorization: ";
5199 ret +=
"Proxy-Authorization: ";
5209 case QNetworkProxy::DefaultProxy:
5211 case QNetworkProxy::Socks5Proxy:
5212 return QLatin1String(
"socks");
5213 case QNetworkProxy::NoProxy:
5215 case QNetworkProxy::HttpProxy:
5216 case QNetworkProxy::HttpCachingProxy:
5217 case QNetworkProxy::FtpCachingProxy:
5222 return QLatin1String(
"http");
5227 kDebug(7113) <<
"realm:" << authenticator->realm() <<
"user:" << authenticator->user();
5238 info.
username = authenticator->user();
5241 const bool haveCachedCredentials = checkCachedAuthentication(info);
5246 if (!haveCachedCredentials || retryAuth) {
5249 connect(
socket(), SIGNAL(connected()),
5252 info.
prompt =
i18n(
"You need to supply a username and a password for "
5253 "the proxy server listed below before you are allowed "
5254 "to access any sites.");
5259 const QString errMsg ((retryAuth ?
i18n(
"Proxy Authentication Failed.") :
QString()));
5261 if (!openPasswordDialog(info, errMsg)) {
5262 kDebug(7113) <<
"looks like the user canceled proxy authentication.";
5269 authenticator->setUser(info.
username);
5270 authenticator->setPassword(info.
password);
5271 authenticator->setOption(QLatin1String(
"keepalive"), info.
keepPassword);
5286 kDebug(7113) <<
"Saving authenticator";
5287 disconnect(
socket(), SIGNAL(connected()),
5299 cacheAuthentication(a);
5308 bool alreadyCached =
false;
5313 alreadyCached =
config()->readEntry(
"cached-www-auth",
false);
5317 alreadyCached =
config()->readEntry(
"cached-proxy-auth",
false);
5324 if (auth && (!auth->
realm().isEmpty() || !alreadyCached)) {
5327 setMetaData(QLatin1String(
"{internal~currenthost}cached-www-auth"), QLatin1String(
"true"));
5329 setMetaData(QLatin1String(
"{internal~currenthost}www-auth-realm"), authinfo.
realmValue);
5331 setMetaData(QLatin1String(
"{internal~currenthost}www-auth-challenge"), authinfo.
digestInfo);
5333 setMetaData(QLatin1String(
"{internal~allhosts}cached-proxy-auth"), QLatin1String(
"true"));
5335 setMetaData(QLatin1String(
"{internal~allhosts}proxy-auth-realm"), authinfo.
realmValue);
5337 setMetaData(QLatin1String(
"{internal~allhosts}proxy-auth-challenge"), authinfo.
digestInfo);
5343 cacheAuthentication(authinfo);
5359 authTokens = tokenizer->iterator(
"www-authenticate").all();
5362 authinfo.
prompt =
i18n(
"You need to supply a username and a "
5363 "password to access this site.");
5369 Q_ASSERT(QNetworkProxy::applicationProxy().type() == QNetworkProxy::NoProxy);
5371 authTokens = tokenizer->iterator(
"proxy-authenticate").all();
5374 authinfo.
prompt =
i18n(
"You need to supply a username and a password for "
5375 "the proxy server listed below before you are allowed "
5376 "to access any sites." );
5380 bool authRequiresAnotherRoundtrip =
false;
5385 if (!authTokens.isEmpty()) {
5387 authRequiresAnotherRoundtrip =
true;
5391 if ((*auth)->wasFinalStage()) {
5393 i18n(
"Authentication Failed.") :
5394 i18n(
"Proxy Authentication Failed."));
5402 QMutableListIterator<QByteArray> it (authTokens);
5403 const QByteArray authScheme ((*auth)->scheme().trimmed());
5404 while (it.hasNext()) {
5405 if (qstrnicmp(authScheme.constData(), it.next().constData(), authScheme.length()) != 0) {
5412 try_next_auth_scheme:
5415 const QByteArray authScheme ((*auth)->scheme().trimmed());
5416 if (qstrnicmp(authScheme.constData(), bestOffer.constData(), authScheme.length()) != 0) {
5428 kDebug(7113) <<
"Trying authentication scheme:" << (*auth)->scheme();
5434 bool generateAuthHeader =
true;
5435 if ((*auth)->needCredentials()) {
5446 if (authinfo.
realmValue.isEmpty() && !(*auth)->supportsPathMatching())
5447 authinfo.
realmValue = QLatin1String((*auth)->scheme());
5452 const KUrl reqUrl = authinfo.
url;
5453 if (!errorMsg.isEmpty() || !checkCachedAuthentication(authinfo)) {
5455 authinfo.
url = reqUrl;
5460 if (!openPasswordDialog(authinfo, errorMsg)) {
5461 generateAuthHeader =
false;
5462 authRequiresAnotherRoundtrip =
false;
5466 kDebug(7113) <<
"looks like the user canceled the authentication dialog";
5476 if (generateAuthHeader) {
5477 (*auth)->generateResponse(username, password);
5478 (*auth)->setCachePasswordEnabled(authinfo.
keepPassword);
5480 kDebug(7113) <<
"isError=" << (*auth)->isError()
5481 <<
"needCredentials=" << (*auth)->needCredentials()
5482 <<
"forceKeepAlive=" << (*auth)->forceKeepAlive()
5483 <<
"forceDisconnect=" << (*auth)->forceDisconnect();
5485 if ((*auth)->isError()) {
5486 authTokens.removeOne(bestOffer);
5487 if (!authTokens.isEmpty()) {
5488 goto try_next_auth_scheme;
5491 authRequiresAnotherRoundtrip =
false;
5494 }
else if ((*auth)->forceKeepAlive()) {
5497 }
else if ((*auth)->forceDisconnect()) {
5504 authRequiresAnotherRoundtrip =
false;
5511 return authRequiresAnotherRoundtrip;