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("\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 setMetaData("referrer", m_request.referrer);
00404
00405
00406 setSSLMetaData();
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 davStatList( url, false );
00650 }
00651
00652 void HTTPProtocol::davSetRequest( const QCString& requestXML )
00653 {
00654
00655 m_bufPOST = requestXML;
00656
00657 if (m_bufPOST.size())
00658 m_bufPOST.truncate( m_bufPOST.size() - 1 );
00659 }
00660
00661 void HTTPProtocol::davStatList( const KURL& url, bool stat )
00662 {
00663 UDSEntry entry;
00664 UDSAtom atom;
00665
00666
00667 if ( !davHostOk() )
00668 return;
00669
00670
00671 QString query = metaData("davSearchQuery");
00672 if ( !query.isEmpty() )
00673 {
00674 QCString request = "<?xml version=\"1.0\"?>\r\n";
00675 request.append( "<D:searchrequest xmlns:D=\"DAV:\">\r\n" );
00676 request.append( query.utf8() );
00677 request.append( "</D:searchrequest>\r\n" );
00678
00679 davSetRequest( request );
00680 } else {
00681
00682 QCString request;
00683 request = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
00684 "<D:propfind xmlns:D=\"DAV:\">";
00685
00686
00687 if ( hasMetaData( "davRequestResponse" ) )
00688 request += metaData( "davRequestResponse" ).utf8();
00689 else {
00690
00691 request += "<D:prop>"
00692 "<D:creationdate/>"
00693 "<D:getcontentlength/>"
00694 "<D:displayname/>"
00695 "<D:source/>"
00696 "<D:getcontentlanguage/>"
00697 "<D:getcontenttype/>"
00698 "<D:executable/>"
00699 "<D:getlastmodified/>"
00700 "<D:getetag/>"
00701 "<D:supportedlock/>"
00702 "<D:lockdiscovery/>"
00703 "<D:resourcetype/>"
00704 "</D:prop>";
00705 }
00706 request += "</D:propfind>";
00707
00708 davSetRequest( request );
00709 }
00710
00711
00712 m_request.method = query.isEmpty() ? DAV_PROPFIND : DAV_SEARCH;
00713 m_request.query = QString::null;
00714 m_request.cache = CC_Reload;
00715 m_request.doProxy = m_bUseProxy;
00716 m_request.davData.depth = stat ? 0 : 1;
00717 if (!stat)
00718 m_request.url.adjustPath(+1);
00719
00720 retrieveContent( true );
00721
00722
00723 if (m_bRedirect) {
00724 finished();
00725 return;
00726 }
00727
00728 QDomDocument multiResponse;
00729 multiResponse.setContent( m_bufWebDavData, true );
00730
00731 bool hasResponse = false;
00732
00733 for ( QDomNode n = multiResponse.documentElement().firstChild();
00734 !n.isNull(); n = n.nextSibling())
00735 {
00736 QDomElement thisResponse = n.toElement();
00737 if (thisResponse.isNull())
00738 continue;
00739
00740 hasResponse = true;
00741
00742 QDomElement href = thisResponse.namedItem( "href" ).toElement();
00743 if ( !href.isNull() )
00744 {
00745 entry.clear();
00746
00747 QString urlStr = href.text();
00748 int encoding = remoteEncoding()->encodingMib();
00749 if ((encoding == 106) && (!KStringHandler::isUtf8(KURL::decode_string(urlStr, 4).latin1())))
00750 encoding = 4;
00751
00752 KURL thisURL ( urlStr, encoding );
00753
00754 atom.m_uds = KIO::UDS_NAME;
00755
00756 if ( thisURL.isValid() ) {
00757
00758 if ( !stat && thisURL.path(+1).length() == url.path(+1).length() )
00759 continue;
00760
00761 atom.m_str = thisURL.fileName();
00762 } else {
00763
00764 atom.m_str = href.text();
00765 }
00766
00767 entry.append( atom );
00768
00769 QDomNodeList propstats = thisResponse.elementsByTagName( "propstat" );
00770
00771 davParsePropstats( propstats, entry );
00772
00773 if ( stat )
00774 {
00775
00776 statEntry( entry );
00777 finished();
00778 return;
00779 }
00780 else
00781 {
00782 listEntry( entry, false );
00783 }
00784 }
00785 else
00786 {
00787 kdDebug(7113) << "Error: no URL contained in response to PROPFIND on "
00788 << url.prettyURL() << endl;
00789 }
00790 }
00791
00792 if ( stat || !hasResponse )
00793 {
00794 error( ERR_DOES_NOT_EXIST, url.prettyURL() );
00795 }
00796 else
00797 {
00798 listEntry( entry, true );
00799 finished();
00800 }
00801 }
00802
00803 void HTTPProtocol::davGeneric( const KURL& url, KIO::HTTP_METHOD method )
00804 {
00805 kdDebug(7113) << "(" << m_pid << ") HTTPProtocol::davGeneric " << url.url()
00806 << endl;
00807
00808 if ( !checkRequestURL( url ) )
00809 return;
00810
00811
00812 if ( !davHostOk() )
00813 return;
00814
00815
00816 m_request.method = method;
00817 m_request.query = QString::null;
00818 m_request.cache = CC_Reload;
00819 m_request.doProxy = m_bUseProxy;
00820
00821 retrieveContent( false );
00822 }
00823
00824 int HTTPProtocol::codeFromResponse( const QString& response )
00825 {
00826 int firstSpace = response.find( ' ' );
00827 int secondSpace = response.find( ' ', firstSpace + 1 );
00828 return response.mid( firstSpace + 1, secondSpace - firstSpace - 1 ).toInt();
00829 }
00830
00831 void HTTPProtocol::davParsePropstats( const QDomNodeList& propstats, UDSEntry& entry )
00832 {
00833 QString mimeType;
00834 UDSAtom atom;
00835 bool foundExecutable = false;
00836 bool isDirectory = false;
00837 uint lockCount = 0;
00838 uint supportedLockCount = 0;
00839
00840 for ( uint i = 0; i < propstats.count(); i++)
00841 {
00842 QDomElement propstat = propstats.item(i).toElement();
00843
00844 QDomElement status = propstat.namedItem( "status" ).toElement();
00845 if ( status.isNull() )
00846 {
00847
00848 kdDebug(7113) << "Error, no status code in this propstat" << endl;
00849 return;
00850 }
00851
00852 int code = codeFromResponse( status.text() );
00853
00854 if ( code != 200 )
00855 {
00856 kdDebug(7113) << "Warning: status code " << code << " (this may mean that some properties are unavailable" << endl;
00857 continue;
00858 }
00859
00860 QDomElement prop = propstat.namedItem( "prop" ).toElement();
00861 if ( prop.isNull() )
00862 {
00863 kdDebug(7113) << "Error: no prop segment in this propstat." << endl;
00864 return;
00865 }
00866
00867 if ( hasMetaData( "davRequestResponse" ) )
00868 {
00869 atom.m_uds = KIO::UDS_XML_PROPERTIES;
00870 QDomDocument doc;
00871 doc.appendChild(prop);
00872 atom.m_str = doc.toString();
00873 entry.append( atom );
00874 }
00875
00876 for ( QDomNode n = prop.firstChild(); !n.isNull(); n = n.nextSibling() )
00877 {
00878 QDomElement property = n.toElement();
00879 if (property.isNull())
00880 continue;
00881
00882 if ( property.namespaceURI() != "DAV:" )
00883 {
00884
00885 continue;
00886 }
00887
00888 if ( property.tagName() == "creationdate" )
00889 {
00890
00891 atom.m_uds = KIO::UDS_CREATION_TIME;
00892 atom.m_long = parseDateTime( property.text(), property.attribute("dt") );
00893 entry.append( atom );
00894 }
00895 else if ( property.tagName() == "getcontentlength" )
00896 {
00897
00898 atom.m_uds = KIO::UDS_SIZE;
00899 atom.m_long = property.text().toULong();
00900 entry.append( atom );
00901 }
00902 else if ( property.tagName() == "displayname" )
00903 {
00904
00905 setMetaData( "davDisplayName", property.text() );
00906 }
00907 else if ( property.tagName() == "source" )
00908 {
00909
00910 QDomElement source = property.namedItem( "link" ).toElement()
00911 .namedItem( "dst" ).toElement();
00912 if ( !source.isNull() )
00913 setMetaData( "davSource", source.text() );
00914 }
00915 else if ( property.tagName() == "getcontentlanguage" )
00916 {
00917
00918 setMetaData( "davContentLanguage", property.text() );
00919 }
00920 else if ( property.tagName() == "getcontenttype" )
00921 {
00922
00923
00924
00925 if ( property.text() == "httpd/unix-directory" )
00926 {
00927 isDirectory = true;
00928 }
00929 else
00930 {
00931 mimeType = property.text();
00932 }
00933 }
00934 else if ( property.tagName() == "executable" )
00935 {
00936
00937 if ( property.text() == "T" )
00938 foundExecutable = true;
00939
00940 }
00941 else if ( property.tagName() == "getlastmodified" )
00942 {
00943
00944 atom.m_uds = KIO::UDS_MODIFICATION_TIME;
00945 atom.m_long = parseDateTime( property.text(), property.attribute("dt") );
00946 entry.append( atom );
00947
00948 }
00949 else if ( property.tagName() == "getetag" )
00950 {
00951
00952 setMetaData( "davEntityTag", property.text() );
00953 }
00954 else if ( property.tagName() == "supportedlock" )
00955 {
00956
00957 for ( QDomNode n2 = property.firstChild(); !n2.isNull(); n2 = n2.nextSibling() )
00958 {
00959 QDomElement lockEntry = n2.toElement();
00960 if ( lockEntry.tagName() == "lockentry" )
00961 {
00962 QDomElement lockScope = lockEntry.namedItem( "lockscope" ).toElement();
00963 QDomElement lockType = lockEntry.namedItem( "locktype" ).toElement();
00964 if ( !lockScope.isNull() && !lockType.isNull() )
00965 {
00966
00967 supportedLockCount++;
00968 QString scope = lockScope.firstChild().toElement().tagName();
00969 QString type = lockType.firstChild().toElement().tagName();
00970
00971 setMetaData( QString("davSupportedLockScope%1").arg(supportedLockCount), scope );
00972 setMetaData( QString("davSupportedLockType%1").arg(supportedLockCount), type );
00973 }
00974 }
00975 }
00976 }
00977 else if ( property.tagName() == "lockdiscovery" )
00978 {
00979
00980 davParseActiveLocks( property.elementsByTagName( "activelock" ), lockCount );
00981 }
00982 else if ( property.tagName() == "resourcetype" )
00983 {
00984
00985 if ( !property.namedItem( "collection" ).toElement().isNull() )
00986 {
00987
00988 isDirectory = true;
00989 }
00990 }
00991 else
00992 {
00993 kdDebug(7113) << "Found unknown webdav property: " << property.tagName() << endl;
00994 }
00995 }
00996 }
00997
00998 setMetaData( "davLockCount", QString("%1").arg(lockCount) );
00999 setMetaData( "davSupportedLockCount", QString("%1").arg(supportedLockCount) );
01000
01001 atom.m_uds = KIO::UDS_FILE_TYPE;
01002 atom.m_long = isDirectory ? S_IFDIR : S_IFREG;
01003 entry.append( atom );
01004
01005 if ( foundExecutable || isDirectory )
01006 {
01007
01008 atom.m_uds = KIO::UDS_ACCESS;
01009 atom.m_long = 0700;
01010 entry.append(atom);
01011 }
01012 else
01013 {
01014 atom.m_uds = KIO::UDS_ACCESS;
01015 atom.m_long = 0600;
01016 entry.append(atom);
01017 }
01018
01019 if ( !isDirectory && !mimeType.isEmpty() )
01020 {
01021 atom.m_uds = KIO::UDS_MIME_TYPE;
01022 atom.m_str = mimeType;
01023 entry.append( atom );
01024 }
01025 }
01026
01027 void HTTPProtocol::davParseActiveLocks( const QDomNodeList& activeLocks,
01028 uint& lockCount )
01029 {
01030 for ( uint i = 0; i < activeLocks.count(); i++ )
01031 {
01032 QDomElement activeLock = activeLocks.item(i).toElement();
01033
01034 lockCount++;
01035
01036 QDomElement lockScope = activeLock.namedItem( "lockscope" ).toElement();
01037 QDomElement lockType = activeLock.namedItem( "locktype" ).toElement();
01038 QDomElement lockDepth = activeLock.namedItem( "depth" ).toElement();
01039
01040 QDomElement lockOwner = activeLock.namedItem( "owner" ).toElement();
01041 QDomElement lockTimeout = activeLock.namedItem( "timeout" ).toElement();
01042 QDomElement lockToken = activeLock.namedItem( "locktoken" ).toElement();
01043
01044 if ( !lockScope.isNull() && !lockType.isNull() && !lockDepth.isNull() )
01045 {
01046
01047 lockCount++;
01048 QString scope = lockScope.firstChild().toElement().tagName();
01049 QString type = lockType.firstChild().toElement().tagName();
01050 QString depth = lockDepth.text();
01051
01052 setMetaData( QString("davLockScope%1").arg( lockCount ), scope );
01053 setMetaData( QString("davLockType%1").arg( lockCount ), type );
01054 setMetaData( QString("davLockDepth%1").arg( lockCount ), depth );
01055
01056 if ( !lockOwner.isNull() )
01057 setMetaData( QString("davLockOwner%1").arg( lockCount ), lockOwner.text() );
01058
01059 if ( !lockTimeout.isNull() )
01060 setMetaData( QString("davLockTimeout%1").arg( lockCount ), lockTimeout.text() );
01061
01062 if ( !lockToken.isNull() )
01063 {
01064 QDomElement tokenVal = lockScope.namedItem( "href" ).toElement();
01065 if ( !tokenVal.isNull() )
01066 setMetaData( QString("davLockToken%1").arg( lockCount ), tokenVal.text() );
01067 }
01068 }
01069 }
01070 }
01071
01072 long HTTPProtocol::parseDateTime( const QString& input, const QString& type )
01073 {
01074 if ( type == "dateTime.tz" )
01075 {
01076 return KRFCDate::parseDateISO8601( input );
01077 }
01078 else if ( type == "dateTime.rfc1123" )
01079 {
01080 return KRFCDate::parseDate( input );
01081 }
01082
01083
01084 time_t time = KRFCDate::parseDate( input );
01085 if ( time != 0 )
01086 return time;
01087
01088 return KRFCDate::parseDateISO8601( input );
01089 }
01090
01091 QString HTTPProtocol::davProcessLocks()
01092 {
01093 if ( hasMetaData( "davLockCount" ) )
01094 {
01095 QString response("If:");
01096 int numLocks;
01097 numLocks = metaData( "davLockCount" ).toInt();
01098 bool bracketsOpen = false;
01099 for ( int i = 0; i < numLocks; i++ )
01100 {
01101 if ( hasMetaData( QString("davLockToken%1").arg(i) ) )
01102 {
01103 if ( hasMetaData( QString("davLockURL%1").arg(i) ) )
01104 {
01105 if ( bracketsOpen )
01106 {
01107 response += ")";
01108 bracketsOpen = false;
01109 }
01110 response += " <" + metaData( QString("davLockURL%1").arg(i) ) + ">";
01111 }
01112
01113 if ( !bracketsOpen )
01114 {
01115 response += " (";
01116 bracketsOpen = true;
01117 }
01118 else
01119 {
01120 response += " ";
01121 }
01122
01123 if ( hasMetaData( QString("davLockNot%1").arg(i) ) )
01124 response += "Not ";
01125
01126 response += "<" + metaData( QString("davLockToken%1").arg(i) ) + ">";
01127 }
01128 }
01129
01130 if ( bracketsOpen )
01131 response += ")";
01132
01133 response += "\r\n";
01134 return response;
01135 }
01136
01137 return QString::null;
01138 }
01139
01140 bool HTTPProtocol::davHostOk()
01141 {
01142
01143 return true;
01144
01145
01146 if ( m_davHostOk )
01147 {
01148 kdDebug(7113) << "(" << m_pid << ") " << k_funcinfo << " true" << endl;
01149 return true;
01150 }
01151 else if ( m_davHostUnsupported )
01152 {
01153 kdDebug(7113) << "(" << m_pid << ") " << k_funcinfo << " false" << endl;
01154 davError( -2 );
01155 return false;
01156 }
01157
01158 m_request.method = HTTP_OPTIONS;
01159
01160
01161 m_request.path = "*";
01162 m_request.query = QString::null;
01163 m_request.cache = CC_Reload;
01164 m_request.doProxy = m_bUseProxy;
01165
01166
01167 m_davCapabilities.clear();
01168
01169 retrieveHeader(false);
01170
01171 if (m_davCapabilities.count())
01172 {
01173 for (uint i = 0; i < m_davCapabilities.count(); i++)
01174 {
01175 bool ok;
01176 uint verNo = m_davCapabilities[i].toUInt(&ok);
01177 if (ok && verNo > 0 && verNo < 3)
01178 {
01179 m_davHostOk = true;
01180 kdDebug(7113) << "Server supports DAV version " << verNo << "." << endl;
01181 }
01182 }
01183
01184 if ( m_davHostOk )
01185 return true;
01186 }
01187
01188 m_davHostUnsupported = true;
01189 davError( -2 );
01190 return false;
01191 }
01192
01193
01194
01195 void HTTPProtocol::davFinished()
01196 {
01197
01198 httpClose(m_bKeepAlive);
01199 finished();
01200 }
01201
01202 void HTTPProtocol::mkdir( const KURL& url, int )
01203 {
01204 kdDebug(7113) << "(" << m_pid << ") HTTPProtocol::mkdir " << url.url()
01205 << endl;
01206
01207 if ( !checkRequestURL( url ) )
01208 return;
01209
01210 m_request.method = DAV_MKCOL;
01211 m_request.path = url.path();
01212 m_request.query = QString::null;
01213 m_request.cache = CC_Reload;
01214 m_request.doProxy = m_bUseProxy;
01215
01216 retrieveHeader( false );
01217
01218 if ( m_responseCode == 201 )
01219 davFinished();
01220 else
01221 davError();
01222 }
01223
01224 void HTTPProtocol::get( const KURL& url )
01225 {
01226 kdDebug(7113) << "(" << m_pid << ") HTTPProtocol::get " << url.url()
01227 << endl;
01228
01229 if ( !checkRequestURL( url ) )
01230 return;
01231
01232 m_request.method = HTTP_GET;
01233 m_request.path = url.path();
01234 m_request.query = url.query();
01235
01236 QString tmp = metaData("cache");
01237 if (!tmp.isEmpty())
01238 m_request.cache = parseCacheControl(tmp);
01239 else
01240 m_request.cache = DEFAULT_CACHE_CONTROL;
01241
01242 m_request.passwd = url.pass();
01243 m_request.user = url.user();
01244 m_request.doProxy = m_bUseProxy;
01245
01246 retrieveContent();
01247 }
01248
01249 void HTTPProtocol::put( const KURL &url, int, bool overwrite, bool)
01250 {
01251 kdDebug(7113) << "(" << m_pid << ") HTTPProtocol::put " << url.prettyURL()
01252 << endl;
01253
01254 if ( !checkRequestURL( url ) )
01255 return;
01256
01257
01258 if (!overwrite && m_protocol.left(6) == "webdav") {
01259
01260 if ( !davHostOk() )
01261 return;
01262
01263 QCString request;
01264 request = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
01265 "<D:propfind xmlns:D=\"DAV:\"><D:prop>"
01266 "<D:creationdate/>"
01267 "<D:getcontentlength/>"
01268 "<D:displayname/>"
01269 "<D:resourcetype/>"
01270 "</D:prop></D:propfind>";
01271
01272 davSetRequest( request );
01273
01274
01275 m_request.method = DAV_PROPFIND;
01276 m_request.query = QString::null;
01277 m_request.cache = CC_Reload;
01278 m_request.doProxy = m_bUseProxy;
01279 m_request.davData.depth = 0;
01280
01281 retrieveContent(true);
01282
01283 if (m_responseCode == 207) {
01284 error(ERR_FILE_ALREADY_EXIST, QString::null);
01285 return;
01286 }
01287
01288 m_bError = false;
01289 }
01290
01291 m_request.method = HTTP_PUT;
01292 m_request.path = url.path();
01293 m_request.query = QString::null;
01294 m_request.cache = CC_Reload;
01295 m_request.doProxy = m_bUseProxy;
01296
01297 retrieveHeader( false );
01298
01299 kdDebug(7113) << "(" << m_pid << ") HTTPProtocol::put error = " << m_bError << endl;
01300 if (m_bError)
01301 return;
01302
01303 kdDebug(7113) << "(" << m_pid << ") HTTPProtocol::put responseCode = " << m_responseCode << endl;
01304
01305 httpClose(false);
01306
01307 if ( (m_responseCode >= 200) && (m_responseCode < 300) )
01308 finished();
01309 else
01310 httpError();
01311 }
01312
01313 void HTTPProtocol::copy( const KURL& src, const KURL& dest, int, bool overwrite )
01314 {
01315 kdDebug(7113) << "(" << m_pid << ") HTTPProtocol::copy " << src.prettyURL()
01316 << " -> " << dest.prettyURL() << endl;
01317
01318 if ( !checkRequestURL( dest ) || !checkRequestURL( src ) )
01319 return;
01320
01321
01322 KURL newDest = dest;
01323 if (newDest.protocol() == "webdavs")
01324 newDest.setProtocol("https");
01325 else
01326 newDest.setProtocol("http");
01327
01328 m_request.method = DAV_COPY;
01329 m_request.path = src.path();
01330 m_request.davData.desturl = newDest.url();
01331 m_request.davData.overwrite = overwrite;
01332 m_request.query = QString::null;
01333 m_request.cache = CC_Reload;
01334 m_request.doProxy = m_bUseProxy;
01335
01336 retrieveHeader( false );
01337
01338
01339 if ( m_responseCode == 201 || m_responseCode == 204 )
01340 davFinished();
01341 else
01342 davError();
01343 }
01344
01345 void HTTPProtocol::rename( const KURL& src, const KURL& dest, bool overwrite )
01346 {
01347 kdDebug(7113) << "(" << m_pid << ") HTTPProtocol::rename " << src.prettyURL()
01348 << " -> " << dest.prettyURL() << endl;
01349
01350 if ( !checkRequestURL( dest ) || !checkRequestURL( src ) )
01351 return;
01352
01353
01354 KURL newDest = dest;
01355 if (newDest.protocol() == "webdavs")
01356 newDest.setProtocol("https");
01357 else
01358 newDest.setProtocol("http");
01359
01360 m_request.method = DAV_MOVE;
01361 m_request.path = src.path();
01362 m_request.davData.desturl = newDest.url();
01363 m_request.davData.overwrite = overwrite;
01364 m_request.query = QString::null;
01365 m_request.cache = CC_Reload;
01366 m_request.doProxy = m_bUseProxy;
01367
01368 retrieveHeader( false );
01369
01370 if ( m_responseCode == 301 )
01371 {
01372
01373
01374
01375
01376 if (m_redirectLocation.protocol() == "https")
01377 m_redirectLocation.setProtocol("webdavs");
01378 else
01379 m_redirectLocation.setProtocol("webdav");
01380
01381 if ( !checkRequestURL( m_redirectLocation ) )
01382 return;
01383
01384 m_request.method = DAV_MOVE;
01385 m_request.path = m_redirectLocation.path();
01386 m_request.davData.desturl = newDest.url();
01387 m_request.davData.overwrite = overwrite;
01388 m_request.query = QString::null;
01389 m_request.cache = CC_Reload;
01390 m_request.doProxy = m_bUseProxy;
01391
01392 retrieveHeader( false );
01393 }
01394
01395 if ( m_responseCode == 201 )
01396 davFinished();
01397 else
01398 davError();
01399 }
01400
01401 void HTTPProtocol::del( const KURL& url, bool )
01402 {
01403 kdDebug(7113) << "(" << m_pid << ") HTTPProtocol::del " << url.prettyURL()
01404 << endl;
01405
01406 if ( !checkRequestURL( url ) )
01407 return;
01408
01409 m_request.method = HTTP_DELETE;
01410 m_request.path = url.path();
01411 m_request.query = QString::null;
01412 m_request.cache = CC_Reload;
01413 m_request.doProxy = m_bUseProxy;
01414
01415 retrieveHeader( false );
01416
01417
01418
01419 if ( m_responseCode == 200 || m_responseCode == 204 )
01420 davFinished();
01421 else
01422 davError();
01423 }
01424
01425 void HTTPProtocol::post( const KURL& url )
01426 {
01427 kdDebug(7113) << "(" << m_pid << ") HTTPProtocol::post "
01428 << url.prettyURL() << endl;
01429
01430 if ( !checkRequestURL( url ) )
01431 return;
01432
01433 m_request.method = HTTP_POST;
01434 m_request.path = url.path();
01435 m_request.query = url.query();
01436 m_request.cache = CC_Reload;
01437 m_request.doProxy = m_bUseProxy;
01438
01439 retrieveContent();
01440 }
01441
01442 void HTTPProtocol::davLock( const KURL& url, const QString& scope,
01443 const QString& type, const QString& owner )
01444 {
01445 kdDebug(7113) << "(" << m_pid << ") HTTPProtocol::davLock "
01446 << url.prettyURL() << endl;
01447
01448 if ( !checkRequestURL( url ) )
01449 return;
01450
01451 m_request.method = DAV_LOCK;
01452 m_request.path = url.path();
01453 m_request.query = QString::null;
01454 m_request.cache = CC_Reload;
01455 m_request.doProxy = m_bUseProxy;
01456
01457
01458 QDomDocument lockReq;
01459
01460 QDomElement lockInfo = lockReq.createElementNS( "DAV:", "lockinfo" );
01461 lockReq.appendChild( lockInfo );
01462
01463 QDomElement lockScope = lockReq.createElement( "lockscope" );
01464 lockInfo.appendChild( lockScope );
01465
01466 lockScope.appendChild( lockReq.createElement( scope ) );
01467
01468 QDomElement lockType = lockReq.createElement( "locktype" );
01469 lockInfo.appendChild( lockType );
01470
01471 lockType.appendChild( lockReq.createElement( type ) );
01472
01473 if ( !owner.isNull() ) {
01474 QDomElement ownerElement = lockReq.createElement( "owner" );
01475 lockReq.appendChild( ownerElement );
01476
01477 QDomElement ownerHref = lockReq.createElement( "href" );
01478 ownerElement.appendChild( ownerHref );
01479
01480 ownerHref.appendChild( lockReq.createTextNode( owner ) );
01481 }
01482
01483
01484 m_bufPOST = lockReq.toCString();
01485
01486 retrieveContent( true );
01487
01488 if ( m_responseCode == 200 ) {
01489
01490 QDomDocument multiResponse;
01491 multiResponse.setContent( m_bufWebDavData, true );
01492
01493 QDomElement prop = multiResponse.documentElement().namedItem( "prop" ).toElement();
01494
01495 QDomElement lockdiscovery = prop.namedItem( "lockdiscovery" ).toElement();
01496
01497 uint lockCount = 0;
01498 davParseActiveLocks( lockdiscovery.elementsByTagName( "activelock" ), lockCount );
01499
01500 setMetaData( "davLockCount", QString("%1").arg( lockCount ) );
01501
01502 finished();
01503
01504 } else
01505 davError();
01506 }
01507
01508 void HTTPProtocol::davUnlock( const KURL& url )
01509 {
01510 kdDebug(7113) << "(" << m_pid << ") HTTPProtocol::davUnlock "
01511 << url.prettyURL() << endl;
01512
01513 if ( !checkRequestURL( url ) )
01514 return;
01515
01516 m_request.method = DAV_UNLOCK;
01517 m_request.path = url.path();
01518 m_request.query = QString::null;
01519 m_request.cache = CC_Reload;
01520 m_request.doProxy = m_bUseProxy;
01521
01522 retrieveContent( true );
01523
01524 if ( m_responseCode == 200 )
01525 finished();
01526 else
01527 davError();
01528 }
01529
01530 QString HTTPProtocol::davError( int code , QString url )
01531 {
01532 bool callError = false;
01533 if ( code == -1 ) {
01534 code = m_responseCode;
01535 callError = true;
01536 }
01537 if ( code == -2 ) {
01538 callError = true;
01539 }
01540
01541 if ( !url.isNull() )
01542 url = m_request.url.url();
01543
01544 QString action, errorString;
01545 KIO::Error kError;
01546
01547
01548 QString ow = i18n( "Otherwise, the request would have succeeded." );
01549
01550 switch ( m_request.method ) {
01551 case DAV_PROPFIND:
01552 action = i18n( "retrieve property values" );
01553 break;
01554 case DAV_PROPPATCH:
01555 action = i18n( "set property values" );
01556 break;
01557 case DAV_MKCOL:
01558 action = i18n( "create the requested folder" );
01559 break;
01560 case DAV_COPY:
01561 action = i18n( "copy the specified file or folder" );
01562 break;
01563 case DAV_MOVE:
01564 action = i18n( "move the specified file or folder" );
01565 break;
01566 case DAV_SEARCH:
01567 action = i18n( "search in the specified folder" );
01568 break;
01569 case DAV_LOCK:
01570 action = i18n( "lock the specified file or folder" );
01571 break;
01572 case DAV_UNLOCK:
01573 action = i18n( "unlock the specified file or folder" );
01574 break;
01575 case HTTP_DELETE:
01576 action = i18n( "delete the specified file or folder" );
01577 break;
01578 case HTTP_OPTIONS:
01579 action = i18n( "query the server's capabilities" );
01580 break;
01581 case HTTP_GET:
01582 action = i18n( "retrieve the contents of the specified file or folder" );
01583 break;
01584 case HTTP_PUT:
01585 case HTTP_POST:
01586 case HTTP_HEAD:
01587 default:
01588
01589 Q_ASSERT(0);
01590 }
01591
01592
01593 kError = ERR_INTERNAL;
01594 errorString = i18n("An unexpected error (%1) occurred while attempting to %2.")
01595 .arg( code ).arg( action );
01596
01597 switch ( code )
01598 {
01599 case -2:
01600
01601 kError = ERR_UNSUPPORTED_PROTOCOL;
01602 errorString = i18n("The server does not support the WebDAV protocol.");
01603 break;
01604 case 207:
01605
01606 {
01607
01608
01609
01610
01611
01612 if ( !readBody( true ) && m_bError )
01613 return QString::null;
01614
01615 QStringList errors;
01616 QDomDocument multiResponse;
01617
01618 multiResponse.setContent( m_bufWebDavData, true );
01619
01620 QDomElement multistatus = multiResponse.documentElement().namedItem( "multistatus" ).toElement();
01621
01622 QDomNodeList responses = multistatus.elementsByTagName( "response" );
01623
01624 for (uint i = 0; i < responses.count(); i++)
01625 {
01626 int errCode;
01627 QString errUrl;
01628
01629 QDomElement response = responses.item(i).toElement();
01630 QDomElement code = response.namedItem( "status" ).toElement();
01631
01632 if ( !code.isNull() )
01633 {
01634 errCode = codeFromResponse( code.text() );
01635 QDomElement href = response.namedItem( "href" ).toElement();
01636 if ( !href.isNull() )
01637 errUrl = href.text();
01638 errors << davError( errCode, errUrl );
01639 }
01640 }
01641
01642
01643 errorString = i18n("An error occurred while attempting to %1, %2. A "
01644 "summary of the reasons is below.<ul>").arg( action ).arg( url );
01645
01646 for ( QStringList::Iterator it = errors.begin(); it != errors.end(); ++it )
01647 errorString += "<li>" + *it + "</li>";
01648
01649 errorString += "</ul>";
01650 }
01651 case 403:
01652 case 500:
01653
01654 kError = ERR_ACCESS_DENIED;
01655 errorString = i18n("Access was denied while attempting to %1.").arg( action );
01656 break;
01657 case 405:
01658
01659 if ( m_request.method == DAV_MKCOL )
01660 {
01661 kError = ERR_DIR_ALREADY_EXIST;
01662 errorString = i18n("The specified folder already exists.");
01663 }
01664 break;
01665 case 409:
01666
01667 kError = ERR_ACCESS_DENIED;
01668 errorString = i18n("A resource cannot be created at the destination "
01669 "until one or more intermediate collections (folders) "
01670 "have been created.");
01671 break;
01672 case 412:
01673
01674 if ( m_request.method == DAV_COPY || m_request.method == DAV_MOVE )
01675 {
01676 kError = ERR_ACCESS_DENIED;
01677 errorString = i18n("The server was unable to maintain the liveness of "
01678 "the properties listed in the propertybehavior XML "
01679 "element or you attempted to overwrite a file while "
01680 "requesting that files are not overwritten. %1")
01681 .arg( ow );
01682
01683 }
01684 else if ( m_request.method == DAV_LOCK )
01685 {
01686 kError = ERR_ACCESS_DENIED;
01687 errorString = i18n("The requested lock could not be granted. %1").arg( ow );
01688 }
01689 break;
01690 case 415:
01691
01692 kError = ERR_ACCESS_DENIED;
01693 errorString = i18n("The server does not support the request type of the body.");
01694 break;
01695 case 423:
01696
01697 kError = ERR_ACCESS_DENIED;
01698 errorString = i18n("Unable to %1 because the resource is locked.").arg( action );
01699 break;
01700 case 425:
01701
01702 errorString = i18n("This action was prevented by another error.");
01703 break;
01704 case 502:
01705
01706 if ( m_request.method == DAV_COPY || m_request.method == DAV_MOVE )
01707 {
01708 kError = ERR_WRITE_ACCESS_DENIED;
01709 errorString = i18n("Unable to %1 because the destination server refuses "
01710 "to accept the file or folder.").arg( action );
01711 }
01712 break;
01713 case 507:
01714
01715 kError = ERR_DISK_FULL;
01716 errorString = i18n("The destination resource does not have sufficient space "
01717 "to record the state of the resource after the execution "
01718 "of this method.");
01719 break;
01720 }
01721
01722
01723
01724
01725 if ( callError )
01726 error( ERR_SLAVE_DEFINED, errorString );
01727
01728 return errorString;
01729 }
01730
01731 void HTTPProtocol::httpError()
01732 {
01733 QString action, errorString;
01734 KIO::Error kError;
01735
01736 switch ( m_request.method ) {
01737 case HTTP_PUT:
01738 action = i18n( "upload %1" ).arg(m_request.url.prettyURL());
01739 break;
01740 default:
01741
01742 Q_ASSERT(0);
01743 }
01744
01745
01746 kError = ERR_INTERNAL;
01747 errorString = i18n("An unexpected error (%1) occurred while attempting to %2.")
01748 .arg( m_responseCode ).arg( action );
01749
01750 switch ( m_responseCode )
01751 {
01752 case 403:
01753 case 405:
01754 case 500:
01755
01756
01757 kError = ERR_ACCESS_DENIED;
01758 errorString = i18n("Access was denied while attempting to %1.").arg( action );
01759 break;
01760 case 409:
01761
01762 kError = ERR_ACCESS_DENIED;
01763 errorString = i18n("A resource cannot be created at the destination "
01764 "until one or more intermediate collections (folders) "
01765 "have been created.");
01766 break;
01767 case 423:
01768
01769 kError = ERR_ACCESS_DENIED;
01770 errorString = i18n("Unable to %1 because the resource is locked.").arg( action );
01771 break;
01772 case 502:
01773
01774 kError = ERR_WRITE_ACCESS_DENIED;
01775 errorString = i18n("Unable to %1 because the destination server refuses "
01776 "to accept the file or folder.").arg( action );
01777 break;
01778 case 507:
01779
01780 kError = ERR_DISK_FULL;
01781 errorString = i18n("The destination resource does not have sufficient space "
01782 "to record the state of the resource after the execution "
01783 "of this method.");
01784 break;
01785 }
01786
01787
01788
01789
01790 error( ERR_SLAVE_DEFINED, errorString );
01791 }
01792
01793 bool HTTPProtocol::isOffline(const KURL &url)
01794 {
01795 const int NetWorkStatusUnknown = 1;
01796 const int NetWorkStatusOnline = 8;
01797 QCString replyType;
01798 QByteArray params;
01799 QByteArray reply;
01800
01801 QDataStream stream(params, IO_WriteOnly);
01802 stream << url.url();
01803
01804 if ( dcopClient()->call( "kded", "networkstatus", "status(QString)",
01805 params, replyType, reply ) && (replyType == "int") )
01806 {
01807 int result;
01808 QDataStream stream2( reply, IO_ReadOnly );
01809 stream2 >> result;
01810 kdDebug(7113) << "(" << m_pid << ") networkstatus status = " << result << endl;
01811 return (result != NetWorkStatusUnknown) && (result != NetWorkStatusOnline);
01812 }
01813 kdDebug(7113) << "(" << m_pid << ") networkstatus <unreachable>" << endl;
01814 return false;
01815 }
01816
01817 void HTTPProtocol::multiGet(const QByteArray &data)
01818 {
01819 QDataStream stream(data, IO_ReadOnly);
01820 Q_UINT32 n;
01821 stream >> n;
01822
01823 kdDebug(7113) << "(" << m_pid << ") HTTPProtcool::multiGet n = " << n << endl;
01824
01825 HTTPRequest saveRequest;
01826 if (m_bBusy)
01827 saveRequest = m_request;
01828
01829
01830 for(unsigned i = 0; i < n; i++)
01831 {
01832 KURL url;
01833 stream >> url >> mIncomingMetaData;
01834
01835 if ( !checkRequestURL( url ) )
01836 continue;
01837
01838 kdDebug(7113) << "(" << m_pid << ") HTTPProtocol::multi_get " << url.url() << endl;
01839
01840 m_request.method = HTTP_GET;
01841 m_request.path = url.path();
01842 m_request.query = url.query();
01843 QString tmp = metaData("cache");
01844 if (!tmp.isEmpty())
01845 m_request.cache = parseCacheControl(tmp);
01846 else
01847 m_request.cache = DEFAULT_CACHE_CONTROL;
01848
01849 m_request.passwd = url.pass();
01850 m_request.user = url.user();
01851 m_request.doProxy = m_bUseProxy;
01852
01853 HTTPRequest *newRequest = new HTTPRequest(m_request);
01854 m_requestQueue.append(newRequest);
01855 }
01856
01857 if (m_bBusy)
01858 m_request = saveRequest;
01859
01860 if (!m_bBusy)
01861 {
01862 m_bBusy = true;
01863 while(!m_requestQueue.isEmpty())
01864 {
01865 HTTPRequest *request = m_requestQueue.take(0);
01866 m_request = *request;
01867 delete request;
01868 retrieveContent();
01869 }
01870 m_bBusy = false;
01871 }
01872 }
01873
01874 ssize_t HTTPProtocol::write (const void *_buf, size_t nbytes)
01875 {
01876 int bytes_sent = 0;
01877 const char* buf = static_cast<const char*>(_buf);
01878 while ( nbytes > 0 )
01879 {
01880 int n = TCPSlaveBase::write(buf, nbytes);
01881
01882 if ( n <= 0 )
01883 {
01884
01885 if ( n == 0 )
01886 break;
01887
01888 if (n < 0 && ((errno == EINTR) || (errno == EAGAIN)))
01889 continue;
01890
01891 return -1;
01892 }
01893
01894 nbytes -= n;
01895 buf += n;
01896 bytes_sent += n;
01897 }
01898
01899 return bytes_sent;
01900 }
01901
01902 void HTTPProtocol::setRewindMarker()
01903 {
01904 m_rewindCount = 0;
01905 }
01906
01907 void HTTPProtocol::rewind()
01908 {
01909 m_linePtrUnget = m_rewindBuf,
01910 m_lineCountUnget = m_rewindCount;
01911 m_rewindCount = 0;
01912 }
01913
01914
01915 char *HTTPProtocol::gets (char *s, int size)
01916 {
01917 int len=0;
01918 char *buf=s;
01919 char mybuf[2]={0,0};
01920
01921 while (len < size)
01922 {
01923 read(mybuf, 1);
01924 if (m_bEOF)
01925 break;
01926
01927 if (m_rewindCount < sizeof(m_rewindBuf))
01928 m_rewindBuf[m_rewindCount++] = *mybuf;
01929
01930 if (*mybuf == '\r')
01931 continue;
01932
01933 if ((*mybuf == '\n') || !*mybuf)
01934 break;
01935
01936 *buf++ = *mybuf;
01937 len++;
01938 }
01939
01940 *buf=0;
01941 return s;
01942 }
01943
01944 ssize_t HTTPProtocol::read (void *b, size_t nbytes)
01945 {
01946 ssize_t ret = 0;
01947
01948 if (m_lineCountUnget > 0)
01949 {
01950 ret = ( nbytes < m_lineCountUnget ? nbytes : m_lineCountUnget );
01951 m_lineCountUnget -= ret;
01952 memcpy(b, m_linePtrUnget, ret);
01953 m_linePtrUnget += ret;
01954
01955 return ret;
01956 }
01957
01958 if (m_lineCount > 0)
01959 {
01960 ret = ( nbytes < m_lineCount ? nbytes : m_lineCount );
01961 m_lineCount -= ret;
01962 memcpy(b, m_linePtr, ret);
01963 m_linePtr += ret;
01964 return ret;
01965 }
01966
01967 if (nbytes == 1)
01968 {
01969 ret = read(m_lineBuf, 1024);
01970 m_linePtr = m_lineBuf;
01971 if (ret <= 0)
01972 {
01973 m_lineCount = 0;
01974 return ret;
01975 }
01976 m_lineCount = ret;
01977 return read(b, 1);
01978 }
01979
01980 do
01981 {
01982 ret = TCPSlaveBase::read( b, nbytes);
01983 if (ret == 0)
01984 m_bEOF = true;
01985
01986 } while ((ret == -1) && (errno == EAGAIN || errno == EINTR));
01987
01988 return ret;
01989 }
01990
01991 void HTTPProtocol::httpCheckConnection()
01992 {
01993 kdDebug(7113) << "(" << m_pid << ") HTTPProtocol::httpCheckConnection: " <<
01994 " Socket status: " << m_iSock <<
01995 " Keep Alive: " << m_bKeepAlive <<
01996 " First: " << m_bFirstRequest << endl;
01997
01998 if ( !m_bFirstRequest && (m_iSock != -1) )
01999 {
02000 bool closeDown = false;
02001 if ( !isConnectionValid())
02002 {
02003 kdDebug(7113) << "(" << m_pid << ") Connection lost!" << endl;
02004 closeDown = true;
02005 }
02006 else if ( m_request.method != HTTP_GET )
02007 {
02008 closeDown = true;
02009 }
02010 else if ( !m_state.doProxy && !m_request.doProxy )
02011 {
02012 if (m_state.hostname != m_request.hostname ||
02013 m_state.port != m_request.port ||
02014 m_state.user != m_request.user ||
02015 m_state.passwd != m_request.passwd)
02016 closeDown = true;
02017 }
02018 else
02019 {
02020
02021 if ( !(m_request.doProxy && m_state.doProxy) )
02022 closeDown = true;
02023 }
02024
02025 if (closeDown)
02026 httpCloseConnection();
02027 }
02028
02029
02030 m_state.hostname = m_request.hostname;
02031 m_state.encoded_hostname = m_request.encoded_hostname;
02032 m_state.port = m_request.port;
02033 m_state.user = m_request.user;
02034 m_state.passwd = m_request.passwd;
02035 m_state.doProxy = m_request.doProxy;
02036 }
02037
02038 bool HTTPProtocol::httpOpenConnection()
02039 {
02040 int errCode;
02041 QString errMsg;
02042
02043 kdDebug(7113) << "(" << m_pid << ") HTTPProtocol::httpOpenConnection" << endl;
02044
02045 setBlockConnection( true );
02046
02047 KSocks::self()->disableSocks();
02048
02049 if ( m_state.doProxy )
02050 {
02051 QString proxy_host = m_proxyURL.host();
02052 int proxy_port = m_proxyURL.port();
02053
02054 kdDebug(7113) << "(" << m_pid << ") Connecting to proxy server: "
02055 << proxy_host << ", port: " << proxy_port << endl;
02056
02057 infoMessage( i18n("Connecting to %1...").arg(m_state.hostname) );
02058
02059 setConnectTimeout( m_proxyConnTimeout );
02060
02061 if ( !connectToHost(proxy_host, proxy_port, false) )
02062 {
02063 if (userAborted()) {
02064 error(ERR_NO_CONTENT, "");
02065 return false;
02066 }
02067
02068 switch ( connectResult() )
02069 {
02070 case IO_LookupError:
02071 errMsg = proxy_host;
02072 errCode = ERR_UNKNOWN_PROXY_HOST;
02073 break;
02074 case IO_TimeOutError:
02075 errMsg = i18n("Proxy %1 at port %2").arg(proxy_host).arg(proxy_port);
02076 errCode = ERR_SERVER_TIMEOUT;
02077 break;
02078 default:
02079 errMsg = i18n("Proxy %1 at port %2").arg(proxy_host).arg(proxy_port);
02080 errCode = ERR_COULD_NOT_CONNECT;
02081 }
02082 error( errCode, errMsg );
02083 return false;
02084 }
02085 }
02086 else
02087 {
02088
02089 setConnectTimeout(m_remoteConnTimeout);
02090
02091 if ( !connectToHost(m_state.hostname, m_state.port, false ) )
02092 {
02093 if (userAborted()) {
02094 error(ERR_NO_CONTENT, "");
02095 return false;
02096 }
02097
02098 switch ( connectResult() )
02099 {
02100 case IO_LookupError:
02101 errMsg = m_state.hostname;
02102 errCode = ERR_UNKNOWN_HOST;
02103 break;
02104 case IO_TimeOutError:
02105 errMsg = i18n("Connection was to %1 at port %2").arg(m_state.hostname).arg(m_state.port);
02106 errCode = ERR_SERVER_TIMEOUT;
02107 break;
02108 default:
02109 errCode = ERR_COULD_NOT_CONNECT;
02110 if (m_state.port != m_iDefaultPort)
02111 errMsg = i18n("%1 (port %2)").arg(m_state.hostname).arg(m_state.port);
02112 else
02113 errMsg = m_state.hostname;
02114 }
02115 error( errCode, errMsg );
02116 return false;
02117 }
02118 }
02119
02120
02121 int on = 1;
02122 (void) setsockopt( m_iSock, IPPROTO_TCP, TCP_NODELAY, (char*)&on, sizeof(on) );
02123
02124 m_bFirstRequest = true;
02125
02126 connected();
02127 return true;
02128 }
02129
02130
02153 bool HTTPProtocol::httpOpen()
02154 {
02155 kdDebug(7113) << "(" << m_pid << ") HTTPProtocol::httpOpen" << endl;
02156
02157
02158
02159
02160 if ( (m_protocol == "https" || m_protocol == "webdavs") && !m_bIsSSL )
02161 {
02162 error( ERR_UNSUPPORTED_PROTOCOL, m_protocol );
02163 return false;
02164 }
02165
02166 m_request.fcache = 0;
02167 m_request.bCachedRead = false;
02168 m_request.bCachedWrite = false;
02169 m_request.bMustRevalidate = false;
02170 m_request.expireDate = 0;
02171 m_request.creationDate = 0;
02172
02173 if (m_request.bUseCache)
02174 {
02175 m_request.fcache = checkCacheEntry( );
02176
02177 bool bCacheOnly = (m_request.cache == KIO::CC_CacheOnly);
02178 bool bOffline = isOffline(m_request.doProxy ? m_proxyURL : m_request.url);
02179 if (bOffline && (m_request.cache != KIO::CC_Reload))
02180 m_request.cache = KIO::CC_CacheOnly;
02181
02182 if (m_request.cache == CC_Reload && m_request.fcache)
02183 {
02184 if (m_request.fcache)
02185 fclose(m_request.fcache);
02186 m_request.fcache = 0;
02187 }
02188 if ((m_request.cache == KIO::CC_CacheOnly) || (m_request.cache == KIO::CC_Cache))
02189 m_request.bMustRevalidate = false;
02190
02191 m_request.bCachedWrite = true;
02192
02193 if (m_request.fcache && !m_request.bMustRevalidate)
02194 {
02195
02196 m_request.bCachedRead = true;
02197 return true;
02198 }
02199 else if (!m_request.fcache)
02200 {
02201 m_request.bMustRevalidate = false;
02202 }
02203 else
02204 {
02205
02206 }
02207
02208 if (bCacheOnly)
02209 {
02210 error( ERR_DOES_NOT_EXIST, m_request.url.url() );
02211 return false;
02212 }
02213 if (bOffline)
02214 {
02215 error( ERR_COULD_NOT_CONNECT, m_request.url.url() );
02216 return false;
02217 }
02218 }
02219
02220 QString header;
02221 QString davHeader;
02222
02223 bool moreData = false;
02224 bool davData = false;
02225
02226
02227 resetConnectionSettings ();
02228
02229
02230 httpCheckConnection();
02231
02232 if ( !m_bIsTunneled && m_bNeedTunnel )
02233 {
02234 setEnableSSLTunnel( true );
02235
02236
02237 header = QString("CONNECT %1:%2 HTTP/1.0"
02238 "\r\n").arg( m_request.encoded_hostname).arg(m_request.port);
02239
02240
02241 if (!m_request.userAgent.isEmpty())
02242 header += "User-Agent: " + m_request.userAgent + "\r\n";
02243
02244
02245 header += "Host: " + m_state.encoded_hostname;
02246
02247 if (m_state.port != m_iDefaultPort)
02248 header += QString(":%1").arg(m_state.port);
02249 header += "\r\n";
02250
02251 header += proxyAuthenticationHeader();
02252 }
02253 else
02254 {
02255
02256 switch (m_request.method)
02257 {
02258 case HTTP_GET:
02259 header = "GET ";
02260 break;
02261 case HTTP_PUT:
02262 header = "PUT ";
02263 moreData = true;
02264 m_request.bCachedWrite = false;
02265 break;
02266 case HTTP_POST:
02267 header = "POST ";
02268 moreData = true;
02269 m_request.bCachedWrite = false;
02270 break;
02271 case HTTP_HEAD:
02272 header = "HEAD ";
02273 break;
02274 case HTTP_DELETE:
02275 header = "DELETE ";
02276 m_request.bCachedWrite = false;
02277 break;
02278 case HTTP_OPTIONS:
02279 header = "OPTIONS ";
02280 m_request.bCachedWrite = false;
02281 break;
02282 case DAV_PROPFIND:
02283 header = "PROPFIND ";
02284 davData = true;
02285 davHeader = "Depth: ";
02286 if ( hasMetaData( "davDepth" ) )
02287 {
02288 kdDebug(7113) << "Reading DAV depth from metadata: " << metaData( "davDepth" ) << endl;
02289 davHeader += metaData( "davDepth" );
02290 }
02291 else
02292 {
02293 if ( m_request.davData.depth == 2 )
02294 davHeader += "infinity";
02295 else
02296 davHeader += QString("%1").arg( m_request.davData.depth );
02297 }
02298 davHeader += "\r\n";
02299 m_request.bCachedWrite = false;
02300 break;
02301 case DAV_PROPPATCH:
02302 header = "PROPPATCH ";
02303 davData = true;
02304 m_request.bCachedWrite = false;
02305 break;
02306 case DAV_MKCOL:
02307 header = "MKCOL ";
02308 m_request.bCachedWrite = false;
02309 break;
02310 case DAV_COPY:
02311 case DAV_MOVE:
02312 header = ( m_request.method == DAV_COPY ) ? "COPY " : "MOVE ";
02313 davHeader = "Destination: " + m_request.davData.desturl;
02314
02315
02316 davHeader += "\r\nDepth: infinity\r\nOverwrite: ";
02317 davHeader += m_request.davData.overwrite ? "T" : "F";
02318 davHeader += "\r\n";
02319 m_request.bCachedWrite = false;
02320 break;
02321 case DAV_LOCK:
02322 header = "LOCK ";
02323 davHeader = "Timeout: ";
02324 {
02325 uint timeout = 0;
02326 if ( hasMetaData( "davTimeout" ) )
02327 timeout = metaData( "davTimeout" ).toUInt();
02328 if ( timeout == 0 )
02329 davHeader += "Infinite";
02330 else
02331 davHeader += QString("Seconds-%1").arg(timeout);
02332 }
02333 davHeader += "\r\n";
02334 m_request.bCachedWrite = false;
02335 davData = true;
02336 break;
02337 case DAV_UNLOCK:
02338 header = "UNLOCK ";
02339 davHeader = "Lock-token: " + metaData("davLockToken") + "\r\n";
02340 m_request.bCachedWrite = false;
02341 break;
02342 case DAV_SEARCH:
02343 header = "SEARCH ";
02344 davData = true;
02345 m_request.bCachedWrite = false;
02346 break;
02347 case DAV_SUBSCRIBE:
02348 header = "SUBSCRIBE ";
02349 m_request.bCachedWrite = false;
02350 break;
02351 case DAV_UNSUBSCRIBE:
02352 header = "UNSUBSCRIBE ";
02353 m_request.bCachedWrite = false;
02354 break;
02355 case DAV_POLL:
02356 header = "POLL ";
02357 m_request.bCachedWrite = false;
02358 break;
02359 default:
02360 error (ERR_UNSUPPORTED_ACTION, QString::null);
02361 return false;
02362 }
02363
02364
02365
02366 if (m_state.doProxy && !m_bIsTunneled)
02367 {
02368 KURL u;
02369
02370 if (m_protocol == "webdav")
02371 u.setProtocol( "http" );
02372 else if (m_protocol == "webdavs" )
02373 u.setProtocol( "https" );
02374 else
02375 u.setProtocol( m_protocol );
02376
02377
02378
02379
02380
02381 if (m_protocol != "http" && m_protocol != "https" &&
02382 !m_state.user.isEmpty())
02383 u.setUser (m_state.user);
02384
02385 u.setHost( m_state.hostname );
02386 if (m_state.port != m_iDefaultPort)
02387 u.setPort( m_state.port );
02388 u.setEncodedPathAndQuery( m_request.url.encodedPathAndQuery(0,true) );
02389 header += u.url();
02390 }
02391 else
02392 {
02393 header += m_request.url.encodedPathAndQuery(0, true);
02394 }
02395
02396 header += " HTTP/1.1\r\n";
02397
02398 if (!m_request.userAgent.isEmpty())
02399 {
02400 header += "User-Agent: ";
02401 header += m_request.userAgent;
02402 header += "\r\n";
02403 }
02404
02405 if (!m_request.referrer.isEmpty())
02406 {
02407 header += "Referer: ";
02408 header += m_request.referrer;
02409 header += "\r\n";
02410 }
02411
02412 if ( m_request.offset > 0 )
02413 {
02414 header += QString("Range: bytes=%1-\r\n").arg(KIO::number(m_request.offset));
02415 kdDebug(7103) << "kio_http : Range = " << KIO::number(m_request.offset) << endl;
02416 }
02417
02418 if ( m_request.cache == CC_Reload )
02419 {
02420
02421 header += "Pragma: no-cache\r\n";
02422 header += "Cache-control: no-cache\r\n";
02423 }
02424
02425 if (m_request.bMustRevalidate)
02426 {
02427
02428 if (!m_request.etag.isEmpty())
02429 header += "If-None-Match: "+m_request.etag+"\r\n";
02430 if (!m_request.lastModified.isEmpty())
02431 header += "If-Modified-Since: "+m_request.lastModified+"\r\n";
02432 }
02433
02434 header += "Accept: ";
02435 QString acceptHeader = metaData("accept");
02436 if (!acceptHeader.isEmpty())
02437 header += acceptHeader;
02438 else
02439 header += DEFAULT_ACCEPT_HEADER;
02440 header += "\r\n";
02441
02442 #ifdef DO_GZIP
02443 if (m_request.allowCompressedPage)
02444 header += "Accept-Encoding: x-gzip, x-deflate, gzip, deflate\r\n";
02445 #endif
02446
02447 if (!m_request.charsets.isEmpty())
02448 header += "Accept-Charset: " + m_request.charsets + "\r\n";
02449
02450 if (!m_request.languages.isEmpty())
02451 header += "Accept-Language: " + m_request.languages + "\r\n";
02452
02453
02454
02455 header += "Host: " + m_state.encoded_hostname;
02456
02457 if (m_state.port != m_iDefaultPort)
02458 header += QString(":%1").arg(m_state.port);
02459 header += "\r\n";
02460
02461 QString cookieStr;
02462 QString cookieMode = metaData("cookies").lower();
02463 if (cookieMode == "none")
02464 {
02465 m_request.cookieMode = HTTPRequest::CookiesNone;
02466 }
02467 else if (cookieMode == "manual")
02468 {
02469 m_request.cookieMode = HTTPRequest::CookiesManual;
02470 cookieStr = metaData("setcookies");
02471 }
02472 else
02473 {
02474 m_request.cookieMode = HTTPRequest::CookiesAuto;
02475 if (m_request.bUseCookiejar)
02476 cookieStr = findCookies( m_request.url.url());
02477 }
02478
02479 if (!cookieStr.isEmpty())
02480 header += cookieStr + "\r\n";
02481
02482 QString customHeader = metaData( "customHTTPHeader" );
02483 if (!customHeader.isEmpty())
02484 {
02485 header += sanitizeCustomHTTPHeader(customHeader);
02486 header += "\r\n";
02487 }
02488
02489 if (m_request.method == HTTP_POST)
02490 {
02491 header += metaData("content-type");
02492 header += "\r\n";
02493 }
02494
02495
02496
02497
02498 if ( !m_request.bNoAuth && m_responseCode != 401 && m_responseCode != 407 && Authentication != AUTH_Negotiate )
02499 {
02500 kdDebug(7113) << "(" << m_pid << ") Calling checkCachedAuthentication " << endl;
02501 AuthInfo info;
02502 info.url = m_request.url;
02503 info.verifyPath = true;
02504 if ( !m_request.user.isEmpty() )
02505 info.username = m_request.user;
02506 if ( checkCachedAuthentication( info ) && !info.digestInfo.isEmpty() )
02507 {
02508 Authentication = info.digestInfo.startsWith("Basic") ? AUTH_Basic : info.digestInfo.startsWith("NTLM") ? AUTH_NTLM : info.digestInfo.startsWith("Negotiate") ? AUTH_Negotiate : AUTH_Digest ;
02509 m_state.user = info.username;
02510 m_state.passwd = info.password;
02511 m_strRealm = info.realmValue;
02512 if ( Authentication != AUTH_NTLM && Authentication != AUTH_Negotiate )
02513 m_strAuthorization = info.digestInfo;
02514 }
02515 }
02516 else
02517 {
02518 kdDebug(7113) << "(" << m_pid << ") Not calling checkCachedAuthentication " << endl;
02519 }
02520
02521 switch ( Authentication )
02522 {
02523 case AUTH_Basic:
02524 header += createBasicAuth();
02525 break;
02526 case AUTH_Digest:
02527 header += createDigestAuth();
02528 break;
02529 #ifdef HAVE_LIBGSSAPI
02530 case AUTH_Negotiate:
02531 header += createNegotiateAuth();
02532 break;
02533 #endif
02534 case AUTH_NTLM:
02535 header += createNTLMAuth();
02536 break;
02537 case AUTH_None:
02538 default:
02539 break;
02540 }
02541
02542
02543 if ( Authentication != AUTH_None )
02544 {
02545 kdDebug(7113) << "(" << m_pid << ") Using Authentication: " << endl;
02546 kdDebug(7113) << "(" << m_pid << ") HOST= " << m_state.hostname << endl;
02547 kdDebug(7113) << "(" << m_pid << ") PORT= " << m_state.port << endl;
02548 kdDebug(7113) << "(" << m_pid << ") USER= " << m_state.user << endl;
02549 kdDebug(7113) << "(" << m_pid << ") PASSWORD= [protected]" << endl;
02550 kdDebug(7113) << "(" << m_pid << ") REALM= " << m_strRealm << endl;
02551 kdDebug(7113) << "(" << m_pid << ") EXTRA= " << m_strAuthorization << endl;
02552 }
02553
02554
02555 if ( m_state.doProxy && !m_bIsTunneled )
02556 header += proxyAuthenticationHeader();
02557
02558
02559
02560
02561
02562 if (!m_bUseProxy || m_bPersistentProxyConnection || m_bIsTunneled)
02563 header += "Connection: Keep-Alive\r\n";
02564 else
02565 header += "Connection: close\r\n";
02566
02567 if ( m_protocol == "webdav" || m_protocol == "webdavs" )
02568 {
02569 header += davProcessLocks();
02570
02571
02572 QString davExtraHeader = metaData("davHeader");
02573 if ( !davExtraHeader.isEmpty() )
02574 davHeader += davExtraHeader;
02575
02576
02577 if (davData)
02578 davHeader += "Content-Type: text/xml; charset=utf-8\r\n";
02579
02580
02581 if ( !davHeader.isNull() )
02582 header += davHeader;
02583 }
02584 }
02585
02586 kdDebug(7103) << "(" << m_pid << ") ============ Sending Header:" << endl;
02587
02588 QStringList headerOutput = QStringList::split("\r\n", header);
02589 QStringList::Iterator it = headerOutput.begin();
02590
02591 for (; it != headerOutput.end(); it++)
02592 kdDebug(7103) << "(" << m_pid << ") " << (*it) << endl;
02593
02594 if ( !moreData && !davData)
02595 header += "\r\n";
02596
02597
02598
02599
02600 if ( m_iSock == -1)
02601 {
02602 if (!httpOpenConnection())
02603 return false;
02604 }
02605
02606
02607 bool sendOk = (write(header.latin1(), header.length()) == (ssize_t) header.length());
02608 if (!sendOk)
02609 {
02610 kdDebug(7113) << "(" << m_pid << ") HTTPProtocol::httpOpen: "
02611 "Connection broken! (" << m_state.hostname << ")" << endl;
02612
02613
02614
02615 if (m_bKeepAlive)
02616 {
02617 httpCloseConnection();
02618 return true;
02619 }
02620
02621 if (!sendOk)
02622 {
02623 kdDebug(7113) << "(" << m_pid << ") HTTPProtocol::httpOpen: sendOk==false."
02624 " Connnection broken !" << endl;
02625 error( ERR_CONNECTION_BROKEN, m_state.hostname );
02626 return false;
02627 }
02628 }
02629
02630 bool res = true;
02631
02632 if ( moreData || davData )
02633 res = sendBody();
02634
02635 infoMessage(i18n("%1 contacted. Waiting for reply...").arg(m_request.hostname));
02636
02637 return res;
02638 }
02639
02640 void HTTPProtocol::forwardHttpResponseHeader()
02641 {
02642
02643 if ( config()->readBoolEntry("PropagateHttpHeader", false) )
02644 {
02645 setMetaData("HTTP-Headers", m_responseHeader.join("\n"));
02646 sendMetaData();
02647 }
02648 m_responseHeader.clear();
02649 }
02650
02657 bool HTTPProtocol::readHeader()
02658 {
02659 try_again:
02660 kdDebug(7113) << "(" << m_pid << ") HTTPProtocol::readHeader" << endl;
02661
02662
02663 if (m_request.bCachedRead)
02664 {
02665 m_responseHeader << "HTTP-CACHE";
02666
02667 char buffer[4097];
02668 if (!fgets(buffer, 4096, m_request.fcache) )
02669 {
02670
02671 kdDebug(7113) << "(" << m_pid << ") HTTPProtocol::readHeader: "
02672 << "Could not access cache to obtain mimetype!" << endl;
02673 error( ERR_CONNECTION_BROKEN, m_state.hostname );
02674 return false;
02675 }
02676
02677 m_strMimeType = QString::fromUtf8( buffer).stripWhiteSpace();
02678
02679 kdDebug(7113) << "(" << m_pid << ") HTTPProtocol::readHeader: cached "
02680 << "data mimetype: " << m_strMimeType << endl;
02681
02682 if (!fgets(buffer, 4096, m_request.fcache) )
02683 {
02684
02685 kdDebug(7113) << "(" << m_pid << ") HTTPProtocol::readHeader: "
02686 << "Could not access cached data! " << endl;
02687 error( ERR_CONNECTION_BROKEN, m_state.hostname );
02688 return false;
02689 }
02690
02691 m_request.strCharset = QString::fromUtf8( buffer).stripWhiteSpace().lower();
02692 setMetaData("charset", m_request.strCharset);
02693 if (!m_request.lastModified.isEmpty())
02694 setMetaData("modified", m_request.lastModified);
02695 QString tmp;
02696 tmp.setNum(m_request.expireDate);
02697 setMetaData("expire-date", tmp);
02698 tmp.setNum(m_request.creationDate);
02699 setMetaData("cache-creation-date", tmp);
02700 mimeType(m_strMimeType);
02701 forwardHttpResponseHeader();
02702 return true;
02703 }
02704
02705 QCString locationStr;
02706 QCString cookieStr;
02707
02708 QString disposition;
02709 QString mediaValue;
02710 QString mediaAttribute;
02711
02712 QStringList upgradeOffers;
02713
02714 bool upgradeRequired = false;
02715
02716
02717
02718 bool canUpgrade = false;
02719
02720
02721 m_request.etag = QString::null;
02722 m_request.lastModified = QString::null;
02723 m_request.strCharset = QString::null;
02724
02725 time_t dateHeader = 0;
02726 time_t expireDate = 0;
02727 int currentAge = 0;
02728 int maxAge = -1;
02729 int maxHeaderSize = 64*1024;
02730
02731
02732 int len = 0;
02733 char buffer[4097];
02734 bool cont = false;
02735 bool cacheValidated = false;
02736 bool mayCache = true;
02737 bool hasCacheDirective = false;
02738 bool bCanResume = false;
02739
02740 if (m_iSock == -1)
02741 {
02742 kdDebug(7113) << "HTTPProtocol::readHeader: No connection." << endl;
02743 return false;
02744 }
02745
02746 if (!waitForResponse(m_remoteRespTimeout))
02747 {
02748
02749 error( ERR_SERVER_TIMEOUT , m_state.hostname );
02750 return false;
02751 }
02752
02753 setRewindMarker();
02754
02755 gets(buffer, sizeof(buffer)-1);
02756
02757 if (m_bEOF || *buffer == '\0')
02758 {
02759 kdDebug(7113) << "(" << m_pid << ") HTTPProtocol::readHeader: "
02760 << "EOF while waiting for header start." << endl;
02761 if (m_bKeepAlive)
02762 {
02763 httpCloseConnection();
02764 return false;
02765 }
02766
02767 if (m_request.method == HTTP_HEAD)
02768 {
02769
02770
02771
02772
02773 kdDebug(7113) << "(" << m_pid << ") HTTPPreadHeader: HEAD -> returned "
02774 << "mimetype: " << DEFAULT_MIME_TYPE << endl;
02775 mimeType(QString::fromLatin1(DEFAULT_MIME_TYPE));
02776 return true;
02777 }
02778
02779 kdDebug(7113) << "HTTPProtocol::readHeader: Connection broken !" << endl;
02780 error( ERR_CONNECTION_BROKEN, m_state.hostname );
02781 return false;
02782 }
02783
02784 kdDebug(7103) << "(" << m_pid << ") ============ Received Response:"<< endl;
02785
02786 bool noHeader = true;
02787 HTTP_REV httpRev = HTTP_None;
02788 int headerSize = 0;
02789
02790 do
02791 {
02792
02793 len = strlen(buffer);
02794
02795 while(len && (buffer[len-1] == '\n' || buffer[len-1] == '\r'))
02796 buffer[--len] = 0;
02797
02798
02799 if (!len)
02800 {
02801 kdDebug(7103) << "(" << m_pid << ") --empty--" << endl;
02802 continue;
02803 }
02804
02805 headerSize += len;
02806
02807
02808
02809
02810
02811 noHeader = false;
02812
02813 kdDebug(7103) << "(" << m_pid << ") \"" << buffer << "\"" << endl;
02814
02815
02816 char* buf = buffer;
02817 while( *buf == ' ' )
02818 buf++;
02819
02820
02821 if (buf[0] == '<')
02822 {
02823
02824
02825 kdDebug(7103) << "kio_http: No valid HTTP header found! Document starts with XML/HTML tag" << endl;
02826
02827
02828 m_strMimeType = "text/html";
02829
02830 rewind();
02831 break;
02832 }
02833
02834
02835
02836 m_responseHeader << QString::fromLatin1(buf);
02837
02838 if ((strncasecmp(buf, "HTTP", 4) == 0) ||
02839 (strncasecmp(buf, "ICY ", 4) == 0))
02840 {
02841 if (strncasecmp(buf, "ICY ", 4) == 0)
02842 {
02843
02844 httpRev = SHOUTCAST;
02845 m_bKeepAlive = false;
02846 }
02847 else if (strncmp((buf + 5), "1.0",3) == 0)
02848 {
02849 httpRev = HTTP_10;
02850
02851
02852
02853
02854
02855 m_bKeepAlive = false;
02856 }
02857 else if (strncmp((buf + 5), "1.1",3) == 0)
02858 {
02859 httpRev = HTTP_11;
02860 }
02861 else
02862 {
02863 httpRev = HTTP_Unknown;
02864 }
02865
02866 if (m_responseCode)
02867 m_prevResponseCode = m_responseCode;
02868
02869 const char* rptr = buf;
02870 while ( *rptr && *rptr > ' ' )
02871 ++rptr;
02872 m_responseCode = atoi(rptr);
02873
02874
02875 if (m_responseCode >= 500 && m_responseCode <= 599)
02876 {
02877 if (m_request.method == HTTP_HEAD)
02878 {
02879 ;
02880 }
02881 else
02882 {
02883 if (m_request.bErrorPage)
02884 errorPage();
02885 else
02886 {
02887 error(ERR_INTERNAL_SERVER, m_request.url.url());
02888 return false;
02889 }
02890 }
02891 m_request.bCachedWrite = false;
02892 mayCache = false;
02893 }
02894
02895 else if (m_responseCode == 401 || m_responseCode == 407)
02896 {
02897
02898
02899 if ( m_prevResponseCode != m_responseCode &&
02900 (m_prevResponseCode == 401 || m_prevResponseCode == 407) )
02901 saveAuthorization();
02902
02903 m_bUnauthorized = true;
02904 m_request.bCachedWrite = false;
02905 mayCache = false;
02906 }
02907
02908 else if (m_responseCode == 416)
02909 {
02910 m_request.offset = 0;
02911 httpCloseConnection();
02912 return false;
02913 }
02914
02915 else if (m_responseCode == 426)
02916 {
02917 upgradeRequired = true;
02918 }
02919
02920 else if (m_responseCode >= 400 && m_responseCode <= 499)
02921 {
02922
02923 if (m_request.bErrorPage)
02924 errorPage();
02925 else
02926 {
02927 error(ERR_DOES_NOT_EXIST, m_request.url.url());
02928 return false;
02929 }
02930 m_request.bCachedWrite = false;
02931 mayCache = false;
02932 }
02933 else if (m_responseCode == 307)
02934 {
02935
02936 m_request.bCachedWrite = false;
02937 mayCache = false;
02938 }
02939 else if (m_responseCode == 304)
02940 {
02941
02942
02943 cacheValidated = true;
02944 }
02945 else if (m_responseCode >= 301 && m_responseCode<= 303)
02946 {
02947
02948 if (m_responseCode == 301)
02949 setMetaData("permanent-redirect", "true");
02950
02951
02952
02953 if (m_request.method != HTTP_HEAD && m_request.method != HTTP_GET)
02954 {
02955 #if 0
02956
02957
02958 if (m_request.method == HTTP_POST)
02959 m_bufPOST.resize(0);
02960 #endif
02961
02962
02963
02964
02965
02966
02967
02968
02969
02970 m_request.method = HTTP_GET;
02971 }
02972 m_request.bCachedWrite = false;
02973 mayCache = false;
02974 }
02975 else if ( m_responseCode == 207 )
02976 {
02977
02978 }
02979 else if ( m_responseCode == 204 )
02980 {
02981
02982
02983
02984
02985
02986
02987
02988 }
02989 else if ( m_responseCode == 206 )
02990 {
02991 if ( m_request.offset )
02992 bCanResume = true;
02993 }
02994 else if (m_responseCode == 102)
02995 {
02996
02997
02998
02999
03000
03001 infoMessage( i18n( "Server processing request, please wait..." ) );
03002 cont = true;
03003 }
03004 else if (m_responseCode == 100)
03005 {
03006
03007 cont = true;
03008 }
03009 }
03010
03011
03012 else if (strncasecmp(buf, "Accept-Ranges:", 14) == 0) {
03013 if (strncasecmp(trimLead(buf + 14), "none", 4) == 0)
03014 bCanResume = false;
03015 }
03016
03017 else if (strncasecmp(buf, "Keep-Alive:", 11) == 0) {
03018 QStringList options = QStringList::split(',',
03019 QString::fromLatin1(trimLead(buf+11)));
03020 for(QStringList::ConstIterator it = options.begin();
03021 it != options.end();
03022 it++)
03023 {
03024 QString option = (*it).stripWhiteSpace().lower();
03025 if (option.startsWith("timeout="))
03026 {
03027 m_keepAliveTimeout = option.mid(8).toInt();
03028 }
03029 }
03030 }
03031
03032
03033 else if (strncasecmp(buf, "Cache-Control:", 14) == 0) {
03034 QStringList cacheControls = QStringList::split(',',
03035 QString::fromLatin1(trimLead(buf+14)));
03036 for(QStringList::ConstIterator it = cacheControls.begin();
03037 it != cacheControls.end();
03038 it++)
03039 {
03040 QString cacheControl = (*it).stripWhiteSpace();
03041 if (strncasecmp(cacheControl.latin1(), "no-cache", 8) == 0)
03042 {
03043 m_request.bCachedWrite = false;
03044 mayCache = false;
03045 }
03046 else if (strncasecmp(cacheControl.latin1(), "no-store", 8) == 0)
03047 {
03048 m_request.bCachedWrite = false;
03049 mayCache = false;
03050 }
03051 else if (strncasecmp(cacheControl.latin1(), "max-age=", 8) == 0)
03052 {
03053 QString age = cacheControl.mid(8).stripWhiteSpace();
03054 if (!age.isNull())
03055 maxAge = STRTOLL(age.latin1(), 0, 10);
03056 }
03057 }
03058 hasCacheDirective = true;
03059 }
03060
03061
03062 else if (strncasecmp(buf, "Content-length:", 15) == 0) {
03063 char* len = trimLead(buf + 15);
03064 if (len)
03065 m_iSize = STRTOLL(len, 0, 10);
03066 }
03067
03068 else if (strncasecmp(buf, "Content-location:", 17) == 0) {
03069 setMetaData ("content-location",
03070 QString::fromLatin1(trimLead(buf+17)).stripWhiteSpace());
03071 }
03072
03073
03074 else if (strncasecmp(buf, "Content-type:", 13) == 0) {
03075 char *start = trimLead(buf + 13);
03076 char *pos = start;
03077
03078
03079 while ( *pos && *pos != ';' ) pos++;
03080
03081
03082 m_strMimeType = QString::fromLatin1(start, pos-start).stripWhiteSpace().lower();
03083 kdDebug(7113) << "(" << m_pid << ") Content-type: " << m_strMimeType << endl;
03084
03085
03086
03087 while (*pos)
03088 {
03089 start = ++pos;
03090 while ( *pos && *pos != '=' ) pos++;
03091
03092 char *end = pos;
03093 while ( *end && *end != ';' ) end++;
03094
03095 if (*pos)
03096 {
03097 mediaAttribute = QString::fromLatin1(start, pos-start).stripWhiteSpace().lower();
03098 mediaValue = QString::fromLatin1(pos+1, end-pos-1).stripWhiteSpace();
03099 pos = end;
03100 if (mediaValue.length() &&
03101 (mediaValue[0] == '"') &&
03102 (mediaValue[mediaValue.length()-1] == '"'))
03103 mediaValue = mediaValue.mid(1, mediaValue.length()-2);
03104
03105 kdDebug (7113) << "(" << m_pid << ") Media-Parameter Attribute: "
03106 << mediaAttribute << endl;
03107 kdDebug (7113) << "(" << m_pid << ") Media-Parameter Value: "
03108 << mediaValue << endl;
03109
03110 if ( mediaAttribute == "charset")
03111 {
03112 mediaValue = mediaValue.lower();
03113 m_request.strCharset = mediaValue;
03114 }
03115 else
03116 {
03117 setMetaData("media-"+mediaAttribute, mediaValue);
03118 }
03119 }
03120 }
03121 }
03122
03123
03124 else if (strncasecmp(buf, "Date:", 5) == 0) {
03125 dateHeader = KRFCDate::parseDate(trimLead(buf+5));
03126 }
03127
03128
03129 else if (strncasecmp(buf, "ETag:", 5) == 0) {
03130 m_request.etag = trimLead(buf+5);
03131 }
03132
03133
03134 else if (strncasecmp(buf, "Expires:", 8) == 0) {
03135 expireDate = KRFCDate::parseDate(trimLead(buf+8));
03136 if (!expireDate)
03137 expireDate = 1;
03138 }
03139
03140
03141 else if (strncasecmp(buf, "Last-Modified:", 14) == 0) {
03142 m_request.lastModified = (QString::fromLatin1(trimLead(buf+14))).stripWhiteSpace();
03143 }
03144
03145
03146 else if (strncasecmp(buf, "Warning:", 8) == 0) {
03147
03148
03149 infoMessage(trimLead(buf + 8));
03150 }
03151
03152
03153 else if (strncasecmp(buf, "Pragma:", 7) == 0) {
03154 QCString pragma = QCString(trimLead(buf+7)).stripWhiteSpace().lower();
03155 if (pragma == "no-cache")
03156 {
03157 m_request.bCachedWrite = false;
03158 mayCache = false;
03159 hasCacheDirective = true;
03160 }
03161 }
03162
03163
03164 else if (strncasecmp(buf,"Refresh:", 8) == 0) {
03165 mayCache = false;
03166 setMetaData( "http-refresh", QString::fromLatin1(trimLead(buf+8)).stripWhiteSpace() );
03167 }
03168
03169
03170 else if (strncasecmp(buf, "Location:", 9) == 0) {
03171
03172 if ( m_responseCode > 299 && m_responseCode < 400 )
03173 locationStr = QCString(trimLead(buf+9)).stripWhiteSpace();
03174 }
03175
03176
03177 else if (strncasecmp(buf, "Set-Cookie", 10) == 0) {
03178 cookieStr += buf;
03179 cookieStr += '\n';
03180 }
03181
03182
03183 else if (strncasecmp(buf, "WWW-Authenticate:", 17) == 0) {
03184 configAuth(trimLead(buf + 17), false);
03185 }
03186
03187
03188 else if (strncasecmp(buf, "Proxy-Authenticate:", 19) == 0) {
03189 configAuth(trimLead(buf + 19), true);
03190 }
03191
03192 else if (strncasecmp(buf, "Upgrade:", 8) == 0) {
03193
03194 QString offered = &(buf[8]);
03195 upgradeOffers = QStringList::split(QRegExp("[ \n,\r\t]"), offered);
03196 }
03197
03198
03199 else if (strncasecmp(buf, "Content-Encoding:", 17) == 0) {
03200
03201
03202
03203
03204
03205
03206
03207
03208
03209
03210
03211
03212
03213 addEncoding(trimLead(buf + 17), m_qContentEncodings);
03214 }
03215
03216 else if(strncasecmp(buf, "Content-Disposition:", 20) == 0) {
03217 char* dispositionBuf = trimLead(buf + 20);
03218 while ( *dispositionBuf )
03219 {
03220 if ( strncasecmp( dispositionBuf, "filename", 8 ) == 0 )
03221 {
03222 dispositionBuf += 8;
03223
03224 while ( *dispositionBuf == ' ' || *dispositionBuf == '=' )
03225 dispositionBuf++;
03226
03227 char* bufStart = dispositionBuf;
03228
03229 while ( *dispositionBuf && *dispositionBuf != ';' )
03230 dispositionBuf++;
03231
03232 if ( dispositionBuf > bufStart )
03233 {
03234
03235 while ( *bufStart == '"' )
03236 bufStart++;
03237
03238
03239 while ( *(dispositionBuf-1) == ' ' || *(dispositionBuf-1) == '"')
03240 dispositionBuf--;
03241
03242 if ( dispositionBuf > bufStart )
03243 disposition = QString::fromLatin1( bufStart, dispositionBuf-bufStart );
03244
03245 break;
03246 }
03247 }
03248 else
03249 {
03250 char *bufStart = dispositionBuf;
03251
03252 while ( *dispositionBuf && *dispositionBuf != ';' )
03253 dispositionBuf++;
03254
03255 if ( dispositionBuf > bufStart )
03256 disposition = QString::fromLatin1( bufStart, dispositionBuf-bufStart ).stripWhiteSpace();
03257
03258 while ( *dispositionBuf == ';' || *dispositionBuf == ' ' )
03259 dispositionBuf++;
03260 }
03261 }
03262
03263
03264
03265 if ( !disposition.isEmpty() )
03266 {
03267 int pos = disposition.findRev( '/' );
03268
03269 if( pos > -1 )
03270 disposition = disposition.mid(pos+1);
03271
03272 kdDebug(7113) << "(" << m_pid << ") Content-Disposition: "
03273 << disposition<< endl;
03274 }
03275 }
03276 else if (strncasecmp(buf, "Proxy-Connection:", 17) == 0)
03277 {
03278 if (strncasecmp(trimLead(buf + 17), "Close", 5) == 0)
03279 m_bKeepAlive = false;
03280 else if (strncasecmp(trimLead(buf + 17), "Keep-Alive", 10)==0)
03281 m_bKeepAlive = true;
03282 }
03283 else if (strncasecmp(buf, "Link:", 5) == 0) {
03284
03285 QStringList link = QStringList::split(";", QString(buf)
03286 .replace(QRegExp("^Link:[ ]*"),
03287 ""));
03288 if (link.count() == 2) {
03289 QString rel = link[1].stripWhiteSpace();
03290 if (rel.startsWith("rel=\"")) {
03291 rel = rel.mid(5, rel.length() - 6);
03292 if (rel.lower() == "pageservices") {
03293 QString url = link[0].replace(QRegExp("[<>]"),"").stripWhiteSpace();
03294 setMetaData("PageServices", url);
03295 }
03296 }
03297 }
03298 }
03299 else if (strncasecmp(buf, "P3P:", 4) == 0) {
03300 QString p3pstr = buf;
03301 p3pstr = p3pstr.mid(4).simplifyWhiteSpace();
03302 QStringList policyrefs, compact;
03303 QStringList policyfields = QStringList::split(QRegExp(",[ ]*"), p3pstr);
03304 for (QStringList::Iterator it = policyfields.begin();
03305 it != policyfields.end();
03306 ++it) {
03307 QStringList policy = QStringList::split("=", *it);
03308
03309 if (policy.count() == 2) {
03310 if (policy[0].lower() == "policyref") {
03311 policyrefs << policy[1].replace(QRegExp("[\"\']"), "")
03312 .stripWhiteSpace();
03313 } else if (policy[0].lower() == "cp") {
03314
03315
03316
03317 QStringList cps = QStringList::split(" ",
03318 policy[1].replace(QRegExp("[\"\']"), "")
03319 .simplifyWhiteSpace());
03320
03321 for (QStringList::Iterator j = cps.begin(); j != cps.end(); ++j)
03322 compact << *j;
03323 }
03324 }
03325 }
03326
03327 if (!policyrefs.isEmpty())
03328 setMetaData("PrivacyPolicy", policyrefs.join("\n"));
03329
03330 if (!compact.isEmpty())
03331 setMetaData("PrivacyCompactPolicy", compact.join("\n"));
03332 }
03333
03334
03335 else if (httpRev == HTTP_11) {
03336
03337 if (strncasecmp(buf, "Connection:", 11) == 0)
03338 {
03339 if (strncasecmp(trimLead(buf + 11), "Close", 5) == 0)
03340 m_bKeepAlive = false;
03341 else if (strncasecmp(trimLead(buf + 11), "Keep-Alive", 10)==0)
03342 m_bKeepAlive = true;
03343 else if (strncasecmp(trimLead(buf + 11), "Upgrade", 7)==0)
03344 {
03345 if (m_responseCode == 101) {
03346
03347 upgradeRequired = true;
03348 } else if (upgradeRequired) {
03349
03350 } else {
03351
03352 canUpgrade = true;
03353 }
03354 }
03355
03356 }
03357
03358 else if (strncasecmp(buf, "Transfer-Encoding:", 18) == 0) {
03359
03360
03361
03362 addEncoding(trimLead(buf + 18), m_qTransferEncodings);
03363 }
03364
03365
03366 else if (strncasecmp(buf, "Content-MD5:", 12) == 0) {
03367 m_sContentMD5 = QString::fromLatin1(trimLead(buf + 12));
03368 }
03369
03370
03371
03372 else if (strncasecmp(buf, "DAV:", 4) == 0) {
03373 if (m_davCapabilities.isEmpty()) {
03374 m_davCapabilities << QString::fromLatin1(trimLead(buf + 4));
03375 }
03376 else {
03377 m_davCapabilities << QString::fromLatin1(trimLead(buf + 4));
03378 }
03379 }
03380
03381 }
03382 else if ((httpRev == HTTP_None) && (strlen(buf) != 0))
03383 {
03384
03385
03386 rewind();
03387 if (m_responseCode)
03388 m_prevResponseCode = m_responseCode;
03389
03390 m_responseCode = 200;
03391 httpRev = HTTP_Unknown;
03392 m_bKeepAlive = false;
03393 break;
03394 }
03395 setRewindMarker();
03396
03397
03398 memset(buffer, 0, sizeof(buffer));
03399
03400 } while (!m_bEOF && (len || noHeader) && (headerSize < maxHeaderSize) && (gets(buffer, sizeof(buffer)-1)));
03401
03402
03403
03404 QStringList::Iterator opt = upgradeOffers.begin();
03405 for( ; opt != upgradeOffers.end(); ++opt) {
03406 if (*opt == "TLS/1.0") {
03407 if(upgradeRequired) {
03408 if (!startTLS() && !usingTLS()) {
03409 error(ERR_UPGRADE_REQUIRED, *opt);
03410 return false;
03411 }
03412 }
03413 } else if (*opt == "HTTP/1.1") {
03414 httpRev = HTTP_11;
03415 } else {
03416
03417 if (upgradeRequired) {
03418 error(ERR_UPGRADE_REQUIRED, *opt);
03419 return false;
03420 }
03421 }
03422 }
03423
03424 setMetaData("charset", m_request.strCharset);
03425
03426
03427 if ( (m_responseCode == 401 && Authentication == AUTH_None) ||
03428 (m_responseCode == 407 && ProxyAuthentication == AUTH_None) )
03429 {
03430 m_bUnauthorized = false;
03431 if (m_request.bErrorPage)
03432 errorPage();
03433 else
03434 {
03435 error( ERR_UNSUPPORTED_ACTION, "Unknown Authorization method!" );
03436 return false;
03437 }
03438 }
03439
03440
03441 if (expireDate && (expireDate <= dateHeader))
03442 expireDate = 1;
03443
03444
03445 if (maxAge == 0)
03446 expireDate = 1;
03447 else if (maxAge > 0)
03448 {
03449 if (currentAge)
03450 maxAge -= currentAge;
03451 if (maxAge <=0)
03452 maxAge = 0;
03453 expireDate = time(0) + maxAge;
03454 }
03455
03456 if (!expireDate)
03457 {
03458 time_t lastModifiedDate = 0;
03459 if (!m_request.lastModified.isEmpty())
03460 lastModifiedDate = KRFCDate::parseDate(m_request.lastModified);
03461
03462 if (lastModifiedDate)
03463 {
03464 long diff = static_cast<long>(difftime(dateHeader, lastModifiedDate));
03465 if (diff < 0)
03466 expireDate = time(0) + 1;
03467 else
03468 expireDate = time(0) + (diff / 10);
03469 }
03470 else
03471 {
03472 expireDate = time(0) + DEFAULT_CACHE_EXPIRE;
03473 }
03474 }
03475
03476
03477 if (!cookieStr.isEmpty())
03478 {
03479 if ((m_request.cookieMode == HTTPRequest::CookiesAuto) && m_request.bUseCookiejar)
03480 {
03481
03482 QString domain = config()->readEntry("cross-domain");
03483 if (!domain.isEmpty() && isCrossDomainRequest(m_request.url.host(), domain))
03484 cookieStr = "Cross-Domain\n" + cookieStr;
03485 addCookies( m_request.url.url(), cookieStr );
03486 }
03487 else if (m_request.cookieMode == HTTPRequest::CookiesManual)
03488 {
03489
03490 setMetaData("setcookies", cookieStr);
03491 }
03492 }
03493
03494 if (m_request.bMustRevalidate)
03495 {
03496 m_request.bMustRevalidate = false;
03497 if (cacheValidated)
03498 {
03499
03500
03501 fclose(m_request.fcache);
03502 m_request.fcache = 0;
03503 updateExpireDate( expireDate, true );
03504 m_request.fcache = checkCacheEntry( );
03505
03506 if (m_request.fcache)
03507 {
03508 m_request.bCachedRead = true;
03509 goto try_again;
03510 }
03511 else
03512 {
03513
03514 }
03515 }
03516 else
03517 {
03518
03519 fclose(m_request.fcache);
03520 m_request.fcache = 0;
03521 }
03522 }
03523
03524
03525 if ( cont )
03526 {
03527 goto try_again;
03528 }
03529
03530
03531
03532 if (!m_bChunked && (m_iSize == NO_SIZE))
03533 m_bKeepAlive = false;
03534
03535 if ( m_responseCode == 204 )
03536 {
03537 return true;
03538 }
03539
03540
03541 if ( m_bUnauthorized )
03542 {
03543 if ( (m_responseCode == 401) ||
03544 (m_bUseProxy && (m_responseCode == 407))
03545 )
03546 {
03547 if ( getAuthorization() )
03548 {
03549
03550 if ( Authentication == AUTH_NTLM && m_strAuthorization.length() > 4 )
03551 {
03552 m_bKeepAlive = true;
03553 readBody( true );
03554 }
03555 else if (ProxyAuthentication == AUTH_NTLM && m_strProxyAuthorization.length() > 4)
03556 {
03557 readBody( true );
03558 }
03559 else
03560 httpCloseConnection();
03561 return false;
03562 }
03563
03564 if (m_bError)
03565 return false;
03566
03567
03568 }
03569 m_bUnauthorized = false;
03570 }
03571
03572
03573 if (!locationStr.isEmpty())
03574 {
03575 KURL u(m_request.url, locationStr);
03576 if(!u.isValid())
03577 {
03578 error(ERR_MALFORMED_URL, u.url());
03579 return false;
03580 }
03581 if ((u.protocol() != "http") && (u.protocol() != "https") &&
03582 (u.protocol() != "ftp") && (u.protocol() != "webdav") &&
03583 (u.protocol() != "webdavs"))
03584 {
03585 redirection(u);
03586 error(ERR_ACCESS_DENIED, u.url());
03587 return false;
03588 }
03589 m_bRedirect = true;
03590 m_redirectLocation = u;
03591
03592 if (!m_request.id.isEmpty())
03593 {
03594 sendMetaData();
03595 }
03596
03597 kdDebug(7113) << "(" << m_pid << ") request.url: " << m_request.url.url()
03598 << endl << "LocationStr: " << locationStr.data() << endl;
03599
03600 kdDebug(7113) << "(" << m_pid << ") Requesting redirection to: " << u.url()
03601 << endl;
03602
03603
03604 if (m_protocol == "webdav" || m_protocol == "webdavs")
03605 u.setProtocol(m_protocol);
03606
03607 redirection(u);
03608 m_request.bCachedWrite = false;
03609 mayCache = false;
03610 }
03611
03612
03613 if ( bCanResume && m_request.offset )
03614 canResume();
03615 else
03616 m_request.offset = 0;
03617
03618
03619 if (m_strMimeType.startsWith("text/") &&
03620 (m_strMimeType != "text/css") &&
03621 (m_strMimeType != "text/x-javascript") &&
03622 !hasCacheDirective)
03623 {
03624
03625
03626
03627 if ( m_bIsSSL || (Authentication != AUTH_None) )
03628 {
03629 m_request.bCachedWrite = false;
03630 mayCache = false;
03631 }
03632 }
03633
03634
03635
03636
03637
03638
03639 if (m_qContentEncodings.last() == "gzip")
03640 {
03641 if (m_strMimeType == "application/x-tar")
03642 {
03643 m_qContentEncodings.remove(m_qContentEncodings.fromLast());
03644 m_strMimeType = QString::fromLatin1("application/x-tgz");
03645 }
03646 else if (m_strMimeType == "application/postscript")
03647 {
03648
03649
03650 m_qContentEncodings.remove(m_qContentEncodings.fromLast());
03651 m_strMimeType = QString::fromLatin1("application/x-gzpostscript");
03652 }
03653 else if ( (m_request.allowCompressedPage &&
03654 m_strMimeType == "text/html")
03655 ||
03656 (m_request.allowCompressedPage &&
03657 m_strMimeType != "application/x-tgz" &&
03658 m_strMimeType != "application/x-targz" &&
03659 m_strMimeType != "application/x-gzip" &&
03660 m_request.url.path().right(3) != ".gz")
03661 )
03662 {
03663
03664 }
03665 else
03666 {
03667 m_qContentEncodings.remove(m_qContentEncodings.fromLast());
03668 m_strMimeType = QString::fromLatin1("application/x-gzip");
03669 }
03670 }
03671
03672
03673
03674
03675
03676
03677
03678 if (m_qContentEncodings.last() == "bzip2")
03679 {
03680 m_qContentEncodings.remove(m_qContentEncodings.fromLast());
03681 m_strMimeType = QString::fromLatin1("application/x-bzip2");
03682 }
03683
03684
03685 if (m_strMimeType == "application/x-targz")
03686 m_strMimeType = QString::fromLatin1("application/x-tgz");
03687 else if (m_strMimeType == "application/zip")
03688 m_strMimeType = QString::fromLatin1("application/x-zip");
03689 else if (m_strMimeType == "image/x-png")
03690 m_strMimeType = QString::fromLatin1("image/png");
03691 else if (m_strMimeType == "image/bmp")
03692 m_strMimeType = QString::fromLatin1("image/x-bmp");
03693 else if (m_strMimeType == "audio/mpeg" || m_strMimeType == "audio/x-mpeg" || m_strMimeType == "audio/mp3")
03694 m_strMimeType = QString::fromLatin1("audio/x-mp3");
03695 else if (m_strMimeType == "audio/microsoft-wave")
03696 m_strMimeType = QString::fromLatin1("audio/x-wav");
03697 else if (m_strMimeType == "audio/midi")
03698 m_strMimeType = QString::fromLatin1("audio/x-midi");
03699 else if (m_strMimeType == "image/x-xpixmap")
03700 m_strMimeType = QString::fromLatin1("image/x-xpm");
03701 else if (m_strMimeType == "application/rtf")
03702 m_strMimeType = QString::fromLatin1("text/rtf");
03703
03704
03705 else if (m_strMimeType == "application/pkix-cert" ||
03706 m_strMimeType == "application/binary-certificate")
03707 {
03708 m_strMimeType = QString::fromLatin1("application/x-x509-ca-cert");
03709 }
03710
03711
03712 else if (m_strMimeType == "application/x-gzip")
03713 {
03714 if ((m_request.url.path().right(7) == ".tar.gz") ||
03715 (m_request.url.path().right(4) == ".tar"))
03716 m_strMimeType = QString::fromLatin1("application/x-tgz");
03717 if ((m_request.url.path().right(6) == ".ps.gz"))
03718 m_strMimeType = QString::fromLatin1("application/x-gzpostscript");
03719 }
03720
03721
03722 else if ((m_strMimeType == "text/plain") || (m_strMimeType == "application/octet-stream"))
03723 {
03724 QString ext = m_request.url.path().right(4).upper();
03725 if (ext == ".BZ2")
03726 m_strMimeType = QString::fromLatin1("application/x-bzip2");
03727 else if (ext == ".PEM")
03728 m_strMimeType = QString::fromLatin1("application/x-x509-ca-cert");
03729 else if (ext == ".SWF")
03730 m_strMimeType = QString::fromLatin1("application/x-shockwave-flash");
03731 else if (ext == ".PLS")
03732 m_strMimeType = QString::fromLatin1("audio/x-scpls");
03733 else if (ext == ".WMV")
03734 m_strMimeType = QString::fromLatin1("video/x-ms-wmv");
03735 }
03736
03737 #if 0
03738
03739
03740
03741 if (!m_qContentEncodings.isEmpty())
03742 {
03743
03744 m_iSize = NO_SIZE;
03745 }
03746 #endif
03747
03748 if( !disposition.isEmpty() )
03749 {
03750 kdDebug(7113) << "(" << m_pid << ") Setting Content-Disposition metadata to: "
03751 << disposition << endl;
03752 setMetaData("content-disposition", disposition);
03753 }
03754
03755 if (!m_request.lastModified.isEmpty())
03756 setMetaData("modified", m_request.lastModified);
03757
03758 if (!mayCache)
03759 {
03760 setMetaData("no-cache", "true");
03761 setMetaData("expire-date", "1");
03762 }
03763 else
03764 {
03765 QString tmp;
03766 tmp.setNum(expireDate);
03767 setMetaData("expire-date", tmp);
03768 tmp.setNum(time(0));
03769 setMetaData("cache-creation-date", tmp);
03770 }
03771
03772
03773
03774 if (locationStr.isEmpty() && (!m_strMimeType.isEmpty() ||
03775 m_request.method == HTTP_HEAD))
03776 {
03777 kdDebug(7113) << "(" << m_pid << ") Emitting mimetype " << m_strMimeType << endl;
03778 mimeType( m_strMimeType );
03779 }
03780
03781 forwardHttpResponseHeader();
03782
03783 if (m_request.method == HTTP_HEAD)
03784 return true;
03785
03786
03787 if (m_request.bUseCache)
03788 {
03789 ::unlink( QFile::encodeName(m_request.cef));
03790 if ( m_request.bCachedWrite && !m_strMimeType.isEmpty() )
03791 {
03792
03793 createCacheEntry(m_strMimeType, expireDate);
03794 if (!m_request.fcache)
03795 {
03796 m_request.bCachedWrite = false;
03797 kdDebug(7113) << "(" << m_pid << ") Error creating cache entry for " << m_request.url.url()<<"!\n";
03798 }
03799 m_request.expireDate = expireDate;
03800 m_maxCacheSize = config()->readNumEntry("MaxCacheSize", DEFAULT_MAX_CACHE_SIZE) / 2;
03801 }
03802 }
03803
03804 if (m_request.bCachedWrite && !m_strMimeType.isEmpty())
03805 kdDebug(7113) << "(" << m_pid << ") Cache, adding \"" << m_request.url.url() << "\"" << endl;
03806 else if (m_request.bCachedWrite && m_strMimeType.isEmpty())
03807 kdDebug(7113) << "(" << m_pid << ") Cache, pending \"" << m_request.url.url() << "\"" << endl;
03808 else
03809 kdDebug(7113) << "(" << m_pid << ") Cache, not adding \"" << m_request.url.url() << "\"" << endl;
03810 return true;
03811 }
03812
03813
03814 void HTTPProtocol::addEncoding(QString encoding, QStringList &encs)
03815 {
03816 encoding = encoding.stripWhiteSpace().lower();
03817
03818 if (encoding == "identity") {
03819 return;
03820 } else if (encoding == "8bit") {
03821
03822 return;
03823 } else if (encoding == "chunked") {
03824 m_bChunked = true;
03825
03826
03827 m_iSize = NO_SIZE;
03828 } else if ((encoding == "x-gzip") || (encoding == "gzip")) {
03829 encs.append(QString::fromLatin1("gzip"));
03830 } else if ((encoding == "x-bzip2") || (encoding == "bzip2")) {
03831 encs.append(QString::fromLatin1("bzip2"));
03832 } else if ((encoding == "x-deflate") || (encoding == "deflate")) {
03833 encs.append(QString::fromLatin1("deflate"));
03834 } else {
03835 kdDebug(7113) << "(" << m_pid << ") Unknown encoding encountered. "
03836 << "Please write code. Encoding = \"" << encoding
03837 << "\"" << endl;
03838 }
03839 }
03840
03841 bool HTTPProtocol::sendBody()
03842 {
03843 int result=-1;
03844 int length=0;
03845
03846 infoMessage( i18n( "Requesting data to send" ) );
03847
03848
03849
03850
03851 if ( !m_bufPOST.isNull() )
03852 {
03853 kdDebug(7113) << "(" << m_pid << ") POST'ing saved data..." << endl;
03854
03855 result = 0;
03856 length = m_bufPOST.size();
03857 }
03858 else
03859 {
03860 kdDebug(7113) << "(" << m_pid << ") POST'ing live data..." << endl;
03861
03862 QByteArray buffer;
03863 int old_size;
03864
03865 m_bufPOST.resize(0);
03866 do
03867 {
03868 dataReq();
03869 result = readData( buffer );
03870 if ( result > 0 )
03871 {
03872 length += result;
03873 old_size = m_bufPOST.size();
03874 m_bufPOST.resize( old_size+result );
03875 memcpy( m_bufPOST.data()+ old_size, buffer.data(), buffer.size() );
03876 buffer.resize(0);
03877 }
03878 } while ( result > 0 );
03879 }
03880
03881 if ( result < 0 )
03882 {
03883 error( ERR_ABORTED, m_request.hostname );
03884 return false;
03885 }
03886
03887 infoMessage( i18n( "Sending data to %1" ).arg( m_request.hostname ) );
03888
03889 QString size = QString ("Content-Length: %1\r\n\r\n").arg(length);
03890 kdDebug( 7113 ) << "(" << m_pid << ")" << size << endl;
03891
03892
03893 bool sendOk = (write(size.latin1(), size.length()) == (ssize_t) size.length());
03894 if (!sendOk)
03895 {
03896 kdDebug( 7113 ) << "(" << m_pid << ") Connection broken when sending "
03897 << "content length: (" << m_state.hostname << ")" << endl;
03898 error( ERR_CONNECTION_BROKEN, m_state.hostname );
03899 return false;
03900 }
03901
03902
03903
03904 sendOk = (write(m_bufPOST.data(), m_bufPOST.size()) == (ssize_t) m_bufPOST.size());
03905 if (!sendOk)
03906 {
03907 kdDebug(7113) << "(" << m_pid << ") Connection broken when sending message body: ("
03908 << m_state.hostname << ")" << endl;
03909 error( ERR_CONNECTION_BROKEN, m_state.hostname );
03910 return false;
03911 }
03912
03913 return true;
03914 }
03915
03916 void HTTPProtocol::httpClose( bool keepAlive )
03917 {
03918 kdDebug(7113) << "(" << m_pid << ") HTTPProtocol::httpClose" << endl;
03919
03920 if (m_request.fcache)
03921 {
03922 fclose(m_request.fcache);
03923 m_request.fcache = 0;
03924 if (m_request.bCachedWrite)
03925 {
03926 QString filename = m_request.cef + ".new";
03927 ::unlink( QFile::encodeName(filename) );
03928 }
03929 }
03930
03931
03932
03933
03934
03935 if (keepAlive && (!m_bUseProxy ||
03936 m_bPersistentProxyConnection || m_bIsTunneled))
03937 {
03938 if (!m_keepAliveTimeout)
03939 m_keepAliveTimeout = DEFAULT_KEEP_ALIVE_TIMEOUT;
03940 else if (m_keepAliveTimeout > 2*DEFAULT_KEEP_ALIVE_TIMEOUT)
03941 m_keepAliveTimeout = 2*DEFAULT_KEEP_ALIVE_TIMEOUT;
03942
03943 kdDebug(7113) << "(" << m_pid << ") HTTPProtocol::httpClose: keep alive (" << m_keepAliveTimeout << ")" << endl;
03944 QByteArray data;
03945 QDataStream stream( data, IO_WriteOnly );
03946 stream << int(99);
03947 setTimeoutSpecialCommand(m_keepAliveTimeout, data);
03948 return;
03949 }
03950
03951 httpCloseConnection();
03952 }
03953
03954 void HTTPProtocol::closeConnection()
03955 {
03956 kdDebug(7113) << "(" << m_pid << ") HTTPProtocol::closeConnection" << endl;
03957 httpCloseConnection ();
03958 }
03959
03960 void HTTPProtocol::httpCloseConnection ()
03961 {
03962 kdDebug(7113) << "(" << m_pid << ") HTTPProtocol::httpCloseConnection" << endl;
03963 m_bIsTunneled = false;
03964 m_bKeepAlive = false;
03965 closeDescriptor();
03966 setTimeoutSpecialCommand(-1);
03967 }
03968
03969 void HTTPProtocol::slave_status()
03970 {
03971 kdDebug(7113) << "(" << m_pid << ") HTTPProtocol::slave_status" << endl;
03972
03973 if ( m_iSock != -1 && !isConnectionValid() )
03974 httpCloseConnection();
03975
03976 slaveStatus( m_state.hostname, (m_iSock != -1) );
03977 }
03978
03979 void HTTPProtocol::mimetype( const KURL& url )
03980 {
03981 kdDebug(7113) << "(" << m_pid << ") HTTPProtocol::mimetype: "
03982 << url.prettyURL() << endl;
03983
03984 if ( !checkRequestURL( url ) )
03985 return;
03986
03987 m_request.method = HTTP_HEAD;
03988 m_request.path = url.path();
03989 m_request.query = url.query();
03990 m_request.cache = CC_Cache;
03991 m_request.doProxy = m_bUseProxy;
03992
03993 retrieveHeader();
03994
03995 kdDebug(7113) << "(" << m_pid << ") http: mimetype = " << m_strMimeType
03996 << endl;
03997 }
03998
03999 void HTTPProtocol::special( const QByteArray &data )
04000 {
04001 kdDebug(7113) << "(" << m_pid << ") HTTPProtocol::special" << endl;
04002
04003 int tmp;
04004 QDataStream stream(data, IO_ReadOnly);
04005
04006 stream >> tmp;
04007 switch (tmp) {
04008 case 1:
04009 {
04010 KURL url;
04011 stream >> url;
04012 post( url );
04013 break;
04014 }
04015 case 2:
04016 {
04017 KURL url;
04018 bool no_cache;
04019 time_t expireDate;
04020 stream >> url >> no_cache >> expireDate;
04021 cacheUpdate( url, no_cache, expireDate );
04022 break;
04023 }
04024 case 5:
04025 {
04026 KURL url;
04027 QString scope, type, owner;
04028 stream >> url >> scope >> type >> owner;
04029 davLock( url, scope, type, owner );
04030 break;
04031 }
04032 case 6:
04033 {
04034 KURL url;
04035 stream >> url;
04036 davUnlock( url );
04037 break;
04038 }
04039 case 7:
04040 {
04041 KURL url;
04042 int method;
04043 stream >> url >> method;
04044 davGeneric( url, (KIO::HTTP_METHOD) method );
04045 break;
04046 }
04047 case 99:
04048 {
04049 httpCloseConnection();
04050 break;
04051 }
04052 default:
04053
04054
04055 break;
04056 }
04057 }
04058
04062 int HTTPProtocol::readChunked()
04063 {
04064 if ((m_iBytesLeft == 0) || (m_iBytesLeft == NO_SIZE))
04065 {
04066 setRewindMarker();
04067
04068 m_bufReceive.resize(4096);
04069
04070 if (!gets(m_bufReceive.data(), m_bufReceive.size()-1))
04071 {
04072 kdDebug(7113) << "(" << m_pid << ") gets() failure on Chunk header" << endl;
04073 return -1;
04074 }
04075
04076
04077 if (m_bufReceive[0] == '\0')
04078 {
04079 if (!gets(m_bufReceive.data(), m_bufReceive.size()-1))
04080 {
04081 kdDebug(7113) << "(" << m_pid << ") gets() failure on Chunk header" << endl;
04082 return -1;
04083 }
04084 }
04085 if (m_bEOF)
04086 {
04087 kdDebug(7113) << "(" << m_pid << ") EOF on Chunk header" << endl;
04088 return -1;
04089 }
04090
04091 long long trunkSize = STRTOLL(m_bufReceive.data(), 0, 16);
04092 if (trunkSize < 0)
04093 {
04094 kdDebug(7113) << "(" << m_pid << ") Negative chunk size" << endl;
04095 return -1;
04096 }
04097 m_iBytesLeft = trunkSize;
04098
04099
04100
04101 if (m_iBytesLeft == 0)
04102 {
04103
04104
04105 do {
04106
04107 if (!gets(m_bufReceive.data(), m_bufReceive.size()-1))
04108 {
04109 kdDebug(7113) << "(" << m_pid << ") gets() failure on Chunk trailer" << endl;
04110 return -1;
04111 }
04112
04113 }
04114 while (strlen(m_bufReceive.data()) != 0);
04115
04116 return 0;
04117 }
04118 }
04119
04120 int bytesReceived = readLimited();
04121 if (!m_iBytesLeft)
04122 m_iBytesLeft = NO_SIZE;
04123 return bytesReceived;
04124 }
04125
04126 int HTTPProtocol::readLimited()
04127 {
04128 if (!m_iBytesLeft)
04129 return 0;
04130
04131 m_bufReceive.resize(4096);
04132
04133 int bytesReceived;
04134 int bytesToReceive;
04135
04136 if (m_iBytesLeft > m_bufReceive.size())
04137 bytesToReceive = m_bufReceive.size();
04138 else
04139 bytesToReceive = m_iBytesLeft;
04140
04141 bytesReceived = read(m_bufReceive.data(), bytesToReceive);
04142
04143 if (bytesReceived <= 0)
04144 return -1;
04145
04146 m_iBytesLeft -= bytesReceived;
04147 return bytesReceived;
04148 }
04149
04150 int HTTPProtocol::readUnlimited()
04151 {
04152 if (m_bKeepAlive)
04153 {
04154 kdDebug(7113) << "(" << m_pid << ") Unbounded datastream on a Keep "
04155 << "alive connection!" << endl;
04156 m_bKeepAlive = false;
04157 }
04158
04159 m_bufReceive.resize(4096);
04160
04161 int result = read(m_bufReceive.data(), m_bufReceive.size());
04162 if (result > 0)
04163 return result;
04164
04165 m_bEOF = true;
04166 m_iBytesLeft = 0;
04167 return 0;
04168 }
04169
04170 void HTTPProtocol::slotData(const QByteArray &_d)
04171 {
04172 if (!_d.size())
04173 {
04174 m_bEOD = true;
04175 return;
04176 }
04177
04178 if (m_iContentLeft != NO_SIZE)
04179 {
04180 if (m_iContentLeft >= _d.size())
04181 m_iContentLeft -= _d.size();
04182 else
04183 m_iContentLeft = NO_SIZE;
04184 }
04185
04186 QByteArray d = _d;
04187 if ( !m_dataInternal )
04188 {
04189
04190
04191
04192 if ( m_strMimeType.isEmpty() && !m_bRedirect &&
04193 !( m_responseCode >= 300 && m_responseCode <=399) )
04194 {
04195 kdDebug(7113) << "(" << m_pid << ") Determining mime-type from content..." << endl;
04196 int old_size = m_mimeTypeBuffer.size();
04197 m_mimeTypeBuffer.resize( old_size + d.size() );
04198 memcpy( m_mimeTypeBuffer.data() + old_size, d.data(), d.size() );
04199 if ( (m_iBytesLeft != NO_SIZE) && (m_iBytesLeft > 0)
04200 && (m_mimeTypeBuffer.size() < 1024) )
04201 {
04202 m_cpMimeBuffer = true;
04203 return;
04204 }
04205
04206 kdDebug(7113) << "(" << m_pid << ") Mimetype buffer size: " << m_mimeTypeBuffer.size()
04207 << endl;
04208
04209 KMimeMagicResult *result;
04210 result = KMimeMagic::self()->findBufferFileType( m_mimeTypeBuffer,
04211 m_request.url.fileName() );
04212 if( result )
04213 {
04214 m_strMimeType = result->mimeType();
04215 kdDebug(7113) << "(" << m_pid << ") Mimetype from content: "
04216 << m_strMimeType << endl;
04217 }
04218
04219 if ( m_strMimeType.isEmpty() )
04220 {
04221 m_strMimeType = QString::fromLatin1( DEFAULT_MIME_TYPE );
04222 kdDebug(7113) << "(" << m_pid << ") Using default mimetype: "
04223 << m_strMimeType << endl;
04224 }
04225
04226 if ( m_request.bCachedWrite )
04227 {
04228 createCacheEntry( m_strMimeType, m_request.expireDate );
04229 if (!m_request.fcache)
04230 m_request.bCachedWrite = false;
04231 }
04232
04233 if ( m_cpMimeBuffer )
04234 {
04235 d.resize(0);
04236 d.resize(m_mimeTypeBuffer.size());
04237 memcpy( d.data(), m_mimeTypeBuffer.data(),
04238 d.size() );
04239 }
04240 mimeType(m_strMimeType);
04241 m_mimeTypeBuffer.resize(0);
04242 }
04243
04244 data( d );
04245 if (m_request.bCachedWrite && m_request.fcache)
04246 writeCacheEntry(d.data(), d.size());
04247 }
04248 else
04249 {
04250 uint old_size = m_bufWebDavData.size();
04251 m_bufWebDavData.resize (old_size + d.size());
04252 memcpy (m_bufWebDavData.data() + old_size, d.data(), d.size());
04253 }
04254 }
04255
04265 bool HTTPProtocol::readBody( bool dataInternal )
04266 {
04267 if (m_responseCode == 204)
04268 return true;
04269
04270 m_bEOD = false;
04271
04272
04273
04274
04275
04276 m_dataInternal = dataInternal;
04277 if ( dataInternal )
04278 m_bufWebDavData.resize (0);
04279
04280
04281
04282 bool useMD5 = !m_sContentMD5.isEmpty();
04283
04284
04285 KIO::filesize_t sz = m_request.offset;
04286 if ( sz )
04287 m_iSize += sz;
04288
04289
04290
04291
04292
04293 if ( !dataInternal ) {
04294 if ( (m_iSize > 0) && (m_iSize != NO_SIZE)) {
04295 totalSize(m_iSize);
04296 infoMessage( i18n( "Retrieving %1 from %2...").arg(KIO::convertSize(m_iSize))
04297 .arg( m_request.hostname ) );
04298 }
04299 else
04300 {
04301 totalSize ( 0 );
04302 }
04303 }
04304 else
04305 infoMessage( i18n( "Retrieving from %1..." ).arg( m_request.hostname ) );
04306
04307 if (m_request.bCachedRead)
04308 {
04309 kdDebug(7113) << "(" << m_pid << ") HTTPProtocol::readBody: read data from cache!" << endl;
04310 m_request.bCachedWrite = false;
04311
04312 char buffer[ MAX_IPC_SIZE ];
04313
04314 m_iContentLeft = NO_SIZE;
04315
04316
04317 while (!feof(m_request.fcache) && !ferror(m_request.fcache))
04318 {
04319 int nbytes = fread( buffer, 1, MAX_IPC_SIZE, m_request.fcache);
04320
04321 if (nbytes > 0)
04322 {
04323 m_bufReceive.setRawData( buffer, nbytes);
04324 slotData( m_bufReceive );
04325 m_bufReceive.resetRawData( buffer, nbytes );
04326 sz += nbytes;
04327 }
04328 }
04329
04330 m_bufReceive.resize( 0 );
04331
04332 if ( !dataInternal )
04333 {
04334 processedSize( sz );
04335 data( QByteArray() );
04336 }
04337
04338 return true;
04339 }
04340
04341
04342 if (m_iSize != NO_SIZE)
04343 m_iBytesLeft = m_iSize - sz;
04344 else
04345 m_iBytesLeft = NO_SIZE;
04346
04347 m_iContentLeft = m_iBytesLeft;
04348
04349 if (m_bChunked)
04350 m_iBytesLeft = NO_SIZE;
04351
04352 kdDebug(7113) << "(" << m_pid << ") HTTPProtocol::readBody: retrieve data. "<<KIO::number(m_iBytesLeft)<<" left." << endl;
04353
04354
04355 m_cpMimeBuffer = false;
04356 m_mimeTypeBuffer.resize(0);
04357 struct timeval last_tv;
04358 gettimeofday( &last_tv, 0L );
04359
04360 HTTPFilterChain chain;
04361
04362 QObject::connect(&chain, SIGNAL(output(const QByteArray &)),
04363 this, SLOT(slotData(const QByteArray &)));
04364 QObject::connect(&chain, SIGNAL(error(int, const QString &)),
04365 this, SLOT(error(int, const QString &)));
04366
04367
04368 while (!m_qTransferEncodings.isEmpty())
04369 {
04370 QString enc = m_qTransferEncodings.last();
04371 m_qTransferEncodings.remove(m_qTransferEncodings.fromLast());
04372 if ( enc == "gzip" )
04373 chain.addFilter(new HTTPFilterGZip);
04374 else if ( enc == "deflate" )
04375 chain.addFilter(new HTTPFilterDeflate);
04376 }
04377
04378
04379
04380
04381
04382
04383
04384 HTTPFilterMD5 *md5Filter = 0;
04385 if ( useMD5 )
04386 {
04387 md5Filter = new HTTPFilterMD5;
04388 chain.addFilter(md5Filter);
04389 }
04390
04391
04392
04393
04394
04395
04396
04397
04398
04399 while (!m_qContentEncodings.isEmpty())
04400 {
04401 QString enc = m_qContentEncodings.last();
04402 m_qContentEncodings.remove(m_qContentEncodings.fromLast());
04403 if ( enc == "gzip" )
04404 chain.addFilter(new HTTPFilterGZip);
04405 else if ( enc == "deflate" )
04406 chain.addFilter(new HTTPFilterDeflate);
04407 }
04408
04409 while (!m_bEOF)
04410 {
04411 int bytesReceived;
04412
04413 if (m_bChunked)
04414 bytesReceived = readChunked();
04415 else if (m_iSize != NO_SIZE)
04416 bytesReceived = readLimited();
04417 else
04418 bytesReceived = readUnlimited();
04419
04420
04421
04422
04423
04424 if (bytesReceived == -1)
04425 {
04426 if (m_iContentLeft == 0)
04427 {
04428
04429
04430 m_iBytesLeft = 0;
04431 break;
04432 }
04433
04434 kdDebug(7113) << "(" << m_pid << ") readBody: bytesReceived==-1 sz=" << (int)sz
04435 << " Connnection broken !" << endl;
04436 error(ERR_CONNECTION_BROKEN, m_state.hostname);
04437 return false;
04438 }
04439
04440
04441
04442 if (bytesReceived > 0)
04443 {
04444
04445
04446 m_bufReceive.truncate( bytesReceived );
04447
04448 chain.slotInput(m_bufReceive);
04449
04450 if (m_bError)
04451 return false;
04452
04453 sz += bytesReceived;
04454 if (!dataInternal)
04455 processedSize( sz );
04456 }
04457 m_bufReceive.resize(0);
04458
04459 if (m_iBytesLeft && m_bEOD && !m_bChunked)
04460 {
04461
04462
04463 m_iBytesLeft = 0;
04464 }
04465
04466 if (m_iBytesLeft == 0)
04467 {
04468 kdDebug(7113) << "("<<m_pid<<") EOD received! Left = "<< KIO::number(m_iBytesLeft) << endl;
04469 break;
04470 }
04471 }
04472 chain.slotInput(QByteArray());
04473
04474 if ( useMD5 )
04475 {
04476 QString calculatedMD5 = md5Filter->md5();
04477
04478 if ( m_sContentMD5 == calculatedMD5 )
04479 kdDebug(7113) << "(" << m_pid << ") MD5 checksum MATCHED!!" << endl;
04480 else
04481 kdDebug(7113) << "(" << m_pid << ") MD5 checksum MISMATCH! Expected: "
04482 << calculatedMD5 << ", Got: " << m_sContentMD5 << endl;
04483 }
04484
04485
04486 if (m_iBytesLeft == 0)
04487 {
04488 if (m_request.bCachedWrite && m_request.fcache)
04489 closeCacheEntry();
04490 else if (m_request.bCachedWrite) kdDebug(7113) << "(" << m_pid << ") no cache file!\n";
04491 }
04492 else kdDebug(7113) << "(" << m_pid << ") still "<< KIO::number(m_iBytesLeft) <<" bytes left! can't close cache entry!\n";
04493
04494 if (!dataInternal)
04495 data( QByteArray() );
04496 return true;
04497 }
04498
04499
04500 void HTTPProtocol::error( int _err, const QString &_text )
04501 {
04502 httpClose(false);
04503
04504 if (!m_request.id.isEmpty())
04505 {
04506 forwardHttpResponseHeader();
04507 sendMetaData();
04508 }
04509
04510
04511 if (!m_bufPOST.isEmpty())
04512 {
04513 m_bufPOST.resize(0);
04514 kdDebug(7113) << "(" << m_pid << ") HTTP::retreiveHeader: Cleared POST "
04515 "buffer..." << endl;
04516 }
04517
04518 SlaveBase::error( _err, _text );
04519 m_bError = true;
04520 }
04521
04522
04523 void HTTPProtocol::addCookies( const QString &url, const QCString &cookieHeader )
04524 {
04525 long windowId = m_request.window.toLong();
04526 QByteArray params;
04527 QDataStream stream(params, IO_WriteOnly);
04528 stream << url << cookieHeader << windowId;
04529
04530 kdDebug(7113) << "(" << m_pid << ") " << cookieHeader << endl;
04531 kdDebug(7113) << "(" << m_pid << ") " << "Window ID: "
04532 << windowId << ", for host = " << url << endl;
04533
04534 if ( !dcopClient()->send( "kded", "kcookiejar", "addCookies(QString,QCString,long int)", params ) )
04535 {
04536 kdWarning(7113) << "(" << m_pid << ") Can't communicate with kded_kcookiejar!" << endl;
04537 }
04538 }
04539
04540 QString HTTPProtocol::findCookies( const QString &url)
04541 {
04542 QCString replyType;
04543 QByteArray params;
04544 QByteArray reply;
04545 QString result;
04546
04547 long windowId = m_request.window.toLong();
04548 result = QString::null;
04549 QDataStream stream(params, IO_WriteOnly);
04550 stream << url << windowId;
04551
04552 if ( !dcopClient()->call( "kded", "kcookiejar", "findCookies(QString,long int)",
04553 params, replyType, reply ) )
04554 {
04555 kdWarning(7113) << "(" << m_pid << ") Can't communicate with kded_kcookiejar!" << endl;
04556 return result;
04557 }
04558 if ( replyType == "QString" )
04559 {
04560 QDataStream stream2( reply, IO_ReadOnly );
04561 stream2 >> result;
04562 }
04563 else
04564 {
04565 kdError(7113) << "(" << m_pid << ") DCOP function findCookies(...) returns "
04566 << replyType << ", expected QString" << endl;
04567 }
04568 return result;
04569 }
04570
04571
04572
04573
04574 void HTTPProtocol::cacheUpdate( const KURL& url, bool no_cache, time_t expireDate)
04575 {
04576 if ( !checkRequestURL( url ) )
04577 return;
04578
04579 m_request.path = url.path();
04580 m_request.query = url.query();
04581 m_request.cache = CC_Reload;
04582 m_request.doProxy = m_bUseProxy;
04583
04584 if (no_cache)
04585 {
04586 m_request.fcache = checkCacheEntry( );
04587 if (m_request.fcache)
04588 {
04589 fclose(m_request.fcache);
04590 m_request.fcache = 0;
04591 ::unlink( QFile::encodeName(m_request.cef) );
04592 }
04593 }
04594 else
04595 {
04596 updateExpireDate( expireDate );
04597 }
04598 finished();
04599 }
04600
04601
04602
04603
04604
04605 FILE* HTTPProtocol::checkCacheEntry( bool readWrite)
04606 {
04607 const QChar separator = '_';
04608
04609 QString CEF = m_request.path;
04610
04611 int p = CEF.find('/');
04612
04613 while(p != -1)
04614 {
04615 CEF[p] = separator;
04616 p = CEF.find('/', p);
04617 }
04618
04619 QString host = m_request.hostname.lower();
04620 CEF = host + CEF + '_';
04621
04622 QString dir = m_strCacheDir;
04623 if (dir[dir.length()-1] != '/')
04624 dir += "/";
04625
04626 int l = host.length();
04627 for(int i = 0; i < l; i++)
04628 {
04629 if (host[i].isLetter() && (host[i] != 'w'))
04630 {
04631 dir += host[i];
04632 break;
04633 }
04634 }
04635 if (dir[dir.length()-1] == '/')
04636 dir += "0";
04637
04638 unsigned long hash = 0x00000000;
04639 QCString u = m_request.url.url().latin1();
04640 for(int i = u.length(); i--;)
04641 {
04642 hash = (hash * 12211 + u[i]) % 2147483563;
04643 }
04644
04645 QString hashString;
04646 hashString.sprintf("%08lx", hash);
04647
04648 CEF = CEF + hashString;
04649
04650 CEF = dir + "/" + CEF;
04651
04652 m_request.cef = CEF;
04653
04654 const char *mode = (readWrite ? "r+" : "r");
04655
04656 FILE *fs = fopen( QFile::encodeName(CEF), mode);
04657 if (!fs)
04658 return 0;
04659
04660 char buffer[401];
04661 bool ok = true;
04662
04663
04664 if (ok && (!fgets(buffer, 400, fs)))
04665 ok = false;
04666 if (ok && (strcmp(buffer, CACHE_REVISION) != 0))
04667 ok = false;
04668
04669 time_t date;
04670 time_t currentDate = time(0);
04671
04672
04673 if (ok && (!fgets(buffer, 400, fs)))
04674 ok = false;
04675 if (ok)
04676 {
04677 int l = strlen(buffer);
04678 if (l>0)
04679 buffer[l-1] = 0;
04680 if (m_request.url.url() != buffer)
04681 {
04682 ok = false;
04683 }
04684 }
04685
04686
04687 if (ok && (!fgets(buffer, 400, fs)))
04688 ok = false;
04689 if (ok)
04690 {
04691 date = (time_t) strtoul(buffer, 0, 10);
04692 m_request.creationDate = date;
04693 if (m_maxCacheAge && (difftime(currentDate, date) > m_maxCacheAge))
04694 {
04695 m_request.bMustRevalidate = true;
04696 m_request.expireDate = currentDate;
04697 }
04698 }
04699
04700
04701 m_request.cacheExpireDateOffset = ftell(fs);
04702 if (ok && (!fgets(buffer, 400, fs)))
04703 ok = false;
04704 if (ok)
04705 {
04706 if (m_request.cache == CC_Verify)
04707 {
04708 date = (time_t) strtoul(buffer, 0, 10);
04709
04710 if (!date || difftime(currentDate, date) >= 0)
04711 m_request.bMustRevalidate = true;
04712 m_request.expireDate = date;
04713 }
04714 else if (m_request.cache == CC_Refresh)
04715 {
04716 m_request.bMustRevalidate = true;
04717 m_request.expireDate = currentDate;
04718 }
04719 }
04720
04721
04722 if (ok && (!fgets(buffer, 400, fs)))
04723 ok = false;
04724 if (ok)
04725 {
04726 m_request.etag = QString(buffer).stripWhiteSpace();
04727 }
04728
04729
04730 if (ok && (!fgets(buffer, 400, fs)))
04731 ok = false;
04732 if (ok)
04733 {
04734 m_request.lastModified = QString(buffer).stripWhiteSpace();
04735 }
04736
04737 if (ok)
04738 return fs;
04739
04740 fclose(fs);
04741 unlink( QFile::encodeName(CEF));
04742 return 0;
04743 }
04744
04745 void HTTPProtocol::updateExpireDate(time_t expireDate, bool updateCreationDate)
04746 {
04747 bool ok = true;
04748
04749 FILE *fs = checkCacheEntry(true);
04750 if (fs)
04751 {
04752 QString date;
04753 char buffer[401];
04754 time_t creationDate;
04755
04756 fseek(fs, 0, SEEK_SET);
04757 if (ok && !fgets(buffer, 400, fs))
04758 ok = false;
04759 if (ok && !fgets(buffer, 400, fs))
04760 ok = false;
04761 long cacheCreationDateOffset = ftell(fs);
04762 if (ok && !fgets(buffer, 400, fs))
04763 ok = false;
04764 creationDate = strtoul(buffer, 0, 10);
04765 if (!creationDate)
04766 ok = false;
04767
04768 if (updateCreationDate)
04769 {
04770 if (!ok || fseek(fs, cacheCreationDateOffset, SEEK_SET))
04771 return;
04772 QString date;
04773 date.setNum( time(0) );
04774 date = date.leftJustify(16);
04775 fputs(date.latin1(), fs);
04776 fputc('\n', fs);
04777 }
04778
04779 if (expireDate>(30*365*24*60*60))
04780 {
04781
04782
04783 date.setNum( expireDate );
04784 }
04785 else
04786 {
04787
04788
04789
04790
04791
04792 date.setNum( creationDate + expireDate );
04793 }
04794 date = date.leftJustify(16);
04795 if (!ok || fseek(fs, m_request.cacheExpireDateOffset, SEEK_SET))
04796 return;
04797 fputs(date.latin1(), fs);
04798 fseek(fs, 0, SEEK_END);
04799 fclose(fs);
04800 }
04801 }
04802
04803 void HTTPProtocol::createCacheEntry( const QString &mimetype, time_t expireDate)
04804 {
04805 QString dir = m_request.cef;
04806 int p = dir.findRev('/');
04807 if (p == -1) return;
04808 dir.truncate(p);
04809
04810
04811 (void) ::mkdir( QFile::encodeName(dir), 0700 );
04812
04813 QString filename = m_request.cef + ".new";
04814
04815
04816
04817 m_request.fcache = fopen( QFile::encodeName(filename), "w");
04818 if (!m_request.fcache)
04819 {
04820 kdWarning(7113) << "(" << m_pid << ")createCacheEntry: opening " << filename << " failed." << endl;
04821 return;
04822 }
04823
04824 fputs(CACHE_REVISION, m_request.fcache);
04825
04826 fputs(m_request.url.url().latin1(), m_request.fcache);
04827 fputc('\n', m_request.fcache);
04828
04829 QString date;
04830 m_request.creationDate = time(0);
04831 date.setNum( m_request.creationDate );
04832 date = date.leftJustify(16);
04833 fputs(date.latin1(), m_request.fcache);
04834 fputc('\n', m_request.fcache);
04835
04836 date.setNum( expireDate );
04837 date = date.leftJustify(16);
04838 fputs(date.latin1(), m_request.fcache);
04839 fputc('\n', m_request.fcache);
04840
04841 if (!m_request.etag.isEmpty())
04842 fputs(m_request.etag.latin1(), m_request.fcache);
04843 fputc('\n', m_request.fcache);
04844
04845 if (!m_request.lastModified.isEmpty())
04846 fputs(m_request.lastModified.latin1(), m_request.fcache);
04847 fputc('\n', m_request.fcache);
04848
04849 fputs(mimetype.latin1(), m_request.fcache);
04850 fputc('\n', m_request.fcache);
04851
04852 if (!m_request.strCharset.isEmpty())
04853 fputs(m_request.strCharset.latin1(), m_request.fcache);
04854 fputc('\n', m_request.fcache);
04855
04856 return;
04857 }
04858
04859
04860
04861
04862 void HTTPProtocol::writeCacheEntry( const char *buffer, int nbytes)
04863 {
04864 if (fwrite( buffer, nbytes, 1, m_request.fcache) != 1)
04865 {
04866 kdWarning(7113) << "(" << m_pid << ") writeCacheEntry: writing " << nbytes << " bytes failed." << endl;
04867 fclose(m_request.fcache);
04868 m_request.fcache = 0;
04869 QString filename = m_request.cef + ".new";
04870 ::unlink( QFile::encodeName(filename) );
04871 return;
04872 }
04873 long file_pos = ftell( m_request.fcache ) / 1024;
04874 if ( file_pos > m_maxCacheSize )
04875 {
04876 kdDebug(7113) << "writeCacheEntry: File size reaches " << file_pos
04877 << "Kb, exceeds cache limits. (" << m_maxCacheSize << "Kb)" << endl;
04878 fclose(m_request.fcache);
04879 m_request.fcache = 0;
04880 QString filename = m_request.cef + ".new";
04881 ::unlink( QFile::encodeName(filename) );
04882 return;
04883 }
04884 }
04885
04886 void HTTPProtocol::closeCacheEntry()
04887 {
04888 QString filename = m_request.cef + ".new";
04889 int result = fclose( m_request.fcache);
04890 m_request.fcache = 0;
04891 if (result == 0)
04892 {
04893 if (::rename( QFile::encodeName(filename), QFile::encodeName(m_request.cef)) == 0)
04894 return;
04895
04896 kdWarning(7113) << "(" << m_pid << ") closeCacheEntry: error renaming "
04897 << "cache entry. (" << filename << " -> " << m_request.cef
04898 << ")" << endl;
04899 }
04900
04901 kdWarning(7113) << "(" << m_pid << ") closeCacheEntry: error closing cache "
04902 << "entry. (" << filename<< ")" << endl;
04903 }
04904
04905 void HTTPProtocol::cleanCache()
04906 {
04907 const time_t maxAge = DEFAULT_CLEAN_CACHE_INTERVAL;
04908 bool doClean = false;
04909 QString cleanFile = m_strCacheDir;
04910 if (cleanFile[cleanFile.length()-1] != '/')
04911 cleanFile += "/";
04912 cleanFile += "cleaned";
04913
04914 struct stat stat_buf;
04915
04916 int result = ::stat(QFile::encodeName(cleanFile), &stat_buf);
04917 if (result == -1)
04918 {
04919 int fd = creat( QFile::encodeName(cleanFile), 0600);
04920 if (fd != -1)
04921 {
04922 doClean = true;
04923 ::close(fd);
04924 }
04925 }
04926 else
04927 {
04928 time_t age = (time_t) difftime( time(0), stat_buf.st_mtime );
04929 if (age > maxAge)
04930 doClean = true;
04931 }
04932 if (doClean)
04933 {
04934
04935 utime(QFile::encodeName(cleanFile), 0);
04936 KApplication::startServiceByDesktopPath("http_cache_cleaner.desktop");
04937 }
04938 }
04939
04940
04941
04942
04943
04944
04945 void HTTPProtocol::configAuth( char *p, bool isForProxy )
04946 {
04947 HTTP_AUTH f = AUTH_None;
04948 const char *strAuth = p;
04949
04950 if ( strncasecmp( p, "Basic", 5 ) == 0 )
04951 {
04952 f = AUTH_Basic;
04953 p += 5;
04954 strAuth = "Basic";
04955 }
04956 else if ( strncasecmp (p, "Digest", 6) == 0 )
04957 {
04958 f = AUTH_Digest;
04959 memcpy((void *)p, "Digest", 6);
04960 p += 6;
04961 }
04962 else if (strncasecmp( p, "MBS_PWD_COOKIE", 14 ) == 0)
04963 {
04964
04965 f = AUTH_Basic;
04966 p += 14;
04967 strAuth = "Basic";
04968 }
04969 #ifdef HAVE_LIBGSSAPI
04970 else if ( strncasecmp( p, "Negotiate", 9 ) == 0 )
04971 {
04972
04973
04974 if ( !isForProxy && !(m_responseCode == 401 && m_prevResponseCode == 401) )
04975 {
04976 f = AUTH_Negotiate;
04977 memcpy((void *)p, "Negotiate", 9);
04978 p += 9;
04979 };
04980 }
04981 #endif
04982 else if ( strncasecmp( p, "NTLM", 4 ) == 0 )
04983 {
04984 f = AUTH_NTLM;
04985 memcpy((void *)p, "NTLM", 4);
04986 p += 4;
04987 m_strRealm = "NTLM";
04988 }
04989 else
04990 {
04991 kdWarning(7113) << "(" << m_pid << ") Unsupported or invalid authorization "
04992 << "type requested" << endl;
04993 if (isForProxy)
04994 kdWarning(7113) << "(" << m_pid << ") Proxy URL: " << m_proxyURL << endl;
04995 else
04996 kdWarning(7113) << "(" << m_pid << ") URL: " << m_request.url << endl;
04997 kdWarning(7113) << "(" << m_pid << ") Request Authorization: " << p << endl;
04998 }
04999
05000
05001
05002
05003
05004
05005
05006
05007 if (isForProxy)
05008 {
05009 if ((f == AUTH_None) ||
05010 ((m_iProxyAuthCount > 0) && (f < ProxyAuthentication)))
05011 {
05012
05013
05014
05015
05016 if ( m_iProxyAuthCount == 0)
05017 ProxyAuthentication = f;
05018 kdDebug(7113) << "(" << m_pid << ") Rejected proxy auth method: " << f << endl;
05019 return;
05020 }
05021 m_iProxyAuthCount++;
05022 kdDebug(7113) << "(" << m_pid << ") Accepted proxy auth method: " << f << endl;
05023 }
05024 else
05025 {
05026 if ((f == AUTH_None) ||
05027 ((m_iWWWAuthCount > 0) && (f < Authentication)))
05028 {
05029 kdDebug(7113) << "(" << m_pid << ") Rejected auth method: " << f << endl;
05030 return;
05031 }
05032 m_iWWWAuthCount++;
05033 kdDebug(7113) << "(" << m_pid << ") Accepted auth method: " << f << endl;
05034 }
05035
05036
05037 while (*p)
05038 {
05039 int i = 0;
05040 while( (*p == ' ') || (*p == ',') || (*p == '\t') ) { p++; }
05041 if ( strncasecmp( p, "realm=", 6 ) == 0 )
05042 {
05043 p += 6;
05044 if (*p == '"') p++;
05045 while( p[i] && p[i] != '"' ) i++;
05046 if( isForProxy )
05047 m_strProxyRealm = QString::fromLatin1( p, i );
05048 else
05049 m_strRealm = QString::fromLatin1( p, i );
05050 if (!p[i]) break;
05051 }
05052 p+=(i+1);
05053 }
05054
05055 if( isForProxy )
05056 {
05057 ProxyAuthentication = f;
05058 m_strProxyAuthorization = QString::fromLatin1( strAuth );
05059 }
05060 else
05061 {
05062 Authentication = f;
05063 m_strAuthorization = QString::fromLatin1( strAuth );
05064 }
05065 }
05066
05067
05068 bool HTTPProtocol::retryPrompt()
05069 {
05070 QString prompt;
05071 switch ( m_responseCode )
05072 {
05073 case 401:
05074 prompt = i18n("Authentication Failed.");
05075 break;
05076 case 407:
05077 prompt = i18n("Proxy Authentication Failed.");
05078 break;
05079 default:
05080 break;
05081 }
05082 prompt += i18n(" Do you want to retry?");
05083 return (messageBox(QuestionYesNo, prompt, i18n("Authentication")) == 3);
05084 }
05085
05086 void HTTPProtocol::promptInfo( AuthInfo& info )
05087 {
05088 if ( m_responseCode == 401 )
05089 {
05090 info.url = m_request.url;
05091 if ( !m_state.user.isEmpty() )
05092 info.username = m_state.user;
05093 info.readOnly = !m_request.url.user().isEmpty();
05094 info.prompt = i18n( "You need to supply a username and a "
05095 "password to access this site." );
05096 info.keepPassword = true;
05097 if ( !m_strRealm.isEmpty() )
05098 {
05099 info.realmValue = m_strRealm;
05100 info.verifyPath = false;
05101 info.digestInfo = m_strAuthorization;
05102 info.commentLabel = i18n( "Site:" );
05103 info.comment = i18n("<b>%1</b> at <b>%2</b>").arg( m_strRealm ).arg( m_request.hostname );
05104 }
05105 }
05106 else if ( m_responseCode == 407 )
05107 {
05108 info.url = m_proxyURL;
05109 info.username = m_proxyURL.user();
05110 info.prompt = i18n( "You need to supply a username and a password for "
05111 "the proxy server listed below before you are allowed "
05112 "to access any sites." );
05113 info.keepPassword = true;
05114 if ( !m_strProxyRealm.isEmpty() )
05115 {
05116 info.realmValue = m_strProxyRealm;
05117 info.verifyPath = false;
05118 info.digestInfo = m_strProxyAuthorization;
05119 info.commentLabel = i18n( "Proxy:" );
05120 info.comment = i18n("<b>%1</b> at <b>%2</b>").arg( m_strProxyRealm ).arg( m_proxyURL.host() );
05121 }
05122 }
05123 }
05124
05125 bool HTTPProtocol::getAuthorization()
05126 {
05127 AuthInfo info;
05128 bool result = false;
05129
05130 kdDebug (7113) << "(" << m_pid << ") HTTPProtocol::getAuthorization: "
05131 << "Current Response: " << m_responseCode << ", "
05132 << "Previous Response: " << m_prevResponseCode << ", "
05133 << "Authentication: " << Authentication << ", "
05134 << "ProxyAuthentication: " << ProxyAuthentication << endl;
05135
05136 if (m_request.bNoAuth)
05137 {
05138 if (m_request.bErrorPage)
05139 errorPage();
05140 else
05141 error( ERR_COULD_NOT_LOGIN, i18n("Authentication needed for %1 but authentication is disabled.").arg(m_request.hostname));
05142 return false;
05143 }
05144
05145 bool repeatFailure = (m_prevResponseCode == m_responseCode);
05146
05147 QString errorMsg;
05148
05149 if (repeatFailure)
05150 {
05151 bool prompt = true;
05152 if ( Authentication == AUTH_Digest || ProxyAuthentication == AUTH_Digest )
05153 {
05154 bool isStaleNonce = false;
05155 QString auth = ( m_responseCode == 401 ) ? m_strAuthorization : m_strProxyAuthorization;
05156 int pos = auth.find("stale", 0, false);
05157 if ( pos != -1 )
05158 {
05159 pos += 5;
05160 int len = auth.length();
05161 while( pos < len && (auth[pos] == ' ' || auth[pos] == '=') ) pos++;
05162 if ( pos < len && auth.find("true", pos, false) != -1 )
05163 {
05164 isStaleNonce = true;
05165 kdDebug(7113) << "(" << m_pid << ") Stale nonce value. "
05166 << "Will retry using same info..." << endl;
05167 }
05168 }
05169 if ( isStaleNonce )
05170 {
05171 prompt = false;
05172 result = true;
05173 if ( m_responseCode == 401 )
05174 {
05175 info.username = m_request.user;
05176 info.password = m_request.passwd;
05177 info.realmValue = m_strRealm;
05178 info.digestInfo = m_strAuthorization;
05179 }
05180 else if ( m_responseCode == 407 )
05181 {
05182 info.username = m_proxyURL.user();
05183 info.password = m_proxyURL.pass();
05184 info.realmValue = m_strProxyRealm;
05185 info.digestInfo = m_strProxyAuthorization;
05186 }
05187 }
05188 }
05189
05190 if ( Authentication == AUTH_NTLM || ProxyAuthentication == AUTH_NTLM )
05191 {
05192 QString auth = ( m_responseCode == 401 ) ? m_strAuthorization : m_strProxyAuthorization;
05193 kdDebug(7113) << "auth: " << auth << endl;
05194 if ( auth.length() > 4 )
05195 {
05196 prompt = false;
05197 result = true;
05198 kdDebug(7113) << "(" << m_pid << ") NTLM auth second phase, "
05199 << "sending response..." << endl;
05200 if ( m_responseCode == 401 )
05201 {
05202 info.username = m_request.user;
05203 info.password = m_request.passwd;
05204 info.realmValue = m_strRealm;
05205 info.digestInfo = m_strAuthorization;
05206 }
05207 else if ( m_responseCode == 407 )
05208 {
05209 info.username = m_proxyURL.user();
05210 info.password = m_proxyURL.pass();
05211 info.realmValue = m_strProxyRealm;
05212 info.digestInfo = m_strProxyAuthorization;
05213 }
05214 }
05215 }
05216
05217 if ( prompt )
05218 {
05219 switch ( m_responseCode )
05220 {
05221 case 401:
05222 errorMsg = i18n("Authentication Failed.");
05223 break;
05224 case 407:
05225 errorMsg = i18n("Proxy Authentication Failed.");
05226 break;
05227 default:
05228 break;
05229 }
05230 }
05231 }
05232 else
05233 {
05234
05235
05236
05237
05238
05239 if (m_bProxyAuthValid)
05240 {
05241
05242 m_bProxyAuthValid = false;
05243 KURL proxy ( config()->readEntry("UseProxy") );
05244 m_proxyURL.setUser(proxy.user());
05245 m_proxyURL.setPass(proxy.pass());
05246 }
05247
05248 info.verifyPath = false;
05249 if ( m_responseCode == 407 )
05250 {
05251 info.url = m_proxyURL;
05252 info.username = m_proxyURL.user();
05253 info.password = m_proxyURL.pass();
05254 info.realmValue = m_strProxyRealm;
05255 info.digestInfo = m_strProxyAuthorization;
05256 }
05257 else
05258 {
05259 info.url = m_request.url;
05260 info.username = m_request.user;
05261 info.password = m_request.passwd;
05262 info.realmValue = m_strRealm;
05263 info.digestInfo = m_strAuthorization;
05264 }
05265
05266
05267
05268 if ( info.username.isNull() ||
05269 info.password.isNull() )
05270 result = checkCachedAuthentication( info );
05271
05272 if ( Authentication == AUTH_Digest )
05273 {
05274 QString auth;
05275
05276 if (m_responseCode == 401)
05277 auth = m_strAuthorization;
05278 else
05279 auth = m_strProxyAuthorization;
05280
05281 int pos = auth.find("stale", 0, false);
05282 if ( pos != -1 )
05283 {
05284 pos += 5;
05285 int len = auth.length();
05286 while( pos < len && (auth[pos] == ' ' || auth[pos] == '=') ) pos++;
05287 if ( pos < len && auth.find("true", pos, false) != -1 )
05288 {
05289 info.digestInfo = (m_responseCode == 401) ? m_strAuthorization : m_strProxyAuthorization;
05290 kdDebug(7113) << "(" << m_pid << ") Just a stale nonce value! "
05291 << "Retrying using the new nonce sent..." << endl;
05292 }
05293 }
05294 }
05295 }
05296
05297 if (!result )
05298 {
05299
05300
05301
05302 if ( !repeatFailure &&
05303 !info.username.isNull() &&
05304 !info.password.isNull() )
05305 result = true;
05306 else
05307 {
05308 if (Authentication == AUTH_Negotiate)
05309 {
05310 if (!repeatFailure)
05311 result = true;
05312 }
05313 else if ( m_request.disablePassDlg == false )
05314 {
05315 kdDebug( 7113 ) << "(" << m_pid << ") Prompting the user for authorization..." << endl;
05316 promptInfo( info );
05317 result = openPassDlg( info, errorMsg );
05318 }
05319 }
05320 }
05321
05322 if ( result )
05323 {
05324 switch (m_responseCode)
05325 {
05326 case 401:
05327 m_request.user = info.username;
05328 m_request.passwd = info.password;
05329 m_strRealm = info.realmValue;
05330 m_strAuthorization = info.digestInfo;
05331 break;
05332 case 407:
05333 m_proxyURL.setUser( info.username );
05334 m_proxyURL.setPass( info.password );
05335 m_strProxyRealm = info.realmValue;
05336 m_strProxyAuthorization = info.digestInfo;
05337 break;
05338 default:
05339 break;
05340 }
05341 return true;
05342 }
05343
05344 if (m_request.bErrorPage)
05345 errorPage();
05346 else
05347 error( ERR_USER_CANCELED, QString::null );
05348 return false;
05349 }
05350
05351 void HTTPProtocol::saveAuthorization()
05352 {
05353 AuthInfo info;
05354 if ( m_prevResponseCode == 407 )
05355 {
05356 if (!m_bUseProxy)
05357 return;
05358 m_bProxyAuthValid = true;
05359 info.url = m_proxyURL;
05360 info.username = m_proxyURL.user();
05361 info.password = m_proxyURL.pass();
05362 info.realmValue = m_strProxyRealm;
05363 info.digestInfo = m_strProxyAuthorization;
05364 cacheAuthentication( info );
05365 }
05366 else
05367 {
05368 info.url = m_request.url;
05369 info.username = m_request.user;
05370 info.password = m_request.passwd;
05371 info.realmValue = m_strRealm;
05372 info.digestInfo = m_strAuthorization;
05373 cacheAuthentication( info );
05374 }
05375 }
05376
05377 #ifdef HAVE_LIBGSSAPI
05378 QCString HTTPProtocol::gssError( int major_status, int minor_status )
05379 {
05380 OM_uint32 new_status;
05381 OM_uint32 msg_ctx = 0;
05382 gss_buffer_desc major_string;
05383 gss_buffer_desc minor_string;
05384 OM_uint32 ret;
05385 QCString errorstr;
05386
05387 errorstr = "";
05388
05389 do {
05390 ret = gss_display_status(&new_status, major_status, GSS_C_GSS_CODE, GSS_C_NULL_OID, &msg_ctx, &major_string);
05391 errorstr += (const char *)major_string.value;
05392 errorstr += " ";
05393 ret = gss_display_status(&new_status, minor_status, GSS_C_MECH_CODE, GSS_C_NULL_OID, &msg_ctx, &minor_string);
05394 errorstr += (const char *)minor_string.value;
05395 errorstr += " ";
05396 } while (!GSS_ERROR(ret) && msg_ctx != 0);
05397
05398 return errorstr;
05399 }
05400
05401 QString HTTPProtocol::createNegotiateAuth()
05402 {
05403 QString auth;
05404 QCString servicename;
05405 QByteArray input;
05406 OM_uint32 major_status, minor_status;
05407 OM_uint32 req_flags = 0;
05408 gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
05409 gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
05410 gss_name_t server;
05411 gss_ctx_id_t ctx;
05412 gss_OID mech_oid;
05413 static gss_OID_desc krb5_oid_desc = {9, (void *) "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"};
05414 static gss_OID_desc spnego_oid_desc = {6, (void *) "\x2b\x06\x01\x05\x05\x02"};
05415 int found = 0;
05416 unsigned int i;
05417 gss_OID_set mech_set;
05418 gss_OID tmp_oid;
05419
05420 ctx = GSS_C_NO_CONTEXT;
05421 mech_oid = &krb5_oid_desc;
05422
05423
05424 major_status = gss_indicate_mechs(&minor_status, &mech_set);
05425 if (GSS_ERROR(major_status)) {
05426 kdDebug(7113) << "(" << m_pid << ") gss_indicate_mechs failed: " << gssError(major_status, minor_status) << endl;
05427 } else {
05428 for (i=0; i<mech_set->count && !found; i++) {
05429 tmp_oid = &mech_set->elements[i];
05430 if (tmp_oid->length == spnego_oid_desc.length &&
05431 !memcmp(tmp_oid->elements, spnego_oid_desc.elements, tmp_oid->length)) {
05432 kdDebug(7113) << "(" << m_pid << ") createNegotiateAuth: found SPNEGO mech" << endl;
05433 found = 1;
05434 mech_oid = &spnego_oid_desc;
05435 break;
05436 }
05437 }
05438 gss_release_oid_set(&minor_status, &mech_set);
05439 }
05440
05441
05442 servicename = "HTTP@";
05443 servicename += m_state.hostname.ascii();
05444
05445 input_token.value = (void *)servicename.data();
05446 input_token.length = servicename.length() + 1;
05447
05448 major_status = gss_import_name(&minor_status, &input_token,
05449 GSS_C_NT_HOSTBASED_SERVICE, &server);
05450
05451 input_token.value = NULL;
05452 input_token.length = 0;
05453
05454 if (GSS_ERROR(major_status)) {
05455 kdDebug(7113) << "(" << m_pid << ") gss_import_name failed: " << gssError(major_status, minor_status) << endl;
05456
05457 m_strAuthorization = QString::null;
05458 return QString::null;
05459 }
05460
05461 major_status = gss_init_sec_context(&minor_status, GSS_C_NO_CREDENTIAL,
05462 &ctx, server, mech_oid,
05463 req_flags, GSS_C_INDEFINITE,
05464 GSS_C_NO_CHANNEL_BINDINGS,
05465 GSS_C_NO_BUFFER, NULL, &output_token,
05466 NULL, NULL);
05467
05468
05469 if (GSS_ERROR(major_status) || (output_token.length == 0)) {
05470 kdDebug(7113) << "(" << m_pid << ") gss_init_sec_context failed: " << gssError(major_status, minor_status) << endl;
05471 gss_release_name(&minor_status, &server);
05472 if (ctx != GSS_C_NO_CONTEXT) {
05473 gss_delete_sec_context(&minor_status, &ctx, GSS_C_NO_BUFFER);
05474 ctx = GSS_C_NO_CONTEXT;
05475 }
05476
05477 m_strAuthorization = QString::null;
05478 return QString::null;
05479 }
05480
05481 input.duplicate((const char *)output_token.value, output_token.length);
05482 auth = "Authorization: Negotiate ";
05483 auth += KCodecs::base64Encode( input );
05484 auth += "\r\n";
05485
05486
05487 gss_release_name(&minor_status, &server);
05488 if (ctx != GSS_C_NO_CONTEXT) {
05489 gss_delete_sec_context(&minor_status, &ctx, GSS_C_NO_BUFFER);
05490 ctx = GSS_C_NO_CONTEXT;
05491 }
05492 gss_release_buffer(&minor_status, &output_token);
05493
05494 return auth;
05495 }
05496 #else
05497
05498
05499 QCString HTTPProtocol::gssError( int, int )
05500 {
05501 return "";
05502 }
05503
05504
05505 QString HTTPProtocol::createNegotiateAuth()
05506 {
05507 return QString::null;
05508 }
05509 #endif
05510
05511 QString HTTPProtocol::createNTLMAuth( bool isForProxy )
05512 {
05513 uint len;
05514 QString auth, user, domain, passwd;
05515 QCString strauth;
05516 QByteArray buf;
05517
05518 if ( isForProxy )
05519 {
05520 auth = "Proxy-Connection: Keep-Alive\r\n";
05521 auth += "Proxy-Authorization: NTLM ";
05522 user = m_proxyURL.user();
05523 passwd = m_proxyURL.pass();
05524 strauth = m_strProxyAuthorization.latin1();
05525 len = m_strProxyAuthorization.length();
05526 }
05527 else
05528 {
05529 auth = "Authorization: NTLM ";
05530 user = m_state.user;
05531 passwd = m_state.passwd;
05532 strauth = m_strAuthorization.latin1();
05533 len = m_strAuthorization.length();
05534 }
05535 if ( user.contains('\\') ) {
05536 domain = user.section( '\\', 0, 0);
05537 user = user.section( '\\', 1 );
05538 }
05539
05540 kdDebug(7113) << "(" << m_pid << ") NTLM length: " << len << endl;
05541 if ( user.isEmpty() || passwd.isEmpty() || len < 4 )
05542 return QString::null;
05543
05544 if ( len > 4 )
05545 {
05546
05547 QByteArray challenge;
05548 KCodecs::base64Decode( strauth.right( len - 5 ), challenge );
05549 KNTLM::getAuth( buf, challenge, user, passwd, domain,
05550 KNetwork::KResolver::localHostName(), false, false );
05551 }
05552 else
05553 {
05554 KNTLM::getNegotiate( buf );
05555 }
05556
05557
05558 if ( isForProxy )
05559 m_strProxyAuthorization = "NTLM";
05560 else
05561 m_strAuthorization = "NTLM";
05562
05563 auth += KCodecs::base64Encode( buf );
05564 auth += "\r\n";
05565
05566 return auth;
05567 }
05568
05569 QString HTTPProtocol::createBasicAuth( bool isForProxy )
05570 {
05571 QString auth;
05572 QCString user, passwd;
05573 if ( isForProxy )
05574 {
05575 auth = "Proxy-Authorization: Basic ";
05576 user = m_proxyURL.user().latin1();
05577 passwd = m_proxyURL.pass().latin1();
05578 }
05579 else
05580 {
05581 auth = "Authorization: Basic ";
05582 user = m_state.user.latin1();
05583 passwd = m_state.passwd.latin1();
05584 }
05585
05586 if ( user.isEmpty() )
05587 user = "";
05588 if ( passwd.isEmpty() )
05589 passwd = "";
05590
05591 user += ':';
05592 user += passwd;
05593 auth += KCodecs::base64Encode( user );
05594 auth += "\r\n";
05595
05596 return auth;
05597 }
05598
05599 void HTTPProtocol::calculateResponse( DigestAuthInfo& info, QCString& Response )
05600 {
05601 KMD5 md;
05602 QCString HA1;
05603 QCString HA2;
05604
05605
05606 QCString authStr = info.username;
05607 authStr += ':';
05608 authStr += info.realm;
05609 authStr += ':';
05610 authStr += info.password;
05611 md.update( authStr );
05612
05613 if ( info.algorithm.lower() == "md5-sess" )
05614 {
05615 authStr = md.hexDigest();
05616 authStr += ':';
05617 authStr += info.nonce;
05618 authStr += ':';
05619 authStr += info.cnonce;
05620 md.reset();
05621 md.update( authStr );
05622 }
05623 HA1 = md.hexDigest();
05624
05625 kdDebug(7113) << "(" << m_pid << ") calculateResponse(): A1 => " << HA1 << endl;
05626
05627
05628 authStr = info.method;
05629 authStr += ':';
05630 authStr += m_request.url.encodedPathAndQuery(0, true).latin1();
05631 if ( info.qop == "auth-int" )
05632 {
05633 authStr += ':';
05634 authStr += info.entityBody;
05635 }
05636 md.reset();
05637 md.update( authStr );
05638 HA2 = md.hexDigest();
05639
05640 kdDebug(7113) << "(" << m_pid << ") calculateResponse(): A2 => "
05641 << HA2 << endl;
05642
05643
05644 authStr = HA1;
05645 authStr += ':';
05646 authStr += info.nonce;
05647 authStr += ':';
05648 if ( !info.qop.isEmpty() )
05649 {
05650 authStr += info.nc;
05651 authStr += ':';
05652 authStr += info.cnonce;
05653 authStr += ':';
05654 authStr += info.qop;
05655 authStr += ':';
05656 }
05657 authStr += HA2;
05658 md.reset();
05659 md.update( authStr );
05660 Response = md.hexDigest();
05661
05662 kdDebug(7113) << "(" << m_pid << ") calculateResponse(): Response => "
05663 << Response << endl;
05664 }
05665
05666 QString HTTPProtocol::createDigestAuth ( bool isForProxy )
05667 {
05668 const char *p;
05669
05670 QString auth;
05671 QCString opaque;
05672 QCString Response;
05673
05674 DigestAuthInfo info;
05675
05676 opaque = "";
05677 if ( isForProxy )
05678 {
05679 auth = "Proxy-Authorization: Digest ";
05680 info.username = m_proxyURL.user().latin1();
05681 info.password = m_proxyURL.pass().latin1();
05682 p = m_strProxyAuthorization.latin1();
05683 }
05684 else
05685 {
05686 auth = "Authorization: Digest ";
05687 info.username = m_state.user.latin1();
05688 info.password = m_state.passwd.latin1();
05689 p = m_strAuthorization.latin1();
05690 }
05691 if (!p || !*p)
05692 return QString::null;
05693
05694 p += 6;
05695
05696 if ( info.username.isEmpty() || info.password.isEmpty() || !p )
05697 return QString::null;
05698
05699
05700 info.realm = "";
05701 info.algorithm = "MD5";
05702 info.nonce = "";
05703 info.qop = "";
05704
05705
05706 info.cnonce = KApplication::randomString(16).latin1();
05707
05708
05709 info.nc = "00000001";
05710
05711
05712 switch ( m_request.method )
05713 {
05714 case HTTP_GET:
05715 info.method = "GET";
05716 break;
05717 case HTTP_PUT:
05718 info.method = "PUT";
05719 break;
05720 case HTTP_POST:
05721 info.method = "POST";
05722 break;
05723 case HTTP_HEAD:
05724 info.method = "HEAD";
05725 break;
05726 case HTTP_DELETE:
05727 info.method = "DELETE";
05728 break;
05729 case DAV_PROPFIND:
05730 info.method = "PROPFIND";
05731 break;
05732 case DAV_PROPPATCH:
05733 info.method = "PROPPATCH";
05734 break;
05735 case DAV_MKCOL:
05736 info.method = "MKCOL";
05737 break;
05738 case DAV_COPY:
05739 info.method = "COPY";
05740 break;
05741 case DAV_MOVE:
05742 info.method = "MOVE";
05743 break;
05744 case DAV_LOCK:
05745 info.method = "LOCK";
05746 break;
05747 case DAV_UNLOCK:
05748 info.method = "UNLOCK";
05749 break;
05750 case DAV_SEARCH:
05751 info.method = "SEARCH";
05752 break;
05753 case DAV_SUBSCRIBE:
05754 info.method = "SUBSCRIBE";
05755 break;
05756 case DAV_UNSUBSCRIBE:
05757 info.method = "UNSUBSCRIBE";
05758 break;
05759 case DAV_POLL:
05760 info.method = "POLL";
05761 break;
05762 default:
05763 error( ERR_UNSUPPORTED_ACTION, i18n("Unsupported method: authentication will fail. Please submit a bug report."));
05764 break;
05765 }
05766
05767
05768 while (*p)
05769 {
05770 int i = 0;
05771 while ( (*p == ' ') || (*p == ',') || (*p == '\t')) { p++; }
05772 if (strncasecmp(p, "realm=", 6 )==0)
05773 {
05774 p+=6;
05775 while ( *p == '"' ) p++;
05776 while ( p[i] != '"' ) i++;
05777 info.realm = QCString( p, i+1 );
05778 }
05779 else if (strncasecmp(p, "algorith=", 9)==0)
05780 {
05781 p+=9;
05782 while ( *p == '"' ) p++;
05783 while ( ( p[i] != '"' ) && ( p[i] != ',' ) && ( p[i] != '\0' ) ) i++;
05784 info.algorithm = QCString(p, i+1);
05785 }
05786 else if (strncasecmp(p, "algorithm=", 10)==0)
05787 {
05788 p+=10;
05789 while ( *p == '"' ) p++;
05790 while ( ( p[i] != '"' ) && ( p[i] != ',' ) && ( p[i] != '\0' ) ) i++;
05791 info.algorithm = QCString(p,i+1);
05792 }
05793 else if (strncasecmp(p, "domain=", 7)==0)
05794 {
05795 p+=7;
05796 while ( *p == '"' ) p++;
05797 while ( p[i] != '"' ) i++;
05798 int pos;
05799 int idx = 0;
05800 QCString uri = QCString(p,i+1);
05801 do
05802 {
05803 pos = uri.find( ' ', idx );
05804 if ( pos != -1 )
05805 {
05806 KURL u (m_request.url, uri.mid(idx, pos-idx));
05807 if (u.isValid ())
05808 info.digestURI.append( u.url().latin1() );
05809 }
05810 else
05811 {
05812 KURL u (m_request.url, uri.mid(idx, uri.length()-idx));
05813 if (u.isValid ())
05814 info.digestURI.append( u.url().latin1() );
05815 }
05816 idx = pos+1;
05817 } while ( pos != -1 );
05818 }
05819 else if (strncasecmp(p, "nonce=", 6)==0)
05820 {
05821 p+=6;
05822 while ( *p == '"' ) p++;
05823 while ( p[i] != '"' ) i++;
05824 info.nonce = QCString(p,i+1);
05825 }
05826 else if (strncasecmp(p, "opaque=", 7)==0)
05827 {
05828 p+=7;
05829 while ( *p == '"' ) p++;
05830 while ( p[i] != '"' ) i++;
05831 opaque = QCString(p,i+1);
05832 }
05833 else if (strncasecmp(p, "qop=", 4)==0)
05834 {
05835 p+=4;
05836 while ( *p == '"' ) p++;
05837 while ( p[i] != '"' ) i++;
05838 info.qop = QCString(p,i+1);
05839 }
05840 p+=(i+1);
05841 }
05842
05843 if (info.realm.isEmpty() || info.nonce.isEmpty())
05844 return QString::null;
05845
05846
05847
05848
05849 if (info.digestURI.isEmpty() && (m_responseCode == 401 || m_responseCode == 407))
05850 info.digestURI.append (m_request.url.url().latin1());
05851 else
05852 {
05853
05854
05855 bool send = true;
05856
05857
05858 QString requestPath = m_request.url.directory(false, false);
05859 if (requestPath.isEmpty())
05860 requestPath = "/";
05861
05862 int count = info.digestURI.count();
05863
05864 for (int i = 0; i < count; i++ )
05865 {
05866 KURL u ( info.digestURI.at(i) );
05867
05868 send &= (m_request.url.protocol().lower() == u.protocol().lower());
05869 send &= (m_request.hostname.lower() == u.host().lower());
05870
05871 if (m_request.port > 0 && u.port() > 0)
05872 send &= (m_request.port == u.port());
05873
05874 QString digestPath = u.directory (false, false);
05875 if (digestPath.isEmpty())
05876 digestPath = "/";
05877
05878 send &= (requestPath.startsWith(digestPath));
05879
05880 if (send)
05881 break;
05882 }
05883
05884 kdDebug(7113) << "(" << m_pid << ") createDigestAuth(): passed digest "
05885 "authentication credential test: " << send << endl;
05886
05887 if (!send)
05888 return QString::null;
05889 }
05890
05891 kdDebug(7113) << "(" << m_pid << ") RESULT OF PARSING:" << endl;
05892 kdDebug(7113) << "(" << m_pid << ") algorithm: " << info.algorithm << endl;
05893 kdDebug(7113) << "(" << m_pid << ") realm: " << info.realm << endl;
05894 kdDebug(7113) << "(" << m_pid << ") nonce: " << info.nonce << endl;
05895 kdDebug(7113) << "(" << m_pid << ") opaque: " << opaque << endl;
05896 kdDebug(7113) << "(" << m_pid << ") qop: " << info.qop << endl;
05897
05898
05899 calculateResponse( info, Response );
05900
05901 auth += "username=\"";
05902 auth += info.username;
05903
05904 auth += "\", realm=\"";
05905 auth += info.realm;
05906 auth += "\"";
05907
05908 auth += ", nonce=\"";
05909 auth += info.nonce;
05910
05911 auth += "\", uri=\"";
05912 auth += m_request.url.encodedPathAndQuery(0, true);
05913
05914 auth += "\", algorithm=\"";
05915 auth += info.algorithm;
05916 auth +="\"";
05917
05918 if ( !info.qop.isEmpty() )
05919 {
05920 auth += ", qop=\"";
05921 auth += info.qop;
05922 auth += "\", cnonce=\"";
05923 auth += info.cnonce;
05924 auth += "\", nc=";
05925 auth += info.nc;
05926 }
05927
05928 auth += ", response=\"";
05929 auth += Response;
05930 if ( !opaque.isEmpty() )
05931 {
05932 auth += "\", opaque=\"";
05933 auth += opaque;
05934 }
05935 auth += "\"\r\n";
05936
05937 return auth;
05938 }
05939
05940 QString HTTPProtocol::proxyAuthenticationHeader()
05941 {
05942 QString header;
05943
05944
05945
05946
05947 if ( m_strProxyRealm.isEmpty() )
05948 {
05949 AuthInfo info;
05950 info.url = m_proxyURL;
05951 info.username = m_proxyURL.user();
05952 info.password = m_proxyURL.pass();
05953 info.verifyPath = true;
05954
05955
05956
05957
05958 if ( !info.username.isNull() && !info.password.isNull() )
05959 {
05960 if( m_strProxyAuthorization.isEmpty() )
05961 ProxyAuthentication = AUTH_None;
05962 else if( m_strProxyAuthorization.startsWith("Basic") )
05963 ProxyAuthentication = AUTH_Basic;
05964 else if( m_strProxyAuthorization.startsWith("NTLM") )
05965 ProxyAuthentication = AUTH_NTLM;
05966 else
05967 ProxyAuthentication = AUTH_Digest;
05968 }
05969 else
05970 {
05971 if ( checkCachedAuthentication(info) && !info.digestInfo.isEmpty() )
05972 {
05973 m_proxyURL.setUser( info.username );
05974 m_proxyURL.setPass( info.password );
05975 m_strProxyRealm = info.realmValue;
05976 m_strProxyAuthorization = info.digestInfo;
05977 if( m_strProxyAuthorization.startsWith("Basic") )
05978 ProxyAuthentication = AUTH_Basic;
05979 else if( m_strProxyAuthorization.startsWith("NTLM") )
05980 ProxyAuthentication = AUTH_NTLM;
05981 else
05982 ProxyAuthentication = AUTH_Digest;
05983 }
05984 else
05985 {
05986 ProxyAuthentication = AUTH_None;
05987 }
05988 }
05989 }
05990
05991
05992 if ( ProxyAuthentication != AUTH_None )
05993 {
05994 kdDebug(7113) << "(" << m_pid << ") Using Proxy Authentication: " << endl;
05995 kdDebug(7113) << "(" << m_pid << ") HOST= " << m_proxyURL.host() << endl;
05996 kdDebug(7113) << "(" << m_pid << ") PORT= " << m_proxyURL.port() << endl;
05997 kdDebug(7113) << "(" << m_pid << ") USER= " << m_proxyURL.user() << endl;
05998 kdDebug(7113) << "(" << m_pid << ") PASSWORD= [protected]" << endl;
05999 kdDebug(7113) << "(" << m_pid << ") REALM= " << m_strProxyRealm << endl;
06000 kdDebug(7113) << "(" << m_pid << ") EXTRA= " << m_strProxyAuthorization << endl;
06001 }
06002
06003 switch ( ProxyAuthentication )
06004 {
06005 case AUTH_Basic:
06006 header += createBasicAuth( true );
06007 break;
06008 case AUTH_Digest:
06009 header += createDigestAuth( true );
06010 break;
06011 case AUTH_NTLM:
06012 if ( m_bFirstRequest ) header += createNTLMAuth( true );
06013 break;
06014 case AUTH_None:
06015 default:
06016 break;
06017 }
06018
06019 return header;
06020 }
06021
06022 #include "http.moc"