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