00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include <config.h>
00025
00026 #include <errno.h>
00027 #include <fcntl.h>
00028 #include <utime.h>
00029 #include <stdlib.h>
00030 #include <signal.h>
00031 #include <sys/stat.h>
00032 #include <sys/socket.h>
00033 #include <netinet/in.h>
00034 #include <netinet/tcp.h>
00035 #include <unistd.h>
00036
00037
00038
00039
00040
00041
00042
00043 #include <qdom.h>
00044 #include <qfile.h>
00045 #include <qregexp.h>
00046 #include <qdatetime.h>
00047 #include <qstringlist.h>
00048
00049 #include <kurl.h>
00050 #include <kidna.h>
00051 #include <ksocks.h>
00052 #include <kdebug.h>
00053 #include <klocale.h>
00054 #include <kconfig.h>
00055 #include <kextsock.h>
00056 #include <kservice.h>
00057 #include <krfcdate.h>
00058 #include <kmdcodec.h>
00059 #include <kinstance.h>
00060 #include <kresolver.h>
00061 #include <kmimemagic.h>
00062 #include <dcopclient.h>
00063 #include <kdatastream.h>
00064 #include <kapplication.h>
00065 #include <kstandarddirs.h>
00066 #include <kstringhandler.h>
00067 #include <kremoteencoding.h>
00068
00069 #include "kio/ioslave_defaults.h"
00070 #include "kio/http_slave_defaults.h"
00071
00072 #include "httpfilter.h"
00073 #include "http.h"
00074
00075 #ifdef HAVE_LIBGSSAPI
00076 #ifdef GSSAPI_MIT
00077 #include <gssapi/gssapi.h>
00078 #else
00079 #include <gssapi.h>
00080 #endif
00081
00082
00083 #if defined(GSS_RFC_COMPLIANT_OIDS) && (GSS_RFC_COMPLIANT_OIDS == 0)
00084 #include <gssapi/gssapi_generic.h>
00085 #define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name
00086 #endif
00087
00088 #endif
00089
00090 #include <misc/kntlm/kntlm.h>
00091
00092 using namespace KIO;
00093
00094 extern "C" {
00095 KDE_EXPORT int kdemain(int argc, char **argv);
00096 }
00097
00098 int kdemain( int argc, char **argv )
00099 {
00100 KLocale::setMainCatalogue("kdelibs");
00101 KInstance instance( "kio_http" );
00102 ( void ) KGlobal::locale();
00103
00104 if (argc != 4)
00105 {
00106 fprintf(stderr, "Usage: kio_http protocol domain-socket1 domain-socket2\n");
00107 exit(-1);
00108 }
00109
00110 HTTPProtocol slave(argv[1], argv[2], argv[3]);
00111 slave.dispatchLoop();
00112 return 0;
00113 }
00114
00115
00116
00117 static char * trimLead (char *orig_string)
00118 {
00119 while (*orig_string == ' ')
00120 orig_string++;
00121 return orig_string;
00122 }
00123
00124 static bool isCrossDomainRequest( const QString& fqdn, const QString& originURL )
00125 {
00126 if (originURL == "true")
00127 return true;
00128
00129 KURL url ( originURL );
00130
00131
00132 QString a = url.host();
00133
00134
00135 QString b = fqdn;
00136
00137 if (a == b)
00138 return false;
00139
00140 QStringList l1 = QStringList::split('.', a);
00141 QStringList l2 = QStringList::split('.', b);
00142
00143 while(l1.count() > l2.count())
00144 l1.pop_front();
00145
00146 while(l2.count() > l1.count())
00147 l2.pop_front();
00148
00149 while(l2.count() >= 2)
00150 {
00151 if (l1 == l2)
00152 return false;
00153
00154 l1.pop_front();
00155 l2.pop_front();
00156 }
00157
00158 return true;
00159 }
00160
00161
00162
00163
00164 static QString sanitizeCustomHTTPHeader(const QString& _header)
00165 {
00166 QString sanitizedHeaders;
00167 QStringList headers = QStringList::split(QRegExp("[\r\n]"), _header);
00168
00169 for(QStringList::Iterator it = headers.begin(); it != headers.end(); ++it)
00170 {
00171 QString header = (*it).lower();
00172
00173
00174 if (header.find(':') == -1 ||
00175 header.startsWith("host") ||
00176 header.startsWith("via"))
00177 continue;
00178
00179 sanitizedHeaders += (*it);
00180 sanitizedHeaders += "\r\n";
00181 }
00182
00183 return sanitizedHeaders.stripWhiteSpace();
00184 }
00185
00186
00187 #define NO_SIZE ((KIO::filesize_t) -1)
00188
00189 #ifdef HAVE_STRTOLL
00190 #define STRTOLL strtoll
00191 #else
00192 #define STRTOLL strtol
00193 #endif
00194
00195
00196
00197
00198 HTTPProtocol::HTTPProtocol( const QCString &protocol, const QCString &pool,
00199 const QCString &app )
00200 :TCPSlaveBase( 0, protocol , pool, app,
00201 (protocol == "https" || protocol == "webdavs") )
00202 {
00203 m_requestQueue.setAutoDelete(true);
00204
00205 m_bBusy = false;
00206 m_bFirstRequest = false;
00207 m_bProxyAuthValid = false;
00208
00209 m_iSize = NO_SIZE;
00210 m_lineBufUnget = 0;
00211
00212 m_protocol = protocol;
00213
00214 m_maxCacheAge = DEFAULT_MAX_CACHE_AGE;
00215 m_maxCacheSize = DEFAULT_MAX_CACHE_SIZE / 2;
00216 m_remoteConnTimeout = DEFAULT_CONNECT_TIMEOUT;
00217 m_remoteRespTimeout = DEFAULT_RESPONSE_TIMEOUT;
00218 m_proxyConnTimeout = DEFAULT_PROXY_CONNECT_TIMEOUT;
00219
00220 m_pid = getpid();
00221
00222 setMultipleAuthCaching( true );
00223 reparseConfiguration();
00224 }
00225
00226 HTTPProtocol::~HTTPProtocol()
00227 {
00228 httpClose(false);
00229 }
00230
00231 void HTTPProtocol::reparseConfiguration()
00232 {
00233 kdDebug(7113) << "(" << m_pid << ") HTTPProtocol::reparseConfiguration" << endl;
00234
00235 m_strProxyRealm = QString::null;
00236 m_strProxyAuthorization = QString::null;
00237 ProxyAuthentication = AUTH_None;
00238 m_bUseProxy = false;
00239
00240 if (m_protocol == "https" || m_protocol == "webdavs")
00241 m_iDefaultPort = DEFAULT_HTTPS_PORT;
00242 else if (m_protocol == "ftp")
00243 m_iDefaultPort = DEFAULT_FTP_PORT;
00244 else
00245 m_iDefaultPort = DEFAULT_HTTP_PORT;
00246 }
00247
00248 void HTTPProtocol::resetConnectionSettings()
00249 {
00250 m_bEOF = false;
00251 m_bError = false;
00252 m_lineCount = 0;
00253 m_iWWWAuthCount = 0;
00254 m_lineCountUnget = 0;
00255 m_iProxyAuthCount = 0;
00256
00257 }
00258
00259 void HTTPProtocol::resetResponseSettings()
00260 {
00261 m_bRedirect = false;
00262 m_redirectLocation = KURL();
00263 m_bChunked = false;
00264 m_iSize = NO_SIZE;
00265
00266 m_responseHeader.clear();
00267 m_qContentEncodings.clear();
00268 m_qTransferEncodings.clear();
00269 m_sContentMD5 = QString::null;
00270 m_strMimeType = QString::null;
00271
00272 setMetaData("request-id", m_request.id);
00273 }
00274
00275 void HTTPProtocol::resetSessionSettings()
00276 {
00277
00278
00279 KURL proxy ( config()->readEntry("UseProxy") );
00280
00281 if ( m_strProxyRealm.isEmpty() || !proxy.isValid() ||
00282 m_proxyURL.host() != proxy.host() ||
00283 (!proxy.user().isNull() && proxy.user() != m_proxyURL.user()) ||
00284 (!proxy.pass().isNull() && proxy.pass() != m_proxyURL.pass()) )
00285 {
00286 m_bProxyAuthValid = false;
00287 m_proxyURL = proxy;
00288 m_bUseProxy = m_proxyURL.isValid();
00289
00290 kdDebug(7113) << "(" << m_pid << ") Using proxy: " << m_bUseProxy <<
00291 " URL: " << m_proxyURL.url() <<
00292 " Realm: " << m_strProxyRealm << endl;
00293 }
00294
00295 m_bPersistentProxyConnection = config()->readBoolEntry("PersistentProxyConnection", false);
00296 kdDebug(7113) << "(" << m_pid << ") Enable Persistent Proxy Connection: "
00297 << m_bPersistentProxyConnection << endl;
00298
00299 m_request.bUseCookiejar = config()->readBoolEntry("Cookies");
00300 m_request.bUseCache = config()->readBoolEntry("UseCache", true);
00301 m_request.bErrorPage = config()->readBoolEntry("errorPage", true);
00302 m_request.bNoAuth = config()->readBoolEntry("no-auth");
00303 m_strCacheDir = config()->readPathEntry("CacheDir");
00304 m_maxCacheAge = config()->readNumEntry("MaxCacheAge", DEFAULT_MAX_CACHE_AGE);
00305 m_request.window = config()->readEntry("window-id");
00306
00307 kdDebug(7113) << "(" << m_pid << ") Window Id = " << m_request.window << endl;
00308 kdDebug(7113) << "(" << m_pid << ") ssl_was_in_use = "
00309 << metaData ("ssl_was_in_use") << endl;
00310
00311 m_request.referrer = QString::null;
00312 if ( config()->readBoolEntry("SendReferrer", true) &&
00313 (m_protocol == "https" || m_protocol == "webdavs" ||
00314 metaData ("ssl_was_in_use") != "TRUE" ) )
00315 {
00316 KURL referrerURL ( metaData("referrer") );
00317 if (referrerURL.isValid())
00318 {
00319
00320 QString protocol = referrerURL.protocol();
00321 if (protocol.startsWith("webdav"))
00322 {
00323 protocol.replace(0, 6, "http");
00324 referrerURL.setProtocol(protocol);
00325 }
00326
00327 if (protocol.startsWith("http"))
00328 {
00329 referrerURL.setRef(QString::null);
00330 referrerURL.setUser(QString::null);
00331 referrerURL.setPass(QString::null);
00332 m_request.referrer = referrerURL.url();
00333 }
00334 }
00335 }
00336
00337 if ( config()->readBoolEntry("SendLanguageSettings", true) )
00338 {
00339 m_request.charsets = config()->readEntry( "Charsets", "iso-8859-1" );
00340
00341 if ( !m_request.charsets.isEmpty() )
00342 m_request.charsets += DEFAULT_PARTIAL_CHARSET_HEADER;
00343
00344 m_request.languages = config()->readEntry( "Languages", DEFAULT_LANGUAGE_HEADER );
00345 }
00346 else
00347 {
00348 m_request.charsets = QString::null;
00349 m_request.languages = QString::null;
00350 }
00351
00352
00353 QString resumeOffset = metaData("resume");
00354 if ( !resumeOffset.isEmpty() )
00355 m_request.offset = resumeOffset.toInt();
00356 else
00357 m_request.offset = 0;
00358
00359 m_request.disablePassDlg = config()->readBoolEntry("DisablePassDlg", false);
00360 m_request.allowCompressedPage = config()->readBoolEntry("AllowCompressedPage", true);
00361 m_request.id = metaData("request-id");
00362
00363
00364 if ( config()->readBoolEntry("SendUserAgent", true) )
00365 m_request.userAgent = metaData("UserAgent");
00366 else
00367 m_request.userAgent = QString::null;
00368
00369
00370
00371
00372 if ( m_request.bUseCache )
00373 cleanCache();
00374
00375
00376 if ( m_bIsSSL && m_bUseProxy && m_proxyURL.protocol() != "https" &&
00377 m_proxyURL.protocol() != "webdavs")
00378 {
00379 m_bNeedTunnel = true;
00380 setRealHost( m_request.hostname );
00381 kdDebug(7113) << "(" << m_pid << ") SSL tunnel: Setting real hostname to: "
00382 << m_request.hostname << endl;
00383 }
00384 else
00385 {
00386 m_bNeedTunnel = false;
00387 setRealHost( QString::null);
00388 }
00389
00390 m_responseCode = 0;
00391 m_prevResponseCode = 0;
00392
00393 m_strRealm = QString::null;
00394 m_strAuthorization = QString::null;
00395 Authentication = AUTH_None;
00396
00397
00398 m_proxyConnTimeout = proxyConnectTimeout();
00399 m_remoteConnTimeout = connectTimeout();
00400 m_remoteRespTimeout = responseTimeout();
00401
00402
00403 setSSLMetaData();
00404
00405
00406 setMetaData("referrer", m_request.referrer);
00407
00408
00409
00410
00411 m_bKeepAlive = true;
00412 m_keepAliveTimeout = 0;
00413 m_bUnauthorized = false;
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423 m_bFirstRequest = false;
00424 }
00425
00426 void HTTPProtocol::setHost( const QString& host, int port,
00427 const QString& user, const QString& pass )
00428 {
00429
00430 if ( m_request.hostname != host )
00431 m_davHostOk = m_davHostUnsupported = false;
00432
00433
00434 if (host.find(':') == -1)
00435 {
00436 m_request.hostname = host;
00437 m_request.encoded_hostname = KIDNA::toAscii(host);
00438 }
00439 else
00440 {
00441 m_request.hostname = host;
00442 int pos = host.find('%');
00443 if (pos == -1)
00444 m_request.encoded_hostname = '[' + host + ']';
00445 else
00446
00447 m_request.encoded_hostname = '[' + host.left(pos) + ']';
00448 }
00449 m_request.port = (port == 0) ? m_iDefaultPort : port;
00450 m_request.user = user;
00451 m_request.passwd = pass;
00452
00453 m_bIsTunneled = false;
00454
00455 kdDebug(7113) << "(" << m_pid << ") Hostname is now: " << m_request.hostname <<
00456 " (" << m_request.encoded_hostname << ")" <<endl;
00457 }
00458
00459 bool HTTPProtocol::checkRequestURL( const KURL& u )
00460 {
00461 kdDebug (7113) << "(" << m_pid << ") HTTPProtocol::checkRequestURL: " << u.url() << endl;
00462
00463 m_request.url = u;
00464
00465 if (m_request.hostname.isEmpty())
00466 {
00467 error( KIO::ERR_UNKNOWN_HOST, i18n("No host specified."));
00468 return false;
00469 }
00470
00471 if (u.path().isEmpty())
00472 {
00473 KURL newUrl(u);
00474 newUrl.setPath("/");
00475 redirection(newUrl);
00476 finished();
00477 return false;
00478 }
00479
00480 if ( m_protocol != u.protocol().latin1() )
00481 {
00482 short unsigned int oldDefaultPort = m_iDefaultPort;
00483 m_protocol = u.protocol().latin1();
00484 reparseConfiguration();
00485 if ( m_iDefaultPort != oldDefaultPort &&
00486 m_request.port == oldDefaultPort )
00487 m_request.port = m_iDefaultPort;
00488 }
00489
00490 resetSessionSettings();
00491 return true;
00492 }
00493
00494 void HTTPProtocol::retrieveContent( bool dataInternal )
00495 {
00496 kdDebug (7113) << "(" << m_pid << ") HTTPProtocol::retrieveContent " << endl;
00497 if ( !retrieveHeader( false ) )
00498 {
00499 if ( m_bError )
00500 return;
00501 }
00502 else
00503 {
00504 if ( !readBody( dataInternal ) && m_bError )
00505 return;
00506 }
00507
00508 httpClose(m_bKeepAlive);
00509
00510
00511
00512 if ( !dataInternal )
00513 {
00514 if ((m_responseCode == 204) &&
00515 ((m_request.method == HTTP_GET) || (m_request.method == HTTP_POST)))
00516 error(ERR_NO_CONTENT, "");
00517 else
00518 finished();
00519 }
00520 }
00521
00522 bool HTTPProtocol::retrieveHeader( bool close_connection )
00523 {
00524 kdDebug (7113) << "(" << m_pid << ") HTTPProtocol::retrieveHeader " << endl;
00525 while ( 1 )
00526 {
00527 if (!httpOpen())
00528 return false;
00529
00530 resetResponseSettings();
00531 if (!readHeader())
00532 {
00533 if ( m_bError )
00534 return false;
00535
00536 if (m_bIsTunneled)
00537 {
00538 kdDebug(7113) << "(" << m_pid << ") Re-establishing SSL tunnel..." << endl;
00539 httpCloseConnection();
00540 }
00541 }
00542 else
00543 {
00544
00545
00546 kdDebug(7113) << "(" << m_pid << ") Previous Response: "
00547 << m_prevResponseCode << endl;
00548 kdDebug(7113) << "(" << m_pid << ") Current Response: "
00549 << m_responseCode << endl;
00550
00551 if (isSSLTunnelEnabled() && m_bIsSSL && !m_bUnauthorized && !m_bError)
00552 {
00553
00554 if ( m_responseCode < 400 )
00555 {
00556 kdDebug(7113) << "(" << m_pid << ") Unset tunneling flag!" << endl;
00557 setEnableSSLTunnel( false );
00558 m_bIsTunneled = true;
00559
00560 m_responseCode = m_prevResponseCode;
00561 continue;
00562 }
00563 else
00564 {
00565 if ( !m_request.bErrorPage )
00566 {
00567 kdDebug(7113) << "(" << m_pid << ") Sending an error message!" << endl;
00568 error( ERR_UNKNOWN_PROXY_HOST, m_proxyURL.host() );
00569 return false;
00570 }
00571
00572 kdDebug(7113) << "(" << m_pid << ") Sending an error page!" << endl;
00573 }
00574 }
00575
00576 if (m_responseCode < 400 && (m_prevResponseCode == 401 ||
00577 m_prevResponseCode == 407))
00578 saveAuthorization();
00579 break;
00580 }
00581 }
00582
00583
00584 if (!m_bufPOST.isEmpty())
00585 {
00586 m_bufPOST.resize(0);
00587 kdDebug(7113) << "(" << m_pid << ") HTTP::retreiveHeader: Cleared POST "
00588 "buffer..." << endl;
00589 }
00590
00591 if ( close_connection )
00592 {
00593 httpClose(m_bKeepAlive);
00594 finished();
00595 }
00596
00597 return true;
00598 }
00599
00600 void HTTPProtocol::stat(const KURL& url)
00601 {
00602 kdDebug(7113) << "(" << m_pid << ") HTTPProtocol::stat " << url.prettyURL()
00603 << endl;
00604
00605 if ( !checkRequestURL( url ) )
00606 return;
00607
00608 if ( m_protocol != "webdav" && m_protocol != "webdavs" )
00609 {
00610 QString statSide = metaData(QString::fromLatin1("statSide"));
00611 if ( statSide != "source" )
00612 {
00613
00614 error( ERR_DOES_NOT_EXIST, url.prettyURL() );
00615 return;
00616 }
00617
00618
00619 UDSEntry entry;
00620 UDSAtom atom;
00621 atom.m_uds = KIO::UDS_NAME;
00622 atom.m_str = url.fileName();
00623 entry.append( atom );
00624
00625 atom.m_uds = KIO::UDS_FILE_TYPE;
00626 atom.m_long = S_IFREG;
00627 entry.append( atom );
00628
00629 atom.m_uds = KIO::UDS_ACCESS;
00630 atom.m_long = S_IRUSR | S_IRGRP | S_IROTH;
00631 entry.append( atom );
00632
00633 statEntry( entry );
00634 finished();
00635 return;
00636 }
00637
00638 davStatList( url );
00639 }
00640
00641 void HTTPProtocol::listDir( const KURL& url )
00642 {
00643 kdDebug(7113) << "(" << m_pid << ") HTTPProtocol::listDir " << url.url()
00644 << endl;
00645
00646 if ( !checkRequestURL( url ) )
00647 return;
00648
00649 if (!url.protocol().startsWith("webdav")) {
00650 error(ERR_UNSUPPORTED_ACTION, url.prettyURL());
00651 return;
00652 }
00653
00654 davStatList( url, false );
00655 }
00656
00657 void HTTPProtocol::davSetRequest( const QCString& requestXML )
00658 {
00659
00660 m_bufPOST = requestXML;
00661
00662 if (m_bufPOST.size())
00663 m_bufPOST.truncate( m_bufPOST.size() - 1 );
00664 }
00665
00666 void HTTPProtocol::davStatList( const KURL& url, bool stat )
00667 {
00668 UDSEntry entry;
00669 UDSAtom atom;
00670
00671
00672 if ( !davHostOk() )
00673 return;
00674
00675
00676 QString query = metaData("davSearchQuery");
00677 if ( !query.isEmpty() )
00678 {
00679 QCString request = "<?xml version=\"1.0\"?>\r\n";
00680 request.append( "<D:searchrequest xmlns:D=\"DAV:\">\r\n" );
00681 request.append( query.utf8() );
00682 request.append( "</D:searchrequest>\r\n" );
00683
00684 davSetRequest( request );
00685 } else {
00686
00687 QCString request;
00688 request = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
00689 "<D:propfind xmlns:D=\"DAV:\">";
00690
00691
00692 if ( hasMetaData( "davRequestResponse" ) )
00693 request += metaData( "davRequestResponse" ).utf8();
00694 else {
00695
00696 request += "<D:prop>"
00697 "<D:creationdate/>"
00698 "<D:getcontentlength/>"
00699 "<D:displayname/>"
00700 "<D:source/>"
00701 "<D:getcontentlanguage/>"
00702 "<D:getcontenttype/>"
00703 "<D:executable/>"
00704 "<D:getlastmodified/>"
00705 "<D:getetag/>"
00706 "<D:supportedlock/>"
00707 "<D:lockdiscovery/>"
00708 "<D:resourcetype/>"
00709 "</D:prop>";
00710 }
00711 request += "</D:propfind>";
00712
00713 davSetRequest( request );
00714 }
00715
00716
00717 m_request.method = query.isEmpty() ? DAV_PROPFIND : DAV_SEARCH;
00718 m_request.query = QString::null;
00719 m_request.cache = CC_Reload;
00720 m_request.doProxy = m_bUseProxy;
00721 m_request.davData.depth = stat ? 0 : 1;
00722 if (!stat)
00723 m_request.url.adjustPath(+1);
00724
00725 retrieveContent( true );
00726
00727
00728 if (m_bRedirect) {
00729 finished();
00730 return;
00731 }
00732
00733 QDomDocument multiResponse;
00734 multiResponse.setContent( m_bufWebDavData, true );
00735
00736 bool hasResponse = false;
00737
00738 for ( QDomNode n = multiResponse.documentElement().firstChild();
00739 !n.isNull(); n = n.nextSibling())
00740 {
00741 QDomElement thisResponse = n.toElement();
00742 if (thisResponse.isNull())
00743 continue;
00744
00745 hasResponse = true;
00746
00747 QDomElement href = thisResponse.namedItem( "href" ).toElement();
00748 if ( !href.isNull() )
00749 {
00750 entry.clear();
00751
00752 QString urlStr = href.text();
00753 int encoding = remoteEncoding()->encodingMib();
00754 if ((encoding == 106) && (!KStringHandler::isUtf8(KURL::decode_string(urlStr, 4).latin1())))
00755 encoding = 4;
00756
00757 KURL thisURL ( urlStr, encoding );
00758
00759 atom.m_uds = KIO::UDS_NAME;
00760
00761 if ( thisURL.isValid() ) {
00762
00763 if ( !stat && thisURL.path(+1).length() == url.path(+1).length() )
00764 continue;
00765
00766 atom.m_str = thisURL.fileName();
00767 } else {
00768
00769 atom.m_str = href.text();
00770 }
00771
00772 entry.append( atom );
00773
00774 QDomNodeList propstats = thisResponse.elementsByTagName( "propstat" );
00775
00776 davParsePropstats( propstats, entry );
00777
00778 if ( stat )
00779 {
00780
00781 statEntry( entry );
00782 finished();
00783 return;
00784 }
00785 else
00786 {
00787 listEntry( entry, false );
00788 }
00789 }
00790 else
00791 {
00792 kdDebug(7113) << "Error: no URL contained in response to PROPFIND on "
00793 << url.prettyURL() << endl;
00794 }
00795 }
00796
00797 if ( stat || !hasResponse )
00798 {
00799 error( ERR_DOES_NOT_EXIST, url.prettyURL() );
00800 }
00801 else
00802 {
00803 listEntry( entry, true );
00804 finished();
00805 }
00806 }
00807
00808 void HTTPProtocol::davGeneric( const KURL& url, KIO::HTTP_METHOD method )
00809 {
00810 kdDebug(7113) << "(" << m_pid << ") HTTPProtocol::davGeneric " << url.url()
00811 << endl;
00812
00813 if ( !checkRequestURL( url ) )
00814 return;
00815
00816
00817 if ( !davHostOk() )
00818 return;
00819
00820
00821 m_request.method = method;
00822 m_request.query = QString::null;
00823 m_request.cache = CC_Reload;
00824 m_request.doProxy = m_bUseProxy;
00825
00826 retrieveContent( false );
00827 }
00828
00829 int HTTPProtocol::codeFromResponse( const QString& response )
00830 {
00831 int firstSpace = response.find( ' ' );
00832 int secondSpace = response.find( ' ', firstSpace + 1 );
00833 return response.mid( firstSpace + 1, secondSpace - firstSpace - 1 ).toInt();
00834 }
00835
00836 void HTTPProtocol::davParsePropstats( const QDomNodeList& propstats, UDSEntry& entry )
00837 {
00838 QString mimeType;
00839 UDSAtom atom;
00840 bool foundExecutable = false;
00841 bool isDirectory = false;
00842 uint lockCount = 0;
00843 uint supportedLockCount = 0;
00844
00845 for ( uint i = 0; i < propstats.count(); i++)
00846 {
00847 QDomElement propstat = propstats.item(i).toElement();
00848
00849 QDomElement status = propstat.namedItem( "status" ).toElement();
00850 if ( status.isNull() )
00851 {
00852
00853 kdDebug(7113) << "Error, no status code in this propstat" << endl;
00854 return;
00855 }
00856
00857 int code = codeFromResponse( status.text() );
00858
00859 if ( code != 200 )
00860 {
00861 kdDebug(7113) << "Warning: status code " << code << " (this may mean that some properties are unavailable" << endl;
00862 continue;
00863 }
00864
00865 QDomElement prop = propstat.namedItem( "prop" ).toElement();
00866 if ( prop.isNull() )
00867 {
00868 kdDebug(7113) << "Error: no prop segment in this propstat." << endl;
00869 return;
00870 }
00871
00872 if ( hasMetaData( "davRequestResponse" ) )
00873 {
00874 atom.m_uds = KIO::UDS_XML_PROPERTIES;
00875 QDomDocument doc;
00876 doc.appendChild(prop);
00877 atom.m_str = doc.toString();
00878 entry.append( atom );
00879 }
00880
00881 for ( QDomNode n = prop.firstChild(); !n.isNull(); n = n.nextSibling() )
00882 {
00883 QDomElement property = n.toElement();
00884 if (property.isNull())
00885 continue;
00886
00887 if ( property.namespaceURI() != "DAV:" )
00888 {
00889
00890 continue;
00891 }
00892
00893 if ( property.tagName() == "creationdate" )
00894 {
00895
00896 atom.m_uds = KIO::UDS_CREATION_TIME;
00897 atom.m_long = parseDateTime( property.text(), property.attribute("dt") );
00898 entry.append( atom );
00899 }
00900 else if ( property.tagName() == "getcontentlength" )
00901 {
00902
00903 atom.m_uds = KIO::UDS_SIZE;
00904 atom.m_long = property.text().toULong();
00905 entry.append( atom );
00906 }
00907 else if ( property.tagName() == "displayname" )
00908 {
00909
00910 setMetaData( "davDisplayName", property.text() );
00911 }
00912 else if ( property.tagName() == "source" )
00913 {
00914
00915 QDomElement source = property.namedItem( "link" ).toElement()
00916 .namedItem( "dst" ).toElement();
00917 if ( !source.isNull() )
00918 setMetaData( "davSource", source.text() );
00919 }
00920 else if ( property.tagName() == "getcontentlanguage" )
00921 {
00922
00923 setMetaData( "davContentLanguage", property.text() );
00924 }
00925 else if ( property.tagName() == "getcontenttype" )
00926 {
00927
00928
00929
00930 if ( property.text() == "httpd/unix-directory" )
00931 {
00932 isDirectory = true;
00933 }
00934 else
00935 {
00936 mimeType = property.text();
00937 }
00938 }
00939 else if ( property.tagName() == "executable" )
00940 {
00941
00942 if ( property.text() == "T" )
00943 foundExecutable = true;
00944
00945 }
00946 else if ( property.tagName() == "getlastmodified" )
00947 {
00948
00949 atom.m_uds = KIO::UDS_MODIFICATION_TIME;
00950 atom.m_long = parseDateTime( property.text(), property.attribute("dt") );
00951 entry.append( atom );
00952
00953 }
00954 else if ( property.tagName() == "getetag" )
00955 {
00956
00957 setMetaData( "davEntityTag", property.text() );
00958 }
00959 else if ( property.tagName() == "supportedlock" )
00960 {
00961
00962 for ( QDomNode n2 = property.firstChild(); !n2.isNull(); n2 = n2.nextSibling() )
00963 {
00964 QDomElement lockEntry = n2.toElement();
00965 if ( lockEntry.tagName() == "lockentry" )
00966 {
00967 QDomElement lockScope = lockEntry.namedItem( "lockscope" ).toElement();
00968 QDomElement lockType = lockEntry.namedItem( "locktype" ).toElement();
00969 if ( !lockScope.isNull() && !lockType.isNull() )
00970 {
00971
00972 supportedLockCount++;
00973 QString scope = lockScope.firstChild().toElement().tagName();
00974 QString type = lockType.firstChild().toElement().tagName();
00975
00976 setMetaData( QString("davSupportedLockScope%1").arg(supportedLockCount), scope );
00977 setMetaData( QString("davSupportedLockType%1").arg(supportedLockCount), type );
00978 }
00979 }
00980 }
00981 }
00982 else if ( property.tagName() == "lockdiscovery" )
00983 {
00984
00985 davParseActiveLocks( property.elementsByTagName( "activelock" ), lockCount );
00986 }
00987 else if ( property.tagName() == "resourcetype" )
00988 {
00989
00990 if ( !property.namedItem( "collection" ).toElement().isNull() )
00991 {
00992
00993 isDirectory = true;
00994 }
00995 }
00996 else
00997 {
00998 kdDebug(7113) << "Found unknown webdav property: " << property.tagName() << endl;
00999 }
01000 }
01001 }
01002
01003 setMetaData( "davLockCount", QString("%1").arg(lockCount) );
01004 setMetaData( "davSupportedLockCount", QString("%1").arg(supportedLockCount) );
01005
01006 atom.m_uds = KIO::UDS_FILE_TYPE;
01007 atom.m_long = isDirectory ? S_IFDIR : S_IFREG;
01008 entry.append( atom );
01009
01010 if ( foundExecutable || isDirectory )
01011 {
01012
01013 atom.m_uds = KIO::UDS_ACCESS;
01014 atom.m_long = 0700;
01015 entry.append(atom);
01016 }
01017 else
01018 {
01019 atom.m_uds = KIO::UDS_ACCESS;
01020 atom.m_long = 0600;
01021 entry.append(atom);
01022 }
01023
01024 if ( !isDirectory && !mimeType.isEmpty() )
01025 {
01026 atom.m_uds = KIO::UDS_MIME_TYPE;
01027 atom.m_str = mimeType;
01028 entry.append( atom );
01029 }
01030 }
01031
01032 void HTTPProtocol::davParseActiveLocks( const QDomNodeList& activeLocks,
01033 uint& lockCount )
01034 {
01035 for ( uint i = 0; i < activeLocks.count(); i++ )
01036 {
01037 QDomElement activeLock = activeLocks.item(i).toElement();
01038
01039 lockCount++;
01040
01041 QDomElement lockScope = activeLock.namedItem( "lockscope" ).toElement();
01042 QDomElement lockType = activeLock.namedItem( "locktype" ).toElement();
01043 QDomElement lockDepth = activeLock.namedItem( "depth" ).toElement();
01044
01045 QDomElement lockOwner = activeLock.namedItem( "owner" ).toElement();
01046 QDomElement lockTimeout = activeLock.namedItem( "timeout" ).toElement();
01047 QDomElement lockToken = activeLock.namedItem( "locktoken" ).toElement();
01048
01049 if ( !lockScope.isNull() && !lockType.isNull() && !lockDepth.isNull() )
01050 {
01051
01052 lockCount++;
01053 QString scope = lockScope.firstChild().toElement().tagName();
01054 QString type = lockType.firstChild().toElement().tagName();
01055 QString depth = lockDepth.text();
01056
01057 setMetaData( QString("davLockScope%1").arg( lockCount ), scope );
01058 setMetaData( QString("davLockType%1").arg( lockCount ), type );
01059 setMetaData( QString("davLockDepth%1").arg( lockCount ), depth );
01060
01061 if ( !lockOwner.isNull() )
01062 setMetaData( QString("davLockOwner%1").arg( lockCount ), lockOwner.text() );
01063
01064 if ( !lockTimeout.isNull() )
01065 setMetaData( QString("davLockTimeout%1").arg( lockCount ), lockTimeout.text() );
01066
01067 if ( !lockToken.isNull() )
01068 {
01069 QDomElement tokenVal = lockScope.namedItem( "href" ).toElement();
01070 if ( !tokenVal.isNull() )
01071 setMetaData( QString("davLockToken%1").arg( lockCount ), tokenVal.text() );
01072 }
01073 }
01074 }
01075 }
01076
01077 long HTTPProtocol::parseDateTime( const QString& input, const QString& type )
01078 {
01079 if ( type == "dateTime.tz" )
01080 {
01081 return KRFCDate::parseDateISO8601( input );
01082 }
01083 else if ( type == "dateTime.rfc1123" )
01084 {
01085 return KRFCDate::parseDate( input );
01086 }
01087
01088
01089 time_t time = KRFCDate::parseDate( input );
01090 if ( time != 0 )
01091 return time;
01092
01093 return KRFCDate::parseDateISO8601( input );
01094 }
01095
01096 QString HTTPProtocol::davProcessLocks()
01097 {
01098 if ( hasMetaData( "davLockCount" ) )
<