32 #include <sys/socket.h>
33 #include <netinet/in.h>
34 #include <netinet/tcp.h>
46 #include <tqdatetime.h>
47 #include <tqstringlist.h>
60 #include <kinstance.h>
61 #include <kresolver.h>
62 #include <kmimemagic.h>
63 #include <dcopclient.h>
64 #include <kdatastream.h>
65 #include <kapplication.h>
66 #include <kstandarddirs.h>
67 #include <kstringhandler.h>
68 #include <kremoteencoding.h>
70 #include "kio/ioslave_defaults.h"
71 #include "kio/http_slave_defaults.h"
73 #include "httpfilter.h"
78 #include <gssapi/gssapi.h>
84 #if defined(GSS_RFC_COMPLIANT_OIDS) && (GSS_RFC_COMPLIANT_OIDS == 0)
85 #include <gssapi/gssapi_generic.h>
86 #define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name
91 #include <misc/kntlm/kntlm.h>
96 KDE_EXPORT
int kdemain(
int argc,
char **argv);
99 int kdemain(
int argc,
char **argv )
101 KLocale::setMainCatalogue(
"kdelibs");
102 KInstance instance(
"kio_http" );
103 ( void ) KGlobal::locale();
107 fprintf(stderr,
"Usage: kio_http protocol domain-socket1 domain-socket2\n");
111 HTTPProtocol slave(argv[1], argv[2], argv[3]);
112 slave.dispatchLoop();
118 static char * trimLead (
char *orig_string)
120 while (*orig_string ==
' ')
125 static bool isCrossDomainRequest(
const TQString& fqdn,
const TQString& originURL )
127 if (originURL ==
"true")
130 KURL url ( originURL );
133 TQString a = url.host();
141 TQStringList l1 = TQStringList::split(
'.', a);
142 TQStringList l2 = TQStringList::split(
'.', b);
144 while(l1.count() > l2.count())
147 while(l2.count() > l1.count())
150 while(l2.count() >= 2)
165 static TQString sanitizeCustomHTTPHeader(
const TQString& _header)
167 TQString sanitizedHeaders;
168 TQStringList headers = TQStringList::split(TQRegExp(
"[\r\n]"), _header);
170 for(TQStringList::Iterator it = headers.begin(); it != headers.end(); ++it)
172 TQString header = (*it).lower();
175 if (header.find(
':') == -1 ||
176 header.startsWith(
"host") ||
177 header.startsWith(
"via"))
180 sanitizedHeaders += (*it);
181 sanitizedHeaders +=
"\r\n";
184 return sanitizedHeaders.stripWhiteSpace();
187 static TQString htmlEscape(
const TQString &plain)
190 rich.reserve(uint(plain.length() * 1.1));
191 for (uint i = 0; i < plain.length(); ++i) {
192 if (plain.at(i) ==
'<') {
194 }
else if (plain.at(i) ==
'>') {
196 }
else if (plain.at(i) ==
'&') {
198 }
else if (plain.at(i) ==
'"') {
209 #define NO_SIZE ((KIO::filesize_t) -1)
212 #define STRTOLL strtoll
214 #define STRTOLL strtol
220 HTTPProtocol::HTTPProtocol(
const TQCString &protocol,
const TQCString &pool,
221 const TQCString &app )
222 :TCPSlaveBase( 0, protocol , pool, app,
223 (protocol ==
"https" || protocol ==
"webdavs") )
225 m_requestQueue.setAutoDelete(
true);
228 m_bFirstRequest =
false;
229 m_bProxyAuthValid =
false;
234 m_protocol = protocol;
236 m_maxCacheAge = DEFAULT_MAX_CACHE_AGE;
237 m_maxCacheSize = DEFAULT_MAX_CACHE_SIZE / 2;
238 m_remoteConnTimeout = DEFAULT_CONNECT_TIMEOUT;
239 m_remoteRespTimeout = DEFAULT_RESPONSE_TIMEOUT;
240 m_proxyConnTimeout = DEFAULT_PROXY_CONNECT_TIMEOUT;
244 setMultipleAuthCaching(
true );
245 reparseConfiguration();
248 HTTPProtocol::~HTTPProtocol()
253 void HTTPProtocol::reparseConfiguration()
255 kdDebug(7113) <<
"(" << m_pid <<
") HTTPProtocol::reparseConfiguration" << endl;
257 m_strProxyRealm = TQString::null;
258 m_strProxyAuthorization = TQString::null;
259 ProxyAuthentication = AUTH_None;
262 if (m_protocol ==
"https" || m_protocol ==
"webdavs")
263 m_iDefaultPort = DEFAULT_HTTPS_PORT;
264 else if (m_protocol ==
"ftp")
265 m_iDefaultPort = DEFAULT_FTP_PORT;
267 m_iDefaultPort = DEFAULT_HTTP_PORT;
270 void HTTPProtocol::resetConnectionSettings()
276 m_lineCountUnget = 0;
277 m_iProxyAuthCount = 0;
281 void HTTPProtocol::resetResponseSettings()
284 m_redirectLocation = KURL();
288 m_responseHeader.clear();
289 m_qContentEncodings.clear();
290 m_qTransferEncodings.clear();
291 m_sContentMD5 = TQString::null;
292 m_strMimeType = TQString::null;
294 setMetaData(
"request-id", m_request.id);
297 void HTTPProtocol::resetSessionSettings()
301 KURL proxy ( config()->readEntry(
"UseProxy") );
303 if ( m_strProxyRealm.isEmpty() || !proxy.isValid() ||
304 m_proxyURL.host() != proxy.host() ||
305 (!proxy.user().isNull() && proxy.user() != m_proxyURL.user()) ||
306 (!proxy.pass().isNull() && proxy.pass() != m_proxyURL.pass()) )
308 m_bProxyAuthValid =
false;
310 m_bUseProxy = m_proxyURL.isValid();
312 kdDebug(7113) <<
"(" << m_pid <<
") Using proxy: " << m_bUseProxy <<
313 " URL: " << m_proxyURL.url() <<
314 " Realm: " << m_strProxyRealm << endl;
317 m_bPersistentProxyConnection = config()->readBoolEntry(
"PersistentProxyConnection",
false);
318 kdDebug(7113) <<
"(" << m_pid <<
") Enable Persistent Proxy Connection: "
319 << m_bPersistentProxyConnection << endl;
321 m_request.bUseCookiejar = config()->readBoolEntry(
"Cookies");
322 m_request.bUseCache = config()->readBoolEntry(
"UseCache",
true);
323 m_request.bErrorPage = config()->readBoolEntry(
"errorPage",
true);
324 m_request.bNoAuth = config()->readBoolEntry(
"no-auth");
325 m_strCacheDir = config()->readPathEntry(
"CacheDir");
326 m_maxCacheAge = config()->readNumEntry(
"MaxCacheAge", DEFAULT_MAX_CACHE_AGE);
327 m_request.window = config()->readEntry(
"window-id");
329 kdDebug(7113) <<
"(" << m_pid <<
") Window Id = " << m_request.window << endl;
330 kdDebug(7113) <<
"(" << m_pid <<
") ssl_was_in_use = "
331 << metaData (
"ssl_was_in_use") << endl;
333 m_request.referrer = TQString::null;
334 if ( config()->readBoolEntry(
"SendReferrer",
true) &&
335 (m_protocol ==
"https" || m_protocol ==
"webdavs" ||
336 metaData (
"ssl_was_in_use") !=
"TRUE" ) )
338 KURL referrerURL ( metaData(
"referrer") );
339 if (referrerURL.isValid())
342 TQString protocol = referrerURL.protocol();
343 if (protocol.startsWith(
"webdav"))
345 protocol.replace(0, 6,
"http");
346 referrerURL.setProtocol(protocol);
349 if (protocol.startsWith(
"http"))
351 referrerURL.setRef(TQString::null);
352 referrerURL.setUser(TQString::null);
353 referrerURL.setPass(TQString::null);
354 m_request.referrer = referrerURL.url();
359 if ( config()->readBoolEntry(
"SendLanguageSettings",
true) )
361 m_request.charsets = config()->readEntry(
"Charsets",
"iso-8859-1" );
363 if ( !m_request.charsets.isEmpty() )
364 m_request.charsets += DEFAULT_PARTIAL_CHARSET_HEADER;
366 m_request.languages = config()->readEntry(
"Languages", DEFAULT_LANGUAGE_HEADER );
370 m_request.charsets = TQString::null;
371 m_request.languages = TQString::null;
375 TQString resumeOffset = metaData(
"resume");
376 if ( !resumeOffset.isEmpty() )
377 m_request.offset = resumeOffset.toInt();
379 m_request.offset = 0;
381 m_request.disablePassDlg = config()->readBoolEntry(
"DisablePassDlg",
false);
382 m_request.allowCompressedPage = config()->readBoolEntry(
"AllowCompressedPage",
true);
383 m_request.id = metaData(
"request-id");
386 if ( config()->readBoolEntry(
"SendUserAgent",
true) )
387 m_request.userAgent = metaData(
"UserAgent");
389 m_request.userAgent = TQString::null;
394 if ( m_request.bUseCache )
398 if ( m_bIsSSL && m_bUseProxy && m_proxyURL.protocol() !=
"https" &&
399 m_proxyURL.protocol() !=
"webdavs")
401 m_bNeedTunnel =
true;
402 setRealHost( m_request.hostname );
403 kdDebug(7113) <<
"(" << m_pid <<
") SSL tunnel: Setting real hostname to: "
404 << m_request.hostname << endl;
408 m_bNeedTunnel =
false;
409 setRealHost( TQString::null);
413 m_prevResponseCode = 0;
415 m_strRealm = TQString::null;
416 m_strAuthorization = TQString::null;
417 Authentication = AUTH_None;
420 m_proxyConnTimeout = proxyConnectTimeout();
421 m_remoteConnTimeout = connectTimeout();
422 m_remoteRespTimeout = responseTimeout();
428 setMetaData(
"referrer", m_request.referrer);
434 m_keepAliveTimeout = 0;
435 m_bUnauthorized =
false;
445 m_bFirstRequest =
false;
448 void HTTPProtocol::setHost(
const TQString& host,
int port,
449 const TQString& user,
const TQString& pass )
452 if ( m_request.hostname != host )
453 m_davHostOk = m_davHostUnsupported =
false;
456 if (host.find(
':') == -1)
458 m_request.hostname = host;
459 m_request.encoded_hostname = KIDNA::toAscii(host);
463 m_request.hostname = host;
464 int pos = host.find(
'%');
466 m_request.encoded_hostname =
'[' + host +
']';
469 m_request.encoded_hostname =
'[' + host.left(pos) +
']';
471 m_request.port = (port == 0) ? m_iDefaultPort : port;
472 m_request.user = user;
473 m_request.passwd = pass;
475 m_bIsTunneled =
false;
477 kdDebug(7113) <<
"(" << m_pid <<
") Hostname is now: " << m_request.hostname <<
478 " (" << m_request.encoded_hostname <<
")" <<endl;
481 bool HTTPProtocol::checkRequestURL(
const KURL& u )
483 kdDebug (7113) <<
"(" << m_pid <<
") HTTPProtocol::checkRequestURL: " << u.url() << endl;
487 if (m_request.hostname.isEmpty())
489 error( KIO::ERR_UNKNOWN_HOST, i18n(
"No host specified."));
493 if (u.path().isEmpty())
502 if ( m_protocol != u.protocol().latin1() )
504 short unsigned int oldDefaultPort = m_iDefaultPort;
505 m_protocol = u.protocol().latin1();
506 reparseConfiguration();
507 if ( m_iDefaultPort != oldDefaultPort &&
508 m_request.port == oldDefaultPort )
509 m_request.port = m_iDefaultPort;
512 resetSessionSettings();
516 void HTTPProtocol::retrieveContent(
bool dataInternal )
518 kdDebug (7113) <<
"(" << m_pid <<
") HTTPProtocol::retrieveContent " << endl;
519 if ( !retrieveHeader(
false ) )
526 if ( !readBody( dataInternal ) && m_bError )
530 httpClose(m_bKeepAlive);
536 if ((m_responseCode == 204) &&
537 ((m_request.method == HTTP_GET) || (m_request.method == HTTP_POST)))
538 error(ERR_NO_CONTENT,
"");
544 bool HTTPProtocol::retrieveHeader(
bool close_connection )
546 kdDebug (7113) <<
"(" << m_pid <<
") HTTPProtocol::retrieveHeader " << endl;
552 resetResponseSettings();
560 kdDebug(7113) <<
"(" << m_pid <<
") Re-establishing SSL tunnel..." << endl;
561 httpCloseConnection();
568 kdDebug(7113) <<
"(" << m_pid <<
") Previous Response: "
569 << m_prevResponseCode << endl;
570 kdDebug(7113) <<
"(" << m_pid <<
") Current Response: "
571 << m_responseCode << endl;
573 if (isSSLTunnelEnabled() && m_bIsSSL && !m_bUnauthorized && !m_bError)
576 if ( m_responseCode < 400 )
578 kdDebug(7113) <<
"(" << m_pid <<
") Unset tunneling flag!" << endl;
579 setEnableSSLTunnel(
false );
580 m_bIsTunneled =
true;
582 m_responseCode = m_prevResponseCode;
587 if ( !m_request.bErrorPage )
589 kdDebug(7113) <<
"(" << m_pid <<
") Sending an error message!" << endl;
590 error( ERR_UNKNOWN_PROXY_HOST, m_proxyURL.host() );
594 kdDebug(7113) <<
"(" << m_pid <<
") Sending an error page!" << endl;
598 if (m_responseCode < 400 && (m_prevResponseCode == 401 ||
599 m_prevResponseCode == 407))
606 if (!m_bufPOST.isEmpty())
609 kdDebug(7113) <<
"(" << m_pid <<
") HTTP::retreiveHeader: Cleared POST "
613 if ( close_connection )
615 httpClose(m_bKeepAlive);
622 void HTTPProtocol::stat(
const KURL& url)
624 kdDebug(7113) <<
"(" << m_pid <<
") HTTPProtocol::stat " << url.prettyURL()
627 if ( !checkRequestURL( url ) )
630 if ( m_protocol !=
"webdav" && m_protocol !=
"webdavs" )
632 TQString statSide = metaData(TQString::fromLatin1(
"statSide"));
633 if ( statSide !=
"source" )
636 error( ERR_DOES_NOT_EXIST, url.prettyURL() );
643 atom.m_uds = KIO::UDS_NAME;
644 atom.m_str = url.fileName();
645 entry.append( atom );
647 atom.m_uds = KIO::UDS_FILE_TYPE;
648 atom.m_long = S_IFREG;
649 entry.append( atom );
651 atom.m_uds = KIO::UDS_ACCESS;
652 atom.m_long = S_IRUSR | S_IRGRP | S_IROTH;
653 entry.append( atom );
663 void HTTPProtocol::listDir(
const KURL& url )
665 kdDebug(7113) <<
"(" << m_pid <<
") HTTPProtocol::listDir " << url.url()
668 if ( !checkRequestURL( url ) )
671 if (!url.protocol().startsWith(
"webdav")) {
672 error(ERR_UNSUPPORTED_ACTION, url.prettyURL());
676 davStatList( url,
false );
679 void HTTPProtocol::davSetRequest(
const TQCString& requestXML )
682 m_bufPOST = requestXML;
684 if (m_bufPOST.size())
685 m_bufPOST.truncate( m_bufPOST.size() - 1 );
688 void HTTPProtocol::davStatList(
const KURL& url,
bool stat )
698 TQString query = metaData(
"davSearchQuery");
699 if ( !query.isEmpty() )
701 TQCString request =
"<?xml version=\"1.0\"?>\r\n";
702 request.append(
"<D:searchrequest xmlns:D=\"DAV:\">\r\n" );
703 request.append( query.utf8() );
704 request.append(
"</D:searchrequest>\r\n" );
706 davSetRequest( request );
710 request =
"<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
711 "<D:propfind xmlns:D=\"DAV:\">";
714 if ( hasMetaData(
"davRequestResponse" ) )
715 request += metaData(
"davRequestResponse" ).utf8();
718 request +=
"<D:prop>"
720 "<D:getcontentlength/>"
723 "<D:getcontentlanguage/>"
724 "<D:getcontenttype/>"
726 "<D:getlastmodified/>"
733 request +=
"</D:propfind>";
735 davSetRequest( request );
739 m_request.method = query.isEmpty() ? DAV_PROPFIND : DAV_SEARCH;
740 m_request.query = TQString::null;
741 m_request.cache = CC_Reload;
742 m_request.doProxy = m_bUseProxy;
743 m_request.davData.depth = stat ? 0 : 1;
745 m_request.url.adjustPath(+1);
747 retrieveContent(
true );
755 TQDomDocument multiResponse;
756 multiResponse.setContent( m_bufWebDavData,
true );
758 bool hasResponse =
false;
760 for ( TQDomNode n = multiResponse.documentElement().firstChild();
761 !n.isNull(); n = n.nextSibling())
763 TQDomElement thisResponse = n.toElement();
764 if (thisResponse.isNull())
769 TQDomElement href = thisResponse.namedItem(
"href" ).toElement();
770 if ( !href.isNull() )
774 TQString urlStr = href.text();
776 int encoding = remoteEncoding()->encodingMib();
777 if ((encoding == 106) && (!KStringHandler::isUtf8(KURL::decode_string(urlStr, 4).latin1())))
780 TQUrl::decode(urlStr);
784 KURL thisURL ( urlStr, encoding );
786 atom.m_uds = KIO::UDS_NAME;
788 if ( thisURL.isValid() ) {
790 if ( !stat && thisURL.path(+1).length() == url.path(+1).length() )
793 atom.m_str = thisURL.fileName();
796 atom.m_str = href.text();
799 entry.append( atom );
801 TQDomNodeList propstats = thisResponse.elementsByTagName(
"propstat" );
803 davParsePropstats( propstats, entry );
814 listEntry( entry,
false );
819 kdDebug(7113) <<
"Error: no URL contained in response to PROPFIND on "
820 << url.prettyURL() << endl;
824 if ( stat || !hasResponse )
826 error( ERR_DOES_NOT_EXIST, url.prettyURL() );
830 listEntry( entry,
true );
835 void HTTPProtocol::davGeneric(
const KURL& url, KIO::HTTP_METHOD method )
837 kdDebug(7113) <<
"(" << m_pid <<
") HTTPProtocol::davGeneric " << url.url()
840 if ( !checkRequestURL( url ) )
848 m_request.method = method;
849 m_request.query = TQString::null;
850 m_request.cache = CC_Reload;
851 m_request.doProxy = m_bUseProxy;
853 retrieveContent(
false );
856 int HTTPProtocol::codeFromResponse(
const TQString& response )
858 int firstSpace = response.find(
' ' );
859 int secondSpace = response.find(
' ', firstSpace + 1 );
860 return response.mid( firstSpace + 1, secondSpace - firstSpace - 1 ).toInt();
863 void HTTPProtocol::davParsePropstats(
const TQDomNodeList& propstats, UDSEntry& entry )
867 bool foundExecutable =
false;
868 bool isDirectory =
false;
870 uint supportedLockCount = 0;
872 for ( uint i = 0; i < propstats.count(); i++)
874 TQDomElement propstat = propstats.item(i).toElement();
876 TQDomElement status = propstat.namedItem(
"status" ).toElement();
877 if ( status.isNull() )
880 kdDebug(7113) <<
"Error, no status code in this propstat" << endl;
884 int code = codeFromResponse( status.text() );
888 kdDebug(7113) <<
"Warning: status code " << code <<
" (this may mean that some properties are unavailable" << endl;
892 TQDomElement prop = propstat.namedItem(
"prop" ).toElement();
895 kdDebug(7113) <<
"Error: no prop segment in this propstat." << endl;
899 if ( hasMetaData(
"davRequestResponse" ) )
901 atom.m_uds = KIO::UDS_XML_PROPERTIES;
903 doc.appendChild(prop);
904 atom.m_str = doc.toString();
905 entry.append( atom );
908 for ( TQDomNode n = prop.firstChild(); !n.isNull(); n = n.nextSibling() )
910 TQDomElement
property = n.toElement();
911 if (property.isNull())
914 if ( property.namespaceURI() !=
"DAV:" )
920 if ( property.tagName() ==
"creationdate" )
923 atom.m_uds = KIO::UDS_CREATION_TIME;
924 atom.m_long = parseDateTime( property.text(),
property.attribute(
"dt") );
925 entry.append( atom );
927 else if ( property.tagName() ==
"getcontentlength" )
930 atom.m_uds = KIO::UDS_SIZE;
931 atom.m_long =
property.text().toULong();
932 entry.append( atom );
934 else if ( property.tagName() ==
"displayname" )
937 setMetaData(
"davDisplayName", property.text() );
939 else if ( property.tagName() ==
"source" )
942 TQDomElement source =
property.namedItem(
"link" ).toElement()
943 .namedItem(
"dst" ).toElement();
944 if ( !source.isNull() )
945 setMetaData(
"davSource", source.text() );
947 else if ( property.tagName() ==
"getcontentlanguage" )
950 setMetaData(
"davContentLanguage", property.text() );
952 else if ( property.tagName() ==
"getcontenttype" )
957 if ( property.text() ==
"httpd/unix-directory" )
963 mimeType =
property.text();
966 else if ( property.tagName() ==
"executable" )
969 if ( property.text() ==
"T" )
970 foundExecutable =
true;
973 else if ( property.tagName() ==
"getlastmodified" )
976 atom.m_uds = KIO::UDS_MODIFICATION_TIME;
977 atom.m_long = parseDateTime( property.text(),
property.attribute(
"dt") );
978 entry.append( atom );
981 else if ( property.tagName() ==
"getetag" )
984 setMetaData(
"davEntityTag", property.text() );
986 else if ( property.tagName() ==
"supportedlock" )
989 for ( TQDomNode n2 = property.firstChild(); !n2.isNull(); n2 = n2.nextSibling() )
991 TQDomElement lockEntry = n2.toElement();
992 if ( lockEntry.tagName() ==
"lockentry" )
994 TQDomElement lockScope = lockEntry.namedItem(
"lockscope" ).toElement();
995 TQDomElement lockType = lockEntry.namedItem(
"locktype" ).toElement();
996 if ( !lockScope.isNull() && !lockType.isNull() )
999 supportedLockCount++;
1000 TQString scope = lockScope.firstChild().toElement().tagName();
1001 TQString type = lockType.firstChild().toElement().tagName();
1003 setMetaData( TQString(
"davSupportedLockScope%1").arg(supportedLockCount), scope );
1004 setMetaData( TQString(
"davSupportedLockType%1").arg(supportedLockCount), type );
1009 else if ( property.tagName() ==
"lockdiscovery" )
1012 davParseActiveLocks( property.elementsByTagName(
"activelock" ), lockCount );
1014 else if ( property.tagName() ==
"resourcetype" )
1017 if ( !property.namedItem(
"collection" ).toElement().isNull() )
1025 kdDebug(7113) <<
"Found unknown webdav property: " <<
property.tagName() << endl;
1030 setMetaData(
"davLockCount", TQString(
"%1").arg(lockCount) );
1031 setMetaData(
"davSupportedLockCount", TQString(
"%1").arg(supportedLockCount) );
1033 atom.m_uds = KIO::UDS_FILE_TYPE;
1034 atom.m_long = isDirectory ? S_IFDIR : S_IFREG;
1035 entry.append( atom );
1037 if ( foundExecutable || isDirectory )
1040 atom.m_uds = KIO::UDS_ACCESS;
1046 atom.m_uds = KIO::UDS_ACCESS;
1051 if ( !isDirectory && !mimeType.isEmpty() )
1053 atom.m_uds = KIO::UDS_MIME_TYPE;
1054 atom.m_str = mimeType;
1055 entry.append( atom );
1059 void HTTPProtocol::davParseActiveLocks(
const TQDomNodeList& activeLocks,
1062 for ( uint i = 0; i < activeLocks.count(); i++ )
1064 TQDomElement activeLock = activeLocks.item(i).toElement();
1068 TQDomElement lockScope = activeLock.namedItem(
"lockscope" ).toElement();
1069 TQDomElement lockType = activeLock.namedItem(
"locktype" ).toElement();
1070 TQDomElement lockDepth = activeLock.namedItem(
"depth" ).toElement();
1072 TQDomElement lockOwner = activeLock.namedItem(
"owner" ).toElement();
1073 TQDomElement lockTimeout = activeLock.namedItem(
"timeout" ).toElement();
1074 TQDomElement lockToken = activeLock.namedItem(
"locktoken" ).toElement();
1076 if ( !lockScope.isNull() && !lockType.isNull() && !lockDepth.isNull() )
1080 TQString scope = lockScope.firstChild().toElement().tagName();
1081 TQString type = lockType.firstChild().toElement().tagName();
1082 TQString depth = lockDepth.text();
1084 setMetaData( TQString(
"davLockScope%1").arg( lockCount ), scope );
1085 setMetaData( TQString(
"davLockType%1").arg( lockCount ), type );
1086 setMetaData( TQString(
"davLockDepth%1").arg( lockCount ), depth );
1088 if ( !lockOwner.isNull() )
1089 setMetaData( TQString(
"davLockOwner%1").arg( lockCount ), lockOwner.text() );
1091 if ( !lockTimeout.isNull() )
1092 setMetaData( TQString(
"davLockTimeout%1").arg( lockCount ), lockTimeout.text() );
1094 if ( !lockToken.isNull() )
1096 TQDomElement tokenVal = lockScope.namedItem(
"href" ).toElement();
1097 if ( !tokenVal.isNull() )
1098 setMetaData( TQString(
"davLockToken%1").arg( lockCount ), tokenVal.text() );
1104 long HTTPProtocol::parseDateTime(
const TQString& input,
const TQString& type )
1106 if ( type ==
"dateTime.tz" )
1108 return KRFCDate::parseDateISO8601( input );
1110 else if ( type ==
"dateTime.rfc1123" )
1112 return KRFCDate::parseDate( input );
1116 time_t time = KRFCDate::parseDate( input );
1120 return KRFCDate::parseDateISO8601( input );
1123 TQString HTTPProtocol::davProcessLocks()
1125 if ( hasMetaData(
"davLockCount" ) )
1127 TQString response(
"If:");
1129 numLocks = metaData(
"davLockCount" ).toInt();
1130 bool bracketsOpen =
false;
1131 for (
int i = 0; i < numLocks; i++ )
1133 if ( hasMetaData( TQString(
"davLockToken%1").arg(i) ) )
1135 if ( hasMetaData( TQString(
"davLockURL%1").arg(i) ) )
1140 bracketsOpen =
false;
1142 response +=
" <" + metaData( TQString(
"davLockURL%1").arg(i) ) +
">";
1145 if ( !bracketsOpen )
1148 bracketsOpen =
true;
1155 if ( hasMetaData( TQString(
"davLockNot%1").arg(i) ) )
1158 response +=
"<" + metaData( TQString(
"davLockToken%1").arg(i) ) +
">";
1169 return TQString::null;
1172 bool HTTPProtocol::davHostOk()
1180 kdDebug(7113) <<
"(" << m_pid <<
") " << k_funcinfo <<
" true" << endl;
1183 else if ( m_davHostUnsupported )
1185 kdDebug(7113) <<
"(" << m_pid <<
") " << k_funcinfo <<
" false" << endl;
1190 m_request.method = HTTP_OPTIONS;
1193 m_request.path =
"*";
1194 m_request.query = TQString::null;
1195 m_request.cache = CC_Reload;
1196 m_request.doProxy = m_bUseProxy;
1199 m_davCapabilities.clear();
1201 retrieveHeader(
false);
1203 if (m_davCapabilities.count())
1205 for (uint i = 0; i < m_davCapabilities.count(); i++)
1208 uint verNo = m_davCapabilities[i].toUInt(&ok);
1209 if (ok && verNo > 0 && verNo < 3)
1212 kdDebug(7113) <<
"Server supports DAV version " << verNo <<
"." << endl;
1220 m_davHostUnsupported =
true;
1227 void HTTPProtocol::davFinished()
1230 httpClose(m_bKeepAlive);
1234 void HTTPProtocol::mkdir(
const KURL& url,
int )
1236 kdDebug(7113) <<
"(" << m_pid <<
") HTTPProtocol::mkdir " << url.url()
1239 if ( !checkRequestURL( url ) )
1242 m_request.method = DAV_MKCOL;
1243 m_request.path = url.path();
1244 m_request.query = TQString::null;
1245 m_request.cache = CC_Reload;
1246 m_request.doProxy = m_bUseProxy;
1248 retrieveHeader(
false );
1250 if ( m_responseCode == 201 )
1256 void HTTPProtocol::get(
const KURL& url )
1258 kdDebug(7113) <<
"(" << m_pid <<
") HTTPProtocol::get " << url.url()
1261 if ( !checkRequestURL( url ) )
1264 m_request.method = HTTP_GET;
1265 m_request.path = url.path();
1266 m_request.query = url.query();
1268 TQString tmp = metaData(
"cache");
1270 m_request.cache = parseCacheControl(tmp);
1272 m_request.cache = DEFAULT_CACHE_CONTROL;
1274 m_request.passwd = url.pass();
1275 m_request.user = url.user();
1276 m_request.doProxy = m_bUseProxy;
1281 void HTTPProtocol::put(
const KURL &url,
int,
bool overwrite,
bool)
1283 kdDebug(7113) <<
"(" << m_pid <<
") HTTPProtocol::put " << url.prettyURL()
1286 if ( !checkRequestURL( url ) )
1290 if (!overwrite && m_protocol.left(6) ==
"webdav") {
1296 request =
"<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
1297 "<D:propfind xmlns:D=\"DAV:\"><D:prop>"
1299 "<D:getcontentlength/>"
1302 "</D:prop></D:propfind>";
1304 davSetRequest( request );
1307 m_request.method = DAV_PROPFIND;
1308 m_request.query = TQString::null;
1309 m_request.cache = CC_Reload;
1310 m_request.doProxy = m_bUseProxy;
1311 m_request.davData.depth = 0;
1313 retrieveContent(
true);
1315 if (m_responseCode == 207) {
1316 error(ERR_FILE_ALREADY_EXIST, TQString::null);
1323 m_request.method = HTTP_PUT;
1324 m_request.path = url.path();
1325 m_request.query = TQString::null;
1326 m_request.cache = CC_Reload;
1327 m_request.doProxy = m_bUseProxy;
1329 retrieveHeader(
false );
1331 kdDebug(7113) <<
"(" << m_pid <<
") HTTPProtocol::put error = " << m_bError << endl;
1335 kdDebug(7113) <<
"(" << m_pid <<
") HTTPProtocol::put responseCode = " << m_responseCode << endl;
1339 if ( (m_responseCode >= 200) && (m_responseCode < 300) )
1345 void HTTPProtocol::copy(
const KURL& src,
const KURL& dest,
int,
bool overwrite )
1347 kdDebug(7113) <<
"(" << m_pid <<
") HTTPProtocol::copy " << src.prettyURL()
1348 <<
" -> " << dest.prettyURL() << endl;
1350 if ( !checkRequestURL( dest ) || !checkRequestURL( src ) )
1354 KURL newDest = dest;
1355 if (newDest.protocol() ==
"webdavs")
1356 newDest.setProtocol(
"https");
1358 newDest.setProtocol(
"http");
1360 m_request.method = DAV_COPY;
1361 m_request.path = src.path();
1362 m_request.davData.desturl = newDest.url();
1363 m_request.davData.overwrite = overwrite;
1364 m_request.query = TQString::null;
1365 m_request.cache = CC_Reload;
1366 m_request.doProxy = m_bUseProxy;
1368 retrieveHeader(
false );
1371 if ( m_responseCode == 201 || m_responseCode == 204 )
1377 void HTTPProtocol::rename(
const KURL& src,
const KURL& dest,
bool overwrite )
1379 kdDebug(7113) <<
"(" << m_pid <<
") HTTPProtocol::rename " << src.prettyURL()
1380 <<
" -> " << dest.prettyURL() << endl;
1382 if ( !checkRequestURL( dest ) || !checkRequestURL( src ) )
1386 KURL newDest = dest;
1387 if (newDest.protocol() ==
"webdavs")
1388 newDest.setProtocol(
"https");
1390 newDest.setProtocol(
"http");
1392 m_request.method = DAV_MOVE;
1393 m_request.path = src.path();
1394 m_request.davData.desturl = newDest.url();
1395 m_request.davData.overwrite = overwrite;
1396 m_request.query = TQString::null;
1397 m_request.cache = CC_Reload;
1398 m_request.doProxy = m_bUseProxy;
1400 retrieveHeader(
false );
1402 if ( m_responseCode == 301 )
1408 if (m_redirectLocation.protocol() ==
"https")
1409 m_redirectLocation.setProtocol(
"webdavs");
1411 m_redirectLocation.setProtocol(
"webdav");
1413 if ( !checkRequestURL( m_redirectLocation ) )
1416 m_request.method = DAV_MOVE;
1417 m_request.path = m_redirectLocation.path();
1418 m_request.davData.desturl = newDest.url();
1419 m_request.davData.overwrite = overwrite;
1420 m_request.query = TQString::null;
1421 m_request.cache = CC_Reload;
1422 m_request.doProxy = m_bUseProxy;
1424 retrieveHeader(
false );
1427 if ( m_responseCode == 201 )
1433 void HTTPProtocol::del(
const KURL& url,
bool )
1435 kdDebug(7113) <<
"(" << m_pid <<
") HTTPProtocol::del " << url.prettyURL()
1438 if ( !checkRequestURL( url ) )
1441 m_request.method = HTTP_DELETE;
1442 m_request.path = url.path();
1443 m_request.query = TQString::null;
1444 m_request.cache = CC_Reload;
1445 m_request.doProxy = m_bUseProxy;
1447 retrieveHeader(
false );
1451 if ( m_responseCode == 200 || m_responseCode == 204 )
1457 void HTTPProtocol::post(
const KURL& url )
1459 kdDebug(7113) <<
"(" << m_pid <<
") HTTPProtocol::post "
1460 << url.prettyURL() << endl;
1462 if ( !checkRequestURL( url ) )
1465 m_request.method = HTTP_POST;
1466 m_request.path = url.path();
1467 m_request.query = url.query();
1468 m_request.cache = CC_Reload;
1469 m_request.doProxy = m_bUseProxy;
1474 void HTTPProtocol::davLock(
const KURL& url,
const TQString& scope,
1475 const TQString& type,
const TQString& owner )
1477 kdDebug(7113) <<
"(" << m_pid <<
") HTTPProtocol::davLock "
1478 << url.prettyURL() << endl;
1480 if ( !checkRequestURL( url ) )
1483 m_request.method = DAV_LOCK;
1484 m_request.path = url.path();
1485 m_request.query = TQString::null;
1486 m_request.cache = CC_Reload;
1487 m_request.doProxy = m_bUseProxy;
1490 TQDomDocument lockReq;
1492 TQDomElement lockInfo = lockReq.createElementNS(
"DAV:",
"lockinfo" );
1493 lockReq.appendChild( lockInfo );
1495 TQDomElement lockScope = lockReq.createElement(
"lockscope" );
1496 lockInfo.appendChild( lockScope );
1498 lockScope.appendChild( lockReq.createElement( scope ) );
1500 TQDomElement lockType = lockReq.createElement(
"locktype" );
1501 lockInfo.appendChild( lockType );
1503 lockType.appendChild( lockReq.createElement( type ) );
1505 if ( !owner.isNull() ) {
1506 TQDomElement ownerElement = lockReq.createElement(
"owner" );
1507 lockReq.appendChild( ownerElement );
1509 TQDomElement ownerHref = lockReq.createElement(
"href" );
1510 ownerElement.appendChild( ownerHref );
1512 ownerHref.appendChild( lockReq.createTextNode( owner ) );
1516 m_bufPOST = lockReq.toCString();
1518 retrieveContent(
true );
1520 if ( m_responseCode == 200 ) {
1522 TQDomDocument multiResponse;
1523 multiResponse.setContent( m_bufWebDavData,
true );
1525 TQDomElement prop = multiResponse.documentElement().namedItem(
"prop" ).toElement();
1527 TQDomElement lockdiscovery = prop.namedItem(
"lockdiscovery" ).toElement();
1530 davParseActiveLocks( lockdiscovery.elementsByTagName(
"activelock" ), lockCount );
1532 setMetaData(
"davLockCount", TQString(
"%1").arg( lockCount ) );
1540 void HTTPProtocol::davUnlock(
const KURL& url )
1542 kdDebug(7113) <<
"(" << m_pid <<
") HTTPProtocol::davUnlock "
1543 << url.prettyURL() << endl;
1545 if ( !checkRequestURL( url ) )
1548 m_request.method = DAV_UNLOCK;
1549 m_request.path = url.path();
1550 m_request.query = TQString::null;
1551 m_request.cache = CC_Reload;
1552 m_request.doProxy = m_bUseProxy;
1554 retrieveContent(
true );
1556 if ( m_responseCode == 200 )
1562 TQString HTTPProtocol::davError(
int code , TQString url )
1564 bool callError =
false;
1566 code = m_responseCode;
1573 if ( !url.isNull() )
1574 url = m_request.url.url();
1576 TQString action, errorString;
1580 TQString ow = i18n(
"Otherwise, the request would have succeeded." );
1582 switch ( m_request.method ) {
1584 action = i18n(
"retrieve property values" );
1587 action = i18n(
"set property values" );
1590 action = i18n(
"create the requested folder" );
1593 action = i18n(
"copy the specified file or folder" );
1596 action = i18n(
"move the specified file or folder" );
1599 action = i18n(
"search in the specified folder" );
1602 action = i18n(
"lock the specified file or folder" );
1605 action = i18n(
"unlock the specified file or folder" );
1608 action = i18n(
"delete the specified file or folder" );
1611 action = i18n(
"query the server's capabilities" );
1614 action = i18n(
"retrieve the contents of the specified file or folder" );
1625 kError = ERR_INTERNAL;
1626 errorString = i18n(
"An unexpected error (%1) occurred while attempting to %2.")
1627 .arg( code ).arg( action );
1633 kError = ERR_UNSUPPORTED_PROTOCOL;
1634 errorString = i18n(
"The server does not support the WebDAV protocol.");
1644 if ( !readBody(
true ) && m_bError )
1645 return TQString::null;
1647 TQStringList errors;
1648 TQDomDocument multiResponse;
1650 multiResponse.setContent( m_bufWebDavData,
true );
1652 TQDomElement multistatus = multiResponse.documentElement().namedItem(
"multistatus" ).toElement();
1654 TQDomNodeList responses = multistatus.elementsByTagName(
"response" );
1656 for (uint i = 0; i < responses.count(); i++)
1661 TQDomElement response = responses.item(i).toElement();
1662 TQDomElement code = response.namedItem(
"status" ).toElement();
1664 if ( !code.isNull() )
1666 errCode = codeFromResponse( code.text() );
1667 TQDomElement href = response.namedItem(
"href" ).toElement();
1668 if ( !href.isNull() )
1669 errUrl = href.text();
1670 errors << davError( errCode, errUrl );
1675 errorString = i18n(
"An error occurred while attempting to %1, %2. A "
1676 "summary of the reasons is below.<ul>").arg( action ).arg( url );
1678 for ( TQStringList::Iterator it = errors.begin(); it != errors.end(); ++it )
1679 errorString +=
"<li>" + *it +
"</li>";
1681 errorString +=
"</ul>";
1686 kError = ERR_ACCESS_DENIED;
1687 errorString = i18n(
"Access was denied while attempting to %1.").arg( action );
1691 if ( m_request.method == DAV_MKCOL )
1693 kError = ERR_DIR_ALREADY_EXIST;
1694 errorString = i18n(
"The specified folder already exists.");
1699 kError = ERR_ACCESS_DENIED;
1700 errorString = i18n(
"A resource cannot be created at the destination "
1701 "until one or more intermediate collections (folders) "
1702 "have been created.");
1706 if ( m_request.method == DAV_COPY || m_request.method == DAV_MOVE )
1708 kError = ERR_ACCESS_DENIED;
1709 errorString = i18n(
"The server was unable to maintain the liveness of "
1710 "the properties listed in the propertybehavior XML "
1711 "element or you attempted to overwrite a file while "
1712 "requesting that files are not overwritten. %1")
1716 else if ( m_request.method == DAV_LOCK )
1718 kError = ERR_ACCESS_DENIED;
1719 errorString = i18n(
"The requested lock could not be granted. %1").arg( ow );
1724 kError = ERR_ACCESS_DENIED;
1725 errorString = i18n(
"The server does not support the request type of the body.");
1729 kError = ERR_ACCESS_DENIED;
1730 errorString = i18n(
"Unable to %1 because the resource is locked.").arg( action );
1734 errorString = i18n(
"This action was prevented by another error.");
1738 if ( m_request.method == DAV_COPY || m_request.method == DAV_MOVE )
1740 kError = ERR_WRITE_ACCESS_DENIED;
1741 errorString = i18n(
"Unable to %1 because the destination server refuses "
1742 "to accept the file or folder.").arg( action );
1747 kError = ERR_DISK_FULL;
1748 errorString = i18n(
"The destination resource does not have sufficient space "
1749 "to record the state of the resource after the execution "
1758 error( ERR_SLAVE_DEFINED, errorString );
1763 void HTTPProtocol::httpError()
1765 TQString action, errorString;
1768 switch ( m_request.method ) {
1770 action = i18n(
"upload %1" ).arg(m_request.url.prettyURL());
1778 kError = ERR_INTERNAL;
1779 errorString = i18n(
"An unexpected error (%1) occurred while attempting to %2.")
1780 .arg( m_responseCode ).arg( action );
1782 switch ( m_responseCode )
1789 kError = ERR_ACCESS_DENIED;
1790 errorString = i18n(
"Access was denied while attempting to %1.").arg( action );
1794 kError = ERR_ACCESS_DENIED;
1795 errorString = i18n(
"A resource cannot be created at the destination "
1796 "until one or more intermediate collections (folders) "
1797 "have been created.");
1801 kError = ERR_ACCESS_DENIED;
1802 errorString = i18n(
"Unable to %1 because the resource is locked.").arg( action );
1806 kError = ERR_WRITE_ACCESS_DENIED;
1807 errorString = i18n(
"Unable to %1 because the destination server refuses "
1808 "to accept the file or folder.").arg( action );
1812 kError = ERR_DISK_FULL;
1813 errorString = i18n(
"The destination resource does not have sufficient space "
1814 "to record the state of the resource after the execution "
1822 error( ERR_SLAVE_DEFINED, errorString );
1825 bool HTTPProtocol::isOffline(
const KURL &url)
1827 const int NetWorkStatusUnknown = 1;
1828 const int NetWorkStatusOnline = 8;
1829 TQCString replyType;
1833 TQDataStream stream(params, IO_WriteOnly);
1835 if ( url.host() == TQString::fromLatin1(
"localhost") || url.host() == TQString::fromLatin1(
"127.0.0.1") || url.host() == TQString::fromLatin1(
"::") ) {
1838 if ( dcopClient()->call(
"kded",
"networkstatus",
"status()",
1839 params, replyType, reply ) && (replyType ==
"int") )
1842 TQDataStream stream2( reply, IO_ReadOnly );
1844 kdDebug(7113) <<
"(" << m_pid <<
") networkstatus status = " << result << endl;
1845 return (result != NetWorkStatusUnknown) && (result != NetWorkStatusOnline);
1847 kdDebug(7113) <<
"(" << m_pid <<
") networkstatus <unreachable>" << endl;
1851 void HTTPProtocol::multiGet(
const TQByteArray &data)
1853 TQDataStream stream(data, IO_ReadOnly);
1857 kdDebug(7113) <<
"(" << m_pid <<
") HTTPProtcool::multiGet n = " << n << endl;
1859 HTTPRequest saveRequest;
1861 saveRequest = m_request;
1864 for(
unsigned i = 0; i < n; i++)
1867 stream >> url >> mIncomingMetaData;
1869 if ( !checkRequestURL( url ) )
1872 kdDebug(7113) <<
"(" << m_pid <<
") HTTPProtocol::multi_get " << url.url() << endl;
1874 m_request.method = HTTP_GET;
1875 m_request.path = url.path();
1876 m_request.query = url.query();
1877 TQString tmp = metaData(
"cache");
1879 m_request.cache = parseCacheControl(tmp);
1881 m_request.cache = DEFAULT_CACHE_CONTROL;
1883 m_request.passwd = url.pass();
1884 m_request.user = url.user();
1885 m_request.doProxy = m_bUseProxy;
1887 HTTPRequest *newRequest =
new HTTPRequest(m_request);
1888 m_requestQueue.append(newRequest);
1892 m_request = saveRequest;
1897 while(!m_requestQueue.isEmpty())
1899 HTTPRequest *request = m_requestQueue.take(0);
1900 m_request = *request;
1908 ssize_t HTTPProtocol::write (
const void *_buf,
size_t nbytes)
1911 const char* buf =
static_cast<const char*
>(_buf);
1912 while ( nbytes > 0 )
1914 int n = TCPSlaveBase::write(buf, nbytes);
1922 if (n < 0 && ((errno == EINTR) || (errno == EAGAIN)))
1936 void HTTPProtocol::setRewindMarker()
1941 void HTTPProtocol::rewind()
1943 m_linePtrUnget = m_rewindBuf,
1944 m_lineCountUnget = m_rewindCount;
1949 char *HTTPProtocol::gets (
char *s,
int size)
1953 char mybuf[2]={0,0};
1961 if (m_rewindCount <
sizeof(m_rewindBuf))
1962 m_rewindBuf[m_rewindCount++] = *mybuf;
1967 if ((*mybuf ==
'\n') || !*mybuf)
1978 ssize_t HTTPProtocol::read (
void *b,
size_t nbytes)
1982 if (m_lineCountUnget > 0)
1984 ret = ( nbytes < m_lineCountUnget ? nbytes : m_lineCountUnget );
1985 m_lineCountUnget -= ret;
1986 memcpy(b, m_linePtrUnget, ret);
1987 m_linePtrUnget += ret;
1992 if (m_lineCount > 0)
1994 ret = ( nbytes < m_lineCount ? nbytes : m_lineCount );
1996 memcpy(b, m_linePtr, ret);
2003 ret = read(m_lineBuf, 1024);
2004 m_linePtr = m_lineBuf;
2016 ret = TCPSlaveBase::read( b, nbytes);
2020 }
while ((ret == -1) && (errno == EAGAIN || errno == EINTR));
2025 void HTTPProtocol::httpCheckConnection()
2027 kdDebug(7113) <<
"(" << m_pid <<
") HTTPProtocol::httpCheckConnection: " <<
2028 " Socket status: " << m_iSock <<
2029 " Keep Alive: " << m_bKeepAlive <<
2030 " First: " << m_bFirstRequest << endl;
2032 if ( !m_bFirstRequest && (m_iSock != -1) )
2034 bool closeDown =
false;
2035 if ( !isConnectionValid())
2037 kdDebug(7113) <<
"(" << m_pid <<
") Connection lost!" << endl;
2040 else if ( m_request.method != HTTP_GET )
2044 else if ( !m_state.doProxy && !m_request.doProxy )
2046 if (m_state.hostname != m_request.hostname ||
2047 m_state.port != m_request.port ||
2048 m_state.user != m_request.user ||
2049 m_state.passwd != m_request.passwd)
2055 if ( !(m_request.doProxy && m_state.doProxy) )
2060 httpCloseConnection();
2064 m_state.hostname = m_request.hostname;
2065 m_state.encoded_hostname = m_request.encoded_hostname;
2066 m_state.port = m_request.port;
2067 m_state.user = m_request.user;
2068 m_state.passwd = m_request.passwd;
2069 m_state.doProxy = m_request.doProxy;
2072 bool HTTPProtocol::httpOpenConnection()
2077 kdDebug(7113) <<
"(" << m_pid <<
") HTTPProtocol::httpOpenConnection" << endl;
2079 setBlockConnection(
true );
2081 KSocks::self()->disableSocks();
2083 if ( m_state.doProxy )
2085 TQString proxy_host = m_proxyURL.host();
2086 int proxy_port = m_proxyURL.port();
2088 kdDebug(7113) <<
"(" << m_pid <<
") Connecting to proxy server: "
2089 << proxy_host <<
", port: " << proxy_port << endl;
2091 infoMessage( i18n(
"Connecting to %1...").arg(m_state.hostname) );
2093 setConnectTimeout( m_proxyConnTimeout );
2095 if ( !connectToHost(proxy_host, proxy_port,
false) )
2097 if (userAborted()) {
2098 error(ERR_NO_CONTENT,
"");
2102 switch ( connectResult() )
2104 case IO_LookupError:
2105 errMsg = proxy_host;
2106 errCode = ERR_UNKNOWN_PROXY_HOST;
2108 case IO_TimeOutError:
2109 errMsg = i18n(
"Proxy %1 at port %2").arg(proxy_host).arg(proxy_port);
2110 errCode = ERR_SERVER_TIMEOUT;
2113 errMsg = i18n(
"Proxy %1 at port %2").arg(proxy_host).arg(proxy_port);
2114 errCode = ERR_COULD_NOT_CONNECT;
2116 error( errCode, errMsg );
2123 setConnectTimeout(m_remoteConnTimeout);
2125 if ( !connectToHost(m_state.hostname, m_state.port,
false ) )
2127 if (userAborted()) {
2128 error(ERR_NO_CONTENT,
"");
2132 switch ( connectResult() )
2134 case IO_LookupError:
2135 errMsg = m_state.hostname;
2136 errCode = ERR_UNKNOWN_HOST;
2138 case IO_TimeOutError:
2139 errMsg = i18n(
"Connection was to %1 at port %2").arg(m_state.hostname).arg(m_state.port);
2140 errCode = ERR_SERVER_TIMEOUT;
2143 errCode = ERR_COULD_NOT_CONNECT;
2144 if (m_state.port != m_iDefaultPort)
2145 errMsg = i18n(
"%1 (port %2)").arg(m_state.hostname).arg(m_state.port);
2147 errMsg = m_state.hostname;
2149 error( errCode, errMsg );
2156 (void) setsockopt( m_iSock, IPPROTO_TCP, TCP_NODELAY, (
char*)&on,
sizeof(on) );
2158 m_bFirstRequest =
true;
2187 bool HTTPProtocol::httpOpen()
2189 kdDebug(7113) <<
"(" << m_pid <<
") HTTPProtocol::httpOpen" << endl;
2194 if ( (m_protocol ==
"https" || m_protocol ==
"webdavs") && !m_bIsSSL )
2196 error( ERR_UNSUPPORTED_PROTOCOL, m_protocol );
2200 m_request.fcache = 0;
2201 m_request.bCachedRead =
false;
2202 m_request.bCachedWrite =
false;
2203 m_request.bMustRevalidate =
false;
2204 m_request.expireDate = 0;
2205 m_request.creationDate = 0;
2207 if (m_request.bUseCache)
2209 m_request.fcache = checkCacheEntry( );
2211 bool bCacheOnly = (m_request.cache == KIO::CC_CacheOnly);
2212 bool bOffline = isOffline(m_request.doProxy ? m_proxyURL : m_request.url);
2213 if (bOffline && (m_request.cache != KIO::CC_Reload))
2214 m_request.cache = KIO::CC_CacheOnly;
2216 if (m_request.cache == CC_Reload && m_request.fcache)
2218 if (m_request.fcache)
2219 fclose(m_request.fcache);
2220 m_request.fcache = 0;
2222 if ((m_request.cache == KIO::CC_CacheOnly) || (m_request.cache == KIO::CC_Cache))
2223 m_request.bMustRevalidate =
false;
2225 m_request.bCachedWrite =
true;
2227 if (m_request.fcache && !m_request.bMustRevalidate)
2230 m_request.bCachedRead =
true;
2233 else if (!m_request.fcache)
2235 m_request.bMustRevalidate =
false;
2242 if (bCacheOnly && bOffline)
2244 error( ERR_OFFLINE_MODE, m_request.url.url() );
2249 error( ERR_DOES_NOT_EXIST, m_request.url.url() );
2254 error( ERR_OFFLINE_MODE, m_request.url.url() );
2262 bool moreData =
false;
2263 bool davData =
false;
2266 resetConnectionSettings ();
2269 httpCheckConnection();
2271 if ( !m_bIsTunneled && m_bNeedTunnel )
2273 setEnableSSLTunnel(
true );
2276 header = TQString(
"CONNECT %1:%2 HTTP/1.0"
2277 "\r\n").arg( m_request.encoded_hostname).arg(m_request.port);
2280 if (!m_request.userAgent.isEmpty())
2281 header +=
"User-Agent: " + m_request.userAgent +
"\r\n";
2284 header +=
"Host: " + m_state.encoded_hostname;
2286 if (m_state.port != m_iDefaultPort)
2287 header += TQString(
":%1").arg(m_state.port);
2290 header += proxyAuthenticationHeader();
2295 switch (m_request.method)
2303 m_request.bCachedWrite =
false;
2308 m_request.bCachedWrite =
false;
2315 m_request.bCachedWrite =
false;
2318 header =
"OPTIONS ";
2319 m_request.bCachedWrite =
false;
2322 header =
"PROPFIND ";
2324 davHeader =
"Depth: ";
2325 if ( hasMetaData(
"davDepth" ) )
2327 kdDebug(7113) <<
"Reading DAV depth from metadata: " << metaData(
"davDepth" ) << endl;
2328 davHeader += metaData(
"davDepth" );
2332 if ( m_request.davData.depth == 2 )
2333 davHeader +=
"infinity";
2335 davHeader += TQString(
"%1").arg( m_request.davData.depth );
2337 davHeader +=
"\r\n";
2338 m_request.bCachedWrite =
false;
2341 header =
"PROPPATCH ";
2343 m_request.bCachedWrite =
false;
2347 m_request.bCachedWrite =
false;
2351 header = ( m_request.method == DAV_COPY ) ?
"COPY " :
"MOVE ";
2352 davHeader =
"Destination: " + m_request.davData.desturl;
2355 davHeader +=
"\r\nDepth: infinity\r\nOverwrite: ";
2356 davHeader += m_request.davData.overwrite ?
"T" :
"F";
2357 davHeader +=
"\r\n";
2358 m_request.bCachedWrite =
false;
2362 davHeader =
"Timeout: ";
2365 if ( hasMetaData(
"davTimeout" ) )
2366 timeout = metaData(
"davTimeout" ).toUInt();
2368 davHeader +=
"Infinite";
2370 davHeader += TQString(
"Seconds-%1").arg(timeout);
2372 davHeader +=
"\r\n";
2373 m_request.bCachedWrite =
false;
2378 davHeader =
"Lock-token: " + metaData(
"davLockToken") +
"\r\n";
2379 m_request.bCachedWrite =
false;
2384 m_request.bCachedWrite =
false;
2387 header =
"SUBSCRIBE ";
2388 m_request.bCachedWrite =
false;
2390 case DAV_UNSUBSCRIBE:
2391 header =
"UNSUBSCRIBE ";
2392 m_request.bCachedWrite =
false;
2396 m_request.bCachedWrite =
false;
2399 error (ERR_UNSUPPORTED_ACTION, TQString::null);
2405 if (m_state.doProxy && !m_bIsTunneled)
2409 if (m_protocol ==
"webdav")
2410 u.setProtocol(
"http" );
2411 else if (m_protocol ==
"webdavs" )
2412 u.setProtocol(
"https" );
2414 u.setProtocol( m_protocol );
2420 if (m_protocol !=
"http" && m_protocol !=
"https" &&
2421 !m_state.user.isEmpty())
2422 u.setUser (m_state.user);
2424 u.setHost( m_state.hostname );
2425 if (m_state.port != m_iDefaultPort)
2426 u.setPort( m_state.port );
2427 u.setEncodedPathAndQuery( m_request.url.encodedPathAndQuery(0,
true) );
2432 header += m_request.url.encodedPathAndQuery(0,
true);
2435 header +=
" HTTP/1.1\r\n";
2437 if (!m_request.userAgent.isEmpty())
2439 header +=
"User-Agent: ";
2440 header += m_request.userAgent;
2444 if (!m_request.referrer.isEmpty())
2446 header +=
"Referer: ";
2447 header += m_request.referrer;
2451 if ( m_request.offset > 0 )
2453 header += TQString(
"Range: bytes=%1-\r\n").arg(KIO::number(m_request.offset));
2454 kdDebug(7103) <<
"kio_http : Range = " << KIO::number(m_request.offset) << endl;
2457 if ( m_request.cache == CC_Reload )
2460 header +=
"Pragma: no-cache\r\n";
2461 header +=
"Cache-control: no-cache\r\n";
2464 if (m_request.bMustRevalidate)
2467 if (!m_request.etag.isEmpty())
2468 header +=
"If-None-Match: "+m_request.etag+
"\r\n";
2469 if (!m_request.lastModified.isEmpty())
2470 header +=
"If-Modified-Since: "+m_request.lastModified+
"\r\n";
2473 header +=
"Accept: ";
2474 TQString acceptHeader = metaData(
"accept");
2475 if (!acceptHeader.isEmpty())
2476 header += acceptHeader;
2478 header += DEFAULT_ACCEPT_HEADER;
2482 if (m_request.allowCompressedPage)
2483 header +=
"Accept-Encoding: x-gzip, x-deflate, gzip, deflate\r\n";
2486 if (!m_request.charsets.isEmpty())
2487 header +=
"Accept-Charset: " + m_request.charsets +
"\r\n";
2489 if (!m_request.languages.isEmpty())
2490 header +=
"Accept-Language: " + m_request.languages +
"\r\n";
2494 header +=
"Host: " + m_state.encoded_hostname;
2496 if (m_state.port != m_iDefaultPort)
2497 header += TQString(
":%1").arg(m_state.port);
2501 TQString cookieMode = metaData(
"cookies").lower();
2502 if (cookieMode ==
"none")
2504 m_request.cookieMode = HTTPRequest::CookiesNone;
2506 else if (cookieMode ==
"manual")
2508 m_request.cookieMode = HTTPRequest::CookiesManual;
2509 cookieStr = metaData(
"setcookies");
2513 m_request.cookieMode = HTTPRequest::CookiesAuto;
2514 if (m_request.bUseCookiejar)
2515 cookieStr = findCookies( m_request.url.url());
2518 if (!cookieStr.isEmpty())
2519 header += cookieStr +
"\r\n";
2521 TQString customHeader = metaData(
"customHTTPHeader" );
2522 if (!customHeader.isEmpty())
2524 header += sanitizeCustomHTTPHeader(customHeader);
2528 if (m_request.method == HTTP_POST)
2530 header += metaData(
"content-type");
2537 if ( !m_request.bNoAuth && m_responseCode != 401 && m_responseCode != 407 && Authentication != AUTH_Negotiate )
2539 kdDebug(7113) <<
"(" << m_pid <<
") Calling checkCachedAuthentication " << endl;
2541 info.url = m_request.url;
2542 info.verifyPath =
true;
2543 if ( !m_request.user.isEmpty() )
2544 info.username = m_request.user;
2545 if ( checkCachedAuthentication( info ) && !info.digestInfo.isEmpty() )
2547 Authentication = info.digestInfo.startsWith(
"Basic") ? AUTH_Basic : info.digestInfo.startsWith(
"NTLM") ? AUTH_NTLM : info.digestInfo.startsWith(
"Negotiate") ? AUTH_Negotiate : AUTH_Digest ;
2548 m_state.user = info.username;
2549 m_state.passwd = info.password;
2550 m_strRealm = info.realmValue;
2551 if ( Authentication != AUTH_NTLM && Authentication != AUTH_Negotiate )
2552 m_strAuthorization = info.digestInfo;
2557 kdDebug(7113) <<
"(" << m_pid <<
") Not calling checkCachedAuthentication " << endl;
2560 switch ( Authentication )
2563 header += createBasicAuth();
2566 header += createDigestAuth();
2568 #ifdef HAVE_LIBGSSAPI
2569 case AUTH_Negotiate:
2570 header += createNegotiateAuth();
2574 header += createNTLMAuth();
2582 if ( Authentication != AUTH_None )
2584 kdDebug(7113) <<
"(" << m_pid <<
") Using Authentication: " << endl;
2585 kdDebug(7113) <<
"(" << m_pid <<
") HOST= " << m_state.hostname << endl;
2586 kdDebug(7113) <<
"(" << m_pid <<
") PORT= " << m_state.port << endl;
2587 kdDebug(7113) <<
"(" << m_pid <<
") USER= " << m_state.user << endl;
2588 kdDebug(7113) <<
"(" << m_pid <<
") PASSWORD= [protected]" << endl;
2589 kdDebug(7113) <<
"(" << m_pid <<
") REALM= " << m_strRealm << endl;
2590 kdDebug(7113) <<
"(" << m_pid <<
") EXTRA= " << m_strAuthorization << endl;
2594 if ( m_state.doProxy && !m_bIsTunneled )
2595 header += proxyAuthenticationHeader();
2601 if (!m_bUseProxy || m_bPersistentProxyConnection || m_bIsTunneled)
2602 header +=
"Connection: Keep-Alive\r\n";
2604 header +=
"Connection: close\r\n";
2606 if ( m_protocol ==
"webdav" || m_protocol ==
"webdavs" )
2608 header += davProcessLocks();
2611 TQString davExtraHeader = metaData(
"davHeader");
2612 if ( !davExtraHeader.isEmpty() )
2613 davHeader += davExtraHeader;
2617 davHeader +=
"Content-Type: text/xml; charset=utf-8\r\n";
2620 if ( !davHeader.isNull() )
2621 header += davHeader;
2625 kdDebug(7103) <<
"(" << m_pid <<
") ============ Sending Header:" << endl;
2627 TQStringList headerOutput = TQStringList::split(
"\r\n", header);
2628 TQStringList::Iterator it = headerOutput.begin();
2630 for (; it != headerOutput.end(); it++)
2631 kdDebug(7103) <<
"(" << m_pid <<
") " << (*it) << endl;
2633 if ( !moreData && !davData)
2641 if (!httpOpenConnection())
2646 bool sendOk = (write(header.latin1(), header.length()) == (ssize_t) header.length());
2649 kdDebug(7113) <<
"(" << m_pid <<
") HTTPProtocol::httpOpen: "
2650 "Connection broken! (" << m_state.hostname <<
")" << endl;
2656 httpCloseConnection();
2662 kdDebug(7113) <<
"(" << m_pid <<
") HTTPProtocol::httpOpen: sendOk==false."
2663 " Connnection broken !" << endl;
2664 error( ERR_CONNECTION_BROKEN, m_state.hostname );
2671 if ( moreData || davData )
2674 infoMessage(i18n(
"%1 contacted. Waiting for reply...").arg(m_request.hostname));
2679 void HTTPProtocol::forwardHttpResponseHeader()
2682 if ( config()->readBoolEntry(
"PropagateHttpHeader",
false) )
2684 setMetaData(
"HTTP-Headers", m_responseHeader.join(
"\n"));
2687 m_responseHeader.clear();
2696 bool HTTPProtocol::readHeader()
2699 kdDebug(7113) <<
"(" << m_pid <<
") HTTPProtocol::readHeader" << endl;
2702 if (m_request.bCachedRead)
2704 m_responseHeader <<
"HTTP-CACHE";
2707 if (!fgets(buffer, 4096, m_request.fcache) )
2710 kdDebug(7113) <<
"(" << m_pid <<
") HTTPProtocol::readHeader: "
2711 <<
"Could not access cache to obtain mimetype!" << endl;
2712 error( ERR_CONNECTION_BROKEN, m_state.hostname );
2716 m_strMimeType = TQString(TQString::fromUtf8( buffer)).stripWhiteSpace();
2718 kdDebug(7113) <<
"(" << m_pid <<
") HTTPProtocol::readHeader: cached "
2719 <<
"data mimetype: " << m_strMimeType << endl;
2721 if (!fgets(buffer, 4096, m_request.fcache) )
2724 kdDebug(7113) <<
"(" << m_pid <<
") HTTPProtocol::readHeader: "
2725 <<
"Could not access cached data! " << endl;
2726 error( ERR_CONNECTION_BROKEN, m_state.hostname );
2730 m_request.strCharset = TQString(TQString::fromUtf8( buffer)).stripWhiteSpace().lower();
2731 setMetaData(
"charset", m_request.strCharset);
2732 if (!m_request.lastModified.isEmpty())
2733 setMetaData(
"modified", m_request.lastModified);
2735 tmp.setNum(m_request.expireDate);
2736 setMetaData(
"expire-date", tmp);
2737 tmp.setNum(m_request.creationDate);
2738 setMetaData(
"cache-creation-date", tmp);
2739 mimeType(m_strMimeType);
2740 forwardHttpResponseHeader();
2744 TQCString locationStr;
2745 TQCString cookieStr;
2747 TQString dispositionType;
2748 TQString dispositionFilename;
2750 TQString mediaValue;
2751 TQString mediaAttribute;
2753 TQStringList upgradeOffers;
2755 bool upgradeRequired =
false;
2759 bool canUpgrade =
false;
2762 m_request.etag = TQString::null;
2763 m_request.lastModified = TQString::null;
2764 m_request.strCharset = TQString::null;
2766 time_t dateHeader = 0;
2767 time_t expireDate = 0;
2770 int maxHeaderSize = 64*1024;
2776 bool cacheValidated =
false;
2777 bool mayCache =
true;
2778 bool hasCacheDirective =
false;
2779 bool bCanResume =
false;
2783 kdDebug(7113) <<
"HTTPProtocol::readHeader: No connection." << endl;
2787 if (!waitForResponse(m_remoteRespTimeout))
2790 error( ERR_SERVER_TIMEOUT , m_state.hostname );
2796 gets(buffer,
sizeof(buffer)-1);
2798 if (m_bEOF || *buffer ==
'\0')
2800 kdDebug(7113) <<
"(" << m_pid <<
") HTTPProtocol::readHeader: "
2801 <<
"EOF while waiting for header start." << endl;
2804 httpCloseConnection();
2808 if (m_request.method == HTTP_HEAD)
2814 kdDebug(7113) <<
"(" << m_pid <<
") HTTPPreadHeader: HEAD -> returned "
2815 <<
"mimetype: " << DEFAULT_MIME_TYPE << endl;
2816 mimeType(TQString::fromLatin1(DEFAULT_MIME_TYPE));
2820 kdDebug(7113) <<
"HTTPProtocol::readHeader: Connection broken !" << endl;
2821 error( ERR_CONNECTION_BROKEN, m_state.hostname );
2825 kdDebug(7103) <<
"(" << m_pid <<
") ============ Received Response:"<< endl;
2827 bool noHeader =
true;
2828 HTTP_REV httpRev = HTTP_None;
2834 len = strlen(buffer);
2836 while(len && (buffer[len-1] ==
'\n' || buffer[len-1] ==
'\r'))
2842 kdDebug(7103) <<
"(" << m_pid <<
") --empty--" << endl;
2854 kdDebug(7103) <<
"(" << m_pid <<
") \"" << buffer <<
"\"" << endl;
2858 while( *buf ==
' ' )
2866 kdDebug(7103) <<
"kio_http: No valid HTTP header found! Document starts with XML/HTML tag" << endl;
2869 m_strMimeType =
"text/html";
2877 m_responseHeader << TQString::fromLatin1(buf);
2879 if ((strncasecmp(buf,
"HTTP/", 5) == 0) ||
2880 (strncasecmp(buf,
"ICY ", 4) == 0))
2882 if (strncasecmp(buf,
"ICY ", 4) == 0)
2885 httpRev = SHOUTCAST;
2886 m_bKeepAlive =
false;
2888 else if (strncmp((buf + 5),
"1.0",3) == 0)
2896 m_bKeepAlive =
false;
2898 else if (strncmp((buf + 5),
"1.1",3) == 0)
2904 httpRev = HTTP_Unknown;
2908 m_prevResponseCode = m_responseCode;
2910 const char* rptr = buf;
2911 while ( *rptr && *rptr >
' ' )
2913 m_responseCode = atoi(rptr);
2916 if (m_responseCode >= 500 && m_responseCode <= 599)
2918 if (m_request.method == HTTP_HEAD)
2924 if (m_request.bErrorPage)
2928 error(ERR_INTERNAL_SERVER, m_request.url.url());
2932 m_request.bCachedWrite =
false;
2936 else if (m_responseCode == 401 || m_responseCode == 407)
2940 if ( m_prevResponseCode != m_responseCode &&
2941 (m_prevResponseCode == 401 || m_prevResponseCode == 407) )
2942 saveAuthorization();
2944 m_bUnauthorized =
true;
2945 m_request.bCachedWrite =
false;
2949 else if (m_responseCode == 416)
2951 m_request.offset = 0;
2952 httpCloseConnection();
2956 else if (m_responseCode == 426)
2958 upgradeRequired =
true;
2961 else if (m_responseCode >= 400 && m_responseCode <= 499)
2964 if (m_request.bErrorPage)
2968 error(ERR_DOES_NOT_EXIST, m_request.url.url());
2971 m_request.bCachedWrite =
false;
2974 else if (m_responseCode == 307)
2977 m_request.bCachedWrite =
false;
2980 else if (m_responseCode == 304)
2984 cacheValidated =
true;
2986 else if (m_responseCode >= 301 && m_responseCode<= 303)
2989 if (m_responseCode == 301)
2990 setMetaData(
"permanent-redirect",
"true");
2994 if (m_request.method != HTTP_HEAD && m_request.method != HTTP_GET)
2999 if (m_request.method == HTTP_POST)
3000 m_bufPOST.resize(0);
3011 m_request.method = HTTP_GET;
3013 m_request.bCachedWrite =
false;
3016 else if ( m_responseCode == 207 )
3020 else if ( m_responseCode == 204 )
3030 else if ( m_responseCode == 206 )
3032 if ( m_request.offset )
3035 else if (m_responseCode == 102)
3042 infoMessage( i18n(
"Server processing request, please wait..." ) );
3045 else if (m_responseCode == 100)
3053 else if (strncasecmp(buf,
"Accept-Ranges:", 14) == 0) {
3054 if (strncasecmp(trimLead(buf + 14),
"none", 4) == 0)
3058 else if (strncasecmp(buf,
"Keep-Alive:", 11) == 0) {
3059 TQStringList options = TQStringList::split(
',',
3060 TQString::fromLatin1(trimLead(buf+11)));
3061 for(TQStringList::ConstIterator it = options.begin();
3062 it != options.end();
3065 TQString option = (*it).stripWhiteSpace().lower();
3066 if (option.startsWith(
"timeout="))
3068 m_keepAliveTimeout = option.mid(8).toInt();
3074 else if (strncasecmp(buf,
"Cache-Control:", 14) == 0) {
3075 TQStringList cacheControls = TQStringList::split(
',',
3076 TQString::fromLatin1(trimLead(buf+14)));
3077 for(TQStringList::ConstIterator it = cacheControls.begin();
3078 it != cacheControls.end();
3081 TQString cacheControl = (*it).stripWhiteSpace();
3082 if (strncasecmp(cacheControl.latin1(),
"no-cache", 8) == 0)
3084 m_request.bCachedWrite =
false;
3087 else if (strncasecmp(cacheControl.latin1(),
"no-store", 8) == 0)
3089 m_request.bCachedWrite =
false;
3092 else if (strncasecmp(cacheControl.latin1(),
"max-age=", 8) == 0)
3094 TQString age = cacheControl.mid(8).stripWhiteSpace();
3096 maxAge = STRTOLL(age.latin1(), 0, 10);
3099 hasCacheDirective =
true;
3103 else if (strncasecmp(buf,
"Content-length:", 15) == 0) {
3104 char* len = trimLead(buf + 15);
3106 m_iSize = STRTOLL(len, 0, 10);
3109 else if (strncasecmp(buf,
"Content-location:", 17) == 0) {
3110 setMetaData (
"content-location",
3111 TQString::fromLatin1(trimLead(buf+17)).stripWhiteSpace());
3115 else if (strncasecmp(buf,
"Content-type:", 13) == 0) {
3116 char *start = trimLead(buf + 13);
3120 while ( *pos && *pos !=
';' ) pos++;
3123 m_strMimeType = TQString::fromLatin1(start, pos-start).stripWhiteSpace().lower();
3124 kdDebug(7113) <<
"(" << m_pid <<
") Content-type: " << m_strMimeType << endl;
3131 while ( *pos && *pos !=
'=' ) pos++;
3134 while ( *end && *end !=
';' ) end++;
3138 mediaAttribute = TQString::fromLatin1(start, pos-start).stripWhiteSpace().lower();
3139 mediaValue = TQString::fromLatin1(pos+1, end-pos-1).stripWhiteSpace();
3141 if (mediaValue.length() &&
3142 (mediaValue[0] ==
'"') &&
3143 (mediaValue[mediaValue.length()-1] ==
'"'))
3144 mediaValue = mediaValue.mid(1, mediaValue.length()-2);
3146 kdDebug (7113) <<
"(" << m_pid <<
") Media-Parameter Attribute: "
3147 << mediaAttribute << endl;
3148 kdDebug (7113) <<
"(" << m_pid <<
") Media-Parameter Value: "
3149 << mediaValue << endl;
3151 if ( mediaAttribute ==
"charset")
3153 mediaValue = mediaValue.lower();
3154 m_request.strCharset = mediaValue;
3158 setMetaData(
"media-"+mediaAttribute, mediaValue);
3165 else if (strncasecmp(buf,
"Date:", 5) == 0) {
3166 dateHeader = KRFCDate::parseDate(trimLead(buf+5));
3170 else if (strncasecmp(buf,
"ETag:", 5) == 0) {
3171 m_request.etag = trimLead(buf+5);
3175 else if (strncasecmp(buf,
"Expires:", 8) == 0) {
3176 expireDate = KRFCDate::parseDate(trimLead(buf+8));
3182 else if (strncasecmp(buf,
"Last-Modified:", 14) == 0) {
3183 m_request.lastModified = (TQString::fromLatin1(trimLead(buf+14))).stripWhiteSpace();
3187 else if (strncasecmp(buf,
"Warning:", 8) == 0) {
3190 infoMessage(trimLead(buf + 8));
3194 else if (strncasecmp(buf,
"Pragma:", 7) == 0) {
3195 TQCString pragma = TQCString(trimLead(buf+7)).stripWhiteSpace().lower();
3196 if (pragma ==
"no-cache")
3198 m_request.bCachedWrite =
false;
3200 hasCacheDirective =
true;
3205 else if (strncasecmp(buf,
"Refresh:", 8) == 0) {
3207 setMetaData(
"http-refresh", TQString::fromLatin1(trimLead(buf+8)).stripWhiteSpace() );
3211 else if (strncasecmp(buf,
"Location:", 9) == 0) {
3213 if ( m_responseCode > 299 && m_responseCode < 400 )
3214 locationStr = TQCString(trimLead(buf+9)).stripWhiteSpace();
3218 else if (strncasecmp(buf,
"Set-Cookie", 10) == 0) {
3224 else if (strncasecmp(buf,
"WWW-Authenticate:", 17) == 0) {
3225 configAuth(trimLead(buf + 17),
false);
3229 else if (strncasecmp(buf,
"Proxy-Authenticate:", 19) == 0) {
3230 configAuth(trimLead(buf + 19),
true);
3233 else if (strncasecmp(buf,
"Upgrade:", 8) == 0) {
3235 TQString offered = &(buf[8]);
3236 upgradeOffers = TQStringList::split(TQRegExp(
"[ \n,\r\t]"), offered);
3240 else if (strncasecmp(buf,
"Content-Encoding:", 17) == 0) {
3254 addEncoding(trimLead(buf + 17), m_qContentEncodings);
3257 else if(strncasecmp(buf,
"Content-Disposition:", 20) == 0) {
3258 char* dispositionBuf = trimLead(buf + 20);
3259 while ( *dispositionBuf )
3261 if ( strncasecmp( dispositionBuf,
"filename", 8 ) == 0 )
3263 dispositionBuf += 8;
3265 while ( *dispositionBuf ==
' ' || *dispositionBuf ==
'=' )
3268 char* bufStart = dispositionBuf;
3270 while ( *dispositionBuf && *dispositionBuf !=
';' )
3273 if ( dispositionBuf > bufStart )
3276 while ( *bufStart ==
'"' )
3280 while ( *(dispositionBuf-1) ==
' ' || *(dispositionBuf-1) ==
'"')
3283 if ( dispositionBuf > bufStart )
3284 dispositionFilename = TQString::fromLatin1( bufStart, dispositionBuf-bufStart );
3291 char *bufStart = dispositionBuf;
3293 while ( *dispositionBuf && *dispositionBuf !=
';' )
3296 if ( dispositionBuf > bufStart )
3297 dispositionType = TQString::fromLatin1( bufStart, dispositionBuf-bufStart ).stripWhiteSpace();
3299 while ( *dispositionBuf ==
';' || *dispositionBuf ==
' ' )
3306 if ( !dispositionFilename.isEmpty() )
3308 int pos = dispositionFilename.findRev(
'/' );
3311 dispositionFilename = dispositionFilename.mid(pos+1);
3313 kdDebug(7113) <<
"(" << m_pid <<
") Content-Disposition: filename="
3314 << dispositionFilename<< endl;
3317 else if(strncasecmp(buf,
"Content-Language:", 17) == 0) {
3318 TQString language = TQString::fromLatin1(trimLead(buf+17)).stripWhiteSpace();
3319 if (!language.isEmpty())
3320 setMetaData(
"content-language", language);
3322 else if (strncasecmp(buf,
"Proxy-Connection:", 17) == 0)
3324 if (strncasecmp(trimLead(buf + 17),
"Close", 5) == 0)
3325 m_bKeepAlive =
false;
3326 else if (strncasecmp(trimLead(buf + 17),
"Keep-Alive", 10)==0)
3327 m_bKeepAlive =
true;
3329 else if (strncasecmp(buf,
"Link:", 5) == 0) {
3331 TQStringList link = TQStringList::split(
";", TQString(buf)
3332 .replace(TQRegExp(
"^Link:[ ]*"),
3334 if (link.count() == 2) {
3335 TQString rel = link[1].stripWhiteSpace();
3336 if (rel.startsWith(
"rel=\"")) {
3337 rel = rel.mid(5, rel.length() - 6);
3338 if (rel.lower() ==
"pageservices") {
3339 TQString url = TQString(link[0].replace(TQRegExp(
"[<>]"),
"")).stripWhiteSpace();
3340 setMetaData(
"PageServices", url);
3345 else if (strncasecmp(buf,
"P3P:", 4) == 0) {
3346 TQString p3pstr = buf;
3347 p3pstr = p3pstr.mid(4).simplifyWhiteSpace();
3348 TQStringList policyrefs, compact;
3349 TQStringList policyfields = TQStringList::split(TQRegExp(
",[ ]*"), p3pstr);
3350 for (TQStringList::Iterator it = policyfields.begin();
3351 it != policyfields.end();
3353 TQStringList policy = TQStringList::split(
"=", *it);
3355 if (policy.count() == 2) {
3356 if (policy[0].lower() ==
"policyref") {
3357 policyrefs << TQString(policy[1].replace(TQRegExp(
"[\"\']"),
""))
3359 }
else if (policy[0].lower() ==
"cp") {
3363 TQStringList cps = TQStringList::split(
" ",
3364 TQString(policy[1].replace(TQRegExp(
"[\"\']"),
""))
3365 .simplifyWhiteSpace());
3367 for (TQStringList::Iterator j = cps.begin(); j != cps.end(); ++j)
3373 if (!policyrefs.isEmpty())
3374 setMetaData(
"PrivacyPolicy", policyrefs.join(
"\n"));
3376 if (!compact.isEmpty())
3377 setMetaData(
"PrivacyCompactPolicy", compact.join(
"\n"));
3380 else if (strncasecmp(buf,
"Connection:", 11) == 0)
3382 if (strncasecmp(trimLead(buf + 11),
"Close", 5) == 0)
3383 m_bKeepAlive =
false;
3384 else if (strncasecmp(trimLead(buf + 11),
"Keep-Alive", 10)==0)
3385 m_bKeepAlive =
true;
3386 else if (strncasecmp(trimLead(buf + 11),
"Upgrade", 7)==0)
3388 if (m_responseCode == 101) {
3390 upgradeRequired =
true;
3391 }
else if (upgradeRequired) {
3400 else if ( httpRev == HTTP_11) {
3402 if (strncasecmp(buf,
"Transfer-Encoding:", 18) == 0) {
3406 addEncoding(trimLead(buf + 18), m_qTransferEncodings);
3410 else if (strncasecmp(buf,
"Content-MD5:", 12) == 0) {
3411 m_sContentMD5 = TQString::fromLatin1(trimLead(buf + 12));
3416 else if (strncasecmp(buf,
"DAV:", 4) == 0) {
3417 if (m_davCapabilities.isEmpty()) {
3418 m_davCapabilities << TQString::fromLatin1(trimLead(buf + 4));
3421 m_davCapabilities << TQString::fromLatin1(trimLead(buf + 4));
3426 else if ((httpRev == HTTP_None) && (strlen(buf) != 0))
3432 m_prevResponseCode = m_responseCode;
3434 m_responseCode = 200;
3435 httpRev = HTTP_Unknown;
3436 m_bKeepAlive =
false;
3442 memset(buffer, 0,
sizeof(buffer));
3444 }
while (!m_bEOF && (len || noHeader) && (headerSize < maxHeaderSize) && (gets(buffer,
sizeof(buffer)-1)));
3447 TQStringList::Iterator opt = upgradeOffers.begin();
3448 for( ; opt != upgradeOffers.end(); ++opt) {
3449 if (*opt ==
"TLS/1.0") {
3450 if(upgradeRequired) {
3451 if (!startTLS() && !usingTLS()) {
3452 error(ERR_UPGRADE_REQUIRED, *opt);
3456 }
else if (*opt ==
"HTTP/1.1") {
3460 if (upgradeRequired) {
3461 error(ERR_UPGRADE_REQUIRED, *opt);
3467 setMetaData(
"charset", m_request.strCharset);
3470 if ( (m_responseCode == 401 && Authentication == AUTH_None) ||
3471 (m_responseCode == 407 && ProxyAuthentication == AUTH_None) )
3473 m_bUnauthorized =
false;
3474 if (m_request.bErrorPage)
3478 error( ERR_UNSUPPORTED_ACTION,
"Unknown Authorization method!" );
3484 if (expireDate && (expireDate <= dateHeader))
3490 else if (maxAge > 0)
3493 maxAge -= currentAge;
3496 expireDate = time(0) + maxAge;
3501 time_t lastModifiedDate = 0;
3502 if (!m_request.lastModified.isEmpty())
3503 lastModifiedDate = KRFCDate::parseDate(m_request.lastModified);
3505 if (lastModifiedDate)
3507 long diff =
static_cast<long>(difftime(dateHeader, lastModifiedDate));
3509 expireDate = time(0) + 1;
3511 expireDate = time(0) + (diff / 10);
3515 expireDate = time(0) + DEFAULT_CACHE_EXPIRE;
3520 if (!cookieStr.isEmpty())
3522 if ((m_request.cookieMode == HTTPRequest::CookiesAuto) && m_request.bUseCookiejar)
3525 TQString domain = config()->readEntry(
"cross-domain");
3526 if (!domain.isEmpty() && isCrossDomainRequest(m_request.url.host(), domain))
3527 cookieStr =
"Cross-Domain\n" + cookieStr;
3528 addCookies( m_request.url.url(), cookieStr );
3530 else if (m_request.cookieMode == HTTPRequest::CookiesManual)
3533 setMetaData(
"setcookies", cookieStr);
3537 if (m_request.bMustRevalidate)
3539 m_request.bMustRevalidate =
false;
3544 fclose(m_request.fcache);
3545 m_request.fcache = 0;
3546 updateExpireDate( expireDate,
true );
3547 m_request.fcache = checkCacheEntry( );
3549 if (m_request.fcache)
3551 m_request.bCachedRead =
true;
3562 fclose(m_request.fcache);
3563 m_request.fcache = 0;
3575 if (!m_bChunked && (m_iSize == NO_SIZE))
3576 m_bKeepAlive =
false;
3578 if ( m_responseCode == 204 )
3584 if ( m_bUnauthorized )
3586 if ( (m_responseCode == 401) ||
3587 (m_bUseProxy && (m_responseCode == 407))
3590 if ( getAuthorization() )
3593 if ( Authentication == AUTH_NTLM && m_strAuthorization.length() > 4 )
3595 m_bKeepAlive =
true;
3598 else if (ProxyAuthentication == AUTH_NTLM && m_strProxyAuthorization.length() > 4)
3603 httpCloseConnection();
3612 m_bUnauthorized =
false;
3616 if (!locationStr.isEmpty())
3618 KURL u(m_request.url, locationStr);
3621 error(ERR_MALFORMED_URL, u.url());
3624 if ((u.protocol() !=
"http") && (u.protocol() !=
"https") &&
3625 (u.protocol() !=
"ftp") && (u.protocol() !=
"webdav") &&
3626 (u.protocol() !=
"webdavs"))
3629 error(ERR_ACCESS_DENIED, u.url());
3637 if (m_request.url.hasRef() && !u.hasRef() &&
3638 (m_request.url.host() == u.host()) &&
3639 (m_request.url.protocol() == u.protocol()))
3640 u.setRef(m_request.url.ref());
3643 m_redirectLocation = u;
3645 if (!m_request.id.isEmpty())
3650 kdDebug(7113) <<
"(" << m_pid <<
") request.url: " << m_request.url.url()
3651 << endl <<
"LocationStr: " << locationStr.data() << endl;
3653 kdDebug(7113) <<
"(" << m_pid <<
") Requesting redirection to: " << u.url()
3657 if (m_protocol ==
"webdav" || m_protocol ==
"webdavs")
3658 u.setProtocol(m_protocol);
3661 m_request.bCachedWrite =
false;
3666 if ( bCanResume && m_request.offset )
3669 m_request.offset = 0;
3672 if (m_strMimeType.startsWith(
"text/") &&
3673 (m_strMimeType !=
"text/css") &&
3674 (m_strMimeType !=
"text/x-javascript") &&
3680 if ( m_bIsSSL || (Authentication != AUTH_None) )
3682 m_request.bCachedWrite =
false;
3692 if (m_qContentEncodings.last() ==
"gzip")
3694 if (m_strMimeType ==
"application/x-tar")
3696 m_qContentEncodings.remove(m_qContentEncodings.fromLast());
3697 m_strMimeType = TQString::fromLatin1(
"application/x-tgz");
3699 else if (m_strMimeType ==
"application/postscript")
3703 m_qContentEncodings.remove(m_qContentEncodings.fromLast());
3704 m_strMimeType = TQString::fromLatin1(
"application/x-gzpostscript");
3706 else if ( m_request.allowCompressedPage &&
3707 m_strMimeType !=
"application/x-tgz" &&
3708 m_strMimeType !=
"application/x-targz" &&
3709 m_strMimeType !=
"application/x-gzip" &&
3710 m_request.url.path().right(6) ==
".ps.gz" )
3712 m_qContentEncodings.remove(m_qContentEncodings.fromLast());
3713 m_strMimeType = TQString::fromLatin1(
"application/x-gzpostscript");
3715 else if ( (m_request.allowCompressedPage &&
3716 m_strMimeType ==
"text/html")
3718 (m_request.allowCompressedPage &&
3719 m_strMimeType !=
"application/x-tgz" &&
3720 m_strMimeType !=
"application/x-targz" &&
3721 m_strMimeType !=
"application/x-gzip" &&
3722 m_request.url.path().right(3) !=
".gz")
3729 m_qContentEncodings.remove(m_qContentEncodings.fromLast());
3730 m_strMimeType = TQString::fromLatin1(
"application/x-gzip");
3740 if (m_qContentEncodings.last() ==
"bzip2")
3742 m_qContentEncodings.remove(m_qContentEncodings.fromLast());
3743 m_strMimeType = TQString::fromLatin1(
"application/x-bzip2");
3747 if (m_strMimeType ==
"application/x-targz")
3748 m_strMimeType = TQString::fromLatin1(
"application/x-tgz");
3749 else if (m_strMimeType ==
"application/zip")
3750 m_strMimeType = TQString::fromLatin1(
"application/x-zip");
3751 else if (m_strMimeType ==
"image/x-png")
3752 m_strMimeType = TQString::fromLatin1(
"image/png");
3753 else if (m_strMimeType ==
"image/bmp")
3754 m_strMimeType = TQString::fromLatin1(
"image/x-bmp");
3755 else if (m_strMimeType ==
"audio/mpeg" || m_strMimeType ==
"audio/x-mpeg" || m_strMimeType ==
"audio/mp3")
3756 m_strMimeType = TQString::fromLatin1(
"audio/x-mp3");
3757 else if (m_strMimeType ==
"audio/microsoft-wave")
3758 m_strMimeType = TQString::fromLatin1(
"audio/x-wav");
3759 else if (m_strMimeType ==
"audio/midi")
3760 m_strMimeType = TQString::fromLatin1(
"audio/x-midi");
3761 else if (m_strMimeType ==
"image/x-xpixmap")
3762 m_strMimeType = TQString::fromLatin1(
"image/x-xpm");
3763 else if (m_strMimeType ==
"application/rtf")
3764 m_strMimeType = TQString::fromLatin1(
"text/rtf");
3767 else if (m_strMimeType ==
"application/pkix-cert" ||
3768 m_strMimeType ==
"application/binary-certificate")
3770 m_strMimeType = TQString::fromLatin1(
"application/x-x509-ca-cert");
3774 else if (m_strMimeType ==
"application/x-gzip")
3776 if ((m_request.url.path().right(7) ==
".tar.gz") ||
3777 (m_request.url.path().right(4) ==
".tar"))
3778 m_strMimeType = TQString::fromLatin1(
"application/x-tgz");
3779 if ((m_request.url.path().right(6) ==
".ps.gz"))
3780 m_strMimeType = TQString::fromLatin1(
"application/x-gzpostscript");
3784 else if ((m_strMimeType ==
"text/plain") || (m_strMimeType ==
"application/octet-stream"))
3786 TQString ext = m_request.url.path().right(4).upper();
3788 m_strMimeType = TQString::fromLatin1(
"application/x-bzip2");
3789 else if (ext ==
".PEM")
3790 m_strMimeType = TQString::fromLatin1(
"application/x-x509-ca-cert");
3791 else if (ext ==
".SWF")
3792 m_strMimeType = TQString::fromLatin1(
"application/x-shockwave-flash");
3793 else if (ext ==
".PLS")
3794 m_strMimeType = TQString::fromLatin1(
"audio/x-scpls");
3795 else if (ext ==
".WMV")
3796 m_strMimeType = TQString::fromLatin1(
"video/x-ms-wmv");
3803 if (!m_qContentEncodings.isEmpty())
3810 if( !dispositionType.isEmpty() )
3812 kdDebug(7113) <<
"(" << m_pid <<
") Setting Content-Disposition type to: "
3813 << dispositionType << endl;
3814 setMetaData(
"content-disposition-type", dispositionType);
3816 if( !dispositionFilename.isEmpty() )
3818 kdDebug(7113) <<
"(" << m_pid <<
") Setting Content-Disposition filename to: "
3819 << dispositionFilename << endl;
3821 setMetaData(
"content-disposition", dispositionFilename);
3822 setMetaData(
"content-disposition-filename", dispositionFilename);
3825 if (!m_request.lastModified.isEmpty())
3826 setMetaData(
"modified", m_request.lastModified);
3830 setMetaData(
"no-cache",
"true");
3831 setMetaData(
"expire-date",
"1");
3836 tmp.setNum(expireDate);
3837 setMetaData(
"expire-date", tmp);
3838 tmp.setNum(time(0));
3839 setMetaData(
"cache-creation-date", tmp);
3844 if (locationStr.isEmpty() && (!m_strMimeType.isEmpty() ||
3845 m_request.method == HTTP_HEAD))
3847 kdDebug(7113) <<
"(" << m_pid <<
") Emitting mimetype " << m_strMimeType << endl;
3848 mimeType( m_strMimeType );
3853 forwardHttpResponseHeader();
3855 if (m_request.method == HTTP_HEAD)
3859 if (m_request.bUseCache)
3861 ::unlink( TQFile::encodeName(m_request.cef));
3862 if ( m_request.bCachedWrite && !m_strMimeType.isEmpty() )
3865 createCacheEntry(m_strMimeType, expireDate);
3866 if (!m_request.fcache)
3868 m_request.bCachedWrite =
false;
3869 kdDebug(7113) <<
"(" << m_pid <<
") Error creating cache entry for " << m_request.url.url()<<
"!\n";
3871 m_request.expireDate = expireDate;
3872 m_maxCacheSize = config()->readNumEntry(
"MaxCacheSize", DEFAULT_MAX_CACHE_SIZE) / 2;
3876 if (m_request.bCachedWrite && !m_strMimeType.isEmpty())
3877 kdDebug(7113) <<
"(" << m_pid <<
") Cache, adding \"" << m_request.url.url() <<
"\"" << endl;
3878 else if (m_request.bCachedWrite && m_strMimeType.isEmpty())
3879 kdDebug(7113) <<
"(" << m_pid <<
") Cache, pending \"" << m_request.url.url() <<
"\"" << endl;
3881 kdDebug(7113) <<
"(" << m_pid <<
") Cache, not adding \"" << m_request.url.url() <<
"\"" << endl;
3886 void HTTPProtocol::addEncoding(TQString encoding, TQStringList &encs)
3888 encoding = encoding.stripWhiteSpace().lower();
3890 if (encoding ==
"identity") {
3892 }
else if (encoding ==
"8bit") {
3895 }
else if (encoding ==
"chunked") {
3900 }
else if ((encoding ==
"x-gzip") || (encoding ==
"gzip")) {
3901 encs.append(TQString::fromLatin1(
"gzip"));
3902 }
else if ((encoding ==
"x-bzip2") || (encoding ==
"bzip2")) {
3903 encs.append(TQString::fromLatin1(
"bzip2"));
3904 }
else if ((encoding ==
"x-deflate") || (encoding ==
"deflate")) {
3905 encs.append(TQString::fromLatin1(
"deflate"));
3907 kdDebug(7113) <<
"(" << m_pid <<
") Unknown encoding encountered. "
3908 <<
"Please write code. Encoding = \"" << encoding
3913 bool HTTPProtocol::sendBody()
3918 infoMessage( i18n(
"Requesting data to send" ) );
3923 if ( !m_bufPOST.isNull() )
3925 kdDebug(7113) <<
"(" << m_pid <<
") POST'ing saved data..." << endl;
3928 length = m_bufPOST.size();
3932 kdDebug(7113) <<
"(" << m_pid <<
") POST'ing live data..." << endl;
3937 m_bufPOST.resize(0);
3941 result = readData( buffer );
3945 old_size = m_bufPOST.size();
3946 m_bufPOST.resize( old_size+result );
3947 memcpy( m_bufPOST.data()+ old_size, buffer.data(), buffer.size() );
3950 }
while ( result > 0 );
3955 error( ERR_ABORTED, m_request.hostname );
3959 infoMessage( i18n(
"Sending data to %1" ).arg( m_request.hostname ) );
3961 TQString size = TQString (
"Content-Length: %1\r\n\r\n").arg(length);
3962 kdDebug( 7113 ) <<
"(" << m_pid <<
")" << size << endl;
3965 bool sendOk = (write(size.latin1(), size.length()) == (ssize_t) size.length());
3968 kdDebug( 7113 ) <<
"(" << m_pid <<
") Connection broken when sending "
3969 <<
"content length: (" << m_state.hostname <<
")" << endl;
3970 error( ERR_CONNECTION_BROKEN, m_state.hostname );
3976 sendOk = (write(m_bufPOST.data(), m_bufPOST.size()) == (ssize_t) m_bufPOST.size());
3979 kdDebug(7113) <<
"(" << m_pid <<
") Connection broken when sending message body: ("
3980 << m_state.hostname <<
")" << endl;
3981 error( ERR_CONNECTION_BROKEN, m_state.hostname );
3988 void HTTPProtocol::httpClose(
bool keepAlive )
3990 kdDebug(7113) <<
"(" << m_pid <<
") HTTPProtocol::httpClose" << endl;
3992 if (m_request.fcache)
3994 fclose(m_request.fcache);
3995 m_request.fcache = 0;
3996 if (m_request.bCachedWrite)
3998 TQString filename = m_request.cef +
".new";
3999 ::unlink( TQFile::encodeName(filename) );
4007 if (keepAlive && (!m_bUseProxy ||
4008 m_bPersistentProxyConnection || m_bIsTunneled))
4010 if (!m_keepAliveTimeout)
4011 m_keepAliveTimeout = DEFAULT_KEEP_ALIVE_TIMEOUT;
4012 else if (m_keepAliveTimeout > 2*DEFAULT_KEEP_ALIVE_TIMEOUT)
4013 m_keepAliveTimeout = 2*DEFAULT_KEEP_ALIVE_TIMEOUT;
4015 kdDebug(7113) <<
"(" << m_pid <<
") HTTPProtocol::httpClose: keep alive (" << m_keepAliveTimeout <<
")" << endl;
4017 TQDataStream stream( data, IO_WriteOnly );
4019 setTimeoutSpecialCommand(m_keepAliveTimeout, data);
4023 httpCloseConnection();
4026 void HTTPProtocol::closeConnection()
4028 kdDebug(7113) <<
"(" << m_pid <<
") HTTPProtocol::closeConnection" << endl;
4029 httpCloseConnection ();
4032 void HTTPProtocol::httpCloseConnection ()
4034 kdDebug(7113) <<
"(" << m_pid <<
") HTTPProtocol::httpCloseConnection" << endl;
4035 m_bIsTunneled =
false;
4036 m_bKeepAlive =
false;
4038 setTimeoutSpecialCommand(-1);
4041 void HTTPProtocol::slave_status()
4043 kdDebug(7113) <<
"(" << m_pid <<
") HTTPProtocol::slave_status" << endl;
4045 if ( m_iSock != -1 && !isConnectionValid() )
4046 httpCloseConnection();
4048 slaveStatus( m_state.hostname, (m_iSock != -1) );
4051 void HTTPProtocol::mimetype(
const KURL& url )
4053 kdDebug(7113) <<
"(" << m_pid <<
") HTTPProtocol::mimetype: "
4054 << url.prettyURL() << endl;
4056 if ( !checkRequestURL( url ) )
4059 m_request.method = HTTP_HEAD;
4060 m_request.path = url.path();
4061 m_request.query = url.query();
4062 m_request.cache = CC_Cache;
4063 m_request.doProxy = m_bUseProxy;
4067 kdDebug(7113) <<
"(" << m_pid <<
") http: mimetype = " << m_strMimeType
4071 void HTTPProtocol::special(
const TQByteArray &data )
4073 kdDebug(7113) <<
"(" << m_pid <<
") HTTPProtocol::special" << endl;
4076 TQDataStream stream(data, IO_ReadOnly);
4092 stream >> url >> no_cache >> expireDate;
4093 cacheUpdate( url, no_cache, expireDate );
4099 TQString scope, type, owner;
4100 stream >> url >> scope >> type >> owner;
4101 davLock( url, scope, type, owner );
4115 stream >> url >> method;
4116 davGeneric( url, (KIO::HTTP_METHOD) method );
4121 httpCloseConnection();
4134 int HTTPProtocol::readChunked()
4136 if ((m_iBytesLeft == 0) || (m_iBytesLeft == NO_SIZE))
4140 m_bufReceive.resize(4096);
4142 if (!gets(m_bufReceive.data(), m_bufReceive.size()-1))
4144 kdDebug(7113) <<
"(" << m_pid <<
") gets() failure on Chunk header" << endl;
4149 if (m_bufReceive[0] ==
'\0')
4151 if (!gets(m_bufReceive.data(), m_bufReceive.size()-1))
4153 kdDebug(7113) <<
"(" << m_pid <<
") gets() failure on Chunk header" << endl;
4163 kdDebug(7113) <<
"(" << m_pid <<
") EOF on Chunk header" << endl;
4168 long long trunkSize = STRTOLL(m_bufReceive.data(), 0, 16);
4171 kdDebug(7113) <<
"(" << m_pid <<
") Negative chunk size" << endl;
4174 m_iBytesLeft = trunkSize;
4178 if (m_iBytesLeft == 0)
4184 if (!gets(m_bufReceive.data(), m_bufReceive.size()-1))
4186 kdDebug(7113) <<
"(" << m_pid <<
") gets() failure on Chunk trailer" << endl;
4191 while (strlen(m_bufReceive.data()) != 0);
4197 int bytesReceived = readLimited();
4199 m_iBytesLeft = NO_SIZE;
4202 return bytesReceived;
4205 int HTTPProtocol::readLimited()
4210 m_bufReceive.resize(4096);
4215 if (m_iBytesLeft > m_bufReceive.size())
4216 bytesToReceive = m_bufReceive.size();
4218 bytesToReceive = m_iBytesLeft;
4220 bytesReceived = read(m_bufReceive.data(), bytesToReceive);
4222 if (bytesReceived <= 0)
4225 m_iBytesLeft -= bytesReceived;
4226 return bytesReceived;
4229 int HTTPProtocol::readUnlimited()
4233 kdDebug(7113) <<
"(" << m_pid <<
") Unbounded datastream on a Keep "
4234 <<
"alive connection!" << endl;
4235 m_bKeepAlive =
false;
4238 m_bufReceive.resize(4096);
4240 int result = read(m_bufReceive.data(), m_bufReceive.size());
4249 void HTTPProtocol::slotData(
const TQByteArray &_d)
4257 if (m_iContentLeft != NO_SIZE)
4259 if (m_iContentLeft >= _d.size())
4260 m_iContentLeft -= _d.size();
4262 m_iContentLeft = NO_SIZE;
4266 if ( !m_dataInternal )
4271 if ( m_strMimeType.isEmpty() && !m_bRedirect &&
4272 !( m_responseCode >= 300 && m_responseCode <=399) )
4274 kdDebug(7113) <<
"(" << m_pid <<
") Determining mime-type from content..." << endl;
4275 int old_size = m_mimeTypeBuffer.size();
4276 m_mimeTypeBuffer.resize( old_size + d.size() );
4277 memcpy( m_mimeTypeBuffer.data() + old_size, d.data(), d.size() );
4278 if ( (m_iBytesLeft != NO_SIZE) && (m_iBytesLeft > 0)
4279 && (m_mimeTypeBuffer.size() < 1024) )
4281 m_cpMimeBuffer =
true;
4285 kdDebug(7113) <<
"(" << m_pid <<
") Mimetype buffer size: " << m_mimeTypeBuffer.size()
4288 KMimeMagicResult *result;
4289 result = KMimeMagic::self()->findBufferFileType( m_mimeTypeBuffer,
4290 m_request.url.fileName() );
4293 m_strMimeType = result->mimeType();
4294 kdDebug(7113) <<
"(" << m_pid <<
") Mimetype from content: "
4295 << m_strMimeType << endl;
4298 if ( m_strMimeType.isEmpty() )
4300 m_strMimeType = TQString::fromLatin1( DEFAULT_MIME_TYPE );
4301 kdDebug(7113) <<
"(" << m_pid <<
") Using default mimetype: "
4302 << m_strMimeType << endl;
4305 if ( m_request.bCachedWrite )
4307 createCacheEntry( m_strMimeType, m_request.expireDate );
4308 if (!m_request.fcache)
4309 m_request.bCachedWrite =
false;
4312 if ( m_cpMimeBuffer )
4318 d.resize(m_mimeTypeBuffer.size());
4319 memcpy( d.data(), m_mimeTypeBuffer.data(),
4322 mimeType(m_strMimeType);
4323 m_mimeTypeBuffer.resize(0);
4327 if (m_request.bCachedWrite && m_request.fcache)
4328 writeCacheEntry(d.data(), d.size());
4332 uint old_size = m_bufWebDavData.size();
4333 m_bufWebDavData.resize (old_size + d.size());
4334 memcpy (m_bufWebDavData.data() + old_size, d.data(), d.size());
4347 bool HTTPProtocol::readBody(
bool dataInternal )
4349 if (m_responseCode == 204)
4358 m_dataInternal = dataInternal;
4360 m_bufWebDavData.resize (0);
4364 bool useMD5 = !m_sContentMD5.isEmpty();
4367 KIO::filesize_t sz = m_request.offset;
4375 if ( !dataInternal ) {
4376 if ( (m_iSize > 0) && (m_iSize != NO_SIZE)) {
4378 infoMessage( i18n(
"Retrieving %1 from %2...").arg(KIO::convertSize(m_iSize))
4379 .arg( m_request.hostname ) );
4387 infoMessage( i18n(
"Retrieving from %1..." ).arg( m_request.hostname ) );
4389 if (m_request.bCachedRead)
4391 kdDebug(7113) <<
"(" << m_pid <<
") HTTPProtocol::readBody: read data from cache!" << endl;
4392 m_request.bCachedWrite =
false;
4394 char buffer[ MAX_IPC_SIZE ];
4396 m_iContentLeft = NO_SIZE;
4399 while (!feof(m_request.fcache) && !ferror(m_request.fcache))
4401 int nbytes = fread( buffer, 1, MAX_IPC_SIZE, m_request.fcache);
4405 m_bufReceive.setRawData( buffer, nbytes);
4406 slotData( m_bufReceive );
4407 m_bufReceive.resetRawData( buffer, nbytes );
4412 m_bufReceive.resize( 0 );
4414 if ( !dataInternal )
4416 processedSize( sz );
4417 data( TQByteArray() );
4424 if (m_iSize != NO_SIZE)
4425 m_iBytesLeft = m_iSize - sz;
4427 m_iBytesLeft = NO_SIZE;
4429 m_iContentLeft = m_iBytesLeft;
4432 m_iBytesLeft = NO_SIZE;
4434 kdDebug(7113) <<
"(" << m_pid <<
") HTTPProtocol::readBody: retrieve data. "
4435 << KIO::number(m_iBytesLeft) <<
" left." << endl;
4438 m_cpMimeBuffer =
false;
4439 m_mimeTypeBuffer.resize(0);
4440 struct timeval last_tv;
4441 gettimeofday( &last_tv, 0L );
4443 HTTPFilterChain chain;
4445 TQObject::connect(&chain, TQT_SIGNAL(output(
const TQByteArray &)),
4446 this, TQT_SLOT(slotData(
const TQByteArray &)));
4447 TQObject::connect(&chain, TQT_SIGNAL(error(
int,
const TQString &)),
4448 this, TQT_SLOT(error(
int,
const TQString &)));
4451 while (!m_qTransferEncodings.isEmpty())
4453 TQString enc = m_qTransferEncodings.last();
4454 m_qTransferEncodings.remove(m_qTransferEncodings.fromLast());
4455 if ( enc ==
"gzip" )
4456 chain.addFilter(
new HTTPFilterGZip);
4457 else if ( enc ==
"deflate" )
4458 chain.addFilter(
new HTTPFilterDeflate);
4467 HTTPFilterMD5 *md5Filter = 0;
4470 md5Filter =
new HTTPFilterMD5;
4471 chain.addFilter(md5Filter);
4482 while (!m_qContentEncodings.isEmpty())
4484 TQString enc = m_qContentEncodings.last();
4485 m_qContentEncodings.remove(m_qContentEncodings.fromLast());
4486 if ( enc ==
"gzip" )
4487 chain.addFilter(
new HTTPFilterGZip);
4488 else if ( enc ==
"deflate" )
4489 chain.addFilter(
new HTTPFilterDeflate);
4497 bytesReceived = readChunked();
4498 else if (m_iSize != NO_SIZE)
4499 bytesReceived = readLimited();
4501 bytesReceived = readUnlimited();
4507 if (bytesReceived == -1)
4509 if (m_iContentLeft == 0)
4517 kdDebug(7113) <<
"(" << m_pid <<
") readBody: bytesReceived==-1 sz=" << (int)sz
4518 <<
" Connnection broken !" << endl;
4519 error(ERR_CONNECTION_BROKEN, m_state.hostname);
4525 if (bytesReceived > 0)
4529 m_bufReceive.truncate( bytesReceived );
4531 chain.slotInput(m_bufReceive);
4536 sz += bytesReceived;
4538 processedSize( sz );
4540 m_bufReceive.resize(0);
4542 if (m_iBytesLeft && m_bEOD && !m_bChunked)
4549 if (m_iBytesLeft == 0)
4551 kdDebug(7113) <<
"("<<m_pid<<
") EOD received! Left = "<< KIO::number(m_iBytesLeft) << endl;
4555 chain.slotInput(TQByteArray());
4559 TQString calculatedMD5 = md5Filter->md5();
4561 if ( m_sContentMD5 == calculatedMD5 )
4562 kdDebug(7113) <<
"(" << m_pid <<
") MD5 checksum MATCHED!!" << endl;
4564 kdDebug(7113) <<
"(" << m_pid <<
") MD5 checksum MISMATCH! Expected: "
4565 << calculatedMD5 <<
", Got: " << m_sContentMD5 << endl;
4569 if (m_iBytesLeft == 0)
4571 if (m_request.bCachedWrite && m_request.fcache)
4573 else if (m_request.bCachedWrite)
4574 kdDebug(7113) <<
"(" << m_pid <<
") no cache file!\n";
4578 kdDebug(7113) <<
"(" << m_pid <<
") still "<< KIO::number(m_iBytesLeft)
4579 <<
" bytes left! can't close cache entry!\n";
4586 if (m_responseCode >= 500 && m_responseCode <= 599)
4587 error(ERR_INTERNAL_SERVER, m_state.hostname);
4588 else if (m_responseCode >= 400 && m_responseCode <= 499)
4589 error(ERR_DOES_NOT_EXIST, m_state.hostname);
4593 data( TQByteArray() );
4599 void HTTPProtocol::error(
int _err,
const TQString &_text )
4603 if (!m_request.id.isEmpty())
4605 forwardHttpResponseHeader();
4610 if (!m_bufPOST.isEmpty())
4612 m_bufPOST.resize(0);
4613 kdDebug(7113) <<
"(" << m_pid <<
") HTTP::retreiveHeader: Cleared POST "
4614 "buffer..." << endl;
4617 SlaveBase::error( _err, _text );
4622 void HTTPProtocol::addCookies(
const TQString &url,
const TQCString &cookieHeader )
4624 long windowId = m_request.window.toLong();
4626 TQDataStream stream(params, IO_WriteOnly);
4627 stream << url << cookieHeader << windowId;
4629 kdDebug(7113) <<
"(" << m_pid <<
") " << cookieHeader << endl;
4630 kdDebug(7113) <<
"(" << m_pid <<
") " <<
"Window ID: "
4631 << windowId <<
", for host = " << url << endl;
4633 if ( !dcopClient()->send(
"kded",
"kcookiejar",
"addCookies(TQString,TQCString,long int)", params ) )
4635 kdWarning(7113) <<
"(" << m_pid <<
") Can't communicate with kded_kcookiejar!" << endl;
4639 TQString HTTPProtocol::findCookies(
const TQString &url)
4641 TQCString replyType;
4646 long windowId = m_request.window.toLong();
4647 result = TQString::null;
4648 TQDataStream stream(params, IO_WriteOnly);
4649 stream << url << windowId;
4651 if ( !dcopClient()->call(
"kded",
"kcookiejar",
"findCookies(TQString,long int)",
4652 params, replyType, reply ) )
4654 kdWarning(7113) <<
"(" << m_pid <<
") Can't communicate with kded_kcookiejar!" << endl;
4657 if ( replyType ==
"TQString" )
4659 TQDataStream stream2( reply, IO_ReadOnly );
4664 kdError(7113) <<
"(" << m_pid <<
") DCOP function findCookies(...) returns "
4665 << replyType <<
", expected TQString" << endl;
4673 void HTTPProtocol::cacheUpdate(
const KURL& url,
bool no_cache, time_t expireDate)
4675 if ( !checkRequestURL( url ) )
4678 m_request.path = url.path();
4679 m_request.query = url.query();
4680 m_request.cache = CC_Reload;
4681 m_request.doProxy = m_bUseProxy;
4685 m_request.fcache = checkCacheEntry( );
4686 if (m_request.fcache)
4688 fclose(m_request.fcache);
4689 m_request.fcache = 0;
4690 ::unlink( TQFile::encodeName(m_request.cef) );
4695 updateExpireDate( expireDate );
4704 FILE* HTTPProtocol::checkCacheEntry(
bool readWrite)
4706 const TQChar separator =
'_';
4708 TQString CEF = m_request.path;
4710 int p = CEF.find(
'/');
4715 p = CEF.find(
'/', p);
4718 TQString host = m_request.hostname.lower();
4719 CEF = host + CEF +
'_';
4721 TQString dir = m_strCacheDir;
4722 if (dir[dir.length()-1] !=
'/')
4725 int l = host.length();
4726 for(
int i = 0; i < l; i++)
4728 if (host[i].isLetter() && (host[i] !=
'w'))
4734 if (dir[dir.length()-1] ==
'/')
4737 unsigned long hash = 0x00000000;
4738 TQCString u = m_request.url.url().latin1();
4739 for(
int i = u.length(); i--;)
4741 hash = (hash * 12211 +
static_cast<const char>(u.at(i))) % 2147483563;
4744 TQString hashString;
4745 hashString.sprintf(
"%08lx", hash);
4747 CEF = CEF + hashString;
4749 CEF = dir +
"/" + CEF;
4751 m_request.cef = CEF;
4753 const char *mode = (readWrite ?
"r+" :
"r");
4755 FILE *fs = fopen( TQFile::encodeName(CEF), mode);
4763 if (ok && (!fgets(buffer, 400, fs)))
4765 if (ok && (strcmp(buffer, CACHE_REVISION) != 0))
4769 time_t currentDate = time(0);
4772 if (ok && (!fgets(buffer, 400, fs)))
4776 int l = strlen(buffer);
4779 if (m_request.url.url() != buffer)
4786 if (ok && (!fgets(buffer, 400, fs)))
4790 date = (time_t) strtoul(buffer, 0, 10);
4791 m_request.creationDate = date;
4792 if (m_maxCacheAge && (difftime(currentDate, date) > m_maxCacheAge))
4794 m_request.bMustRevalidate =
true;
4795 m_request.expireDate = currentDate;
4800 m_request.cacheExpireDateOffset = ftell(fs);
4801 if (ok && (!fgets(buffer, 400, fs)))
4805 if (m_request.cache == CC_Verify)
4807 date = (time_t) strtoul(buffer, 0, 10);
4809 if (!date || difftime(currentDate, date) >= 0)
4810 m_request.bMustRevalidate =
true;
4811 m_request.expireDate = date;
4813 else if (m_request.cache == CC_Refresh)
4815 m_request.bMustRevalidate =
true;
4816 m_request.expireDate = currentDate;
4821 if (ok && (!fgets(buffer, 400, fs)))
4825 m_request.etag = TQString(buffer).stripWhiteSpace();
4829 if (ok && (!fgets(buffer, 400, fs)))
4833 m_request.lastModified = TQString(buffer).stripWhiteSpace();
4840 unlink( TQFile::encodeName(CEF));
4844 void HTTPProtocol::updateExpireDate(time_t expireDate,
bool updateCreationDate)
4848 FILE *fs = checkCacheEntry(
true);
4853 time_t creationDate;
4855 fseek(fs, 0, SEEK_SET);
4856 if (ok && !fgets(buffer, 400, fs))
4858 if (ok && !fgets(buffer, 400, fs))
4860 long cacheCreationDateOffset = ftell(fs);
4861 if (ok && !fgets(buffer, 400, fs))
4863 creationDate = strtoul(buffer, 0, 10);
4867 if (updateCreationDate)
4869 if (!ok || fseek(fs, cacheCreationDateOffset, SEEK_SET))
4872 date.setNum( time(0) );
4873 date = date.leftJustify(16);
4874 fputs(date.latin1(), fs);
4878 if (expireDate>(30*365*24*60*60))
4882 date.setNum( expireDate );
4891 date.setNum( creationDate + expireDate );
4893 date = date.leftJustify(16);
4894 if (!ok || fseek(fs, m_request.cacheExpireDateOffset, SEEK_SET))
4896 fputs(date.latin1(), fs);
4897 fseek(fs, 0, SEEK_END);
4902 void HTTPProtocol::createCacheEntry(
const TQString &mimetype, time_t expireDate)
4904 TQString dir = m_request.cef;
4905 int p = dir.findRev(
'/');
4906 if (p == -1)
return;
4910 (void) ::mkdir( TQFile::encodeName(dir), 0700 );
4912 TQString filename = m_request.cef +
".new";
4916 m_request.fcache = fopen( TQFile::encodeName(filename),
"w");
4917 if (!m_request.fcache)
4919 kdWarning(7113) <<
"(" << m_pid <<
")createCacheEntry: opening " << filename <<
" failed." << endl;
4923 fputs(CACHE_REVISION, m_request.fcache);
4925 fputs(m_request.url.url().latin1(), m_request.fcache);
4926 fputc(
'\n', m_request.fcache);
4929 m_request.creationDate = time(0);
4930 date.setNum( m_request.creationDate );
4931 date = date.leftJustify(16);
4932 fputs(date.latin1(), m_request.fcache);
4933 fputc(
'\n', m_request.fcache);
4935 date.setNum( expireDate );
4936 date = date.leftJustify(16);
4937 fputs(date.latin1(), m_request.fcache);
4938 fputc(
'\n', m_request.fcache);
4940 if (!m_request.etag.isEmpty())
4941 fputs(m_request.etag.latin1(), m_request.fcache);
4942 fputc(
'\n', m_request.fcache);
4944 if (!m_request.lastModified.isEmpty())
4945 fputs(m_request.lastModified.latin1(), m_request.fcache);
4946 fputc(
'\n', m_request.fcache);
4948 fputs(mimetype.latin1(), m_request.fcache);
4949 fputc(
'\n', m_request.fcache);
4951 if (!m_request.strCharset.isEmpty())
4952 fputs(m_request.strCharset.latin1(), m_request.fcache);
4953 fputc(
'\n', m_request.fcache);
4961 void HTTPProtocol::writeCacheEntry(
const char *buffer,
int nbytes)
4963 if (fwrite( buffer, nbytes, 1, m_request.fcache) != 1)
4965 kdWarning(7113) <<
"(" << m_pid <<
") writeCacheEntry: writing " << nbytes <<
" bytes failed." << endl;
4966 fclose(m_request.fcache);
4967 m_request.fcache = 0;
4968 TQString filename = m_request.cef +
".new";
4969 ::unlink( TQFile::encodeName(filename) );
4972 long file_pos = ftell( m_request.fcache ) / 1024;
4973 if ( file_pos > m_maxCacheSize )
4975 kdDebug(7113) <<
"writeCacheEntry: File size reaches " << file_pos
4976 <<
"Kb, exceeds cache limits. (" << m_maxCacheSize <<
"Kb)" << endl;
4977 fclose(m_request.fcache);
4978 m_request.fcache = 0;
4979 TQString filename = m_request.cef +
".new";
4980 ::unlink( TQFile::encodeName(filename) );
4985 void HTTPProtocol::closeCacheEntry()
4987 TQString filename = m_request.cef +
".new";
4988 int result = fclose( m_request.fcache);
4989 m_request.fcache = 0;
4992 if (::rename( TQFile::encodeName(filename), TQFile::encodeName(m_request.cef)) == 0)
4995 kdWarning(7113) <<
"(" << m_pid <<
") closeCacheEntry: error renaming "
4996 <<
"cache entry. (" << filename <<
" -> " << m_request.cef
5000 kdWarning(7113) <<
"(" << m_pid <<
") closeCacheEntry: error closing cache "
5001 <<
"entry. (" << filename<<
")" << endl;
5004 void HTTPProtocol::cleanCache()
5006 const time_t maxAge = DEFAULT_CLEAN_CACHE_INTERVAL;
5007 bool doClean =
false;
5008 TQString cleanFile = m_strCacheDir;
5009 if (cleanFile[cleanFile.length()-1] !=
'/')
5011 cleanFile +=
"cleaned";
5013 struct stat stat_buf;
5015 int result = ::stat(TQFile::encodeName(cleanFile), &stat_buf);
5018 int fd = creat( TQFile::encodeName(cleanFile), 0600);
5027 time_t age = (time_t) difftime( time(0), stat_buf.st_mtime );
5034 utime(TQFile::encodeName(cleanFile), 0);
5035 KApplication::startServiceByDesktopPath(
"http_cache_cleaner.desktop");
5044 void HTTPProtocol::configAuth(
char *p,
bool isForProxy )
5046 HTTP_AUTH f = AUTH_None;
5047 const char *strAuth = p;
5049 if ( strncasecmp( p,
"Basic", 5 ) == 0 )
5055 else if ( strncasecmp (p,
"Digest", 6) == 0 )
5058 memcpy((
void *)p,
"Digest", 6);
5061 else if (strncasecmp( p,
"MBS_PWD_COOKIE", 14 ) == 0)
5068 #ifdef HAVE_LIBGSSAPI
5069 else if ( strncasecmp( p,
"Negotiate", 9 ) == 0 )
5073 if ( !isForProxy && !(m_responseCode == 401 && m_prevResponseCode == 401) )
5076 memcpy((
void *)p,
"Negotiate", 9);
5081 else if ( strncasecmp( p,
"NTLM", 4 ) == 0 )
5084 memcpy((
void *)p,
"NTLM", 4);
5086 m_strRealm =
"NTLM";
5090 kdWarning(7113) <<
"(" << m_pid <<
") Unsupported or invalid authorization "
5091 <<
"type requested" << endl;
5093 kdWarning(7113) <<
"(" << m_pid <<
") Proxy URL: " << m_proxyURL << endl;
5095 kdWarning(7113) <<
"(" << m_pid <<
") URL: " << m_request.url << endl;
5096 kdWarning(7113) <<
"(" << m_pid <<
") Request Authorization: " << p << endl;
5108 if ((f == AUTH_None) ||
5109 ((m_iProxyAuthCount > 0) && (f < ProxyAuthentication)))
5115 if ( m_iProxyAuthCount == 0)
5116 ProxyAuthentication = f;
5117 kdDebug(7113) <<
"(" << m_pid <<
") Rejected proxy auth method: " << f << endl;
5120 m_iProxyAuthCount++;
5121 kdDebug(7113) <<
"(" << m_pid <<
") Accepted proxy auth method: " << f << endl;
5125 if ((f == AUTH_None) ||
5126 ((m_iWWWAuthCount > 0) && (f < Authentication)))
5128 kdDebug(7113) <<
"(" << m_pid <<
") Rejected auth method: " << f << endl;
5132 kdDebug(7113) <<
"(" << m_pid <<
") Accepted auth method: " << f << endl;
5139 while( (*p ==
' ') || (*p ==
',') || (*p ==
'\t') ) { p++; }
5140 if ( strncasecmp( p,
"realm=", 6 ) == 0 )
5143 TQTextCodec* oldCodec=TQTextCodec::codecForCStrings();
5144 if (KGlobal::locale()->language().contains(
"ru"))
5145 TQTextCodec::setCodecForCStrings(TQTextCodec::codecForName(
"CP1251"));
5149 while( p[i] && p[i] !=
'"' ) i++;
5151 m_strProxyRealm = TQString::fromAscii( p, i );
5153 m_strRealm = TQString::fromAscii( p, i );
5155 TQTextCodec::setCodecForCStrings(oldCodec);
5164 ProxyAuthentication = f;
5165 m_strProxyAuthorization = TQString::fromLatin1( strAuth );
5170 m_strAuthorization = TQString::fromLatin1( strAuth );
5175 bool HTTPProtocol::retryPrompt()
5178 switch ( m_responseCode )
5181 prompt = i18n(
"Authentication Failed.");
5184 prompt = i18n(
"Proxy Authentication Failed.");
5189 prompt += i18n(
" Do you want to retry?");
5190 return (messageBox(QuestionYesNo, prompt, i18n(
"Authentication")) == 3);
5193 void HTTPProtocol::promptInfo( AuthInfo& info )
5195 if ( m_responseCode == 401 )
5197 info.url = m_request.url;
5198 if ( !m_state.user.isEmpty() )
5199 info.username = m_state.user;
5200 info.readOnly = !m_request.url.user().isEmpty();
5201 info.prompt = i18n(
"You need to supply a username and a "
5202 "password to access this site." );
5203 info.keepPassword =
true;
5204 if ( !m_strRealm.isEmpty() )
5206 info.realmValue = m_strRealm;
5207 info.verifyPath =
false;
5208 info.digestInfo = m_strAuthorization;
5209 info.commentLabel = i18n(
"Site:" );
5210 info.comment = i18n(
"<b>%1</b> at <b>%2</b>").arg( htmlEscape(m_strRealm) ).arg( m_request.hostname );
5213 else if ( m_responseCode == 407 )
5215 info.url = m_proxyURL;
5216 info.username = m_proxyURL.user();
5217 info.prompt = i18n(
"You need to supply a username and a password for "
5218 "the proxy server listed below before you are allowed "
5219 "to access any sites." );
5220 info.keepPassword =
true;
5221 if ( !m_strProxyRealm.isEmpty() )
5223 info.realmValue = m_strProxyRealm;
5224 info.verifyPath =
false;
5225 info.digestInfo = m_strProxyAuthorization;
5226 info.commentLabel = i18n(
"Proxy:" );
5227 info.comment = i18n(
"<b>%1</b> at <b>%2</b>").arg( htmlEscape(m_strProxyRealm) ).arg( m_proxyURL.host() );
5232 bool HTTPProtocol::getAuthorization()
5235 bool result =
false;
5237 kdDebug (7113) <<
"(" << m_pid <<
") HTTPProtocol::getAuthorization: "
5238 <<
"Current Response: " << m_responseCode <<
", "
5239 <<
"Previous Response: " << m_prevResponseCode <<
", "
5240 <<
"Authentication: " << Authentication <<
", "
5241 <<
"ProxyAuthentication: " << ProxyAuthentication << endl;
5243 if (m_request.bNoAuth)
5245 if (m_request.bErrorPage)
5248 error( ERR_COULD_NOT_LOGIN, i18n(
"Authentication needed for %1 but authentication is disabled.").arg(m_request.hostname));
5252 bool repeatFailure = (m_prevResponseCode == m_responseCode);
5259 if ( Authentication == AUTH_Digest || ProxyAuthentication == AUTH_Digest )
5261 bool isStaleNonce =
false;
5262 TQString auth = ( m_responseCode == 401 ) ? m_strAuthorization : m_strProxyAuthorization;
5263 int pos = auth.find(
"stale", 0,
false);
5267 int len = auth.length();
5268 while( pos < len && (auth[pos] ==
' ' || auth[pos] ==
'=') ) pos++;
5269 if ( pos < len && auth.find(
"true", pos,
false) != -1 )
5271 isStaleNonce =
true;
5272 kdDebug(7113) <<
"(" << m_pid <<
") Stale nonce value. "
5273 <<
"Will retry using same info..." << endl;
5280 if ( m_responseCode == 401 )
5282 info.username = m_request.user;
5283 info.password = m_request.passwd;
5284 info.realmValue = m_strRealm;
5285 info.digestInfo = m_strAuthorization;
5287 else if ( m_responseCode == 407 )
5289 info.username = m_proxyURL.user();
5290 info.password = m_proxyURL.pass();
5291 info.realmValue = m_strProxyRealm;
5292 info.digestInfo = m_strProxyAuthorization;
5297 if ( Authentication == AUTH_NTLM || ProxyAuthentication == AUTH_NTLM )
5299 TQString auth = ( m_responseCode == 401 ) ? m_strAuthorization : m_strProxyAuthorization;
5300 kdDebug(7113) <<
"auth: " << auth << endl;
5301 if ( auth.length() > 4 )
5305 kdDebug(7113) <<
"(" << m_pid <<
") NTLM auth second phase, "
5306 <<
"sending response..." << endl;
5307 if ( m_responseCode == 401 )
5309 info.username = m_request.user;
5310 info.password = m_request.passwd;
5311 info.realmValue = m_strRealm;
5312 info.digestInfo = m_strAuthorization;
5314 else if ( m_responseCode == 407 )
5316 info.username = m_proxyURL.user();
5317 info.password = m_proxyURL.pass();
5318 info.realmValue = m_strProxyRealm;
5319 info.digestInfo = m_strProxyAuthorization;
5326 switch ( m_responseCode )
5329 errorMsg = i18n(
"Authentication Failed.");
5332 errorMsg = i18n(
"Proxy Authentication Failed.");
5346 if (m_bProxyAuthValid)
5349 m_bProxyAuthValid =
false;
5350 KURL proxy ( config()->readEntry(
"UseProxy") );
5351 m_proxyURL.setUser(proxy.user());
5352 m_proxyURL.setPass(proxy.pass());
5355 info.verifyPath =
false;
5356 if ( m_responseCode == 407 )
5358 info.url = m_proxyURL;
5359 info.username = m_proxyURL.user();
5360 info.password = m_proxyURL.pass();
5361 info.realmValue = m_strProxyRealm;
5362 info.digestInfo = m_strProxyAuthorization;
5366 info.url = m_request.url;
5367 info.username = m_request.user;
5368 info.password = m_request.passwd;
5369 info.realmValue = m_strRealm;
5370 info.digestInfo = m_strAuthorization;
5375 if ( info.username.isNull() ||
5376 info.password.isNull() )
5377 result = checkCachedAuthentication( info );
5379 if ( Authentication == AUTH_Digest )
5383 if (m_responseCode == 401)
5384 auth = m_strAuthorization;
5386 auth = m_strProxyAuthorization;
5388 int pos = auth.find(
"stale", 0,
false);
5392 int len = auth.length();
5393 while( pos < len && (auth[pos] ==
' ' || auth[pos] ==
'=') ) pos++;
5394 if ( pos < len && auth.find(
"true", pos,
false) != -1 )
5396 info.digestInfo = (m_responseCode == 401) ? m_strAuthorization : m_strProxyAuthorization;
5397 kdDebug(7113) <<
"(" << m_pid <<
") Just a stale nonce value! "
5398 <<
"Retrying using the new nonce sent..." << endl;
5409 if ( !repeatFailure &&
5410 !info.username.isNull() &&
5411 !info.password.isNull() )
5415 if (Authentication == AUTH_Negotiate)
5420 else if ( m_request.disablePassDlg ==
false )
5422 kdDebug( 7113 ) <<
"(" << m_pid <<
") Prompting the user for authorization..." << endl;
5424 result = openPassDlg( info, errorMsg );
5431 switch (m_responseCode)
5434 m_request.user = info.username;
5435 m_request.passwd = info.password;
5436 m_strRealm = info.realmValue;
5437 m_strAuthorization = info.digestInfo;
5440 m_proxyURL.setUser( info.username );
5441 m_proxyURL.setPass( info.password );
5442 m_strProxyRealm = info.realmValue;
5443 m_strProxyAuthorization = info.digestInfo;
5451 if (m_request.bErrorPage)
5454 error( ERR_USER_CANCELED, TQString::null );
5458 void HTTPProtocol::saveAuthorization()
5461 if ( m_prevResponseCode == 407 )
5465 m_bProxyAuthValid =
true;
5466 info.url = m_proxyURL;
5467 info.username = m_proxyURL.user();
5468 info.password = m_proxyURL.pass();
5469 info.realmValue = m_strProxyRealm;
5470 info.digestInfo = m_strProxyAuthorization;
5471 cacheAuthentication( info );
5475 info.url = m_request.url;
5476 info.username = m_request.user;
5477 info.password = m_request.passwd;
5478 info.realmValue = m_strRealm;
5479 info.digestInfo = m_strAuthorization;
5480 cacheAuthentication( info );
5484 #ifdef HAVE_LIBGSSAPI
5485 TQCString HTTPProtocol::gssError(
int major_status,
int minor_status )
5487 OM_uint32 new_status;
5488 OM_uint32 msg_ctx = 0;
5489 gss_buffer_desc major_string;
5490 gss_buffer_desc minor_string;
5497 ret = gss_display_status(&new_status, major_status, GSS_C_GSS_CODE, GSS_C_NULL_OID, &msg_ctx, &major_string);
5498 errorstr += (
const char *)major_string.value;
5500 ret = gss_display_status(&new_status, minor_status, GSS_C_MECH_CODE, GSS_C_NULL_OID, &msg_ctx, &minor_string);
5501 errorstr += (
const char *)minor_string.value;
5503 }
while (!GSS_ERROR(ret) && msg_ctx != 0);
5508 TQString HTTPProtocol::createNegotiateAuth()
5511 TQCString servicename;
5513 OM_uint32 major_status, minor_status;
5514 OM_uint32 req_flags = 0;
5515 gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
5516 gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
5520 static gss_OID_desc krb5_oid_desc = {9, (
void *)
"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"};
5521 static gss_OID_desc spnego_oid_desc = {6, (
void *)
"\x2b\x06\x01\x05\x05\x02"};
5524 gss_OID_set mech_set;
5527 ctx = GSS_C_NO_CONTEXT;
5528 mech_oid = &krb5_oid_desc;
5531 major_status = gss_indicate_mechs(&minor_status, &mech_set);
5532 if (GSS_ERROR(major_status)) {
5533 kdDebug(7113) <<
"(" << m_pid <<
") gss_indicate_mechs failed: " << gssError(major_status, minor_status) << endl;
5535 for (i=0; i<mech_set->count && !found; i++) {
5536 tmp_oid = &mech_set->elements[i];
5537 if (tmp_oid->length == spnego_oid_desc.length &&
5538 !memcmp(tmp_oid->elements, spnego_oid_desc.elements, tmp_oid->length)) {
5539 kdDebug(7113) <<
"(" << m_pid <<
") createNegotiateAuth: found SPNEGO mech" << endl;
5541 mech_oid = &spnego_oid_desc;
5545 gss_release_oid_set(&minor_status, &mech_set);
5549 servicename =
"HTTP@";
5550 servicename += m_state.hostname.ascii();
5552 input_token.value = (
void *)servicename.data();
5553 input_token.length = servicename.length() + 1;
5555 major_status = gss_import_name(&minor_status, &input_token,
5556 GSS_C_NT_HOSTBASED_SERVICE, &server);
5558 input_token.value = NULL;
5559 input_token.length = 0;
5561 if (GSS_ERROR(major_status)) {
5562 kdDebug(7113) <<
"(" << m_pid <<
") gss_import_name failed: " << gssError(major_status, minor_status) << endl;
5564 m_strAuthorization = TQString::null;
5565 return TQString::null;
5568 major_status = gss_init_sec_context(&minor_status, GSS_C_NO_CREDENTIAL,
5569 &ctx, server, mech_oid,
5570 req_flags, GSS_C_INDEFINITE,
5571 GSS_C_NO_CHANNEL_BINDINGS,
5572 GSS_C_NO_BUFFER, NULL, &output_token,
5576 if (GSS_ERROR(major_status) || (output_token.length == 0)) {
5577 kdDebug(7113) <<
"(" << m_pid <<
") gss_init_sec_context failed: " << gssError(major_status, minor_status) << endl;
5578 gss_release_name(&minor_status, &server);
5579 if (ctx != GSS_C_NO_CONTEXT) {
5580 gss_delete_sec_context(&minor_status, &ctx, GSS_C_NO_BUFFER);
5581 ctx = GSS_C_NO_CONTEXT;
5584 m_strAuthorization = TQString::null;
5585 return TQString::null;
5588 input.duplicate((
const char *)output_token.value, output_token.length);
5589 auth =
"Authorization: Negotiate ";
5590 auth += KCodecs::base64Encode( input );
5594 gss_release_name(&minor_status, &server);
5595 if (ctx != GSS_C_NO_CONTEXT) {
5596 gss_delete_sec_context(&minor_status, &ctx, GSS_C_NO_BUFFER);
5597 ctx = GSS_C_NO_CONTEXT;
5599 gss_release_buffer(&minor_status, &output_token);
5606 TQCString HTTPProtocol::gssError(
int,
int )
5612 TQString HTTPProtocol::createNegotiateAuth()
5614 return TQString::null;
5618 TQString HTTPProtocol::createNTLMAuth(
bool isForProxy )
5621 TQString auth, user, domain, passwd;
5627 auth =
"Proxy-Connection: Keep-Alive\r\n";
5628 auth +=
"Proxy-Authorization: NTLM ";
5629 user = m_proxyURL.user();
5630 passwd = m_proxyURL.pass();
5631 strauth = m_strProxyAuthorization.latin1();
5632 len = m_strProxyAuthorization.length();
5636 auth =
"Authorization: NTLM ";
5637 user = m_state.user;
5638 passwd = m_state.passwd;
5639 strauth = m_strAuthorization.latin1();
5640 len = m_strAuthorization.length();
5642 if ( user.contains(
'\\') ) {
5643 domain = user.section(
'\\', 0, 0);
5644 user = user.section(
'\\', 1 );
5647 kdDebug(7113) <<
"(" << m_pid <<
") NTLM length: " << len << endl;
5648 if ( user.isEmpty() || passwd.isEmpty() || len < 4 )
5649 return TQString::null;
5654 TQByteArray challenge;
5655 KCodecs::base64Decode( strauth.right( len - 5 ), challenge );
5656 KNTLM::getAuth( buf, challenge, user, passwd, domain,
5657 KNetwork::KResolver::localHostName(),
false,
false );
5661 KNTLM::getNegotiate( buf );
5666 m_strProxyAuthorization =
"NTLM";
5668 m_strAuthorization =
"NTLM";
5670 auth += KCodecs::base64Encode( buf );
5676 TQString HTTPProtocol::createBasicAuth(
bool isForProxy )
5679 TQCString user, passwd;
5682 auth =
"Proxy-Authorization: Basic ";
5683 user = m_proxyURL.user().latin1();
5684 passwd = m_proxyURL.pass().latin1();
5688 auth =
"Authorization: Basic ";
5689 user = m_state.user.latin1();
5690 passwd = m_state.passwd.latin1();
5693 if ( user.isEmpty() )
5695 if ( passwd.isEmpty() )
5700 auth += KCodecs::base64Encode( user );
5706 void HTTPProtocol::calculateResponse( DigestAuthInfo& info, TQCString& Response )
5713 TQCString authStr = info.username;
5715 authStr += info.realm;
5717 authStr += info.password;
5718 md.update( authStr );
5720 if ( info.algorithm.lower() ==
"md5-sess" )
5722 authStr = md.hexDigest();
5724 authStr += info.nonce;
5726 authStr += info.cnonce;
5728 md.update( authStr );
5730 HA1 = md.hexDigest();
5732 kdDebug(7113) <<
"(" << m_pid <<
") calculateResponse(): A1 => " << HA1 << endl;
5735 authStr = info.method;
5737 authStr += m_request.url.encodedPathAndQuery(0,
true).latin1();
5738 if ( info.qop ==
"auth-int" )
5741 authStr += info.entityBody;
5744 md.update( authStr );
5745 HA2 = md.hexDigest();
5747 kdDebug(7113) <<
"(" << m_pid <<
") calculateResponse(): A2 => "
5753 authStr += info.nonce;
5755 if ( !info.qop.isEmpty() )
5759 authStr += info.cnonce;
5761 authStr += info.qop;
5766 md.update( authStr );
5767 Response = md.hexDigest();
5769 kdDebug(7113) <<
"(" << m_pid <<
") calculateResponse(): Response => "
5770 << Response << endl;
5773 TQString HTTPProtocol::createDigestAuth (
bool isForProxy )
5781 DigestAuthInfo info;
5786 auth =
"Proxy-Authorization: Digest ";
5787 info.username = m_proxyURL.user().latin1();
5788 info.password = m_proxyURL.pass().latin1();
5789 p = m_strProxyAuthorization.latin1();
5793 auth =
"Authorization: Digest ";
5794 info.username = m_state.user.latin1();
5795 info.password = m_state.passwd.latin1();
5796 p = m_strAuthorization.latin1();
5799 return TQString::null;
5803 if ( info.username.isEmpty() || info.password.isEmpty() || !p )
5804 return TQString::null;
5808 info.algorithm =
"MD5";
5813 info.cnonce = KApplication::randomString(16).latin1();
5816 info.nc =
"00000001";
5819 switch ( m_request.method )
5822 info.method =
"GET";
5825 info.method =
"PUT";
5828 info.method =
"POST";
5831 info.method =
"HEAD";
5834 info.method =
"DELETE";
5837 info.method =
"PROPFIND";
5840 info.method =
"PROPPATCH";
5843 info.method =
"MKCOL";
5846 info.method =
"COPY";
5849 info.method =
"MOVE";
5852 info.method =
"LOCK";
5855 info.method =
"UNLOCK";
5858 info.method =
"SEARCH";
5861 info.method =
"SUBSCRIBE";
5863 case DAV_UNSUBSCRIBE:
5864 info.method =
"UNSUBSCRIBE";
5867 info.method =
"POLL";
5870 error( ERR_UNSUPPORTED_ACTION, i18n(
"Unsupported method: authentication will fail. Please submit a bug report."));
5878 while ( (*p ==
' ') || (*p ==
',') || (*p ==
'\t')) { p++; }
5879 if (strncasecmp(p,
"realm=", 6 )==0)
5882 while ( *p ==
'"' ) p++;
5883 while ( p[i] !=
'"' ) i++;
5884 info.realm = TQCString( p, i+1 );
5886 else if (strncasecmp(p,
"algorith=", 9)==0)
5889 while ( *p ==
'"' ) p++;
5890 while ( ( p[i] !=
'"' ) && ( p[i] !=
',' ) && ( p[i] !=
'\0' ) ) i++;
5891 info.algorithm = TQCString(p, i+1);
5893 else if (strncasecmp(p,
"algorithm=", 10)==0)
5896 while ( *p ==
'"' ) p++;
5897 while ( ( p[i] !=
'"' ) && ( p[i] !=
',' ) && ( p[i] !=
'\0' ) ) i++;
5898 info.algorithm = TQCString(p,i+1);
5900 else if (strncasecmp(p,
"domain=", 7)==0)
5903 while ( *p ==
'"' ) p++;
5904 while ( p[i] !=
'"' ) i++;
5907 TQCString uri = TQCString(p,i+1);
5910 pos = uri.find(
' ', idx );
5913 KURL u (m_request.url, uri.mid(idx, pos-idx));
5915 info.digestURI.append( u.url().latin1() );
5919 KURL u (m_request.url, uri.mid(idx, uri.length()-idx));
5921 info.digestURI.append( u.url().latin1() );
5924 }
while ( pos != -1 );
5926 else if (strncasecmp(p,
"nonce=", 6)==0)
5929 while ( *p ==
'"' ) p++;
5930 while ( p[i] !=
'"' ) i++;
5931 info.nonce = TQCString(p,i+1);
5933 else if (strncasecmp(p,
"opaque=", 7)==0)
5936 while ( *p ==
'"' ) p++;
5937 while ( p[i] !=
'"' ) i++;
5938 opaque = TQCString(p,i+1);
5940 else if (strncasecmp(p,
"qop=", 4)==0)
5943 while ( *p ==
'"' ) p++;
5944 while ( p[i] !=
'"' ) i++;
5945 info.qop = TQCString(p,i+1);
5950 if (info.realm.isEmpty() || info.nonce.isEmpty())
5951 return TQString::null;
5956 if (info.digestURI.isEmpty() && (m_responseCode == 401 || m_responseCode == 407))
5957 info.digestURI.append (m_request.url.url().latin1());
5965 TQString requestPath = m_request.url.directory(
false,
false);
5966 if (requestPath.isEmpty())
5969 int count = info.digestURI.count();
5971 for (
int i = 0; i < count; i++ )
5973 KURL u ( info.digestURI.at(i) );
5975 send &= (m_request.url.protocol().lower() == u.protocol().lower());
5976 send &= (m_request.hostname.lower() == u.host().lower());
5978 if (m_request.port > 0 && u.port() > 0)
5979 send &= (m_request.port == u.port());
5981 TQString digestPath = u.directory (
false,
false);
5982 if (digestPath.isEmpty())
5985 send &= (requestPath.startsWith(digestPath));
5991 kdDebug(7113) <<
"(" << m_pid <<
") createDigestAuth(): passed digest "
5992 "authentication credential test: " << send << endl;
5995 return TQString::null;
5998 kdDebug(7113) <<
"(" << m_pid <<
") RESULT OF PARSING:" << endl;
5999 kdDebug(7113) <<
"(" << m_pid <<
") algorithm: " << info.algorithm << endl;
6000 kdDebug(7113) <<
"(" << m_pid <<
") realm: " << info.realm << endl;
6001 kdDebug(7113) <<
"(" << m_pid <<
") nonce: " << info.nonce << endl;
6002 kdDebug(7113) <<
"(" << m_pid <<
") opaque: " << opaque << endl;
6003 kdDebug(7113) <<
"(" << m_pid <<
") qop: " << info.qop << endl;
6006 calculateResponse( info, Response );
6008 auth +=
"username=\"";
6009 auth += info.username;
6011 auth +=
"\", realm=\"";
6015 auth +=
", nonce=\"";
6018 auth +=
"\", uri=\"";
6019 auth += m_request.url.encodedPathAndQuery(0,
true);
6021 auth +=
"\", algorithm=\"";
6022 auth += info.algorithm;
6025 if ( !info.qop.isEmpty() )
6029 auth +=
"\", cnonce=\"";
6030 auth += info.cnonce;
6035 auth +=
", response=\"";
6037 if ( !opaque.isEmpty() )
6039 auth +=
"\", opaque=\"";
6047 TQString HTTPProtocol::proxyAuthenticationHeader()
6054 if ( m_strProxyRealm.isEmpty() )
6057 info.url = m_proxyURL;
6058 info.username = m_proxyURL.user();
6059 info.password = m_proxyURL.pass();
6060 info.verifyPath =
true;
6065 if ( !info.username.isNull() && !info.password.isNull() )
6067 if( m_strProxyAuthorization.isEmpty() )
6068 ProxyAuthentication = AUTH_None;
6069 else if( m_strProxyAuthorization.startsWith(
"Basic") )
6070 ProxyAuthentication = AUTH_Basic;
6071 else if( m_strProxyAuthorization.startsWith(
"NTLM") )
6072 ProxyAuthentication = AUTH_NTLM;
6074 ProxyAuthentication = AUTH_Digest;
6078 if ( checkCachedAuthentication(info) && !info.digestInfo.isEmpty() )
6080 m_proxyURL.setUser( info.username );
6081 m_proxyURL.setPass( info.password );
6082 m_strProxyRealm = info.realmValue;
6083 m_strProxyAuthorization = info.digestInfo;
6084 if( m_strProxyAuthorization.startsWith(
"Basic") )
6085 ProxyAuthentication = AUTH_Basic;
6086 else if( m_strProxyAuthorization.startsWith(
"NTLM") )
6087 ProxyAuthentication = AUTH_NTLM;
6089 ProxyAuthentication = AUTH_Digest;
6093 ProxyAuthentication = AUTH_None;
6099 if ( ProxyAuthentication != AUTH_None )
6101 kdDebug(7113) <<
"(" << m_pid <<
") Using Proxy Authentication: " << endl;
6102 kdDebug(7113) <<
"(" << m_pid <<
") HOST= " << m_proxyURL.host() << endl;
6103 kdDebug(7113) <<
"(" << m_pid <<
") PORT= " << m_proxyURL.port() << endl;
6104 kdDebug(7113) <<
"(" << m_pid <<
") USER= " << m_proxyURL.user() << endl;
6105 kdDebug(7113) <<
"(" << m_pid <<
") PASSWORD= [protected]" << endl;
6106 kdDebug(7113) <<
"(" << m_pid <<
") REALM= " << m_strProxyRealm << endl;
6107 kdDebug(7113) <<
"(" << m_pid <<
") EXTRA= " << m_strProxyAuthorization << endl;
6110 switch ( ProxyAuthentication )
6113 header += createBasicAuth(
true );
6116 header += createDigestAuth(
true );
6119 if ( m_bFirstRequest ) header += createNTLMAuth(
true );