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