diff options
Diffstat (limited to 'kioslave/http')
45 files changed, 0 insertions, 15873 deletions
diff --git a/kioslave/http/CMakeLists.txt b/kioslave/http/CMakeLists.txt deleted file mode 100644 index c093df483..000000000 --- a/kioslave/http/CMakeLists.txt +++ /dev/null @@ -1,69 +0,0 @@ -################################################# -# -# (C) 2010 Serghei Amelian -# serghei (DOT) amelian (AT) gmail.com -# -# Improvements and feedback are welcome -# -# This file is released under GPL >= 2 -# -################################################# - -add_subdirectory( kcookiejar ) - -include_directories( - ${TQT_INCLUDE_DIRS} - ${CMAKE_CURRENT_BINARY_DIR} - ${CMAKE_BINARY_DIR} - ${CMAKE_BINARY_DIR}/tdecore - ${CMAKE_SOURCE_DIR}/dcop - ${CMAKE_SOURCE_DIR}/tdecore - ${CMAKE_SOURCE_DIR}/tdecore/network - ${CMAKE_SOURCE_DIR}/interfaces - ${CMAKE_SOURCE_DIR}/kio - ${CMAKE_SOURCE_DIR}/kio/kio - ${CMAKE_SOURCE_DIR}/kio/httpfilter -) - -link_directories( - ${TQT_LIBRARY_DIRS} -) - - -##### other data ################################ - -install( FILES - http_cache_cleaner.desktop http.protocol https.protocol - webdav.protocol webdavs.protocol - DESTINATION ${SERVICES_INSTALL_DIR} ) - - -##### kio_http_cache_cleaner #################### - -set( target kio_http_cache_cleaner ) - -set( ${target}_SRCS - http_cache_cleaner.cpp -) - -tde_add_tdeinit_executable( ${target} AUTOMOC - SOURCES ${${target}_SRCS} - LINK kio-shared -) - - -##### kio_http ################################## - -# FIXME GSSAPI support is not handled yet - -set( target kio_http ) - -set( ${target}_SRCS - http.cc -) - -tde_add_kpart( ${target} AUTOMOC - SOURCES ${${target}_SRCS} - LINK httpfilter-static tdentlm-shared kio-shared - DESTINATION ${PLUGIN_INSTALL_DIR} -) diff --git a/kioslave/http/Makefile.am b/kioslave/http/Makefile.am deleted file mode 100644 index 5946fc9f8..000000000 --- a/kioslave/http/Makefile.am +++ /dev/null @@ -1,31 +0,0 @@ -# $Id$ -# Makefile.am of tdebase/kioslave/http - -SUBDIRS = kcookiejar - -INCLUDES= -I$(top_srcdir)/interfaces -I$(top_srcdir)/kio/httpfilter -I$(top_srcdir)/tdecore/network $(all_includes) $(GSSAPI_INCS) -AM_LDFLAGS = $(all_libraries) $(GSSAPI_RPATH) - -####### Files - -bin_PROGRAMS= -lib_LTLIBRARIES= -tdeinit_LTLIBRARIES = kio_http_cache_cleaner.la -kde_module_LTLIBRARIES = kio_http.la - -kio_http_la_SOURCES = http.cc -kio_http_la_METASOURCES = AUTO -kio_http_la_LIBADD = $(LIB_KIO) $(top_builddir)/kio/httpfilter/libhttpfilter.la $(LIB_QT) $(LIB_TDECORE) $(LIBZ) $(top_builddir)/dcop/libDCOP.la $(top_builddir)/kio/misc/tdentlm/libtdentlm.la -kio_http_la_LDFLAGS = $(all_libraries) $(GSSAPI_RPATH) -module $(KDE_PLUGIN) $(GSSAPI_LIBS) - -kio_http_cache_cleaner_la_SOURCES = http_cache_cleaner.cpp -kio_http_cache_cleaner_la_LIBADD = $(LIB_KIO) $(LIB_QT) $(LIB_TDECORE) $(top_builddir)/dcop/libDCOP.la -kio_http_cache_cleaner_la_LDFLAGS = -module -avoid-version - -noinst_HEADERS = http.h - -kdelnkdir = $(kde_servicesdir) -kdelnk_DATA = http_cache_cleaner.desktop http.protocol https.protocol \ - webdav.protocol webdavs.protocol - -include $(top_srcdir)/admin/Doxyfile.am diff --git a/kioslave/http/README.http_cache_cleaner b/kioslave/http/README.http_cache_cleaner deleted file mode 100644 index 7714bfba6..000000000 --- a/kioslave/http/README.http_cache_cleaner +++ /dev/null @@ -1,20 +0,0 @@ -khttpcache README -================= - -khttpcache checks the HTTP Cache of a user -and throws out expired entries. - -TODO: - -* Skip entries which end in .new and are younger than -30 minutes / delte entries which end in .new and are -older than 30 minutes. - -* Let kio_http fill in expire dates other than 0. - -DONE: - -* Start khttpcache from kio_http if the file "cleaned" -is older than 30(?) minutes. - -* Accept command line parameteres diff --git a/kioslave/http/README.webdav b/kioslave/http/README.webdav deleted file mode 100644 index c7ee900bb..000000000 --- a/kioslave/http/README.webdav +++ /dev/null @@ -1,184 +0,0 @@ -This document describes how to add support for extended webdav features (locking, -properties etc.) to your webdav-aware application. -Author: Hamish Rodda, rodda@kde.org -Version: 0.3 - -Compatable with (tested on): -Apache + mod_dav version 1 and 2 -Zope -Silverstream webdav server - -Applications supporting extended webdav features - (include name and contact email, in case the interface has to change): -[none currently] - -Much of the info here is elaborated by rfc #2518; the rest can be understood by reading -davPropStat() in http.cc, specifically the setMetaData() calls. - -Extended information is transferred via kio's metadata system... - -=== MISCELLANEOUS === -Display Names (names suitable for presentation to the user) are passed as the metadata -element davDisplayName. - -Source template locations (href, usually an absolute URL w/o host info) -are passed as element davSource. - -Content languages are passed as element davContentLanguage. - -Extra webdav headers are passed as metadata element davHeader - -For doing a webdav SEARCH, use listDir() and set the metadata element -davSearchQuery to the search query. The root element of this query should be like -<d:basicsearch> or <d:sql>. - -For doing a generic webdav action, call a special request, with -the following data: -int, value 7 (WEBDAV generic) -KURL url -int method - the HTTP/WEBDAV method to call -Send the xml request and receive the xml response in the usual way. - -=== CREATING A LOCK === -To create a lock, call a special request, with the following data: - -int, value 5 (LOCK request) -KURL url - the location of the resource to lock -QString scope - the scope of the lock, currently "exclusive" or "shared" -QString type - the type of the lock, currently only "write" -QString owner (optional) - owner contact details (url) - -Additionally, the lock timeout requested from the server may be altered from the default -of Infinity by setting the metadata "davTimeout" to the number of seconds, or 0 for -infinity. - -=== REMOVING A LOCK === -To remove a lock, call a special request, with the following data: - -int, value 5 (LOCK request) -KURL url - the location of the resource to unlock - -metadata required: -davLockToken - the lock token to remove - -and, of course, any other lock information as below required for the operation -to suceed. - -=== SETTING LOCK INFORMATION === -To provide lock data so that urls can be accessed, you need to pass the following metadata: -davLockCount: (uint) the number of locks you are providing -davLockToken%1: (string) the token -(optional) davLockURL%1: (string) the absolute URL specified by the lock token -(optional) davLockNot%1: (value ignored) the presence of this meta key negates the lock - (ie. requires the lock to not be set) - -Example data: -============= -davLockCount: 2 -davLockToken1: opaquelocktoken:f81de2ad-7f3d-a1b2-4f3c-00a0c91a9d76A -davLockNot1: (value ignored) -davLockToken2: opaquelocktoken:f81de2ad-7f3d-a1b2-4f3c-00a0c91a9d76B -davLockURL2: http://www.foo.bar/container2/ - - -=== RECEIVING LOCK INFORMATION === -For each file, stat/listdir always returns two pieces of information: - -davSupportedLockCount: (uint) the number of lock types discovered for this resource. -davLockCount: (uint) the number of locks discovered on this resource. - -for each count, additional information is returned: - -=================== -Information about the locks on a resource: - -davLockCount: %1 (the number of locks to be described, as below) -*** Required items *** -davLockScope%1 - The scope of this lock. May be exclusive, shared, or a custom type. -davLockType%1 - The type of the lock. -davLockDepth%1 - The depth to which this lock applies - (0=only this resource, 1=this collection, infinity=applies recursively) - -*** Optional items *** -davLockOwner%1 - The owner of this lock. -davLockTimeout%1 - The timeout parameter. Possibilities: see section 9.8, rfc #2518 -davLockToken%1 - The token which iden - -=================== -Information about the lock types supported by the resource - -davSupportedLockCount: %1 (the number of locks types to be described, as below) - -davSupportedLockScope%1 - The scope of the lock (exclusive, shared, other custom type) -davSupportedLockType%1 - The type of the lock (webdav 1.0 supports only the "write" type) -=================== - -Example Metadata which would be supplied if the response was the example XML below: - -davSupportedLockCount: 2 -davLockCount: 2 -davLockScope1: exclusive -davLockType1: write -davLockDepth1: 0 -davLockOwner1: Jane Smith -davLockTimeout1: infinite -davLockToken1: opaquelocktoken:f81de2ad-7f3d-a1b2-4f3c-00a0c91a9d76A -davLockScope2: shared -davLockType2: write -davLockDepth2: 1 -davLockOwner2: John Doe -davLockToken2: opaquelocktoken:f81de2ad-7f3d-a1b2-4f3c-00a0c91a9d76B -davSupportedLockScope1: exclusive -davSupportedLockType1: write -davSupportedLockScope2: shared -davSupportedLockType2: write - - -(example XML:) - - <?xml version="1.0" encoding="utf-8" ?> - <D:multistatus xmlns:D='DAV:'> - <D:response> - <D:href>http://www.foo.bar/container/</D:href> - <D:propstat> - <D:prop> - <D:lockdiscovery> - <D:activelock> - <D:locktype><D:write/></D:locktype> - <D:lockscope><D:exclusive/></D:lockscope> - <D:depth>0</D:depth> - <D:owner>Jane Smith</D:owner> - <D:timeout>Infinite</D:timeout> - <D:locktoken> - <D:href> - opaquelocktoken:f81de2ad-7f3d-a1b2-4f3c-00a0c91a9d76A - </D:href> - </D:locktoken> - </D:activelock> - <D:activelock> - <D:locktype><D:write/></D:locktype> - <D:lockscope><D:shared/></D:lockscope> - <D:depth>1</D:depth> - <D:owner>John Doe</D:owner> - <D:locktoken> - <D:href> - opaquelocktoken:f81de2ad-7f3d-a1b2-4f3c-00a0c91a9d76B - </D:href> - </D:locktoken> - </D:activelock> - </D:lockdiscovery> - <D:supportedlock> - <D:lockentry> - <D:lockscope><D:exclusive/></D:lockscope> - <D:locktype><D:write/></D:locktype> - </D:lockentry> - <D:lockentry> - <D:lockscope><D:shared/></D:lockscope> - <D:locktype><D:write/></D:locktype> - </D:lockentry> - </D:supportedlock> - </D:prop> - <D:status>HTTP/1.1 200 OK</D:status> - </D:propstat> - </D:response> - </D:multistatus> diff --git a/kioslave/http/THOUGHTS b/kioslave/http/THOUGHTS deleted file mode 100644 index 9715b5c2f..000000000 --- a/kioslave/http/THOUGHTS +++ /dev/null @@ -1,28 +0,0 @@ -Here's a few ideas for those with blistered hands and nothing better to -do: - -SSL certificate verification: -We do establish SSL connections, but we never actually verify a -certificate! - -HTTP/1.1 Persistant Connections: -The header often specifies the timeout value used for connections. -Close the connection ourselves when the timeout has expired. That way -we don't loose time sending stuff to an already closed connection. - -Rating(s) support. http://www.w3.org/PICS -This might involve an external program to parse the labels, and something -to configure access. - -WebDAV support. MSIE5 calls it web folders support, and a similar -approach would probably be a good idea. Perhaps with an exists() -function.. one could tell if an http url was part of a WebDAV collection.. -and this could be used for some kind of integration with kfile... to -provide seamless integration. Uhm, also, this might entail an external -program (xml parser and such). - -"Friendly" error messages. How often have you seen a useless 404 message? -Again something I first notied in MSIE5, and that would be some sort of -translation of what an error really means. Yes this would have to be -i18n'd and easily turned off. But this could also be extended to all the -slaves (ftp, pop3, etc, etc). diff --git a/kioslave/http/TODO b/kioslave/http/TODO deleted file mode 100644 index 9dbf60a3e..000000000 --- a/kioslave/http/TODO +++ /dev/null @@ -1,45 +0,0 @@ -The following is a list of items that are currently missing or partially implemented -in kio_http: - -- HTTP/1.1 Persistant Connections: -The header often specifies the timeout value used for connections. -Close the connection ourselves when the timeout has expired. That way -we don't loose time sending stuff to an already closed connection. - -- HTTP/1.1 Pipelining support -This more of an optimization of the http io-slave that is intended to make it -faster while using as few resources as possible. Work on this is currently -being done to add this support for KDE 3.x version. - -- WebDAV support: -The majority of the work for this is done, see README.webdav. GUI integration -into konqueror as a konqueror part would be nice, to add GUI support for -features such as locking. - -- Rating(s) support. http://www.w3.org/PICS: -This might involve an external program to parse the labels, and something to -configure access accordingly. There is only some basic things that need to be -added to kio_http to support this. The majority of the work has to be done at the -application level. A tdehtml plugin in tdeaddons to do this might be a nice idea. - -- P3P support: -This can also be implemented as a plugin to konqueror and does -not need any speical support in HTTP except perhaps sending a -flag that indicates that the web page provides some P3P information. -This is something that can be added as a plugin to tdeaddons. - - -Things that do not require programming -============================ - -- "Friendly" error message html page. -We currently support the sending of error messages, but this is only done if the server -sends back nicely formatted error messages. We do not have fall back HTML pages that -describe these error messages in a non-technical manner! This of course also means that -we will certainly need to have these files translated. - - -Maintainers -Waldo Bastian <bastian@kde.org> -Dawit Alemayehu <adawit@kde.org> -WebDAV support: Hamish Rodda <rodda@kde.org> diff --git a/kioslave/http/configure.in.bot b/kioslave/http/configure.in.bot deleted file mode 100644 index 56d051424..000000000 --- a/kioslave/http/configure.in.bot +++ /dev/null @@ -1,10 +0,0 @@ -dnl put here things which have to be done as very last part of configure - -if test "x$with_gssapi" = xNOTFOUND; then - echo "" - echo "You're missing GSSAPI/Kerberos." - echo "KDE can use GSSAPI/Kerberos to authenticate on certain secure websites." - echo "GSSAPI/Kerberos authentication is typically used on intranets." - echo "" - all_tests=bad -fi diff --git a/kioslave/http/configure.in.in b/kioslave/http/configure.in.in deleted file mode 100644 index a7d1ca7cf..000000000 --- a/kioslave/http/configure.in.in +++ /dev/null @@ -1,110 +0,0 @@ -AC_MSG_CHECKING(whether to enable GSSAPI support) -AC_ARG_WITH(gssapi, -[ --with-gssapi=PATH Set path for GSSAPI files [default=check]], -[ case "$withval" in - yes) - with_gssapi=CHECK - ;; - esac ], -[ with_gssapi=CHECK ] -)dnl - -if test "x$with_gssapi" = "xCHECK" ; then - with_gssapi=NOTFOUND - KDE_FIND_PATH(krb5-config, KRB5_CONFIG, [${prefix}/bin ${exec_prefix}/bin /usr/bin /usr/local/bin /opt/local/bin /usr/lib/mit/bin], [ - AC_MSG_WARN([Could not find krb5-config]) - ]) - - if test -n "$KRB5_CONFIG"; then - kde_save_cflags="$CFLAGS" - unset CFLAGS - GSSAPI_INCS="`$KRB5_CONFIG --cflags gssapi`" - GSSAPI_LIBS="`$KRB5_CONFIG --libs gssapi`" - CFLAGS="$kde_save_cflags" - if test "$USE_RPATH" = yes; then - for args in $GSSAPI_LIBS; do - case $args in - -L/usr/lib) ;; - -L*) - GSSAPI_RPATH="$GSSAPI_RPATH $args" - ;; - esac - done - GSSAPI_RPATH=`echo $GSSAPI_RPATH | sed -e "s/-L/-R/g"` - fi - gssapi_incdir="$GSSAPI_INCS" - gssapi_libdir="$GSSAPI_LIBS" - with_gssapi=FOUND - if $KRB5_CONFIG --vendor | grep "Massachusetts" > /dev/null; then - gssapi_flavor=MIT - else - gssapi_flavor=HEIMDAL - fi - else - search_incs="$kde_includes /usr/include /usr/local/include" - AC_FIND_FILE(gssapi.h, $search_incs, gssapi_incdir) - if test -r $gssapi_incdir/gssapi.h ; then - test "x$gssapi_incdir" != "x/usr/include" && GSSAPI_INCS="-I$gssapi_incdir" - with_gssapi=FOUND - fi - if test $with_gssapi = FOUND ; then - with_gssapi=NOTFOUND - for ext in la so sl a dylib ; do - AC_FIND_FILE(libgssapi.$ext, $kde_libraries /usr/lib /usr/local/lib, - gssapi_libdir) - if test -r $gssapi_libdir/libgssapi.$ext ; then - if test "x$gssapi_libdir" != "x/usr/lib" ; then - GSSAPI_LIBS="-L$gssapi_libdir " - test "$USE_RPATH" = yes && GSSAPI_RPATH="-R $gssapi_libdir" - fi - GSSAPI_LIBS="${GSSAPI_LIBS} -lgssapi -lkrb5 -lasn1 -lcrypto -lroken -lcrypt ${LIBRESOLV}" - with_gssapi=FOUND - gssapi_flavor=HEIMDAL - break - fi - done - fi - fi -fi - -case "$with_gssapi" in -no) AC_MSG_RESULT(no) ;; -framework) - GSSAPI_LIBS="-Xlinker -framework -Xlinker Kerberos" - AC_DEFINE_UNQUOTED(HAVE_LIBGSSAPI, 1, [Define if you have GSSAPI libraries]) - GSSAPI_SUBDIR="gssapi" - AC_MSG_RESULT(Apple framework) - ;; -NOTFOUND) AC_MSG_RESULT(searched but not found) ;; -*) - if test "x$with_gssapi" = "xFOUND" ; then - msg="incs=$gssapi_incdir libs=$gssapi_libdir" - else - msg="$with_gssapi" - GSSAPI_ROOT="$with_gssapi" - if test "x$GSSAPI_ROOT" != "x/usr" ; then - GSSAPI_INCS="-I${GSSAPI_ROOT}/include" - GSSAPI_LIBS="-L${GSSAPI_ROOT}/lib " - if test "$USE_RPATH" = "yes" ; then - GSSAPI_RPATH="-R ${GSSAPI_ROOT}/lib" - fi - fi - if test -f ${GSSAPI_ROOT}/include/gssapi/gssapi.h ; then - gssapi_flavor=MIT - GSSAPI_LIBS="${GSSAPI_LIBS}-lgssapi_krb5 -lkrb5 -lk5crypto -lcom_err ${LIBRESOLV}" - else - gssapi_flavor=HEIMDAL - GSSAPI_LIBS="${GSSAPI_LIBS}-lgssapi -lkrb5 -lasn1 -lcrypto -lroken -lcrypt ${LIBRESOLV}" - fi - fi - if test "x$gssapi_flavor" = "xMIT" ; then - AC_DEFINE_UNQUOTED(GSSAPI_MIT, 1, [Define if you have the MIT Kerberos libraries]) - fi - AC_DEFINE_UNQUOTED(HAVE_LIBGSSAPI, 1, [Define if you have GSSAPI libraries]) - AC_MSG_RESULT($msg) - ;; -esac - -AC_SUBST(GSSAPI_INCS) -AC_SUBST(GSSAPI_LIBS) -AC_SUBST(GSSAPI_RPATH) diff --git a/kioslave/http/http.cc b/kioslave/http/http.cc deleted file mode 100644 index e1eefa595..000000000 --- a/kioslave/http/http.cc +++ /dev/null @@ -1,6108 +0,0 @@ -/* - Copyright (C) 2000-2003 Waldo Bastian <bastian@kde.org> - Copyright (C) 2000-2002 George Staikos <staikos@kde.org> - Copyright (C) 2000-2002 Dawit Alemayehu <adawit@kde.org> - Copyright (C) 2001,2002 Hamish Rodda <rodda@kde.org> - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License (LGPL) as published by the Free Software Foundation; - either version 2 of the License, or (at your option) any later - version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -#include <config.h> - -#include <errno.h> -#include <fcntl.h> -#include <utime.h> -#include <stdlib.h> -#include <signal.h> -#include <sys/stat.h> -#include <sys/socket.h> -#include <netinet/in.h> // Required for AIX -#include <netinet/tcp.h> -#include <unistd.h> // must be explicitly included for MacOSX - -/* -#include <netdb.h> -#include <sys/time.h> -#include <sys/wait.h> -*/ - -#include <tqdom.h> -#include <tqfile.h> -#include <tqregexp.h> -#include <tqdatetime.h> -#include <tqstringlist.h> -#include <tqurl.h> - -#include <kurl.h> -#include <kidna.h> -#include <ksocks.h> -#include <kdebug.h> -#include <klocale.h> -#include <kconfig.h> -#include <kextsock.h> -#include <kservice.h> -#include <krfcdate.h> -#include <kmdcodec.h> -#include <kinstance.h> -#include <kresolver.h> -#include <kmimemagic.h> -#include <dcopclient.h> -#include <kdatastream.h> -#include <kapplication.h> -#include <kstandarddirs.h> -#include <kstringhandler.h> -#include <kremoteencoding.h> - -#include "kio/ioslave_defaults.h" -#include "kio/http_slave_defaults.h" - -#include "httpfilter.h" -#include "http.h" - -#ifdef HAVE_LIBGSSAPI -#ifdef GSSAPI_MIT -#include <gssapi/gssapi.h> -#else -#include <gssapi.h> -#endif /* GSSAPI_MIT */ - -// Catch uncompatible crap (BR86019) -#if defined(GSS_RFC_COMPLIANT_OIDS) && (GSS_RFC_COMPLIANT_OIDS == 0) -#include <gssapi/gssapi_generic.h> -#define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name -#endif - -#endif /* HAVE_LIBGSSAPI */ - -#include <misc/tdentlm/tdentlm.h> - -using namespace TDEIO; - -extern "C" { - KDE_EXPORT int kdemain(int argc, char **argv); -} - -int kdemain( int argc, char **argv ) -{ - KLocale::setMainCatalogue("tdelibs"); - TDEInstance instance( "kio_http" ); - ( void ) TDEGlobal::locale(); - - if (argc != 4) - { - fprintf(stderr, "Usage: kio_http protocol domain-socket1 domain-socket2\n"); - exit(-1); - } - - HTTPProtocol slave(argv[1], argv[2], argv[3]); - slave.dispatchLoop(); - return 0; -} - -/*********************************** Generic utility functions ********************/ - -static char * trimLead (char *orig_string) -{ - while (*orig_string == ' ') - orig_string++; - return orig_string; -} - -static bool isCrossDomainRequest( const TQString& fqdn, const TQString& originURL ) -{ - if (originURL == "true") // Backwards compatibility - return true; - - KURL url ( originURL ); - - // Document Origin domain - TQString a = url.host(); - - // Current request domain - TQString b = fqdn; - - if (a == b) - return false; - - TQStringList l1 = TQStringList::split('.', a); - TQStringList l2 = TQStringList::split('.', b); - - while(l1.count() > l2.count()) - l1.pop_front(); - - while(l2.count() > l1.count()) - l2.pop_front(); - - while(l2.count() >= 2) - { - if (l1 == l2) - return false; - - l1.pop_front(); - l2.pop_front(); - } - - return true; -} - -/* - Eliminates any custom header that could potentically alter the request -*/ -static TQString sanitizeCustomHTTPHeader(const TQString& _header) -{ - TQString sanitizedHeaders; - TQStringList headers = TQStringList::split(TQRegExp("[\r\n]"), _header); - - for(TQStringList::Iterator it = headers.begin(); it != headers.end(); ++it) - { - TQString header = (*it).lower(); - // Do not allow Request line to be specified and ignore - // the other HTTP headers. - if (header.find(':') == -1 || - header.startsWith("host") || - header.startsWith("via")) - continue; - - sanitizedHeaders += (*it); - sanitizedHeaders += "\r\n"; - } - - return sanitizedHeaders.stripWhiteSpace(); -} - - -#define NO_SIZE ((TDEIO::filesize_t) -1) - -#ifdef HAVE_STRTOLL -#define STRTOLL strtoll -#else -#define STRTOLL strtol -#endif - - -/************************************** HTTPProtocol **********************************************/ - -HTTPProtocol::HTTPProtocol( const TQCString &protocol, const TQCString &pool, - const TQCString &app ) - :TCPSlaveBase( 0, protocol , pool, app, - (protocol == "https" || protocol == "webdavs") ) -{ - m_requestQueue.setAutoDelete(true); - - m_bBusy = false; - m_bFirstRequest = false; - m_bProxyAuthValid = false; - - m_iSize = NO_SIZE; - m_lineBufUnget = 0; - - m_protocol = protocol; - - m_maxCacheAge = DEFAULT_MAX_CACHE_AGE; - m_maxCacheSize = DEFAULT_MAX_CACHE_SIZE / 2; - m_remoteConnTimeout = DEFAULT_CONNECT_TIMEOUT; - m_remoteRespTimeout = DEFAULT_RESPONSE_TIMEOUT; - m_proxyConnTimeout = DEFAULT_PROXY_CONNECT_TIMEOUT; - - m_pid = getpid(); - - setMultipleAuthCaching( true ); - reparseConfiguration(); -} - -HTTPProtocol::~HTTPProtocol() -{ - httpClose(false); -} - -void HTTPProtocol::reparseConfiguration() -{ - kdDebug(7113) << "(" << m_pid << ") HTTPProtocol::reparseConfiguration" << endl; - - m_strProxyRealm = TQString::null; - m_strProxyAuthorization = TQString::null; - ProxyAuthentication = AUTH_None; - m_bUseProxy = false; - - if (m_protocol == "https" || m_protocol == "webdavs") - m_iDefaultPort = DEFAULT_HTTPS_PORT; - else if (m_protocol == "ftp") - m_iDefaultPort = DEFAULT_FTP_PORT; - else - m_iDefaultPort = DEFAULT_HTTP_PORT; -} - -void HTTPProtocol::resetConnectionSettings() -{ - m_bEOF = false; - m_bError = false; - m_lineCount = 0; - m_iWWWAuthCount = 0; - m_lineCountUnget = 0; - m_iProxyAuthCount = 0; - -} - -void HTTPProtocol::resetResponseSettings() -{ - m_bRedirect = false; - m_redirectLocation = KURL(); - m_bChunked = false; - m_iSize = NO_SIZE; - - m_responseHeader.clear(); - m_qContentEncodings.clear(); - m_qTransferEncodings.clear(); - m_sContentMD5 = TQString::null; - m_strMimeType = TQString::null; - - setMetaData("request-id", m_request.id); -} - -void HTTPProtocol::resetSessionSettings() -{ - // Do not reset the URL on redirection if the proxy - // URL, username or password has not changed! - KURL proxy ( config()->readEntry("UseProxy") ); - - if ( m_strProxyRealm.isEmpty() || !proxy.isValid() || - m_proxyURL.host() != proxy.host() || - (!proxy.user().isNull() && proxy.user() != m_proxyURL.user()) || - (!proxy.pass().isNull() && proxy.pass() != m_proxyURL.pass()) ) - { - m_bProxyAuthValid = false; - m_proxyURL = proxy; - m_bUseProxy = m_proxyURL.isValid(); - - kdDebug(7113) << "(" << m_pid << ") Using proxy: " << m_bUseProxy << - " URL: " << m_proxyURL.url() << - " Realm: " << m_strProxyRealm << endl; - } - - m_bPersistentProxyConnection = config()->readBoolEntry("PersistentProxyConnection", false); - kdDebug(7113) << "(" << m_pid << ") Enable Persistent Proxy Connection: " - << m_bPersistentProxyConnection << endl; - - m_request.bUseCookiejar = config()->readBoolEntry("Cookies"); - m_request.bUseCache = config()->readBoolEntry("UseCache", true); - m_request.bErrorPage = config()->readBoolEntry("errorPage", true); - m_request.bNoAuth = config()->readBoolEntry("no-auth"); - m_strCacheDir = config()->readPathEntry("CacheDir"); - m_maxCacheAge = config()->readNumEntry("MaxCacheAge", DEFAULT_MAX_CACHE_AGE); - m_request.window = config()->readEntry("window-id"); - - kdDebug(7113) << "(" << m_pid << ") Window Id = " << m_request.window << endl; - kdDebug(7113) << "(" << m_pid << ") ssl_was_in_use = " - << metaData ("ssl_was_in_use") << endl; - - m_request.referrer = TQString::null; - if ( config()->readBoolEntry("SendReferrer", true) && - (m_protocol == "https" || m_protocol == "webdavs" || - metaData ("ssl_was_in_use") != "TRUE" ) ) - { - KURL referrerURL ( metaData("referrer") ); - if (referrerURL.isValid()) - { - // Sanitize - TQString protocol = referrerURL.protocol(); - if (protocol.startsWith("webdav")) - { - protocol.replace(0, 6, "http"); - referrerURL.setProtocol(protocol); - } - - if (protocol.startsWith("http")) - { - referrerURL.setRef(TQString::null); - referrerURL.setUser(TQString::null); - referrerURL.setPass(TQString::null); - m_request.referrer = referrerURL.url(); - } - } - } - - if ( config()->readBoolEntry("SendLanguageSettings", true) ) - { - m_request.charsets = config()->readEntry( "Charsets", "iso-8859-1" ); - - if ( !m_request.charsets.isEmpty() ) - m_request.charsets += DEFAULT_PARTIAL_CHARSET_HEADER; - - m_request.languages = config()->readEntry( "Languages", DEFAULT_LANGUAGE_HEADER ); - } - else - { - m_request.charsets = TQString::null; - m_request.languages = TQString::null; - } - - // Adjust the offset value based on the "resume" meta-data. - TQString resumeOffset = metaData("resume"); - if ( !resumeOffset.isEmpty() ) - m_request.offset = resumeOffset.toInt(); // TODO: Convert to 64 bit - else - m_request.offset = 0; - - m_request.disablePassDlg = config()->readBoolEntry("DisablePassDlg", false); - m_request.allowCompressedPage = config()->readBoolEntry("AllowCompressedPage", true); - m_request.id = metaData("request-id"); - - // Store user agent for this host. - if ( config()->readBoolEntry("SendUserAgent", true) ) - m_request.userAgent = metaData("UserAgent"); - else - m_request.userAgent = TQString::null; - - // Deal with cache cleaning. - // TODO: Find a smarter way to deal with cleaning the - // cache ? - if ( m_request.bUseCache ) - cleanCache(); - - // Deal with HTTP tunneling - if ( m_bIsSSL && m_bUseProxy && m_proxyURL.protocol() != "https" && - m_proxyURL.protocol() != "webdavs") - { - m_bNeedTunnel = true; - setRealHost( m_request.hostname ); - kdDebug(7113) << "(" << m_pid << ") SSL tunnel: Setting real hostname to: " - << m_request.hostname << endl; - } - else - { - m_bNeedTunnel = false; - setRealHost( TQString::null); - } - - m_responseCode = 0; - m_prevResponseCode = 0; - - m_strRealm = TQString::null; - m_strAuthorization = TQString::null; - Authentication = AUTH_None; - - // Obtain the proxy and remote server timeout values - m_proxyConnTimeout = proxyConnectTimeout(); - m_remoteConnTimeout = connectTimeout(); - m_remoteRespTimeout = responseTimeout(); - - // Set the SSL meta-data here... - setSSLMetaData(); - - // Bounce back the actual referrer sent - setMetaData("referrer", m_request.referrer); - - // Follow HTTP/1.1 spec and enable keep-alive by default - // unless the remote side tells us otherwise or we determine - // the persistent link has been terminated by the remote end. - m_bKeepAlive = true; - m_keepAliveTimeout = 0; - m_bUnauthorized = false; - - // A single request can require multiple exchanges with the remote - // server due to authentication challenges or SSL tunneling. - // m_bFirstRequest is a flag that indicates whether we are - // still processing the first request. This is important because we - // should not force a close of a keep-alive connection in the middle - // of the first request. - // m_bFirstRequest is set to "true" whenever a new connection is - // made in httpOpenConnection() - m_bFirstRequest = false; -} - -void HTTPProtocol::setHost( const TQString& host, int port, - const TQString& user, const TQString& pass ) -{ - // Reset the webdav-capable flags for this host - if ( m_request.hostname != host ) - m_davHostOk = m_davHostUnsupported = false; - - // is it an IPv6 address? - if (host.find(':') == -1) - { - m_request.hostname = host; - m_request.encoded_hostname = KIDNA::toAscii(host); - } - else - { - m_request.hostname = host; - int pos = host.find('%'); - if (pos == -1) - m_request.encoded_hostname = '[' + host + ']'; - else - // don't send the scope-id in IPv6 addresses to the server - m_request.encoded_hostname = '[' + host.left(pos) + ']'; - } - m_request.port = (port == 0) ? m_iDefaultPort : port; - m_request.user = user; - m_request.passwd = pass; - - m_bIsTunneled = false; - - kdDebug(7113) << "(" << m_pid << ") Hostname is now: " << m_request.hostname << - " (" << m_request.encoded_hostname << ")" <<endl; -} - -bool HTTPProtocol::checkRequestURL( const KURL& u ) -{ - kdDebug (7113) << "(" << m_pid << ") HTTPProtocol::checkRequestURL: " << u.url() << endl; - - m_request.url = u; - - if (m_request.hostname.isEmpty()) - { - error( TDEIO::ERR_UNKNOWN_HOST, i18n("No host specified.")); - return false; - } - - if (u.path().isEmpty()) - { - KURL newUrl(u); - newUrl.setPath("/"); - redirection(newUrl); - finished(); - return false; - } - - if ( m_protocol != u.protocol().latin1() ) - { - short unsigned int oldDefaultPort = m_iDefaultPort; - m_protocol = u.protocol().latin1(); - reparseConfiguration(); - if ( m_iDefaultPort != oldDefaultPort && - m_request.port == oldDefaultPort ) - m_request.port = m_iDefaultPort; - } - - resetSessionSettings(); - return true; -} - -void HTTPProtocol::retrieveContent( bool dataInternal /* = false */ ) -{ - kdDebug (7113) << "(" << m_pid << ") HTTPProtocol::retrieveContent " << endl; - if ( !retrieveHeader( false ) ) - { - if ( m_bError ) - return; - } - else - { - if ( !readBody( dataInternal ) && m_bError ) - return; - } - - httpClose(m_bKeepAlive); - - // if data is required internally, don't finish, - // it is processed before we finish() - if ( !dataInternal ) - { - if ((m_responseCode == 204) && - ((m_request.method == HTTP_GET) || (m_request.method == HTTP_POST))) - error(ERR_NO_CONTENT, ""); - else - finished(); - } -} - -bool HTTPProtocol::retrieveHeader( bool close_connection ) -{ - kdDebug (7113) << "(" << m_pid << ") HTTPProtocol::retrieveHeader " << endl; - while ( 1 ) - { - if (!httpOpen()) - return false; - - resetResponseSettings(); - if (!readHeader()) - { - if ( m_bError ) - return false; - - if (m_bIsTunneled) - { - kdDebug(7113) << "(" << m_pid << ") Re-establishing SSL tunnel..." << endl; - httpCloseConnection(); - } - } - else - { - // Do not save authorization if the current response code is - // 4xx (client error) or 5xx (server error). - kdDebug(7113) << "(" << m_pid << ") Previous Response: " - << m_prevResponseCode << endl; - kdDebug(7113) << "(" << m_pid << ") Current Response: " - << m_responseCode << endl; - - if (isSSLTunnelEnabled() && m_bIsSSL && !m_bUnauthorized && !m_bError) - { - // If there is no error, disable tunneling - if ( m_responseCode < 400 ) - { - kdDebug(7113) << "(" << m_pid << ") Unset tunneling flag!" << endl; - setEnableSSLTunnel( false ); - m_bIsTunneled = true; - // Reset the CONNECT response code... - m_responseCode = m_prevResponseCode; - continue; - } - else - { - if ( !m_request.bErrorPage ) - { - kdDebug(7113) << "(" << m_pid << ") Sending an error message!" << endl; - error( ERR_UNKNOWN_PROXY_HOST, m_proxyURL.host() ); - return false; - } - - kdDebug(7113) << "(" << m_pid << ") Sending an error page!" << endl; - } - } - - if (m_responseCode < 400 && (m_prevResponseCode == 401 || - m_prevResponseCode == 407)) - saveAuthorization(); - break; - } - } - - // Clear of the temporary POST buffer if it is not empty... - if (!m_bufPOST.isEmpty()) - { - m_bufPOST.resize(0); - kdDebug(7113) << "(" << m_pid << ") HTTP::retreiveHeader: Cleared POST " - "buffer..." << endl; - } - - if ( close_connection ) - { - httpClose(m_bKeepAlive); - finished(); - } - - return true; -} - -void HTTPProtocol::stat(const KURL& url) -{ - kdDebug(7113) << "(" << m_pid << ") HTTPProtocol::stat " << url.prettyURL() - << endl; - - if ( !checkRequestURL( url ) ) - return; - - if ( m_protocol != "webdav" && m_protocol != "webdavs" ) - { - TQString statSide = metaData(TQString::fromLatin1("statSide")); - if ( statSide != "source" ) - { - // When uploading we assume the file doesn't exit - error( ERR_DOES_NOT_EXIST, url.prettyURL() ); - return; - } - - // When downloading we assume it exists - UDSEntry entry; - UDSAtom atom; - atom.m_uds = TDEIO::UDS_NAME; - atom.m_str = url.fileName(); - entry.append( atom ); - - atom.m_uds = TDEIO::UDS_FILE_TYPE; - atom.m_long = S_IFREG; // a file - entry.append( atom ); - - atom.m_uds = TDEIO::UDS_ACCESS; - atom.m_long = S_IRUSR | S_IRGRP | S_IROTH; // readable by everybody - entry.append( atom ); - - statEntry( entry ); - finished(); - return; - } - - davStatList( url ); -} - -void HTTPProtocol::listDir( const KURL& url ) -{ - kdDebug(7113) << "(" << m_pid << ") HTTPProtocol::listDir " << url.url() - << endl; - - if ( !checkRequestURL( url ) ) - return; - - if (!url.protocol().startsWith("webdav")) { - error(ERR_UNSUPPORTED_ACTION, url.prettyURL()); - return; - } - - davStatList( url, false ); -} - -void HTTPProtocol::davSetRequest( const TQCString& requestXML ) -{ - // insert the document into the POST buffer, kill trailing zero byte - m_bufPOST = requestXML; - - if (m_bufPOST.size()) - m_bufPOST.truncate( m_bufPOST.size() - 1 ); -} - -void HTTPProtocol::davStatList( const KURL& url, bool stat ) -{ - UDSEntry entry; - UDSAtom atom; - - // check to make sure this host supports WebDAV - if ( !davHostOk() ) - return; - - // Maybe it's a disguised SEARCH... - TQString query = metaData("davSearchQuery"); - if ( !query.isEmpty() ) - { - TQCString request = "<?xml version=\"1.0\"?>\r\n"; - request.append( "<D:searchrequest xmlns:D=\"DAV:\">\r\n" ); - request.append( query.utf8() ); - request.append( "</D:searchrequest>\r\n" ); - - davSetRequest( request ); - } else { - // We are only after certain features... - TQCString request; - request = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>" - "<D:propfind xmlns:D=\"DAV:\">"; - - // insert additional XML request from the davRequestResponse metadata - if ( hasMetaData( "davRequestResponse" ) ) - request += metaData( "davRequestResponse" ).utf8(); - else { - // No special request, ask for default properties - request += "<D:prop>" - "<D:creationdate/>" - "<D:getcontentlength/>" - "<D:displayname/>" - "<D:source/>" - "<D:getcontentlanguage/>" - "<D:getcontenttype/>" - "<D:executable/>" - "<D:getlastmodified/>" - "<D:getetag/>" - "<D:supportedlock/>" - "<D:lockdiscovery/>" - "<D:resourcetype/>" - "</D:prop>"; - } - request += "</D:propfind>"; - - davSetRequest( request ); - } - - // WebDAV Stat or List... - m_request.method = query.isEmpty() ? DAV_PROPFIND : DAV_SEARCH; - m_request.query = TQString::null; - m_request.cache = CC_Reload; - m_request.doProxy = m_bUseProxy; - m_request.davData.depth = stat ? 0 : 1; - if (!stat) - m_request.url.adjustPath(+1); - - retrieveContent( true ); - - // Has a redirection already been called? If so, we're done. - if (m_bRedirect) { - finished(); - return; - } - - TQDomDocument multiResponse; - multiResponse.setContent( m_bufWebDavData, true ); - - bool hasResponse = false; - - for ( TQDomNode n = multiResponse.documentElement().firstChild(); - !n.isNull(); n = n.nextSibling()) - { - TQDomElement thisResponse = n.toElement(); - if (thisResponse.isNull()) - continue; - - hasResponse = true; - - TQDomElement href = thisResponse.namedItem( "href" ).toElement(); - if ( !href.isNull() ) - { - entry.clear(); - - TQString urlStr = href.text(); -#if 0 - int encoding = remoteEncoding()->encodingMib(); - if ((encoding == 106) && (!KStringHandler::isUtf8(KURL::decode_string(urlStr, 4).latin1()))) - encoding = 4; // Use latin1 if the file is not actually utf-8 -#else - TQUrl::decode(urlStr); - int encoding = 106; -#endif - - KURL thisURL ( urlStr, encoding ); - - atom.m_uds = TDEIO::UDS_NAME; - - if ( thisURL.isValid() ) { - // don't list the base dir of a listDir() - if ( !stat && thisURL.path(+1).length() == url.path(+1).length() ) - continue; - - atom.m_str = thisURL.fileName(); - } else { - // This is a relative URL. - atom.m_str = href.text(); - } - - entry.append( atom ); - - TQDomNodeList propstats = thisResponse.elementsByTagName( "propstat" ); - - davParsePropstats( propstats, entry ); - - if ( stat ) - { - // return an item - statEntry( entry ); - finished(); - return; - } - else - { - listEntry( entry, false ); - } - } - else - { - kdDebug(7113) << "Error: no URL contained in response to PROPFIND on " - << url.prettyURL() << endl; - } - } - - if ( stat || !hasResponse ) - { - error( ERR_DOES_NOT_EXIST, url.prettyURL() ); - } - else - { - listEntry( entry, true ); - finished(); - } -} - -void HTTPProtocol::davGeneric( const KURL& url, TDEIO::HTTP_METHOD method ) -{ - kdDebug(7113) << "(" << m_pid << ") HTTPProtocol::davGeneric " << url.url() - << endl; - - if ( !checkRequestURL( url ) ) - return; - - // check to make sure this host supports WebDAV - if ( !davHostOk() ) - return; - - // WebDAV method - m_request.method = method; - m_request.query = TQString::null; - m_request.cache = CC_Reload; - m_request.doProxy = m_bUseProxy; - - retrieveContent( false ); -} - -int HTTPProtocol::codeFromResponse( const TQString& response ) -{ - int firstSpace = response.find( ' ' ); - int secondSpace = response.find( ' ', firstSpace + 1 ); - return response.mid( firstSpace + 1, secondSpace - firstSpace - 1 ).toInt(); -} - -void HTTPProtocol::davParsePropstats( const TQDomNodeList& propstats, UDSEntry& entry ) -{ - TQString mimeType; - UDSAtom atom; - bool foundExecutable = false; - bool isDirectory = false; - uint lockCount = 0; - uint supportedLockCount = 0; - - for ( uint i = 0; i < propstats.count(); i++) - { - TQDomElement propstat = propstats.item(i).toElement(); - - TQDomElement status = propstat.namedItem( "status" ).toElement(); - if ( status.isNull() ) - { - // error, no status code in this propstat - kdDebug(7113) << "Error, no status code in this propstat" << endl; - return; - } - - int code = codeFromResponse( status.text() ); - - if ( code != 200 ) - { - kdDebug(7113) << "Warning: status code " << code << " (this may mean that some properties are unavailable" << endl; - continue; - } - - TQDomElement prop = propstat.namedItem( "prop" ).toElement(); - if ( prop.isNull() ) - { - kdDebug(7113) << "Error: no prop segment in this propstat." << endl; - return; - } - - if ( hasMetaData( "davRequestResponse" ) ) - { - atom.m_uds = TDEIO::UDS_XML_PROPERTIES; - TQDomDocument doc; - doc.appendChild(prop); - atom.m_str = doc.toString(); - entry.append( atom ); - } - - for ( TQDomNode n = prop.firstChild(); !n.isNull(); n = n.nextSibling() ) - { - TQDomElement property = n.toElement(); - if (property.isNull()) - continue; - - if ( property.namespaceURI() != "DAV:" ) - { - // break out - we're only interested in properties from the DAV namespace - continue; - } - - if ( property.tagName() == "creationdate" ) - { - // Resource creation date. Should be is ISO 8601 format. - atom.m_uds = TDEIO::UDS_CREATION_TIME; - atom.m_long = parseDateTime( property.text(), property.attribute("dt") ); - entry.append( atom ); - } - else if ( property.tagName() == "getcontentlength" ) - { - // Content length (file size) - atom.m_uds = TDEIO::UDS_SIZE; - atom.m_long = property.text().toULong(); - entry.append( atom ); - } - else if ( property.tagName() == "displayname" ) - { - // Name suitable for presentation to the user - setMetaData( "davDisplayName", property.text() ); - } - else if ( property.tagName() == "source" ) - { - // Source template location - TQDomElement source = property.namedItem( "link" ).toElement() - .namedItem( "dst" ).toElement(); - if ( !source.isNull() ) - setMetaData( "davSource", source.text() ); - } - else if ( property.tagName() == "getcontentlanguage" ) - { - // equiv. to Content-Language header on a GET - setMetaData( "davContentLanguage", property.text() ); - } - else if ( property.tagName() == "getcontenttype" ) - { - // Content type (mime type) - // This may require adjustments for other server-side webdav implementations - // (tested with Apache + mod_dav 1.0.3) - if ( property.text() == "httpd/unix-directory" ) - { - isDirectory = true; - } - else - { - mimeType = property.text(); - } - } - else if ( property.tagName() == "executable" ) - { - // File executable status - if ( property.text() == "T" ) - foundExecutable = true; - - } - else if ( property.tagName() == "getlastmodified" ) - { - // Last modification date - atom.m_uds = TDEIO::UDS_MODIFICATION_TIME; - atom.m_long = parseDateTime( property.text(), property.attribute("dt") ); - entry.append( atom ); - - } - else if ( property.tagName() == "getetag" ) - { - // Entity tag - setMetaData( "davEntityTag", property.text() ); - } - else if ( property.tagName() == "supportedlock" ) - { - // Supported locking specifications - for ( TQDomNode n2 = property.firstChild(); !n2.isNull(); n2 = n2.nextSibling() ) - { - TQDomElement lockEntry = n2.toElement(); - if ( lockEntry.tagName() == "lockentry" ) - { - TQDomElement lockScope = lockEntry.namedItem( "lockscope" ).toElement(); - TQDomElement lockType = lockEntry.namedItem( "locktype" ).toElement(); - if ( !lockScope.isNull() && !lockType.isNull() ) - { - // Lock type was properly specified - supportedLockCount++; - TQString scope = lockScope.firstChild().toElement().tagName(); - TQString type = lockType.firstChild().toElement().tagName(); - - setMetaData( TQString("davSupportedLockScope%1").arg(supportedLockCount), scope ); - setMetaData( TQString("davSupportedLockType%1").arg(supportedLockCount), type ); - } - } - } - } - else if ( property.tagName() == "lockdiscovery" ) - { - // Lists the available locks - davParseActiveLocks( property.elementsByTagName( "activelock" ), lockCount ); - } - else if ( property.tagName() == "resourcetype" ) - { - // Resource type. "Specifies the nature of the resource." - if ( !property.namedItem( "collection" ).toElement().isNull() ) - { - // This is a collection (directory) - isDirectory = true; - } - } - else - { - kdDebug(7113) << "Found unknown webdav property: " << property.tagName() << endl; - } - } - } - - setMetaData( "davLockCount", TQString("%1").arg(lockCount) ); - setMetaData( "davSupportedLockCount", TQString("%1").arg(supportedLockCount) ); - - atom.m_uds = TDEIO::UDS_FILE_TYPE; - atom.m_long = isDirectory ? S_IFDIR : S_IFREG; - entry.append( atom ); - - if ( foundExecutable || isDirectory ) - { - // File was executable, or is a directory. - atom.m_uds = TDEIO::UDS_ACCESS; - atom.m_long = 0700; - entry.append(atom); - } - else - { - atom.m_uds = TDEIO::UDS_ACCESS; - atom.m_long = 0600; - entry.append(atom); - } - - if ( !isDirectory && !mimeType.isEmpty() ) - { - atom.m_uds = TDEIO::UDS_MIME_TYPE; - atom.m_str = mimeType; - entry.append( atom ); - } -} - -void HTTPProtocol::davParseActiveLocks( const TQDomNodeList& activeLocks, - uint& lockCount ) -{ - for ( uint i = 0; i < activeLocks.count(); i++ ) - { - TQDomElement activeLock = activeLocks.item(i).toElement(); - - lockCount++; - // required - TQDomElement lockScope = activeLock.namedItem( "lockscope" ).toElement(); - TQDomElement lockType = activeLock.namedItem( "locktype" ).toElement(); - TQDomElement lockDepth = activeLock.namedItem( "depth" ).toElement(); - // optional - TQDomElement lockOwner = activeLock.namedItem( "owner" ).toElement(); - TQDomElement lockTimeout = activeLock.namedItem( "timeout" ).toElement(); - TQDomElement lockToken = activeLock.namedItem( "locktoken" ).toElement(); - - if ( !lockScope.isNull() && !lockType.isNull() && !lockDepth.isNull() ) - { - // lock was properly specified - lockCount++; - TQString scope = lockScope.firstChild().toElement().tagName(); - TQString type = lockType.firstChild().toElement().tagName(); - TQString depth = lockDepth.text(); - - setMetaData( TQString("davLockScope%1").arg( lockCount ), scope ); - setMetaData( TQString("davLockType%1").arg( lockCount ), type ); - setMetaData( TQString("davLockDepth%1").arg( lockCount ), depth ); - - if ( !lockOwner.isNull() ) - setMetaData( TQString("davLockOwner%1").arg( lockCount ), lockOwner.text() ); - - if ( !lockTimeout.isNull() ) - setMetaData( TQString("davLockTimeout%1").arg( lockCount ), lockTimeout.text() ); - - if ( !lockToken.isNull() ) - { - TQDomElement tokenVal = lockScope.namedItem( "href" ).toElement(); - if ( !tokenVal.isNull() ) - setMetaData( TQString("davLockToken%1").arg( lockCount ), tokenVal.text() ); - } - } - } -} - -long HTTPProtocol::parseDateTime( const TQString& input, const TQString& type ) -{ - if ( type == "dateTime.tz" ) - { - return KRFCDate::parseDateISO8601( input ); - } - else if ( type == "dateTime.rfc1123" ) - { - return KRFCDate::parseDate( input ); - } - - // format not advertised... try to parse anyway - time_t time = KRFCDate::parseDate( input ); - if ( time != 0 ) - return time; - - return KRFCDate::parseDateISO8601( input ); -} - -TQString HTTPProtocol::davProcessLocks() -{ - if ( hasMetaData( "davLockCount" ) ) - { - TQString response("If:"); - int numLocks; - numLocks = metaData( "davLockCount" ).toInt(); - bool bracketsOpen = false; - for ( int i = 0; i < numLocks; i++ ) - { - if ( hasMetaData( TQString("davLockToken%1").arg(i) ) ) - { - if ( hasMetaData( TQString("davLockURL%1").arg(i) ) ) - { - if ( bracketsOpen ) - { - response += ")"; - bracketsOpen = false; - } - response += " <" + metaData( TQString("davLockURL%1").arg(i) ) + ">"; - } - - if ( !bracketsOpen ) - { - response += " ("; - bracketsOpen = true; - } - else - { - response += " "; - } - - if ( hasMetaData( TQString("davLockNot%1").arg(i) ) ) - response += "Not "; - - response += "<" + metaData( TQString("davLockToken%1").arg(i) ) + ">"; - } - } - - if ( bracketsOpen ) - response += ")"; - - response += "\r\n"; - return response; - } - - return TQString::null; -} - -bool HTTPProtocol::davHostOk() -{ - // FIXME needs to be reworked. Switched off for now. - return true; - - // cached? - if ( m_davHostOk ) - { - kdDebug(7113) << "(" << m_pid << ") " << k_funcinfo << " true" << endl; - return true; - } - else if ( m_davHostUnsupported ) - { - kdDebug(7113) << "(" << m_pid << ") " << k_funcinfo << " false" << endl; - davError( -2 ); - return false; - } - - m_request.method = HTTP_OPTIONS; - - // query the server's capabilities generally, not for a specific URL - m_request.path = "*"; - m_request.query = TQString::null; - m_request.cache = CC_Reload; - m_request.doProxy = m_bUseProxy; - - // clear davVersions variable, which holds the response to the DAV: header - m_davCapabilities.clear(); - - retrieveHeader(false); - - if (m_davCapabilities.count()) - { - for (uint i = 0; i < m_davCapabilities.count(); i++) - { - bool ok; - uint verNo = m_davCapabilities[i].toUInt(&ok); - if (ok && verNo > 0 && verNo < 3) - { - m_davHostOk = true; - kdDebug(7113) << "Server supports DAV version " << verNo << "." << endl; - } - } - - if ( m_davHostOk ) - return true; - } - - m_davHostUnsupported = true; - davError( -2 ); - return false; -} - -// This function is for closing retrieveHeader( false ); requests -// Required because there may or may not be further info expected -void HTTPProtocol::davFinished() -{ - // TODO: Check with the DAV extension developers - httpClose(m_bKeepAlive); - finished(); -} - -void HTTPProtocol::mkdir( const KURL& url, int ) -{ - kdDebug(7113) << "(" << m_pid << ") HTTPProtocol::mkdir " << url.url() - << endl; - - if ( !checkRequestURL( url ) ) - return; - - m_request.method = DAV_MKCOL; - m_request.path = url.path(); - m_request.query = TQString::null; - m_request.cache = CC_Reload; - m_request.doProxy = m_bUseProxy; - - retrieveHeader( false ); - - if ( m_responseCode == 201 ) - davFinished(); - else - davError(); -} - -void HTTPProtocol::get( const KURL& url ) -{ - kdDebug(7113) << "(" << m_pid << ") HTTPProtocol::get " << url.url() - << endl; - - if ( !checkRequestURL( url ) ) - return; - - m_request.method = HTTP_GET; - m_request.path = url.path(); - m_request.query = url.query(); - - TQString tmp = metaData("cache"); - if (!tmp.isEmpty()) - m_request.cache = parseCacheControl(tmp); - else - m_request.cache = DEFAULT_CACHE_CONTROL; - - m_request.passwd = url.pass(); - m_request.user = url.user(); - m_request.doProxy = m_bUseProxy; - - retrieveContent(); -} - -void HTTPProtocol::put( const KURL &url, int, bool overwrite, bool) -{ - kdDebug(7113) << "(" << m_pid << ") HTTPProtocol::put " << url.prettyURL() - << endl; - - if ( !checkRequestURL( url ) ) - return; - - // Webdav hosts are capable of observing overwrite == false - if (!overwrite && m_protocol.left(6) == "webdav") { - // check to make sure this host supports WebDAV - if ( !davHostOk() ) - return; - - TQCString request; - request = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>" - "<D:propfind xmlns:D=\"DAV:\"><D:prop>" - "<D:creationdate/>" - "<D:getcontentlength/>" - "<D:displayname/>" - "<D:resourcetype/>" - "</D:prop></D:propfind>"; - - davSetRequest( request ); - - // WebDAV Stat or List... - m_request.method = DAV_PROPFIND; - m_request.query = TQString::null; - m_request.cache = CC_Reload; - m_request.doProxy = m_bUseProxy; - m_request.davData.depth = 0; - - retrieveContent(true); - - if (m_responseCode == 207) { - error(ERR_FILE_ALREADY_EXIST, TQString::null); - return; - } - - m_bError = false; - } - - m_request.method = HTTP_PUT; - m_request.path = url.path(); - m_request.query = TQString::null; - m_request.cache = CC_Reload; - m_request.doProxy = m_bUseProxy; - - retrieveHeader( false ); - - kdDebug(7113) << "(" << m_pid << ") HTTPProtocol::put error = " << m_bError << endl; - if (m_bError) - return; - - kdDebug(7113) << "(" << m_pid << ") HTTPProtocol::put responseCode = " << m_responseCode << endl; - - httpClose(false); // Always close connection. - - if ( (m_responseCode >= 200) && (m_responseCode < 300) ) - finished(); - else - httpError(); -} - -void HTTPProtocol::copy( const KURL& src, const KURL& dest, int, bool overwrite ) -{ - kdDebug(7113) << "(" << m_pid << ") HTTPProtocol::copy " << src.prettyURL() - << " -> " << dest.prettyURL() << endl; - - if ( !checkRequestURL( dest ) || !checkRequestURL( src ) ) - return; - - // destination has to be "http(s)://..." - KURL newDest = dest; - if (newDest.protocol() == "webdavs") - newDest.setProtocol("https"); - else - newDest.setProtocol("http"); - - m_request.method = DAV_COPY; - m_request.path = src.path(); - m_request.davData.desturl = newDest.url(); - m_request.davData.overwrite = overwrite; - m_request.query = TQString::null; - m_request.cache = CC_Reload; - m_request.doProxy = m_bUseProxy; - - retrieveHeader( false ); - - // The server returns a HTTP/1.1 201 Created or 204 No Content on successful completion - if ( m_responseCode == 201 || m_responseCode == 204 ) - davFinished(); - else - davError(); -} - -void HTTPProtocol::rename( const KURL& src, const KURL& dest, bool overwrite ) -{ - kdDebug(7113) << "(" << m_pid << ") HTTPProtocol::rename " << src.prettyURL() - << " -> " << dest.prettyURL() << endl; - - if ( !checkRequestURL( dest ) || !checkRequestURL( src ) ) - return; - - // destination has to be "http://..." - KURL newDest = dest; - if (newDest.protocol() == "webdavs") - newDest.setProtocol("https"); - else - newDest.setProtocol("http"); - - m_request.method = DAV_MOVE; - m_request.path = src.path(); - m_request.davData.desturl = newDest.url(); - m_request.davData.overwrite = overwrite; - m_request.query = TQString::null; - m_request.cache = CC_Reload; - m_request.doProxy = m_bUseProxy; - - retrieveHeader( false ); - - if ( m_responseCode == 301 ) - { - // Work around strict Apache-2 WebDAV implementation which refuses to cooperate - // with webdav://host/directory, instead requiring webdav://host/directory/ - // (strangely enough it accepts Destination: without a trailing slash) - - if (m_redirectLocation.protocol() == "https") - m_redirectLocation.setProtocol("webdavs"); - else - m_redirectLocation.setProtocol("webdav"); - - if ( !checkRequestURL( m_redirectLocation ) ) - return; - - m_request.method = DAV_MOVE; - m_request.path = m_redirectLocation.path(); - m_request.davData.desturl = newDest.url(); - m_request.davData.overwrite = overwrite; - m_request.query = TQString::null; - m_request.cache = CC_Reload; - m_request.doProxy = m_bUseProxy; - - retrieveHeader( false ); - } - - if ( m_responseCode == 201 ) - davFinished(); - else - davError(); -} - -void HTTPProtocol::del( const KURL& url, bool ) -{ - kdDebug(7113) << "(" << m_pid << ") HTTPProtocol::del " << url.prettyURL() - << endl; - - if ( !checkRequestURL( url ) ) - return; - - m_request.method = HTTP_DELETE; - m_request.path = url.path(); - m_request.query = TQString::null; - m_request.cache = CC_Reload; - m_request.doProxy = m_bUseProxy; - - retrieveHeader( false ); - - // The server returns a HTTP/1.1 200 Ok or HTTP/1.1 204 No Content - // on successful completion - if ( m_responseCode == 200 || m_responseCode == 204 ) - davFinished(); - else - davError(); -} - -void HTTPProtocol::post( const KURL& url ) -{ - kdDebug(7113) << "(" << m_pid << ") HTTPProtocol::post " - << url.prettyURL() << endl; - - if ( !checkRequestURL( url ) ) - return; - - m_request.method = HTTP_POST; - m_request.path = url.path(); - m_request.query = url.query(); - m_request.cache = CC_Reload; - m_request.doProxy = m_bUseProxy; - - retrieveContent(); -} - -void HTTPProtocol::davLock( const KURL& url, const TQString& scope, - const TQString& type, const TQString& owner ) -{ - kdDebug(7113) << "(" << m_pid << ") HTTPProtocol::davLock " - << url.prettyURL() << endl; - - if ( !checkRequestURL( url ) ) - return; - - m_request.method = DAV_LOCK; - m_request.path = url.path(); - m_request.query = TQString::null; - m_request.cache = CC_Reload; - m_request.doProxy = m_bUseProxy; - - /* Create appropriate lock XML request. */ - TQDomDocument lockReq; - - TQDomElement lockInfo = lockReq.createElementNS( "DAV:", "lockinfo" ); - lockReq.appendChild( lockInfo ); - - TQDomElement lockScope = lockReq.createElement( "lockscope" ); - lockInfo.appendChild( lockScope ); - - lockScope.appendChild( lockReq.createElement( scope ) ); - - TQDomElement lockType = lockReq.createElement( "locktype" ); - lockInfo.appendChild( lockType ); - - lockType.appendChild( lockReq.createElement( type ) ); - - if ( !owner.isNull() ) { - TQDomElement ownerElement = lockReq.createElement( "owner" ); - lockReq.appendChild( ownerElement ); - - TQDomElement ownerHref = lockReq.createElement( "href" ); - ownerElement.appendChild( ownerHref ); - - ownerHref.appendChild( lockReq.createTextNode( owner ) ); - } - - // insert the document into the POST buffer - m_bufPOST = lockReq.toCString(); - - retrieveContent( true ); - - if ( m_responseCode == 200 ) { - // success - TQDomDocument multiResponse; - multiResponse.setContent( m_bufWebDavData, true ); - - TQDomElement prop = multiResponse.documentElement().namedItem( "prop" ).toElement(); - - TQDomElement lockdiscovery = prop.namedItem( "lockdiscovery" ).toElement(); - - uint lockCount = 0; - davParseActiveLocks( lockdiscovery.elementsByTagName( "activelock" ), lockCount ); - - setMetaData( "davLockCount", TQString("%1").arg( lockCount ) ); - - finished(); - - } else - davError(); -} - -void HTTPProtocol::davUnlock( const KURL& url ) -{ - kdDebug(7113) << "(" << m_pid << ") HTTPProtocol::davUnlock " - << url.prettyURL() << endl; - - if ( !checkRequestURL( url ) ) - return; - - m_request.method = DAV_UNLOCK; - m_request.path = url.path(); - m_request.query = TQString::null; - m_request.cache = CC_Reload; - m_request.doProxy = m_bUseProxy; - - retrieveContent( true ); - - if ( m_responseCode == 200 ) - finished(); - else - davError(); -} - -TQString HTTPProtocol::davError( int code /* = -1 */, TQString url ) -{ - bool callError = false; - if ( code == -1 ) { - code = m_responseCode; - callError = true; - } - if ( code == -2 ) { - callError = true; - } - - if ( !url.isNull() ) - url = m_request.url.url(); - - TQString action, errorString; - TDEIO::Error kError; - - // for 412 Precondition Failed - TQString ow = i18n( "Otherwise, the request would have succeeded." ); - - switch ( m_request.method ) { - case DAV_PROPFIND: - action = i18n( "retrieve property values" ); - break; - case DAV_PROPPATCH: - action = i18n( "set property values" ); - break; - case DAV_MKCOL: - action = i18n( "create the requested folder" ); - break; - case DAV_COPY: - action = i18n( "copy the specified file or folder" ); - break; - case DAV_MOVE: - action = i18n( "move the specified file or folder" ); - break; - case DAV_SEARCH: - action = i18n( "search in the specified folder" ); - break; - case DAV_LOCK: - action = i18n( "lock the specified file or folder" ); - break; - case DAV_UNLOCK: - action = i18n( "unlock the specified file or folder" ); - break; - case HTTP_DELETE: - action = i18n( "delete the specified file or folder" ); - break; - case HTTP_OPTIONS: - action = i18n( "query the server's capabilities" ); - break; - case HTTP_GET: - action = i18n( "retrieve the contents of the specified file or folder" ); - break; - case HTTP_PUT: - case HTTP_POST: - case HTTP_HEAD: - default: - // this should not happen, this function is for webdav errors only - Q_ASSERT(0); - } - - // default error message if the following code fails - kError = ERR_INTERNAL; - errorString = i18n("An unexpected error (%1) occurred while attempting to %2.") - .arg( code ).arg( action ); - - switch ( code ) - { - case -2: - // internal error: OPTIONS request did not specify DAV compliance - kError = ERR_UNSUPPORTED_PROTOCOL; - errorString = i18n("The server does not support the WebDAV protocol."); - break; - case 207: - // 207 Multi-status - { - // our error info is in the returned XML document. - // retrieve the XML document - - // there was an error retrieving the XML document. - // ironic, eh? - if ( !readBody( true ) && m_bError ) - return TQString::null; - - TQStringList errors; - TQDomDocument multiResponse; - - multiResponse.setContent( m_bufWebDavData, true ); - - TQDomElement multistatus = multiResponse.documentElement().namedItem( "multistatus" ).toElement(); - - TQDomNodeList responses = multistatus.elementsByTagName( "response" ); - - for (uint i = 0; i < responses.count(); i++) - { - int errCode; - TQString errUrl; - - TQDomElement response = responses.item(i).toElement(); - TQDomElement code = response.namedItem( "status" ).toElement(); - - if ( !code.isNull() ) - { - errCode = codeFromResponse( code.text() ); - TQDomElement href = response.namedItem( "href" ).toElement(); - if ( !href.isNull() ) - errUrl = href.text(); - errors << davError( errCode, errUrl ); - } - } - - //kError = ERR_SLAVE_DEFINED; - errorString = i18n("An error occurred while attempting to %1, %2. A " - "summary of the reasons is below.<ul>").arg( action ).arg( url ); - - for ( TQStringList::Iterator it = errors.begin(); it != errors.end(); ++it ) - errorString += "<li>" + *it + "</li>"; - - errorString += "</ul>"; - } - case 403: - case 500: // hack: Apache mod_dav returns this instead of 403 (!) - // 403 Forbidden - kError = ERR_ACCESS_DENIED; - errorString = i18n("Access was denied while attempting to %1.").arg( action ); - break; - case 405: - // 405 Method Not Allowed - if ( m_request.method == DAV_MKCOL ) - { - kError = ERR_DIR_ALREADY_EXIST; - errorString = i18n("The specified folder already exists."); - } - break; - case 409: - // 409 Conflict - kError = ERR_ACCESS_DENIED; - errorString = i18n("A resource cannot be created at the destination " - "until one or more intermediate collections (folders) " - "have been created."); - break; - case 412: - // 412 Precondition failed - if ( m_request.method == DAV_COPY || m_request.method == DAV_MOVE ) - { - kError = ERR_ACCESS_DENIED; - errorString = i18n("The server was unable to maintain the liveness of " - "the properties listed in the propertybehavior XML " - "element or you attempted to overwrite a file while " - "requesting that files are not overwritten. %1") - .arg( ow ); - - } - else if ( m_request.method == DAV_LOCK ) - { - kError = ERR_ACCESS_DENIED; - errorString = i18n("The requested lock could not be granted. %1").arg( ow ); - } - break; - case 415: - // 415 Unsupported Media Type - kError = ERR_ACCESS_DENIED; - errorString = i18n("The server does not support the request type of the body."); - break; - case 423: - // 423 Locked - kError = ERR_ACCESS_DENIED; - errorString = i18n("Unable to %1 because the resource is locked.").arg( action ); - break; - case 425: - // 424 Failed Dependency - errorString = i18n("This action was prevented by another error."); - break; - case 502: - // 502 Bad Gateway - if ( m_request.method == DAV_COPY || m_request.method == DAV_MOVE ) - { - kError = ERR_WRITE_ACCESS_DENIED; - errorString = i18n("Unable to %1 because the destination server refuses " - "to accept the file or folder.").arg( action ); - } - break; - case 507: - // 507 Insufficient Storage - kError = ERR_DISK_FULL; - errorString = i18n("The destination resource does not have sufficient space " - "to record the state of the resource after the execution " - "of this method."); - break; - } - - // if ( kError != ERR_SLAVE_DEFINED ) - //errorString += " (" + url + ")"; - - if ( callError ) - error( ERR_SLAVE_DEFINED, errorString ); - - return errorString; -} - -void HTTPProtocol::httpError() -{ - TQString action, errorString; - TDEIO::Error kError; - - switch ( m_request.method ) { - case HTTP_PUT: - action = i18n( "upload %1" ).arg(m_request.url.prettyURL()); - break; - default: - // this should not happen, this function is for http errors only - Q_ASSERT(0); - } - - // default error message if the following code fails - kError = ERR_INTERNAL; - errorString = i18n("An unexpected error (%1) occurred while attempting to %2.") - .arg( m_responseCode ).arg( action ); - - switch ( m_responseCode ) - { - case 403: - case 405: - case 500: // hack: Apache mod_dav returns this instead of 403 (!) - // 403 Forbidden - // 405 Method Not Allowed - kError = ERR_ACCESS_DENIED; - errorString = i18n("Access was denied while attempting to %1.").arg( action ); - break; - case 409: - // 409 Conflict - kError = ERR_ACCESS_DENIED; - errorString = i18n("A resource cannot be created at the destination " - "until one or more intermediate collections (folders) " - "have been created."); - break; - case 423: - // 423 Locked - kError = ERR_ACCESS_DENIED; - errorString = i18n("Unable to %1 because the resource is locked.").arg( action ); - break; - case 502: - // 502 Bad Gateway - kError = ERR_WRITE_ACCESS_DENIED; - errorString = i18n("Unable to %1 because the destination server refuses " - "to accept the file or folder.").arg( action ); - break; - case 507: - // 507 Insufficient Storage - kError = ERR_DISK_FULL; - errorString = i18n("The destination resource does not have sufficient space " - "to record the state of the resource after the execution " - "of this method."); - break; - } - - // if ( kError != ERR_SLAVE_DEFINED ) - //errorString += " (" + url + ")"; - - error( ERR_SLAVE_DEFINED, errorString ); -} - -bool HTTPProtocol::isOffline(const KURL &url) -{ - const int NetWorkStatusUnknown = 1; - const int NetWorkStatusOnline = 8; - TQCString replyType; - TQByteArray params; - TQByteArray reply; - - TQDataStream stream(params, IO_WriteOnly); - - if ( url.host() == TQString::fromLatin1("localhost") || url.host() == TQString::fromLatin1("127.0.0.1") || url.host() == TQString::fromLatin1("::") ) { - return false; - } - if ( dcopClient()->call( "kded", "networkstatus", "status()", - params, replyType, reply ) && (replyType == "int") ) - { - int result; - TQDataStream stream2( reply, IO_ReadOnly ); - stream2 >> result; - kdDebug(7113) << "(" << m_pid << ") networkstatus status = " << result << endl; - return (result != NetWorkStatusUnknown) && (result != NetWorkStatusOnline); - } - kdDebug(7113) << "(" << m_pid << ") networkstatus <unreachable>" << endl; - return false; // On error, assume we are online -} - -void HTTPProtocol::multiGet(const TQByteArray &data) -{ - TQDataStream stream(data, IO_ReadOnly); - TQ_UINT32 n; - stream >> n; - - kdDebug(7113) << "(" << m_pid << ") HTTPProtcool::multiGet n = " << n << endl; - - HTTPRequest saveRequest; - if (m_bBusy) - saveRequest = m_request; - -// m_requestQueue.clear(); - for(unsigned i = 0; i < n; i++) - { - KURL url; - stream >> url >> mIncomingMetaData; - - if ( !checkRequestURL( url ) ) - continue; - - kdDebug(7113) << "(" << m_pid << ") HTTPProtocol::multi_get " << url.url() << endl; - - m_request.method = HTTP_GET; - m_request.path = url.path(); - m_request.query = url.query(); - TQString tmp = metaData("cache"); - if (!tmp.isEmpty()) - m_request.cache = parseCacheControl(tmp); - else - m_request.cache = DEFAULT_CACHE_CONTROL; - - m_request.passwd = url.pass(); - m_request.user = url.user(); - m_request.doProxy = m_bUseProxy; - - HTTPRequest *newRequest = new HTTPRequest(m_request); - m_requestQueue.append(newRequest); - } - - if (m_bBusy) - m_request = saveRequest; - - if (!m_bBusy) - { - m_bBusy = true; - while(!m_requestQueue.isEmpty()) - { - HTTPRequest *request = m_requestQueue.take(0); - m_request = *request; - delete request; - retrieveContent(); - } - m_bBusy = false; - } -} - -ssize_t HTTPProtocol::write (const void *_buf, size_t nbytes) -{ - int bytes_sent = 0; - const char* buf = static_cast<const char*>(_buf); - while ( nbytes > 0 ) - { - int n = TCPSlaveBase::write(buf, nbytes); - - if ( n <= 0 ) - { - // remote side closed connection ? - if ( n == 0 ) - break; - // a valid exception(s) occurred, let's retry... - if (n < 0 && ((errno == EINTR) || (errno == EAGAIN))) - continue; - // some other error occurred ? - return -1; - } - - nbytes -= n; - buf += n; - bytes_sent += n; - } - - return bytes_sent; -} - -void HTTPProtocol::setRewindMarker() -{ - m_rewindCount = 0; -} - -void HTTPProtocol::rewind() -{ - m_linePtrUnget = m_rewindBuf, - m_lineCountUnget = m_rewindCount; - m_rewindCount = 0; -} - - -char *HTTPProtocol::gets (char *s, int size) -{ - int len=0; - char *buf=s; - char mybuf[2]={0,0}; - - while (len < size) - { - read(mybuf, 1); - if (m_bEOF) - break; - - if (m_rewindCount < sizeof(m_rewindBuf)) - m_rewindBuf[m_rewindCount++] = *mybuf; - - if (*mybuf == '\r') // Ignore! - continue; - - if ((*mybuf == '\n') || !*mybuf) - break; - - *buf++ = *mybuf; - len++; - } - - *buf=0; - return s; -} - -ssize_t HTTPProtocol::read (void *b, size_t nbytes) -{ - ssize_t ret = 0; - - if (m_lineCountUnget > 0) - { - ret = ( nbytes < m_lineCountUnget ? nbytes : m_lineCountUnget ); - m_lineCountUnget -= ret; - memcpy(b, m_linePtrUnget, ret); - m_linePtrUnget += ret; - - return ret; - } - - if (m_lineCount > 0) - { - ret = ( nbytes < m_lineCount ? nbytes : m_lineCount ); - m_lineCount -= ret; - memcpy(b, m_linePtr, ret); - m_linePtr += ret; - return ret; - } - - if (nbytes == 1) - { - ret = read(m_lineBuf, 1024); // Read into buffer - m_linePtr = m_lineBuf; - if (ret <= 0) - { - m_lineCount = 0; - return ret; - } - m_lineCount = ret; - return read(b, 1); // Read from buffer - } - - do - { - ret = TCPSlaveBase::read( b, nbytes); - if (ret == 0) - m_bEOF = true; - - } while ((ret == -1) && (errno == EAGAIN || errno == EINTR)); - - return ret; -} - -void HTTPProtocol::httpCheckConnection() -{ - kdDebug(7113) << "(" << m_pid << ") HTTPProtocol::httpCheckConnection: " << - " Socket status: " << m_iSock << - " Keep Alive: " << m_bKeepAlive << - " First: " << m_bFirstRequest << endl; - - if ( !m_bFirstRequest && (m_iSock != -1) ) - { - bool closeDown = false; - if ( !isConnectionValid()) - { - kdDebug(7113) << "(" << m_pid << ") Connection lost!" << endl; - closeDown = true; - } - else if ( m_request.method != HTTP_GET ) - { - closeDown = true; - } - else if ( !m_state.doProxy && !m_request.doProxy ) - { - if (m_state.hostname != m_request.hostname || - m_state.port != m_request.port || - m_state.user != m_request.user || - m_state.passwd != m_request.passwd) - closeDown = true; - } - else - { - // Keep the connection to the proxy. - if ( !(m_request.doProxy && m_state.doProxy) ) - closeDown = true; - } - - if (closeDown) - httpCloseConnection(); - } - - // Let's update our current state - m_state.hostname = m_request.hostname; - m_state.encoded_hostname = m_request.encoded_hostname; - m_state.port = m_request.port; - m_state.user = m_request.user; - m_state.passwd = m_request.passwd; - m_state.doProxy = m_request.doProxy; -} - -bool HTTPProtocol::httpOpenConnection() -{ - int errCode; - TQString errMsg; - - kdDebug(7113) << "(" << m_pid << ") HTTPProtocol::httpOpenConnection" << endl; - - setBlockConnection( true ); - // kio_http uses its own proxying: - KSocks::self()->disableSocks(); - - if ( m_state.doProxy ) - { - TQString proxy_host = m_proxyURL.host(); - int proxy_port = m_proxyURL.port(); - - kdDebug(7113) << "(" << m_pid << ") Connecting to proxy server: " - << proxy_host << ", port: " << proxy_port << endl; - - infoMessage( i18n("Connecting to %1...").arg(m_state.hostname) ); - - setConnectTimeout( m_proxyConnTimeout ); - - if ( !connectToHost(proxy_host, proxy_port, false) ) - { - if (userAborted()) { - error(ERR_NO_CONTENT, ""); - return false; - } - - switch ( connectResult() ) - { - case IO_LookupError: - errMsg = proxy_host; - errCode = ERR_UNKNOWN_PROXY_HOST; - break; - case IO_TimeOutError: - errMsg = i18n("Proxy %1 at port %2").arg(proxy_host).arg(proxy_port); - errCode = ERR_SERVER_TIMEOUT; - break; - default: - errMsg = i18n("Proxy %1 at port %2").arg(proxy_host).arg(proxy_port); - errCode = ERR_COULD_NOT_CONNECT; - } - error( errCode, errMsg ); - return false; - } - } - else - { - // Apparently we don't want a proxy. let's just connect directly - setConnectTimeout(m_remoteConnTimeout); - - if ( !connectToHost(m_state.hostname, m_state.port, false ) ) - { - if (userAborted()) { - error(ERR_NO_CONTENT, ""); - return false; - } - - switch ( connectResult() ) - { - case IO_LookupError: - errMsg = m_state.hostname; - errCode = ERR_UNKNOWN_HOST; - break; - case IO_TimeOutError: - errMsg = i18n("Connection was to %1 at port %2").arg(m_state.hostname).arg(m_state.port); - errCode = ERR_SERVER_TIMEOUT; - break; - default: - errCode = ERR_COULD_NOT_CONNECT; - if (m_state.port != m_iDefaultPort) - errMsg = i18n("%1 (port %2)").arg(m_state.hostname).arg(m_state.port); - else - errMsg = m_state.hostname; - } - error( errCode, errMsg ); - return false; - } - } - - // Set our special socket option!! - int on = 1; - (void) setsockopt( m_iSock, IPPROTO_TCP, TCP_NODELAY, (char*)&on, sizeof(on) ); - - m_bFirstRequest = true; - - connected(); - return true; -} - - -/** - * This function is responsible for opening up the connection to the remote - * HTTP server and sending the header. If this requires special - * authentication or other such fun stuff, then it will handle it. This - * function will NOT receive anything from the server, however. This is in - * contrast to previous incarnations of 'httpOpen'. - * - * The reason for the change is due to one small fact: some requests require - * data to be sent in addition to the header (POST requests) and there is no - * way for this function to get that data. This function is called in the - * slotPut() or slotGet() functions which, in turn, are called (indirectly) as - * a result of a TDEIOJob::put() or TDEIOJob::get(). It is those latter functions - * which are responsible for starting up this ioslave in the first place. - * This means that 'httpOpen' is called (essentially) as soon as the ioslave - * is created -- BEFORE any data gets to this slave. - * - * The basic process now is this: - * - * 1) Open up the socket and port - * 2) Format our request/header - * 3) Send the header to the remote server - */ -bool HTTPProtocol::httpOpen() -{ - kdDebug(7113) << "(" << m_pid << ") HTTPProtocol::httpOpen" << endl; - - // Cannot have an https request without the m_bIsSSL being set! This can - // only happen if TCPSlaveBase::InitializeSSL() function failed in which it - // means the current installation does not support SSL... - if ( (m_protocol == "https" || m_protocol == "webdavs") && !m_bIsSSL ) - { - error( ERR_UNSUPPORTED_PROTOCOL, m_protocol ); - return false; - } - - m_request.fcache = 0; - m_request.bCachedRead = false; - m_request.bCachedWrite = false; - m_request.bMustRevalidate = false; - m_request.expireDate = 0; - m_request.creationDate = 0; - - if (m_request.bUseCache) - { - m_request.fcache = checkCacheEntry( ); - - bool bCacheOnly = (m_request.cache == TDEIO::CC_CacheOnly); - bool bOffline = isOffline(m_request.doProxy ? m_proxyURL : m_request.url); - if (bOffline && (m_request.cache != TDEIO::CC_Reload)) - m_request.cache = TDEIO::CC_CacheOnly; - - if (m_request.cache == CC_Reload && m_request.fcache) - { - if (m_request.fcache) - fclose(m_request.fcache); - m_request.fcache = 0; - } - if ((m_request.cache == TDEIO::CC_CacheOnly) || (m_request.cache == TDEIO::CC_Cache)) - m_request.bMustRevalidate = false; - - m_request.bCachedWrite = true; - - if (m_request.fcache && !m_request.bMustRevalidate) - { - // Cache entry is OK. - m_request.bCachedRead = true; // Cache hit. - return true; - } - else if (!m_request.fcache) - { - m_request.bMustRevalidate = false; // Cache miss - } - else - { - // Conditional cache hit. (Validate) - } - - if (bCacheOnly && bOffline) - { - error( ERR_OFFLINE_MODE, m_request.url.url() ); - return false; - } - if (bCacheOnly) - { - error( ERR_DOES_NOT_EXIST, m_request.url.url() ); - return false; - } - if (bOffline) - { - error( ERR_OFFLINE_MODE, m_request.url.url() ); - return false; - } - } - - TQString header; - TQString davHeader; - - bool moreData = false; - bool davData = false; - - // Clear out per-connection settings... - resetConnectionSettings (); - - // Check the validity of the current connection, if one exists. - httpCheckConnection(); - - if ( !m_bIsTunneled && m_bNeedTunnel ) - { - setEnableSSLTunnel( true ); - // We send a HTTP 1.0 header since some proxies refuse HTTP 1.1 and we don't - // need any HTTP 1.1 capabilities for CONNECT - Waba - header = TQString("CONNECT %1:%2 HTTP/1.0" - "\r\n").arg( m_request.encoded_hostname).arg(m_request.port); - - // Identify who you are to the proxy server! - if (!m_request.userAgent.isEmpty()) - header += "User-Agent: " + m_request.userAgent + "\r\n"; - - /* Add hostname information */ - header += "Host: " + m_state.encoded_hostname; - - if (m_state.port != m_iDefaultPort) - header += TQString(":%1").arg(m_state.port); - header += "\r\n"; - - header += proxyAuthenticationHeader(); - } - else - { - // Determine if this is a POST or GET method - switch (m_request.method) - { - case HTTP_GET: - header = "GET "; - break; - case HTTP_PUT: - header = "PUT "; - moreData = true; - m_request.bCachedWrite = false; // Do not put any result in the cache - break; - case HTTP_POST: - header = "POST "; - moreData = true; - m_request.bCachedWrite = false; // Do not put any result in the cache - break; - case HTTP_HEAD: - header = "HEAD "; - break; - case HTTP_DELETE: - header = "DELETE "; - m_request.bCachedWrite = false; // Do not put any result in the cache - break; - case HTTP_OPTIONS: - header = "OPTIONS "; - m_request.bCachedWrite = false; // Do not put any result in the cache - break; - case DAV_PROPFIND: - header = "PROPFIND "; - davData = true; - davHeader = "Depth: "; - if ( hasMetaData( "davDepth" ) ) - { - kdDebug(7113) << "Reading DAV depth from metadata: " << metaData( "davDepth" ) << endl; - davHeader += metaData( "davDepth" ); - } - else - { - if ( m_request.davData.depth == 2 ) - davHeader += "infinity"; - else - davHeader += TQString("%1").arg( m_request.davData.depth ); - } - davHeader += "\r\n"; - m_request.bCachedWrite = false; // Do not put any result in the cache - break; - case DAV_PROPPATCH: - header = "PROPPATCH "; - davData = true; - m_request.bCachedWrite = false; // Do not put any result in the cache - break; - case DAV_MKCOL: - header = "MKCOL "; - m_request.bCachedWrite = false; // Do not put any result in the cache - break; - case DAV_COPY: - case DAV_MOVE: - header = ( m_request.method == DAV_COPY ) ? "COPY " : "MOVE "; - davHeader = "Destination: " + m_request.davData.desturl; - // infinity depth means copy recursively - // (optional for copy -> but is the desired action) - davHeader += "\r\nDepth: infinity\r\nOverwrite: "; - davHeader += m_request.davData.overwrite ? "T" : "F"; - davHeader += "\r\n"; - m_request.bCachedWrite = false; // Do not put any result in the cache - break; - case DAV_LOCK: - header = "LOCK "; - davHeader = "Timeout: "; - { - uint timeout = 0; - if ( hasMetaData( "davTimeout" ) ) - timeout = metaData( "davTimeout" ).toUInt(); - if ( timeout == 0 ) - davHeader += "Infinite"; - else - davHeader += TQString("Seconds-%1").arg(timeout); - } - davHeader += "\r\n"; - m_request.bCachedWrite = false; // Do not put any result in the cache - davData = true; - break; - case DAV_UNLOCK: - header = "UNLOCK "; - davHeader = "Lock-token: " + metaData("davLockToken") + "\r\n"; - m_request.bCachedWrite = false; // Do not put any result in the cache - break; - case DAV_SEARCH: - header = "SEARCH "; - davData = true; - m_request.bCachedWrite = false; - break; - case DAV_SUBSCRIBE: - header = "SUBSCRIBE "; - m_request.bCachedWrite = false; - break; - case DAV_UNSUBSCRIBE: - header = "UNSUBSCRIBE "; - m_request.bCachedWrite = false; - break; - case DAV_POLL: - header = "POLL "; - m_request.bCachedWrite = false; - break; - default: - error (ERR_UNSUPPORTED_ACTION, TQString::null); - return false; - } - // DAV_POLL; DAV_NOTIFY - - // format the URI - if (m_state.doProxy && !m_bIsTunneled) - { - KURL u; - - if (m_protocol == "webdav") - u.setProtocol( "http" ); - else if (m_protocol == "webdavs" ) - u.setProtocol( "https" ); - else - u.setProtocol( m_protocol ); - - // For all protocols other than the once handled by this io-slave - // append the username. This fixes a long standing bug of ftp io-slave - // logging in anonymously in proxied connections even when the username - // is explicitly specified. - if (m_protocol != "http" && m_protocol != "https" && - !m_state.user.isEmpty()) - u.setUser (m_state.user); - - u.setHost( m_state.hostname ); - if (m_state.port != m_iDefaultPort) - u.setPort( m_state.port ); - u.setEncodedPathAndQuery( m_request.url.encodedPathAndQuery(0,true) ); - header += u.url(); - } - else - { - header += m_request.url.encodedPathAndQuery(0, true); - } - - header += " HTTP/1.1\r\n"; /* start header */ - - if (!m_request.userAgent.isEmpty()) - { - header += "User-Agent: "; - header += m_request.userAgent; - header += "\r\n"; - } - - if (!m_request.referrer.isEmpty()) - { - header += "Referer: "; //Don't try to correct spelling! - header += m_request.referrer; - header += "\r\n"; - } - - if ( m_request.offset > 0 ) - { - header += TQString("Range: bytes=%1-\r\n").arg(TDEIO::number(m_request.offset)); - kdDebug(7103) << "kio_http : Range = " << TDEIO::number(m_request.offset) << endl; - } - - if ( m_request.cache == CC_Reload ) - { - /* No caching for reload */ - header += "Pragma: no-cache\r\n"; /* for HTTP/1.0 caches */ - header += "Cache-control: no-cache\r\n"; /* for HTTP >=1.1 caches */ - } - - if (m_request.bMustRevalidate) - { - /* conditional get */ - if (!m_request.etag.isEmpty()) - header += "If-None-Match: "+m_request.etag+"\r\n"; - if (!m_request.lastModified.isEmpty()) - header += "If-Modified-Since: "+m_request.lastModified+"\r\n"; - } - - header += "Accept: "; - TQString acceptHeader = metaData("accept"); - if (!acceptHeader.isEmpty()) - header += acceptHeader; - else - header += DEFAULT_ACCEPT_HEADER; - header += "\r\n"; - -#ifdef DO_GZIP - if (m_request.allowCompressedPage) - header += "Accept-Encoding: x-gzip, x-deflate, gzip, deflate\r\n"; -#endif - - if (!m_request.charsets.isEmpty()) - header += "Accept-Charset: " + m_request.charsets + "\r\n"; - - if (!m_request.languages.isEmpty()) - header += "Accept-Language: " + m_request.languages + "\r\n"; - - - /* support for virtual hosts and required by HTTP 1.1 */ - header += "Host: " + m_state.encoded_hostname; - - if (m_state.port != m_iDefaultPort) - header += TQString(":%1").arg(m_state.port); - header += "\r\n"; - - TQString cookieStr; - TQString cookieMode = metaData("cookies").lower(); - if (cookieMode == "none") - { - m_request.cookieMode = HTTPRequest::CookiesNone; - } - else if (cookieMode == "manual") - { - m_request.cookieMode = HTTPRequest::CookiesManual; - cookieStr = metaData("setcookies"); - } - else - { - m_request.cookieMode = HTTPRequest::CookiesAuto; - if (m_request.bUseCookiejar) - cookieStr = findCookies( m_request.url.url()); - } - - if (!cookieStr.isEmpty()) - header += cookieStr + "\r\n"; - - TQString customHeader = metaData( "customHTTPHeader" ); - if (!customHeader.isEmpty()) - { - header += sanitizeCustomHTTPHeader(customHeader); - header += "\r\n"; - } - - if (m_request.method == HTTP_POST) - { - header += metaData("content-type"); - header += "\r\n"; - } - - // Only check for a cached copy if the previous - // response was NOT a 401 or 407. - // no caching for Negotiate auth. - if ( !m_request.bNoAuth && m_responseCode != 401 && m_responseCode != 407 && Authentication != AUTH_Negotiate ) - { - kdDebug(7113) << "(" << m_pid << ") Calling checkCachedAuthentication " << endl; - AuthInfo info; - info.url = m_request.url; - info.verifyPath = true; - if ( !m_request.user.isEmpty() ) - info.username = m_request.user; - if ( checkCachedAuthentication( info ) && !info.digestInfo.isEmpty() ) - { - Authentication = info.digestInfo.startsWith("Basic") ? AUTH_Basic : info.digestInfo.startsWith("NTLM") ? AUTH_NTLM : info.digestInfo.startsWith("Negotiate") ? AUTH_Negotiate : AUTH_Digest ; - m_state.user = info.username; - m_state.passwd = info.password; - m_strRealm = info.realmValue; - if ( Authentication != AUTH_NTLM && Authentication != AUTH_Negotiate ) // don't use the cached challenge - m_strAuthorization = info.digestInfo; - } - } - else - { - kdDebug(7113) << "(" << m_pid << ") Not calling checkCachedAuthentication " << endl; - } - - switch ( Authentication ) - { - case AUTH_Basic: - header += createBasicAuth(); - break; - case AUTH_Digest: - header += createDigestAuth(); - break; -#ifdef HAVE_LIBGSSAPI - case AUTH_Negotiate: - header += createNegotiateAuth(); - break; -#endif - case AUTH_NTLM: - header += createNTLMAuth(); - break; - case AUTH_None: - default: - break; - } - - /********* Only for debugging purpose *********/ - if ( Authentication != AUTH_None ) - { - kdDebug(7113) << "(" << m_pid << ") Using Authentication: " << endl; - kdDebug(7113) << "(" << m_pid << ") HOST= " << m_state.hostname << endl; - kdDebug(7113) << "(" << m_pid << ") PORT= " << m_state.port << endl; - kdDebug(7113) << "(" << m_pid << ") USER= " << m_state.user << endl; - kdDebug(7113) << "(" << m_pid << ") PASSWORD= [protected]" << endl; - kdDebug(7113) << "(" << m_pid << ") REALM= " << m_strRealm << endl; - kdDebug(7113) << "(" << m_pid << ") EXTRA= " << m_strAuthorization << endl; - } - - // Do we need to authorize to the proxy server ? - if ( m_state.doProxy && !m_bIsTunneled ) - header += proxyAuthenticationHeader(); - - // Support old HTTP/1.0 style keep-alive header for compatability - // purposes as well as performance improvements while giving end - // users the ability to disable this feature proxy servers that - // don't not support such feature, e.g. junkbuster proxy server. - if (!m_bUseProxy || m_bPersistentProxyConnection || m_bIsTunneled) - header += "Connection: Keep-Alive\r\n"; - else - header += "Connection: close\r\n"; - - if ( m_protocol == "webdav" || m_protocol == "webdavs" ) - { - header += davProcessLocks(); - - // add extra webdav headers, if supplied - TQString davExtraHeader = metaData("davHeader"); - if ( !davExtraHeader.isEmpty() ) - davHeader += davExtraHeader; - - // Set content type of webdav data - if (davData) - davHeader += "Content-Type: text/xml; charset=utf-8\r\n"; - - // add extra header elements for WebDAV - if ( !davHeader.isNull() ) - header += davHeader; - } - } - - kdDebug(7103) << "(" << m_pid << ") ============ Sending Header:" << endl; - - TQStringList headerOutput = TQStringList::split("\r\n", header); - TQStringList::Iterator it = headerOutput.begin(); - - for (; it != headerOutput.end(); it++) - kdDebug(7103) << "(" << m_pid << ") " << (*it) << endl; - - if ( !moreData && !davData) - header += "\r\n"; /* end header */ - - // Now that we have our formatted header, let's send it! - // Create a new connection to the remote machine if we do - // not already have one... - if ( m_iSock == -1) - { - if (!httpOpenConnection()) - return false; - } - - // Send the data to the remote machine... - bool sendOk = (write(header.latin1(), header.length()) == (ssize_t) header.length()); - if (!sendOk) - { - kdDebug(7113) << "(" << m_pid << ") HTTPProtocol::httpOpen: " - "Connection broken! (" << m_state.hostname << ")" << endl; - - // With a Keep-Alive connection this can happen. - // Just reestablish the connection. - if (m_bKeepAlive) - { - httpCloseConnection(); - return true; // Try again - } - - if (!sendOk) - { - kdDebug(7113) << "(" << m_pid << ") HTTPProtocol::httpOpen: sendOk==false." - " Connnection broken !" << endl; - error( ERR_CONNECTION_BROKEN, m_state.hostname ); - return false; - } - } - - bool res = true; - - if ( moreData || davData ) - res = sendBody(); - - infoMessage(i18n("%1 contacted. Waiting for reply...").arg(m_request.hostname)); - - return res; -} - -void HTTPProtocol::forwardHttpResponseHeader() -{ - // Send the response header if it was requested - if ( config()->readBoolEntry("PropagateHttpHeader", false) ) - { - setMetaData("HTTP-Headers", m_responseHeader.join("\n")); - sendMetaData(); - } - m_responseHeader.clear(); -} - -/** - * This function will read in the return header from the server. It will - * not read in the body of the return message. It will also not transmit - * the header to our client as the client doesn't need to know the gory - * details of HTTP headers. - */ -bool HTTPProtocol::readHeader() -{ -try_again: - kdDebug(7113) << "(" << m_pid << ") HTTPProtocol::readHeader" << endl; - - // Check - if (m_request.bCachedRead) - { - m_responseHeader << "HTTP-CACHE"; - // Read header from cache... - char buffer[4097]; - if (!fgets(buffer, 4096, m_request.fcache) ) - { - // Error, delete cache entry - kdDebug(7113) << "(" << m_pid << ") HTTPProtocol::readHeader: " - << "Could not access cache to obtain mimetype!" << endl; - error( ERR_CONNECTION_BROKEN, m_state.hostname ); - return false; - } - - m_strMimeType = TQString(TQString::fromUtf8( buffer)).stripWhiteSpace(); - - kdDebug(7113) << "(" << m_pid << ") HTTPProtocol::readHeader: cached " - << "data mimetype: " << m_strMimeType << endl; - - if (!fgets(buffer, 4096, m_request.fcache) ) - { - // Error, delete cache entry - kdDebug(7113) << "(" << m_pid << ") HTTPProtocol::readHeader: " - << "Could not access cached data! " << endl; - error( ERR_CONNECTION_BROKEN, m_state.hostname ); - return false; - } - - m_request.strCharset = TQString(TQString::fromUtf8( buffer)).stripWhiteSpace().lower(); - setMetaData("charset", m_request.strCharset); - if (!m_request.lastModified.isEmpty()) - setMetaData("modified", m_request.lastModified); - TQString tmp; - tmp.setNum(m_request.expireDate); - setMetaData("expire-date", tmp); - tmp.setNum(m_request.creationDate); - setMetaData("cache-creation-date", tmp); - mimeType(m_strMimeType); - forwardHttpResponseHeader(); - return true; - } - - TQCString locationStr; // In case we get a redirect. - TQCString cookieStr; // In case we get a cookie. - - TQString dispositionType; // In case we get a Content-Disposition type - TQString dispositionFilename; // In case we get a Content-Disposition filename - - TQString mediaValue; - TQString mediaAttribute; - - TQStringList upgradeOffers; - - bool upgradeRequired = false; // Server demands that we upgrade to something - // This is also true if we ask to upgrade and - // the server accepts, since we are now - // committed to doing so - bool canUpgrade = false; // The server offered an upgrade - - - m_request.etag = TQString::null; - m_request.lastModified = TQString::null; - m_request.strCharset = TQString::null; - - time_t dateHeader = 0; - time_t expireDate = 0; // 0 = no info, 1 = already expired, > 1 = actual date - int currentAge = 0; - int maxAge = -1; // -1 = no max age, 0 already expired, > 0 = actual time - int maxHeaderSize = 64*1024; // 64Kb to catch DOS-attacks - - // read in 8192 bytes at a time (HTTP cookies can be quite large.) - int len = 0; - char buffer[8193]; - bool cont = false; - bool cacheValidated = false; // Revalidation was successful - bool mayCache = true; - bool hasCacheDirective = false; - bool bCanResume = false; - - if (m_iSock == -1) - { - kdDebug(7113) << "HTTPProtocol::readHeader: No connection." << endl; - return false; // Restablish connection and try again - } - - if (!waitForResponse(m_remoteRespTimeout)) - { - // No response error - error( ERR_SERVER_TIMEOUT , m_state.hostname ); - return false; - } - - setRewindMarker(); - - gets(buffer, sizeof(buffer)-1); - - if (m_bEOF || *buffer == '\0') - { - kdDebug(7113) << "(" << m_pid << ") HTTPProtocol::readHeader: " - << "EOF while waiting for header start." << endl; - if (m_bKeepAlive) // Try to reestablish connection. - { - httpCloseConnection(); - return false; // Reestablish connection and try again. - } - - if (m_request.method == HTTP_HEAD) - { - // HACK - // Some web-servers fail to respond properly to a HEAD request. - // We compensate for their failure to properly implement the HTTP standard - // by assuming that they will be sending html. - kdDebug(7113) << "(" << m_pid << ") HTTPPreadHeader: HEAD -> returned " - << "mimetype: " << DEFAULT_MIME_TYPE << endl; - mimeType(TQString::fromLatin1(DEFAULT_MIME_TYPE)); - return true; - } - - kdDebug(7113) << "HTTPProtocol::readHeader: Connection broken !" << endl; - error( ERR_CONNECTION_BROKEN, m_state.hostname ); - return false; - } - - kdDebug(7103) << "(" << m_pid << ") ============ Received Response:"<< endl; - - bool noHeader = true; - HTTP_REV httpRev = HTTP_None; - int headerSize = 0; - - do - { - // strip off \r and \n if we have them - len = strlen(buffer); - - while(len && (buffer[len-1] == '\n' || buffer[len-1] == '\r')) - buffer[--len] = 0; - - // if there was only a newline then continue - if (!len) - { - kdDebug(7103) << "(" << m_pid << ") --empty--" << endl; - continue; - } - - headerSize += len; - - // We have a response header. This flag is a work around for - // servers that append a "\r\n" before the beginning of the HEADER - // response!!! It only catches x number of \r\n being placed at the - // top of the reponse... - noHeader = false; - - kdDebug(7103) << "(" << m_pid << ") \"" << buffer << "\"" << endl; - - // Save broken servers from damnation!! - char* buf = buffer; - while( *buf == ' ' ) - buf++; - - - if (buf[0] == '<') - { - // We get XML / HTTP without a proper header - // put string back - kdDebug(7103) << "kio_http: No valid HTTP header found! Document starts with XML/HTML tag" << endl; - - // Document starts with a tag, assume html instead of text/plain - m_strMimeType = "text/html"; - - rewind(); - break; - } - - // Store the the headers so they can be passed to the - // calling application later - m_responseHeader << TQString::fromLatin1(buf); - - if ((strncasecmp(buf, "HTTP/", 5) == 0) || - (strncasecmp(buf, "ICY ", 4) == 0)) // Shoutcast support - { - if (strncasecmp(buf, "ICY ", 4) == 0) - { - // Shoutcast support - httpRev = SHOUTCAST; - m_bKeepAlive = false; - } - else if (strncmp((buf + 5), "1.0",3) == 0) - { - httpRev = HTTP_10; - // For 1.0 servers, the server itself has to explicitly - // tell us whether it supports persistent connection or - // not. By default, we assume it does not, but we do - // send the old style header "Connection: Keep-Alive" to - // inform it that we support persistence. - m_bKeepAlive = false; - } - else if (strncmp((buf + 5), "1.1",3) == 0) - { - httpRev = HTTP_11; - } - else - { - httpRev = HTTP_Unknown; - } - - if (m_responseCode) - m_prevResponseCode = m_responseCode; - - const char* rptr = buf; - while ( *rptr && *rptr > ' ' ) - ++rptr; - m_responseCode = atoi(rptr); - - // server side errors - if (m_responseCode >= 500 && m_responseCode <= 599) - { - if (m_request.method == HTTP_HEAD) - { - ; // Ignore error - } - else - { - if (m_request.bErrorPage) - errorPage(); - else - { - error(ERR_INTERNAL_SERVER, m_request.url.url()); - return false; - } - } - m_request.bCachedWrite = false; // Don't put in cache - mayCache = false; - } - // Unauthorized access - else if (m_responseCode == 401 || m_responseCode == 407) - { - // Double authorization requests, i.e. a proxy auth - // request followed immediately by a regular auth request. - if ( m_prevResponseCode != m_responseCode && - (m_prevResponseCode == 401 || m_prevResponseCode == 407) ) - saveAuthorization(); - - m_bUnauthorized = true; - m_request.bCachedWrite = false; // Don't put in cache - mayCache = false; - } - // - else if (m_responseCode == 416) // Range not supported - { - m_request.offset = 0; - httpCloseConnection(); - return false; // Try again. - } - // Upgrade Required - else if (m_responseCode == 426) - { - upgradeRequired = true; - } - // Any other client errors - else if (m_responseCode >= 400 && m_responseCode <= 499) - { - // Tell that we will only get an error page here. - if (m_request.bErrorPage) - errorPage(); - else - { - error(ERR_DOES_NOT_EXIST, m_request.url.url()); - return false; - } - m_request.bCachedWrite = false; // Don't put in cache - mayCache = false; - } - else if (m_responseCode == 307) - { - // 307 Temporary Redirect - m_request.bCachedWrite = false; // Don't put in cache - mayCache = false; - } - else if (m_responseCode == 304) - { - // 304 Not Modified - // The value in our cache is still valid. - cacheValidated = true; - } - else if (m_responseCode >= 301 && m_responseCode<= 303) - { - // 301 Moved permanently - if (m_responseCode == 301) - setMetaData("permanent-redirect", "true"); - - // 302 Found (temporary location) - // 303 See Other - if (m_request.method != HTTP_HEAD && m_request.method != HTTP_GET) - { -#if 0 - // Reset the POST buffer to avoid a double submit - // on redirection - if (m_request.method == HTTP_POST) - m_bufPOST.resize(0); -#endif - - // NOTE: This is wrong according to RFC 2616. However, - // because most other existing user agent implementations - // treat a 301/302 response as a 303 response and preform - // a GET action regardless of what the previous method was, - // many servers have simply adapted to this way of doing - // things!! Thus, we are forced to do the same thing or we - // won't be able to retrieve these pages correctly!! See RFC - // 2616 sections 10.3.[2/3/4/8] - m_request.method = HTTP_GET; // Force a GET - } - m_request.bCachedWrite = false; // Don't put in cache - mayCache = false; - } - else if ( m_responseCode == 207 ) // Multi-status (for WebDav) - { - - } - else if ( m_responseCode == 204 ) // No content - { - // error(ERR_NO_CONTENT, i18n("Data have been successfully sent.")); - // Short circuit and do nothing! - - // The original handling here was wrong, this is not an error: eg. in the - // example of a 204 No Content response to a PUT completing. - // m_bError = true; - // return false; - } - else if ( m_responseCode == 206 ) - { - if ( m_request.offset ) - bCanResume = true; - } - else if (m_responseCode == 102) // Processing (for WebDAV) - { - /*** - * This status code is given when the server expects the - * command to take significant time to complete. So, inform - * the user. - */ - infoMessage( i18n( "Server processing request, please wait..." ) ); - cont = true; - } - else if (m_responseCode == 100) - { - // We got 'Continue' - ignore it - cont = true; - } - } - - // are we allowd to resume? this will tell us - else if (strncasecmp(buf, "Accept-Ranges:", 14) == 0) { - if (strncasecmp(trimLead(buf + 14), "none", 4) == 0) - bCanResume = false; - } - // Keep Alive - else if (strncasecmp(buf, "Keep-Alive:", 11) == 0) { - TQStringList options = TQStringList::split(',', - TQString::fromLatin1(trimLead(buf+11))); - for(TQStringList::ConstIterator it = options.begin(); - it != options.end(); - it++) - { - TQString option = (*it).stripWhiteSpace().lower(); - if (option.startsWith("timeout=")) - { - m_keepAliveTimeout = option.mid(8).toInt(); - } - } - } - - // Cache control - else if (strncasecmp(buf, "Cache-Control:", 14) == 0) { - TQStringList cacheControls = TQStringList::split(',', - TQString::fromLatin1(trimLead(buf+14))); - for(TQStringList::ConstIterator it = cacheControls.begin(); - it != cacheControls.end(); - it++) - { - TQString cacheControl = (*it).stripWhiteSpace(); - if (strncasecmp(cacheControl.latin1(), "no-cache", 8) == 0) - { - m_request.bCachedWrite = false; // Don't put in cache - mayCache = false; - } - else if (strncasecmp(cacheControl.latin1(), "no-store", 8) == 0) - { - m_request.bCachedWrite = false; // Don't put in cache - mayCache = false; - } - else if (strncasecmp(cacheControl.latin1(), "max-age=", 8) == 0) - { - TQString age = cacheControl.mid(8).stripWhiteSpace(); - if (!age.isNull()) - maxAge = STRTOLL(age.latin1(), 0, 10); - } - } - hasCacheDirective = true; - } - - // get the size of our data - else if (strncasecmp(buf, "Content-length:", 15) == 0) { - char* len = trimLead(buf + 15); - if (len) - m_iSize = STRTOLL(len, 0, 10); - } - - else if (strncasecmp(buf, "Content-location:", 17) == 0) { - setMetaData ("content-location", - TQString::fromLatin1(trimLead(buf+17)).stripWhiteSpace()); - } - - // what type of data do we have? - else if (strncasecmp(buf, "Content-type:", 13) == 0) { - char *start = trimLead(buf + 13); - char *pos = start; - - // Increment until we encounter ";" or the end of the buffer - while ( *pos && *pos != ';' ) pos++; - - // Assign the mime-type. - m_strMimeType = TQString::fromLatin1(start, pos-start).stripWhiteSpace().lower(); - kdDebug(7113) << "(" << m_pid << ") Content-type: " << m_strMimeType << endl; - - // If we still have text, then it means we have a mime-type with a - // parameter (eg: charset=iso-8851) ; so let's get that... - while (*pos) - { - start = ++pos; - while ( *pos && *pos != '=' ) pos++; - - char *end = pos; - while ( *end && *end != ';' ) end++; - - if (*pos) - { - mediaAttribute = TQString::fromLatin1(start, pos-start).stripWhiteSpace().lower(); - mediaValue = TQString::fromLatin1(pos+1, end-pos-1).stripWhiteSpace(); - pos = end; - if (mediaValue.length() && - (mediaValue[0] == '"') && - (mediaValue[mediaValue.length()-1] == '"')) - mediaValue = mediaValue.mid(1, mediaValue.length()-2); - - kdDebug (7113) << "(" << m_pid << ") Media-Parameter Attribute: " - << mediaAttribute << endl; - kdDebug (7113) << "(" << m_pid << ") Media-Parameter Value: " - << mediaValue << endl; - - if ( mediaAttribute == "charset") - { - mediaValue = mediaValue.lower(); - m_request.strCharset = mediaValue; - } - else - { - setMetaData("media-"+mediaAttribute, mediaValue); - } - } - } - } - - // Date - else if (strncasecmp(buf, "Date:", 5) == 0) { - dateHeader = KRFCDate::parseDate(trimLead(buf+5)); - } - - // Cache management - else if (strncasecmp(buf, "ETag:", 5) == 0) { - m_request.etag = trimLead(buf+5); - } - - // Cache management - else if (strncasecmp(buf, "Expires:", 8) == 0) { - expireDate = KRFCDate::parseDate(trimLead(buf+8)); - if (!expireDate) - expireDate = 1; // Already expired - } - - // Cache management - else if (strncasecmp(buf, "Last-Modified:", 14) == 0) { - m_request.lastModified = (TQString::fromLatin1(trimLead(buf+14))).stripWhiteSpace(); - } - - // whoops.. we received a warning - else if (strncasecmp(buf, "Warning:", 8) == 0) { - //Don't use warning() here, no need to bother the user. - //Those warnings are mostly about caches. - infoMessage(trimLead(buf + 8)); - } - - // Cache management (HTTP 1.0) - else if (strncasecmp(buf, "Pragma:", 7) == 0) { - TQCString pragma = TQCString(trimLead(buf+7)).stripWhiteSpace().lower(); - if (pragma == "no-cache") - { - m_request.bCachedWrite = false; // Don't put in cache - mayCache = false; - hasCacheDirective = true; - } - } - - // The deprecated Refresh Response - else if (strncasecmp(buf,"Refresh:", 8) == 0) { - mayCache = false; // Do not cache page as it defeats purpose of Refresh tag! - setMetaData( "http-refresh", TQString::fromLatin1(trimLead(buf+8)).stripWhiteSpace() ); - } - - // In fact we should do redirection only if we got redirection code - else if (strncasecmp(buf, "Location:", 9) == 0) { - // Redirect only for 3xx status code, will ya! Thanks, pal! - if ( m_responseCode > 299 && m_responseCode < 400 ) - locationStr = TQCString(trimLead(buf+9)).stripWhiteSpace(); - } - - // Check for cookies - else if (strncasecmp(buf, "Set-Cookie", 10) == 0) { - cookieStr += buf; - cookieStr += '\n'; - } - - // check for direct authentication - else if (strncasecmp(buf, "WWW-Authenticate:", 17) == 0) { - configAuth(trimLead(buf + 17), false); - } - - // check for proxy-based authentication - else if (strncasecmp(buf, "Proxy-Authenticate:", 19) == 0) { - configAuth(trimLead(buf + 19), true); - } - - else if (strncasecmp(buf, "Upgrade:", 8) == 0) { - // Now we have to check to see what is offered for the upgrade - TQString offered = &(buf[8]); - upgradeOffers = TQStringList::split(TQRegExp("[ \n,\r\t]"), offered); - } - - // content? - else if (strncasecmp(buf, "Content-Encoding:", 17) == 0) { - // This is so wrong !! No wonder kio_http is stripping the - // gzip encoding from downloaded files. This solves multiple - // bug reports and caitoo's problem with downloads when such a - // header is encountered... - - // A quote from RFC 2616: - // " When present, its (Content-Encoding) value indicates what additional - // content have been applied to the entity body, and thus what decoding - // mechanism must be applied to obtain the media-type referenced by the - // Content-Type header field. Content-Encoding is primarily used to allow - // a document to be compressed without loosing the identity of its underlying - // media type. Simply put if it is specified, this is the actual mime-type - // we should use when we pull the resource !!! - addEncoding(trimLead(buf + 17), m_qContentEncodings); - } - // Refer to RFC 2616 sec 15.5/19.5.1 and RFC 2183 - else if(strncasecmp(buf, "Content-Disposition:", 20) == 0) { - char* dispositionBuf = trimLead(buf + 20); - while ( *dispositionBuf ) - { - if ( strncasecmp( dispositionBuf, "filename", 8 ) == 0 ) - { - dispositionBuf += 8; - - while ( *dispositionBuf == ' ' || *dispositionBuf == '=' ) - dispositionBuf++; - - char* bufStart = dispositionBuf; - - while ( *dispositionBuf && *dispositionBuf != ';' ) - dispositionBuf++; - - if ( dispositionBuf > bufStart ) - { - // Skip any leading quotes... - while ( *bufStart == '"' ) - bufStart++; - - // Skip any trailing quotes as well as white spaces... - while ( *(dispositionBuf-1) == ' ' || *(dispositionBuf-1) == '"') - dispositionBuf--; - - if ( dispositionBuf > bufStart ) - dispositionFilename = TQString::fromLatin1( bufStart, dispositionBuf-bufStart ); - - break; - } - } - else - { - char *bufStart = dispositionBuf; - - while ( *dispositionBuf && *dispositionBuf != ';' ) - dispositionBuf++; - - if ( dispositionBuf > bufStart ) - dispositionType = TQString::fromLatin1( bufStart, dispositionBuf-bufStart ).stripWhiteSpace(); - - while ( *dispositionBuf == ';' || *dispositionBuf == ' ' ) - dispositionBuf++; - } - } - - // Content-Dispostion is not allowed to dictate directory - // path, thus we extract the filename only. - if ( !dispositionFilename.isEmpty() ) - { - int pos = dispositionFilename.findRev( '/' ); - - if( pos > -1 ) - dispositionFilename = dispositionFilename.mid(pos+1); - - kdDebug(7113) << "(" << m_pid << ") Content-Disposition: filename=" - << dispositionFilename<< endl; - } - } - else if(strncasecmp(buf, "Content-Language:", 17) == 0) { - TQString language = TQString::fromLatin1(trimLead(buf+17)).stripWhiteSpace(); - if (!language.isEmpty()) - setMetaData("content-language", language); - } - else if (strncasecmp(buf, "Proxy-Connection:", 17) == 0) - { - if (strncasecmp(trimLead(buf + 17), "Close", 5) == 0) - m_bKeepAlive = false; - else if (strncasecmp(trimLead(buf + 17), "Keep-Alive", 10)==0) - m_bKeepAlive = true; - } - else if (strncasecmp(buf, "Link:", 5) == 0) { - // We only support Link: <url>; rel="type" so far - TQStringList link = TQStringList::split(";", TQString(buf) - .replace(TQRegExp("^Link:[ ]*"), - "")); - if (link.count() == 2) { - TQString rel = link[1].stripWhiteSpace(); - if (rel.startsWith("rel=\"")) { - rel = rel.mid(5, rel.length() - 6); - if (rel.lower() == "pageservices") { - TQString url = TQString(link[0].replace(TQRegExp("[<>]"),"")).stripWhiteSpace(); - setMetaData("PageServices", url); - } - } - } - } - else if (strncasecmp(buf, "P3P:", 4) == 0) { - TQString p3pstr = buf; - p3pstr = p3pstr.mid(4).simplifyWhiteSpace(); - TQStringList policyrefs, compact; - TQStringList policyfields = TQStringList::split(TQRegExp(",[ ]*"), p3pstr); - for (TQStringList::Iterator it = policyfields.begin(); - it != policyfields.end(); - ++it) { - TQStringList policy = TQStringList::split("=", *it); - - if (policy.count() == 2) { - if (policy[0].lower() == "policyref") { - policyrefs << TQString(policy[1].replace(TQRegExp("[\"\']"), "")) - .stripWhiteSpace(); - } else if (policy[0].lower() == "cp") { - // We convert to cp\ncp\ncp\n[...]\ncp to be consistent with - // other metadata sent in strings. This could be a bit more - // efficient but I'm going for correctness right now. - TQStringList cps = TQStringList::split(" ", - TQString(policy[1].replace(TQRegExp("[\"\']"), "")) - .simplifyWhiteSpace()); - - for (TQStringList::Iterator j = cps.begin(); j != cps.end(); ++j) - compact << *j; - } - } - } - - if (!policyrefs.isEmpty()) - setMetaData("PrivacyPolicy", policyrefs.join("\n")); - - if (!compact.isEmpty()) - setMetaData("PrivacyCompactPolicy", compact.join("\n")); - } - // let them tell us if we should stay alive or not - else if (strncasecmp(buf, "Connection:", 11) == 0) - { - if (strncasecmp(trimLead(buf + 11), "Close", 5) == 0) - m_bKeepAlive = false; - else if (strncasecmp(trimLead(buf + 11), "Keep-Alive", 10)==0) - m_bKeepAlive = true; - else if (strncasecmp(trimLead(buf + 11), "Upgrade", 7)==0) - { - if (m_responseCode == 101) { - // Ok, an upgrade was accepted, now we must do it - upgradeRequired = true; - } else if (upgradeRequired) { // 426 - // Nothing to do since we did it above already - } else { - // Just an offer to upgrade - no need to take it - canUpgrade = true; - } - } - } - // continue only if we know that we're HTTP/1.1 - else if ( httpRev == HTTP_11) { - // what kind of encoding do we have? transfer? - if (strncasecmp(buf, "Transfer-Encoding:", 18) == 0) { - // If multiple encodings have been applied to an entity, the - // transfer-codings MUST be listed in the order in which they - // were applied. - addEncoding(trimLead(buf + 18), m_qTransferEncodings); - } - - // md5 signature - else if (strncasecmp(buf, "Content-MD5:", 12) == 0) { - m_sContentMD5 = TQString::fromLatin1(trimLead(buf + 12)); - } - - // *** Responses to the HTTP OPTIONS method follow - // WebDAV capabilities - else if (strncasecmp(buf, "DAV:", 4) == 0) { - if (m_davCapabilities.isEmpty()) { - m_davCapabilities << TQString::fromLatin1(trimLead(buf + 4)); - } - else { - m_davCapabilities << TQString::fromLatin1(trimLead(buf + 4)); - } - } - // *** Responses to the HTTP OPTIONS method finished - } - else if ((httpRev == HTTP_None) && (strlen(buf) != 0)) - { - // Remote server does not seem to speak HTTP at all - // Put the crap back into the buffer and hope for the best - rewind(); - if (m_responseCode) - m_prevResponseCode = m_responseCode; - - m_responseCode = 200; // Fake it - httpRev = HTTP_Unknown; - m_bKeepAlive = false; - break; - } - setRewindMarker(); - - // Clear out our buffer for further use. - memset(buffer, 0, sizeof(buffer)); - - } while (!m_bEOF && (len || noHeader) && (headerSize < maxHeaderSize) && (gets(buffer, sizeof(buffer)-1))); - - // Now process the HTTP/1.1 upgrade - TQStringList::Iterator opt = upgradeOffers.begin(); - for( ; opt != upgradeOffers.end(); ++opt) { - if (*opt == "TLS/1.0") { - if(upgradeRequired) { - if (!startTLS() && !usingTLS()) { - error(ERR_UPGRADE_REQUIRED, *opt); - return false; - } - } - } else if (*opt == "HTTP/1.1") { - httpRev = HTTP_11; - } else { - // unknown - if (upgradeRequired) { - error(ERR_UPGRADE_REQUIRED, *opt); - return false; - } - } - } - - setMetaData("charset", m_request.strCharset); - - // If we do not support the requested authentication method... - if ( (m_responseCode == 401 && Authentication == AUTH_None) || - (m_responseCode == 407 && ProxyAuthentication == AUTH_None) ) - { - m_bUnauthorized = false; - if (m_request.bErrorPage) - errorPage(); - else - { - error( ERR_UNSUPPORTED_ACTION, "Unknown Authorization method!" ); - return false; - } - } - - // Fixup expire date for clock drift. - if (expireDate && (expireDate <= dateHeader)) - expireDate = 1; // Already expired. - - // Convert max-age into expireDate (overriding previous set expireDate) - if (maxAge == 0) - expireDate = 1; // Already expired. - else if (maxAge > 0) - { - if (currentAge) - maxAge -= currentAge; - if (maxAge <=0) - maxAge = 0; - expireDate = time(0) + maxAge; - } - - if (!expireDate) - { - time_t lastModifiedDate = 0; - if (!m_request.lastModified.isEmpty()) - lastModifiedDate = KRFCDate::parseDate(m_request.lastModified); - - if (lastModifiedDate) - { - long diff = static_cast<long>(difftime(dateHeader, lastModifiedDate)); - if (diff < 0) - expireDate = time(0) + 1; - else - expireDate = time(0) + (diff / 10); - } - else - { - expireDate = time(0) + DEFAULT_CACHE_EXPIRE; - } - } - - // DONE receiving the header! - if (!cookieStr.isEmpty()) - { - if ((m_request.cookieMode == HTTPRequest::CookiesAuto) && m_request.bUseCookiejar) - { - // Give cookies to the cookiejar. - TQString domain = config()->readEntry("cross-domain"); - if (!domain.isEmpty() && isCrossDomainRequest(m_request.url.host(), domain)) - cookieStr = "Cross-Domain\n" + cookieStr; - addCookies( m_request.url.url(), cookieStr ); - } - else if (m_request.cookieMode == HTTPRequest::CookiesManual) - { - // Pass cookie to application - setMetaData("setcookies", cookieStr); - } - } - - if (m_request.bMustRevalidate) - { - m_request.bMustRevalidate = false; // Reset just in case. - if (cacheValidated) - { - // Yippie, we can use the cached version. - // Update the cache with new "Expire" headers. - fclose(m_request.fcache); - m_request.fcache = 0; - updateExpireDate( expireDate, true ); - m_request.fcache = checkCacheEntry( ); // Re-read cache entry - - if (m_request.fcache) - { - m_request.bCachedRead = true; - goto try_again; // Read header again, but now from cache. - } - else - { - // Where did our cache entry go??? - } - } - else - { - // Validation failed. Close cache. - fclose(m_request.fcache); - m_request.fcache = 0; - } - } - - // We need to reread the header if we got a '100 Continue' or '102 Processing' - if ( cont ) - { - goto try_again; - } - - // Do not do a keep-alive connection if the size of the - // response is not known and the response is not Chunked. - if (!m_bChunked && (m_iSize == NO_SIZE)) - m_bKeepAlive = false; - - if ( m_responseCode == 204 ) - { - return true; - } - - // We need to try to login again if we failed earlier - if ( m_bUnauthorized ) - { - if ( (m_responseCode == 401) || - (m_bUseProxy && (m_responseCode == 407)) - ) - { - if ( getAuthorization() ) - { - // for NTLM Authentication we have to keep the connection open! - if ( Authentication == AUTH_NTLM && m_strAuthorization.length() > 4 ) - { - m_bKeepAlive = true; - readBody( true ); - } - else if (ProxyAuthentication == AUTH_NTLM && m_strProxyAuthorization.length() > 4) - { - readBody( true ); - } - else - httpCloseConnection(); - return false; // Try again. - } - - if (m_bError) - return false; // Error out - - // Show error page... - } - m_bUnauthorized = false; - } - - // We need to do a redirect - if (!locationStr.isEmpty()) - { - KURL u(m_request.url, locationStr); - if(!u.isValid()) - { - error(ERR_MALFORMED_URL, u.url()); - return false; - } - if ((u.protocol() != "http") && (u.protocol() != "https") && - (u.protocol() != "ftp") && (u.protocol() != "webdav") && - (u.protocol() != "webdavs")) - { - redirection(u); - error(ERR_ACCESS_DENIED, u.url()); - return false; - } - - // preserve #ref: (bug 124654) - // if we were at http://host/resource1#ref, we sent a GET for "/resource1" - // if we got redirected to http://host/resource2, then we have to re-add - // the fragment: - if (m_request.url.hasRef() && !u.hasRef() && - (m_request.url.host() == u.host()) && - (m_request.url.protocol() == u.protocol())) - u.setRef(m_request.url.ref()); - - m_bRedirect = true; - m_redirectLocation = u; - - if (!m_request.id.isEmpty()) - { - sendMetaData(); - } - - kdDebug(7113) << "(" << m_pid << ") request.url: " << m_request.url.url() - << endl << "LocationStr: " << locationStr.data() << endl; - - kdDebug(7113) << "(" << m_pid << ") Requesting redirection to: " << u.url() - << endl; - - // If we're redirected to a http:// url, remember that we're doing webdav... - if (m_protocol == "webdav" || m_protocol == "webdavs") - u.setProtocol(m_protocol); - - redirection(u); - m_request.bCachedWrite = false; // Turn off caching on re-direction (DA) - mayCache = false; - } - - // Inform the job that we can indeed resume... - if ( bCanResume && m_request.offset ) - canResume(); - else - m_request.offset = 0; - - // We don't cache certain text objects - if (m_strMimeType.startsWith("text/") && - (m_strMimeType != "text/css") && - (m_strMimeType != "text/x-javascript") && - !hasCacheDirective) - { - // Do not cache secure pages or pages - // originating from password protected sites - // unless the webserver explicitly allows it. - if ( m_bIsSSL || (Authentication != AUTH_None) ) - { - m_request.bCachedWrite = false; - mayCache = false; - } - } - - // WABA: Correct for tgz files with a gzip-encoding. - // They really shouldn't put gzip in the Content-Encoding field! - // Web-servers really shouldn't do this: They let Content-Size refer - // to the size of the tgz file, not to the size of the tar file, - // while the Content-Type refers to "tar" instead of "tgz". - if (m_qContentEncodings.last() == "gzip") - { - if (m_strMimeType == "application/x-tar") - { - m_qContentEncodings.remove(m_qContentEncodings.fromLast()); - m_strMimeType = TQString::fromLatin1("application/x-tgz"); - } - else if (m_strMimeType == "application/postscript") - { - // LEONB: Adding another exception for psgz files. - // Could we use the mimelnk files instead of hardcoding all this? - m_qContentEncodings.remove(m_qContentEncodings.fromLast()); - m_strMimeType = TQString::fromLatin1("application/x-gzpostscript"); - } - else if ( m_request.allowCompressedPage && - m_strMimeType != "application/x-tgz" && - m_strMimeType != "application/x-targz" && - m_strMimeType != "application/x-gzip" && - m_request.url.path().right(6) == ".ps.gz" ) - { - m_qContentEncodings.remove(m_qContentEncodings.fromLast()); - m_strMimeType = TQString::fromLatin1("application/x-gzpostscript"); - } - else if ( (m_request.allowCompressedPage && - m_strMimeType == "text/html") - || - (m_request.allowCompressedPage && - m_strMimeType != "application/x-tgz" && - m_strMimeType != "application/x-targz" && - m_strMimeType != "application/x-gzip" && - m_request.url.path().right(3) != ".gz") - ) - { - // Unzip! - } - else - { - m_qContentEncodings.remove(m_qContentEncodings.fromLast()); - m_strMimeType = TQString::fromLatin1("application/x-gzip"); - } - } - - // We can't handle "bzip2" encoding (yet). So if we get something with - // bzip2 encoding, we change the mimetype to "application/x-bzip2". - // Note for future changes: some web-servers send both "bzip2" as - // encoding and "application/x-bzip2" as mimetype. That is wrong. - // currently that doesn't bother us, because we remove the encoding - // and set the mimetype to x-bzip2 anyway. - if (m_qContentEncodings.last() == "bzip2") - { - m_qContentEncodings.remove(m_qContentEncodings.fromLast()); - m_strMimeType = TQString::fromLatin1("application/x-bzip2"); - } - - // Convert some common mimetypes to standard KDE mimetypes - if (m_strMimeType == "application/x-targz") - m_strMimeType = TQString::fromLatin1("application/x-tgz"); - else if (m_strMimeType == "application/zip") - m_strMimeType = TQString::fromLatin1("application/x-zip"); - else if (m_strMimeType == "image/x-png") - m_strMimeType = TQString::fromLatin1("image/png"); - else if (m_strMimeType == "image/bmp") - m_strMimeType = TQString::fromLatin1("image/x-bmp"); - else if (m_strMimeType == "audio/mpeg" || m_strMimeType == "audio/x-mpeg" || m_strMimeType == "audio/mp3") - m_strMimeType = TQString::fromLatin1("audio/x-mp3"); - else if (m_strMimeType == "audio/microsoft-wave") - m_strMimeType = TQString::fromLatin1("audio/x-wav"); - else if (m_strMimeType == "audio/midi") - m_strMimeType = TQString::fromLatin1("audio/x-midi"); - else if (m_strMimeType == "image/x-xpixmap") - m_strMimeType = TQString::fromLatin1("image/x-xpm"); - else if (m_strMimeType == "application/rtf") - m_strMimeType = TQString::fromLatin1("text/rtf"); - - // Crypto ones.... - else if (m_strMimeType == "application/pkix-cert" || - m_strMimeType == "application/binary-certificate") - { - m_strMimeType = TQString::fromLatin1("application/x-x509-ca-cert"); - } - - // Prefer application/x-tgz or x-gzpostscript over application/x-gzip. - else if (m_strMimeType == "application/x-gzip") - { - if ((m_request.url.path().right(7) == ".tar.gz") || - (m_request.url.path().right(4) == ".tar")) - m_strMimeType = TQString::fromLatin1("application/x-tgz"); - if ((m_request.url.path().right(6) == ".ps.gz")) - m_strMimeType = TQString::fromLatin1("application/x-gzpostscript"); - } - - // Some webservers say "text/plain" when they mean "application/x-bzip2" - else if ((m_strMimeType == "text/plain") || (m_strMimeType == "application/octet-stream")) - { - TQString ext = m_request.url.path().right(4).upper(); - if (ext == ".BZ2") - m_strMimeType = TQString::fromLatin1("application/x-bzip2"); - else if (ext == ".PEM") - m_strMimeType = TQString::fromLatin1("application/x-x509-ca-cert"); - else if (ext == ".SWF") - m_strMimeType = TQString::fromLatin1("application/x-shockwave-flash"); - else if (ext == ".PLS") - m_strMimeType = TQString::fromLatin1("audio/x-scpls"); - else if (ext == ".WMV") - m_strMimeType = TQString::fromLatin1("video/x-ms-wmv"); - } - -#if 0 - // Even if we can't rely on content-length, it seems that we should - // never get more data than content-length. Maybe less, if the - // content-length refers to the unzipped data. - if (!m_qContentEncodings.isEmpty()) - { - // If we still have content encoding we can't rely on the Content-Length. - m_iSize = NO_SIZE; - } -#endif - - if( !dispositionType.isEmpty() ) - { - kdDebug(7113) << "(" << m_pid << ") Setting Content-Disposition type to: " - << dispositionType << endl; - setMetaData("content-disposition-type", dispositionType); - } - if( !dispositionFilename.isEmpty() ) - { - kdDebug(7113) << "(" << m_pid << ") Setting Content-Disposition filename to: " - << dispositionFilename << endl; - // ### KDE4: setting content-disposition to filename for pre 3.5.2 compatability - setMetaData("content-disposition", dispositionFilename); - setMetaData("content-disposition-filename", dispositionFilename); - } - - if (!m_request.lastModified.isEmpty()) - setMetaData("modified", m_request.lastModified); - - if (!mayCache) - { - setMetaData("no-cache", "true"); - setMetaData("expire-date", "1"); // Expired - } - else - { - TQString tmp; - tmp.setNum(expireDate); - setMetaData("expire-date", tmp); - tmp.setNum(time(0)); // Cache entry will be created shortly. - setMetaData("cache-creation-date", tmp); - } - - // Let the app know about the mime-type iff this is not - // a redirection and the mime-type string is not empty. - if (locationStr.isEmpty() && (!m_strMimeType.isEmpty() || - m_request.method == HTTP_HEAD)) - { - kdDebug(7113) << "(" << m_pid << ") Emitting mimetype " << m_strMimeType << endl; - mimeType( m_strMimeType ); - } - - // Do not move send response header before any redirection as it seems - // to screw up some sites. See BR# 150904. - forwardHttpResponseHeader(); - - if (m_request.method == HTTP_HEAD) - return true; - - // Do we want to cache this request? - if (m_request.bUseCache) - { - ::unlink( TQFile::encodeName(m_request.cef)); - if ( m_request.bCachedWrite && !m_strMimeType.isEmpty() ) - { - // Check... - createCacheEntry(m_strMimeType, expireDate); // Create a cache entry - if (!m_request.fcache) - { - m_request.bCachedWrite = false; // Error creating cache entry. - kdDebug(7113) << "(" << m_pid << ") Error creating cache entry for " << m_request.url.url()<<"!\n"; - } - m_request.expireDate = expireDate; - m_maxCacheSize = config()->readNumEntry("MaxCacheSize", DEFAULT_MAX_CACHE_SIZE) / 2; - } - } - - if (m_request.bCachedWrite && !m_strMimeType.isEmpty()) - kdDebug(7113) << "(" << m_pid << ") Cache, adding \"" << m_request.url.url() << "\"" << endl; - else if (m_request.bCachedWrite && m_strMimeType.isEmpty()) - kdDebug(7113) << "(" << m_pid << ") Cache, pending \"" << m_request.url.url() << "\"" << endl; - else - kdDebug(7113) << "(" << m_pid << ") Cache, not adding \"" << m_request.url.url() << "\"" << endl; - return true; -} - - -void HTTPProtocol::addEncoding(TQString encoding, TQStringList &encs) -{ - encoding = encoding.stripWhiteSpace().lower(); - // Identity is the same as no encoding - if (encoding == "identity") { - return; - } else if (encoding == "8bit") { - // Strange encoding returned by http://linac.ikp.physik.tu-darmstadt.de - return; - } else if (encoding == "chunked") { - m_bChunked = true; - // Anyone know of a better way to handle unknown sizes possibly/ideally with unsigned ints? - //if ( m_cmd != CMD_COPY ) - m_iSize = NO_SIZE; - } else if ((encoding == "x-gzip") || (encoding == "gzip")) { - encs.append(TQString::fromLatin1("gzip")); - } else if ((encoding == "x-bzip2") || (encoding == "bzip2")) { - encs.append(TQString::fromLatin1("bzip2")); // Not yet supported! - } else if ((encoding == "x-deflate") || (encoding == "deflate")) { - encs.append(TQString::fromLatin1("deflate")); - } else { - kdDebug(7113) << "(" << m_pid << ") Unknown encoding encountered. " - << "Please write code. Encoding = \"" << encoding - << "\"" << endl; - } -} - -bool HTTPProtocol::sendBody() -{ - int result=-1; - int length=0; - - infoMessage( i18n( "Requesting data to send" ) ); - - // m_bufPOST will NOT be empty iff authentication was required before posting - // the data OR a re-connect is requested from ::readHeader because the - // connection was lost for some reason. - if ( !m_bufPOST.isNull() ) - { - kdDebug(7113) << "(" << m_pid << ") POST'ing saved data..." << endl; - - result = 0; - length = m_bufPOST.size(); - } - else - { - kdDebug(7113) << "(" << m_pid << ") POST'ing live data..." << endl; - - TQByteArray buffer; - int old_size; - - m_bufPOST.resize(0); - do - { - dataReq(); // Request for data - result = readData( buffer ); - if ( result > 0 ) - { - length += result; - old_size = m_bufPOST.size(); - m_bufPOST.resize( old_size+result ); - memcpy( m_bufPOST.data()+ old_size, buffer.data(), buffer.size() ); - buffer.resize(0); - } - } while ( result > 0 ); - } - - if ( result < 0 ) - { - error( ERR_ABORTED, m_request.hostname ); - return false; - } - - infoMessage( i18n( "Sending data to %1" ).arg( m_request.hostname ) ); - - TQString size = TQString ("Content-Length: %1\r\n\r\n").arg(length); - kdDebug( 7113 ) << "(" << m_pid << ")" << size << endl; - - // Send the content length... - bool sendOk = (write(size.latin1(), size.length()) == (ssize_t) size.length()); - if (!sendOk) - { - kdDebug( 7113 ) << "(" << m_pid << ") Connection broken when sending " - << "content length: (" << m_state.hostname << ")" << endl; - error( ERR_CONNECTION_BROKEN, m_state.hostname ); - return false; - } - - // Send the data... - // kdDebug( 7113 ) << "(" << m_pid << ") POST DATA: " << TQCString(m_bufPOST) << endl; - sendOk = (write(m_bufPOST.data(), m_bufPOST.size()) == (ssize_t) m_bufPOST.size()); - if (!sendOk) - { - kdDebug(7113) << "(" << m_pid << ") Connection broken when sending message body: (" - << m_state.hostname << ")" << endl; - error( ERR_CONNECTION_BROKEN, m_state.hostname ); - return false; - } - - return true; -} - -void HTTPProtocol::httpClose( bool keepAlive ) -{ - kdDebug(7113) << "(" << m_pid << ") HTTPProtocol::httpClose" << endl; - - if (m_request.fcache) - { - fclose(m_request.fcache); - m_request.fcache = 0; - if (m_request.bCachedWrite) - { - TQString filename = m_request.cef + ".new"; - ::unlink( TQFile::encodeName(filename) ); - } - } - - // Only allow persistent connections for GET requests. - // NOTE: we might even want to narrow this down to non-form - // based submit requests which will require a meta-data from - // tdehtml. - if (keepAlive && (!m_bUseProxy || - m_bPersistentProxyConnection || m_bIsTunneled)) - { - if (!m_keepAliveTimeout) - m_keepAliveTimeout = DEFAULT_KEEP_ALIVE_TIMEOUT; - else if (m_keepAliveTimeout > 2*DEFAULT_KEEP_ALIVE_TIMEOUT) - m_keepAliveTimeout = 2*DEFAULT_KEEP_ALIVE_TIMEOUT; - - kdDebug(7113) << "(" << m_pid << ") HTTPProtocol::httpClose: keep alive (" << m_keepAliveTimeout << ")" << endl; - TQByteArray data; - TQDataStream stream( data, IO_WriteOnly ); - stream << int(99); // special: Close connection - setTimeoutSpecialCommand(m_keepAliveTimeout, data); - return; - } - - httpCloseConnection(); -} - -void HTTPProtocol::closeConnection() -{ - kdDebug(7113) << "(" << m_pid << ") HTTPProtocol::closeConnection" << endl; - httpCloseConnection (); -} - -void HTTPProtocol::httpCloseConnection () -{ - kdDebug(7113) << "(" << m_pid << ") HTTPProtocol::httpCloseConnection" << endl; - m_bIsTunneled = false; - m_bKeepAlive = false; - closeDescriptor(); - setTimeoutSpecialCommand(-1); // Cancel any connection timeout -} - -void HTTPProtocol::slave_status() -{ - kdDebug(7113) << "(" << m_pid << ") HTTPProtocol::slave_status" << endl; - - if ( m_iSock != -1 && !isConnectionValid() ) - httpCloseConnection(); - - slaveStatus( m_state.hostname, (m_iSock != -1) ); -} - -void HTTPProtocol::mimetype( const KURL& url ) -{ - kdDebug(7113) << "(" << m_pid << ") HTTPProtocol::mimetype: " - << url.prettyURL() << endl; - - if ( !checkRequestURL( url ) ) - return; - - m_request.method = HTTP_HEAD; - m_request.path = url.path(); - m_request.query = url.query(); - m_request.cache = CC_Cache; - m_request.doProxy = m_bUseProxy; - - retrieveHeader(); - - kdDebug(7113) << "(" << m_pid << ") http: mimetype = " << m_strMimeType - << endl; -} - -void HTTPProtocol::special( const TQByteArray &data ) -{ - kdDebug(7113) << "(" << m_pid << ") HTTPProtocol::special" << endl; - - int tmp; - TQDataStream stream(data, IO_ReadOnly); - - stream >> tmp; - switch (tmp) { - case 1: // HTTP POST - { - KURL url; - stream >> url; - post( url ); - break; - } - case 2: // cache_update - { - KURL url; - bool no_cache; - time_t expireDate; - stream >> url >> no_cache >> expireDate; - cacheUpdate( url, no_cache, expireDate ); - break; - } - case 5: // WebDAV lock - { - KURL url; - TQString scope, type, owner; - stream >> url >> scope >> type >> owner; - davLock( url, scope, type, owner ); - break; - } - case 6: // WebDAV unlock - { - KURL url; - stream >> url; - davUnlock( url ); - break; - } - case 7: // Generic WebDAV - { - KURL url; - int method; - stream >> url >> method; - davGeneric( url, (TDEIO::HTTP_METHOD) method ); - break; - } - case 99: // Close Connection - { - httpCloseConnection(); - break; - } - default: - // Some command we don't understand. - // Just ignore it, it may come from some future version of KDE. - break; - } -} - -/** - * Read a chunk from the data stream. - */ -int HTTPProtocol::readChunked() -{ - if ((m_iBytesLeft == 0) || (m_iBytesLeft == NO_SIZE)) - { - setRewindMarker(); - - m_bufReceive.resize(4096); - - if (!gets(m_bufReceive.data(), m_bufReceive.size()-1)) - { - kdDebug(7113) << "(" << m_pid << ") gets() failure on Chunk header" << endl; - return -1; - } - // We could have got the CRLF of the previous chunk. - // If so, try again. - if (m_bufReceive[0] == '\0') - { - if (!gets(m_bufReceive.data(), m_bufReceive.size()-1)) - { - kdDebug(7113) << "(" << m_pid << ") gets() failure on Chunk header" << endl; - return -1; - } - } - - // m_bEOF is set to true when read called from gets returns 0. For chunked reading 0 - // means end of chunked transfer and not error. See RFC 2615 section 3.6.1 - #if 0 - if (m_bEOF) - { - kdDebug(7113) << "(" << m_pid << ") EOF on Chunk header" << endl; - return -1; - } - #endif - - long long trunkSize = STRTOLL(m_bufReceive.data(), 0, 16); - if (trunkSize < 0) - { - kdDebug(7113) << "(" << m_pid << ") Negative chunk size" << endl; - return -1; - } - m_iBytesLeft = trunkSize; - - // kdDebug(7113) << "(" << m_pid << ") Chunk size = " << m_iBytesLeft << " bytes" << endl; - - if (m_iBytesLeft == 0) - { - // Last chunk. - // Skip trailers. - do { - // Skip trailer of last chunk. - if (!gets(m_bufReceive.data(), m_bufReceive.size()-1)) - { - kdDebug(7113) << "(" << m_pid << ") gets() failure on Chunk trailer" << endl; - return -1; - } - // kdDebug(7113) << "(" << m_pid << ") Chunk trailer = \"" << m_bufReceive.data() << "\"" << endl; - } - while (strlen(m_bufReceive.data()) != 0); - - return 0; - } - } - - int bytesReceived = readLimited(); - if (!m_iBytesLeft) - m_iBytesLeft = NO_SIZE; // Don't stop, continue with next chunk - - // kdDebug(7113) << "(" << m_pid << ") readChunked: BytesReceived=" << bytesReceived << endl; - return bytesReceived; -} - -int HTTPProtocol::readLimited() -{ - if (!m_iBytesLeft) - return 0; - - m_bufReceive.resize(4096); - - int bytesReceived; - int bytesToReceive; - - if (m_iBytesLeft > m_bufReceive.size()) - bytesToReceive = m_bufReceive.size(); - else - bytesToReceive = m_iBytesLeft; - - bytesReceived = read(m_bufReceive.data(), bytesToReceive); - - if (bytesReceived <= 0) - return -1; // Error: connection lost - - m_iBytesLeft -= bytesReceived; - return bytesReceived; -} - -int HTTPProtocol::readUnlimited() -{ - if (m_bKeepAlive) - { - kdDebug(7113) << "(" << m_pid << ") Unbounded datastream on a Keep " - << "alive connection!" << endl; - m_bKeepAlive = false; - } - - m_bufReceive.resize(4096); - - int result = read(m_bufReceive.data(), m_bufReceive.size()); - if (result > 0) - return result; - - m_bEOF = true; - m_iBytesLeft = 0; - return 0; -} - -void HTTPProtocol::slotData(const TQByteArray &_d) -{ - if (!_d.size()) - { - m_bEOD = true; - return; - } - - if (m_iContentLeft != NO_SIZE) - { - if (m_iContentLeft >= _d.size()) - m_iContentLeft -= _d.size(); - else - m_iContentLeft = NO_SIZE; - } - - TQByteArray d = _d; - if ( !m_dataInternal ) - { - // If a broken server does not send the mime-type, - // we try to id it from the content before dealing - // with the content itself. - if ( m_strMimeType.isEmpty() && !m_bRedirect && - !( m_responseCode >= 300 && m_responseCode <=399) ) - { - kdDebug(7113) << "(" << m_pid << ") Determining mime-type from content..." << endl; - int old_size = m_mimeTypeBuffer.size(); - m_mimeTypeBuffer.resize( old_size + d.size() ); - memcpy( m_mimeTypeBuffer.data() + old_size, d.data(), d.size() ); - if ( (m_iBytesLeft != NO_SIZE) && (m_iBytesLeft > 0) - && (m_mimeTypeBuffer.size() < 1024) ) - { - m_cpMimeBuffer = true; - return; // Do not send up the data since we do not yet know its mimetype! - } - - kdDebug(7113) << "(" << m_pid << ") Mimetype buffer size: " << m_mimeTypeBuffer.size() - << endl; - - KMimeMagicResult *result; - result = KMimeMagic::self()->findBufferFileType( m_mimeTypeBuffer, - m_request.url.fileName() ); - if( result ) - { - m_strMimeType = result->mimeType(); - kdDebug(7113) << "(" << m_pid << ") Mimetype from content: " - << m_strMimeType << endl; - } - - if ( m_strMimeType.isEmpty() ) - { - m_strMimeType = TQString::fromLatin1( DEFAULT_MIME_TYPE ); - kdDebug(7113) << "(" << m_pid << ") Using default mimetype: " - << m_strMimeType << endl; - } - - if ( m_request.bCachedWrite ) - { - createCacheEntry( m_strMimeType, m_request.expireDate ); - if (!m_request.fcache) - m_request.bCachedWrite = false; - } - - if ( m_cpMimeBuffer ) - { - // Do not make any assumption about the state of the TQByteArray we received. - // Fix the crash described by BR# 130104. - d.detach(); - d.resize(0); - d.resize(m_mimeTypeBuffer.size()); - memcpy( d.data(), m_mimeTypeBuffer.data(), - d.size() ); - } - mimeType(m_strMimeType); - m_mimeTypeBuffer.resize(0); - } - - data( d ); - if (m_request.bCachedWrite && m_request.fcache) - writeCacheEntry(d.data(), d.size()); - } - else - { - uint old_size = m_bufWebDavData.size(); - m_bufWebDavData.resize (old_size + d.size()); - memcpy (m_bufWebDavData.data() + old_size, d.data(), d.size()); - } -} - -/** - * This function is our "receive" function. It is responsible for - * downloading the message (not the header) from the HTTP server. It - * is called either as a response to a client's TDEIOJob::dataEnd() - * (meaning that the client is done sending data) or by 'httpOpen()' - * (if we are in the process of a PUT/POST request). It can also be - * called by a webDAV function, to receive stat/list/property/etc. - * data; in this case the data is stored in m_bufWebDavData. - */ -bool HTTPProtocol::readBody( bool dataInternal /* = false */ ) -{ - if (m_responseCode == 204) - return true; - - m_bEOD = false; - // Note that when dataInternal is true, we are going to: - // 1) save the body data to a member variable, m_bufWebDavData - // 2) _not_ advertise the data, speed, size, etc., through the - // corresponding functions. - // This is used for returning data to WebDAV. - m_dataInternal = dataInternal; - if ( dataInternal ) - m_bufWebDavData.resize (0); - - // Check if we need to decode the data. - // If we are in copy mode, then use only transfer decoding. - bool useMD5 = !m_sContentMD5.isEmpty(); - - // Deal with the size of the file. - TDEIO::filesize_t sz = m_request.offset; - if ( sz ) - m_iSize += sz; - - // Update the application with total size except when - // it is compressed, or when the data is to be handled - // internally (webDAV). If compressed we have to wait - // until we uncompress to find out the actual data size - if ( !dataInternal ) { - if ( (m_iSize > 0) && (m_iSize != NO_SIZE)) { - totalSize(m_iSize); - infoMessage( i18n( "Retrieving %1 from %2...").arg(TDEIO::convertSize(m_iSize)) - .arg( m_request.hostname ) ); - } - else - { - totalSize ( 0 ); - } - } - else - infoMessage( i18n( "Retrieving from %1..." ).arg( m_request.hostname ) ); - - if (m_request.bCachedRead) - { - kdDebug(7113) << "(" << m_pid << ") HTTPProtocol::readBody: read data from cache!" << endl; - m_request.bCachedWrite = false; - - char buffer[ MAX_IPC_SIZE ]; - - m_iContentLeft = NO_SIZE; - - // Jippie! It's already in the cache :-) - while (!feof(m_request.fcache) && !ferror(m_request.fcache)) - { - int nbytes = fread( buffer, 1, MAX_IPC_SIZE, m_request.fcache); - - if (nbytes > 0) - { - m_bufReceive.setRawData( buffer, nbytes); - slotData( m_bufReceive ); - m_bufReceive.resetRawData( buffer, nbytes ); - sz += nbytes; - } - } - - m_bufReceive.resize( 0 ); - - if ( !dataInternal ) - { - processedSize( sz ); - data( TQByteArray() ); - } - - return true; - } - - - if (m_iSize != NO_SIZE) - m_iBytesLeft = m_iSize - sz; - else - m_iBytesLeft = NO_SIZE; - - m_iContentLeft = m_iBytesLeft; - - if (m_bChunked) - m_iBytesLeft = NO_SIZE; - - kdDebug(7113) << "(" << m_pid << ") HTTPProtocol::readBody: retrieve data. " - << TDEIO::number(m_iBytesLeft) << " left." << endl; - - // Main incoming loop... Gather everything while we can... - m_cpMimeBuffer = false; - m_mimeTypeBuffer.resize(0); - struct timeval last_tv; - gettimeofday( &last_tv, 0L ); - - HTTPFilterChain chain; - - TQObject::connect(&chain, TQT_SIGNAL(output(const TQByteArray &)), - this, TQT_SLOT(slotData(const TQByteArray &))); - TQObject::connect(&chain, TQT_SIGNAL(error(int, const TQString &)), - this, TQT_SLOT(error(int, const TQString &))); - - // decode all of the transfer encodings - while (!m_qTransferEncodings.isEmpty()) - { - TQString enc = m_qTransferEncodings.last(); - m_qTransferEncodings.remove(m_qTransferEncodings.fromLast()); - if ( enc == "gzip" ) - chain.addFilter(new HTTPFilterGZip); - else if ( enc == "deflate" ) - chain.addFilter(new HTTPFilterDeflate); - } - - // From HTTP 1.1 Draft 6: - // The MD5 digest is computed based on the content of the entity-body, - // including any content-coding that has been applied, but not including - // any transfer-encoding applied to the message-body. If the message is - // received with a transfer-encoding, that encoding MUST be removed - // prior to checking the Content-MD5 value against the received entity. - HTTPFilterMD5 *md5Filter = 0; - if ( useMD5 ) - { - md5Filter = new HTTPFilterMD5; - chain.addFilter(md5Filter); - } - - // now decode all of the content encodings - // -- Why ?? We are not - // -- a proxy server, be a client side implementation!! The applications - // -- are capable of determinig how to extract the encoded implementation. - // WB: That's a misunderstanding. We are free to remove the encoding. - // WB: Some braindead www-servers however, give .tgz files an encoding - // WB: of "gzip" (or even "x-gzip") and a content-type of "applications/tar" - // WB: They shouldn't do that. We can work around that though... - while (!m_qContentEncodings.isEmpty()) - { - TQString enc = m_qContentEncodings.last(); - m_qContentEncodings.remove(m_qContentEncodings.fromLast()); - if ( enc == "gzip" ) - chain.addFilter(new HTTPFilterGZip); - else if ( enc == "deflate" ) - chain.addFilter(new HTTPFilterDeflate); - } - - while (!m_bEOF) - { - int bytesReceived; - - if (m_bChunked) - bytesReceived = readChunked(); - else if (m_iSize != NO_SIZE) - bytesReceived = readLimited(); - else - bytesReceived = readUnlimited(); - - // make sure that this wasn't an error, first - // kdDebug(7113) << "(" << (int) m_pid << ") readBody: bytesReceived: " - // << (int) bytesReceived << " m_iSize: " << (int) m_iSize << " Chunked: " - // << (int) m_bChunked << " BytesLeft: "<< (int) m_iBytesLeft << endl; - if (bytesReceived == -1) - { - if (m_iContentLeft == 0) - { - // gzip'ed data sometimes reports a too long content-length. - // (The length of the unzipped data) - m_iBytesLeft = 0; - break; - } - // Oh well... log an error and bug out - kdDebug(7113) << "(" << m_pid << ") readBody: bytesReceived==-1 sz=" << (int)sz - << " Connnection broken !" << endl; - error(ERR_CONNECTION_BROKEN, m_state.hostname); - return false; - } - - // I guess that nbytes == 0 isn't an error.. but we certainly - // won't work with it! - if (bytesReceived > 0) - { - // Important: truncate the buffer to the actual size received! - // Otherwise garbage will be passed to the app - m_bufReceive.truncate( bytesReceived ); - - chain.slotInput(m_bufReceive); - - if (m_bError) - return false; - - sz += bytesReceived; - if (!dataInternal) - processedSize( sz ); - } - m_bufReceive.resize(0); // res - - if (m_iBytesLeft && m_bEOD && !m_bChunked) - { - // gzip'ed data sometimes reports a too long content-length. - // (The length of the unzipped data) - m_iBytesLeft = 0; - } - - if (m_iBytesLeft == 0) - { - kdDebug(7113) << "("<<m_pid<<") EOD received! Left = "<< TDEIO::number(m_iBytesLeft) << endl; - break; - } - } - chain.slotInput(TQByteArray()); // Flush chain. - - if ( useMD5 ) - { - TQString calculatedMD5 = md5Filter->md5(); - - if ( m_sContentMD5 == calculatedMD5 ) - kdDebug(7113) << "(" << m_pid << ") MD5 checksum MATCHED!!" << endl; - else - kdDebug(7113) << "(" << m_pid << ") MD5 checksum MISMATCH! Expected: " - << calculatedMD5 << ", Got: " << m_sContentMD5 << endl; - } - - // Close cache entry - if (m_iBytesLeft == 0) - { - if (m_request.bCachedWrite && m_request.fcache) - closeCacheEntry(); - else if (m_request.bCachedWrite) - kdDebug(7113) << "(" << m_pid << ") no cache file!\n"; - } - else - { - kdDebug(7113) << "(" << m_pid << ") still "<< TDEIO::number(m_iBytesLeft) - << " bytes left! can't close cache entry!\n"; - } - - if (sz <= 1) - { - /* kdDebug(7113) << "(" << m_pid << ") readBody: sz = " << TDEIO::number(sz) - << ", responseCode =" << m_responseCode << endl; */ - if (m_responseCode >= 500 && m_responseCode <= 599) - error(ERR_INTERNAL_SERVER, m_state.hostname); - else if (m_responseCode >= 400 && m_responseCode <= 499) - error(ERR_DOES_NOT_EXIST, m_state.hostname); - } - - if (!dataInternal) - data( TQByteArray() ); - - return true; -} - - -void HTTPProtocol::error( int _err, const TQString &_text ) -{ - httpClose(false); - - if (!m_request.id.isEmpty()) - { - forwardHttpResponseHeader(); - sendMetaData(); - } - - // Clear of the temporary POST buffer if it is not empty... - if (!m_bufPOST.isEmpty()) - { - m_bufPOST.resize(0); - kdDebug(7113) << "(" << m_pid << ") HTTP::retreiveHeader: Cleared POST " - "buffer..." << endl; - } - - SlaveBase::error( _err, _text ); - m_bError = true; -} - - -void HTTPProtocol::addCookies( const TQString &url, const TQCString &cookieHeader ) -{ - long windowId = m_request.window.toLong(); - TQByteArray params; - TQDataStream stream(params, IO_WriteOnly); - stream << url << cookieHeader << windowId; - - kdDebug(7113) << "(" << m_pid << ") " << cookieHeader << endl; - kdDebug(7113) << "(" << m_pid << ") " << "Window ID: " - << windowId << ", for host = " << url << endl; - - if ( !dcopClient()->send( "kded", "kcookiejar", "addCookies(TQString,TQCString,long int)", params ) ) - { - kdWarning(7113) << "(" << m_pid << ") Can't communicate with kded_kcookiejar!" << endl; - } -} - -TQString HTTPProtocol::findCookies( const TQString &url) -{ - TQCString replyType; - TQByteArray params; - TQByteArray reply; - TQString result; - - long windowId = m_request.window.toLong(); - result = TQString::null; - TQDataStream stream(params, IO_WriteOnly); - stream << url << windowId; - - if ( !dcopClient()->call( "kded", "kcookiejar", "findCookies(TQString,long int)", - params, replyType, reply ) ) - { - kdWarning(7113) << "(" << m_pid << ") Can't communicate with kded_kcookiejar!" << endl; - return result; - } - if ( replyType == "TQString" ) - { - TQDataStream stream2( reply, IO_ReadOnly ); - stream2 >> result; - } - else - { - kdError(7113) << "(" << m_pid << ") DCOP function findCookies(...) returns " - << replyType << ", expected TQString" << endl; - } - return result; -} - -/******************************* CACHING CODE ****************************/ - - -void HTTPProtocol::cacheUpdate( const KURL& url, bool no_cache, time_t expireDate) -{ - if ( !checkRequestURL( url ) ) - return; - - m_request.path = url.path(); - m_request.query = url.query(); - m_request.cache = CC_Reload; - m_request.doProxy = m_bUseProxy; - - if (no_cache) - { - m_request.fcache = checkCacheEntry( ); - if (m_request.fcache) - { - fclose(m_request.fcache); - m_request.fcache = 0; - ::unlink( TQFile::encodeName(m_request.cef) ); - } - } - else - { - updateExpireDate( expireDate ); - } - finished(); -} - -// !START SYNC! -// The following code should be kept in sync -// with the code in http_cache_cleaner.cpp - -FILE* HTTPProtocol::checkCacheEntry( bool readWrite) -{ - const TQChar separator = '_'; - - TQString CEF = m_request.path; - - int p = CEF.find('/'); - - while(p != -1) - { - CEF[p] = separator; - p = CEF.find('/', p); - } - - TQString host = m_request.hostname.lower(); - CEF = host + CEF + '_'; - - TQString dir = m_strCacheDir; - if (dir[dir.length()-1] != '/') - dir += "/"; - - int l = host.length(); - for(int i = 0; i < l; i++) - { - if (host[i].isLetter() && (host[i] != 'w')) - { - dir += host[i]; - break; - } - } - if (dir[dir.length()-1] == '/') - dir += "0"; - - unsigned long hash = 0x00000000; - TQCString u = m_request.url.url().latin1(); - for(int i = u.length(); i--;) - { - hash = (hash * 12211 + static_cast<const char>(u.at(i))) % 2147483563; - } - - TQString hashString; - hashString.sprintf("%08lx", hash); - - CEF = CEF + hashString; - - CEF = dir + "/" + CEF; - - m_request.cef = CEF; - - const char *mode = (readWrite ? "r+" : "r"); - - FILE *fs = fopen( TQFile::encodeName(CEF), mode); // Open for reading and writing - if (!fs) - return 0; - - char buffer[401]; - bool ok = true; - - // CacheRevision - if (ok && (!fgets(buffer, 400, fs))) - ok = false; - if (ok && (strcmp(buffer, CACHE_REVISION) != 0)) - ok = false; - - time_t date; - time_t currentDate = time(0); - - // URL - if (ok && (!fgets(buffer, 400, fs))) - ok = false; - if (ok) - { - int l = strlen(buffer); - if (l>0) - buffer[l-1] = 0; // Strip newline - if (m_request.url.url() != buffer) - { - ok = false; // Hash collision - } - } - - // Creation Date - if (ok && (!fgets(buffer, 400, fs))) - ok = false; - if (ok) - { - date = (time_t) strtoul(buffer, 0, 10); - m_request.creationDate = date; - if (m_maxCacheAge && (difftime(currentDate, date) > m_maxCacheAge)) - { - m_request.bMustRevalidate = true; - m_request.expireDate = currentDate; - } - } - - // Expiration Date - m_request.cacheExpireDateOffset = ftell(fs); - if (ok && (!fgets(buffer, 400, fs))) - ok = false; - if (ok) - { - if (m_request.cache == CC_Verify) - { - date = (time_t) strtoul(buffer, 0, 10); - // After the expire date we need to revalidate. - if (!date || difftime(currentDate, date) >= 0) - m_request.bMustRevalidate = true; - m_request.expireDate = date; - } - else if (m_request.cache == CC_Refresh) - { - m_request.bMustRevalidate = true; - m_request.expireDate = currentDate; - } - } - - // ETag - if (ok && (!fgets(buffer, 400, fs))) - ok = false; - if (ok) - { - m_request.etag = TQString(buffer).stripWhiteSpace(); - } - - // Last-Modified - if (ok && (!fgets(buffer, 400, fs))) - ok = false; - if (ok) - { - m_request.lastModified = TQString(buffer).stripWhiteSpace(); - } - - if (ok) - return fs; - - fclose(fs); - unlink( TQFile::encodeName(CEF)); - return 0; -} - -void HTTPProtocol::updateExpireDate(time_t expireDate, bool updateCreationDate) -{ - bool ok = true; - - FILE *fs = checkCacheEntry(true); - if (fs) - { - TQString date; - char buffer[401]; - time_t creationDate; - - fseek(fs, 0, SEEK_SET); - if (ok && !fgets(buffer, 400, fs)) - ok = false; - if (ok && !fgets(buffer, 400, fs)) - ok = false; - long cacheCreationDateOffset = ftell(fs); - if (ok && !fgets(buffer, 400, fs)) - ok = false; - creationDate = strtoul(buffer, 0, 10); - if (!creationDate) - ok = false; - - if (updateCreationDate) - { - if (!ok || fseek(fs, cacheCreationDateOffset, SEEK_SET)) - return; - TQString date; - date.setNum( time(0) ); - date = date.leftJustify(16); - fputs(date.latin1(), fs); // Creation date - fputc('\n', fs); - } - - if (expireDate>(30*365*24*60*60)) - { - // expire date is a really a big number, it can't be - // a relative date. - date.setNum( expireDate ); - } - else - { - // expireDate before 2000. those values must be - // interpreted as relative expiration dates from - // <META http-equiv="Expires"> tags. - // so we have to scan the creation time and add - // it to the expiryDate - date.setNum( creationDate + expireDate ); - } - date = date.leftJustify(16); - if (!ok || fseek(fs, m_request.cacheExpireDateOffset, SEEK_SET)) - return; - fputs(date.latin1(), fs); // Expire date - fseek(fs, 0, SEEK_END); - fclose(fs); - } -} - -void HTTPProtocol::createCacheEntry( const TQString &mimetype, time_t expireDate) -{ - TQString dir = m_request.cef; - int p = dir.findRev('/'); - if (p == -1) return; // Error. - dir.truncate(p); - - // Create file - (void) ::mkdir( TQFile::encodeName(dir), 0700 ); - - TQString filename = m_request.cef + ".new"; // Create a new cache entryexpireDate - -// kdDebug( 7103 ) << "creating new cache entry: " << filename << endl; - - m_request.fcache = fopen( TQFile::encodeName(filename), "w"); - if (!m_request.fcache) - { - kdWarning(7113) << "(" << m_pid << ")createCacheEntry: opening " << filename << " failed." << endl; - return; // Error. - } - - fputs(CACHE_REVISION, m_request.fcache); // Revision - - fputs(m_request.url.url().latin1(), m_request.fcache); // Url - fputc('\n', m_request.fcache); - - TQString date; - m_request.creationDate = time(0); - date.setNum( m_request.creationDate ); - date = date.leftJustify(16); - fputs(date.latin1(), m_request.fcache); // Creation date - fputc('\n', m_request.fcache); - - date.setNum( expireDate ); - date = date.leftJustify(16); - fputs(date.latin1(), m_request.fcache); // Expire date - fputc('\n', m_request.fcache); - - if (!m_request.etag.isEmpty()) - fputs(m_request.etag.latin1(), m_request.fcache); //ETag - fputc('\n', m_request.fcache); - - if (!m_request.lastModified.isEmpty()) - fputs(m_request.lastModified.latin1(), m_request.fcache); // Last modified - fputc('\n', m_request.fcache); - - fputs(mimetype.latin1(), m_request.fcache); // Mimetype - fputc('\n', m_request.fcache); - - if (!m_request.strCharset.isEmpty()) - fputs(m_request.strCharset.latin1(), m_request.fcache); // Charset - fputc('\n', m_request.fcache); - - return; -} -// The above code should be kept in sync -// with the code in http_cache_cleaner.cpp -// !END SYNC! - -void HTTPProtocol::writeCacheEntry( const char *buffer, int nbytes) -{ - if (fwrite( buffer, nbytes, 1, m_request.fcache) != 1) - { - kdWarning(7113) << "(" << m_pid << ") writeCacheEntry: writing " << nbytes << " bytes failed." << endl; - fclose(m_request.fcache); - m_request.fcache = 0; - TQString filename = m_request.cef + ".new"; - ::unlink( TQFile::encodeName(filename) ); - return; - } - long file_pos = ftell( m_request.fcache ) / 1024; - if ( file_pos > m_maxCacheSize ) - { - kdDebug(7113) << "writeCacheEntry: File size reaches " << file_pos - << "Kb, exceeds cache limits. (" << m_maxCacheSize << "Kb)" << endl; - fclose(m_request.fcache); - m_request.fcache = 0; - TQString filename = m_request.cef + ".new"; - ::unlink( TQFile::encodeName(filename) ); - return; - } -} - -void HTTPProtocol::closeCacheEntry() -{ - TQString filename = m_request.cef + ".new"; - int result = fclose( m_request.fcache); - m_request.fcache = 0; - if (result == 0) - { - if (::rename( TQFile::encodeName(filename), TQFile::encodeName(m_request.cef)) == 0) - return; // Success - - kdWarning(7113) << "(" << m_pid << ") closeCacheEntry: error renaming " - << "cache entry. (" << filename << " -> " << m_request.cef - << ")" << endl; - } - - kdWarning(7113) << "(" << m_pid << ") closeCacheEntry: error closing cache " - << "entry. (" << filename<< ")" << endl; -} - -void HTTPProtocol::cleanCache() -{ - const time_t maxAge = DEFAULT_CLEAN_CACHE_INTERVAL; // 30 Minutes. - bool doClean = false; - TQString cleanFile = m_strCacheDir; - if (cleanFile[cleanFile.length()-1] != '/') - cleanFile += "/"; - cleanFile += "cleaned"; - - struct stat stat_buf; - - int result = ::stat(TQFile::encodeName(cleanFile), &stat_buf); - if (result == -1) - { - int fd = creat( TQFile::encodeName(cleanFile), 0600); - if (fd != -1) - { - doClean = true; - ::close(fd); - } - } - else - { - time_t age = (time_t) difftime( time(0), stat_buf.st_mtime ); - if (age > maxAge) // - doClean = true; - } - if (doClean) - { - // Touch file. - utime(TQFile::encodeName(cleanFile), 0); - TDEApplication::startServiceByDesktopPath("http_cache_cleaner.desktop"); - } -} - - - -//************************** AUTHENTICATION CODE ********************/ - - -void HTTPProtocol::configAuth( char *p, bool isForProxy ) -{ - HTTP_AUTH f = AUTH_None; - const char *strAuth = p; - - if ( strncasecmp( p, "Basic", 5 ) == 0 ) - { - f = AUTH_Basic; - p += 5; - strAuth = "Basic"; // Correct for upper-case variations. - } - else if ( strncasecmp (p, "Digest", 6) == 0 ) - { - f = AUTH_Digest; - memcpy((void *)p, "Digest", 6); // Correct for upper-case variations. - p += 6; - } - else if (strncasecmp( p, "MBS_PWD_COOKIE", 14 ) == 0) - { - // Found on http://www.webscription.net/baen/default.asp - f = AUTH_Basic; - p += 14; - strAuth = "Basic"; - } -#ifdef HAVE_LIBGSSAPI - else if ( strncasecmp( p, "Negotiate", 9 ) == 0 ) - { - // if we get two 401 in a row let's assume for now that - // Negotiate isn't working and ignore it - if ( !isForProxy && !(m_responseCode == 401 && m_prevResponseCode == 401) ) - { - f = AUTH_Negotiate; - memcpy((void *)p, "Negotiate", 9); // Correct for upper-case variations. - p += 9; - }; - } -#endif - else if ( strncasecmp( p, "NTLM", 4 ) == 0 ) - { - f = AUTH_NTLM; - memcpy((void *)p, "NTLM", 4); // Correct for upper-case variations. - p += 4; - m_strRealm = "NTLM"; // set a dummy realm - } - else - { - kdWarning(7113) << "(" << m_pid << ") Unsupported or invalid authorization " - << "type requested" << endl; - if (isForProxy) - kdWarning(7113) << "(" << m_pid << ") Proxy URL: " << m_proxyURL << endl; - else - kdWarning(7113) << "(" << m_pid << ") URL: " << m_request.url << endl; - kdWarning(7113) << "(" << m_pid << ") Request Authorization: " << p << endl; - } - - /* - This check ensures the following: - 1.) Rejection of any unknown/unsupported authentication schemes - 2.) Usage of the strongest possible authentication schemes if - and when multiple Proxy-Authenticate or WWW-Authenticate - header field is sent. - */ - if (isForProxy) - { - if ((f == AUTH_None) || - ((m_iProxyAuthCount > 0) && (f < ProxyAuthentication))) - { - // Since I purposefully made the Proxy-Authentication settings - // persistent to reduce the number of round-trips to tdesud we - // have to take special care when an unknown/unsupported auth- - // scheme is received. This check accomplishes just that... - if ( m_iProxyAuthCount == 0) - ProxyAuthentication = f; - kdDebug(7113) << "(" << m_pid << ") Rejected proxy auth method: " << f << endl; - return; - } - m_iProxyAuthCount++; - kdDebug(7113) << "(" << m_pid << ") Accepted proxy auth method: " << f << endl; - } - else - { - if ((f == AUTH_None) || - ((m_iWWWAuthCount > 0) && (f < Authentication))) - { - kdDebug(7113) << "(" << m_pid << ") Rejected auth method: " << f << endl; - return; - } - m_iWWWAuthCount++; - kdDebug(7113) << "(" << m_pid << ") Accepted auth method: " << f << endl; - } - - - while (*p) - { - int i = 0; - while( (*p == ' ') || (*p == ',') || (*p == '\t') ) { p++; } - if ( strncasecmp( p, "realm=", 6 ) == 0 ) - { - //for sites like lib.homelinux.org - TQTextCodec* oldCodec=TQTextCodec::codecForCStrings(); - if (TDEGlobal::locale()->language().contains("ru")) - TQTextCodec::setCodecForCStrings(TQTextCodec::codecForName("CP1251")); - - p += 6; - if (*p == '"') p++; - while( p[i] && p[i] != '"' ) i++; - if( isForProxy ) - m_strProxyRealm = TQString::fromAscii( p, i ); - else - m_strRealm = TQString::fromAscii( p, i ); - - TQTextCodec::setCodecForCStrings(oldCodec); - - if (!p[i]) break; - } - p+=(i+1); - } - - if( isForProxy ) - { - ProxyAuthentication = f; - m_strProxyAuthorization = TQString::fromLatin1( strAuth ); - } - else - { - Authentication = f; - m_strAuthorization = TQString::fromLatin1( strAuth ); - } -} - - -bool HTTPProtocol::retryPrompt() -{ - TQString prompt; - switch ( m_responseCode ) - { - case 401: - prompt = i18n("Authentication Failed."); - break; - case 407: - prompt = i18n("Proxy Authentication Failed."); - break; - default: - break; - } - prompt += i18n(" Do you want to retry?"); - return (messageBox(QuestionYesNo, prompt, i18n("Authentication")) == 3); -} - -void HTTPProtocol::promptInfo( AuthInfo& info ) -{ - if ( m_responseCode == 401 ) - { - info.url = m_request.url; - if ( !m_state.user.isEmpty() ) - info.username = m_state.user; - info.readOnly = !m_request.url.user().isEmpty(); - info.prompt = i18n( "You need to supply a username and a " - "password to access this site." ); - info.keepPassword = true; // Prompt the user for persistence as well. - if ( !m_strRealm.isEmpty() ) - { - info.realmValue = m_strRealm; - info.verifyPath = false; - info.digestInfo = m_strAuthorization; - info.commentLabel = i18n( "Site:" ); - info.comment = i18n("<b>%1</b> at <b>%2</b>").arg( m_strRealm ).arg( m_request.hostname ); - } - } - else if ( m_responseCode == 407 ) - { - info.url = m_proxyURL; - info.username = m_proxyURL.user(); - info.prompt = i18n( "You need to supply a username and a password for " - "the proxy server listed below before you are allowed " - "to access any sites." ); - info.keepPassword = true; - if ( !m_strProxyRealm.isEmpty() ) - { - info.realmValue = m_strProxyRealm; - info.verifyPath = false; - info.digestInfo = m_strProxyAuthorization; - info.commentLabel = i18n( "Proxy:" ); - info.comment = i18n("<b>%1</b> at <b>%2</b>").arg( m_strProxyRealm ).arg( m_proxyURL.host() ); - } - } -} - -bool HTTPProtocol::getAuthorization() -{ - AuthInfo info; - bool result = false; - - kdDebug (7113) << "(" << m_pid << ") HTTPProtocol::getAuthorization: " - << "Current Response: " << m_responseCode << ", " - << "Previous Response: " << m_prevResponseCode << ", " - << "Authentication: " << Authentication << ", " - << "ProxyAuthentication: " << ProxyAuthentication << endl; - - if (m_request.bNoAuth) - { - if (m_request.bErrorPage) - errorPage(); - else - error( ERR_COULD_NOT_LOGIN, i18n("Authentication needed for %1 but authentication is disabled.").arg(m_request.hostname)); - return false; - } - - bool repeatFailure = (m_prevResponseCode == m_responseCode); - - TQString errorMsg; - - if (repeatFailure) - { - bool prompt = true; - if ( Authentication == AUTH_Digest || ProxyAuthentication == AUTH_Digest ) - { - bool isStaleNonce = false; - TQString auth = ( m_responseCode == 401 ) ? m_strAuthorization : m_strProxyAuthorization; - int pos = auth.find("stale", 0, false); - if ( pos != -1 ) - { - pos += 5; - int len = auth.length(); - while( pos < len && (auth[pos] == ' ' || auth[pos] == '=') ) pos++; - if ( pos < len && auth.find("true", pos, false) != -1 ) - { - isStaleNonce = true; - kdDebug(7113) << "(" << m_pid << ") Stale nonce value. " - << "Will retry using same info..." << endl; - } - } - if ( isStaleNonce ) - { - prompt = false; - result = true; - if ( m_responseCode == 401 ) - { - info.username = m_request.user; - info.password = m_request.passwd; - info.realmValue = m_strRealm; - info.digestInfo = m_strAuthorization; - } - else if ( m_responseCode == 407 ) - { - info.username = m_proxyURL.user(); - info.password = m_proxyURL.pass(); - info.realmValue = m_strProxyRealm; - info.digestInfo = m_strProxyAuthorization; - } - } - } - - if ( Authentication == AUTH_NTLM || ProxyAuthentication == AUTH_NTLM ) - { - TQString auth = ( m_responseCode == 401 ) ? m_strAuthorization : m_strProxyAuthorization; - kdDebug(7113) << "auth: " << auth << endl; - if ( auth.length() > 4 ) - { - prompt = false; - result = true; - kdDebug(7113) << "(" << m_pid << ") NTLM auth second phase, " - << "sending response..." << endl; - if ( m_responseCode == 401 ) - { - info.username = m_request.user; - info.password = m_request.passwd; - info.realmValue = m_strRealm; - info.digestInfo = m_strAuthorization; - } - else if ( m_responseCode == 407 ) - { - info.username = m_proxyURL.user(); - info.password = m_proxyURL.pass(); - info.realmValue = m_strProxyRealm; - info.digestInfo = m_strProxyAuthorization; - } - } - } - - if ( prompt ) - { - switch ( m_responseCode ) - { - case 401: - errorMsg = i18n("Authentication Failed."); - break; - case 407: - errorMsg = i18n("Proxy Authentication Failed."); - break; - default: - break; - } - } - } - else - { - // At this point we know more details, so use it to find - // out if we have a cached version and avoid a re-prompt! - // We also do not use verify path unlike the pre-emptive - // requests because we already know the realm value... - - if (m_bProxyAuthValid) - { - // Reset cached proxy auth - m_bProxyAuthValid = false; - KURL proxy ( config()->readEntry("UseProxy") ); - m_proxyURL.setUser(proxy.user()); - m_proxyURL.setPass(proxy.pass()); - } - - info.verifyPath = false; - if ( m_responseCode == 407 ) - { - info.url = m_proxyURL; - info.username = m_proxyURL.user(); - info.password = m_proxyURL.pass(); - info.realmValue = m_strProxyRealm; - info.digestInfo = m_strProxyAuthorization; - } - else - { - info.url = m_request.url; - info.username = m_request.user; - info.password = m_request.passwd; - info.realmValue = m_strRealm; - info.digestInfo = m_strAuthorization; - } - - // If either username or password is not supplied - // with the request, check the password cache. - if ( info.username.isNull() || - info.password.isNull() ) - result = checkCachedAuthentication( info ); - - if ( Authentication == AUTH_Digest ) - { - TQString auth; - - if (m_responseCode == 401) - auth = m_strAuthorization; - else - auth = m_strProxyAuthorization; - - int pos = auth.find("stale", 0, false); - if ( pos != -1 ) - { - pos += 5; - int len = auth.length(); - while( pos < len && (auth[pos] == ' ' || auth[pos] == '=') ) pos++; - if ( pos < len && auth.find("true", pos, false) != -1 ) - { - info.digestInfo = (m_responseCode == 401) ? m_strAuthorization : m_strProxyAuthorization; - kdDebug(7113) << "(" << m_pid << ") Just a stale nonce value! " - << "Retrying using the new nonce sent..." << endl; - } - } - } - } - - if (!result ) - { - // Do not prompt if the username & password - // is already supplied and the login attempt - // did not fail before. - if ( !repeatFailure && - !info.username.isNull() && - !info.password.isNull() ) - result = true; - else - { - if (Authentication == AUTH_Negotiate) - { - if (!repeatFailure) - result = true; - } - else if ( m_request.disablePassDlg == false ) - { - kdDebug( 7113 ) << "(" << m_pid << ") Prompting the user for authorization..." << endl; - promptInfo( info ); - result = openPassDlg( info, errorMsg ); - } - } - } - - if ( result ) - { - switch (m_responseCode) - { - case 401: // Request-Authentication - m_request.user = info.username; - m_request.passwd = info.password; - m_strRealm = info.realmValue; - m_strAuthorization = info.digestInfo; - break; - case 407: // Proxy-Authentication - m_proxyURL.setUser( info.username ); - m_proxyURL.setPass( info.password ); - m_strProxyRealm = info.realmValue; - m_strProxyAuthorization = info.digestInfo; - break; - default: - break; - } - return true; - } - - if (m_request.bErrorPage) - errorPage(); - else - error( ERR_USER_CANCELED, TQString::null ); - return false; -} - -void HTTPProtocol::saveAuthorization() -{ - AuthInfo info; - if ( m_prevResponseCode == 407 ) - { - if (!m_bUseProxy) - return; - m_bProxyAuthValid = true; - info.url = m_proxyURL; - info.username = m_proxyURL.user(); - info.password = m_proxyURL.pass(); - info.realmValue = m_strProxyRealm; - info.digestInfo = m_strProxyAuthorization; - cacheAuthentication( info ); - } - else - { - info.url = m_request.url; - info.username = m_request.user; - info.password = m_request.passwd; - info.realmValue = m_strRealm; - info.digestInfo = m_strAuthorization; - cacheAuthentication( info ); - } -} - -#ifdef HAVE_LIBGSSAPI -TQCString HTTPProtocol::gssError( int major_status, int minor_status ) -{ - OM_uint32 new_status; - OM_uint32 msg_ctx = 0; - gss_buffer_desc major_string; - gss_buffer_desc minor_string; - OM_uint32 ret; - TQCString errorstr; - - errorstr = ""; - - do { - ret = gss_display_status(&new_status, major_status, GSS_C_GSS_CODE, GSS_C_NULL_OID, &msg_ctx, &major_string); - errorstr += (const char *)major_string.value; - errorstr += " "; - ret = gss_display_status(&new_status, minor_status, GSS_C_MECH_CODE, GSS_C_NULL_OID, &msg_ctx, &minor_string); - errorstr += (const char *)minor_string.value; - errorstr += " "; - } while (!GSS_ERROR(ret) && msg_ctx != 0); - - return errorstr; -} - -TQString HTTPProtocol::createNegotiateAuth() -{ - TQString auth; - TQCString servicename; - TQByteArray input; - OM_uint32 major_status, minor_status; - OM_uint32 req_flags = 0; - gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER; - gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER; - gss_name_t server; - gss_ctx_id_t ctx; - gss_OID mech_oid; - static gss_OID_desc krb5_oid_desc = {9, (void *) "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"}; - static gss_OID_desc spnego_oid_desc = {6, (void *) "\x2b\x06\x01\x05\x05\x02"}; - int found = 0; - unsigned int i; - gss_OID_set mech_set; - gss_OID tmp_oid; - - ctx = GSS_C_NO_CONTEXT; - mech_oid = &krb5_oid_desc; - - // see whether we can use the SPNEGO mechanism - major_status = gss_indicate_mechs(&minor_status, &mech_set); - if (GSS_ERROR(major_status)) { - kdDebug(7113) << "(" << m_pid << ") gss_indicate_mechs failed: " << gssError(major_status, minor_status) << endl; - } else { - for (i=0; i<mech_set->count && !found; i++) { - tmp_oid = &mech_set->elements[i]; - if (tmp_oid->length == spnego_oid_desc.length && - !memcmp(tmp_oid->elements, spnego_oid_desc.elements, tmp_oid->length)) { - kdDebug(7113) << "(" << m_pid << ") createNegotiateAuth: found SPNEGO mech" << endl; - found = 1; - mech_oid = &spnego_oid_desc; - break; - } - } - gss_release_oid_set(&minor_status, &mech_set); - } - - // the service name is "HTTP/f.q.d.n" - servicename = "HTTP@"; - servicename += m_state.hostname.ascii(); - - input_token.value = (void *)servicename.data(); - input_token.length = servicename.length() + 1; - - major_status = gss_import_name(&minor_status, &input_token, - GSS_C_NT_HOSTBASED_SERVICE, &server); - - input_token.value = NULL; - input_token.length = 0; - - if (GSS_ERROR(major_status)) { - kdDebug(7113) << "(" << m_pid << ") gss_import_name failed: " << gssError(major_status, minor_status) << endl; - // reset the auth string so that subsequent methods aren't confused - m_strAuthorization = TQString::null; - return TQString::null; - } - - major_status = gss_init_sec_context(&minor_status, GSS_C_NO_CREDENTIAL, - &ctx, server, mech_oid, - req_flags, GSS_C_INDEFINITE, - GSS_C_NO_CHANNEL_BINDINGS, - GSS_C_NO_BUFFER, NULL, &output_token, - NULL, NULL); - - - if (GSS_ERROR(major_status) || (output_token.length == 0)) { - kdDebug(7113) << "(" << m_pid << ") gss_init_sec_context failed: " << gssError(major_status, minor_status) << endl; - gss_release_name(&minor_status, &server); - if (ctx != GSS_C_NO_CONTEXT) { - gss_delete_sec_context(&minor_status, &ctx, GSS_C_NO_BUFFER); - ctx = GSS_C_NO_CONTEXT; - } - // reset the auth string so that subsequent methods aren't confused - m_strAuthorization = TQString::null; - return TQString::null; - } - - input.duplicate((const char *)output_token.value, output_token.length); - auth = "Authorization: Negotiate "; - auth += KCodecs::base64Encode( input ); - auth += "\r\n"; - - // free everything - gss_release_name(&minor_status, &server); - if (ctx != GSS_C_NO_CONTEXT) { - gss_delete_sec_context(&minor_status, &ctx, GSS_C_NO_BUFFER); - ctx = GSS_C_NO_CONTEXT; - } - gss_release_buffer(&minor_status, &output_token); - - return auth; -} -#else - -// Dummy -TQCString HTTPProtocol::gssError( int, int ) -{ - return ""; -} - -// Dummy -TQString HTTPProtocol::createNegotiateAuth() -{ - return TQString::null; -} -#endif - -TQString HTTPProtocol::createNTLMAuth( bool isForProxy ) -{ - uint len; - TQString auth, user, domain, passwd; - TQCString strauth; - TQByteArray buf; - - if ( isForProxy ) - { - auth = "Proxy-Connection: Keep-Alive\r\n"; - auth += "Proxy-Authorization: NTLM "; - user = m_proxyURL.user(); - passwd = m_proxyURL.pass(); - strauth = m_strProxyAuthorization.latin1(); - len = m_strProxyAuthorization.length(); - } - else - { - auth = "Authorization: NTLM "; - user = m_state.user; - passwd = m_state.passwd; - strauth = m_strAuthorization.latin1(); - len = m_strAuthorization.length(); - } - if ( user.contains('\\') ) { - domain = user.section( '\\', 0, 0); - user = user.section( '\\', 1 ); - } - - kdDebug(7113) << "(" << m_pid << ") NTLM length: " << len << endl; - if ( user.isEmpty() || passwd.isEmpty() || len < 4 ) - return TQString::null; - - if ( len > 4 ) - { - // create a response - TQByteArray challenge; - KCodecs::base64Decode( strauth.right( len - 5 ), challenge ); - KNTLM::getAuth( buf, challenge, user, passwd, domain, - KNetwork::KResolver::localHostName(), false, false ); - } - else - { - KNTLM::getNegotiate( buf ); - } - - // remove the challenge to prevent reuse - if ( isForProxy ) - m_strProxyAuthorization = "NTLM"; - else - m_strAuthorization = "NTLM"; - - auth += KCodecs::base64Encode( buf ); - auth += "\r\n"; - - return auth; -} - -TQString HTTPProtocol::createBasicAuth( bool isForProxy ) -{ - TQString auth; - TQCString user, passwd; - if ( isForProxy ) - { - auth = "Proxy-Authorization: Basic "; - user = m_proxyURL.user().latin1(); - passwd = m_proxyURL.pass().latin1(); - } - else - { - auth = "Authorization: Basic "; - user = m_state.user.latin1(); - passwd = m_state.passwd.latin1(); - } - - if ( user.isEmpty() ) - user = ""; - if ( passwd.isEmpty() ) - passwd = ""; - - user += ':'; - user += passwd; - auth += KCodecs::base64Encode( user ); - auth += "\r\n"; - - return auth; -} - -void HTTPProtocol::calculateResponse( DigestAuthInfo& info, TQCString& Response ) -{ - KMD5 md; - TQCString HA1; - TQCString HA2; - - // Calculate H(A1) - TQCString authStr = info.username; - authStr += ':'; - authStr += info.realm; - authStr += ':'; - authStr += info.password; - md.update( authStr ); - - if ( info.algorithm.lower() == "md5-sess" ) - { - authStr = md.hexDigest(); - authStr += ':'; - authStr += info.nonce; - authStr += ':'; - authStr += info.cnonce; - md.reset(); - md.update( authStr ); - } - HA1 = md.hexDigest(); - - kdDebug(7113) << "(" << m_pid << ") calculateResponse(): A1 => " << HA1 << endl; - - // Calcualte H(A2) - authStr = info.method; - authStr += ':'; - authStr += m_request.url.encodedPathAndQuery(0, true).latin1(); - if ( info.qop == "auth-int" ) - { - authStr += ':'; - authStr += info.entityBody; - } - md.reset(); - md.update( authStr ); - HA2 = md.hexDigest(); - - kdDebug(7113) << "(" << m_pid << ") calculateResponse(): A2 => " - << HA2 << endl; - - // Calcualte the response. - authStr = HA1; - authStr += ':'; - authStr += info.nonce; - authStr += ':'; - if ( !info.qop.isEmpty() ) - { - authStr += info.nc; - authStr += ':'; - authStr += info.cnonce; - authStr += ':'; - authStr += info.qop; - authStr += ':'; - } - authStr += HA2; - md.reset(); - md.update( authStr ); - Response = md.hexDigest(); - - kdDebug(7113) << "(" << m_pid << ") calculateResponse(): Response => " - << Response << endl; -} - -TQString HTTPProtocol::createDigestAuth ( bool isForProxy ) -{ - const char *p; - - TQString auth; - TQCString opaque; - TQCString Response; - - DigestAuthInfo info; - - opaque = ""; - if ( isForProxy ) - { - auth = "Proxy-Authorization: Digest "; - info.username = m_proxyURL.user().latin1(); - info.password = m_proxyURL.pass().latin1(); - p = m_strProxyAuthorization.latin1(); - } - else - { - auth = "Authorization: Digest "; - info.username = m_state.user.latin1(); - info.password = m_state.passwd.latin1(); - p = m_strAuthorization.latin1(); - } - if (!p || !*p) - return TQString::null; - - p += 6; // Skip "Digest" - - if ( info.username.isEmpty() || info.password.isEmpty() || !p ) - return TQString::null; - - // info.entityBody = p; // FIXME: send digest of data for POST action ?? - info.realm = ""; - info.algorithm = "MD5"; - info.nonce = ""; - info.qop = ""; - - // cnonce is recommended to contain about 64 bits of entropy - info.cnonce = TDEApplication::randomString(16).latin1(); - - // HACK: Should be fixed according to RFC 2617 section 3.2.2 - info.nc = "00000001"; - - // Set the method used... - switch ( m_request.method ) - { - case HTTP_GET: - info.method = "GET"; - break; - case HTTP_PUT: - info.method = "PUT"; - break; - case HTTP_POST: - info.method = "POST"; - break; - case HTTP_HEAD: - info.method = "HEAD"; - break; - case HTTP_DELETE: - info.method = "DELETE"; - break; - case DAV_PROPFIND: - info.method = "PROPFIND"; - break; - case DAV_PROPPATCH: - info.method = "PROPPATCH"; - break; - case DAV_MKCOL: - info.method = "MKCOL"; - break; - case DAV_COPY: - info.method = "COPY"; - break; - case DAV_MOVE: - info.method = "MOVE"; - break; - case DAV_LOCK: - info.method = "LOCK"; - break; - case DAV_UNLOCK: - info.method = "UNLOCK"; - break; - case DAV_SEARCH: - info.method = "SEARCH"; - break; - case DAV_SUBSCRIBE: - info.method = "SUBSCRIBE"; - break; - case DAV_UNSUBSCRIBE: - info.method = "UNSUBSCRIBE"; - break; - case DAV_POLL: - info.method = "POLL"; - break; - default: - error( ERR_UNSUPPORTED_ACTION, i18n("Unsupported method: authentication will fail. Please submit a bug report.")); - break; - } - - // Parse the Digest response.... - while (*p) - { - int i = 0; - while ( (*p == ' ') || (*p == ',') || (*p == '\t')) { p++; } - if (strncasecmp(p, "realm=", 6 )==0) - { - p+=6; - while ( *p == '"' ) p++; // Go past any number of " mark(s) first - while ( p[i] != '"' ) i++; // Read everything until the last " mark - info.realm = TQCString( p, i+1 ); - } - else if (strncasecmp(p, "algorith=", 9)==0) - { - p+=9; - while ( *p == '"' ) p++; // Go past any number of " mark(s) first - while ( ( p[i] != '"' ) && ( p[i] != ',' ) && ( p[i] != '\0' ) ) i++; - info.algorithm = TQCString(p, i+1); - } - else if (strncasecmp(p, "algorithm=", 10)==0) - { - p+=10; - while ( *p == '"' ) p++; // Go past any " mark(s) first - while ( ( p[i] != '"' ) && ( p[i] != ',' ) && ( p[i] != '\0' ) ) i++; - info.algorithm = TQCString(p,i+1); - } - else if (strncasecmp(p, "domain=", 7)==0) - { - p+=7; - while ( *p == '"' ) p++; // Go past any " mark(s) first - while ( p[i] != '"' ) i++; // Read everything until the last " mark - int pos; - int idx = 0; - TQCString uri = TQCString(p,i+1); - do - { - pos = uri.find( ' ', idx ); - if ( pos != -1 ) - { - KURL u (m_request.url, uri.mid(idx, pos-idx)); - if (u.isValid ()) - info.digestURI.append( u.url().latin1() ); - } - else - { - KURL u (m_request.url, uri.mid(idx, uri.length()-idx)); - if (u.isValid ()) - info.digestURI.append( u.url().latin1() ); - } - idx = pos+1; - } while ( pos != -1 ); - } - else if (strncasecmp(p, "nonce=", 6)==0) - { - p+=6; - while ( *p == '"' ) p++; // Go past any " mark(s) first - while ( p[i] != '"' ) i++; // Read everything until the last " mark - info.nonce = TQCString(p,i+1); - } - else if (strncasecmp(p, "opaque=", 7)==0) - { - p+=7; - while ( *p == '"' ) p++; // Go past any " mark(s) first - while ( p[i] != '"' ) i++; // Read everything until the last " mark - opaque = TQCString(p,i+1); - } - else if (strncasecmp(p, "qop=", 4)==0) - { - p+=4; - while ( *p == '"' ) p++; // Go past any " mark(s) first - while ( p[i] != '"' ) i++; // Read everything until the last " mark - info.qop = TQCString(p,i+1); - } - p+=(i+1); - } - - if (info.realm.isEmpty() || info.nonce.isEmpty()) - return TQString::null; - - // If the "domain" attribute was not specified and the current response code - // is authentication needed, add the current request url to the list over which - // this credential can be automatically applied. - if (info.digestURI.isEmpty() && (m_responseCode == 401 || m_responseCode == 407)) - info.digestURI.append (m_request.url.url().latin1()); - else - { - // Verify whether or not we should send a cached credential to the - // server based on the stored "domain" attribute... - bool send = true; - - // Determine the path of the request url... - TQString requestPath = m_request.url.directory(false, false); - if (requestPath.isEmpty()) - requestPath = "/"; - - int count = info.digestURI.count(); - - for (int i = 0; i < count; i++ ) - { - KURL u ( info.digestURI.at(i) ); - - send &= (m_request.url.protocol().lower() == u.protocol().lower()); - send &= (m_request.hostname.lower() == u.host().lower()); - - if (m_request.port > 0 && u.port() > 0) - send &= (m_request.port == u.port()); - - TQString digestPath = u.directory (false, false); - if (digestPath.isEmpty()) - digestPath = "/"; - - send &= (requestPath.startsWith(digestPath)); - - if (send) - break; - } - - kdDebug(7113) << "(" << m_pid << ") createDigestAuth(): passed digest " - "authentication credential test: " << send << endl; - - if (!send) - return TQString::null; - } - - kdDebug(7113) << "(" << m_pid << ") RESULT OF PARSING:" << endl; - kdDebug(7113) << "(" << m_pid << ") algorithm: " << info.algorithm << endl; - kdDebug(7113) << "(" << m_pid << ") realm: " << info.realm << endl; - kdDebug(7113) << "(" << m_pid << ") nonce: " << info.nonce << endl; - kdDebug(7113) << "(" << m_pid << ") opaque: " << opaque << endl; - kdDebug(7113) << "(" << m_pid << ") qop: " << info.qop << endl; - - // Calculate the response... - calculateResponse( info, Response ); - - auth += "username=\""; - auth += info.username; - - auth += "\", realm=\""; - auth += info.realm; - auth += "\""; - - auth += ", nonce=\""; - auth += info.nonce; - - auth += "\", uri=\""; - auth += m_request.url.encodedPathAndQuery(0, true); - - auth += "\", algorithm=\""; - auth += info.algorithm; - auth +="\""; - - if ( !info.qop.isEmpty() ) - { - auth += ", qop=\""; - auth += info.qop; - auth += "\", cnonce=\""; - auth += info.cnonce; - auth += "\", nc="; - auth += info.nc; - } - - auth += ", response=\""; - auth += Response; - if ( !opaque.isEmpty() ) - { - auth += "\", opaque=\""; - auth += opaque; - } - auth += "\"\r\n"; - - return auth; -} - -TQString HTTPProtocol::proxyAuthenticationHeader() -{ - TQString header; - - // We keep proxy authentication locally until they are changed. - // Thus, no need to check with the password manager for every - // connection. - if ( m_strProxyRealm.isEmpty() ) - { - AuthInfo info; - info.url = m_proxyURL; - info.username = m_proxyURL.user(); - info.password = m_proxyURL.pass(); - info.verifyPath = true; - - // If the proxy URL already contains username - // and password simply attempt to retrieve it - // without prompting the user... - if ( !info.username.isNull() && !info.password.isNull() ) - { - if( m_strProxyAuthorization.isEmpty() ) - ProxyAuthentication = AUTH_None; - else if( m_strProxyAuthorization.startsWith("Basic") ) - ProxyAuthentication = AUTH_Basic; - else if( m_strProxyAuthorization.startsWith("NTLM") ) - ProxyAuthentication = AUTH_NTLM; - else - ProxyAuthentication = AUTH_Digest; - } - else - { - if ( checkCachedAuthentication(info) && !info.digestInfo.isEmpty() ) - { - m_proxyURL.setUser( info.username ); - m_proxyURL.setPass( info.password ); - m_strProxyRealm = info.realmValue; - m_strProxyAuthorization = info.digestInfo; - if( m_strProxyAuthorization.startsWith("Basic") ) - ProxyAuthentication = AUTH_Basic; - else if( m_strProxyAuthorization.startsWith("NTLM") ) - ProxyAuthentication = AUTH_NTLM; - else - ProxyAuthentication = AUTH_Digest; - } - else - { - ProxyAuthentication = AUTH_None; - } - } - } - - /********* Only for debugging purpose... *********/ - if ( ProxyAuthentication != AUTH_None ) - { - kdDebug(7113) << "(" << m_pid << ") Using Proxy Authentication: " << endl; - kdDebug(7113) << "(" << m_pid << ") HOST= " << m_proxyURL.host() << endl; - kdDebug(7113) << "(" << m_pid << ") PORT= " << m_proxyURL.port() << endl; - kdDebug(7113) << "(" << m_pid << ") USER= " << m_proxyURL.user() << endl; - kdDebug(7113) << "(" << m_pid << ") PASSWORD= [protected]" << endl; - kdDebug(7113) << "(" << m_pid << ") REALM= " << m_strProxyRealm << endl; - kdDebug(7113) << "(" << m_pid << ") EXTRA= " << m_strProxyAuthorization << endl; - } - - switch ( ProxyAuthentication ) - { - case AUTH_Basic: - header += createBasicAuth( true ); - break; - case AUTH_Digest: - header += createDigestAuth( true ); - break; - case AUTH_NTLM: - if ( m_bFirstRequest ) header += createNTLMAuth( true ); - break; - case AUTH_None: - default: - break; - } - - return header; -} - -#include "http.moc" diff --git a/kioslave/http/http.h b/kioslave/http/http.h deleted file mode 100644 index ccbb60ce6..000000000 --- a/kioslave/http/http.h +++ /dev/null @@ -1,577 +0,0 @@ -/* - Copyright (C) 2000,2001 Dawit Alemayehu <adawit@kde.org> - Copyright (C) 2000,2001 Waldo Bastian <bastian@kde.org> - Copyright (C) 2000,2001 George Staikos <staikos@kde.org> - Copyright (C) 2001,2002 Hamish Rodda <rodda@kde.org> - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -#ifndef HTTP_H_ -#define HTTP_H_ - - -#include <netinet/in.h> -#include <arpa/inet.h> -#include <string.h> -#include <stdio.h> -#include <time.h> - -#include <tqptrlist.h> -#include <tqstrlist.h> -#include <tqstringlist.h> - -#include <kurl.h> -#include "kio/tcpslavebase.h" -#include "kio/http.h" - -class DCOPClient; -class TQDomElement; -class TQDomNodeList; - -namespace TDEIO { - class AuthInfo; -} - -class HTTPProtocol : public TQObject, public TDEIO::TCPSlaveBase -{ - Q_OBJECT -public: - HTTPProtocol( const TQCString &protocol, const TQCString &pool, - const TQCString &app ); - virtual ~HTTPProtocol(); - - /** HTTP version **/ - enum HTTP_REV {HTTP_None, HTTP_Unknown, HTTP_10, HTTP_11, SHOUTCAST}; - - /** Authorization method used **/ - enum HTTP_AUTH {AUTH_None, AUTH_Basic, AUTH_NTLM, AUTH_Digest, AUTH_Negotiate}; - - /** HTTP / DAV method **/ - // Removed to interfaces/kio/http.h - //enum HTTP_METHOD {HTTP_GET, HTTP_PUT, HTTP_POST, HTTP_HEAD, HTTP_DELETE, - // HTTP_OPTIONS, DAV_PROPFIND, DAV_PROPPATCH, DAV_MKCOL, - // DAV_COPY, DAV_MOVE, DAV_LOCK, DAV_UNLOCK, DAV_SEARCH }; - - /** State of the current Connection **/ - struct HTTPState - { - HTTPState () - { - port = 0; - doProxy = false; - } - - TQString hostname; - TQString encoded_hostname; - short unsigned int port; - TQString user; - TQString passwd; - bool doProxy; - }; - - /** DAV-specific request elements for the current connection **/ - struct DAVRequest - { - DAVRequest () - { - overwrite = false; - depth = 0; - } - - TQString desturl; - bool overwrite; - int depth; - }; - - /** The request for the current connection **/ - struct HTTPRequest - { - HTTPRequest () - { - port = 0; - method = TDEIO::HTTP_UNKNOWN; - offset = 0; - doProxy = false; - allowCompressedPage = false; - disablePassDlg = false; - bNoAuth = false; - bUseCache = false; - bCachedRead = false; - bCachedWrite = false; - fcache = 0; - bMustRevalidate = false; - cacheExpireDateOffset = 0; - bErrorPage = false; - bUseCookiejar = false; - expireDate = 0; - creationDate = 0; - } - - TQString hostname; - TQString encoded_hostname; - short unsigned int port; - TQString user; - TQString passwd; - TQString path; - TQString query; - TDEIO::HTTP_METHOD method; - TDEIO::CacheControl cache; - TDEIO::filesize_t offset; - bool doProxy; - KURL url; - TQString window; // Window Id this request is related to. - TQString referrer; - TQString charsets; - TQString languages; - bool allowCompressedPage; - bool disablePassDlg; - TQString userAgent; - TQString id; - DAVRequest davData; - - bool bNoAuth; // Do not authenticate - - // Cache related - TQString cef; // Cache Entry File belonging to this URL. - bool bUseCache; // Whether the cache is active - bool bCachedRead; // Whether the file is to be read from m_fcache. - bool bCachedWrite; // Whether the file is to be written to m_fcache. - FILE* fcache; // File stream of a cache entry - TQString etag; // ETag header. - TQString lastModified; // Last modified. - bool bMustRevalidate; // Cache entry is expired. - long cacheExpireDateOffset; // Position in the cache entry where the - // 16 byte expire date is stored. - time_t expireDate; // Date when the cache entry will expire - time_t creationDate; // Date when the cache entry was created - TQString strCharset; // Charset - - // Indicates whether an error-page or error-msg should is preferred. - bool bErrorPage; - - // Cookie flags - bool bUseCookiejar; - enum { CookiesAuto, CookiesManual, CookiesNone } cookieMode; - }; - - struct DigestAuthInfo - { - TQCString nc; - TQCString qop; - TQCString realm; - TQCString nonce; - TQCString method; - TQCString cnonce; - TQCString username; - TQCString password; - TQStrList digestURI; - TQCString algorithm; - TQCString entityBody; - }; - -//---------------------- Re-implemented methods ---------------- - virtual void setHost(const TQString& host, int port, const TQString& user, - const TQString& pass); - - virtual void slave_status(); - - virtual void get( const KURL& url ); - virtual void put( const KURL& url, int permissions, bool overwrite, - bool resume ); - -//----------------- Re-implemented methods for WebDAV ----------- - virtual void listDir( const KURL& url ); - virtual void mkdir( const KURL& url, int permissions ); - - virtual void rename( const KURL& src, const KURL& dest, bool overwrite ); - virtual void copy( const KURL& src, const KURL& dest, int permissions, bool overwrite ); - virtual void del( const KURL& url, bool isfile ); - - // ask the host whether it supports WebDAV & cache this info - bool davHostOk(); - - // send generic DAV request - void davGeneric( const KURL& url, TDEIO::HTTP_METHOD method ); - - // Send requests to lock and unlock resources - void davLock( const KURL& url, const TQString& scope, - const TQString& type, const TQString& owner ); - void davUnlock( const KURL& url ); - - // Calls httpClose() and finished() - void davFinished(); - - // Handle error conditions - TQString davError( int code = -1, TQString url = TQString::null ); -//---------------------------- End WebDAV ----------------------- - - /** - * Special commands supported by this slave : - * 1 - HTTP POST - * 2 - Cache has been updated - * 3 - SSL Certificate Cache has been updated - * 4 - HTTP multi get - * 5 - DAV LOCK (see - * 6 - DAV UNLOCK README.webdav) - */ - virtual void special( const TQByteArray &data ); - - virtual void mimetype( const KURL& url); - - virtual void stat( const KURL& url ); - - virtual void reparseConfiguration(); - - virtual void closeConnection(); // Forced close of connection - - void post( const KURL& url ); - void multiGet(const TQByteArray &data); - bool checkRequestURL( const KURL& ); - void cacheUpdate( const KURL &url, bool nocache, time_t expireDate); - - void httpError(); // Generate error message based on response code - - bool isOffline(const KURL &url); // Check network status - -protected slots: - void slotData(const TQByteArray &); - void error( int _errid, const TQString &_text ); - -protected: - int readChunked(); // Read a chunk - int readLimited(); // Read maximum m_iSize bytes. - int readUnlimited(); // Read as much as possible. - - /** - * A "smart" wrapper around write that will use SSL_write or - * write(2) depending on whether you've got an SSL connection or not. - * The only shortcomming is that it uses the "global" file handles and - * soforth. So you can't really use this on individual files/sockets. - */ - ssize_t write(const void *buf, size_t nbytes); - - /** - * Another "smart" wrapper, this time around read that will - * use SSL_read or read(2) depending on whether you've got an - * SSL connection or not. - */ - ssize_t read (void *b, size_t nbytes); - - char *gets (char *str, int size); - - void setRewindMarker(); - void rewind(); - - /** - * Add an encoding on to the appropriate stack this - * is nececesary because transfer encodings and - * content encodings must be handled separately. - */ - void addEncoding(TQString, TQStringList &); - - void configAuth( char *, bool ); - - bool httpOpen(); // Open transfer - void httpClose(bool keepAlive); // Close transfer - - bool httpOpenConnection(); // Open connection - void httpCloseConnection(); // Close connection - void httpCheckConnection(); // Check whether to keep connection. - - void forwardHttpResponseHeader(); - - bool readHeader(); - - bool sendBody(); - - // where dataInternal == true, the content is to be made available - // to an internal function. - bool readBody( bool dataInternal = false ); - - /** - * Performs a WebDAV stat or list - */ - void davSetRequest( const TQCString& requestXML ); - void davStatList( const KURL& url, bool stat = true ); - void davParsePropstats( const TQDomNodeList& propstats, TDEIO::UDSEntry& entry ); - void davParseActiveLocks( const TQDomNodeList& activeLocks, - uint& lockCount ); - - /** - * Parses a date & time string - */ - long parseDateTime( const TQString& input, const TQString& type ); - - /** - * Returns the error code from a "HTTP/1.1 code Code Name" string - */ - int codeFromResponse( const TQString& response ); - - /** - * Extracts locks from metadata - * Returns the appropriate If: header - */ - TQString davProcessLocks(); - - /** - * Send a cookie to the cookiejar - */ - void addCookies( const TQString &url, const TQCString &cookieHeader); - - /** - * Look for cookies in the cookiejar - */ - TQString findCookies( const TQString &url); - - /** - * Do a cache lookup for the current url. (m_state.url) - * - * @param readWrite If true, file is opened read/write. - * If false, file is opened read-only. - * - * @return a file stream open for reading and at the start of - * the header section when the Cache entry exists and is valid. - * 0 if no cache entry could be found, or if the entry is not - * valid (any more). - */ - FILE *checkCacheEntry(bool readWrite = false); - - /** - * Create a cache entry for the current url. (m_state.url) - * - * Set the contents type of the cache entry to 'mimetype'. - */ - void createCacheEntry(const TQString &mimetype, time_t expireDate); - - /** - * Write data to cache. - * - * Write 'nbytes' from 'buffer' to the Cache Entry File - */ - void writeCacheEntry( const char *buffer, int nbytes); - - /** - * Close cache entry - */ - void closeCacheEntry(); - - /** - * Update expire time of current cache entry. - */ - void updateExpireDate(time_t expireDate, bool updateCreationDate=false); - - /** - * Quick check whether the cache needs cleaning. - */ - void cleanCache(); - - /** - * Performs a GET HTTP request. - */ - // where dataInternal == true, the content is to be made available - // to an internal function. - void retrieveContent( bool dataInternal = false ); - - /** - * Performs a HEAD HTTP request. - */ - bool retrieveHeader(bool close_connection = true); - - /** - * Resets any per session settings. - */ - void resetSessionSettings(); - - /** - * Resets settings related to parsing a response. - */ - void resetResponseSettings(); - - /** - * Resets any per connection settings. These are different from - * per-session settings in that they must be invalidates every time - * a request is made, e.g. a retry to re-send the header to the - * server, as compared to only when a new request arrives. - */ - void resetConnectionSettings(); - - /** - * Returns any pre-cached proxy authentication info - * info in HTTP header format. - */ - TQString proxyAuthenticationHeader(); - - /** - * Retrieves authorization info from cache or user. - */ - bool getAuthorization(); - - /** - * Saves valid authorization info in the cache daemon. - */ - void saveAuthorization(); - - /** - * Creates the entity-header for Basic authentication. - */ - TQString createBasicAuth( bool isForProxy = false ); - - /** - * Creates the entity-header for Digest authentication. - */ - TQString createDigestAuth( bool isForProxy = false ); - - /** - * Creates the entity-header for NTLM authentication. - */ - TQString createNTLMAuth( bool isForProxy = false ); - - /** - * Creates the entity-header for Negotiate authentication. - */ - TQString createNegotiateAuth(); - - /** - * create GSS error string - */ - TQCString gssError( int major_status, int minor_status ); - - /** - * Calcualtes the message digest response based on RFC 2617. - */ - void calculateResponse( DigestAuthInfo &info, TQCString &Response ); - - /** - * Prompts the user for authorization retry. - */ - bool retryPrompt(); - - /** - * Creates authorization prompt info. - */ - void promptInfo( TDEIO::AuthInfo& info ); - -protected: - HTTPState m_state; - HTTPRequest m_request; - TQPtrList<HTTPRequest> m_requestQueue; - - bool m_bBusy; // Busy handling request queue. - bool m_bEOF; - bool m_bEOD; - -//--- Settings related to a single response only - TQStringList m_responseHeader; // All headers - KURL m_redirectLocation; - bool m_bRedirect; // Indicates current request is a redirection - - // Processing related - bool m_bChunked; // Chunked tranfer encoding - TDEIO::filesize_t m_iSize; // Expected size of message - TDEIO::filesize_t m_iBytesLeft; // # of bytes left to receive in this message. - TDEIO::filesize_t m_iContentLeft; // # of content bytes left - TQByteArray m_bufReceive; // Receive buffer - bool m_dataInternal; // Data is for internal consumption - char m_lineBuf[1024]; - char m_rewindBuf[8192]; - size_t m_rewindCount; - char *m_linePtr; - size_t m_lineCount; - char *m_lineBufUnget; - char *m_linePtrUnget; - size_t m_lineCountUnget; - - // Mimetype determination - bool m_cpMimeBuffer; - TQByteArray m_mimeTypeBuffer; - - // Language/Encoding related - TQStringList m_qTransferEncodings; - TQStringList m_qContentEncodings; - TQString m_sContentMD5; - TQString m_strMimeType; - - -//--- WebDAV - // Data structure to hold data which will be passed to an internal func. - TQByteArray m_bufWebDavData; - TQStringList m_davCapabilities; - - bool m_davHostOk; - bool m_davHostUnsupported; -//---------- - - // Holds the POST data so it won't get lost on if we - // happend to get a 401/407 response when submitting, - // a form. - TQByteArray m_bufPOST; - - // Cache related - int m_maxCacheAge; // Maximum age of a cache entry. - long m_maxCacheSize; // Maximum cache size in Kb. - TQString m_strCacheDir; // Location of the cache. - - - -//--- Proxy related members - bool m_bUseProxy; - bool m_bNeedTunnel; // Whether we need to make a SSL tunnel - bool m_bIsTunneled; // Whether we have an active SSL tunnel - bool m_bProxyAuthValid; - int m_iProxyPort; - KURL m_proxyURL; - TQString m_strProxyRealm; - - // Operation mode - TQCString m_protocol; - - // Authentication - TQString m_strRealm; - TQString m_strAuthorization; - TQString m_strProxyAuthorization; - HTTP_AUTH Authentication; - HTTP_AUTH ProxyAuthentication; - bool m_bUnauthorized; - short unsigned int m_iProxyAuthCount; - short unsigned int m_iWWWAuthCount; - - // First request on a connection - bool m_bFirstRequest; - - // Persistent connections - bool m_bKeepAlive; - int m_keepAliveTimeout; // Timeout in seconds. - - // Persistent proxy connections - bool m_bPersistentProxyConnection; - - - // Indicates whether there was some connection error. - bool m_bError; - - // Previous and current response codes - unsigned int m_responseCode; - unsigned int m_prevResponseCode; - - // Values that determine the remote connection timeouts. - int m_proxyConnTimeout; - int m_remoteConnTimeout; - int m_remoteRespTimeout; - - int m_pid; -}; -#endif diff --git a/kioslave/http/http.protocol b/kioslave/http/http.protocol deleted file mode 100644 index ea7b57869..000000000 --- a/kioslave/http/http.protocol +++ /dev/null @@ -1,12 +0,0 @@ -[Protocol] -exec=kio_http -protocol=http -input=none -output=filesystem -reading=true -defaultMimetype=application/octet-stream -determineMimetypeFromExtension=false -Icon=www -maxInstances=3 -DocPath=kioslave/http.html -Class=:internet diff --git a/kioslave/http/http_cache_cleaner.cpp b/kioslave/http/http_cache_cleaner.cpp deleted file mode 100644 index 554d221d5..000000000 --- a/kioslave/http/http_cache_cleaner.cpp +++ /dev/null @@ -1,284 +0,0 @@ -/* -This file is part of KDE - - Copyright (C) 1999-2000 Waldo Bastian (bastian@kde.org) - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN -AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ -//---------------------------------------------------------------------------- -// -// KDE Http Cache cleanup tool -// $Id$ - -#include <time.h> -#include <stdlib.h> - -#include <tqdir.h> -#include <tqstring.h> -#include <tqptrlist.h> - -#include <kinstance.h> -#include <klocale.h> -#include <kcmdlineargs.h> -#include <kglobal.h> -#include <kstandarddirs.h> -#include <dcopclient.h> -#include <kprotocolmanager.h> - -#include <unistd.h> - -#include <kdebug.h> - -time_t currentDate; -int m_maxCacheAge; -int m_maxCacheSize; - -static const char appName[] = "kio_http_cache_cleaner"; - -static const char description[] = I18N_NOOP("TDE HTTP cache maintenance tool"); - -static const char version[] = "1.0.0"; - -static const KCmdLineOptions options[] = -{ - {"clear-all", I18N_NOOP("Empty the cache"), 0}, - KCmdLineLastOption -}; - -struct FileInfo { - TQString name; - int size; // Size in Kb. - int age; -}; - -template class TQPtrList<FileInfo>; - -class FileInfoList : public TQPtrList<FileInfo> -{ -public: - FileInfoList() : TQPtrList<FileInfo>() { } - int compareItems(TQPtrCollection::Item item1, TQPtrCollection::Item item2) - { return ((FileInfo *)item1)->age - ((FileInfo *)item2)->age; } -}; - -// !START OF SYNC! -// Keep the following in sync with the cache code in http.cc -#define CACHE_REVISION "7\n" - -FileInfo *readEntry( const TQString &filename) -{ - TQCString CEF = TQFile::encodeName(filename); - FILE *fs = fopen( CEF.data(), "r"); - if (!fs) - return 0; - - char buffer[401]; - bool ok = true; - - // CacheRevision - if (ok && (!fgets(buffer, 400, fs))) - ok = false; - if (ok && (strcmp(buffer, CACHE_REVISION) != 0)) - ok = false; - - // Full URL - if (ok && (!fgets(buffer, 400, fs))) - ok = false; - - time_t creationDate; - int age =0; - - // Creation Date - if (ok && (!fgets(buffer, 400, fs))) - ok = false; - if (ok) - { - creationDate = (time_t) strtoul(buffer, 0, 10); - age = (int) difftime(currentDate, creationDate); - if ( m_maxCacheAge && ( age > m_maxCacheAge)) - { - ok = false; // Expired - } - } - - // Expiration Date - if (ok && (!fgets(buffer, 400, fs))) - ok = false; - if (ok) - { -//WABA: It seems I slightly misunderstood the meaning of "Expire:" header. -#if 0 - time_t expireDate; - expireDate = (time_t) strtoul(buffer, 0, 10); - if (expireDate && (expireDate < currentDate)) - ok = false; // Expired -#endif - } - - // ETag - if (ok && (!fgets(buffer, 400, fs))) - ok = false; - if (ok) - { - // Ignore ETag - } - - // Last-Modified - if (ok && (!fgets(buffer, 400, fs))) - ok = false; - if (ok) - { - // Ignore Last-Modified - } - - - fclose(fs); - if (ok) - { - FileInfo *info = new FileInfo; - info->age = age; - return info; - } - - unlink( CEF.data()); - return 0; -} -// Keep the above in sync with the cache code in http.cc -// !END OF SYNC! - -void scanDirectory(FileInfoList &fileEntries, const TQString &name, const TQString &strDir) -{ - TQDir dir(strDir); - if (!dir.exists()) return; - - TQFileInfoList *newEntries = (TQFileInfoList *) dir.entryInfoList(); - - if (!newEntries) return; // Directory not accessible ?? - - for(TQFileInfo *qFileInfo = newEntries->first(); - qFileInfo; - qFileInfo = newEntries->next()) - { - if (qFileInfo->isFile()) - { - FileInfo *fileInfo = readEntry( strDir + "/" + qFileInfo->fileName()); - if (fileInfo) - { - fileInfo->name = name + "/" + qFileInfo->fileName(); - fileInfo->size = (qFileInfo->size() + 1023) / 1024; - fileEntries.append(fileInfo); - } - } - } -} - -extern "C" KDE_EXPORT int kdemain(int argc, char **argv) -{ - KLocale::setMainCatalogue("tdelibs"); - TDECmdLineArgs::init( argc, argv, appName, - I18N_NOOP("TDE HTTP cache maintenance tool"), - description, version, true); - - TDECmdLineArgs::addCmdLineOptions( options ); - - TDECmdLineArgs *args = TDECmdLineArgs::parsedArgs(); - - bool deleteAll = args->isSet("clear-all"); - - TDEInstance ins( appName ); - - if (!deleteAll) - { - DCOPClient *dcop = new DCOPClient(); - TQCString name = dcop->registerAs(appName, false); - if (!name.isEmpty() && (name != appName)) - { - fprintf(stderr, "%s: Already running! (%s)\n", appName, name.data()); - return 0; - } - } - - currentDate = time(0); - m_maxCacheAge = KProtocolManager::maxCacheAge(); - m_maxCacheSize = KProtocolManager::maxCacheSize(); - - if (deleteAll) - m_maxCacheSize = -1; - - TQString strCacheDir = TDEGlobal::dirs()->saveLocation("cache", "http"); - - TQDir cacheDir( strCacheDir ); - if (!cacheDir.exists()) - { - fprintf(stderr, "%s: '%s' does not exist.\n", appName, strCacheDir.ascii()); - return 0; - } - - TQStringList dirs = cacheDir.entryList( ); - - FileInfoList cachedEntries; - - for(TQStringList::Iterator it = dirs.begin(); - it != dirs.end(); - it++) - { - if ((*it)[0] != '.') - { - scanDirectory( cachedEntries, *it, strCacheDir + "/" + *it); - } - } - - cachedEntries.sort(); - - int maxCachedSize = m_maxCacheSize / 2; - - for(FileInfo *fileInfo = cachedEntries.first(); - fileInfo; - fileInfo = cachedEntries.next()) - { - if (fileInfo->size > maxCachedSize) - { - TQCString filename = TQFile::encodeName( strCacheDir + "/" + fileInfo->name); - unlink(filename.data()); -// kdDebug () << appName << ": Object too big, deleting '" << filename.data() << "' (" << result<< ")" << endl; - } - } - - int totalSize = 0; - - for(FileInfo *fileInfo = cachedEntries.first(); - fileInfo; - fileInfo = cachedEntries.next()) - { - if ((totalSize + fileInfo->size) > m_maxCacheSize) - { - TQCString filename = TQFile::encodeName( strCacheDir + "/" + fileInfo->name); - unlink(filename.data()); -// kdDebug () << appName << ": Cache too big, deleting '" << filename.data() << "' (" << fileInfo->size << ")" << endl; - } - else - { - totalSize += fileInfo->size; -// fprintf(stderr, "Keep in cache: %s %d %d total = %d\n", fileInfo->name.ascii(), fileInfo->size, fileInfo->age, totalSize); - } - } - kdDebug () << appName << ": Current size of cache = " << totalSize << " kB." << endl; - return 0; -} - - diff --git a/kioslave/http/http_cache_cleaner.desktop b/kioslave/http/http_cache_cleaner.desktop deleted file mode 100644 index 33cebb731..000000000 --- a/kioslave/http/http_cache_cleaner.desktop +++ /dev/null @@ -1,168 +0,0 @@ -[Desktop Entry] -Type=Service -Name=HTTP Cache Cleaner -Name[af]=Http Kas Skoonmaker -Name[ar]=مزيل كاش HTTP -Name[az]=HTTP Ön Yaddaş Təmizləyici -Name[be]=Ачыстка кэшу HTTP -Name[bg]=Изчистване на кеш-паметта на HTTP -Name[bn]=এইচ-টি-টি-পি ক্যাশ ক্লীনার -Name[br]=Naeter Krubuilh HTTP -Name[bs]=Čistač HTTP cache-a -Name[ca]=Neteja la memòria cau del HTTP -Name[cs]=Nástroj pro vyprázdnění cache protokolu HTTP -Name[csb]=Czëszczenié cache HTTP -Name[cy]=Glanhauwr Storfa HTTP -Name[da]=HTTP-cache-rydder -Name[de]=Aufräumprogramm für den HTTP-Zwischenspeicher -Name[el]=Καθαριστής λανθάνουσας μνήμης HTTP -Name[eo]=HTTP-Tenejpurigilo -Name[es]=Limpiador del caché de HTTP -Name[et]=HTTP vahemälu puhastaja -Name[eu]=HTTP cache-garbitzailea -Name[fa]=پاککنندۀ نهانگاه قام -Name[fi]=HTTP-välimuistin tyhjentäjä -Name[fr]=Nettoyage du cache HTTP -Name[fy]=HTTP Cache oprommer -Name[ga]=Glantóir Taisce HTTP -Name[gl]=Limpador da caché de HTTP -Name[he]=מנקה מטמון ה־HTTP -Name[hi]=HTTP कैश साफ करने वाला -Name[hr]=Brisanje HTTP pohrane -Name[hu]=HTTP gyorstártisztító -Name[id]=Pembersih Cache HTTP -Name[is]=Hreinsiforrit HTTP skyndiminnis -Name[it]=Ripulitore della cache HTTP -Name[ja]=HTTP キャッシュマネージャ -Name[ka]=HTTP ბუფერის გასუფთავება -Name[kk]=HTTP бүркемесін босату -Name[km]=កម្មវិធីសម្អាតឃ្លាំងសម្ងាត់ HTTP -Name[ko]=HTTP 캐시 정리 -Name[lb]=Opraumer fir den HTTP-Zwëschespäicher -Name[lt]=HTTP krepšio ištuštintojas -Name[lv]=HTTP Kešatmiņas tīrītājs -Name[mk]=Бришење на HTTP-кешот -Name[mn]=HTTP-завсрын хадгалагчийн цэвэрлэгээ -Name[ms]=Pembersih Penyimpan HTTP -Name[mt]=Tindif tal-cache HTTP -Name[nb]=HTTP Mellomlagerrenser -Name[nds]=Reenmaker för HTTP-Twischenspieker -Name[ne]=HTTP क्यास क्लीनर -Name[nl]=HTTP Cache opschonen -Name[nn]=HTTP-mellomlageropprensking -Name[nso]=Sehlwekisi sa Polokelo ya HTTP -Name[oc]=Netejador de cabia HTTP -Name[pa]=HTTP ਕੈਂਚੇ ਸਾਫ਼ -Name[pl]=Czyszczenie bufora HTTP -Name[pt]=Limpeza da Cache de HTTP -Name[pt_BR]=Limpador de cache HTTP -Name[ro]=Curăţător cache HTTP -Name[ru]=Очистка кэша HTTP -Name[rw]=Musukura Ubwihisho HTTP -Name[se]=HTTP gaskarádjosa buhtisteaddji -Name[sk]=Čistič vyrovnávacej pamäti HTTP -Name[sl]=Čistilnik predpomnilnika HTTP -Name[sq]=Pastrues për Depon e Fshehtësitëve të HTTP -Name[sr]=Чистач HTTP кеша -Name[sr@Latn]=Čistač HTTP keša -Name[sv]=HTTP-cacherensare -Name[ta]=HTTP தற்காலிக நினைவகத்தை சுத்தம் செய்தல் -Name[te]=హెచ్ టిటిపి కోశం శుభ్రంచేసేది -Name[tg]=HTTP Софкунаки Махфӣ -Name[th]=ตัวล้างแคช HTTP -Name[tr]=HTTP Önbellek Temizleyici -Name[tt]=HTTP Alxäteren Buşatqıç -Name[uk]=Очищувач кешу HTTP -Name[uz]=HTTP kesh boʻshatgich -Name[uz@cyrillic]=HTTP кэш бўшатгич -Name[ven]=Tshikulumagi tsha HTTP Cache -Name[vi]=Bộ làm sạch bộ nhớ tạm HTTP -Name[xh]=Umcoci wendawo efihlakeleyo yokugcina we HTTP -Name[zh_CN]=HTTP 缓存清除程序 -Name[zh_HK]=HTTP 快取清除程式 -Name[zh_TW]=HTTP 快取清除程式 -Name[zu]=Umhlanzi we-Cache ye-HTTP -Exec=kio_http_cache_cleaner -Comment=Cleans up old entries from the HTTP cache -Comment[af]=Skoonmaak begin ou inskrywings van die Http kas -Comment[ar]=يزيل المداخل القديمة من كاش HTTP -Comment[az]=HTTP ön yaddaşından köhnə girişləri silər -Comment[be]=Выдаляе старыя запісы з кэшу HTTP -Comment[bg]=Изчистване на старите данни в кеш-паметта на HTTP -Comment[bn]=HTTP ক্যাশ থেকে পুরনো তথ্য মুছে ফেলে -Comment[br]=Skarañ enmontoù kozh diwar ar grubuilh HTTP -Comment[bs]=Čisti stare datoteke iz HTTP cache-a -Comment[ca]=Neteja les entrades antigues de la memòria cau del HTTP -Comment[cs]=Odstraňuje staré položky z HTTP cache -Comment[csb]=Rëmô stôré wpisënczi z cache HTTP -Comment[cy]=Glanhau'r hen gofnodion o'r storfa HTTP -Comment[da]=Rydder op i gamle indgange fra HTTP-cachen -Comment[de]=Löscht alte Einträge aus dem HTTP-Zwischenspeicher -Comment[el]=Καθαρίζει παλιές καταχωρήσεις από τη λανθάνουσα μνήμη HTTP -Comment[eo]=Forigas malnovajn erojn el HTTP-tenejo -Comment[es]=Elimina entradas antiguas del caché de HTTP -Comment[et]=Puhastab HTTP vahemälu vanadest kirjetest -Comment[eu]=HTTP cachearen sarrera zaharrak garbitzen ditu -Comment[fa]=مدخلهای قدیمی را از نهانگاه قام پاک میکند -Comment[fi]=Puhdistaa vanhat tiedot HTTP-välimuistista -Comment[fr]=Efface les anciennes entrées du cache HTTP -Comment[fy]=Ferwidert âlde items út de HTTP-cache -Comment[ga]=Glanann seaniontrálacha ón taisce HTTP -Comment[gl]=Elimina as entradas antigas da caché de HTTP -Comment[he]=מנקה רשומות ישנות ממטמון ה־HTTP -Comment[hi]=HTTP कैश से पुरानी प्रविष्टि साफ करे -Comment[hr]=Uklanjanje starih datoteka iz HTTP privremene lokalne pohrane -Comment[hu]=Kitörli a régi bejegyzéseket a HTTP gyorstárból -Comment[id]=Membersihkan entri lama dari cache HTTP -Comment[is]=Hreinsar gamlar færslur úr HTTP skyndiminninu -Comment[it]=Ripulisce la cache HTTP dalle voci vecchie -Comment[ja]=HTTP キャッシュから古いエントリを削除します -Comment[ka]=HTTP ბუფერის მოძველებელი ელემენტების -Comment[kk]=HTTP бүркемесін ескі жазулардан тазалау -Comment[km]=សម្អាតធាតុចាស់ៗពីឃ្លាំងសម្ងាត់ HTTP -Comment[ko]=HTTP 캐시에서 오래된 것들을 정리합니다 -Comment[lb]=Entfernt al Entréen aus dem HTTP-Zwëschespäicher -Comment[lt]=Išvalo senus įrašus iš HTTP krepšio -Comment[lv]=Iztīra vecos ierakstus no HTTP kešatmiņas -Comment[mk]=Ги брише старите работи од HTTP кешот -Comment[mn]=HTTP-завсрын хадгалагчаас хуучин бичлэгийг устгах -Comment[ms]=Membersihkan masukan lama daripada penyimpan HTTP -Comment[mt]=Ineħħi fajls antiki mill-cache tal-HTTP -Comment[nb]=Fjerner gamle oppføringer fra hurtiglageret for HTTP -Comment[nds]=Smitt ole Indrääg ut den HTTP-Twischenspieker rut -Comment[ne]=HTTP क्यासबाट पुराना प्रविष्टिहरू सफा गर्दछ -Comment[nl]=Verwijdert oude items uit de HTTP-cache -Comment[nn]=Reinskar opp i gamle oppføringar i HTTP-mellomlageret -Comment[nso]=E hlwekisa ditsenyo tsa kgale gotswa polokelong ya HTTP -Comment[oc]=Neteja les entrades antigues dèu cabia HTTP -Comment[pa]=HTTP ਕੈਂਚੇ ਤੋਂ ਪੁਰਾਣੀਆਂ ਇਕਾਈਆਂ ਸਾਫ -Comment[pl]=Usuwa stare wpisy z bufora HTTP -Comment[pt]=Limpa o conteúdo desactualizado da cache do HTTP -Comment[pt_BR]=Limpa itens velhos do cache HTTP -Comment[ro]=Elimină înregistrările vechi din cache-ul HTTP -Comment[ru]=Удаление устаревших элементов из кэша HTTP -Comment[rw]=Isukura ibyinjijwe bishaje biri mu bwihisho HTTP -Comment[se]=Buhtista boares merko3/4iid HTTP gaskarádjosis -Comment[sk]=Vyčistiť staré záznamy z vyrovnávacej pamäti HTTP -Comment[sl]=Zbriše stare vnose iz pomnilnika HTTP -Comment[sq]=I pastron hyrjet e vjetra nga depoja e fshehtësive të HTTP -Comment[sr]=Чисти старе ставке из HTTP кеша -Comment[sr@Latn]=Čisti stare stavke iz HTTP keša -Comment[sv]=Rensar bort gamla poster från HTTP-cachen -Comment[ta]=HTTP நினைவத்திலிருந்து பழைய உள்ளீடுகளை சுத்தம் செய்கிறது -Comment[te]=హెచ్ టిటిపి కోశం నుంచి పాత ఆరొపములను శుభ్రం చేసేది -Comment[tg]=Ёддоштҳои Кӯҳна аз HTTP Махфӣ Тоза Кунед -Comment[th]=ล้างรายการเก่าๆ จากแคช HTTP -Comment[tr]=HTTP önbelleğinden eski girişleri siler -Comment[tt]=HTTP alxäterendä bulğan iske keremnär beterä -Comment[uk]=Вичищає старі елементи з кешу HTTP -Comment[uz]=HTTP keshidagi eski elementlarni oʻchiradi -Comment[uz@cyrillic]=HTTP кэшидаги эски элементларни ўчиради -Comment[ven]=I kulumaga zwithu zwakale u bva kha HTTP cache -Comment[vi]=Xoá sạch các mục nhập cũ ra bộ nhớ tạm HTTP. -Comment[xh]=Icoca amangeno amadala asuka twindawo efihlakeleyo yokugcina ye HTTP -Comment[zh_CN]=从 HTTP 缓存中清除旧条目 -Comment[zh_HK]=從 HTTP 快取中清除舊的項目 -Comment[zh_TW]=從 HTTP 快取中清除舊的項目 -Comment[zu]=Ihlanza izingeniso ezindalam ezisuka kwi-cache ye-HTTP -X-TDE-StartupNotify=false diff --git a/kioslave/http/https.protocol b/kioslave/http/https.protocol deleted file mode 100644 index 8a9c2f0da..000000000 --- a/kioslave/http/https.protocol +++ /dev/null @@ -1,12 +0,0 @@ -[Protocol] -exec=kio_http -protocol=https -input=none -output=filesystem -reading=true -defaultMimetype=application/octet-stream -determineMimetypeFromExtension=false -Icon=www -config=http -DocPath=kioslave/https.html -Class=:internet diff --git a/kioslave/http/kcookiejar/CMakeLists.txt b/kioslave/http/kcookiejar/CMakeLists.txt deleted file mode 100644 index 289daa4f0..000000000 --- a/kioslave/http/kcookiejar/CMakeLists.txt +++ /dev/null @@ -1,63 +0,0 @@ -################################################# -# -# (C) 2010 Serghei Amelian -# serghei (DOT) amelian (AT) gmail.com -# -# Improvements and feedback are welcome -# -# This file is released under GPL >= 2 -# -################################################# - -include_directories( - ${TQT_INCLUDE_DIRS} - ${CMAKE_CURRENT_BINARY_DIR} - ${CMAKE_BINARY_DIR} - ${CMAKE_BINARY_DIR}/tdecore - ${CMAKE_SOURCE_DIR} - ${CMAKE_SOURCE_DIR}/dcop - ${CMAKE_SOURCE_DIR}/tdecore - ${CMAKE_SOURCE_DIR}/tdeui -) - -link_directories( - ${TQT_LIBRARY_DIRS} -) - - -##### other data ################################ - -install( FILES kcookiejar.desktop DESTINATION ${SERVICES_INSTALL_DIR}/kded ) -install( FILES kcookiescfg.upd DESTINATION ${KCONF_UPDATE_INSTALL_DIR} ) -install( FILES domain_info DESTINATION ${DATA_INSTALL_DIR}/tdehtml ) - - -##### kcookiejar ################################ - -set( target kcookiejar ) - -set( ${target}_SRCS - main.cpp -) - -tde_add_tdeinit_executable( ${target} AUTOMOC - SOURCES ${${target}_SRCS} - LINK tdecore-shared -) - - -##### kded_kcookiejar ########################### - -set( target kded_kcookiejar ) - -set( ${target}_SRCS - kcookiejar.cpp kcookieserver.cpp kcookiewin.cpp - kcookieserver.skel -) - -tde_add_kpart( ${target} AUTOMOC - SOURCES ${${target}_SRCS} - LINK tdeui-shared tdeinit_kded-shared - DEPENDENCIES dcopidl - DESTINATION ${PLUGIN_INSTALL_DIR} -) diff --git a/kioslave/http/kcookiejar/Makefile.am b/kioslave/http/kcookiejar/Makefile.am deleted file mode 100644 index 431502c12..000000000 --- a/kioslave/http/kcookiejar/Makefile.am +++ /dev/null @@ -1,31 +0,0 @@ -# Makefile.am of tdebase/kioslave/http - -SUBDIRS=tests -INCLUDES= $(all_includes) - -####### Files - -bin_PROGRAMS = -lib_LTLIBRARIES = -tdeinit_LTLIBRARIES = kcookiejar.la -kde_module_LTLIBRARIES = kded_kcookiejar.la - -kcookiejar_la_SOURCES = main.cpp -METASOURCES = AUTO -kcookiejar_la_LDFLAGS = $(all_libraries) -module -avoid-version -kcookiejar_la_LIBADD = $(LIB_TDECORE) $(LIB_QT) $(top_builddir)/dcop/libDCOP.la - -kded_kcookiejar_la_SOURCES = kcookiejar.cpp kcookieserver.cpp \ - kcookieserver.skel kcookiewin.cpp -kded_kcookiejar_la_LDFLAGS = $(all_libraries) -module -avoid-version -kded_kcookiejar_la_LIBADD = $(LIB_KDED) $(LIB_QT) $(top_builddir)/dcop/libDCOP.la $(LIB_TDECORE) $(LIB_X11) $(LIB_TDEUI) $(top_builddir)/kded/libtdeinit_kded.la - -kded_DATA = kcookiejar.desktop -kdeddir = $(kde_servicesdir)/kded - -update_DATA = kcookiescfg.upd -updatedir = $(kde_datadir)/kconf_update - -cookie_DATA = domain_info -cookiedir = $(kde_datadir)/tdehtml - diff --git a/kioslave/http/kcookiejar/domain_info b/kioslave/http/kcookiejar/domain_info deleted file mode 100644 index 94baf8dae..000000000 --- a/kioslave/http/kcookiejar/domain_info +++ /dev/null @@ -1 +0,0 @@ -twoLevelTLD=name,ai,au,bd,bh,ck,eg,et,fk,il,in,kh,kr,mk,mt,na,np,nz,pg,pk,qa,sa,sb,sg,sv,ua,ug,uk,uy,vn,za,zw diff --git a/kioslave/http/kcookiejar/kcookiejar.cpp b/kioslave/http/kcookiejar/kcookiejar.cpp deleted file mode 100644 index 12d92a8df..000000000 --- a/kioslave/http/kcookiejar/kcookiejar.cpp +++ /dev/null @@ -1,1559 +0,0 @@ -/* This file is part of the KDE File Manager - - Copyright (C) 1998-2000 Waldo Bastian (bastian@kde.org) - Copyright (C) 2000,2001 Dawit Alemayehu (adawit@kde.org) - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, and/or sell copies of the - Software, and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ -//---------------------------------------------------------------------------- -// -// KDE File Manager -- HTTP Cookies -// $Id$ - -// -// The cookie protocol is a mess. RFC2109 is a joke since nobody seems to -// use it. Apart from that it is badly written. -// We try to implement Netscape Cookies and try to behave us according to -// RFC2109 as much as we can. -// -// We assume cookies do not contain any spaces (Netscape spec.) -// According to RFC2109 this is allowed though. -// - -#include <config.h> -#include <sys/types.h> -#include <sys/stat.h> -#ifdef HAVE_SYS_PARAM_H -#include <sys/param.h> -#endif -#include <fcntl.h> -#include <unistd.h> -#include <stdio.h> -#include <string.h> - -#ifdef USE_SOLARIS -#include <strings.h> -#endif - -#include <stdlib.h> - -//#include <netinet/in.h> -//#include <arpa/inet.h> - -#include <tqstring.h> -#include <tqstrlist.h> -#include <tqptrlist.h> -#include <tqptrdict.h> -#include <tqfile.h> -#include <tqdir.h> -#include <tqregexp.h> - -#include <kurl.h> -#include <krfcdate.h> -#include <kconfig.h> -#include <ksavefile.h> -#include <kdebug.h> - -#include "kcookiejar.h" - - -// BR87227 -// Waba: Should the number of cookies be limited? -// I am not convinced of the need of such limit -// Mozilla seems to limit to 20 cookies / domain -// but it is unclear which policy it uses to expire -// cookies when it exceeds that amount -#undef MAX_COOKIE_LIMIT - -#define MAX_COOKIES_PER_HOST 25 -#define READ_BUFFER_SIZE 8192 -#define IP_ADDRESS_EXPRESSION "(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)" - -// Note with respect to TQString::fromLatin1( ) -// Cookies are stored as 8 bit data and passed to kio_http as -// latin1 regardless of their actual encoding. - -// L1 is used to indicate latin1 constants -#define L1(x) TQString::fromLatin1(x) - -template class TQPtrList<KHttpCookie>; -template class TQPtrDict<KHttpCookieList>; - -TQString KCookieJar::adviceToStr(KCookieAdvice _advice) -{ - switch( _advice ) - { - case KCookieAccept: return L1("Accept"); - case KCookieReject: return L1("Reject"); - case KCookieAsk: return L1("Ask"); - default: return L1("Dunno"); - } -} - -KCookieAdvice KCookieJar::strToAdvice(const TQString &_str) -{ - if (_str.isEmpty()) - return KCookieDunno; - - TQCString advice = _str.lower().latin1(); - - if (advice == "accept") - return KCookieAccept; - else if (advice == "reject") - return KCookieReject; - else if (advice == "ask") - return KCookieAsk; - - return KCookieDunno; -} - -// KHttpCookie -/////////////////////////////////////////////////////////////////////////// - -// -// Cookie constructor -// -KHttpCookie::KHttpCookie(const TQString &_host, - const TQString &_domain, - const TQString &_path, - const TQString &_name, - const TQString &_value, - time_t _expireDate, - int _protocolVersion, - bool _secure, - bool _httpOnly, - bool _explicitPath) : - mHost(_host), - mDomain(_domain), - mPath(_path.isEmpty() ? TQString::null : _path), - mName(_name), - mValue(_value), - mExpireDate(_expireDate), - mProtocolVersion(_protocolVersion), - mSecure(_secure), - mCrossDomain(false), - mHttpOnly(_httpOnly), - mExplicitPath(_explicitPath) -{ -} - -// -// Checks if a cookie has been expired -// -bool KHttpCookie::isExpired(time_t currentDate) -{ - return (mExpireDate != 0) && (mExpireDate < currentDate); -} - -// -// Returns a string for a HTTP-header -// -TQString KHttpCookie::cookieStr(bool useDOMFormat) -{ - TQString result; - - if (useDOMFormat || (mProtocolVersion == 0)) - { - if ( !mName.isEmpty() ) - result = mName + '='; - result += mValue; - } - else - { - result = mName + '=' + mValue; - if (mExplicitPath) - result += L1("; $Path=\"") + mPath + L1("\""); - if (!mDomain.isEmpty()) - result += L1("; $Domain=\"") + mDomain + L1("\""); - } - return result; -} - -// -// Returns whether this cookie should be send to this location. -bool KHttpCookie::match(const TQString &fqdn, const TQStringList &domains, - const TQString &path) -{ - // Cookie domain match check - if (mDomain.isEmpty()) - { - if (fqdn != mHost) - return false; - } - else if (!domains.contains(mDomain)) - { - if (mDomain[0] == '.') - return false; - - // Maybe the domain needs an extra dot. - TQString domain = '.' + mDomain; - if ( !domains.contains( domain ) ) - if ( fqdn != mDomain ) - return false; - } - - // Cookie path match check - if (mPath.isEmpty()) - return true; - - // According to the netscape spec both http://www.acme.com/foobar, - // http://www.acme.com/foo.bar and http://www.acme.com/foo/bar - // match http://www.acme.com/foo. - // We only match http://www.acme.com/foo/bar - - if( path.startsWith(mPath) && - ( - (path.length() == mPath.length() ) || // Paths are exact match - (path[mPath.length()-1] == '/') || // mPath ended with a slash - (path[mPath.length()] == '/') // A slash follows. - )) - return true; // Path of URL starts with cookie-path - - return false; -} - -// KHttpCookieList -/////////////////////////////////////////////////////////////////////////// - -int KHttpCookieList::compareItems( void * item1, void * item2) -{ - int pathLen1 = ((KHttpCookie *)item1)->path().length(); - int pathLen2 = ((KHttpCookie *)item2)->path().length(); - if (pathLen1 > pathLen2) - return -1; - if (pathLen1 < pathLen2) - return 1; - return 0; -} - - -// KCookieJar -/////////////////////////////////////////////////////////////////////////// - -// -// Constructs a new cookie jar -// -// One jar should be enough for all cookies. -// -KCookieJar::KCookieJar() -{ - m_cookieDomains.setAutoDelete( true ); - m_globalAdvice = KCookieDunno; - m_configChanged = false; - m_cookiesChanged = false; - - TDEConfig cfg("tdehtml/domain_info", true, false, "data"); - TQStringList countries = cfg.readListEntry("twoLevelTLD"); - for(TQStringList::ConstIterator it = countries.begin(); - it != countries.end(); ++it) - { - m_twoLevelTLD.replace(*it, (int *) 1); - } -} - -// -// Destructs the cookie jar -// -// Poor little cookies, they will all be eaten by the cookie monster! -// -KCookieJar::~KCookieJar() -{ - // Not much to do here -} - -static void removeDuplicateFromList(KHttpCookieList *list, KHttpCookie *cookiePtr, bool nameMatchOnly=false, bool updateWindowId=false) -{ - TQString domain1 = cookiePtr->domain(); - if (domain1.isEmpty()) - domain1 = cookiePtr->host(); - - for ( KHttpCookiePtr cookie=list->first(); cookie != 0; ) - { - TQString domain2 = cookie->domain(); - if (domain2.isEmpty()) - domain2 = cookie->host(); - - if ( - (cookiePtr->name() == cookie->name()) && - ( - nameMatchOnly || - ( (domain1 == domain2) && (cookiePtr->path() == cookie->path()) ) - ) - ) - { - if (updateWindowId) - { - for(TQValueList<long>::ConstIterator it = cookie->windowIds().begin(); - it != cookie->windowIds().end(); ++it) - { - long windowId = *it; - if (windowId && (cookiePtr->windowIds().find(windowId) == cookiePtr->windowIds().end())) - { - cookiePtr->windowIds().append(windowId); - } - } - } - KHttpCookiePtr old_cookie = cookie; - cookie = list->next(); - list->removeRef( old_cookie ); - break; - } - else - { - cookie = list->next(); - } - } -} - - -// -// Looks for cookies in the cookie jar which are appropriate for _url. -// Returned is a string containing all appropriate cookies in a format -// which can be added to a HTTP-header without any additional processing. -// -TQString KCookieJar::findCookies(const TQString &_url, bool useDOMFormat, long windowId, KHttpCookieList *pendingCookies) -{ - TQString cookieStr; - TQStringList domains; - TQString fqdn; - TQString path; - KHttpCookiePtr cookie; - KCookieAdvice advice = m_globalAdvice; - - if (!parseURL(_url, fqdn, path)) - return cookieStr; - - bool secureRequest = (_url.find( L1("https://"), 0, false) == 0 || - _url.find( L1("webdavs://"), 0, false) == 0); - - // kdDebug(7104) << "findCookies: URL= " << _url << ", secure = " << secureRequest << endl; - - extractDomains(fqdn, domains); - - KHttpCookieList allCookies; - - for(TQStringList::ConstIterator it = domains.begin(); - true; - ++it) - { - KHttpCookieList *cookieList; - if (it == domains.end()) - { - cookieList = pendingCookies; // Add pending cookies - pendingCookies = 0; - if (!cookieList) - break; - } - else - { - TQString key = (*it).isNull() ? L1("") : (*it); - cookieList = m_cookieDomains[key]; - if (!cookieList) - continue; // No cookies for this domain - } - - if (cookieList->getAdvice() != KCookieDunno) - advice = cookieList->getAdvice(); - - for ( cookie=cookieList->first(); cookie != 0; cookie=cookieList->next() ) - { - // If the we are setup to automatically accept all session cookies and to - // treat all cookies as session cookies or the current cookie is a session - // cookie, then send the cookie back regardless of either policy. - if (advice == KCookieReject && - !(m_autoAcceptSessionCookies && - (m_ignoreCookieExpirationDate || cookie->expireDate() == 0))) - continue; - - if (!cookie->match(fqdn, domains, path)) - continue; - - if( cookie->isSecure() && !secureRequest ) - continue; - - if( cookie->isHttpOnly() && useDOMFormat ) - continue; - - // Do not send expired cookies. - if ( cookie->isExpired (time(0)) ) - { - // Note there is no need to actually delete the cookie here - // since the cookieserver will invoke ::saveCookieJar because - // of the state change below. This will then do the job of - // deleting the cookie for us. - m_cookiesChanged = true; - continue; - } - - if (windowId && (cookie->windowIds().find(windowId) == cookie->windowIds().end())) - { - cookie->windowIds().append(windowId); - } - - if (it == domains.end()) // Only needed when processing pending cookies - removeDuplicateFromList(&allCookies, cookie); - - allCookies.append(cookie); - } - if (it == domains.end()) - break; // Finished. - } - - int cookieCount = 0; - - int protVersion=0; - for ( cookie=allCookies.first(); cookie != 0; cookie=allCookies.next() ) - { - if (cookie->protocolVersion() > protVersion) - protVersion = cookie->protocolVersion(); - } - - for ( cookie=allCookies.first(); cookie != 0; cookie=allCookies.next() ) - { - if (useDOMFormat) - { - if (cookieCount > 0) - cookieStr += L1("; "); - cookieStr += cookie->cookieStr(true); - } - else - { - if (cookieCount == 0) - { - cookieStr += L1("Cookie: "); - if (protVersion > 0) - { - TQString version; - version.sprintf("$Version=%d; ", protVersion); // Without quotes - cookieStr += version; - } - } - else - { - cookieStr += L1("; "); - } - cookieStr += cookie->cookieStr(false); - } - cookieCount++; - } - - return cookieStr; -} - -// -// This function parses a string like 'my_name="my_value";' and returns -// 'my_name' in Name and 'my_value' in Value. -// -// A pointer to the end of the parsed part is returned. -// This pointer points either to: -// '\0' - The end of the string has reached. -// ';' - Another my_name="my_value" pair follows -// ',' - Another cookie follows -// '\n' - Another header follows -static const char * parseNameValue(const char *header, - TQString &Name, - TQString &Value, - bool keepQuotes=false, - bool rfcQuotes=false) -{ - const char *s = header; - // Parse 'my_name' part - for(; (*s != '='); s++) - { - if ((*s=='\0') || (*s==';') || (*s=='\n')) - { - // No '=' sign -> use string as the value, name is empty - // (behavior found in Mozilla and IE) - Name = ""; - Value = TQString::fromLatin1(header); - Value.truncate( s - header ); - Value = Value.stripWhiteSpace(); - return (s); - } - } - - Name = header; - Name.truncate( s - header ); - Name = Name.stripWhiteSpace(); - - // *s == '=' - s++; - - // Skip any whitespace - for(; (*s == ' ') || (*s == '\t'); s++) - { - if ((*s=='\0') || (*s==';') || (*s=='\n')) - { - // End of Name - Value = ""; - return (s); - } - } - - if ((rfcQuotes || !keepQuotes) && (*s == '\"')) - { - // Parse '"my_value"' part (quoted value) - if (keepQuotes) - header = s++; - else - header = ++s; // skip " - for(;(*s != '\"');s++) - { - if ((*s=='\0') || (*s=='\n')) - { - // End of Name - Value = TQString::fromLatin1(header); - Value.truncate(s - header); - return (s); - } - } - Value = TQString::fromLatin1(header); - // *s == '\"'; - if (keepQuotes) - Value.truncate( ++s - header ); - else - Value.truncate( s++ - header ); - - // Skip any remaining garbage - for(;; s++) - { - if ((*s=='\0') || (*s==';') || (*s=='\n')) - break; - } - } - else - { - // Parse 'my_value' part (unquoted value) - header = s; - while ((*s != '\0') && (*s != ';') && (*s != '\n')) - s++; - // End of Name - Value = TQString::fromLatin1(header); - Value.truncate( s - header ); - Value = Value.stripWhiteSpace(); - } - return (s); - -} - -void KCookieJar::stripDomain(const TQString &_fqdn, TQString &_domain) -{ - TQStringList domains; - extractDomains(_fqdn, domains); - if (domains.count() > 3) - _domain = domains[3]; - else - _domain = domains[0]; -} - -TQString KCookieJar::stripDomain( KHttpCookiePtr cookiePtr) -{ - TQString domain; // We file the cookie under this domain. - if (cookiePtr->domain().isEmpty()) - stripDomain( cookiePtr->host(), domain); - else - stripDomain (cookiePtr->domain(), domain); - return domain; -} - -bool KCookieJar::parseURL(const TQString &_url, - TQString &_fqdn, - TQString &_path) -{ - KURL kurl(_url); - if (!kurl.isValid()) - return false; - - _fqdn = kurl.host().lower(); - if (kurl.port()) - { - if (((kurl.protocol() == L1("http")) && (kurl.port() != 80)) || - ((kurl.protocol() == L1("https")) && (kurl.port() != 443))) - { - _fqdn = L1("%1:%2").arg(kurl.port()).arg(_fqdn); - } - } - - // Cookie spoofing protection. Since there is no way a path separator - // or escape encoded character is allowed in the hostname according - // to RFC 2396, reject attempts to include such things there! - if(_fqdn.find('/') > -1 || _fqdn.find('%') > -1) - { - return false; // deny everything!! - } - - _path = kurl.path(); - if (_path.isEmpty()) - _path = L1("/"); - - TQRegExp exp(L1("[\\\\/]\\.\\.[\\\\/]")); - // Weird path, cookie stealing attempt? - if (exp.search(_path) != -1) - return false; // Deny everything!! - - return true; -} - -void KCookieJar::extractDomains(const TQString &_fqdn, - TQStringList &_domains) -{ - // Return numeric IPv6 addresses as is... - if (_fqdn[0] == '[') - { - _domains.append( _fqdn ); - return; - } - // Return numeric IPv4 addresses as is... - if ((_fqdn.at(0) >= TQChar('0')) && (_fqdn.at(0) <= TQChar('9'))) - { - if (_fqdn.find(TQRegExp(IP_ADDRESS_EXPRESSION)) > -1) - { - _domains.append( _fqdn ); - return; - } - } - - TQStringList partList = TQStringList::split('.', _fqdn, false); - - if (partList.count()) - partList.remove(partList.begin()); // Remove hostname - - while(partList.count()) - { - - if (partList.count() == 1) - break; // We only have a TLD left. - - if ((partList.count() == 2) && (m_twoLevelTLD[partList[1].lower()])) - { - // This domain uses two-level TLDs in the form xxxx.yy - break; - } - - if ((partList.count() == 2) && (partList[1].length() == 2)) - { - // If this is a TLD, we should stop. (e.g. co.uk) - // We assume this is a TLD if it ends with .xx.yy or .x.yy - if (partList[0].length() <= 2) - break; // This is a TLD. - - // Catch some TLDs that we miss with the previous check - // e.g. com.au, org.uk, mil.co - TQCString t = partList[0].lower().utf8(); - if ((t == "com") || (t == "net") || (t == "org") || (t == "gov") || (t == "edu") || (t == "mil") || (t == "int")) - break; - } - - TQString domain = partList.join(L1(".")); - _domains.append(domain); - _domains.append('.' + domain); - partList.remove(partList.begin()); // Remove part - } - - // Always add the FQDN at the start of the list for - // hostname == cookie-domainname checks! - _domains.prepend( '.' + _fqdn ); - _domains.prepend( _fqdn ); -} - - -/* - Changes dates in from the following format - - Wed Sep 12 07:00:00 2007 GMT - to - Wed Sep 12 2007 07:00:00 GMT - - to allow KRFCDate::parseDate to properly parse expiration date formats - used in cookies by some servers such as amazon.com. See BR# 145244. -*/ -static TQString fixupDateTime(const TQString& dt) -{ - const int index = dt.find(TQRegExp("[0-9]{1,2}:[0-9]{1,2}:[0-9]{1,2}")); - - if (index > -1) - { - TQStringList dateStrList = TQStringList::split(' ', dt.mid(index)); - if (dateStrList.count() > 1) - { - TQString date = dateStrList[0]; - dateStrList[0] = dateStrList[1]; - dateStrList[1] = date; - date = dt; - return date.replace(index, date.length(), dateStrList.join(" ")); - } - } - - return dt; -} - -// -// This function parses cookie_headers and returns a linked list of -// KHttpCookie objects for all cookies found in cookie_headers. -// If no cookies could be found 0 is returned. -// -// cookie_headers should be a concatenation of all lines of a HTTP-header -// which start with "Set-Cookie". The lines should be separated by '\n's. -// -KHttpCookieList KCookieJar::makeCookies(const TQString &_url, - const TQCString &cookie_headers, - long windowId) -{ - KHttpCookieList cookieList; - KHttpCookieList cookieList2; - KHttpCookiePtr lastCookie = 0; - const char *cookieStr = cookie_headers.data(); - TQString Name; - TQString Value; - TQString fqdn; - TQString path; - bool crossDomain = false; - - if (!parseURL(_url, fqdn, path)) - { - // Error parsing _url - return KHttpCookieList(); - } - TQString defaultPath; - int i = path.findRev('/'); - if (i > 0) - defaultPath = path.left(i); - - // The hard stuff :) - for(;;) - { - // check for "Set-Cookie" - if (strncmp(cookieStr, "Cross-Domain\n", 13) == 0) - { - cookieStr += 13; - crossDomain = true; - } - else if (strncasecmp(cookieStr, "Set-Cookie:", 11) == 0) - { - cookieStr = parseNameValue(cookieStr+11, Name, Value, true); - - // Host = FQDN - // Default domain = "" - // Default path according to rfc2109 - - KHttpCookie *cookie = new KHttpCookie(fqdn, L1(""), defaultPath, Name, Value); - if (windowId) - cookie->mWindowIds.append(windowId); - cookie->mCrossDomain = crossDomain; - - // Insert cookie in chain - cookieList.append(cookie); - lastCookie = cookie; - } - else if (strncasecmp(cookieStr, "Set-Cookie2:", 12) == 0) - { - // Attempt to follow rfc2965 - cookieStr = parseNameValue(cookieStr+12, Name, Value, true, true); - - // Host = FQDN - // Default domain = "" - // Default path according to rfc2965 - - KHttpCookie *cookie = new KHttpCookie(fqdn, L1(""), defaultPath, Name, Value); - if (windowId) - cookie->mWindowIds.append(windowId); - cookie->mCrossDomain = crossDomain; - - // Insert cookie in chain - cookieList2.append(cookie); - lastCookie = cookie; - } - else - { - // This is not the start of a cookie header, skip till next line. - while (*cookieStr && *cookieStr != '\n') - cookieStr++; - - if (*cookieStr == '\n') - cookieStr++; - - if (!*cookieStr) - break; // End of cookie_headers - else - continue; // end of this header, continue with next. - } - - while ((*cookieStr == ';') || (*cookieStr == ' ')) - { - cookieStr++; - - // Name-Value pair follows - cookieStr = parseNameValue(cookieStr, Name, Value); - - TQCString cName = Name.lower().latin1(); - if (cName == "domain") - { - TQString dom = Value.lower(); - // RFC2965 3.2.2: If an explicitly specified value does not - // start with a dot, the user agent supplies a leading dot - if(dom.length() && dom[0] != '.') - dom.prepend("."); - // remove a trailing dot - if(dom.length() > 2 && dom[dom.length()-1] == '.') - dom = dom.left(dom.length()-1); - - if(dom.contains('.') > 1 || dom == ".local") - lastCookie->mDomain = dom; - } - else if (cName == "max-age") - { - int max_age = Value.toInt(); - if (max_age == 0) - lastCookie->mExpireDate = 1; - else - lastCookie->mExpireDate = time(0)+max_age; - } - else if (cName == "expires") - { - // Parse brain-dead netscape cookie-format - lastCookie->mExpireDate = KRFCDate::parseDate(Value); - - // Workaround for servers that send the expiration date in - // 'Wed Sep 12 07:00:00 2007 GMT' format. See BR# 145244. - if (lastCookie->mExpireDate == 0) - lastCookie->mExpireDate = KRFCDate::parseDate(fixupDateTime(Value)); - } - else if (cName == "path") - { - if (Value.isEmpty()) - lastCookie->mPath = TQString::null; // Catch "" <> TQString::null - else - lastCookie->mPath = KURL::decode_string(Value); - lastCookie->mExplicitPath = true; - } - else if (cName == "version") - { - lastCookie->mProtocolVersion = Value.toInt(); - } - else if ((cName == "secure") || - (cName.isEmpty() && Value.lower() == L1("secure"))) - { - lastCookie->mSecure = true; - } - else if ((cName == "httponly") || - (cName.isEmpty() && Value.lower() == L1("httponly"))) - { - lastCookie->mHttpOnly = true; - } - } - - if (*cookieStr == '\0') - break; // End of header - - // Skip ';' or '\n' - cookieStr++; - } - - // RFC2965 cookies come last so that they override netscape cookies. - while( !cookieList2.isEmpty() && (lastCookie = cookieList2.take(0)) ) - { - removeDuplicateFromList(&cookieList, lastCookie, true); - cookieList.append(lastCookie); - } - - return cookieList; -} - -/** -* Parses cookie_domstr and returns a linked list of KHttpCookie objects. -* cookie_domstr should be a semicolon-delimited list of "name=value" -* pairs. Any whitespace before "name" or around '=' is discarded. -* If no cookies are found, 0 is returned. -*/ -KHttpCookieList KCookieJar::makeDOMCookies(const TQString &_url, - const TQCString &cookie_domstring, - long windowId) -{ - // A lot copied from above - KHttpCookieList cookieList; - KHttpCookiePtr lastCookie = 0; - - const char *cookieStr = cookie_domstring.data(); - TQString Name; - TQString Value; - TQString fqdn; - TQString path; - - if (!parseURL(_url, fqdn, path)) - { - // Error parsing _url - return KHttpCookieList(); - } - - // This time it's easy - while(*cookieStr) - { - cookieStr = parseNameValue(cookieStr, Name, Value); - - // Host = FQDN - // Default domain = "" - // Default path = "" - KHttpCookie *cookie = new KHttpCookie(fqdn, TQString::null, TQString::null, - Name, Value ); - if (windowId) - cookie->mWindowIds.append(windowId); - - cookieList.append(cookie); - lastCookie = cookie; - - if (*cookieStr != '\0') - cookieStr++; // Skip ';' or '\n' - } - - return cookieList; -} - -#ifdef MAX_COOKIE_LIMIT -static void makeRoom(KHttpCookieList *cookieList, KHttpCookiePtr &cookiePtr) -{ - // Too much cookies: throw one away, try to be somewhat clever - KHttpCookiePtr lastCookie = 0; - for(KHttpCookiePtr cookie = cookieList->first(); cookie; cookie = cookieList->next()) - { - if (cookieList->compareItems(cookie, cookiePtr) < 0) - break; - lastCookie = cookie; - } - if (!lastCookie) - lastCookie = cookieList->first(); - cookieList->removeRef(lastCookie); -} -#endif - -// -// This function hands a KHttpCookie object over to the cookie jar. -// -// On return cookiePtr is set to 0. -// -void KCookieJar::addCookie(KHttpCookiePtr &cookiePtr) -{ - TQStringList domains; - KHttpCookieList *cookieList = 0L; - - // We always need to do this to make sure that the - // that cookies of type hostname == cookie-domainname - // are properly removed and/or updated as necessary! - extractDomains( cookiePtr->host(), domains ); - for ( TQStringList::ConstIterator it = domains.begin(); - (it != domains.end() && !cookieList); - ++it ) - { - TQString key = (*it).isNull() ? L1("") : (*it); - KHttpCookieList *list= m_cookieDomains[key]; - if ( !list ) continue; - - removeDuplicateFromList(list, cookiePtr, false, true); - } - - TQString domain = stripDomain( cookiePtr ); - TQString key = domain.isNull() ? L1("") : domain; - cookieList = m_cookieDomains[ key ]; - if (!cookieList) - { - // Make a new cookie list - cookieList = new KHttpCookieList(); - cookieList->setAutoDelete(true); - - // All cookies whose domain is not already - // known to us should be added with KCookieDunno. - // KCookieDunno means that we use the global policy. - cookieList->setAdvice( KCookieDunno ); - - m_cookieDomains.insert( domain, cookieList); - - // Update the list of domains - m_domainList.append(domain); - } - - // Add the cookie to the cookie list - // The cookie list is sorted 'longest path first' - if (!cookiePtr->isExpired(time(0))) - { -#ifdef MAX_COOKIE_LIMIT - if (cookieList->count() >= MAX_COOKIES_PER_HOST) - makeRoom(cookieList, cookiePtr); // Delete a cookie -#endif - cookieList->inSort( cookiePtr ); - m_cookiesChanged = true; - } - else - { - delete cookiePtr; - } - cookiePtr = 0; -} - -// -// This function advices whether a single KHttpCookie object should -// be added to the cookie jar. -// -KCookieAdvice KCookieJar::cookieAdvice(KHttpCookiePtr cookiePtr) -{ - if (m_rejectCrossDomainCookies && cookiePtr->isCrossDomain()) - return KCookieReject; - - TQStringList domains; - - extractDomains(cookiePtr->host(), domains); - - // If the cookie specifies a domain, check whether it is valid. Otherwise, - // accept the cookie anyways but remove the domain="" value to prevent - // cross-site cookie injection. - if (!cookiePtr->domain().isEmpty()) - { - if (!domains.contains(cookiePtr->domain()) && - !cookiePtr->domain().endsWith("."+cookiePtr->host())) - cookiePtr->fixDomain(TQString::null); - } - - if (m_autoAcceptSessionCookies && (cookiePtr->expireDate() == 0 || - m_ignoreCookieExpirationDate)) - return KCookieAccept; - - KCookieAdvice advice = KCookieDunno; - bool isFQDN = true; // First is FQDN - TQStringList::Iterator it = domains.begin(); // Start with FQDN which first in the list. - while( (advice == KCookieDunno) && (it != domains.end())) - { - TQString domain = *it; - // Check if a policy for the FQDN/domain is set. - if ( domain[0] == '.' || isFQDN ) - { - isFQDN = false; - KHttpCookieList *cookieList = m_cookieDomains[domain]; - if (cookieList) - advice = cookieList->getAdvice(); - } - domains.remove(it); - it = domains.begin(); // Continue from begin of remaining list - } - - if (advice == KCookieDunno) - advice = m_globalAdvice; - - return advice; -} - -// -// This function gets the advice for all cookies originating from -// _domain. -// -KCookieAdvice KCookieJar::getDomainAdvice(const TQString &_domain) -{ - KHttpCookieList *cookieList = m_cookieDomains[_domain]; - KCookieAdvice advice; - - if (cookieList) - { - advice = cookieList->getAdvice(); - } - else - { - advice = KCookieDunno; - } - - return advice; -} - -// -// This function sets the advice for all cookies originating from -// _domain. -// -void KCookieJar::setDomainAdvice(const TQString &_domain, KCookieAdvice _advice) -{ - TQString domain(_domain); - KHttpCookieList *cookieList = m_cookieDomains[domain]; - - if (cookieList) - { - if (cookieList->getAdvice() != _advice) - { - m_configChanged = true; - // domain is already known - cookieList->setAdvice( _advice); - } - - if ((cookieList->isEmpty()) && - (_advice == KCookieDunno)) - { - // This deletes cookieList! - m_cookieDomains.remove(domain); - m_domainList.remove(domain); - } - } - else - { - // domain is not yet known - if (_advice != KCookieDunno) - { - // We should create a domain entry - m_configChanged = true; - // Make a new cookie list - cookieList = new KHttpCookieList(); - cookieList->setAutoDelete(true); - cookieList->setAdvice( _advice); - m_cookieDomains.insert( domain, cookieList); - // Update the list of domains - m_domainList.append( domain); - } - } -} - -// -// This function sets the advice for all cookies originating from -// the same domain as _cookie -// -void KCookieJar::setDomainAdvice(KHttpCookiePtr cookiePtr, KCookieAdvice _advice) -{ - TQString domain; - stripDomain(cookiePtr->host(), domain); // We file the cookie under this domain. - - setDomainAdvice(domain, _advice); -} - -// -// This function sets the global advice for cookies -// -void KCookieJar::setGlobalAdvice(KCookieAdvice _advice) -{ - if (m_globalAdvice != _advice) - m_configChanged = true; - m_globalAdvice = _advice; -} - -// -// Get a list of all domains known to the cookie jar. -// -const TQStringList& KCookieJar::getDomainList() -{ - return m_domainList; -} - -// -// Get a list of all cookies in the cookie jar originating from _domain. -// -const KHttpCookieList *KCookieJar::getCookieList(const TQString & _domain, - const TQString & _fqdn ) -{ - TQString domain; - - if (_domain.isEmpty()) - stripDomain( _fqdn, domain ); - else - domain = _domain; - - return m_cookieDomains[domain]; -} - -// -// Eat a cookie out of the jar. -// cookiePtr should be one of the cookies returned by getCookieList() -// -void KCookieJar::eatCookie(KHttpCookiePtr cookiePtr) -{ - TQString domain = stripDomain(cookiePtr); // We file the cookie under this domain. - KHttpCookieList *cookieList = m_cookieDomains[domain]; - - if (cookieList) - { - // This deletes cookiePtr! - if (cookieList->removeRef( cookiePtr )) - m_cookiesChanged = true; - - if ((cookieList->isEmpty()) && - (cookieList->getAdvice() == KCookieDunno)) - { - // This deletes cookieList! - m_cookieDomains.remove(domain); - - m_domainList.remove(domain); - } - } -} - -void KCookieJar::eatCookiesForDomain(const TQString &domain) -{ - KHttpCookieList *cookieList = m_cookieDomains[domain]; - if (!cookieList || cookieList->isEmpty()) return; - - cookieList->clear(); - if (cookieList->getAdvice() == KCookieDunno) - { - // This deletes cookieList! - m_cookieDomains.remove(domain); - m_domainList.remove(domain); - } - m_cookiesChanged = true; -} - -void KCookieJar::eatSessionCookies( long windowId ) -{ - if (!windowId) - return; - - TQStringList::Iterator it=m_domainList.begin(); - for ( ; it != m_domainList.end(); ++it ) - eatSessionCookies( *it, windowId, false ); -} - -void KCookieJar::eatAllCookies() -{ - for ( TQStringList::Iterator it=m_domainList.begin(); - it != m_domainList.end();) - { - TQString domain = *it++; - // This might remove domain from domainList! - eatCookiesForDomain(domain); - } -} - -void KCookieJar::eatSessionCookies( const TQString& fqdn, long windowId, - bool isFQDN ) -{ - KHttpCookieList* cookieList; - if ( !isFQDN ) - cookieList = m_cookieDomains[fqdn]; - else - { - TQString domain; - stripDomain( fqdn, domain ); - cookieList = m_cookieDomains[domain]; - } - - if ( cookieList ) - { - KHttpCookiePtr cookie=cookieList->first(); - for (; cookie != 0;) - { - if ((cookie->expireDate() != 0) && !m_ignoreCookieExpirationDate) - { - cookie = cookieList->next(); - continue; - } - - TQValueList<long> &ids = cookie->windowIds(); - if (!ids.remove(windowId) || !ids.isEmpty()) - { - cookie = cookieList->next(); - continue; - } - KHttpCookiePtr old_cookie = cookie; - cookie = cookieList->next(); - cookieList->removeRef( old_cookie ); - } - } -} - -// -// Saves all cookies to the file '_filename'. -// On succes 'true' is returned. -// On failure 'false' is returned. -bool KCookieJar::saveCookies(const TQString &_filename) -{ - KSaveFile saveFile(_filename, 0600); - - if (saveFile.status() != 0) - return false; - - FILE *fStream = saveFile.fstream(); - - time_t curTime = time(0); - - fprintf(fStream, "# KDE Cookie File v2\n#\n"); - - fprintf(fStream, "%-20s %-20s %-12s %-10s %-4s %-20s %-4s %s\n", - "# Host", "Domain", "Path", "Exp.date", "Prot", - "Name", "Sec", "Value"); - - for ( TQStringList::Iterator it=m_domainList.begin(); it != m_domainList.end(); - it++ ) - { - const TQString &domain = *it; - bool domainPrinted = false; - - KHttpCookieList *cookieList = m_cookieDomains[domain]; - KHttpCookiePtr cookie=cookieList->last(); - - for (; cookie != 0;) - { - if (cookie->isExpired(curTime)) - { - // Delete expired cookies - KHttpCookiePtr old_cookie = cookie; - cookie = cookieList->prev(); - cookieList->removeRef( old_cookie ); - } - else if (cookie->expireDate() != 0 && !m_ignoreCookieExpirationDate) - { - if (!domainPrinted) - { - domainPrinted = true; - fprintf(fStream, "[%s]\n", domain.local8Bit().data()); - } - // Store persistent cookies - TQString path = L1("\""); - path += cookie->path(); - path += '"'; - TQString domain = L1("\""); - domain += cookie->domain(); - domain += '"'; - fprintf(fStream, "%-20s %-20s %-12s %10lu %3d %-20s %-4i %s\n", - cookie->host().latin1(), domain.latin1(), - path.latin1(), (unsigned long) cookie->expireDate(), - cookie->protocolVersion(), - cookie->name().isEmpty() ? cookie->value().latin1() : cookie->name().latin1(), - (cookie->isSecure() ? 1 : 0) + (cookie->isHttpOnly() ? 2 : 0) + - (cookie->hasExplicitPath() ? 4 : 0) + (cookie->name().isEmpty() ? 8 : 0), - cookie->value().latin1()); - cookie = cookieList->prev(); - } - else - { - // Skip session-only cookies - cookie = cookieList->prev(); - } - } - } - - return saveFile.close(); -} - -typedef char *charPtr; - -static const char *parseField(charPtr &buffer, bool keepQuotes=false) -{ - char *result; - if (!keepQuotes && (*buffer == '\"')) - { - // Find terminating " - buffer++; - result = buffer; - while((*buffer != '\"') && (*buffer)) - buffer++; - } - else - { - // Find first white space - result = buffer; - while((*buffer != ' ') && (*buffer != '\t') && (*buffer != '\n') && (*buffer)) - buffer++; - } - - if (!*buffer) - return result; // - *buffer++ = '\0'; - - // Skip white-space - while((*buffer == ' ') || (*buffer == '\t') || (*buffer == '\n')) - buffer++; - - return result; -} - - -// -// Reloads all cookies from the file '_filename'. -// On succes 'true' is returned. -// On failure 'false' is returned. -bool KCookieJar::loadCookies(const TQString &_filename) -{ - FILE *fStream = fopen( TQFile::encodeName(_filename), "r"); - if (fStream == 0) - { - return false; - } - - time_t curTime = time(0); - - char *buffer = new char[READ_BUFFER_SIZE]; - - bool err = false; - err = (fgets(buffer, READ_BUFFER_SIZE, fStream) == 0); - - int version = 1; - if (!err) - { - if (strcmp(buffer, "# KDE Cookie File\n") == 0) - { - // version 1 - } - else if (sscanf(buffer, "# KDE Cookie File v%d\n", &version) != 1) - { - err = true; - } - } - - if (!err) - { - while(fgets(buffer, READ_BUFFER_SIZE, fStream) != 0) - { - char *line = buffer; - // Skip lines which begin with '#' or '[' - if ((line[0] == '#') || (line[0] == '[')) - continue; - - const char *host( parseField(line) ); - const char *domain( parseField(line) ); - const char *path( parseField(line) ); - const char *expStr( parseField(line) ); - if (!expStr) continue; - int expDate = (time_t) strtoul(expStr, 0, 10); - const char *verStr( parseField(line) ); - if (!verStr) continue; - int protVer = (time_t) strtoul(verStr, 0, 10); - const char *name( parseField(line) ); - bool keepQuotes = false; - bool secure = false; - bool httpOnly = false; - bool explicitPath = false; - const char *value = 0; - if ((version == 2) || (protVer >= 200)) - { - if (protVer >= 200) - protVer -= 200; - int i = atoi( parseField(line) ); - secure = i & 1; - httpOnly = i & 2; - explicitPath = i & 4; - if (i & 8) - name = ""; - line[strlen(line)-1] = '\0'; // Strip LF. - value = line; - } - else - { - if (protVer >= 100) - { - protVer -= 100; - keepQuotes = true; - } - value = parseField(line, keepQuotes); - secure = atoi( parseField(line) ); - } - - // Parse error - if (!value) continue; - - // Expired or parse error - if ((expDate == 0) || (expDate < curTime)) - continue; - - KHttpCookie *cookie = new KHttpCookie(TQString::fromLatin1(host), - TQString::fromLatin1(domain), - TQString::fromLatin1(path), - TQString::fromLatin1(name), - TQString::fromLatin1(value), - expDate, protVer, - secure, httpOnly, explicitPath); - addCookie(cookie); - } - } - delete [] buffer; - m_cookiesChanged = false; - - fclose( fStream); - return err; -} - -// -// Save the cookie configuration -// - -void KCookieJar::saveConfig(TDEConfig *_config) -{ - if (!m_configChanged) - return; - - _config->setGroup("Cookie Dialog"); - _config->writeEntry("PreferredPolicy", m_preferredPolicy); - _config->writeEntry("ShowCookieDetails", m_showCookieDetails ); - _config->setGroup("Cookie Policy"); - _config->writeEntry("CookieGlobalAdvice", adviceToStr( m_globalAdvice)); - - TQStringList domainSettings; - for ( TQStringList::Iterator it=m_domainList.begin(); - it != m_domainList.end(); - it++ ) - { - const TQString &domain = *it; - KCookieAdvice advice = getDomainAdvice( domain); - if (advice != KCookieDunno) - { - TQString value(domain); - value += ':'; - value += adviceToStr(advice); - domainSettings.append(value); - } - } - _config->writeEntry("CookieDomainAdvice", domainSettings); - _config->sync(); - m_configChanged = false; -} - - -// -// Load the cookie configuration -// - -void KCookieJar::loadConfig(TDEConfig *_config, bool reparse ) -{ - if ( reparse ) - _config->reparseConfiguration(); - - _config->setGroup("Cookie Dialog"); - m_showCookieDetails = _config->readBoolEntry( "ShowCookieDetails" ); - m_preferredPolicy = _config->readNumEntry( "PreferredPolicy", 0 ); - - _config->setGroup("Cookie Policy"); - TQStringList domainSettings = _config->readListEntry("CookieDomainAdvice"); - m_rejectCrossDomainCookies = _config->readBoolEntry( "RejectCrossDomainCookies", true ); - m_autoAcceptSessionCookies = _config->readBoolEntry( "AcceptSessionCookies", true ); - m_ignoreCookieExpirationDate = _config->readBoolEntry( "IgnoreExpirationDate", false ); - TQString value = _config->readEntry("CookieGlobalAdvice", L1("Ask")); - m_globalAdvice = strToAdvice(value); - - // Reset current domain settings first. - for ( TQStringList::Iterator it=m_domainList.begin(); it != m_domainList.end(); ) - { - // Make sure to update iterator before calling setDomainAdvice() - // setDomainAdvice() might delete the domain from domainList. - TQString domain = *it++; - setDomainAdvice(domain, KCookieDunno); - } - - // Now apply the domain settings read from config file... - for ( TQStringList::Iterator it=domainSettings.begin(); - it != domainSettings.end(); ) - { - const TQString &value = *it++; - - int sepPos = value.findRev(':'); - - if (sepPos <= 0) - continue; - - TQString domain(value.left(sepPos)); - KCookieAdvice advice = strToAdvice( value.mid(sepPos + 1) ); - setDomainAdvice(domain, advice); - } -} diff --git a/kioslave/http/kcookiejar/kcookiejar.desktop b/kioslave/http/kcookiejar/kcookiejar.desktop deleted file mode 100644 index ebc76e2f8..000000000 --- a/kioslave/http/kcookiejar/kcookiejar.desktop +++ /dev/null @@ -1,157 +0,0 @@ -[Desktop Entry] -Type=Service -Name=KDED Cookie Jar Module -Name[af]=Kded Koekie Houer Module -Name[ar]=وحدة Jar لكعكة KDED -Name[az]=KDED Kökə Jar Modulu -Name[be]=Модуль "печыва" KDED -Name[bg]=Модул KDED Cookie Jar -Name[bn]=KDED কুকি জার মডিউল -Name[bs]=KDED modul "Tegla sa keksima" -Name[ca]=Mòdul Jar de cookies per a KDED -Name[cs]=KDED modul pro cookies -Name[csb]=Sprôwianié kùszkama -Name[cy]=Modiwl Jar Cwci KDED -Name[da]=KDED-cookie-jar-modul -Name[de]=Cookie-Verwaltung -Name[el]=Άρθρωμα Cookie Jar του KDED -Name[eo]=KDED-kuketotraktila modulo -Name[es]=Módulo Jar de cookies de KDED -Name[et]=KDED Cookie Jar moodul -Name[eu]=KDED Cookie Jar modulua -Name[fa]=پیمانۀ ظرف کوکی KDED -Name[fi]=KDED-evästemoduuli -Name[fr]=Module Jar de cookie KDED -Name[fy]=KDED-module foar it bewarjen fan Koekjes -Name[gl]=Módulo Jar de cookies de KDED -Name[he]=מודול צנצנת העוגיות של KDED -Name[hi]=KDED कुकी जार मॉड्यूल -Name[hr]=KDED modul za čuvanje kolačića -Name[hu]=KDED cookie-modul -Name[id]=Modul Penyimpanan Cookies KDED -Name[is]=KDED smákökukrukka -Name[it]=Modulo Jar dei cookie per KDED -Name[ja]=KDED クッキー Jar モジュール -Name[ka]=KDED-ის ბმულების Jar მოდული -Name[kk]=KDED cookie модулі -Name[km]=ម៉ូឌុល Jar នៃខូគី KDED -Name[ko]=KDED 쿠키 JAR 모듈 -Name[lb]=KDED-Modul fir d'Verwaltung vun de Cookien -Name[lt]=KDED slapukų rinkinio modulis -Name[lv]=KDED Cepumu Jar modulis -Name[mk]=KDED модул Тегла со колачиња -Name[ms]=Modul Balang Cecikut KDED -Name[mt]=Modulu tal-"cookies" KDED -Name[nb]=KDEDs modul for informasjonskapsler (Cookie Jar) -Name[nds]=KDED-Kookjepleeg -Name[ne]=KDED कुकी जार मोड्युल -Name[nl]=KDED-module voor het opslaan van cookies -Name[nn]=KDED-informasjonskapselmodul -Name[nso]=Seripa sa Jar ya Cookie ya KDED -Name[pa]=KDED ਕੂਕੀਜ਼ Jar ਮੈਡੀਊਲ -Name[pl]=Zarządzanie ciasteczkami -Name[pt]=Módulo de 'Cookies' do KDED -Name[pt_BR]=Módulo de Cookie Jar do KDED -Name[ro]=Modul Cookie JAR pentru KDED -Name[ru]=Служба cookie -Name[rw]=Igice Jar Inyandikonyakwirema KDED -Name[se]=KDED gáhkošlihtti-moduvla -Name[sk]=Modul pre cookies KDED -Name[sl]=Modul posode za piškotke KDED -Name[sq]=Modul i KDED-it për Qyp të keksave nga KDED -Name[sr]=KDED модул тегле за колачиће -Name[sr@Latn]=KDED modul tegle za kolačiće -Name[sv]=KDED-kakburksmodul -Name[ta]=KDED தற்காலிக நினைவக சாடி பகுதி -Name[te]=కెడిఈడి కుకీ జాడి మాడ్యూల్ -Name[tg]=Модули KDED Cookie Jar -Name[th]=โมดูลโถคุกกี KDED -Name[tr]=KDED Cookie Jar Modülü -Name[tt]=KDED'nıñ Cookie Modulı -Name[uk]=Модуль глечика з куками KDED -Name[uz]=KDED kuki idish moduli -Name[uz@cyrillic]=KDED куки идиш модули -Name[ven]=Modulu wa Jar wa Cookie ya KDED -Name[vi]=Mô-đun Cookie Jar của KDED -Name[xh]=Isicatshulwa se KDED Cookie Jar -Name[zh_CN]=KDED Cookie Jar 模块 -Name[zh_HK]=KDED Cookie Jar 模組 -Name[zh_TW]=KDED Cookie Jar 模組 -Name[zu]=Ingxenye Yojeke ye-Cookie ye-KDED -Comment=Keeps track of all cookies in the system -Comment[af]=Hou tred van al die koekies in die stelsel -Comment[ar]=يراقب جميع الكعكات الموجودة على النظام -Comment[be]=Захоўвае звесткі пра "печыва" -Comment[bg]=Контрол над всички бисквитки в системата -Comment[bn]=সিস্টেমে সমস্ত কুকি-র খোঁজখবর রাখে -Comment[bs]=Prati sve kolačiće (cookije) na sistemu -Comment[ca]=Segueix totes les galetes en el sistema -Comment[cs]=Spravuje Cookies v počítači -Comment[csb]=Trzëmô wszëtczé kùszczi w systemie -Comment[da]=Holder styr på alle cookier på systemet -Comment[de]=Verwaltet die Cookies in KDED -Comment[el]=Διατηρεί αρχείο από όλα τα cookies στο σύστημα -Comment[eo]=Registras ĉiujn kuketojn en la sistemo -Comment[es]=Mantiene registro todas las cookies en el sistema -Comment[et]=Hoiab silma peal kõigil süsteemi küpsistel -Comment[eu]=Sistemaren cookie guztien jarraipena egiten du -Comment[fa]=رد همۀ کوکیها را در سیستم نگه میدارد -Comment[fi]=Seuraa järjestelmän evästeitä -Comment[fr]=Conserve une trace de tous les cookies dans le système -Comment[fy]=Hâld by wer alle koekjes binne -Comment[gl]=Manter as pegadas de todas as Cookies no sistema -Comment[he]=מבצע מעקב אחרי כל העוגיות במערכת -Comment[hi]=तंत्र की सभी कुकी की जानकारी रखता है -Comment[hr]=Vođenje evidencije o svim kolačićima na sustavu -Comment[hu]=Nyomon követi a rendszerben létrejövő cookie-kat -Comment[id]=Menyimpan semua cookies pada sistem -Comment[is]=Heldur utanum allar smákökur í kerfinu -Comment[it]=Tiene traccia di tutti i cookie del sistema -Comment[ja]=システムのすべてのクッキーを管理します -Comment[ka]=სისტემის ყველა ბმულის თვალმიდევნება -Comment[kk]=Жүйедегі бүкіл cookie файлдарды бақылау -Comment[km]=រក្សាការតាមដានខូគីទាំងអស់ក្នុងប្រព័ន្ធ -Comment[lb]=Iwwerwaacht all d'Cookie vum System -Comment[lt]=Seka visus slapukus sistemoje -Comment[lv]=Seko visiem sistēmā esošajiem cepumiem -Comment[mk]=Води сметка за сите колачиња во системот -Comment[ms]=Memerhati semua cecikut dalam sistem -Comment[nb]=Holder rede på alle informasjonskapsler i systemet -Comment[nds]=Passt all Kookjes in't Systeem -Comment[ne]=प्रणालीमा सबै कुकीहरूको पदचिन्ह राख्दछ -Comment[nl]=Houdt alle cookies in het systeem bij -Comment[nn]=Held greie på informasjonskapslane -Comment[pa]=ਸਿਸਟਮ ਦੇ ਸਾਰੇ ਕੂਕੀਜ਼ ਦਾ ਰਿਕਾਰਡ ਰੱਖੋ -Comment[pl]=Przechowuje wszystkie ciasteczka w systemie -Comment[pt]=Mantém um registo de todos os 'cookies' no sistema -Comment[pt_BR]=Mantém informações sobre todos os cookies do sistema -Comment[ro]=Administrează toate "cookie"-urile din sistem -Comment[ru]=Управление закладками-cookie в KDED -Comment[rw]=Iguma inzira y'inyandikonyakwirema zose muri sisitemu -Comment[se]=Halddaša buot diehtočoahkuid -Comment[sk]=Sleduje všetky cookie v systéme -Comment[sl]=Opazuje vse piškotke v sistemu -Comment[sr]=Води евиденцију о свим колачићима на систему -Comment[sr@Latn]=Vodi evidenciju o svim kolačićima na sistemu -Comment[sv]=Håller ordning på alla kakor i systemet -Comment[ta]=கணினியின் எல்லா தற்காலிக நினைவகங்களையும் கண்காணிக்கிறது -Comment[te]=వ్యవస్థలోని అన్ని కుకీల జాడని వుంచుకుంటుంది -Comment[tg]=Гузаргоҳи ҳамаша Cookies дар система муҳофизат кунед -Comment[th]=ใช้ติดตามคุกกีทั้งหมดในระบบ -Comment[tr]=Sistemdeki tüm çerezleri izler -Comment[tt]=Sistemdäge bar cookie'larnı küz astında tota -Comment[uk]=Стежить за всіма куками в системі -Comment[uz]=Tizimdagi hamma kukilarni kuzatadi -Comment[uz@cyrillic]=Тизимдаги ҳамма кукиларни кузатади -Comment[vi]=Theo dõi các tập tin cookie trong hệ thống. -Comment[zh_CN]=将全部 cookies 的记录保存在系统中 -Comment[zh_TW]=追蹤系統所有的 cookies -ServiceTypes=KDEDModule -Exec=kcookiejar -X-DCOP-ServiceType=Unique -X-TDE-StartupNotify=false -X-TDE-ModuleType=Library -X-TDE-Library=kcookiejar -X-TDE-FactoryName=kcookiejar -X-TDE-Kded-autoload=false -X-TDE-Kded-load-on-demand=true diff --git a/kioslave/http/kcookiejar/kcookiejar.h b/kioslave/http/kcookiejar/kcookiejar.h deleted file mode 100644 index bb16d75d3..000000000 --- a/kioslave/http/kcookiejar/kcookiejar.h +++ /dev/null @@ -1,365 +0,0 @@ -/* - This file is part of the KDE File Manager - - Copyright (C) 1998 Waldo Bastian (bastian@kde.org) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - version 2 as published by the Free Software Foundation. - - This software is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this library; see the file COPYING. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ -//---------------------------------------------------------------------------- -// -// KDE File Manager -- HTTP Cookies -// $Id$ - -#ifndef KCOOKIEJAR_H -#define KCOOKIEJAR_H - -#include <tqstring.h> -#include <tqstringlist.h> -#include <tqdict.h> -#include <tqptrlist.h> -#include <time.h> - -class TDEConfig; -class KCookieJar; -class KHttpCookie; -class KHttpCookieList; - -typedef KHttpCookie *KHttpCookiePtr; - -enum KCookieAdvice -{ - KCookieDunno=0, - KCookieAccept, - KCookieReject, - KCookieAsk -}; - -class KHttpCookie -{ - friend class KCookieJar; - friend class KHttpCookieList; - -protected: - TQString mHost; - TQString mDomain; - TQString mPath; - TQString mName; - TQString mValue; - time_t mExpireDate; - int mProtocolVersion; - bool mSecure; - bool mCrossDomain; - bool mHttpOnly; - bool mExplicitPath; - TQValueList<long> mWindowIds; - - TQString cookieStr(bool useDOMFormat); - -public: - KHttpCookie(const TQString &_host=TQString::null, - const TQString &_domain=TQString::null, - const TQString &_path=TQString::null, - const TQString &_name=TQString::null, - const TQString &_value=TQString::null, - time_t _expireDate=0, - int _protocolVersion=0, - bool _secure = false, - bool _httpOnly = false, - bool _explicitPath = false); - - TQString domain(void) { return mDomain; } - TQString host(void) { return mHost; } - TQString path(void) { return mPath; } - TQString name(void) { return mName; } - TQString value(void) { return mValue; } - TQValueList<long> &windowIds(void) { return mWindowIds; } - void fixDomain(const TQString &domain) { mDomain = domain; } - time_t expireDate(void) { return mExpireDate; } - int protocolVersion(void) { return mProtocolVersion; } - bool isSecure(void) { return mSecure; } - bool isExpired(time_t currentDate); - bool isCrossDomain(void) { return mCrossDomain; } - bool isHttpOnly(void) { return mHttpOnly; } - bool hasExplicitPath(void) { return mExplicitPath; } - bool match(const TQString &fqdn, const TQStringList &domainList, const TQString &path); -}; - -class KHttpCookieList : public TQPtrList<KHttpCookie> -{ -public: - KHttpCookieList() : TQPtrList<KHttpCookie>(), advice( KCookieDunno ) - { } - virtual ~KHttpCookieList() { } - - virtual int compareItems( void * item1, void * item2); - KCookieAdvice getAdvice(void) { return advice; } - void setAdvice(KCookieAdvice _advice) { advice = _advice; } - -private: - KCookieAdvice advice; -}; - -class KCookieJar -{ -public: - /** - * Constructs a new cookie jar - * - * One jar should be enough for all cookies. - */ - KCookieJar(); - - /** - * Destructs the cookie jar - * - * Poor little cookies, they will all be eaten by the cookie monster! - */ - ~KCookieJar(); - - /** - * Returns whether the cookiejar has been changed - */ - bool changed() const { return m_cookiesChanged || m_configChanged; } - - /** - * Store all the cookies in a safe(?) place - */ - bool saveCookies(const TQString &_filename); - - /** - * Load all the cookies from file and add them to the cookie jar. - */ - bool loadCookies(const TQString &_filename); - - /** - * Save the cookie configuration - */ - void saveConfig(TDEConfig *_config); - - /** - * Load the cookie configuration - */ - void loadConfig(TDEConfig *_config, bool reparse = false); - - /** - * Looks for cookies in the cookie jar which are appropriate for _url. - * Returned is a string containing all appropriate cookies in a format - * which can be added to a HTTP-header without any additional processing. - * - * If @p useDOMFormat is true, the string is formatted in a format - * in compliance with the DOM standard. - * @p pendingCookies contains a list of cookies that have not been - * approved yet by the user but that will be included in the result - * none the less. - */ - TQString findCookies(const TQString &_url, bool useDOMFormat, long windowId, KHttpCookieList *pendingCookies=0); - - /** - * This function parses cookie_headers and returns a linked list of - * valid KHttpCookie objects for all cookies found in cookie_headers. - * If no cookies could be found 0 is returned. - * - * cookie_headers should be a concatenation of all lines of a HTTP-header - * which start with "Set-Cookie". The lines should be separated by '\n's. - */ - KHttpCookieList makeCookies(const TQString &_url, const TQCString &cookie_headers, long windowId); - - /** - * This function parses cookie_headers and returns a linked list of - * valid KHttpCookie objects for all cookies found in cookie_headers. - * If no cookies could be found 0 is returned. - * - * cookie_domstr should be a concatenation of "name=value" pairs, separated - * by a semicolon ';'. - */ - KHttpCookieList makeDOMCookies(const TQString &_url, const TQCString &cookie_domstr, long windowId); - - /** - * This function hands a KHttpCookie object over to the cookie jar. - * - * On return cookiePtr is set to 0. - */ - void addCookie(KHttpCookiePtr &cookiePtr); - - /** - * This function advices whether a single KHttpCookie object should - * be added to the cookie jar. - * - * Possible return values are: - * - KCookieAccept, the cookie should be added - * - KCookieReject, the cookie should not be added - * - KCookieAsk, the user should decide what to do - */ - KCookieAdvice cookieAdvice(KHttpCookiePtr cookiePtr); - - /** - * This function gets the advice for all cookies originating from - * _domain. - * - * - KCookieDunno, no specific advice for _domain - * - KCookieAccept, accept all cookies for _domain - * - KCookieReject, reject all cookies for _domain - * - KCookieAsk, the user decides what to do with cookies for _domain - */ - KCookieAdvice getDomainAdvice(const TQString &_domain); - - /** - * This function sets the advice for all cookies originating from - * _domain. - * - * _advice can have the following values: - * - KCookieDunno, no specific advice for _domain - * - KCookieAccept, accept all cookies for _domain - * - KCookieReject, reject all cookies for _domain - * - KCookieAsk, the user decides what to do with cookies for _domain - */ - void setDomainAdvice(const TQString &_domain, KCookieAdvice _advice); - - /** - * This function sets the advice for all cookies originating from - * the same domain as _cookie - * - * _advice can have the following values: - * - KCookieDunno, no specific advice for _domain - * - KCookieAccept, accept all cookies for _domain - * - KCookieReject, reject all cookies for _domain - * - KCookieAsk, the user decides what to do with cookies for _domain - */ - void setDomainAdvice(KHttpCookiePtr _cookie, KCookieAdvice _advice); - - /** - * Get the global advice for cookies - * - * The returned advice can have the following values: - * - KCookieAccept, accept cookies - * - KCookieReject, reject cookies - * - KCookieAsk, the user decides what to do with cookies - * - * The global advice is used if the domain has no advice set. - */ - KCookieAdvice getGlobalAdvice() { return m_globalAdvice; } - - /** - * This function sets the global advice for cookies - * - * _advice can have the following values: - * - KCookieAccept, accept cookies - * - KCookieReject, reject cookies - * - KCookieAsk, the user decides what to do with cookies - * - * The global advice is used if the domain has no advice set. - */ - void setGlobalAdvice(KCookieAdvice _advice); - - /** - * Get a list of all domains known to the cookie jar. - * A domain is known to the cookie jar if: - * - It has a cookie originating from the domain - * - It has a specific advice set for the domain - */ - const TQStringList& getDomainList(); - - /** - * Get a list of all cookies in the cookie jar originating from _domain. - */ - const KHttpCookieList *getCookieList(const TQString & _domain, - const TQString& _fqdn ); - - /** - * Remove & delete a cookie from the jar. - * - * cookiePtr should be one of the entries in a KHttpCookieList. - * Update your KHttpCookieList by calling getCookieList after - * calling this function. - */ - void eatCookie(KHttpCookiePtr cookiePtr); - - /** - * Remove & delete all cookies for @p domain. - */ - void eatCookiesForDomain(const TQString &domain); - - /** - * Remove & delete all cookies - */ - void eatAllCookies(); - - /** - * Removes all end of session cookies set by the - * session @p windId. - */ - void eatSessionCookies( long windowId ); - - /** - * Removes all end of session cookies set by the - * session @p windId. - */ - void eatSessionCookies( const TQString& fqdn, long windowId, bool isFQDN = true ); - - /** - * Parses _url and returns the FQDN (_fqdn) and path (_path). - */ - static bool parseURL(const TQString &_url, - TQString &_fqdn, - TQString &_path); - - /** - * Returns a list of domains in @p _domainList relevant for this host. - * The list is sorted with the FQDN listed first and the top-most - * domain listed last - */ - void extractDomains(const TQString &_fqdn, - TQStringList &_domainList); - - static TQString adviceToStr(KCookieAdvice _advice); - static KCookieAdvice strToAdvice(const TQString &_str); - - /** Returns the */ - int preferredDefaultPolicy() const { return m_preferredPolicy; } - - /** Returns the */ - bool showCookieDetails () const { return m_showCookieDetails; } - - /** - * Sets the user's default preference cookie policy. - */ - void setPreferredDefaultPolicy (int value) { m_preferredPolicy = value; } - - /** - * Sets the user's preference of level of detail displayed - * by the cookie dialog. - */ - void setShowCookieDetails (bool value) { m_showCookieDetails = value; } - -protected: - void stripDomain(const TQString &_fqdn, TQString &_domain); - TQString stripDomain( KHttpCookiePtr cookiePtr); - -protected: - TQStringList m_domainList; - KCookieAdvice m_globalAdvice; - TQDict<KHttpCookieList> m_cookieDomains; - TQDict<int> m_twoLevelTLD; - - bool m_configChanged; - bool m_cookiesChanged; - bool m_showCookieDetails; - bool m_rejectCrossDomainCookies; - bool m_autoAcceptSessionCookies; - bool m_ignoreCookieExpirationDate; - - int m_preferredPolicy; -}; -#endif diff --git a/kioslave/http/kcookiejar/kcookiescfg.upd b/kioslave/http/kcookiejar/kcookiescfg.upd deleted file mode 100644 index 0ff26bde0..000000000 --- a/kioslave/http/kcookiejar/kcookiescfg.upd +++ /dev/null @@ -1,16 +0,0 @@ -# Update for old cookie config files, if present -Id=kde2.2/b1 -File=kcookiejarrc -Group=Browser Settings/HTTP,Cookie Policy - -# Update cookies config file... -Id=trinity.1/cvs -File=kcookiejarrc -Group=<default>,Cookie Dialog -Key=DefaultRadioButton,PreferredPolicy -Key=ShowCookieDetails -Group=Cookie Policy -Key=AcceptTempCookies,AcceptSessionCookies -Key=AutoAcceptSessionCookies,AcceptSessionCookies -Key=RejectCrossDomain,RejectCrossDomainCookies -Key=IgnoreCookieExpirationDate,IgnoreExpirationDate diff --git a/kioslave/http/kcookiejar/kcookieserver.cpp b/kioslave/http/kcookiejar/kcookieserver.cpp deleted file mode 100644 index 94df40b63..000000000 --- a/kioslave/http/kcookiejar/kcookieserver.cpp +++ /dev/null @@ -1,606 +0,0 @@ -/* -This file is part of KDE - - Copyright (C) 1998-2000 Waldo Bastian (bastian@kde.org) - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN -AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -//---------------------------------------------------------------------------- -// -// KDE Cookie Server -// $Id$ - -#define SAVE_DELAY 3 // Save after 3 minutes - -#include <unistd.h> - -#include <tqtimer.h> -#include <tqptrlist.h> -#include <tqfile.h> - -#include <dcopclient.h> - -#include <kconfig.h> -#include <kdebug.h> -#include <kapplication.h> -#include <kcmdlineargs.h> -#include <kstandarddirs.h> - -#include "kcookiejar.h" -#include "kcookiewin.h" -#include "kcookieserver.h" - -extern "C" { - KDE_EXPORT KDEDModule *create_kcookiejar(const TQCString &name) - { - return new KCookieServer(name); - } -} - - -// Cookie field indexes -enum CookieDetails { CF_DOMAIN=0, CF_PATH, CF_NAME, CF_HOST, - CF_VALUE, CF_EXPIRE, CF_PROVER, CF_SECURE }; - - -class CookieRequest { -public: - DCOPClient *client; - DCOPClientTransaction *transaction; - TQString url; - bool DOM; - long windowId; -}; - -template class TQPtrList<CookieRequest>; - -class RequestList : public TQPtrList<CookieRequest> -{ -public: - RequestList() : TQPtrList<CookieRequest>() { } -}; - -KCookieServer::KCookieServer(const TQCString &name) - :KDEDModule(name) -{ - mOldCookieServer = new DCOPClient(); // backwards compatibility. - mOldCookieServer->registerAs("kcookiejar", false); - mOldCookieServer->setDaemonMode( true ); - mCookieJar = new KCookieJar; - mPendingCookies = new KHttpCookieList; - mPendingCookies->setAutoDelete(true); - mRequestList = new RequestList; - mAdvicePending = false; - mTimer = new TQTimer(); - connect( mTimer, TQT_SIGNAL( timeout()), TQT_SLOT( slotSave())); - mConfig = new TDEConfig("kcookiejarrc"); - mCookieJar->loadConfig( mConfig ); - - TQString filename = locateLocal("data", "kcookiejar/cookies"); - - // Stay backwards compatible! - TQString filenameOld = locate("data", "kfm/cookies"); - if (!filenameOld.isEmpty()) - { - mCookieJar->loadCookies( filenameOld ); - if (mCookieJar->saveCookies( filename)) - { - unlink(TQFile::encodeName(filenameOld)); // Remove old kfm cookie file - } - } - else - { - mCookieJar->loadCookies( filename); - } - connect(this, TQT_SIGNAL(windowUnregistered(long)), - this, TQT_SLOT(slotDeleteSessionCookies(long))); -} - -KCookieServer::~KCookieServer() -{ - if (mCookieJar->changed()) - slotSave(); - delete mOldCookieServer; - delete mCookieJar; - delete mTimer; - delete mPendingCookies; - delete mConfig; -} - -bool KCookieServer::cookiesPending( const TQString &url, KHttpCookieList *cookieList ) -{ - TQString fqdn; - TQStringList domains; - TQString path; - // Check whether 'url' has cookies on the pending list - if (mPendingCookies->isEmpty()) - return false; - if (!KCookieJar::parseURL(url, fqdn, path)) - return false; - - mCookieJar->extractDomains( fqdn, domains ); - for( KHttpCookie *cookie = mPendingCookies->first(); - cookie != 0L; - cookie = mPendingCookies->next()) - { - if (cookie->match( fqdn, domains, path)) - { - if (!cookieList) - return true; - cookieList->append(cookie); - } - } - if (!cookieList) - return false; - return cookieList->isEmpty(); -} - -void KCookieServer::addCookies( const TQString &url, const TQCString &cookieHeader, - long windowId, bool useDOMFormat ) -{ - KHttpCookieList cookieList; - if (useDOMFormat) - cookieList = mCookieJar->makeDOMCookies(url, cookieHeader, windowId); - else - cookieList = mCookieJar->makeCookies(url, cookieHeader, windowId); - - checkCookies(&cookieList); - - for(KHttpCookiePtr cookie = cookieList.first(); cookie; cookie = cookieList.first()) - mPendingCookies->append(cookieList.take()); - - if (!mAdvicePending) - { - mAdvicePending = true; - while (!mPendingCookies->isEmpty()) - { - checkCookies(0); - } - mAdvicePending = false; - } -} - -void KCookieServer::checkCookies( KHttpCookieList *cookieList) -{ - KHttpCookieList *list; - - if (cookieList) - list = cookieList; - else - list = mPendingCookies; - - KHttpCookiePtr cookie = list->first(); - while (cookie) - { - kdDebug(7104) << "checkCookies: Asking cookie advice for " << cookie->host() << endl; - KCookieAdvice advice = mCookieJar->cookieAdvice(cookie); - switch(advice) - { - case KCookieAccept: - list->take(); - mCookieJar->addCookie(cookie); - cookie = list->current(); - break; - - case KCookieReject: - list->take(); - delete cookie; - cookie = list->current(); - break; - - default: - cookie = list->next(); - break; - } - } - - if (cookieList || list->isEmpty()) - return; - - KHttpCookiePtr currentCookie = mPendingCookies->first(); - - KHttpCookieList currentList; - currentList.append(currentCookie); - TQString currentHost = currentCookie->host(); - - cookie = mPendingCookies->next(); - while (cookie) - { - if (cookie->host() == currentHost) - { - currentList.append(cookie); - } - cookie = mPendingCookies->next(); - } - - KCookieWin *kw = new KCookieWin( 0L, currentList, - mCookieJar->preferredDefaultPolicy(), - mCookieJar->showCookieDetails() ); - KCookieAdvice userAdvice = kw->advice(mCookieJar, currentCookie); - delete kw; - // Save the cookie config if it has changed - mCookieJar->saveConfig( mConfig ); - - // Apply the user's choice to all cookies that are currently - // queued for this host. - cookie = mPendingCookies->first(); - while (cookie) - { - if (cookie->host() == currentHost) - { - switch(userAdvice) - { - case KCookieAccept: - mPendingCookies->take(); - mCookieJar->addCookie(cookie); - cookie = mPendingCookies->current(); - break; - - case KCookieReject: - mPendingCookies->take(); - delete cookie; - cookie = mPendingCookies->current(); - break; - - default: - tqWarning(__FILE__":%d Problem!", __LINE__); - cookie = mPendingCookies->next(); - break; - } - } - else - { - cookie = mPendingCookies->next(); - } - } - - - // Check if we can handle any request - for ( CookieRequest *request = mRequestList->first(); request;) - { - if (!cookiesPending( request->url )) - { - TQCString replyType; - TQByteArray replyData; - TQString res = mCookieJar->findCookies( request->url, request->DOM, request->windowId ); - - TQDataStream stream2(replyData, IO_WriteOnly); - stream2 << res; - replyType = "TQString"; - request->client->endTransaction( request->transaction, - replyType, replyData); - CookieRequest *tmp = request; - request = mRequestList->next(); - mRequestList->removeRef( tmp ); - delete tmp; - } - else - { - request = mRequestList->next(); - } - } - if (mCookieJar->changed()) - saveCookieJar(); -} - -void KCookieServer::slotSave() -{ - TQString filename = locateLocal("data", "kcookiejar/cookies"); - mCookieJar->saveCookies(filename); -} - -void KCookieServer::saveCookieJar() -{ - if( mTimer->isActive() ) - return; - - mTimer->start( 1000*60*SAVE_DELAY, true ); -} - -void KCookieServer::putCookie( TQStringList& out, KHttpCookie *cookie, - const TQValueList<int>& fields ) -{ - TQValueList<int>::ConstIterator i = fields.begin(); - for ( ; i != fields.end(); ++i ) - { - switch(*i) - { - case CF_DOMAIN : - out << cookie->domain(); - break; - case CF_NAME : - out << cookie->name(); - break; - case CF_PATH : - out << cookie->path(); - break; - case CF_HOST : - out << cookie->host(); - break; - case CF_VALUE : - out << cookie->value(); - break; - case CF_EXPIRE : - out << TQString::number(cookie->expireDate()); - break; - case CF_PROVER : - out << TQString::number(cookie->protocolVersion()); - break; - case CF_SECURE : - out << TQString::number( cookie->isSecure() ? 1 : 0 ); - break; - default : - out << TQString::null; - } - } -} - -bool KCookieServer::cookieMatches( KHttpCookiePtr c, - TQString domain, TQString fqdn, - TQString path, TQString name ) -{ - if( c ) - { - bool hasDomain = !domain.isEmpty(); - return - ((hasDomain && c->domain() == domain) || - fqdn == c->host()) && - (c->path() == path) && - (c->name() == name) && - (!c->isExpired(time(0))); - } - return false; -} - -// DCOP function -TQString -KCookieServer::findCookies(TQString url) -{ - return findCookies(url, 0); -} - -// DCOP function -TQString -KCookieServer::findCookies(TQString url, long windowId) -{ - if (cookiesPending(url)) - { - CookieRequest *request = new CookieRequest; - request->client = callingDcopClient(); - request->transaction = request->client->beginTransaction(); - request->url = url; - request->DOM = false; - request->windowId = windowId; - mRequestList->append( request ); - return TQString::null; // Talk to you later :-) - } - - TQString cookies = mCookieJar->findCookies(url, false, windowId); - - if (mCookieJar->changed()) - saveCookieJar(); - - return cookies; -} - -// DCOP function -TQStringList -KCookieServer::findDomains() -{ - TQStringList result; - const TQStringList domains = mCookieJar->getDomainList(); - for ( TQStringList::ConstIterator domIt = domains.begin(); - domIt != domains.end(); ++domIt ) - { - // Ignore domains that have policy set for but contain - // no cookies whatsoever... - const KHttpCookieList* list = mCookieJar->getCookieList(*domIt, ""); - if ( list && !list->isEmpty() ) - result << *domIt; - } - return result; -} - -// DCOP function -TQStringList -KCookieServer::findCookies(TQValueList<int> fields, - TQString domain, - TQString fqdn, - TQString path, - TQString name) -{ - TQStringList result; - bool allDomCookies = name.isEmpty(); - - const KHttpCookieList* list = mCookieJar->getCookieList(domain, fqdn); - if ( list && !list->isEmpty() ) - { - TQPtrListIterator<KHttpCookie>it( *list ); - for ( ; it.current(); ++it ) - { - if ( !allDomCookies ) - { - if ( cookieMatches(it.current(), domain, fqdn, path, name) ) - { - putCookie(result, it.current(), fields); - break; - } - } - else - putCookie(result, it.current(), fields); - } - } - return result; -} - -// DCOP function -TQString -KCookieServer::findDOMCookies(TQString url) -{ - return findDOMCookies(url, 0); -} - -// DCOP function -TQString -KCookieServer::findDOMCookies(TQString url, long windowId) -{ - // We don't wait for pending cookies because it locks up konqueror - // which can cause a deadlock if it happens to have a popup-menu up. - // Instead we just return pending cookies as if they had been accepted already. - KHttpCookieList pendingCookies; - cookiesPending(url, &pendingCookies); - - return mCookieJar->findCookies(url, true, windowId, &pendingCookies); -} - -// DCOP function -void -KCookieServer::addCookies(TQString arg1, TQCString arg2, long arg3) -{ - addCookies(arg1, arg2, arg3, false); -} - -// DCOP function -void -KCookieServer::deleteCookie(TQString domain, TQString fqdn, - TQString path, TQString name) -{ - const KHttpCookieList* list = mCookieJar->getCookieList( domain, fqdn ); - if ( list && !list->isEmpty() ) - { - TQPtrListIterator<KHttpCookie>it (*list); - for ( ; it.current(); ++it ) - { - if( cookieMatches(it.current(), domain, fqdn, path, name) ) - { - mCookieJar->eatCookie( it.current() ); - saveCookieJar(); - break; - } - } - } -} - -// DCOP function -void -KCookieServer::deleteCookiesFromDomain(TQString domain) -{ - mCookieJar->eatCookiesForDomain(domain); - saveCookieJar(); -} - - -// Qt function -void -KCookieServer::slotDeleteSessionCookies( long windowId ) -{ - deleteSessionCookies(windowId); -} - -// DCOP function -void -KCookieServer::deleteSessionCookies( long windowId ) -{ - mCookieJar->eatSessionCookies( windowId ); - saveCookieJar(); -} - -void -KCookieServer::deleteSessionCookiesFor(TQString fqdn, long windowId) -{ - mCookieJar->eatSessionCookies( fqdn, windowId ); - saveCookieJar(); -} - -// DCOP function -void -KCookieServer::deleteAllCookies() -{ - mCookieJar->eatAllCookies(); - saveCookieJar(); -} - -// DCOP function -void -KCookieServer::addDOMCookies(TQString arg1, TQCString arg2, long arg3) -{ - addCookies(arg1, arg2, arg3, true); -} - -// DCOP function -void -KCookieServer::setDomainAdvice(TQString url, TQString advice) -{ - TQString fqdn; - TQString dummy; - if (KCookieJar::parseURL(url, fqdn, dummy)) - { - TQStringList domains; - mCookieJar->extractDomains(fqdn, domains); - - mCookieJar->setDomainAdvice(domains[domains.count() > 3 ? 3 : 0], - KCookieJar::strToAdvice(advice)); - // Save the cookie config if it has changed - mCookieJar->saveConfig( mConfig ); - } -} - -// DCOP function -TQString -KCookieServer::getDomainAdvice(TQString url) -{ - KCookieAdvice advice = KCookieDunno; - TQString fqdn; - TQString dummy; - if (KCookieJar::parseURL(url, fqdn, dummy)) - { - TQStringList domains; - mCookieJar->extractDomains(fqdn, domains); - - TQStringList::ConstIterator it = domains.begin(); - while ( (advice == KCookieDunno) && (it != domains.end()) ) - { - // Always check advice in both ".domain" and "domain". Note - // that we only want to check "domain" if it matches the - // fqdn of the requested URL. - if ( (*it)[0] == '.' || (*it) == fqdn ) - advice = mCookieJar->getDomainAdvice(*it); - ++it; - } - if (advice == KCookieDunno) - advice = mCookieJar->getGlobalAdvice(); - } - return KCookieJar::adviceToStr(advice); -} - -// DCOP function -void -KCookieServer::reloadPolicy() -{ - mCookieJar->loadConfig( mConfig, true ); -} - -// DCOP function -void -KCookieServer::shutdown() -{ - deleteLater(); -} - -#include "kcookieserver.moc" - diff --git a/kioslave/http/kcookiejar/kcookieserver.h b/kioslave/http/kcookiejar/kcookieserver.h deleted file mode 100644 index 2cbb9ccf1..000000000 --- a/kioslave/http/kcookiejar/kcookieserver.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - This file is part of the KDE File Manager - - Copyright (C) 1998 Waldo Bastian (bastian@kde.org) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - version 2 as published by the Free Software Foundation. - - This software is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this library; see the file COPYING. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ -//---------------------------------------------------------------------------- -// -// KDE Cookie Server -// $Id$ - -#ifndef KCOOKIESERVER_H -#define KCOOKIESERVER_H - -#include <tqstringlist.h> -#include <kded/kdedmodule.h> - -class KHttpCookieList; -class KCookieJar; -class KHttpCookie; -class TQTimer; -class RequestList; -class DCOPClient; -class TDEConfig; - -class KCookieServer : public KDEDModule -{ - Q_OBJECT - K_DCOP -public: - KCookieServer(const TQCString &); - ~KCookieServer(); - -k_dcop: - TQString findCookies(TQString); - TQString findCookies(TQString, long); - TQStringList findDomains(); - TQStringList findCookies(TQValueList<int>,TQString,TQString,TQString,TQString); - TQString findDOMCookies(TQString); - TQString findDOMCookies(TQString, long); - void addCookies(TQString, TQCString, long); - void deleteCookie(TQString, TQString, TQString, TQString); - void deleteCookiesFromDomain(TQString); - void deleteSessionCookies(long); - void deleteSessionCookiesFor(TQString, long); - void deleteAllCookies(); - void addDOMCookies(TQString, TQCString, long); - /** - * Sets the cookie policy for the domain associated with the specified URL. - */ - void setDomainAdvice(TQString url, TQString advice); - /** - * Returns the cookie policy in effect for the specified URL. - */ - TQString getDomainAdvice(TQString url); - void reloadPolicy(); - void shutdown(); - -public: - bool cookiesPending(const TQString &url, KHttpCookieList *cookieList=0); - void addCookies(const TQString &url, const TQCString &cookieHeader, - long windowId, bool useDOMFormat); - void checkCookies(KHttpCookieList *cookieList); - -public slots: - void slotSave(); - void slotDeleteSessionCookies(long); - -protected: - KCookieJar *mCookieJar; - KHttpCookieList *mPendingCookies; - RequestList *mRequestList; - TQTimer *mTimer; - bool mAdvicePending; - DCOPClient *mOldCookieServer; - TDEConfig *mConfig; - -private: - virtual int newInstance(TQValueList<TQCString>) { return 0; } - bool cookieMatches(KHttpCookie*, TQString, TQString, TQString, TQString); - void putCookie(TQStringList&, KHttpCookie*, const TQValueList<int>&); - void saveCookieJar(); -}; - -#endif diff --git a/kioslave/http/kcookiejar/kcookiewin.cpp b/kioslave/http/kcookiejar/kcookiewin.cpp deleted file mode 100644 index 57a22f62c..000000000 --- a/kioslave/http/kcookiejar/kcookiewin.cpp +++ /dev/null @@ -1,382 +0,0 @@ -/* -This file is part of KDE - - Copyright (C) 2000- Waldo Bastian <bastian@kde.org> - Copyright (C) 2000- Dawit Alemayehu <adawit@kde.org> - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN -AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ -//---------------------------------------------------------------------------- -// -// KDE File Manager -- HTTP Cookie Dialogs -// $Id$ - -// The purpose of the QT_NO_TOOLTIP and QT_NO_WHATSTHIS ifdefs is because -// this file is also used in Konqueror/Embedded. One of the aims of -// Konqueror/Embedded is to be a small as possible to fit on embedded -// devices. For this it's also useful to strip out unneeded features of -// Qt, like for example TQToolTip or TQWhatsThis. The availability (or the -// lack thereof) can be determined using these preprocessor defines. -// The same applies to the QT_NO_ACCEL ifdef below. I hope it doesn't make -// too much trouble... (Simon) - -#include <tqhbox.h> -#include <tqvbox.h> -#include <tqaccel.h> -#include <tqlabel.h> -#include <tqwidget.h> -#include <tqlayout.h> -#include <tqgroupbox.h> -#include <tqdatetime.h> -#include <tqmessagebox.h> -#include <tqpushbutton.h> -#include <tqradiobutton.h> -#include <tqvbuttongroup.h> - -#ifndef QT_NO_TOOLTIP -#include <tqtooltip.h> -#endif - -#ifndef QT_NO_WHATSTHIS -#include <tqwhatsthis.h> -#endif - -#include <kidna.h> -#include <twin.h> -#include <klocale.h> -#include <kglobal.h> -#include <kurllabel.h> -#include <klineedit.h> -#include <kiconloader.h> -#include <kapplication.h> - -#ifdef Q_WS_X11 -#include <X11/Xlib.h> -#endif - -#include "kcookiejar.h" -#include "kcookiewin.h" - -KCookieWin::KCookieWin( TQWidget *parent, KHttpCookieList cookieList, - int defaultButton, bool showDetails ) - :KDialog( parent, "cookiealert", true ) -{ -#ifndef Q_WS_QWS //FIXME(E): Implement for Qt Embedded - setCaption( i18n("Cookie Alert") ); - setIcon( SmallIcon("cookie") ); - // all cookies in the list should have the same window at this time, so let's take the first -# ifdef Q_WS_X11 - if( cookieList.first()->windowIds().count() > 0 ) - { - XSetTransientForHint( tqt_xdisplay(), winId(), cookieList.first()->windowIds().first()); - } - else - { - // No window associated... make sure the user notices our dialog. - KWin::setState( winId(), NET::KeepAbove ); - kapp->updateUserTimestamp(); - } -# endif -#endif - // Main widget's layout manager... - TQVBoxLayout* vlayout = new TQVBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() ); - vlayout->setResizeMode( TQLayout::Fixed ); - - // Cookie image and message to user - TQHBox* hBox = new TQHBox( this ); - hBox->setSpacing( KDialog::spacingHint() ); - TQLabel* icon = new TQLabel( hBox ); - icon->setPixmap( TQMessageBox::standardIcon(TQMessageBox::Warning) ); - icon->setAlignment( Qt::AlignCenter ); - icon->setFixedSize( 2*icon->sizeHint() ); - - int count = cookieList.count(); - - TQVBox* vBox = new TQVBox( hBox ); - TQString txt = i18n("You received a cookie from", - "You received %n cookies from", count); - TQLabel* lbl = new TQLabel( txt, vBox ); - lbl->setAlignment( Qt::AlignCenter ); - KHttpCookiePtr cookie = cookieList.first(); - - TQString host (cookie->host()); - int pos = host.find(':'); - if ( pos > 0 ) - { - TQString portNum = host.left(pos); - host.remove(0, pos+1); - host += ':'; - host += portNum; - } - - txt = TQString("<b>%1</b>").arg( KIDNA::toUnicode(host) ); - if (cookie->isCrossDomain()) - txt += i18n(" <b>[Cross Domain!]</b>"); - lbl = new TQLabel( txt, vBox ); - lbl->setAlignment( Qt::AlignCenter ); - lbl = new TQLabel( i18n("Do you want to accept or reject?"), vBox ); - lbl->setAlignment( Qt::AlignCenter ); - vlayout->addWidget( hBox, 0, Qt::AlignLeft ); - - // Cookie Details dialog... - m_detailView = new KCookieDetail( cookieList, count, this ); - vlayout->addWidget( m_detailView ); - m_showDetails = showDetails; - m_showDetails ? m_detailView->show():m_detailView->hide(); - - // Cookie policy choice... - m_btnGrp = new TQVButtonGroup( i18n("Apply Choice To"), this ); - m_btnGrp->setRadioButtonExclusive( true ); - - txt = (count == 1)? i18n("&Only this cookie") : i18n("&Only these cookies"); - TQRadioButton* rb = new TQRadioButton( txt, m_btnGrp ); -#ifndef QT_NO_WHATSTHIS - TQWhatsThis::add( rb, i18n("Select this option to accept/reject only this cookie. " - "You will be prompted if another cookie is received. " - "<em>(see WebBrowsing/Cookies in the Control Center)</em>." ) ); -#endif - m_btnGrp->insert( rb ); - rb = new TQRadioButton( i18n("All cookies from this do&main"), m_btnGrp ); -#ifndef QT_NO_WHATSTHIS - TQWhatsThis::add( rb, i18n("Select this option to accept/reject all cookies from " - "this site. Choosing this option will add a new policy for " - "the site this cookie originated from. This policy will be " - "permanent until you manually change it from the Control Center " - "<em>(see WebBrowsing/Cookies in the Control Center)</em>.") ); -#endif - m_btnGrp->insert( rb ); - rb = new TQRadioButton( i18n("All &cookies"), m_btnGrp ); -#ifndef QT_NO_WHATSTHIS - TQWhatsThis::add( rb, i18n("Select this option to accept/reject all cookies from " - "anywhere. Choosing this option will change the global " - "cookie policy set in the Control Center for all cookies " - "<em>(see WebBrowsing/Cookies in the Control Center)</em>.") ); -#endif - m_btnGrp->insert( rb ); - vlayout->addWidget( m_btnGrp ); - - if ( defaultButton > -1 && defaultButton < 3 ) - m_btnGrp->setButton( defaultButton ); - else - m_btnGrp->setButton( 1 ); - - // Accept/Reject buttons - TQWidget* bbox = new TQWidget( this ); - TQBoxLayout* bbLay = new TQHBoxLayout( bbox ); - bbLay->setSpacing( KDialog::spacingHint() ); - TQPushButton* btn = new TQPushButton( i18n("&Accept"), bbox ); - btn->setDefault( true ); - btn->setFocus(); - connect( btn, TQT_SIGNAL(clicked()), TQT_SLOT(accept()) ); - bbLay->addWidget( btn ); - btn = new TQPushButton( i18n("&Reject"), bbox ); - connect( btn, TQT_SIGNAL(clicked()), TQT_SLOT(reject()) ); - bbLay->addWidget( btn ); - bbLay->addStretch( 1 ); -#ifndef QT_NO_ACCEL - TQAccel* a = new TQAccel( this ); - a->connectItem( a->insertItem(Qt::Key_Escape), btn, TQT_SLOT(animateClick()) ); -#endif - - m_button = new TQPushButton( bbox ); - m_button->setText( m_showDetails ? i18n("&Details <<"):i18n("&Details >>") ); - connect( m_button, TQT_SIGNAL(clicked()), TQT_SLOT(slotCookieDetails()) ); - bbLay->addWidget( m_button ); -#ifndef QT_NO_WHATSTHIS - TQWhatsThis::add( m_button, i18n("See or modify the cookie information") ); -#endif - - - vlayout->addWidget( bbox ); - setFixedSize( sizeHint() ); -} - -KCookieWin::~KCookieWin() -{ -} - -void KCookieWin::slotCookieDetails() -{ - if ( m_detailView->isVisible() ) - { - m_detailView->setMaximumSize( 0, 0 ); - m_detailView->adjustSize(); - m_detailView->hide(); - m_button->setText( i18n( "&Details >>" ) ); - m_showDetails = false; - } - else - { - m_detailView->setMaximumSize( 1000, 1000 ); - m_detailView->adjustSize(); - m_detailView->show(); - m_button->setText( i18n( "&Details <<" ) ); - m_showDetails = true; - } -} - -KCookieAdvice KCookieWin::advice( KCookieJar *cookiejar, KHttpCookie* cookie ) -{ - int result = exec(); - - cookiejar->setShowCookieDetails ( m_showDetails ); - - KCookieAdvice advice = (result==TQDialog::Accepted) ? KCookieAccept:KCookieReject; - - int preferredPolicy = m_btnGrp->id( m_btnGrp->selected() ); - cookiejar->setPreferredDefaultPolicy( preferredPolicy ); - - switch ( preferredPolicy ) - { - case 2: - cookiejar->setGlobalAdvice( advice ); - break; - case 1: - cookiejar->setDomainAdvice( cookie, advice ); - break; - case 0: - default: - break; - } - return advice; -} - -KCookieDetail::KCookieDetail( KHttpCookieList cookieList, int cookieCount, - TQWidget* parent, const char* name ) - :TQGroupBox( parent, name ) -{ - setTitle( i18n("Cookie Details") ); - TQGridLayout* grid = new TQGridLayout( this, 9, 2, - KDialog::spacingHint(), - KDialog::marginHint() ); - grid->addRowSpacing( 0, fontMetrics().lineSpacing() ); - grid->setColStretch( 1, 3 ); - - TQLabel* label = new TQLabel( i18n("Name:"), this ); - grid->addWidget( label, 1, 0 ); - m_name = new KLineEdit( this ); - m_name->setReadOnly( true ); - m_name->setMaximumWidth( fontMetrics().maxWidth() * 25 ); - grid->addWidget( m_name, 1 ,1 ); - - //Add the value - label = new TQLabel( i18n("Value:"), this ); - grid->addWidget( label, 2, 0 ); - m_value = new KLineEdit( this ); - m_value->setReadOnly( true ); - m_value->setMaximumWidth( fontMetrics().maxWidth() * 25 ); - grid->addWidget( m_value, 2, 1); - - label = new TQLabel( i18n("Expires:"), this ); - grid->addWidget( label, 3, 0 ); - m_expires = new KLineEdit( this ); - m_expires->setReadOnly( true ); - m_expires->setMaximumWidth(fontMetrics().maxWidth() * 25 ); - grid->addWidget( m_expires, 3, 1); - - label = new TQLabel( i18n("Path:"), this ); - grid->addWidget( label, 4, 0 ); - m_path = new KLineEdit( this ); - m_path->setReadOnly( true ); - m_path->setMaximumWidth( fontMetrics().maxWidth() * 25 ); - grid->addWidget( m_path, 4, 1); - - label = new TQLabel( i18n("Domain:"), this ); - grid->addWidget( label, 5, 0 ); - m_domain = new KLineEdit( this ); - m_domain->setReadOnly( true ); - m_domain->setMaximumWidth( fontMetrics().maxWidth() * 25 ); - grid->addWidget( m_domain, 5, 1); - - label = new TQLabel( i18n("Exposure:"), this ); - grid->addWidget( label, 6, 0 ); - m_secure = new KLineEdit( this ); - m_secure->setReadOnly( true ); - m_secure->setMaximumWidth( fontMetrics().maxWidth() * 25 ); - grid->addWidget( m_secure, 6, 1 ); - - if ( cookieCount > 1 ) - { - TQPushButton* btnNext = new TQPushButton( i18n("Next cookie","&Next >>"), this ); - btnNext->setFixedSize( btnNext->sizeHint() ); - grid->addMultiCellWidget( btnNext, 8, 8, 0, 1 ); - connect( btnNext, TQT_SIGNAL(clicked()), TQT_SLOT(slotNextCookie()) ); -#ifndef QT_NO_TOOLTIP - TQToolTip::add( btnNext, i18n("Show details of the next cookie") ); -#endif - } - m_cookieList = cookieList; - m_cookie = 0; - slotNextCookie(); -} - -KCookieDetail::~KCookieDetail() -{ -} - -void KCookieDetail::slotNextCookie() -{ - KHttpCookiePtr cookie = m_cookieList.first(); - if (m_cookie) while(cookie) - { - if (cookie == m_cookie) - { - cookie = m_cookieList.next(); - break; - } - cookie = m_cookieList.next(); - } - m_cookie = cookie; - if (!m_cookie) - m_cookie = m_cookieList.first(); - - if ( m_cookie ) - { - m_name->setText( m_cookie->name() ); - m_value->setText( ( m_cookie->value() ) ); - if ( m_cookie->domain().isEmpty() ) - m_domain->setText( i18n("Not specified") ); - else - m_domain->setText( m_cookie->domain() ); - m_path->setText( m_cookie->path() ); - TQDateTime cookiedate; - cookiedate.setTime_t( m_cookie->expireDate() ); - if ( m_cookie->expireDate() ) - m_expires->setText( TDEGlobal::locale()->formatDateTime(cookiedate) ); - else - m_expires->setText( i18n("End of Session") ); - TQString sec; - if (m_cookie->isSecure()) - { - if (m_cookie->isHttpOnly()) - sec = i18n("Secure servers only"); - else - sec = i18n("Secure servers, page scripts"); - } - else - { - if (m_cookie->isHttpOnly()) - sec = i18n("Servers"); - else - sec = i18n("Servers, page scripts"); - } - m_secure->setText( sec ); - } -} - -#include "kcookiewin.moc" diff --git a/kioslave/http/kcookiejar/kcookiewin.h b/kioslave/http/kcookiejar/kcookiewin.h deleted file mode 100644 index d739732dc..000000000 --- a/kioslave/http/kcookiejar/kcookiewin.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - This file is part of the KDE File Manager - - Copyright (C) 1998- Waldo Bastian (bastian@kde.org) - Copyright (C) 2000- Dawit Alemayehu (adawit@kde.org) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. - - This software is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this library; see the file COPYING. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ -//---------------------------------------------------------------------------- -// -// KDE File Manager -- HTTP Cookie Dialogs -// $Id$ - -#ifndef _KCOOKIEWIN_H_ -#define _KCOOKIEWIN_H_ - -#include <tqgroupbox.h> - -#include <kdialog.h> -#include "kcookiejar.h" - -class KLineEdit; -class TQPushButton; -class TQVButtonGroup; -class KURLLabel; - -class KCookieDetail : public TQGroupBox -{ - Q_OBJECT - -public : - KCookieDetail( KHttpCookieList cookieList, int cookieCount, TQWidget *parent=0, - const char *name=0 ); - ~KCookieDetail(); - -private : - KLineEdit* m_name; - KLineEdit* m_value; - KLineEdit* m_expires; - KLineEdit* m_domain; - KLineEdit* m_path; - KLineEdit* m_secure; - - KHttpCookieList m_cookieList; - KHttpCookiePtr m_cookie; - -private slots: - void slotNextCookie(); -}; - -class KCookieWin : public KDialog -{ - Q_OBJECT - -public : - KCookieWin( TQWidget *parent, KHttpCookieList cookieList, int defaultButton=0, - bool showDetails=false ); - ~KCookieWin(); - - KCookieAdvice advice( KCookieJar *cookiejar, KHttpCookie* cookie ); - -private : - TQPushButton* m_button; - TQVButtonGroup* m_btnGrp; - KCookieDetail* m_detailView; - bool m_showDetails; - -private slots: - void slotCookieDetails(); -}; -#endif diff --git a/kioslave/http/kcookiejar/main.cpp b/kioslave/http/kcookiejar/main.cpp deleted file mode 100644 index e24112888..000000000 --- a/kioslave/http/kcookiejar/main.cpp +++ /dev/null @@ -1,92 +0,0 @@ -/* -This file is part of KDE - - Copyright (C) 1998-2000 Waldo Bastian (bastian@kde.org) - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN -AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -#include <dcopclient.h> -#include <kcmdlineargs.h> -#include <klocale.h> -#include <kapplication.h> - -static const char description[] = - I18N_NOOP("HTTP Cookie Daemon"); - -static const char version[] = "1.0"; - -static const KCmdLineOptions options[] = -{ - { "shutdown", I18N_NOOP("Shut down cookie jar"), 0 }, - { "remove <domain>", I18N_NOOP("Remove cookies for domain"), 0 }, - { "remove-all", I18N_NOOP("Remove all cookies"), 0 }, - { "reload-config", I18N_NOOP("Reload configuration file"), 0 }, - KCmdLineLastOption -}; - -extern "C" KDE_EXPORT int kdemain(int argc, char *argv[]) -{ - KLocale::setMainCatalogue("tdelibs"); - TDECmdLineArgs::init(argc, argv, "kcookiejar", I18N_NOOP("HTTP cookie daemon"), - description, version); - - TDECmdLineArgs::addCmdLineOptions( options ); - - TDEInstance a("kcookiejar"); - - kapp->dcopClient()->attach(); - - TDECmdLineArgs *args = TDECmdLineArgs::parsedArgs(); - TQCString replyType; - TQByteArray replyData; - if (args->isSet("remove-all")) - { - kapp->dcopClient()->call( "kded", "kcookiejar", "deleteAllCookies()", TQByteArray(), replyType, replyData); - } - if (args->isSet("remove")) - { - TQString domain = args->getOption("remove"); - TQByteArray params; - TQDataStream stream(params, IO_WriteOnly); - stream << domain; - kapp->dcopClient()->call( "kded", "kcookiejar", "deleteCookiesFromDomain(TQString)", params, replyType, replyData); - } - if (args->isSet("shutdown")) - { - TQCString module = "kcookiejar"; - TQByteArray params; - TQDataStream stream(params, IO_WriteOnly); - stream << module; - kapp->dcopClient()->call( "kded", "kded", "unloadModule(TQCString)", params, replyType, replyData); - } - else if(args->isSet("reload-config")) - { - kapp->dcopClient()->call( "kded", "kcookiejar", "reloadPolicy()", TQByteArray(), replyType, replyData); - } - else - { - TQCString module = "kcookiejar"; - TQByteArray params; - TQDataStream stream(params, IO_WriteOnly); - stream << module; - kapp->dcopClient()->call( "kded", "kded", "loadModule(TQCString)", params, replyType, replyData); - } - - return 0; -} diff --git a/kioslave/http/kcookiejar/netscape_cookie_spec.html b/kioslave/http/kcookiejar/netscape_cookie_spec.html deleted file mode 100644 index eb190f2e3..000000000 --- a/kioslave/http/kcookiejar/netscape_cookie_spec.html +++ /dev/null @@ -1,331 +0,0 @@ -<HTML> -<HEAD> -<TITLE>Client Side State - HTTP Cookies</TITLE> -</HEAD> - -<BODY BGCOLOR="#ffffff" LINK="#0000ff" VLINK="#ff0000" ALINK="#ff0000" TEXT="#000000" > - - -<CENTER> -<!-- BANNER:s3 --> -<A HREF="/maps/banners/documentation_s3.map"><IMG SRC="/images/banners/documentation_s3.gif" ALT="Documentation" BORDER=0 WIDTH=612 HEIGHT=50 ISMAP USEMAP="#banner_nav"></A> -<MAP NAME="banner_nav"> -<AREA SHAPE=RECT COORDS="62,11,91,40" HREF="/"> -<AREA SHAPE=RECT COORDS="153,41,221,50" HREF="/"> -<AREA SHAPE=RECT COORDS="298,8,374,34" HREF="/support/index.html"> -<AREA SHAPE=RECT COORDS="381,15,586,43" HREF="http://help.netscape.com/browse/index.html"> -<AREA SHAPE=default NOHREF> -</MAP> - -<!-- BANNER:s3 --> - -<H2> -<FONT SIZE=+3>P</FONT>ERSISTENT -<FONT SIZE=+3>C</FONT>LIENT -<FONT SIZE=+3>S</FONT>TATE<BR> -<FONT SIZE=+3>HTTP C</FONT>OOKIES -</H2> - -<H3>Preliminary Specification - Use with caution</H3> -</CENTER> - -<HR SIZE=4> - -<CENTER> -<H3> -<FONT SIZE=+2>I</FONT>NTRODUCTION -</H3> -</CENTER> - -Cookies are a general mechanism which server side connections (such as -CGI scripts) can use to both store and retrieve information on the -client side of the connection. The addition of a simple, persistent, -client-side state significantly extends the capabilities of Web-based -client/server applications.<P> - -<CENTER> -<H3> -<FONT SIZE=+2>O</FONT>VERVIEW -</H3> -</CENTER> - -A server, when returning an HTTP object to a client, may also send a -piece of state information which the client will store. Included in that -state object is a description of the range of URLs for which that state is -valid. Any future HTTP requests made by the client which fall in that -range will include a transmittal of the current value of the state -object from the client back to the server. The state object is called -a <B>cookie</B>, for no compelling reason. <P> -This simple mechanism provides a powerful new tool which enables a host -of new types of applications to be written for web-based environments. -Shopping applications can now store information about the currently -selected items, for fee services can send back registration information -and free the client from retyping a user-id on next connection, -sites can store per-user preferences on the client, and have the client supply -those preferences every time that site is connected to. - -<CENTER> -<H3> -<FONT SIZE=+2>S</FONT>PECIFICATION -</H3> -</CENTER> - -A cookie is introduced to the client by including a <B>Set-Cookie</B> -header as part of an HTTP response, typically this will be generated -by a CGI script. - -<H3>Syntax of the Set-Cookie HTTP Response Header</H3> - -This is the format a CGI script would use to add to the HTTP headers -a new piece of data which is to be stored by the client for later retrieval. - -<PRE> -Set-Cookie: <I>NAME</I>=<I>VALUE</I>; expires=<I>DATE</I>; -path=<I>PATH</I>; domain=<I>DOMAIN_NAME</I>; secure -</PRE> -<DL> -<DT> <I>NAME</I>=<I>VALUE</I><DD> -This string is a sequence of characters excluding semi-colon, comma and white -space. If there is a need to place such data in the name or value, some -encoding method such as URL style %XX encoding is recommended, though no -encoding is defined or required. <P> This is the only required attribute -on the <B>Set-Cookie</B> header. <P> -<DT><B>expires</B>=<I>DATE</I> -<DD> -The <B>expires</B> attribute specifies a date string that -defines the valid life time of that cookie. Once the expiration -date has been reached, the cookie will no longer be stored or -given out. <P> -The date string is formatted as: -<BLOCKQUOTE> <TT>Wdy, DD-Mon-YYYY HH:MM:SS GMT</TT></BLOCKQUOTE> -This is based on -<A TARGET="_top" HREF="http://ds.internic.net/rfc/rfc822.txt">RFC 822</A>, -<A TARGET="_top" HREF="http://ds.internic.net/rfc/rfc850.txt">RFC 850</A>, -<A TARGET="_top" HREF="http://www.w3.org/hypertext/WWW/Protocols/rfc1036/rfc1036.html#z6"> -RFC 1036</A>, and -<A TARGET="_top" HREF="http://ds1.internic.net/rfc/rfc1123.txt"> -RFC 1123</A>, -with the variations that the only legal time zone is <B>GMT</B> and -the separators between the elements of the date must be dashes. -<P> -<B>expires</B> is an optional attribute. If not specified, the cookie will -expire when the user's session ends. <P> -<B>Note:</B> There is a bug in Netscape Navigator version 1.1 and earlier. -Only cookies whose <B>path</B> attribute is set explicitly to "/" will -be properly saved between sessions if they have an <B>expires</B> -attribute.<P> - -<DT> <B>domain</B>=<I>DOMAIN_NAME</I> -<DD> -When searching the cookie list for valid cookies, a comparison of the -<B>domain</B> -attributes of the cookie is made with the Internet domain name of the -host from which the URL will be fetched. If there is a tail match, -then the cookie will go through <B>path</B> matching to see if it -should be sent. "Tail matching" means that <B>domain</B> attribute -is matched against the tail of the fully qualified domain name of -the host. A <B>domain</B> attribute of "acme.com" would match -host names "anvil.acme.com" as well as "shipping.crate.acme.com". <P> - -Only hosts within the specified domain -can set a cookie for a domain and domains must have at least two (2) -or three (3) periods in them to prevent domains of the form: -".com", ".edu", and "va.us". Any domain that fails within -one of the seven special top level domains listed below only require -two periods. Any other domain requires at least three. The -seven special top level domains are: "COM", "EDU", "NET", "ORG", -"GOV", "MIL", and "INT". - - <P> -The default value of <B>domain</B> is the host name of the server -which generated the cookie response. <P> -<DT> <B>path</B>=<I>PATH</I> -<DD> -The <B>path</B> attribute is used to specify the subset of URLs in a -domain for -which the cookie is valid. If a cookie has already passed <B>domain</B> -matching, then the pathname component -of the URL is compared with the path attribute, and if there is -a match, the cookie is considered valid and is sent along with -the URL request. The path "/foo" -would match "/foobar" and "/foo/bar.html". The path "/" is the most -general path. <P> -If the <B>path</B> is not specified, it as assumed to be the same path -as the document being described by the header which contains the cookie. -<P> -<DT> <B>secure</B> -<DD> -If a cookie is marked <B>secure</B>, it will only be transmitted if the -communications channel with the host is a secure one. Currently -this means that secure cookies will only be sent to HTTPS (HTTP over SSL) -servers. <P> -If <B>secure</B> is not specified, a cookie is considered safe to be sent -in the clear over unsecured channels. -</DL> - -<H3>Syntax of the Cookie HTTP Request Header</H3> - -When requesting a URL from an HTTP server, the browser will match -the URL against all cookies and if any of them match, a line -containing the name/value pairs of all matching cookies will -be included in the HTTP request. Here is the format of that line: -<PRE> -Cookie: <I>NAME1=OPAQUE_STRING1</I>; <I>NAME2=OPAQUE_STRING2 ...</I> -</PRE> - -<H3>Additional Notes</H3> - -<UL> -<LI>Multiple <B>Set-Cookie</B> headers can be issued in a single server -response. -<p> -<LI>Instances of the same path and name will overwrite each other, with the -latest instance taking precedence. Instances of the same path but -different names will add additional mappings. -<p> -<LI>Setting the path to a higher-level value does not override other more -specific path mappings. If there are multiple matches for a given cookie -name, but with separate paths, all the matching cookies will be sent. -(See examples below.) -<p> -<LI>The -expires header lets the client know when it is safe to purge the mapping -but the client is not required to do so. A client may also delete a -cookie before it's expiration date arrives if the number of cookies -exceeds its internal limits. -<p> -<LI>When sending cookies to a server, all cookies with a more specific -path mapping should be sent before cookies with less specific path -mappings. For example, a cookie "name1=foo" with a path mapping -of "/" should be sent after a cookie "name1=foo2" with -a path mapping of "/bar" if they are both to be sent. -<p> -<LI>There are limitations on the number of cookies that a client -can store at any one time. This is a specification of the minimum -number of cookies that a client should be prepared to receive and -store. - -<UL> - <LI>300 total cookies - <LI>4 kilobytes per cookie, where the name and the OPAQUE_STRING - combine to form the 4 kilobyte limit. - <LI>20 cookies per server or domain. (note that completely - specified hosts and domains are treated as separate entities - and have a 20 cookie limitation for each, not combined) -</UL> -Servers should not expect clients to be able to exceed these limits. -When the 300 cookie limit or the 20 cookie per server limit -is exceeded, clients should delete the least recently used cookie. -When a cookie larger than 4 kilobytes is encountered the cookie -should be trimmed to fit, but the name should remain intact -as long as it is less than 4 kilobytes. - <P> -<LI>If a CGI script wishes to delete a cookie, it can do so by -returning a cookie with the same name, and an <B>expires</B> time -which is in the past. The path and name must match exactly -in order for the expiring cookie to replace the valid cookie. -This requirement makes it difficult for anyone but the originator -of a cookie to delete a cookie. -<P><LI>When caching HTTP, as a proxy server might do, the <B>Set-cookie</B> -response header should never be cached. -<P><LI>If a proxy server receives a response which -contains a <B>Set-cookie</B> header, it should propagate the <B>Set-cookie</B> -header to the client, regardless of whether the response was 304 -(Not Modified) or 200 (OK). -<P>Similarly, if a client request contains a Cookie: header, it -should be forwarded through a proxy, even if the conditional -If-modified-since request is being made. -</UL> - -<CENTER> -<H3> -<FONT SIZE=+2>E</FONT>XAMPLES -</H3> -</CENTER> - -Here are some sample exchanges which are designed to illustrate the use -of cookies. -<H3>First Example transaction sequence:</H3> -<DL> -<dt>Client requests a document, and receives in the response:<dd> -<PRE> -Set-Cookie: CUSTOMER=WILE_E_COYOTE; path=/; expires=Wednesday, 09-Nov-99 23:12:40 GMT</PRE> -<dt>When client requests a URL in path "/" on this server, it sends:<DD> -<PRE>Cookie: CUSTOMER=WILE_E_COYOTE</PRE> -<dt>Client requests a document, and receives in the response:<dd> -<PRE>Set-Cookie: PART_NUMBER=ROCKET_LAUNCHER_0001; path=/</PRE> -<dt>When client requests a URL in path "/" on this server, it sends:<dd> -<PRE>Cookie: CUSTOMER=WILE_E_COYOTE; PART_NUMBER=ROCKET_LAUNCHER_0001</PRE> -<dt>Client receives:<dd> -<PRE>Set-Cookie: SHIPPING=FEDEX; path=/foo</PRE> -<dt>When client requests a URL in path "/" on this server, it sends:<dd> -<PRE>Cookie: CUSTOMER=WILE_E_COYOTE; PART_NUMBER=ROCKET_LAUNCHER_0001</PRE> -<dt>When client requests a URL in path "/foo" on this server, it sends:<dd> -<PRE>Cookie: CUSTOMER=WILE_E_COYOTE; PART_NUMBER=ROCKET_LAUNCHER_0001; SHIPPING=FEDEX</PRE> -</DL> -<H3>Second Example transaction sequence:</H3> -<DL> -<dt>Assume all mappings from above have been cleared.<p> -<dt>Client receives:<dd> -<PRE>Set-Cookie: PART_NUMBER=ROCKET_LAUNCHER_0001; path=/</PRE> -<dt>When client requests a URL in path "/" on this server, it sends:<dd> -<PRE>Cookie: PART_NUMBER=ROCKET_LAUNCHER_0001</PRE> -<dt>Client receives:<dd> -<PRE>Set-Cookie: PART_NUMBER=RIDING_ROCKET_0023; path=/ammo</PRE> -<dt>When client requests a URL in path "/ammo" on this server, it sends:<dd> -<PRE>Cookie: PART_NUMBER=RIDING_ROCKET_0023; PART_NUMBER=ROCKET_LAUNCHER_0001</PRE> -<dd>NOTE: There are two name/value pairs named "PART_NUMBER" due to the -inheritance -of the "/" mapping in addition to the "/ammo" mapping. -</DL> - -<HR SIZE=4> -<P> - -<CENTER> - - -<!-- footer --> -<TABLE WIDTH=600 BORDER=0 CELLPADDING=0 CELLSPACING=0> -<TR> -<TD WIDTH=600 HEIGHT=8><HR SIZE=1 NOSHADE></TD></TR> -<TR><TD ALIGN=LEFT VALIGN=TOP><FONT FACE="sans-serif, Arial, Helvetica" SIZE=-2><A HREF="http://home.netscape.com/misc/nav_redir/help.html" TARGET="_top">Help</A> | <A -HREF="http://home.netscape.com/misc/nav_redir/site_map.html" TARGET="_top">Site Map</A> | <A -HREF="http://home.netscape.com/misc/nav_redir/howtoget.html" TARGET="_top">How to Get Netscape Products</A> | <A HREF="http://home.netscape.com/misc/nav_redir/ad.html" TARGET="_top">Advertise With Us</A> | <A HREF="http://home.netscape.com/misc/nav_redir/addsite.html" TARGET="_top">Add Site</A> | <A HREF="http://home.netscape.com/misc/nav_redir/custom_browser.html" TARGET="_top">Custom Browser Program</A></FONT></TD></TR> -<TR> -<TD WIDTH=600 HEIGHT=8 COLSPAN=0></TD> -</TR> - -<TR> -<TD ALIGN=LEFT VALIGN=TOP> -<!-- Channels --> -<FONT FACE="sans-serif, Arial, Helvetica" SIZE=-2><A HREF="http://home.netscape.com/misc/nav_redir/channels/autos.html" TARGET="_top">Autos</A> | <A -HREF="http://home.netscape.com/misc/nav_redir/channels/business.html" TARGET="_top">Business</A> | <A HREF="http://home.netscape.com/misc/nav_redir/channels/computers_internet.html" TARGET="_top">Computing & Internet</A> | <A HREF="http://home.netscape.com/misc/nav_redir/channels/entertainment.html" TARGET="_top">Entertainment</A> | <A -HREF="http://home.netscape.com/misc/nav_redir/channels/kids_family.html" TARGET="_top">Family</A> | <A -HREF="http://home.netscape.com/misc/nav_redir/channels/games.html" TARGET="_top">Games</A> | <A HREF="http://home.netscape.com/misc/nav_redir/channels/health.html" TARGET="_top">Health</A> | <A HREF="http://home.netscape.com/misc/nav_redir/channels/lifestyles.html" TARGET="_top">Lifestyles</A> | <A -HREF="http://home.netscape.com/misc/nav_redir/channels/local.html" TARGET="_top">Local</A> | <A HREF="http://home.netscape.com/misc/nav_redir/channels/netscape.html" TARGET="_top">Netscape</A> | <A HREF="http://home.netscape.com/misc/nav_redir/channels/open_directory.html">Netscape Open Directory</A> | <A -HREF="http://home.netscape.com/misc/nav_redir/channels/news.html" TARGET="_top">News</A> | <A HREF="http://home.netscape.com/misc/nav_redir/channels/personalize_finance.html" TARGET="_top">Personal Finance</A> | <A -HREF="http://home.netscape.com/misc/nav_redir/channels/real_estate.html" TARGET="_top">Real Estate</A> | <A HREF="http://home.netscape.com/misc/nav_redir/channels/education.html" TARGET="_top">Research & Learn</A> | <A HREF="http://home.netscape.com/misc/nav_redir/channels/shopping.html" TARGET="_top">Shopping</A> | <A HREF="http://home.netscape.com/misc/nav_redir/channels/smallbiz.html" TARGET="_top">Small Business</A> | <A -HREF="http://home.netscape.com/misc/nav_redir/channels/sports.html" TARGET="_top">Sports</A> | <A HREF="http://home.netscape.com/misc/nav_redir/channels/travel.html" TARGET="_top">Travel</A></FONT></TD></TR> -</TABLE> - -<TABLE WIDTH=600 BORDER=0 CELLPADDING=0 CELLSPACING=0> -<TR><TD WIDTH=600 HEIGHT=8 COLSPAN=0></TD></TR> -<TR> -<TD WIDTH=600 COLSPAN=5 VALIGN=TOP ALIGN=LEFT> -<FONT FACE="sans-serif, Arial, Helvetica" SIZE=-2> -© 1999 Netscape, All Rights Reserved. <A HREF="http://home.netscape.com/legal_notices/index.html">Legal & Privacy Notices</A><BR>This site powered by <A HREF="http://home.netscape.com/comprod/server_central/index.html" TARGET="_top">Netscape SuiteSpot servers</A>.</FONT></TD> -</TR> -</TABLE> -<!-- end footer --> - - - - -</CENTER> -<P> - - - -</BODY> -</HTML>
\ No newline at end of file diff --git a/kioslave/http/kcookiejar/rfc2109 b/kioslave/http/kcookiejar/rfc2109 deleted file mode 100644 index 432fdcc6e..000000000 --- a/kioslave/http/kcookiejar/rfc2109 +++ /dev/null @@ -1,1179 +0,0 @@ - - - - - - -Network Working Group D. Kristol -Request for Comments: 2109 Bell Laboratories, Lucent Technologies -Category: Standards Track L. Montulli - Netscape Communications - February 1997 - - - HTTP State Management Mechanism - -Status of this Memo - - This document specifies an Internet standards track protocol for the - Internet community, and requests discussion and suggestions for - improvements. Please refer to the current edition of the "Internet - Official Protocol Standards" (STD 1) for the standardization state - and status of this protocol. Distribution of this memo is unlimited. - -1. ABSTRACT - - This document specifies a way to create a stateful session with HTTP - requests and responses. It describes two new headers, Cookie and - Set-Cookie, which carry state information between participating - origin servers and user agents. The method described here differs - from Netscape's Cookie proposal, but it can interoperate with - HTTP/1.0 user agents that use Netscape's method. (See the HISTORICAL - section.) - -2. TERMINOLOGY - - The terms user agent, client, server, proxy, and origin server have - the same meaning as in the HTTP/1.0 specification. - - Fully-qualified host name (FQHN) means either the fully-qualified - domain name (FQDN) of a host (i.e., a completely specified domain - name ending in a top-level domain such as .com or .uk), or the - numeric Internet Protocol (IP) address of a host. The fully - qualified domain name is preferred; use of numeric IP addresses is - strongly discouraged. - - The terms request-host and request-URI refer to the values the client - would send to the server as, respectively, the host (but not port) - and abs_path portions of the absoluteURI (http_URL) of the HTTP - request line. Note that request-host must be a FQHN. - - - - - - - - -Kristol & Montulli Standards Track [Page 1] - -RFC 2109 HTTP State Management Mechanism February 1997 - - - Hosts names can be specified either as an IP address or a FQHN - string. Sometimes we compare one host name with another. Host A's - name domain-matches host B's if - - * both host names are IP addresses and their host name strings match - exactly; or - - * both host names are FQDN strings and their host name strings match - exactly; or - - * A is a FQDN string and has the form NB, where N is a non-empty name - string, B has the form .B', and B' is a FQDN string. (So, x.y.com - domain-matches .y.com but not y.com.) - - Note that domain-match is not a commutative operation: a.b.c.com - domain-matches .c.com, but not the reverse. - - Because it was used in Netscape's original implementation of state - management, we will use the term cookie to refer to the state - information that passes between an origin server and user agent, and - that gets stored by the user agent. - -3. STATE AND SESSIONS - - This document describes a way to create stateful sessions with HTTP - requests and responses. Currently, HTTP servers respond to each - client request without relating that request to previous or - subsequent requests; the technique allows clients and servers that - wish to exchange state information to place HTTP requests and - responses within a larger context, which we term a "session". This - context might be used to create, for example, a "shopping cart", in - which user selections can be aggregated before purchase, or a - magazine browsing system, in which a user's previous reading affects - which offerings are presented. - - There are, of course, many different potential contexts and thus many - different potential types of session. The designers' paradigm for - sessions created by the exchange of cookies has these key attributes: - - 1. Each session has a beginning and an end. - - 2. Each session is relatively short-lived. - - 3. Either the user agent or the origin server may terminate a - session. - - 4. The session is implicit in the exchange of state information. - - - - -Kristol & Montulli Standards Track [Page 2] - -RFC 2109 HTTP State Management Mechanism February 1997 - - -4. OUTLINE - - We outline here a way for an origin server to send state information - to the user agent, and for the user agent to return the state - information to the origin server. The goal is to have a minimal - impact on HTTP and user agents. Only origin servers that need to - maintain sessions would suffer any significant impact, and that - impact can largely be confined to Common Gateway Interface (CGI) - programs, unless the server provides more sophisticated state - management support. (See Implementation Considerations, below.) - -4.1 Syntax: General - - The two state management headers, Set-Cookie and Cookie, have common - syntactic properties involving attribute-value pairs. The following - grammar uses the notation, and tokens DIGIT (decimal digits) and - token (informally, a sequence of non-special, non-white space - characters) from the HTTP/1.1 specification [RFC 2068] to describe - their syntax. - - av-pairs = av-pair *(";" av-pair) - av-pair = attr ["=" value] ; optional value - attr = token - value = word - word = token | quoted-string - - Attributes (names) (attr) are case-insensitive. White space is - permitted between tokens. Note that while the above syntax - description shows value as optional, most attrs require them. - - NOTE: The syntax above allows whitespace between the attribute and - the = sign. - -4.2 Origin Server Role - -4.2.1 General - - The origin server initiates a session, if it so desires. (Note that - "session" here does not refer to a persistent network connection but - to a logical session created from HTTP requests and responses. The - presence or absence of a persistent connection should have no effect - on the use of cookie-derived sessions). To initiate a session, the - origin server returns an extra response header to the client, Set- - Cookie. (The details follow later.) - - A user agent returns a Cookie request header (see below) to the - origin server if it chooses to continue a session. The origin server - may ignore it or use it to determine the current state of the - - - -Kristol & Montulli Standards Track [Page 3] - -RFC 2109 HTTP State Management Mechanism February 1997 - - - session. It may send back to the client a Set-Cookie response header - with the same or different information, or it may send no Set-Cookie - header at all. The origin server effectively ends a session by - sending the client a Set-Cookie header with Max-Age=0. - - Servers may return a Set-Cookie response headers with any response. - User agents should send Cookie request headers, subject to other - rules detailed below, with every request. - - An origin server may include multiple Set-Cookie headers in a - response. Note that an intervening gateway could fold multiple such - headers into a single header. - -4.2.2 Set-Cookie Syntax - - The syntax for the Set-Cookie response header is - - set-cookie = "Set-Cookie:" cookies - cookies = 1#cookie - cookie = NAME "=" VALUE *(";" cookie-av) - NAME = attr - VALUE = value - cookie-av = "Comment" "=" value - | "Domain" "=" value - | "Max-Age" "=" value - | "Path" "=" value - | "Secure" - | "Version" "=" 1*DIGIT - - Informally, the Set-Cookie response header comprises the token Set- - Cookie:, followed by a comma-separated list of one or more cookies. - Each cookie begins with a NAME=VALUE pair, followed by zero or more - semi-colon-separated attribute-value pairs. The syntax for - attribute-value pairs was shown earlier. The specific attributes and - the semantics of their values follows. The NAME=VALUE attribute- - value pair must come first in each cookie. The others, if present, - can occur in any order. If an attribute appears more than once in a - cookie, the behavior is undefined. - - NAME=VALUE - Required. The name of the state information ("cookie") is NAME, - and its value is VALUE. NAMEs that begin with $ are reserved for - other uses and must not be used by applications. - - - - - - - - -Kristol & Montulli Standards Track [Page 4] - -RFC 2109 HTTP State Management Mechanism February 1997 - - - The VALUE is opaque to the user agent and may be anything the - origin server chooses to send, possibly in a server-selected - printable ASCII encoding. "Opaque" implies that the content is of - interest and relevance only to the origin server. The content - may, in fact, be readable by anyone that examines the Set-Cookie - header. - - Comment=comment - Optional. Because cookies can contain private information about a - user, the Cookie attribute allows an origin server to document its - intended use of a cookie. The user can inspect the information to - decide whether to initiate or continue a session with this cookie. - - Domain=domain - Optional. The Domain attribute specifies the domain for which the - cookie is valid. An explicitly specified domain must always start - with a dot. - - Max-Age=delta-seconds - Optional. The Max-Age attribute defines the lifetime of the - cookie, in seconds. The delta-seconds value is a decimal non- - negative integer. After delta-seconds seconds elapse, the client - should discard the cookie. A value of zero means the cookie - should be discarded immediately. - - Path=path - Optional. The Path attribute specifies the subset of URLs to - which this cookie applies. - - Secure - Optional. The Secure attribute (with no value) directs the user - agent to use only (unspecified) secure means to contact the origin - server whenever it sends back this cookie. - - The user agent (possibly under the user's control) may determine - what level of security it considers appropriate for "secure" - cookies. The Secure attribute should be considered security - advice from the server to the user agent, indicating that it is in - the session's interest to protect the cookie contents. - - Version=version - Required. The Version attribute, a decimal integer, identifies to - which version of the state management specification the cookie - conforms. For this specification, Version=1 applies. - - - - - - - -Kristol & Montulli Standards Track [Page 5] - -RFC 2109 HTTP State Management Mechanism February 1997 - - -4.2.3 Controlling Caching - - An origin server must be cognizant of the effect of possible caching - of both the returned resource and the Set-Cookie header. Caching - "public" documents is desirable. For example, if the origin server - wants to use a public document such as a "front door" page as a - sentinel to indicate the beginning of a session for which a Set- - Cookie response header must be generated, the page should be stored - in caches "pre-expired" so that the origin server will see further - requests. "Private documents", for example those that contain - information strictly private to a session, should not be cached in - shared caches. - - If the cookie is intended for use by a single user, the Set-cookie - header should not be cached. A Set-cookie header that is intended to - be shared by multiple users may be cached. - - The origin server should send the following additional HTTP/1.1 - response headers, depending on circumstances: - - * To suppress caching of the Set-Cookie header: Cache-control: no- - cache="set-cookie". - - and one of the following: - - * To suppress caching of a private document in shared caches: Cache- - control: private. - - * To allow caching of a document and require that it be validated - before returning it to the client: Cache-control: must-revalidate. - - * To allow caching of a document, but to require that proxy caches - (not user agent caches) validate it before returning it to the - client: Cache-control: proxy-revalidate. - - * To allow caching of a document and request that it be validated - before returning it to the client (by "pre-expiring" it): - Cache-control: max-age=0. Not all caches will revalidate the - document in every case. - - HTTP/1.1 servers must send Expires: old-date (where old-date is a - date long in the past) on responses containing Set-Cookie response - headers unless they know for certain (by out of band means) that - there are no downsteam HTTP/1.0 proxies. HTTP/1.1 servers may send - other Cache-Control directives that permit caching by HTTP/1.1 - proxies in addition to the Expires: old-date directive; the Cache- - Control directive will override the Expires: old-date for HTTP/1.1 - proxies. - - - -Kristol & Montulli Standards Track [Page 6] - -RFC 2109 HTTP State Management Mechanism February 1997 - - -4.3 User Agent Role - -4.3.1 Interpreting Set-Cookie - - The user agent keeps separate track of state information that arrives - via Set-Cookie response headers from each origin server (as - distinguished by name or IP address and port). The user agent - applies these defaults for optional attributes that are missing: - - VersionDefaults to "old cookie" behavior as originally specified by - Netscape. See the HISTORICAL section. - - Domain Defaults to the request-host. (Note that there is no dot at - the beginning of request-host.) - - Max-AgeThe default behavior is to discard the cookie when the user - agent exits. - - Path Defaults to the path of the request URL that generated the - Set-Cookie response, up to, but not including, the - right-most /. - - Secure If absent, the user agent may send the cookie over an - insecure channel. - -4.3.2 Rejecting Cookies - - To prevent possible security or privacy violations, a user agent - rejects a cookie (shall not store its information) if any of the - following is true: - - * The value for the Path attribute is not a prefix of the request- - URI. - - * The value for the Domain attribute contains no embedded dots or - does not start with a dot. - - * The value for the request-host does not domain-match the Domain - attribute. - - * The request-host is a FQDN (not IP address) and has the form HD, - where D is the value of the Domain attribute, and H is a string - that contains one or more dots. - - Examples: - - * A Set-Cookie from request-host y.x.foo.com for Domain=.foo.com - would be rejected, because H is y.x and contains a dot. - - - -Kristol & Montulli Standards Track [Page 7] - -RFC 2109 HTTP State Management Mechanism February 1997 - - - * A Set-Cookie from request-host x.foo.com for Domain=.foo.com would - be accepted. - - * A Set-Cookie with Domain=.com or Domain=.com., will always be - rejected, because there is no embedded dot. - - * A Set-Cookie with Domain=ajax.com will be rejected because the - value for Domain does not begin with a dot. - -4.3.3 Cookie Management - - If a user agent receives a Set-Cookie response header whose NAME is - the same as a pre-existing cookie, and whose Domain and Path - attribute values exactly (string) match those of a pre-existing - cookie, the new cookie supersedes the old. However, if the Set- - Cookie has a value for Max-Age of zero, the (old and new) cookie is - discarded. Otherwise cookies accumulate until they expire (resources - permitting), at which time they are discarded. - - Because user agents have finite space in which to store cookies, they - may also discard older cookies to make space for newer ones, using, - for example, a least-recently-used algorithm, along with constraints - on the maximum number of cookies that each origin server may set. - - If a Set-Cookie response header includes a Comment attribute, the - user agent should store that information in a human-readable form - with the cookie and should display the comment text as part of a - cookie inspection user interface. - - User agents should allow the user to control cookie destruction. An - infrequently-used cookie may function as a "preferences file" for - network applications, and a user may wish to keep it even if it is - the least-recently-used cookie. One possible implementation would be - an interface that allows the permanent storage of a cookie through a - checkbox (or, conversely, its immediate destruction). - - Privacy considerations dictate that the user have considerable - control over cookie management. The PRIVACY section contains more - information. - -4.3.4 Sending Cookies to the Origin Server - - When it sends a request to an origin server, the user agent sends a - Cookie request header to the origin server if it has cookies that are - applicable to the request, based on - - * the request-host; - - - - -Kristol & Montulli Standards Track [Page 8] - -RFC 2109 HTTP State Management Mechanism February 1997 - - - * the request-URI; - - * the cookie's age. - - The syntax for the header is: - - cookie = "Cookie:" cookie-version - 1*((";" | ",") cookie-value) - cookie-value = NAME "=" VALUE [";" path] [";" domain] - cookie-version = "$Version" "=" value - NAME = attr - VALUE = value - path = "$Path" "=" value - domain = "$Domain" "=" value - - The value of the cookie-version attribute must be the value from the - Version attribute, if any, of the corresponding Set-Cookie response - header. Otherwise the value for cookie-version is 0. The value for - the path attribute must be the value from the Path attribute, if any, - of the corresponding Set-Cookie response header. Otherwise the - attribute should be omitted from the Cookie request header. The - value for the domain attribute must be the value from the Domain - attribute, if any, of the corresponding Set-Cookie response header. - Otherwise the attribute should be omitted from the Cookie request - header. - - Note that there is no Comment attribute in the Cookie request header - corresponding to the one in the Set-Cookie response header. The user - agent does not return the comment information to the origin server. - - The following rules apply to choosing applicable cookie-values from - among all the cookies the user agent has. - - Domain Selection - The origin server's fully-qualified host name must domain-match - the Domain attribute of the cookie. - - Path Selection - The Path attribute of the cookie must match a prefix of the - request-URI. - - Max-Age Selection - Cookies that have expired should have been discarded and thus - are not forwarded to an origin server. - - - - - - - -Kristol & Montulli Standards Track [Page 9] - -RFC 2109 HTTP State Management Mechanism February 1997 - - - If multiple cookies satisfy the criteria above, they are ordered in - the Cookie header such that those with more specific Path attributes - precede those with less specific. Ordering with respect to other - attributes (e.g., Domain) is unspecified. - - Note: For backward compatibility, the separator in the Cookie header - is semi-colon (;) everywhere. A server should also accept comma (,) - as the separator between cookie-values for future compatibility. - -4.3.5 Sending Cookies in Unverifiable Transactions - - Users must have control over sessions in order to ensure privacy. - (See PRIVACY section below.) To simplify implementation and to - prevent an additional layer of complexity where adequate safeguards - exist, however, this document distinguishes between transactions that - are verifiable and those that are unverifiable. A transaction is - verifiable if the user has the option to review the request-URI prior - to its use in the transaction. A transaction is unverifiable if the - user does not have that option. Unverifiable transactions typically - arise when a user agent automatically requests inlined or embedded - entities or when it resolves redirection (3xx) responses from an - origin server. Typically the origin transaction, the transaction - that the user initiates, is verifiable, and that transaction may - directly or indirectly induce the user agent to make unverifiable - transactions. - - When it makes an unverifiable transaction, a user agent must enable a - session only if a cookie with a domain attribute D was sent or - received in its origin transaction, such that the host name in the - Request-URI of the unverifiable transaction domain-matches D. - - This restriction prevents a malicious service author from using - unverifiable transactions to induce a user agent to start or continue - a session with a server in a different domain. The starting or - continuation of such sessions could be contrary to the privacy - expectations of the user, and could also be a security problem. - - User agents may offer configurable options that allow the user agent, - or any autonomous programs that the user agent executes, to ignore - the above rule, so long as these override options default to "off". - - Many current user agents already provide a review option that would - render many links verifiable. For instance, some user agents display - the URL that would be referenced for a particular link when the mouse - pointer is placed over that link. The user can therefore determine - whether to visit that site before causing the browser to do so. - (Though not implemented on current user agents, a similar technique - could be used for a button used to submit a form -- the user agent - - - -Kristol & Montulli Standards Track [Page 10] - -RFC 2109 HTTP State Management Mechanism February 1997 - - - could display the action to be taken if the user were to select that - button.) However, even this would not make all links verifiable; for - example, links to automatically loaded images would not normally be - subject to "mouse pointer" verification. - - Many user agents also provide the option for a user to view the HTML - source of a document, or to save the source to an external file where - it can be viewed by another application. While such an option does - provide a crude review mechanism, some users might not consider it - acceptable for this purpose. - -4.4 How an Origin Server Interprets the Cookie Header - - A user agent returns much of the information in the Set-Cookie header - to the origin server when the Path attribute matches that of a new - request. When it receives a Cookie header, the origin server should - treat cookies with NAMEs whose prefix is $ specially, as an attribute - for the adjacent cookie. The value for such a NAME is to be - interpreted as applying to the lexically (left-to-right) most recent - cookie whose name does not have the $ prefix. If there is no - previous cookie, the value applies to the cookie mechanism as a - whole. For example, consider the cookie - - Cookie: $Version="1"; Customer="WILE_E_COYOTE"; - $Path="/acme" - - $Version applies to the cookie mechanism as a whole (and gives the - version number for the cookie mechanism). $Path is an attribute - whose value (/acme) defines the Path attribute that was used when the - Customer cookie was defined in a Set-Cookie response header. - -4.5 Caching Proxy Role - - One reason for separating state information from both a URL and - document content is to facilitate the scaling that caching permits. - To support cookies, a caching proxy must obey these rules already in - the HTTP specification: - - * Honor requests from the cache, if possible, based on cache validity - rules. - - * Pass along a Cookie request header in any request that the proxy - must make of another server. - - * Return the response to the client. Include any Set-Cookie response - header. - - - - - -Kristol & Montulli Standards Track [Page 11] - -RFC 2109 HTTP State Management Mechanism February 1997 - - - * Cache the received response subject to the control of the usual - headers, such as Expires, Cache-control: no-cache, and Cache- - control: private, - - * Cache the Set-Cookie subject to the control of the usual header, - Cache-control: no-cache="set-cookie". (The Set-Cookie header - should usually not be cached.) - - Proxies must not introduce Set-Cookie (Cookie) headers of their own - in proxy responses (requests). - -5. EXAMPLES - -5.1 Example 1 - - Most detail of request and response headers has been omitted. Assume - the user agent has no stored cookies. - - 1. User Agent -> Server - - POST /acme/login HTTP/1.1 - [form data] - - User identifies self via a form. - - 2. Server -> User Agent - - HTTP/1.1 200 OK - Set-Cookie: Customer="WILE_E_COYOTE"; Version="1"; Path="/acme" - - Cookie reflects user's identity. - - 3. User Agent -> Server - - POST /acme/pickitem HTTP/1.1 - Cookie: $Version="1"; Customer="WILE_E_COYOTE"; $Path="/acme" - [form data] - - User selects an item for "shopping basket." - - 4. Server -> User Agent - - HTTP/1.1 200 OK - Set-Cookie: Part_Number="Rocket_Launcher_0001"; Version="1"; - Path="/acme" - - Shopping basket contains an item. - - - - -Kristol & Montulli Standards Track [Page 12] - -RFC 2109 HTTP State Management Mechanism February 1997 - - - 5. User Agent -> Server - - POST /acme/shipping HTTP/1.1 - Cookie: $Version="1"; - Customer="WILE_E_COYOTE"; $Path="/acme"; - Part_Number="Rocket_Launcher_0001"; $Path="/acme" - [form data] - - User selects shipping method from form. - - 6. Server -> User Agent - - HTTP/1.1 200 OK - Set-Cookie: Shipping="FedEx"; Version="1"; Path="/acme" - - New cookie reflects shipping method. - - 7. User Agent -> Server - - POST /acme/process HTTP/1.1 - Cookie: $Version="1"; - Customer="WILE_E_COYOTE"; $Path="/acme"; - Part_Number="Rocket_Launcher_0001"; $Path="/acme"; - Shipping="FedEx"; $Path="/acme" - [form data] - - User chooses to process order. - - 8. Server -> User Agent - - HTTP/1.1 200 OK - - Transaction is complete. - - The user agent makes a series of requests on the origin server, after - each of which it receives a new cookie. All the cookies have the - same Path attribute and (default) domain. Because the request URLs - all have /acme as a prefix, and that matches the Path attribute, each - request contains all the cookies received so far. - -5.2 Example 2 - - This example illustrates the effect of the Path attribute. All - detail of request and response headers has been omitted. Assume the - user agent has no stored cookies. - - Imagine the user agent has received, in response to earlier requests, - the response headers - - - -Kristol & Montulli Standards Track [Page 13] - -RFC 2109 HTTP State Management Mechanism February 1997 - - - Set-Cookie: Part_Number="Rocket_Launcher_0001"; Version="1"; - Path="/acme" - - and - - Set-Cookie: Part_Number="Riding_Rocket_0023"; Version="1"; - Path="/acme/ammo" - - A subsequent request by the user agent to the (same) server for URLs - of the form /acme/ammo/... would include the following request - header: - - Cookie: $Version="1"; - Part_Number="Riding_Rocket_0023"; $Path="/acme/ammo"; - Part_Number="Rocket_Launcher_0001"; $Path="/acme" - - Note that the NAME=VALUE pair for the cookie with the more specific - Path attribute, /acme/ammo, comes before the one with the less - specific Path attribute, /acme. Further note that the same cookie - name appears more than once. - - A subsequent request by the user agent to the (same) server for a URL - of the form /acme/parts/ would include the following request header: - - Cookie: $Version="1"; Part_Number="Rocket_Launcher_0001"; $Path="/acme" - - Here, the second cookie's Path attribute /acme/ammo is not a prefix - of the request URL, /acme/parts/, so the cookie does not get - forwarded to the server. - -6. IMPLEMENTATION CONSIDERATIONS - - Here we speculate on likely or desirable details for an origin server - that implements state management. - -6.1 Set-Cookie Content - - An origin server's content should probably be divided into disjoint - application areas, some of which require the use of state - information. The application areas can be distinguished by their - request URLs. The Set-Cookie header can incorporate information - about the application areas by setting the Path attribute for each - one. - - The session information can obviously be clear or encoded text that - describes state. However, if it grows too large, it can become - unwieldy. Therefore, an implementor might choose for the session - information to be a key to a server-side resource. Of course, using - - - -Kristol & Montulli Standards Track [Page 14] - -RFC 2109 HTTP State Management Mechanism February 1997 - - - a database creates some problems that this state management - specification was meant to avoid, namely: - - 1. keeping real state on the server side; - - 2. how and when to garbage-collect the database entry, in case the - user agent terminates the session by, for example, exiting. - -6.2 Stateless Pages - - Caching benefits the scalability of WWW. Therefore it is important - to reduce the number of documents that have state embedded in them - inherently. For example, if a shopping-basket-style application - always displays a user's current basket contents on each page, those - pages cannot be cached, because each user's basket's contents would - be different. On the other hand, if each page contains just a link - that allows the user to "Look at My Shopping Basket", the page can be - cached. - -6.3 Implementation Limits - - Practical user agent implementations have limits on the number and - size of cookies that they can store. In general, user agents' cookie - support should have no fixed limits. They should strive to store as - many frequently-used cookies as possible. Furthermore, general-use - user agents should provide each of the following minimum capabilities - individually, although not necessarily simultaneously: - - * at least 300 cookies - - * at least 4096 bytes per cookie (as measured by the size of the - characters that comprise the cookie non-terminal in the syntax - description of the Set-Cookie header) - - * at least 20 cookies per unique host or domain name - - User agents created for specific purposes or for limited-capacity - devices should provide at least 20 cookies of 4096 bytes, to ensure - that the user can interact with a session-based origin server. - - The information in a Set-Cookie response header must be retained in - its entirety. If for some reason there is inadequate space to store - the cookie, it must be discarded, not truncated. - - Applications should use as few and as small cookies as possible, and - they should cope gracefully with the loss of a cookie. - - - - - -Kristol & Montulli Standards Track [Page 15] - -RFC 2109 HTTP State Management Mechanism February 1997 - - -6.3.1 Denial of Service Attacks - - User agents may choose to set an upper bound on the number of cookies - to be stored from a given host or domain name or on the size of the - cookie information. Otherwise a malicious server could attempt to - flood a user agent with many cookies, or large cookies, on successive - responses, which would force out cookies the user agent had received - from other servers. However, the minima specified above should still - be supported. - -7. PRIVACY - -7.1 User Agent Control - - An origin server could create a Set-Cookie header to track the path - of a user through the server. Users may object to this behavior as - an intrusive accumulation of information, even if their identity is - not evident. (Identity might become evident if a user subsequently - fills out a form that contains identifying information.) This state - management specification therefore requires that a user agent give - the user control over such a possible intrusion, although the - interface through which the user is given this control is left - unspecified. However, the control mechanisms provided shall at least - allow the user - - * to completely disable the sending and saving of cookies. - - * to determine whether a stateful session is in progress. - - * to control the saving of a cookie on the basis of the cookie's - Domain attribute. - - Such control could be provided by, for example, mechanisms - - * to notify the user when the user agent is about to send a cookie - to the origin server, offering the option not to begin a session. - - * to display a visual indication that a stateful session is in - progress. - - * to let the user decide which cookies, if any, should be saved - when the user concludes a window or user agent session. - - * to let the user examine the contents of a cookie at any time. - - A user agent usually begins execution with no remembered state - information. It should be possible to configure a user agent never - to send Cookie headers, in which case it can never sustain state with - - - -Kristol & Montulli Standards Track [Page 16] - -RFC 2109 HTTP State Management Mechanism February 1997 - - - an origin server. (The user agent would then behave like one that is - unaware of how to handle Set-Cookie response headers.) - - When the user agent terminates execution, it should let the user - discard all state information. Alternatively, the user agent may ask - the user whether state information should be retained; the default - should be "no". If the user chooses to retain state information, it - would be restored the next time the user agent runs. - - NOTE: User agents should probably be cautious about using files to - store cookies long-term. If a user runs more than one instance of - the user agent, the cookies could be commingled or otherwise messed - up. - -7.2 Protocol Design - - The restrictions on the value of the Domain attribute, and the rules - concerning unverifiable transactions, are meant to reduce the ways - that cookies can "leak" to the "wrong" site. The intent is to - restrict cookies to one, or a closely related set of hosts. - Therefore a request-host is limited as to what values it can set for - Domain. We consider it acceptable for hosts host1.foo.com and - host2.foo.com to share cookies, but not a.com and b.com. - - Similarly, a server can only set a Path for cookies that are related - to the request-URI. - -8. SECURITY CONSIDERATIONS - -8.1 Clear Text - - The information in the Set-Cookie and Cookie headers is unprotected. - Two consequences are: - - 1. Any sensitive information that is conveyed in them is exposed - to intruders. - - 2. A malicious intermediary could alter the headers as they travel - in either direction, with unpredictable results. - - These facts imply that information of a personal and/or financial - nature should only be sent over a secure channel. For less sensitive - information, or when the content of the header is a database key, an - origin server should be vigilant to prevent a bad Cookie value from - causing failures. - - - - - - -Kristol & Montulli Standards Track [Page 17] - -RFC 2109 HTTP State Management Mechanism February 1997 - - -8.2 Cookie Spoofing - - Proper application design can avoid spoofing attacks from related - domains. Consider: - - 1. User agent makes request to victim.cracker.edu, gets back - cookie session_id="1234" and sets the default domain - victim.cracker.edu. - - 2. User agent makes request to spoof.cracker.edu, gets back - cookie session-id="1111", with Domain=".cracker.edu". - - 3. User agent makes request to victim.cracker.edu again, and - passes - - Cookie: $Version="1"; - session_id="1234"; - session_id="1111"; $Domain=".cracker.edu" - - The server at victim.cracker.edu should detect that the second - cookie was not one it originated by noticing that the Domain - attribute is not for itself and ignore it. - -8.3 Unexpected Cookie Sharing - - A user agent should make every attempt to prevent the sharing of - session information between hosts that are in different domains. - Embedded or inlined objects may cause particularly severe privacy - problems if they can be used to share cookies between disparate - hosts. For example, a malicious server could embed cookie - information for host a.com in a URI for a CGI on host b.com. User - agent implementors are strongly encouraged to prevent this sort of - exchange whenever possible. - -9. OTHER, SIMILAR, PROPOSALS - - Three other proposals have been made to accomplish similar goals. - This specification is an amalgam of Kristol's State-Info proposal and - Netscape's Cookie proposal. - - Brian Behlendorf proposed a Session-ID header that would be user- - agent-initiated and could be used by an origin server to track - "clicktrails". It would not carry any origin-server-defined state, - however. Phillip Hallam-Baker has proposed another client-defined - session ID mechanism for similar purposes. - - - - - - -Kristol & Montulli Standards Track [Page 18] - -RFC 2109 HTTP State Management Mechanism February 1997 - - - While both session IDs and cookies can provide a way to sustain - stateful sessions, their intended purpose is different, and, - consequently, the privacy requirements for them are different. A - user initiates session IDs to allow servers to track progress through - them, or to distinguish multiple users on a shared machine. Cookies - are server-initiated, so the cookie mechanism described here gives - users control over something that would otherwise take place without - the users' awareness. Furthermore, cookies convey rich, server- - selected information, whereas session IDs comprise user-selected, - simple information. - -10. HISTORICAL - -10.1 Compatibility With Netscape's Implementation - - HTTP/1.0 clients and servers may use Set-Cookie and Cookie headers - that reflect Netscape's original cookie proposal. These notes cover - inter-operation between "old" and "new" cookies. - -10.1.1 Extended Cookie Header - - This proposal adds attribute-value pairs to the Cookie request header - in a compatible way. An "old" client that receives a "new" cookie - will ignore attributes it does not understand; it returns what it - does understand to the origin server. A "new" client always sends - cookies in the new form. - - An "old" server that receives a "new" cookie will see what it thinks - are many cookies with names that begin with a $, and it will ignore - them. (The "old" server expects these cookies to be separated by - semi-colon, not comma.) A "new" server can detect cookies that have - passed through an "old" client, because they lack a $Version - attribute. - -10.1.2 Expires and Max-Age - - Netscape's original proposal defined an Expires header that took a - date value in a fixed-length variant format in place of Max-Age: - - Wdy, DD-Mon-YY HH:MM:SS GMT - - Note that the Expires date format contains embedded spaces, and that - "old" cookies did not have quotes around values. Clients that - implement to this specification should be aware of "old" cookies and - Expires. - - - - - - -Kristol & Montulli Standards Track [Page 19] - -RFC 2109 HTTP State Management Mechanism February 1997 - - -10.1.3 Punctuation - - In Netscape's original proposal, the values in attribute-value pairs - did not accept "-quoted strings. Origin servers should be cautious - about sending values that require quotes unless they know the - receiving user agent understands them (i.e., "new" cookies). A - ("new") user agent should only use quotes around values in Cookie - headers when the cookie's version(s) is (are) all compliant with this - specification or later. - - In Netscape's original proposal, no whitespace was permitted around - the = that separates attribute-value pairs. Therefore such - whitespace should be used with caution in new implementations. - -10.2 Caching and HTTP/1.0 - - Some caches, such as those conforming to HTTP/1.0, will inevitably - cache the Set-Cookie header, because there was no mechanism to - suppress caching of headers prior to HTTP/1.1. This caching can lead - to security problems. Documents transmitted by an origin server - along with Set-Cookie headers will usually either be uncachable, or - will be "pre-expired". As long as caches obey instructions not to - cache documents (following Expires: <a date in the past> or Pragma: - no-cache (HTTP/1.0), or Cache-control: no-cache (HTTP/1.1)) - uncachable documents present no problem. However, pre-expired - documents may be stored in caches. They require validation (a - conditional GET) on each new request, but some cache operators loosen - the rules for their caches, and sometimes serve expired documents - without first validating them. This combination of factors can lead - to cookies meant for one user later being sent to another user. The - Set-Cookie header is stored in the cache, and, although the document - is stale (expired), the cache returns the document in response to - later requests, including cached headers. - -11. ACKNOWLEDGEMENTS - - This document really represents the collective efforts of the - following people, in addition to the authors: Roy Fielding, Marc - Hedlund, Ted Hardie, Koen Holtman, Shel Kaphan, Rohit Khare. - - - - - - - - - - - - -Kristol & Montulli Standards Track [Page 20] - -RFC 2109 HTTP State Management Mechanism February 1997 - - -12. AUTHORS' ADDRESSES - - David M. Kristol - Bell Laboratories, Lucent Technologies - 600 Mountain Ave. Room 2A-227 - Murray Hill, NJ 07974 - - Phone: (908) 582-2250 - Fax: (908) 582-5809 - EMail: dmk@bell-labs.com - - - Lou Montulli - Netscape Communications Corp. - 501 E. Middlefield Rd. - Mountain View, CA 94043 - - Phone: (415) 528-2600 - EMail: montulli@netscape.com - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Kristol & Montulli Standards Track [Page 21] - diff --git a/kioslave/http/kcookiejar/rfc2965 b/kioslave/http/kcookiejar/rfc2965 deleted file mode 100644 index 8a4d02b17..000000000 --- a/kioslave/http/kcookiejar/rfc2965 +++ /dev/null @@ -1,1459 +0,0 @@ - - - - - - -Network Working Group D. Kristol -Request for Comments: 2965 Bell Laboratories, Lucent Technologies -Obsoletes: 2109 L. Montulli -Category: Standards Track Epinions.com, Inc. - October 2000 - - - HTTP State Management Mechanism - -Status of this Memo - - This document specifies an Internet standards track protocol for the - Internet community, and requests discussion and suggestions for - improvements. Please refer to the current edition of the "Internet - Official Protocol Standards" (STD 1) for the standardization state - and status of this protocol. Distribution of this memo is unlimited. - -Copyright Notice - - Copyright (C) The Internet Society (2000). All Rights Reserved. - -IESG Note - - The IESG notes that this mechanism makes use of the .local top-level - domain (TLD) internally when handling host names that don't contain - any dots, and that this mechanism might not work in the expected way - should an actual .local TLD ever be registered. - -Abstract - - This document specifies a way to create a stateful session with - Hypertext Transfer Protocol (HTTP) requests and responses. It - describes three new headers, Cookie, Cookie2, and Set-Cookie2, which - carry state information between participating origin servers and user - agents. The method described here differs from Netscape's Cookie - proposal [Netscape], but it can interoperate with HTTP/1.0 user - agents that use Netscape's method. (See the HISTORICAL section.) - - This document reflects implementation experience with RFC 2109 and - obsoletes it. - -1. TERMINOLOGY - - The terms user agent, client, server, proxy, origin server, and - http_URL have the same meaning as in the HTTP/1.1 specification - [RFC2616]. The terms abs_path and absoluteURI have the same meaning - as in the URI Syntax specification [RFC2396]. - - - - -Kristol & Montulli Standards Track [Page 1] - -RFC 2965 HTTP State Management Mechanism October 2000 - - - Host name (HN) means either the host domain name (HDN) or the numeric - Internet Protocol (IP) address of a host. The fully qualified domain - name is preferred; use of numeric IP addresses is strongly - discouraged. - - The terms request-host and request-URI refer to the values the client - would send to the server as, respectively, the host (but not port) - and abs_path portions of the absoluteURI (http_URL) of the HTTP - request line. Note that request-host is a HN. - - The term effective host name is related to host name. If a host name - contains no dots, the effective host name is that name with the - string .local appended to it. Otherwise the effective host name is - the same as the host name. Note that all effective host names - contain at least one dot. - - The term request-port refers to the port portion of the absoluteURI - (http_URL) of the HTTP request line. If the absoluteURI has no - explicit port, the request-port is the HTTP default, 80. The - request-port of a cookie is the request-port of the request in which - a Set-Cookie2 response header was returned to the user agent. - - Host names can be specified either as an IP address or a HDN string. - Sometimes we compare one host name with another. (Such comparisons - SHALL be case-insensitive.) Host A's name domain-matches host B's if - - * their host name strings string-compare equal; or - - * A is a HDN string and has the form NB, where N is a non-empty - name string, B has the form .B', and B' is a HDN string. (So, - x.y.com domain-matches .Y.com but not Y.com.) - - Note that domain-match is not a commutative operation: a.b.c.com - domain-matches .c.com, but not the reverse. - - The reach R of a host name H is defined as follows: - - * If - - - H is the host domain name of a host; and, - - - H has the form A.B; and - - - A has no embedded (that is, interior) dots; and - - - B has at least one embedded dot, or B is the string "local". - then the reach of H is .B. - - - - -Kristol & Montulli Standards Track [Page 2] - -RFC 2965 HTTP State Management Mechanism October 2000 - - - * Otherwise, the reach of H is H. - - For two strings that represent paths, P1 and P2, P1 path-matches P2 - if P2 is a prefix of P1 (including the case where P1 and P2 string- - compare equal). Thus, the string /tec/waldo path-matches /tec. - - Because it was used in Netscape's original implementation of state - management, we will use the term cookie to refer to the state - information that passes between an origin server and user agent, and - that gets stored by the user agent. - -1.1 Requirements - - The key words "MAY", "MUST", "MUST NOT", "OPTIONAL", "RECOMMENDED", - "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT" in this - document are to be interpreted as described in RFC 2119 [RFC2119]. - -2. STATE AND SESSIONS - - This document describes a way to create stateful sessions with HTTP - requests and responses. Currently, HTTP servers respond to each - client request without relating that request to previous or - subsequent requests; the state management mechanism allows clients - and servers that wish to exchange state information to place HTTP - requests and responses within a larger context, which we term a - "session". This context might be used to create, for example, a - "shopping cart", in which user selections can be aggregated before - purchase, or a magazine browsing system, in which a user's previous - reading affects which offerings are presented. - - Neither clients nor servers are required to support cookies. A - server MAY refuse to provide content to a client that does not return - the cookies it sends. - -3. DESCRIPTION - - We describe here a way for an origin server to send state information - to the user agent, and for the user agent to return the state - information to the origin server. The goal is to have a minimal - impact on HTTP and user agents. - -3.1 Syntax: General - - The two state management headers, Set-Cookie2 and Cookie, have common - syntactic properties involving attribute-value pairs. The following - grammar uses the notation, and tokens DIGIT (decimal digits), token - - - - - -Kristol & Montulli Standards Track [Page 3] - -RFC 2965 HTTP State Management Mechanism October 2000 - - - (informally, a sequence of non-special, non-white space characters), - and http_URL from the HTTP/1.1 specification [RFC2616] to describe - their syntax. - - av-pairs = av-pair *(";" av-pair) - av-pair = attr ["=" value] ; optional value - attr = token - value = token | quoted-string - - Attributes (names) (attr) are case-insensitive. White space is - permitted between tokens. Note that while the above syntax - description shows value as optional, most attrs require them. - - NOTE: The syntax above allows whitespace between the attribute and - the = sign. - -3.2 Origin Server Role - - 3.2.1 General The origin server initiates a session, if it so - desires. To do so, it returns an extra response header to the - client, Set-Cookie2. (The details follow later.) - - A user agent returns a Cookie request header (see below) to the - origin server if it chooses to continue a session. The origin server - MAY ignore it or use it to determine the current state of the - session. It MAY send back to the client a Set-Cookie2 response - header with the same or different information, or it MAY send no - Set-Cookie2 header at all. The origin server effectively ends a - session by sending the client a Set-Cookie2 header with Max-Age=0. - - Servers MAY return Set-Cookie2 response headers with any response. - User agents SHOULD send Cookie request headers, subject to other - rules detailed below, with every request. - - An origin server MAY include multiple Set-Cookie2 headers in a - response. Note that an intervening gateway could fold multiple such - headers into a single header. - - - - - - - - - - - - - - -Kristol & Montulli Standards Track [Page 4] - -RFC 2965 HTTP State Management Mechanism October 2000 - - - 3.2.2 Set-Cookie2 Syntax The syntax for the Set-Cookie2 response - header is - - set-cookie = "Set-Cookie2:" cookies - cookies = 1#cookie - cookie = NAME "=" VALUE *(";" set-cookie-av) - NAME = attr - VALUE = value - set-cookie-av = "Comment" "=" value - | "CommentURL" "=" <"> http_URL <"> - | "Discard" - | "Domain" "=" value - | "Max-Age" "=" value - | "Path" "=" value - | "Port" [ "=" <"> portlist <"> ] - | "Secure" - | "Version" "=" 1*DIGIT - portlist = 1#portnum - portnum = 1*DIGIT - - Informally, the Set-Cookie2 response header comprises the token Set- - Cookie2:, followed by a comma-separated list of one or more cookies. - Each cookie begins with a NAME=VALUE pair, followed by zero or more - semi-colon-separated attribute-value pairs. The syntax for - attribute-value pairs was shown earlier. The specific attributes and - the semantics of their values follows. The NAME=VALUE attribute- - value pair MUST come first in each cookie. The others, if present, - can occur in any order. If an attribute appears more than once in a - cookie, the client SHALL use only the value associated with the first - appearance of the attribute; a client MUST ignore values after the - first. - - The NAME of a cookie MAY be the same as one of the attributes in this - specification. However, because the cookie's NAME must come first in - a Set-Cookie2 response header, the NAME and its VALUE cannot be - confused with an attribute-value pair. - - NAME=VALUE - REQUIRED. The name of the state information ("cookie") is NAME, - and its value is VALUE. NAMEs that begin with $ are reserved and - MUST NOT be used by applications. - - The VALUE is opaque to the user agent and may be anything the - origin server chooses to send, possibly in a server-selected - printable ASCII encoding. "Opaque" implies that the content is of - interest and relevance only to the origin server. The content - may, in fact, be readable by anyone that examines the Set-Cookie2 - header. - - - -Kristol & Montulli Standards Track [Page 5] - -RFC 2965 HTTP State Management Mechanism October 2000 - - - Comment=value - OPTIONAL. Because cookies can be used to derive or store private - information about a user, the value of the Comment attribute - allows an origin server to document how it intends to use the - cookie. The user can inspect the information to decide whether to - initiate or continue a session with this cookie. Characters in - value MUST be in UTF-8 encoding. [RFC2279] - - CommentURL="http_URL" - OPTIONAL. Because cookies can be used to derive or store private - information about a user, the CommentURL attribute allows an - origin server to document how it intends to use the cookie. The - user can inspect the information identified by the URL to decide - whether to initiate or continue a session with this cookie. - - Discard - OPTIONAL. The Discard attribute instructs the user agent to - discard the cookie unconditionally when the user agent terminates. - - Domain=value - OPTIONAL. The value of the Domain attribute specifies the domain - for which the cookie is valid. If an explicitly specified value - does not start with a dot, the user agent supplies a leading dot. - - Max-Age=value - OPTIONAL. The value of the Max-Age attribute is delta-seconds, - the lifetime of the cookie in seconds, a decimal non-negative - integer. To handle cached cookies correctly, a client SHOULD - calculate the age of the cookie according to the age calculation - rules in the HTTP/1.1 specification [RFC2616]. When the age is - greater than delta-seconds seconds, the client SHOULD discard the - cookie. A value of zero means the cookie SHOULD be discarded - immediately. - - Path=value - OPTIONAL. The value of the Path attribute specifies the subset of - URLs on the origin server to which this cookie applies. - - Port[="portlist"] - OPTIONAL. The Port attribute restricts the port to which a cookie - may be returned in a Cookie request header. Note that the syntax - REQUIREs quotes around the OPTIONAL portlist even if there is only - one portnum in portlist. - - - - - - - - -Kristol & Montulli Standards Track [Page 6] - -RFC 2965 HTTP State Management Mechanism October 2000 - - - Secure - OPTIONAL. The Secure attribute (with no value) directs the user - agent to use only (unspecified) secure means to contact the origin - server whenever it sends back this cookie, to protect the - confidentially and authenticity of the information in the cookie. - - The user agent (possibly with user interaction) MAY determine what - level of security it considers appropriate for "secure" cookies. - The Secure attribute should be considered security advice from the - server to the user agent, indicating that it is in the session's - interest to protect the cookie contents. When it sends a "secure" - cookie back to a server, the user agent SHOULD use no less than - the same level of security as was used when it received the cookie - from the server. - - Version=value - REQUIRED. The value of the Version attribute, a decimal integer, - identifies the version of the state management specification to - which the cookie conforms. For this specification, Version=1 - applies. - - 3.2.3 Controlling Caching An origin server must be cognizant of the - effect of possible caching of both the returned resource and the - Set-Cookie2 header. Caching "public" documents is desirable. For - example, if the origin server wants to use a public document such as - a "front door" page as a sentinel to indicate the beginning of a - session for which a Set-Cookie2 response header must be generated, - the page SHOULD be stored in caches "pre-expired" so that the origin - server will see further requests. "Private documents", for example - those that contain information strictly private to a session, SHOULD - NOT be cached in shared caches. - - If the cookie is intended for use by a single user, the Set-Cookie2 - header SHOULD NOT be cached. A Set-Cookie2 header that is intended - to be shared by multiple users MAY be cached. - - The origin server SHOULD send the following additional HTTP/1.1 - response headers, depending on circumstances: - - * To suppress caching of the Set-Cookie2 header: - - Cache-control: no-cache="set-cookie2" - - and one of the following: - - * To suppress caching of a private document in shared caches: - - Cache-control: private - - - -Kristol & Montulli Standards Track [Page 7] - -RFC 2965 HTTP State Management Mechanism October 2000 - - - * To allow caching of a document and require that it be validated - before returning it to the client: - - Cache-Control: must-revalidate, max-age=0 - - * To allow caching of a document, but to require that proxy - caches (not user agent caches) validate it before returning it - to the client: - - Cache-Control: proxy-revalidate, max-age=0 - - * To allow caching of a document and request that it be validated - before returning it to the client (by "pre-expiring" it): - - Cache-control: max-age=0 - - Not all caches will revalidate the document in every case. - - HTTP/1.1 servers MUST send Expires: old-date (where old-date is a - date long in the past) on responses containing Set-Cookie2 response - headers unless they know for certain (by out of band means) that - there are no HTTP/1.0 proxies in the response chain. HTTP/1.1 - servers MAY send other Cache-Control directives that permit caching - by HTTP/1.1 proxies in addition to the Expires: old-date directive; - the Cache-Control directive will override the Expires: old-date for - HTTP/1.1 proxies. - -3.3 User Agent Role - - 3.3.1 Interpreting Set-Cookie2 The user agent keeps separate track - of state information that arrives via Set-Cookie2 response headers - from each origin server (as distinguished by name or IP address and - port). The user agent MUST ignore attribute-value pairs whose - attribute it does not recognize. The user agent applies these - defaults for optional attributes that are missing: - - Discard The default behavior is dictated by the presence or absence - of a Max-Age attribute. - - Domain Defaults to the effective request-host. (Note that because - there is no dot at the beginning of effective request-host, - the default Domain can only domain-match itself.) - - Max-Age The default behavior is to discard the cookie when the user - agent exits. - - Path Defaults to the path of the request URL that generated the - Set-Cookie2 response, up to and including the right-most /. - - - -Kristol & Montulli Standards Track [Page 8] - -RFC 2965 HTTP State Management Mechanism October 2000 - - - Port The default behavior is that a cookie MAY be returned to any - request-port. - - Secure If absent, the user agent MAY send the cookie over an - insecure channel. - - 3.3.2 Rejecting Cookies To prevent possible security or privacy - violations, a user agent rejects a cookie according to rules below. - The goal of the rules is to try to limit the set of servers for which - a cookie is valid, based on the values of the Path, Domain, and Port - attributes and the request-URI, request-host and request-port. - - A user agent rejects (SHALL NOT store its information) if the Version - attribute is missing. Moreover, a user agent rejects (SHALL NOT - store its information) if any of the following is true of the - attributes explicitly present in the Set-Cookie2 response header: - - * The value for the Path attribute is not a prefix of the - request-URI. - - * The value for the Domain attribute contains no embedded dots, - and the value is not .local. - - * The effective host name that derives from the request-host does - not domain-match the Domain attribute. - - * The request-host is a HDN (not IP address) and has the form HD, - where D is the value of the Domain attribute, and H is a string - that contains one or more dots. - - * The Port attribute has a "port-list", and the request-port was - not in the list. - - Examples: - - * A Set-Cookie2 from request-host y.x.foo.com for Domain=.foo.com - would be rejected, because H is y.x and contains a dot. - - * A Set-Cookie2 from request-host x.foo.com for Domain=.foo.com - would be accepted. - - * A Set-Cookie2 with Domain=.com or Domain=.com., will always be - rejected, because there is no embedded dot. - - * A Set-Cookie2 with Domain=ajax.com will be accepted, and the - value for Domain will be taken to be .ajax.com, because a dot - gets prepended to the value. - - - - -Kristol & Montulli Standards Track [Page 9] - -RFC 2965 HTTP State Management Mechanism October 2000 - - - * A Set-Cookie2 with Port="80,8000" will be accepted if the - request was made to port 80 or 8000 and will be rejected - otherwise. - - * A Set-Cookie2 from request-host example for Domain=.local will - be accepted, because the effective host name for the request- - host is example.local, and example.local domain-matches .local. - - 3.3.3 Cookie Management If a user agent receives a Set-Cookie2 - response header whose NAME is the same as that of a cookie it has - previously stored, the new cookie supersedes the old when: the old - and new Domain attribute values compare equal, using a case- - insensitive string-compare; and, the old and new Path attribute - values string-compare equal (case-sensitive). However, if the Set- - Cookie2 has a value for Max-Age of zero, the (old and new) cookie is - discarded. Otherwise a cookie persists (resources permitting) until - whichever happens first, then gets discarded: its Max-Age lifetime is - exceeded; or, if the Discard attribute is set, the user agent - terminates the session. - - Because user agents have finite space in which to store cookies, they - MAY also discard older cookies to make space for newer ones, using, - for example, a least-recently-used algorithm, along with constraints - on the maximum number of cookies that each origin server may set. - - If a Set-Cookie2 response header includes a Comment attribute, the - user agent SHOULD store that information in a human-readable form - with the cookie and SHOULD display the comment text as part of a - cookie inspection user interface. - - If a Set-Cookie2 response header includes a CommentURL attribute, the - user agent SHOULD store that information in a human-readable form - with the cookie, or, preferably, SHOULD allow the user to follow the - http_URL link as part of a cookie inspection user interface. - - The cookie inspection user interface may include a facility whereby a - user can decide, at the time the user agent receives the Set-Cookie2 - response header, whether or not to accept the cookie. A potentially - confusing situation could arise if the following sequence occurs: - - * the user agent receives a cookie that contains a CommentURL - attribute; - - * the user agent's cookie inspection interface is configured so - that it presents a dialog to the user before the user agent - accepts the cookie; - - - - - -Kristol & Montulli Standards Track [Page 10] - -RFC 2965 HTTP State Management Mechanism October 2000 - - - * the dialog allows the user to follow the CommentURL link when - the user agent receives the cookie; and, - - * when the user follows the CommentURL link, the origin server - (or another server, via other links in the returned content) - returns another cookie. - - The user agent SHOULD NOT send any cookies in this context. The user - agent MAY discard any cookie it receives in this context that the - user has not, through some user agent mechanism, deemed acceptable. - - User agents SHOULD allow the user to control cookie destruction, but - they MUST NOT extend the cookie's lifetime beyond that controlled by - the Discard and Max-Age attributes. An infrequently-used cookie may - function as a "preferences file" for network applications, and a user - may wish to keep it even if it is the least-recently-used cookie. One - possible implementation would be an interface that allows the - permanent storage of a cookie through a checkbox (or, conversely, its - immediate destruction). - - Privacy considerations dictate that the user have considerable - control over cookie management. The PRIVACY section contains more - information. - - 3.3.4 Sending Cookies to the Origin Server When it sends a request - to an origin server, the user agent includes a Cookie request header - if it has stored cookies that are applicable to the request, based on - - * the request-host and request-port; - - * the request-URI; - - * the cookie's age. - - The syntax for the header is: - -cookie = "Cookie:" cookie-version 1*((";" | ",") cookie-value) -cookie-value = NAME "=" VALUE [";" path] [";" domain] [";" port] -cookie-version = "$Version" "=" value -NAME = attr -VALUE = value -path = "$Path" "=" value -domain = "$Domain" "=" value -port = "$Port" [ "=" <"> value <"> ] - - The value of the cookie-version attribute MUST be the value from the - Version attribute of the corresponding Set-Cookie2 response header. - Otherwise the value for cookie-version is 0. The value for the path - - - -Kristol & Montulli Standards Track [Page 11] - -RFC 2965 HTTP State Management Mechanism October 2000 - - - attribute MUST be the value from the Path attribute, if one was - present, of the corresponding Set-Cookie2 response header. Otherwise - the attribute SHOULD be omitted from the Cookie request header. The - value for the domain attribute MUST be the value from the Domain - attribute, if one was present, of the corresponding Set-Cookie2 - response header. Otherwise the attribute SHOULD be omitted from the - Cookie request header. - - The port attribute of the Cookie request header MUST mirror the Port - attribute, if one was present, in the corresponding Set-Cookie2 - response header. That is, the port attribute MUST be present if the - Port attribute was present in the Set-Cookie2 header, and it MUST - have the same value, if any. Otherwise, if the Port attribute was - absent from the Set-Cookie2 header, the attribute likewise MUST be - omitted from the Cookie request header. - - Note that there is neither a Comment nor a CommentURL attribute in - the Cookie request header corresponding to the ones in the Set- - Cookie2 response header. The user agent does not return the comment - information to the origin server. - - The user agent applies the following rules to choose applicable - cookie-values to send in Cookie request headers from among all the - cookies it has received. - - Domain Selection - The origin server's effective host name MUST domain-match the - Domain attribute of the cookie. - - Port Selection - There are three possible behaviors, depending on the Port - attribute in the Set-Cookie2 response header: - - 1. By default (no Port attribute), the cookie MAY be sent to any - port. - - 2. If the attribute is present but has no value (e.g., Port), the - cookie MUST only be sent to the request-port it was received - from. - - 3. If the attribute has a port-list, the cookie MUST only be - returned if the new request-port is one of those listed in - port-list. - - Path Selection - The request-URI MUST path-match the Path attribute of the cookie. - - - - - -Kristol & Montulli Standards Track [Page 12] - -RFC 2965 HTTP State Management Mechanism October 2000 - - - Max-Age Selection - Cookies that have expired should have been discarded and thus are - not forwarded to an origin server. - - If multiple cookies satisfy the criteria above, they are ordered in - the Cookie header such that those with more specific Path attributes - precede those with less specific. Ordering with respect to other - attributes (e.g., Domain) is unspecified. - - Note: For backward compatibility, the separator in the Cookie header - is semi-colon (;) everywhere. A server SHOULD also accept comma (,) - as the separator between cookie-values for future compatibility. - - 3.3.5 Identifying What Version is Understood: Cookie2 The Cookie2 - request header facilitates interoperation between clients and servers - that understand different versions of the cookie specification. When - the client sends one or more cookies to an origin server, if at least - one of those cookies contains a $Version attribute whose value is - different from the version that the client understands, then the - client MUST also send a Cookie2 request header, the syntax for which - is - - cookie2 = "Cookie2:" cookie-version - - Here the value for cookie-version is the highest version of cookie - specification (currently 1) that the client understands. The client - needs to send at most one such request header per request. - - 3.3.6 Sending Cookies in Unverifiable Transactions Users MUST have - control over sessions in order to ensure privacy. (See PRIVACY - section below.) To simplify implementation and to prevent an - additional layer of complexity where adequate safeguards exist, - however, this document distinguishes between transactions that are - verifiable and those that are unverifiable. A transaction is - verifiable if the user, or a user-designated agent, has the option to - review the request-URI prior to its use in the transaction. A - transaction is unverifiable if the user does not have that option. - Unverifiable transactions typically arise when a user agent - automatically requests inlined or embedded entities or when it - resolves redirection (3xx) responses from an origin server. - Typically the origin transaction, the transaction that the user - initiates, is verifiable, and that transaction may directly or - indirectly induce the user agent to make unverifiable transactions. - - An unverifiable transaction is to a third-party host if its request- - host U does not domain-match the reach R of the request-host O in the - origin transaction. - - - - -Kristol & Montulli Standards Track [Page 13] - -RFC 2965 HTTP State Management Mechanism October 2000 - - - When it makes an unverifiable transaction, a user agent MUST disable - all cookie processing (i.e., MUST NOT send cookies, and MUST NOT - accept any received cookies) if the transaction is to a third-party - host. - - This restriction prevents a malicious service author from using - unverifiable transactions to induce a user agent to start or continue - a session with a server in a different domain. The starting or - continuation of such sessions could be contrary to the privacy - expectations of the user, and could also be a security problem. - - User agents MAY offer configurable options that allow the user agent, - or any autonomous programs that the user agent executes, to ignore - the above rule, so long as these override options default to "off". - - (N.B. Mechanisms may be proposed that will automate overriding the - third-party restrictions under controlled conditions.) - - Many current user agents already provide a review option that would - render many links verifiable. For instance, some user agents display - the URL that would be referenced for a particular link when the mouse - pointer is placed over that link. The user can therefore determine - whether to visit that site before causing the browser to do so. - (Though not implemented on current user agents, a similar technique - could be used for a button used to submit a form -- the user agent - could display the action to be taken if the user were to select that - button.) However, even this would not make all links verifiable; for - example, links to automatically loaded images would not normally be - subject to "mouse pointer" verification. - - Many user agents also provide the option for a user to view the HTML - source of a document, or to save the source to an external file where - it can be viewed by another application. While such an option does - provide a crude review mechanism, some users might not consider it - acceptable for this purpose. - -3.4 How an Origin Server Interprets the Cookie Header - - A user agent returns much of the information in the Set-Cookie2 - header to the origin server when the request-URI path-matches the - Path attribute of the cookie. When it receives a Cookie header, the - origin server SHOULD treat cookies with NAMEs whose prefix is $ - specially, as an attribute for the cookie. - - - - - - - - -Kristol & Montulli Standards Track [Page 14] - -RFC 2965 HTTP State Management Mechanism October 2000 - - -3.5 Caching Proxy Role - - One reason for separating state information from both a URL and - document content is to facilitate the scaling that caching permits. - To support cookies, a caching proxy MUST obey these rules already in - the HTTP specification: - - * Honor requests from the cache, if possible, based on cache - validity rules. - - * Pass along a Cookie request header in any request that the - proxy must make of another server. - - * Return the response to the client. Include any Set-Cookie2 - response header. - - * Cache the received response subject to the control of the usual - headers, such as Expires, - - Cache-control: no-cache - - and - - Cache-control: private - - * Cache the Set-Cookie2 subject to the control of the usual - header, - - Cache-control: no-cache="set-cookie2" - - (The Set-Cookie2 header should usually not be cached.) - - Proxies MUST NOT introduce Set-Cookie2 (Cookie) headers of their own - in proxy responses (requests). - -4. EXAMPLES - -4.1 Example 1 - - Most detail of request and response headers has been omitted. Assume - the user agent has no stored cookies. - - 1. User Agent -> Server - - POST /acme/login HTTP/1.1 - [form data] - - User identifies self via a form. - - - -Kristol & Montulli Standards Track [Page 15] - -RFC 2965 HTTP State Management Mechanism October 2000 - - - 2. Server -> User Agent - - HTTP/1.1 200 OK - Set-Cookie2: Customer="WILE_E_COYOTE"; Version="1"; Path="/acme" - - Cookie reflects user's identity. - - 3. User Agent -> Server - - POST /acme/pickitem HTTP/1.1 - Cookie: $Version="1"; Customer="WILE_E_COYOTE"; $Path="/acme" - [form data] - - User selects an item for "shopping basket". - - 4. Server -> User Agent - - HTTP/1.1 200 OK - Set-Cookie2: Part_Number="Rocket_Launcher_0001"; Version="1"; - Path="/acme" - - Shopping basket contains an item. - - 5. User Agent -> Server - - POST /acme/shipping HTTP/1.1 - Cookie: $Version="1"; - Customer="WILE_E_COYOTE"; $Path="/acme"; - Part_Number="Rocket_Launcher_0001"; $Path="/acme" - [form data] - - User selects shipping method from form. - - 6. Server -> User Agent - - HTTP/1.1 200 OK - Set-Cookie2: Shipping="FedEx"; Version="1"; Path="/acme" - - New cookie reflects shipping method. - - 7. User Agent -> Server - - POST /acme/process HTTP/1.1 - Cookie: $Version="1"; - Customer="WILE_E_COYOTE"; $Path="/acme"; - Part_Number="Rocket_Launcher_0001"; $Path="/acme"; - Shipping="FedEx"; $Path="/acme" - [form data] - - - -Kristol & Montulli Standards Track [Page 16] - -RFC 2965 HTTP State Management Mechanism October 2000 - - - User chooses to process order. - - 8. Server -> User Agent - - HTTP/1.1 200 OK - - Transaction is complete. - - The user agent makes a series of requests on the origin server, after - each of which it receives a new cookie. All the cookies have the - same Path attribute and (default) domain. Because the request-URIs - all path-match /acme, the Path attribute of each cookie, each request - contains all the cookies received so far. - -4.2 Example 2 - - This example illustrates the effect of the Path attribute. All - detail of request and response headers has been omitted. Assume the - user agent has no stored cookies. - - Imagine the user agent has received, in response to earlier requests, - the response headers - - Set-Cookie2: Part_Number="Rocket_Launcher_0001"; Version="1"; - Path="/acme" - - and - - Set-Cookie2: Part_Number="Riding_Rocket_0023"; Version="1"; - Path="/acme/ammo" - - A subsequent request by the user agent to the (same) server for URLs - of the form /acme/ammo/... would include the following request - header: - - Cookie: $Version="1"; - Part_Number="Riding_Rocket_0023"; $Path="/acme/ammo"; - Part_Number="Rocket_Launcher_0001"; $Path="/acme" - - Note that the NAME=VALUE pair for the cookie with the more specific - Path attribute, /acme/ammo, comes before the one with the less - specific Path attribute, /acme. Further note that the same cookie - name appears more than once. - - A subsequent request by the user agent to the (same) server for a URL - of the form /acme/parts/ would include the following request header: - - - - - -Kristol & Montulli Standards Track [Page 17] - -RFC 2965 HTTP State Management Mechanism October 2000 - - - Cookie: $Version="1"; Part_Number="Rocket_Launcher_0001"; - $Path="/acme" - - Here, the second cookie's Path attribute /acme/ammo is not a prefix - of the request URL, /acme/parts/, so the cookie does not get - forwarded to the server. - -5. IMPLEMENTATION CONSIDERATIONS - - Here we provide guidance on likely or desirable details for an origin - server that implements state management. - -5.1 Set-Cookie2 Content - - An origin server's content should probably be divided into disjoint - application areas, some of which require the use of state - information. The application areas can be distinguished by their - request URLs. The Set-Cookie2 header can incorporate information - about the application areas by setting the Path attribute for each - one. - - The session information can obviously be clear or encoded text that - describes state. However, if it grows too large, it can become - unwieldy. Therefore, an implementor might choose for the session - information to be a key to a server-side resource. Of course, using - a database creates some problems that this state management - specification was meant to avoid, namely: - - 1. keeping real state on the server side; - - 2. how and when to garbage-collect the database entry, in case the - user agent terminates the session by, for example, exiting. - -5.2 Stateless Pages - - Caching benefits the scalability of WWW. Therefore it is important - to reduce the number of documents that have state embedded in them - inherently. For example, if a shopping-basket-style application - always displays a user's current basket contents on each page, those - pages cannot be cached, because each user's basket's contents would - be different. On the other hand, if each page contains just a link - that allows the user to "Look at My Shopping Basket", the page can be - cached. - - - - - - - - -Kristol & Montulli Standards Track [Page 18] - -RFC 2965 HTTP State Management Mechanism October 2000 - - -5.3 Implementation Limits - - Practical user agent implementations have limits on the number and - size of cookies that they can store. In general, user agents' cookie - support should have no fixed limits. They should strive to store as - many frequently-used cookies as possible. Furthermore, general-use - user agents SHOULD provide each of the following minimum capabilities - individually, although not necessarily simultaneously: - - * at least 300 cookies - - * at least 4096 bytes per cookie (as measured by the characters - that comprise the cookie non-terminal in the syntax description - of the Set-Cookie2 header, and as received in the Set-Cookie2 - header) - - * at least 20 cookies per unique host or domain name - - User agents created for specific purposes or for limited-capacity - devices SHOULD provide at least 20 cookies of 4096 bytes, to ensure - that the user can interact with a session-based origin server. - - The information in a Set-Cookie2 response header MUST be retained in - its entirety. If for some reason there is inadequate space to store - the cookie, it MUST be discarded, not truncated. - - Applications should use as few and as small cookies as possible, and - they should cope gracefully with the loss of a cookie. - - 5.3.1 Denial of Service Attacks User agents MAY choose to set an - upper bound on the number of cookies to be stored from a given host - or domain name or on the size of the cookie information. Otherwise a - malicious server could attempt to flood a user agent with many - cookies, or large cookies, on successive responses, which would force - out cookies the user agent had received from other servers. However, - the minima specified above SHOULD still be supported. - -6. PRIVACY - - Informed consent should guide the design of systems that use cookies. - A user should be able to find out how a web site plans to use - information in a cookie and should be able to choose whether or not - those policies are acceptable. Both the user agent and the origin - server must assist informed consent. - - - - - - - -Kristol & Montulli Standards Track [Page 19] - -RFC 2965 HTTP State Management Mechanism October 2000 - - -6.1 User Agent Control - - An origin server could create a Set-Cookie2 header to track the path - of a user through the server. Users may object to this behavior as - an intrusive accumulation of information, even if their identity is - not evident. (Identity might become evident, for example, if a user - subsequently fills out a form that contains identifying information.) - This state management specification therefore requires that a user - agent give the user control over such a possible intrusion, although - the interface through which the user is given this control is left - unspecified. However, the control mechanisms provided SHALL at least - allow the user - - * to completely disable the sending and saving of cookies. - - * to determine whether a stateful session is in progress. - - * to control the saving of a cookie on the basis of the cookie's - Domain attribute. - - Such control could be provided, for example, by mechanisms - - * to notify the user when the user agent is about to send a - cookie to the origin server, to offer the option not to begin a - session. - - * to display a visual indication that a stateful session is in - progress. - - * to let the user decide which cookies, if any, should be saved - when the user concludes a window or user agent session. - - * to let the user examine and delete the contents of a cookie at - any time. - - A user agent usually begins execution with no remembered state - information. It SHOULD be possible to configure a user agent never - to send Cookie headers, in which case it can never sustain state with - an origin server. (The user agent would then behave like one that is - unaware of how to handle Set-Cookie2 response headers.) - - When the user agent terminates execution, it SHOULD let the user - discard all state information. Alternatively, the user agent MAY ask - the user whether state information should be retained; the default - should be "no". If the user chooses to retain state information, it - would be restored the next time the user agent runs. - - - - - -Kristol & Montulli Standards Track [Page 20] - -RFC 2965 HTTP State Management Mechanism October 2000 - - - NOTE: User agents should probably be cautious about using files to - store cookies long-term. If a user runs more than one instance of - the user agent, the cookies could be commingled or otherwise - corrupted. - -6.2 Origin Server Role - - An origin server SHOULD promote informed consent by adding CommentURL - or Comment information to the cookies it sends. CommentURL is - preferred because of the opportunity to provide richer information in - a multiplicity of languages. - -6.3 Clear Text - - The information in the Set-Cookie2 and Cookie headers is unprotected. - As a consequence: - - 1. Any sensitive information that is conveyed in them is exposed - to intruders. - - 2. A malicious intermediary could alter the headers as they travel - in either direction, with unpredictable results. - - These facts imply that information of a personal and/or financial - nature should only be sent over a secure channel. For less sensitive - information, or when the content of the header is a database key, an - origin server should be vigilant to prevent a bad Cookie value from - causing failures. - - A user agent in a shared user environment poses a further risk. - Using a cookie inspection interface, User B could examine the - contents of cookies that were saved when User A used the machine. - -7. SECURITY CONSIDERATIONS - -7.1 Protocol Design - - The restrictions on the value of the Domain attribute, and the rules - concerning unverifiable transactions, are meant to reduce the ways - that cookies can "leak" to the "wrong" site. The intent is to - restrict cookies to one host, or a closely related set of hosts. - Therefore a request-host is limited as to what values it can set for - Domain. We consider it acceptable for hosts host1.foo.com and - host2.foo.com to share cookies, but not a.com and b.com. - - Similarly, a server can set a Path only for cookies that are related - to the request-URI. - - - - -Kristol & Montulli Standards Track [Page 21] - -RFC 2965 HTTP State Management Mechanism October 2000 - - -7.2 Cookie Spoofing - - Proper application design can avoid spoofing attacks from related - domains. Consider: - - 1. User agent makes request to victim.cracker.edu, gets back - cookie session_id="1234" and sets the default domain - victim.cracker.edu. - - 2. User agent makes request to spoof.cracker.edu, gets back cookie - session-id="1111", with Domain=".cracker.edu". - - 3. User agent makes request to victim.cracker.edu again, and - passes - - Cookie: $Version="1"; session_id="1234", - $Version="1"; session_id="1111"; $Domain=".cracker.edu" - - The server at victim.cracker.edu should detect that the second - cookie was not one it originated by noticing that the Domain - attribute is not for itself and ignore it. - -7.3 Unexpected Cookie Sharing - - A user agent SHOULD make every attempt to prevent the sharing of - session information between hosts that are in different domains. - Embedded or inlined objects may cause particularly severe privacy - problems if they can be used to share cookies between disparate - hosts. For example, a malicious server could embed cookie - information for host a.com in a URI for a CGI on host b.com. User - agent implementors are strongly encouraged to prevent this sort of - exchange whenever possible. - -7.4 Cookies For Account Information - - While it is common practice to use them this way, cookies are not - designed or intended to be used to hold authentication information, - such as account names and passwords. Unless such cookies are - exchanged over an encrypted path, the account information they - contain is highly vulnerable to perusal and theft. - -8. OTHER, SIMILAR, PROPOSALS - - Apart from RFC 2109, three other proposals have been made to - accomplish similar goals. This specification began as an amalgam of - Kristol's State-Info proposal [DMK95] and Netscape's Cookie proposal - [Netscape]. - - - - -Kristol & Montulli Standards Track [Page 22] - -RFC 2965 HTTP State Management Mechanism October 2000 - - - Brian Behlendorf proposed a Session-ID header that would be user- - agent-initiated and could be used by an origin server to track - "clicktrails". It would not carry any origin-server-defined state, - however. Phillip Hallam-Baker has proposed another client-defined - session ID mechanism for similar purposes. - - While both session IDs and cookies can provide a way to sustain - stateful sessions, their intended purpose is different, and, - consequently, the privacy requirements for them are different. A - user initiates session IDs to allow servers to track progress through - them, or to distinguish multiple users on a shared machine. Cookies - are server-initiated, so the cookie mechanism described here gives - users control over something that would otherwise take place without - the users' awareness. Furthermore, cookies convey rich, server- - selected information, whereas session IDs comprise user-selected, - simple information. - -9. HISTORICAL - -9.1 Compatibility with Existing Implementations - - Existing cookie implementations, based on the Netscape specification, - use the Set-Cookie (not Set-Cookie2) header. User agents that - receive in the same response both a Set-Cookie and Set-Cookie2 - response header for the same cookie MUST discard the Set-Cookie - information and use only the Set-Cookie2 information. Furthermore, a - user agent MUST assume, if it received a Set-Cookie2 response header, - that the sending server complies with this document and will - understand Cookie request headers that also follow this - specification. - - New cookies MUST replace both equivalent old- and new-style cookies. - That is, if a user agent that follows both this specification and - Netscape's original specification receives a Set-Cookie2 response - header, and the NAME and the Domain and Path attributes match (per - the Cookie Management section) a Netscape-style cookie, the - Netscape-style cookie MUST be discarded, and the user agent MUST - retain only the cookie adhering to this specification. - - Older user agents that do not understand this specification, but that - do understand Netscape's original specification, will not recognize - the Set-Cookie2 response header and will receive and send cookies - according to the older specification. - - - - - - - - -Kristol & Montulli Standards Track [Page 23] - -RFC 2965 HTTP State Management Mechanism October 2000 - - - A user agent that supports both this specification and Netscape-style - cookies SHOULD send a Cookie request header that follows the older - Netscape specification if it received the cookie in a Set-Cookie - response header and not in a Set-Cookie2 response header. However, - it SHOULD send the following request header as well: - - Cookie2: $Version="1" - - The Cookie2 header advises the server that the user agent understands - new-style cookies. If the server understands new-style cookies, as - well, it SHOULD continue the stateful session by sending a Set- - Cookie2 response header, rather than Set-Cookie. A server that does - not understand new-style cookies will simply ignore the Cookie2 - request header. - -9.2 Caching and HTTP/1.0 - - Some caches, such as those conforming to HTTP/1.0, will inevitably - cache the Set-Cookie2 and Set-Cookie headers, because there was no - mechanism to suppress caching of headers prior to HTTP/1.1. This - caching can lead to security problems. Documents transmitted by an - origin server along with Set-Cookie2 and Set-Cookie headers usually - either will be uncachable, or will be "pre-expired". As long as - caches obey instructions not to cache documents (following Expires: - <a date in the past> or Pragma: no-cache (HTTP/1.0), or Cache- - control: no-cache (HTTP/1.1)) uncachable documents present no - problem. However, pre-expired documents may be stored in caches. - They require validation (a conditional GET) on each new request, but - some cache operators loosen the rules for their caches, and sometimes - serve expired documents without first validating them. This - combination of factors can lead to cookies meant for one user later - being sent to another user. The Set-Cookie2 and Set-Cookie headers - are stored in the cache, and, although the document is stale - (expired), the cache returns the document in response to later - requests, including cached headers. - -10. ACKNOWLEDGEMENTS - - This document really represents the collective efforts of the HTTP - Working Group of the IETF and, particularly, the following people, in - addition to the authors: Roy Fielding, Yaron Goland, Marc Hedlund, - Ted Hardie, Koen Holtman, Shel Kaphan, Rohit Khare, Foteos Macrides, - David W. Morris. - - - - - - - - -Kristol & Montulli Standards Track [Page 24] - -RFC 2965 HTTP State Management Mechanism October 2000 - - -11. AUTHORS' ADDRESSES - - David M. Kristol - Bell Laboratories, Lucent Technologies - 600 Mountain Ave. Room 2A-333 - Murray Hill, NJ 07974 - - Phone: (908) 582-2250 - Fax: (908) 582-1239 - EMail: dmk@bell-labs.com - - - Lou Montulli - Epinions.com, Inc. - 2037 Landings Dr. - Mountain View, CA 94301 - - EMail: lou@montulli.org - -12. REFERENCES - - [DMK95] Kristol, D.M., "Proposed HTTP State-Info Mechanism", - available at <http://portal.research.bell- - labs.com/~dmk/state-info.html>, September, 1995. - - [Netscape] "Persistent Client State -- HTTP Cookies", available at - <http://www.netscape.com/newsref/std/cookie_spec.html>, - undated. - - [RFC2109] Kristol, D. and L. Montulli, "HTTP State Management - Mechanism", RFC 2109, February 1997. - - [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate - Requirement Levels", BCP 14, RFC 2119, March 1997. - - [RFC2279] Yergeau, F., "UTF-8, a transformation format of Unicode - and ISO-10646", RFC 2279, January 1998. - - [RFC2396] Berners-Lee, T., Fielding, R. and L. Masinter, "Uniform - Resource Identifiers (URI): Generic Syntax", RFC 2396, - August 1998. - - [RFC2616] Fielding, R., Gettys, J., Mogul, J., Frystyk, H. and T. - Berners-Lee, "Hypertext Transfer Protocol -- HTTP/1.1", - RFC 2616, June 1999. - - - - - - -Kristol & Montulli Standards Track [Page 25] - -RFC 2965 HTTP State Management Mechanism October 2000 - - -13. Full Copyright Statement - - Copyright (C) The Internet Society (2000). All Rights Reserved. - - This document and translations of it may be copied and furnished to - others, and derivative works that comment on or otherwise explain it - or assist in its implementation may be prepared, copied, published - and distributed, in whole or in part, without restriction of any - kind, provided that the above copyright notice and this paragraph are - included on all such copies and derivative works. However, this - document itself may not be modified in any way, such as by removing - the copyright notice or references to the Internet Society or other - Internet organizations, except as needed for the purpose of - developing Internet standards in which case the procedures for - copyrights defined in the Internet Standards process must be - followed, or as required to translate it into languages other than - English. - - The limited permissions granted above are perpetual and will not be - revoked by the Internet Society or its successors or assigns. - - This document and the information contained herein is provided on an - "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING - TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING - BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION - HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF - MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - -Acknowledgement - - Funding for the RFC Editor function is currently provided by the - Internet Society. - - - - - - - - - - - - - - - - - - - -Kristol & Montulli Standards Track [Page 26] - diff --git a/kioslave/http/kcookiejar/tests/Makefile.am b/kioslave/http/kcookiejar/tests/Makefile.am deleted file mode 100644 index 4059cdcd1..000000000 --- a/kioslave/http/kcookiejar/tests/Makefile.am +++ /dev/null @@ -1,18 +0,0 @@ -# $Id$ -# Makefile.am of tdebase/kioslave/http - -INCLUDES= $(all_includes) - -####### Files - -check_PROGRAMS = kcookiejartest - -kcookiejartest_SOURCES = kcookiejartest.cpp -kcookiejartest_LDADD = $(LIB_KIO) -kcookiejartest_LDFLAGS = $(all_libraries) $(KDE_RPATH) $(LIB_QT) -lDCOP $(LIB_TDECORE) $(LIB_TDEUI) -ltdefx $(LIB_KIO) -ltdetexteditor - -check-local: kcookiejartest - ./kcookiejartest $(srcdir)/cookie.test - ./kcookiejartest $(srcdir)/cookie_rfc.test - ./kcookiejartest $(srcdir)/cookie_saving.test - ./kcookiejartest $(srcdir)/cookie_settings.test diff --git a/kioslave/http/kcookiejar/tests/cookie.test b/kioslave/http/kcookiejar/tests/cookie.test deleted file mode 100644 index 6619bf82d..000000000 --- a/kioslave/http/kcookiejar/tests/cookie.test +++ /dev/null @@ -1,162 +0,0 @@ -## Check setting of cookies -COOKIE ASK http://w.y.z/ Set-Cookie: some_value=value1; Path="/"; expires=%NEXTYEAR% -CHECK http://w.y.z/ Cookie: some_value=value1 -COOKIE ASK http://a.b.c/ Set-Cookie: some_value=value2; Path="/" -CHECK http://a.b.c/ Cookie: some_value=value2 -## Check if clearing cookie jar works -CLEAR COOKIES -CHECK http://w.y.z/ -CHECK http://a.b.c/ -## Check cookie syntax -COOKIE ASK http://w.y.z/ Set-Cookie: some_value=value with spaces -CHECK http://w.y.z/ Cookie: some_value=value with spaces -COOKIE ASK http://a.b.c/ Set-Cookie: some_value="quoted value" -CHECK http://a.b.c/ Cookie: some_value="quoted value" -# Without a = sign, the cookie gets interpreted as the value for a cookie with no name -# This is what IE and Netscape does -COOKIE ASK http://a.b.c/ Set-Cookie: some_value -CHECK http://a.b.c/ Cookie: some_value; some_value="quoted value" -COOKIE ASK http://a.b.c/ Set-Cookie: some_other_value -CHECK http://a.b.c/ Cookie: some_other_value; some_value="quoted value" -CLEAR COOKIES -# This doesn't work with old-style netscape cookies, it should work with RFC2965 cookies -COOKIE ASK http://a.b.c/ Set-Cookie: some_value="quoted value; and such" -# IE & Netscape does this: -CHECK http://a.b.c/ Cookie: some_value="quoted value -# Mozilla does: -# CHECK http://a.b.c/ Cookie: some_value="quoted value; and such" -# COOKIE ASK http://a.b.c/ Set-Cookie: some_value="quoted value; -# CHECK http://a.b.c/ Cookie: some_value= -# Note that we parse RFC2965 cookies like Mozilla does -CLEAR COOKIES -## Check if deleting cookies works -COOKIE ASK http://w.y.z/ Set-Cookie: some_value=value1; Path="/"; expires=%NEXTYEAR% -CHECK http://w.y.z/ Cookie: some_value=value1 -COOKIE ASK http://w.y.z/ Set-Cookie: some_value=value1; Path="/"; expires=%LASTYEAR% -CHECK http://w.y.z/ -## Check if updating cookies works -COOKIE ASK http://w.y.z/ Set-Cookie: some_value=value2; Path="/"; expires=%NEXTYEAR% -COOKIE ASK http://w.y.z/ Set-Cookie: some_value=value3; Path="/"; expires=%NEXTYEAR% -CHECK http://w.y.z/ Cookie: some_value=value3 -## Check if multiple cookies work -COOKIE ASK http://w.y.z/ Set-Cookie: some_value2=foobar; Path="/"; expires=%NEXTYEAR% -CHECK http://w.y.z/ Cookie: some_value2=foobar; some_value=value3 -COOKIE ASK http://w.y.z/ Set-Cookie: some_value=; Path="/"; expires=%LASTYEAR% -CHECK http://w.y.z/ Cookie: some_value2=foobar -CLEAR COOKIES -## Check if path restrictions work -COOKIE ASK http://w.y.z/ Set-Cookie: some_value=value1; Path="/Foo"; expires=%NEXTYEAR% -CHECK http://w.y.z/ -CHECK http://w.y.z/Foo Cookie: some_value=value1 -CHECK http://w.y.z/Foo/ Cookie: some_value=value1 -CHECK http://w.y.z/Foo/bar Cookie: some_value=value1 -CLEAR COOKIES -## Check if default path works -# RFC2965 says that we should default to the URL path, but netscape cookies default to / -COOKIE ASK http://w.y.z/Foo/ Set-Cookie: some_value=value1; expires=%NEXTYEAR% -CHECK http://w.y.z/ -CHECK http://w.y.z/Foo Cookie: some_value=value1 -CHECK http://w.y.z/FooBar -CHECK http://w.y.z/Foo/ Cookie: some_value=value1 -CHECK http://w.y.z/Foo/bar Cookie: some_value=value1 -CLEAR COOKIES -## Check if cookies are correctly ordered based on path -COOKIE ASK http://w.y.z/ Set-Cookie: some_value=value1; Path="/Foo"; expires=%NEXTYEAR% -COOKIE ASK http://w.y.z/ Set-Cookie: some_value2=value2; Path="/Foo/Bar"; expires=%NEXTYEAR% -CHECK http://w.y.z/Foo/Bar Cookie: some_value2=value2; some_value=value1 -COOKIE ASK http://w.y.z/ Set-Cookie: some_value3=value3; Path="/"; expires=%NEXTYEAR% -CHECK http://w.y.z/Foo/Bar Cookie: some_value2=value2; some_value=value1; some_value3=value3 -CLEAR COOKIES -## Check cookies with same name but different paths -COOKIE ASK http://w.y.z/Foo/ Set-Cookie: some_value=value1; expires=%NEXTYEAR% -COOKIE ASK http://w.y.z/Bar/ Set-Cookie: some_value=value2; expires=%NEXTYEAR% -CHECK http://w.y.z/Foo/Bar Cookie: some_value=value1 -CHECK http://w.y.z/Bar/Foo Cookie: some_value=value2 -COOKIE ASK http://w.y.z/ Set-Cookie: some_value=value3; expires=%NEXTYEAR% -CHECK http://w.y.z/Foo/Bar Cookie: some_value=value1; some_value=value3 -## Check secure cookie handling -COOKIE ASK https://secure.y.z/ Set-Cookie: some_value2=value2; Path="/"; expires=%NEXTYEAR%; secure -CHECK https://secure.y.z/Foo/bar Cookie: some_value2=value2 -CHECK http://secure.y.z/Foo/bar -CLEAR COOKIES -COOKIE ASK http://secure.y.z/ Set-Cookie: some_value3=value3; Path="/"; expires=%NEXTYEAR%; secure -CHECK https://secure.y.z/Foo/bar Cookie: some_value3=value3 -CHECK http://secure.y.z/Foo/bar -CLEAR COOKIES -## Check domain restrictions #1 -COOKIE ASK http://www.acme.com/ Set-Cookie: some_value=value1; Domain=".acme.com"; expires=%NEXTYEAR% -CHECK http://www.acme.com/ Cookie: some_value=value1 -CHECK http://www.abc.com/ -CHECK http://frop.acme.com/ Cookie: some_value=value1 -CLEAR COOKIES -## Check domain restrictions #2 -COOKIE ASK http://novell.com/ Set-Cookie: some_value=value1; Domain=".novell.com"; expires=%NEXTYEAR% -CHECK http://novell.com/ Cookie: some_value=value1 -CHECK http://www.novell.com/ Cookie: some_value=value1 -CLEAR COOKIES -COOKIE ASK http://novell.com/ Set-Cookie: some_value=value1; Domain="novell.com"; expires=%NEXTYEAR% -CHECK http://novell.com/ Cookie: some_value=value1 -CHECK http://www.novell.com/ Cookie: some_value=value1 -CLEAR COOKIES -## Check domain restrictions #3 -COOKIE ASK http://novell.com/ Set-Cookie: some_value=value1; expires=%NEXTYEAR% -CHECK http://novell.com/ Cookie: some_value=value1 -# FIXME: Allegedly IE sends cookies to sub-domains as well! -# See e.g. https://bugzilla.mozilla.org/show_bug.cgi?id=223027 -CHECK http://www.novell.com/ -CLEAR COOKIES -## Check domain restrictions #4 -COOKIE ASK http://novell.com/ Set-Cookie: some_value=value1; Domain=".com"; expires=%NEXTYEAR% -CHECK http://novell.com/ Cookie: some_value=value1 -# If the specified domain is too broad, we default to host only -CHECK http://www.novell.com/ -CHECK http://com/ -CHECK http://sun.com/ -## Check domain restrictions #5 -CLEAR COOKIES -COOKIE ASK http://novell.co.uk/ Set-Cookie: some_value=value1; Domain=".co.uk"; expires=%NEXTYEAR% -CHECK http://novell.co.uk/ Cookie: some_value=value1 -# If the specified domain is too broad, we default to host only -CHECK http://www.novell.co.uk/ -CHECK http://co.uk/ -CHECK http://sun.co.uk/ -COOKIE ASK http://x.y.z.foobar.com/ Set-Cookie: set_by=x.y.z.foobar.com; Domain=".foobar.com"; expires=%NEXTYEAR% -CHECK http://x.y.z.foobar.com/ Cookie: set_by=x.y.z.foobar.com -CHECK http://y.z.foobar.com/ Cookie: set_by=x.y.z.foobar.com -CHECK http://z.foobar.com/ Cookie: set_by=x.y.z.foobar.com -CHECK http://www.foobar.com/ Cookie: set_by=x.y.z.foobar.com -CHECK http://foobar.com/ Cookie: set_by=x.y.z.foobar.com -CLEAR COOKIES -## Check domain restrictions #6 -COOKIE ASK http://x.y.z.frop.com/ Set-Cookie: set_by=x.y.z.frop.com; Domain=".foobar.com"; expires=%NEXTYEAR% -COOKIE ASK http://x.y.z.frop.com/ Set-Cookie: set_by2=x.y.z.frop.com; Domain=".com"; expires=%NEXTYEAR% -CHECK http://x.y.z.foobar.com/ -CHECK http://y.z.foobar.com/ -CHECK http://z.foobar.com/ -CHECK http://www.foobar.com/ -CHECK http://foobar.com/ -CLEAR COOKIES -## Check domain restrictions #7 -COOKIE ASK http://frop.com/ Set-Cookie: set_by=x.y.z.frop.com; Domain=".foobar.com"; expires=%NEXTYEAR% -COOKIE ASK http://frop.com/ Set-Cookie: set_by2=x.y.z.frop.com; Domain=".com"; expires=%NEXTYEAR% -CHECK http://x.y.z.foobar.com/ -CHECK http://y.z.foobar.com/ -CHECK http://z.foobar.com/ -CHECK http://www.foobar.com/ -CHECK http://foobar.com/ -CLEAR COOKIES -## Check domain restrictions #8 -CONFIG AcceptSessionCookies true -COOKIE ACCEPT http://www.foobar.com Set-Cookie: from=foobar.com; domain=bar.com; Path="/" -CHECK http://bar.com -CLEAR COOKIES -## Check cookies with IP address hostnames -COOKIE ASK http://192.168.0.1 Set-Cookie: name1=value1; Path="/"; expires=%NEXTYEAR% -COOKIE ASK http://192.168.0.1 Set-Cookie: name11=value11; domain="test.local"; Path="/"; expires=%NEXTYEAR% -COOKIE ASK http://192.168.0.1:8080 Set-Cookie: name2=value2; Path="/"; expires=%NEXTYEAR% -COOKIE ASK https://192.168.0.1 Set-Cookie: name3=value3; Path="/"; expires=%NEXTYEAR%; secure -CHECK http://192.168.0.1 Cookie: name11=value11; name1=value1 -CHECK http://192.168.0.1:8080 Cookie: name2=value2 -CHECK https://192.168.0.1 Cookie: name3=value3; name11=value11; name1=value1 -CHECK http://192.168.0.10 -CHECK http://192.168.0 diff --git a/kioslave/http/kcookiejar/tests/cookie_rfc.test b/kioslave/http/kcookiejar/tests/cookie_rfc.test deleted file mode 100644 index e1d8a40de..000000000 --- a/kioslave/http/kcookiejar/tests/cookie_rfc.test +++ /dev/null @@ -1,148 +0,0 @@ -## Check setting of cookies -COOKIE ASK http://w.y.z/ Set-Cookie2: some_value="value1"; Version=1; Path="/"; Max-Age=3600 -# Although the examples in RFC2965 uses $Version="1" the syntax description suggests that -# such quotes are not allowed, KDE BR59990 reports that the Sun Java server fails to handle -# cookies that use $Version="1" -CHECK http://w.y.z/ Cookie: $Version=1; some_value="value1"; $Path="/" -COOKIE ASK http://a.b.c/ Set-Cookie2: some_value="value2"; Version=1; Path="/" -CHECK http://a.b.c/ Cookie: $Version=1; some_value="value2"; $Path="/" -## Check if clearing cookie jar works -CLEAR COOKIES -CHECK http://w.y.z/ -CHECK http://a.b.c/ -## Check cookie syntax -COOKIE ASK http://w.y.z/ Set-Cookie2: some_value="value with spaces"; Version=1 -CHECK http://w.y.z/ Cookie: $Version=1; some_value="value with spaces" -COOKIE ASK http://w.y.z/ Set-Cookie2: some_value ="extra space 1"; Version=1 -CHECK http://w.y.z/ Cookie: $Version=1; some_value="extra space 1" -COOKIE ASK http://w.y.z/ Set-Cookie2: some_value= "extra space 2"; Version=1 -CHECK http://w.y.z/ Cookie: $Version=1; some_value="extra space 2" -COOKIE ASK http://a.b.c/ Set-Cookie2: some_value=unquoted; Version=1 -CHECK http://a.b.c/ Cookie: $Version=1; some_value=unquoted -# Note that we parse this different for Netscape-style cookies! -COOKIE ASK http://a.b.c/ Set-Cookie2: some_value="quoted value; and such"; Version=1; -CHECK http://a.b.c/ Cookie: $Version=1; some_value="quoted value; and such" -CLEAR COOKIES -## Check if deleting cookies works #1 -COOKIE ASK http://w.y.z/ Set-Cookie2: some_value="value1"; Version=1; Path="/"; Max-Age=3600 -CHECK http://w.y.z/ Cookie: $Version=1; some_value="value1"; $Path="/" -COOKIE ASK http://w.y.z/ Set-Cookie2: some_value=value1; Version=1; Path="/"; Max-Age=0 -CHECK http://w.y.z/ -## Check if updating cookies works -COOKIE ASK http://w.y.z/ Set-Cookie2: some_value=value2; Version=1; Path="/"; Max-Age=3600 -COOKIE ASK http://w.y.z/ Set-Cookie2: some_value=value3; Version=1; Path="/"; Max-Age=3600 -CHECK http://w.y.z/ Cookie: $Version=1; some_value=value3; $Path="/" -## Check if multiple cookies work -COOKIE ASK http://w.y.z/ Set-Cookie2: some_value2=foobar; Version=1; Path="/"; Max-Age=3600 -CHECK http://w.y.z/ Cookie: $Version=1; some_value2=foobar; $Path="/"; some_value=value3; $Path="/" -COOKIE ASK http://w.y.z/ Set-Cookie2: some_value=; Version=1; Path="/"; Max-Age=0 -CHECK http://w.y.z/ Cookie: $Version=1; some_value2=foobar; $Path="/" -CLEAR COOKIES -## Check if we prepend domain with a dot -COOKIE ASK http://w.y.z/ Set-Cookie2: some_value=value2; Version=1; Path="/"; Domain=.y.z; Max-Age=3600 -COOKIE ASK http://w.y.z/ Set-Cookie2: some_value=value3; Version=1; Path="/"; Domain=y.z.; Max-Age=3600 -CHECK http://w.y.z/ Cookie: $Version=1; some_value=value3; $Path="/"; $Domain=".y.z" -CLEAR COOKIES -## Check if multiple cookies on a single line work -## FIXME -#COOKIE ASK http://w.y.z/ Set-Cookie2: some_value=value3; Version=1; Path="/"; Max-Age=3600, some_value2=foobar; Version=1; Path="/"; Max-Age=3600 -# CHECK http://w.y.z/ Cookie: $Version=1; some_value2=foobar; $Path="/"; some_value=value3; $Path="/" -# COOKIE ASK http://w.y.z/ Set-Cookie2: some_value=; Version=1; Path="/"; Max-Age=0 -# CHECK http://w.y.z/ Cookie: $Version=1; some_value2=foobar; $Path="/" -CLEAR COOKIES -## Check if path restrictions work -COOKIE ASK http://w.y.z/ Set-Cookie2: some_value=value1; Version=1; Path="/Foo"; Max-Age=3600 -CHECK http://w.y.z/ -CHECK http://w.y.z/Foo Cookie: $Version=1; some_value=value1; $Path="/Foo" -CHECK http://w.y.z/Foo/ Cookie: $Version=1; some_value=value1; $Path="/Foo" -CHECK http://w.y.z/Foo/bar Cookie: $Version=1; some_value=value1; $Path="/Foo" -CLEAR COOKIES -## Check if default path works -# RFC2965 says that we should default to the URL path -COOKIE ASK http://w.y.z/Foo/ Set-Cookie2: some_value=value1; Version=1; Max-Age=3600 -CHECK http://w.y.z/ -CHECK http://w.y.z/Foo Cookie: $Version=1; some_value=value1 -CHECK http://w.y.z/FooBar -CHECK http://w.y.z/Foo/ Cookie: $Version=1; some_value=value1 -CHECK http://w.y.z/Foo/bar Cookie: $Version=1; some_value=value1 -CLEAR COOKIES -## Check if cookies are correctly ordered based on path -COOKIE ASK http://w.y.z/ Set-Cookie2: some_value=value1; Version=1; Path="/Foo"; Max-Age=3600 -COOKIE ASK http://w.y.z/ Set-Cookie2: some_value2=value2; Version=1; Path="/Foo/Bar"; Max-Age=3600 -CHECK http://w.y.z/Foo/Bar Cookie: $Version=1; some_value2=value2; $Path="/Foo/Bar"; some_value=value1; $Path="/Foo" -COOKIE ASK http://w.y.z/ Set-Cookie2: some_value3=value3; Version=1; Path="/"; Max-Age=3600 -CHECK http://w.y.z/Foo/Bar Cookie: $Version=1; some_value2=value2; $Path="/Foo/Bar"; some_value=value1; $Path="/Foo"; some_value3=value3; $Path="/" -CLEAR COOKIES -## Check cookies with same name but different paths -COOKIE ASK http://w.y.z/Foo/ Set-Cookie2: some_value=value1; Version=1; Max-Age=3600 -COOKIE ASK http://w.y.z/Bar/ Set-Cookie2: some_value=value2; Version=1; Max-Age=3600 -CHECK http://w.y.z/Foo/Bar Cookie: $Version=1; some_value=value1 -CHECK http://w.y.z/Bar/Foo Cookie: $Version=1; some_value=value2 -COOKIE ASK http://w.y.z/ Set-Cookie2: some_value=value3; Version=1; Max-Age=3600 -CHECK http://w.y.z/Foo/Bar Cookie: $Version=1; some_value=value1; some_value=value3 -## Check secure cookie handling -COOKIE ASK https://secure.y.z/ Set-Cookie2: some_value2=value2; Version=1; Path="/"; Max-Age=3600; Secure -CHECK https://secure.y.z/Foo/bar Cookie: $Version=1; some_value2=value2; $Path="/" -CHECK http://secure.y.z/Foo/bar -CLEAR COOKIES -COOKIE ASK http://secure.y.z/ Set-Cookie2: some_value3=value3; Version=1; Path="/"; Max-Age=3600; Secure -CHECK https://secure.y.z/Foo/bar Cookie: $Version=1; some_value3=value3; $Path="/" -CHECK http://secure.y.z/Foo/bar -CLEAR COOKIES -## Check domain restrictions #1 -COOKIE ASK http://www.acme.com/ Set-Cookie2: some_value=value1; Version=1; Domain=".acme.com"; Max-Age=3600 -CHECK http://www.acme.com/ Cookie: $Version=1; some_value=value1; $Domain=".acme.com" -CHECK http://www.abc.com/ -CHECK http://frop.acme.com/ Cookie: $Version=1; some_value=value1; $Domain=".acme.com" -CLEAR COOKIES -## Check domain restrictions #2 -COOKIE ASK http://novell.com/ Set-Cookie2: some_value=value1; Version=1; Domain=".novell.com"; Max-Age=3600 -CHECK http://novell.com/ Cookie: $Version=1; some_value=value1; $Domain=".novell.com" -CHECK http://www.novell.com/ Cookie: $Version=1; some_value=value1; $Domain=".novell.com" -CLEAR COOKIES -## Check domain restrictions #3 -COOKIE ASK http://novell.com/ Set-Cookie2: some_value=value1; Version=1; Max-Age=3600 -CHECK http://novell.com/ Cookie: $Version=1; some_value=value1 -CHECK http://www.novell.com/ -CLEAR COOKIES -## Check domain restrictions #4 -COOKIE ASK http://novell.com/ Set-Cookie2: some_value=value1; Version=1; Domain=".com"; Max-Age=3600 -# If the specified domain is too broad, we ignore the Domain -# FIXME: RFC2965 says we should ignore the cookie completely -CHECK http://novell.com/ Cookie: $Version=1; some_value=value1 -CHECK http://www.novell.com/ -CHECK http://com/ -CHECK http://sun.com/ -## Check domain restrictions #5 -CLEAR COOKIES -COOKIE ASK http://novell.co.uk/ Set-Cookie2: some_value=value1; Version=1; Domain=".co.uk"; Max-Age=3600 -# If the specified domain is too broad, we default to host only -# FIXME: RFC2965 says we should ignore the cookie completely -CHECK http://novell.co.uk/ Cookie: $Version=1; some_value=value1 -CHECK http://www.novell.co.uk/ -CHECK http://co.uk/ -CHECK http://sun.co.uk/ -COOKIE ASK http://x.y.z.foobar.com/ Set-Cookie2: set_by=x.y.z.foobar.com; Version=1; Domain=".foobar.com"; Max-Age=3600 -CHECK http://x.y.z.foobar.com/ Cookie: $Version=1; set_by=x.y.z.foobar.com; $Domain=".foobar.com" -CHECK http://y.z.foobar.com/ Cookie: $Version=1; set_by=x.y.z.foobar.com; $Domain=".foobar.com" -CHECK http://z.foobar.com/ Cookie: $Version=1; set_by=x.y.z.foobar.com; $Domain=".foobar.com" -CHECK http://www.foobar.com/ Cookie: $Version=1; set_by=x.y.z.foobar.com; $Domain=".foobar.com" -CHECK http://foobar.com/ Cookie: $Version=1; set_by=x.y.z.foobar.com; $Domain=".foobar.com" -CLEAR COOKIES -## Check domain restrictions #6 -COOKIE ASK http://x.y.z.frop.com/ Set-Cookie2: set_by=x.y.z.frop.com; Version=1; Domain=".foobar.com"; Max-Age=3600 -COOKIE ASK http://x.y.z.frop.com/ Set-Cookie2: set_by2=x.y.z.frop.com; Version=1; Domain=".com"; Max-Age=3600 -CHECK http://x.y.z.foobar.com/ -CHECK http://y.z.foobar.com/ -CHECK http://z.foobar.com/ -CHECK http://www.foobar.com/ -CHECK http://foobar.com/ -CLEAR COOKIES -## Check domain restrictions #7 -COOKIE ASK http://frop.com/ Set-Cookie2: set_by=x.y.z.frop.com; Version=1; Domain=".foobar.com"; Max-Age=3600 -COOKIE ASK http://frop.com/ Set-Cookie2: set_by2=x.y.z.frop.com; Version=1; Domain=".com"; Max-Age=3600 -CHECK http://x.y.z.foobar.com/ -CHECK http://y.z.foobar.com/ -CHECK http://z.foobar.com/ -CHECK http://www.foobar.com/ -CHECK http://foobar.com/ diff --git a/kioslave/http/kcookiejar/tests/cookie_saving.test b/kioslave/http/kcookiejar/tests/cookie_saving.test deleted file mode 100644 index cb9f34c42..000000000 --- a/kioslave/http/kcookiejar/tests/cookie_saving.test +++ /dev/null @@ -1,430 +0,0 @@ -## Check setting of cookies -COOKIE ASK http://w.y.z/ Set-Cookie: some_value=value1; Path="/"; expires=%NEXTYEAR% -COOKIE ASK http://a.b.c/ Set-Cookie: some_value=value2; Path="/" -## Check if clearing cookie jar works -CLEAR COOKIES -## Check cookie syntax -COOKIE ASK http://w.y1.z/ Set-Cookie: some_value=value with spaces; expires=%NEXTYEAR% -COOKIE ASK http://a.b1.c/ Set-Cookie: some_value="quoted value"; expires=%NEXTYEAR% -# Without a = sign, the cookie gets interpreted as the value for a cookie with no name -# This is what IE and Netscape does -COOKIE ASK http://a.b1.c/ Set-Cookie: some_value -COOKIE ASK http://a.b1.c/ Set-Cookie: some_other_value; expires=%NEXTYEAR% -# This doesn't work with old-style netscape cookies, it should work with RFC2965 cookies -COOKIE ASK http://a.b2.c/ Set-Cookie: some_value="quoted value; and such"; expires=%NEXTYEAR% -# IE & Netscape does this: -## Check if deleting cookies works -COOKIE ASK http://w.y3.z/ Set-Cookie: some_value=value1; Path="/"; expires=%NEXTYEAR% -COOKIE ASK http://w.y3.z/ Set-Cookie: some_value=value1; Path="/"; expires=%LASTYEAR% -## Check if updating cookies works -COOKIE ASK http://w.y3.z/ Set-Cookie: some_value=value2; Path="/"; expires=%NEXTYEAR% -COOKIE ASK http://w.y3.z/ Set-Cookie: some_value=value3; Path="/"; expires=%NEXTYEAR% -## Check if multiple cookies work -COOKIE ASK http://w.y3.z/ Set-Cookie: some_value2=foobar; Path="/"; expires=%NEXTYEAR% -COOKIE ASK http://w.y3.z/ Set-Cookie: some_value=; Path="/"; expires=%LASTYEAR% -## Check if path restrictions work -COOKIE ASK http://w.y4.z/ Set-Cookie: some_value=value1; Path="/Foo"; expires=%NEXTYEAR% -## Check if default path works -COOKIE ASK http://w.y5.z/Foo/ Set-Cookie: some_value=value1; expires=%NEXTYEAR% -## Check if cookies are correctly ordered based on path -COOKIE ASK http://w.y6.z/ Set-Cookie: some_value=value1; Path="/Foo"; expires=%NEXTYEAR% -COOKIE ASK http://w.y6.z/ Set-Cookie: some_value2=value2; Path="/Foo/Bar"; expires=%NEXTYEAR% -COOKIE ASK http://w.y6.z/ Set-Cookie: some_value3=value3; Path="/"; expires=%NEXTYEAR% -## Check cookies with same name but different paths -COOKIE ASK http://w.y7.z/Foo/ Set-Cookie: some_value=value1; expires=%NEXTYEAR% -COOKIE ASK http://w.y7.z/Bar/ Set-Cookie: some_value=value2; expires=%NEXTYEAR% -COOKIE ASK http://w.y7.z/ Set-Cookie: some_value=value3; expires=%NEXTYEAR% -## Check secure cookie handling -COOKIE ASK https://secure.y7.z/ Set-Cookie: some_value2=value2; Path="/"; expires=%NEXTYEAR%; secure -COOKIE ASK http://secure.y8.z/ Set-Cookie: some_value3=value3; Path="/"; expires=%NEXTYEAR%; secure -## Check domain restrictions #1 -COOKIE ASK http://www.acme9.com/ Set-Cookie: some_value=value1; Domain=".acme9.com"; expires=%NEXTYEAR% -## Check domain restrictions #2 -COOKIE ASK http://novell10.com/ Set-Cookie: some_value=value1; Domain=".novell10.com"; expires=%NEXTYEAR% -COOKIE ASK http://novell11.com/ Set-Cookie: some_value=value1; Domain="novell11.com"; expires=%NEXTYEAR% -## Check domain restrictions #3 -COOKIE ASK http://novell12.com/ Set-Cookie: some_value=value1; expires=%NEXTYEAR% -## Check domain restrictions #4 -COOKIE ASK http://novell13.com/ Set-Cookie: some_value=value1; Domain=".com"; expires=%NEXTYEAR% -# If the specified domain is too broad, we default to host only -## Check domain restrictions #5 -COOKIE ASK http://novell14.co.uk/ Set-Cookie: some_value=value1; Domain=".co.uk"; expires=%NEXTYEAR% -COOKIE ASK http://x.y.z.foobar14.com/ Set-Cookie: set_by=x.y.z.foobar14.com; Domain=".foobar14.com"; expires=%NEXTYEAR% -## Check domain restrictions #6 -COOKIE ASK http://x.y.z.frop15.com/ Set-Cookie: set_by=x.y.z.frop15.com; Domain=".foobar15.com"; expires=%NEXTYEAR% -COOKIE ASK http://x.y.z.frop15.com/ Set-Cookie: set_by2=x.y.z.frop15.com; Domain=".com"; expires=%NEXTYEAR% -## Check domain restrictions #7 -COOKIE ASK http://frop16.com/ Set-Cookie: set_by=x.y.z.frop16.com; Domain=".foobar16.com"; expires=%NEXTYEAR% -COOKIE ASK http://frop16.com/ Set-Cookie: set_by2=x.y.z.frop16.com; Domain=".com"; expires=%NEXTYEAR% -## RFC Cookies -## Check setting of cookies -COOKIE ASK http://w.y20.z/ Set-Cookie2: some_value="value1"; Version=1; Path="/"; Max-Age=3600 -# Although the examples in RFC2965 uses $Version="1" the syntax description suggests that -# such quotes are not allowed, KDE BR59990 reports that the Sun Java server fails to handle -# cookies that use $Version="1" -COOKIE ASK http://a.b20.c/ Set-Cookie2: some_value="value2"; Version=1; Path="/"; Max-Age=3600 -## Check cookie syntax -COOKIE ASK http://w.y21.z/ Set-Cookie2: some_value="value with spaces"; Version=1; Max-Age=3600 -COOKIE ASK http://w.y21.z/ Set-Cookie2: some_value ="extra space 1"; Version=1; Max-Age=3600 -COOKIE ASK http://w.y21.z/ Set-Cookie2: some_value= "extra space 2"; Version=1; Max-Age=3600 -COOKIE ASK http://a.b21.c/ Set-Cookie2: some_value=unquoted; Version=1; Max-Age=3600 -# Note that we parse this different for Netscape-style cookies! -COOKIE ASK http://a.b21.c/ Set-Cookie2: some_value="quoted value; and such"; Version=1; Max-Age=3600 -## Check if deleting cookies works #1 -COOKIE ASK http://w.y22.z/ Set-Cookie2: some_value="value1"; Version=1; Path="/"; Max-Age=3600 -COOKIE ASK http://w.y22.z/ Set-Cookie2: some_value=value1; Version=1; Path="/"; Max-Age=0 -## Check if updating cookies works -COOKIE ASK http://w.y22.z/ Set-Cookie2: some_value=value2; Version=1; Path="/"; Max-Age=3600 -COOKIE ASK http://w.y22.z/ Set-Cookie2: some_value=value3; Version=1; Path="/"; Max-Age=3600 -## Check if multiple cookies work -COOKIE ASK http://w.y22.z/ Set-Cookie2: some_value2=foobar; Version=1; Path="/"; Max-Age=3600 -COOKIE ASK http://w.y22.z/ Set-Cookie2: some_value=; Version=1; Path="/"; Max-Age=0 -## Check if path restrictions work -COOKIE ASK http://w.y23.z/ Set-Cookie2: some_value=value1; Version=1; Path="/Foo"; Max-Age=3600 -## Check if default path works -# RFC2965 says that we should default to the URL path -COOKIE ASK http://w.y24.z/Foo/ Set-Cookie2: some_value=value1; Version=1; Max-Age=3600 -## Check if cookies are correctly ordered based on path -COOKIE ASK http://w.y25.z/ Set-Cookie2: some_value=value1; Version=1; Path="/Foo"; Max-Age=3600 -COOKIE ASK http://w.y25.z/ Set-Cookie2: some_value2=value2; Version=1; Path="/Foo/Bar"; Max-Age=3600 -COOKIE ASK http://w.y25.z/ Set-Cookie2: some_value3=value3; Version=1; Path="/"; Max-Age=3600 -## Check cookies with same name but different paths -COOKIE ASK http://w.y26.z/Foo/ Set-Cookie2: some_value=value1; Version=1; Max-Age=3600 -COOKIE ASK http://w.y26.z/Bar/ Set-Cookie2: some_value=value2; Version=1; Max-Age=3600 -COOKIE ASK http://w.y26.z/ Set-Cookie2: some_value=value3; Version=1; Max-Age=3600 -## Check secure cookie handling -COOKIE ASK https://secure.y26.z/ Set-Cookie2: some_value2=value2; Version=1; Path="/"; Max-Age=3600; Secure -COOKIE ASK http://secure.y27.z/ Set-Cookie2: some_value3=value3; Version=1; Path="/"; Max-Age=3600; Secure -## Check domain restrictions #1 -COOKIE ASK http://www.acme28.com/ Set-Cookie2: some_value=value1; Version=1; Domain=".acme28.com"; Max-Age=3600 -## Check domain restrictions #2 -COOKIE ASK http://novell29.com/ Set-Cookie2: some_value=value1; Version=1; Domain=".novell29.com"; Max-Age=3600 -## Check domain restrictions #3 -COOKIE ASK http://novell30.com/ Set-Cookie2: some_value=value1; Version=1; Max-Age=3600 -## Check domain restrictions #4 -COOKIE ASK http://novell31.com/ Set-Cookie2: some_value=value1; Version=1; Domain=".com"; Max-Age=3600 -# If the specified domain is too broad, we ignore the Domain -# FIXME: RFC2965 says we should ignore the cookie completely -## Check domain restrictions #5 -COOKIE ASK http://novell32.co.uk/ Set-Cookie2: some_value=value1; Version=1; Domain=".co.uk"; Max-Age=3600 -# If the specified domain is too broad, we default to host only -# FIXME: RFC2965 says we should ignore the cookie completely -COOKIE ASK http://x.y.z.foobar33.com/ Set-Cookie2: set_by=x.y.z.foobar.com; Version=1; Domain=".foobar33.com"; Max-Age=3600 -## Check domain restrictions #6 -COOKIE ASK http://x.y.z.frop34.com/ Set-Cookie2: set_by=x.y.z.frop.com; Version=1; Domain=".foobar.com"; Max-Age=3600 -COOKIE ASK http://x.y.z.frop34.com/ Set-Cookie2: set_by2=x.y.z.frop.com; Version=1; Domain=".com"; Max-Age=3600 -## Check domain restrictions #7 -COOKIE ASK http://frop35.com/ Set-Cookie2: set_by=x.y.z.frop.com; Version=1; Domain=".foobar.com"; Max-Age=3600 -COOKIE ASK http://frop35.com/ Set-Cookie2: set_by2=x.y.z.frop.com; Version=1; Domain=".com"; Max-Age=3600 - -## Check results -CHECK http://w.y.z/ -CHECK http://a.b.c/ -CHECK http://w.y1.z/ Cookie: some_value=value with spaces -CHECK http://a.b1.c/ Cookie: some_other_value; some_value="quoted value" -CHECK http://a.b2.c/ Cookie: some_value="quoted value -CHECK http://w.y3.z/ Cookie: some_value2=foobar -CHECK http://w.y4.z/ -CHECK http://w.y4.z/Foo Cookie: some_value=value1 -CHECK http://w.y4.z/Foo/ Cookie: some_value=value1 -CHECK http://w.y4.z/Foo/bar Cookie: some_value=value1 -CHECK http://w.y5.z/ -CHECK http://w.y5.z/Foo Cookie: some_value=value1 -CHECK http://w.y5.z/FooBar -CHECK http://w.y5.z/Foo/ Cookie: some_value=value1 -CHECK http://w.y5.z/Foo/bar Cookie: some_value=value1 -CHECK http://w.y6.z/Foo/Bar Cookie: some_value2=value2; some_value=value1; some_value3=value3 -CHECK http://w.y7.z/Bar/Foo Cookie: some_value=value2; some_value=value3 -CHECK http://w.y7.z/Foo/Bar Cookie: some_value=value1; some_value=value3 -CHECK https://secure.y7.z/Foo/bar Cookie: some_value2=value2 -CHECK http://secure.y7.z/Foo/bar -CHECK https://secure.y8.z/Foo/bar Cookie: some_value3=value3 -CHECK http://secure.y8.z/Foo/bar -CHECK http://www.acme9.com/ Cookie: some_value=value1 -CHECK http://www.abc9.com/ -CHECK http://frop.acme9.com/ Cookie: some_value=value1 -CHECK http://novell10.com/ Cookie: some_value=value1 -CHECK http://www.novell10.com/ Cookie: some_value=value1 -CHECK http://novell11.com/ Cookie: some_value=value1 -CHECK http://www.novell11.com/ Cookie: some_value=value1 -CHECK http://novell12.com/ Cookie: some_value=value1 -CHECK http://www.novell12.com/ -CHECK http://novell13.com/ Cookie: some_value=value1 -CHECK http://www.novell13.com/ -CHECK http://com/ -CHECK http://sun13.com/ -CHECK http://novell14.co.uk/ Cookie: some_value=value1 -CHECK http://www.novell14.co.uk/ -CHECK http://co.uk/ -CHECK http://sun14.co.uk/ -CHECK http://x.y.z.foobar14.com/ Cookie: set_by=x.y.z.foobar14.com -CHECK http://y.z.foobar14.com/ Cookie: set_by=x.y.z.foobar14.com -CHECK http://z.foobar14.com/ Cookie: set_by=x.y.z.foobar14.com -CHECK http://www.foobar14.com/ Cookie: set_by=x.y.z.foobar14.com -CHECK http://foobar14.com/ Cookie: set_by=x.y.z.foobar14.com -CHECK http://x.y.z.foobar15.com/ -CHECK http://y.z.foobar15.com/ -CHECK http://z.foobar15.com/ -CHECK http://www.foobar15.com/ -CHECK http://foobar15.com/ -CHECK http://x.y.z.foobar16.com/ -CHECK http://y.z.foobar16.com/ -CHECK http://z.foobar16.com/ -CHECK http://www.foobar16.com/ -CHECK http://foobar16.com/ -## Check results for RFC cookies -CHECK http://w.y20.z/ Cookie: $Version=1; some_value="value1"; $Path="/" -CHECK http://a.b20.c/ Cookie: $Version=1; some_value="value2"; $Path="/" -CHECK http://w.y21.z/ Cookie: $Version=1; some_value="extra space 2" -CHECK http://a.b21.c/ Cookie: $Version=1; some_value="quoted value; and such" -CHECK http://w.y22.z/ Cookie: $Version=1; some_value2=foobar; $Path="/" -CHECK http://w.y23.z/ -CHECK http://w.y23.z/Foo Cookie: $Version=1; some_value=value1; $Path="/Foo" -CHECK http://w.y23.z/Foo/ Cookie: $Version=1; some_value=value1; $Path="/Foo" -CHECK http://w.y23.z/Foo/bar Cookie: $Version=1; some_value=value1; $Path="/Foo" -CHECK http://w.y24.z/ -CHECK http://w.y24.z/Foo Cookie: $Version=1; some_value=value1 -CHECK http://w.y24.z/FooBar -CHECK http://w.y24.z/Foo/ Cookie: $Version=1; some_value=value1 -CHECK http://w.y24.z/Foo/bar Cookie: $Version=1; some_value=value1 -CHECK http://w.y25.z/Foo/Bar Cookie: $Version=1; some_value2=value2; $Path="/Foo/Bar"; some_value=value1; $Path="/Foo"; some_value3=value3; $Path="/" -CHECK http://w.y26.z/Bar/Foo Cookie: $Version=1; some_value=value2; some_value=value3 -CHECK http://w.y26.z/Foo/Bar Cookie: $Version=1; some_value=value1; some_value=value3 -CHECK https://secure.y26.z/Foo/bar Cookie: $Version=1; some_value2=value2; $Path="/" -CHECK http://secure.y26.z/Foo/bar -CHECK https://secure.y27.z/Foo/bar Cookie: $Version=1; some_value3=value3; $Path="/" -CHECK http://secure.y27.z/Foo/bar -CHECK http://www.acme28.com/ Cookie: $Version=1; some_value=value1; $Domain=".acme28.com" -CHECK http://www.abc28.com/ -CHECK http://frop.acme28.com/ Cookie: $Version=1; some_value=value1; $Domain=".acme28.com" -CHECK http://novell29.com/ Cookie: $Version=1; some_value=value1; $Domain=".novell29.com" -CHECK http://www.novell29.com/ Cookie: $Version=1; some_value=value1; $Domain=".novell29.com" -CHECK http://novell30.com/ Cookie: $Version=1; some_value=value1 -CHECK http://www.novell30.com/ -CHECK http://novell31.com/ Cookie: $Version=1; some_value=value1 -CHECK http://www.novell31.com/ -CHECK http://com/ -CHECK http://sun31.com/ -CHECK http://novell32.co.uk/ Cookie: $Version=1; some_value=value1 -CHECK http://www.novell32.co.uk/ -CHECK http://co.uk/ -CHECK http://sun32.co.uk/ -CHECK http://x.y.z.foobar33.com/ Cookie: $Version=1; set_by=x.y.z.foobar.com; $Domain=".foobar33.com" -CHECK http://y.z.foobar33.com/ Cookie: $Version=1; set_by=x.y.z.foobar.com; $Domain=".foobar33.com" -CHECK http://z.foobar33.com/ Cookie: $Version=1; set_by=x.y.z.foobar.com; $Domain=".foobar33.com" -CHECK http://www.foobar33.com/ Cookie: $Version=1; set_by=x.y.z.foobar.com; $Domain=".foobar33.com" -CHECK http://foobar33.com/ Cookie: $Version=1; set_by=x.y.z.foobar.com; $Domain=".foobar33.com" -CHECK http://x.y.z.foobar.com/ -CHECK http://y.z.foobar.com/ -CHECK http://z.foobar.com/ -CHECK http://www.foobar.com/ -CHECK http://foobar.com/ - - -SAVE -## Check result after saving -CHECK http://w.y.z/ -CHECK http://a.b.c/ -CHECK http://w.y1.z/ Cookie: some_value=value with spaces -CHECK http://a.b1.c/ Cookie: some_other_value; some_value="quoted value" -CHECK http://a.b2.c/ Cookie: some_value="quoted value -CHECK http://w.y3.z/ Cookie: some_value2=foobar -CHECK http://w.y4.z/ -CHECK http://w.y4.z/Foo Cookie: some_value=value1 -CHECK http://w.y4.z/Foo/ Cookie: some_value=value1 -CHECK http://w.y4.z/Foo/bar Cookie: some_value=value1 -CHECK http://w.y5.z/ -CHECK http://w.y5.z/Foo Cookie: some_value=value1 -CHECK http://w.y5.z/FooBar -CHECK http://w.y5.z/Foo/ Cookie: some_value=value1 -CHECK http://w.y5.z/Foo/bar Cookie: some_value=value1 -CHECK http://w.y6.z/Foo/Bar Cookie: some_value2=value2; some_value=value1; some_value3=value3 -CHECK http://w.y7.z/Bar/Foo Cookie: some_value=value2; some_value=value3 -CHECK http://w.y7.z/Foo/Bar Cookie: some_value=value1; some_value=value3 -CHECK https://secure.y7.z/Foo/bar Cookie: some_value2=value2 -CHECK http://secure.y7.z/Foo/bar -CHECK https://secure.y8.z/Foo/bar Cookie: some_value3=value3 -CHECK http://secure.y8.z/Foo/bar -CHECK http://www.acme9.com/ Cookie: some_value=value1 -CHECK http://www.abc9.com/ -CHECK http://frop.acme9.com/ Cookie: some_value=value1 -CHECK http://novell10.com/ Cookie: some_value=value1 -CHECK http://www.novell10.com/ Cookie: some_value=value1 -CHECK http://novell11.com/ Cookie: some_value=value1 -CHECK http://www.novell11.com/ Cookie: some_value=value1 -CHECK http://novell12.com/ Cookie: some_value=value1 -CHECK http://www.novell12.com/ -CHECK http://novell13.com/ Cookie: some_value=value1 -CHECK http://www.novell13.com/ -CHECK http://com/ -CHECK http://sun13.com/ -CHECK http://novell14.co.uk/ Cookie: some_value=value1 -CHECK http://www.novell14.co.uk/ -CHECK http://co.uk/ -CHECK http://sun14.co.uk/ -CHECK http://x.y.z.foobar14.com/ Cookie: set_by=x.y.z.foobar14.com -CHECK http://y.z.foobar14.com/ Cookie: set_by=x.y.z.foobar14.com -CHECK http://z.foobar14.com/ Cookie: set_by=x.y.z.foobar14.com -CHECK http://www.foobar14.com/ Cookie: set_by=x.y.z.foobar14.com -CHECK http://foobar14.com/ Cookie: set_by=x.y.z.foobar14.com -CHECK http://x.y.z.foobar15.com/ -CHECK http://y.z.foobar15.com/ -CHECK http://z.foobar15.com/ -CHECK http://www.foobar15.com/ -CHECK http://foobar15.com/ -CHECK http://x.y.z.foobar16.com/ -CHECK http://y.z.foobar16.com/ -CHECK http://z.foobar16.com/ -CHECK http://www.foobar16.com/ -CHECK http://foobar16.com/ -## Check result for RFC cookies after saving -CHECK http://w.y20.z/ Cookie: $Version=1; some_value="value1"; $Path="/" -CHECK http://a.b20.c/ Cookie: $Version=1; some_value="value2"; $Path="/" -CHECK http://w.y21.z/ Cookie: $Version=1; some_value="extra space 2" -CHECK http://a.b21.c/ Cookie: $Version=1; some_value="quoted value; and such" -CHECK http://w.y22.z/ Cookie: $Version=1; some_value2=foobar; $Path="/" -CHECK http://w.y23.z/ -CHECK http://w.y23.z/Foo Cookie: $Version=1; some_value=value1; $Path="/Foo" -CHECK http://w.y23.z/Foo/ Cookie: $Version=1; some_value=value1; $Path="/Foo" -CHECK http://w.y23.z/Foo/bar Cookie: $Version=1; some_value=value1; $Path="/Foo" -CHECK http://w.y24.z/ -CHECK http://w.y24.z/Foo Cookie: $Version=1; some_value=value1 -CHECK http://w.y24.z/FooBar -CHECK http://w.y24.z/Foo/ Cookie: $Version=1; some_value=value1 -CHECK http://w.y24.z/Foo/bar Cookie: $Version=1; some_value=value1 -CHECK http://w.y25.z/Foo/Bar Cookie: $Version=1; some_value2=value2; $Path="/Foo/Bar"; some_value=value1; $Path="/Foo"; some_value3=value3; $Path="/" -CHECK http://w.y26.z/Bar/Foo Cookie: $Version=1; some_value=value2; some_value=value3 -CHECK http://w.y26.z/Foo/Bar Cookie: $Version=1; some_value=value1; some_value=value3 -CHECK https://secure.y26.z/Foo/bar Cookie: $Version=1; some_value2=value2; $Path="/" -CHECK http://secure.y26.z/Foo/bar -CHECK https://secure.y27.z/Foo/bar Cookie: $Version=1; some_value3=value3; $Path="/" -CHECK http://secure.y27.z/Foo/bar -CHECK http://www.acme28.com/ Cookie: $Version=1; some_value=value1; $Domain=".acme28.com" -CHECK http://www.abc28.com/ -CHECK http://frop.acme28.com/ Cookie: $Version=1; some_value=value1; $Domain=".acme28.com" -CHECK http://novell29.com/ Cookie: $Version=1; some_value=value1; $Domain=".novell29.com" -CHECK http://www.novell29.com/ Cookie: $Version=1; some_value=value1; $Domain=".novell29.com" -CHECK http://novell30.com/ Cookie: $Version=1; some_value=value1 -CHECK http://www.novell30.com/ -CHECK http://novell31.com/ Cookie: $Version=1; some_value=value1 -CHECK http://www.novell31.com/ -CHECK http://com/ -CHECK http://sun31.com/ -CHECK http://novell32.co.uk/ Cookie: $Version=1; some_value=value1 -CHECK http://www.novell32.co.uk/ -CHECK http://co.uk/ -CHECK http://sun32.co.uk/ -CHECK http://x.y.z.foobar33.com/ Cookie: $Version=1; set_by=x.y.z.foobar.com; $Domain=".foobar33.com" -CHECK http://y.z.foobar33.com/ Cookie: $Version=1; set_by=x.y.z.foobar.com; $Domain=".foobar33.com" -CHECK http://z.foobar33.com/ Cookie: $Version=1; set_by=x.y.z.foobar.com; $Domain=".foobar33.com" -CHECK http://www.foobar33.com/ Cookie: $Version=1; set_by=x.y.z.foobar.com; $Domain=".foobar33.com" -CHECK http://foobar33.com/ Cookie: $Version=1; set_by=x.y.z.foobar.com; $Domain=".foobar33.com" -CHECK http://x.y.z.foobar.com/ -CHECK http://y.z.foobar.com/ -CHECK http://z.foobar.com/ -CHECK http://www.foobar.com/ -CHECK http://foobar.com/ - -SAVE -## Check result after saving a second time -CHECK http://w.y.z/ -CHECK http://a.b.c/ -CHECK http://w.y1.z/ Cookie: some_value=value with spaces -CHECK http://a.b1.c/ Cookie: some_other_value; some_value="quoted value" -CHECK http://a.b2.c/ Cookie: some_value="quoted value -CHECK http://w.y3.z/ Cookie: some_value2=foobar -CHECK http://w.y4.z/ -CHECK http://w.y4.z/Foo Cookie: some_value=value1 -CHECK http://w.y4.z/Foo/ Cookie: some_value=value1 -CHECK http://w.y4.z/Foo/bar Cookie: some_value=value1 -CHECK http://w.y5.z/ -CHECK http://w.y5.z/Foo Cookie: some_value=value1 -CHECK http://w.y5.z/FooBar -CHECK http://w.y5.z/Foo/ Cookie: some_value=value1 -CHECK http://w.y5.z/Foo/bar Cookie: some_value=value1 -CHECK http://w.y6.z/Foo/Bar Cookie: some_value2=value2; some_value=value1; some_value3=value3 -CHECK http://w.y7.z/Bar/Foo Cookie: some_value=value2; some_value=value3 -CHECK http://w.y7.z/Foo/Bar Cookie: some_value=value1; some_value=value3 -CHECK https://secure.y7.z/Foo/bar Cookie: some_value2=value2 -CHECK http://secure.y7.z/Foo/bar -CHECK https://secure.y8.z/Foo/bar Cookie: some_value3=value3 -CHECK http://secure.y8.z/Foo/bar -CHECK http://www.acme9.com/ Cookie: some_value=value1 -CHECK http://www.abc9.com/ -CHECK http://frop.acme9.com/ Cookie: some_value=value1 -CHECK http://novell10.com/ Cookie: some_value=value1 -CHECK http://www.novell10.com/ Cookie: some_value=value1 -CHECK http://novell11.com/ Cookie: some_value=value1 -CHECK http://www.novell11.com/ Cookie: some_value=value1 -CHECK http://novell12.com/ Cookie: some_value=value1 -CHECK http://www.novell12.com/ -CHECK http://novell13.com/ Cookie: some_value=value1 -CHECK http://www.novell13.com/ -CHECK http://com/ -CHECK http://sun13.com/ -CHECK http://novell14.co.uk/ Cookie: some_value=value1 -CHECK http://www.novell14.co.uk/ -CHECK http://co.uk/ -CHECK http://sun14.co.uk/ -CHECK http://x.y.z.foobar14.com/ Cookie: set_by=x.y.z.foobar14.com -CHECK http://y.z.foobar14.com/ Cookie: set_by=x.y.z.foobar14.com -CHECK http://z.foobar14.com/ Cookie: set_by=x.y.z.foobar14.com -CHECK http://www.foobar14.com/ Cookie: set_by=x.y.z.foobar14.com -CHECK http://foobar14.com/ Cookie: set_by=x.y.z.foobar14.com -CHECK http://x.y.z.foobar15.com/ -CHECK http://y.z.foobar15.com/ -CHECK http://z.foobar15.com/ -CHECK http://www.foobar15.com/ -CHECK http://foobar15.com/ -CHECK http://x.y.z.foobar16.com/ -CHECK http://y.z.foobar16.com/ -CHECK http://z.foobar16.com/ -CHECK http://www.foobar16.com/ -CHECK http://foobar16.com/ -## Check result for rfc cookies after saving a second time -CHECK http://w.y20.z/ Cookie: $Version=1; some_value="value1"; $Path="/" -CHECK http://a.b20.c/ Cookie: $Version=1; some_value="value2"; $Path="/" -CHECK http://w.y21.z/ Cookie: $Version=1; some_value="extra space 2" -CHECK http://a.b21.c/ Cookie: $Version=1; some_value="quoted value; and such" -CHECK http://w.y22.z/ Cookie: $Version=1; some_value2=foobar; $Path="/" -CHECK http://w.y23.z/ -CHECK http://w.y23.z/Foo Cookie: $Version=1; some_value=value1; $Path="/Foo" -CHECK http://w.y23.z/Foo/ Cookie: $Version=1; some_value=value1; $Path="/Foo" -CHECK http://w.y23.z/Foo/bar Cookie: $Version=1; some_value=value1; $Path="/Foo" -CHECK http://w.y24.z/ -CHECK http://w.y24.z/Foo Cookie: $Version=1; some_value=value1 -CHECK http://w.y24.z/FooBar -CHECK http://w.y24.z/Foo/ Cookie: $Version=1; some_value=value1 -CHECK http://w.y24.z/Foo/bar Cookie: $Version=1; some_value=value1 -CHECK http://w.y25.z/Foo/Bar Cookie: $Version=1; some_value2=value2; $Path="/Foo/Bar"; some_value=value1; $Path="/Foo"; some_value3=value3; $Path="/" -CHECK http://w.y26.z/Bar/Foo Cookie: $Version=1; some_value=value2; some_value=value3 -CHECK http://w.y26.z/Foo/Bar Cookie: $Version=1; some_value=value1; some_value=value3 -CHECK https://secure.y26.z/Foo/bar Cookie: $Version=1; some_value2=value2; $Path="/" -CHECK http://secure.y26.z/Foo/bar -CHECK https://secure.y27.z/Foo/bar Cookie: $Version=1; some_value3=value3; $Path="/" -CHECK http://secure.y27.z/Foo/bar -CHECK http://www.acme28.com/ Cookie: $Version=1; some_value=value1; $Domain=".acme28.com" -CHECK http://www.abc28.com/ -CHECK http://frop.acme28.com/ Cookie: $Version=1; some_value=value1; $Domain=".acme28.com" -CHECK http://novell29.com/ Cookie: $Version=1; some_value=value1; $Domain=".novell29.com" -CHECK http://www.novell29.com/ Cookie: $Version=1; some_value=value1; $Domain=".novell29.com" -CHECK http://novell30.com/ Cookie: $Version=1; some_value=value1 -CHECK http://www.novell30.com/ -CHECK http://novell31.com/ Cookie: $Version=1; some_value=value1 -CHECK http://www.novell31.com/ -CHECK http://com/ -CHECK http://sun31.com/ -CHECK http://novell32.co.uk/ Cookie: $Version=1; some_value=value1 -CHECK http://www.novell32.co.uk/ -CHECK http://co.uk/ -CHECK http://sun32.co.uk/ -CHECK http://x.y.z.foobar33.com/ Cookie: $Version=1; set_by=x.y.z.foobar.com; $Domain=".foobar33.com" -CHECK http://y.z.foobar33.com/ Cookie: $Version=1; set_by=x.y.z.foobar.com; $Domain=".foobar33.com" -CHECK http://z.foobar33.com/ Cookie: $Version=1; set_by=x.y.z.foobar.com; $Domain=".foobar33.com" -CHECK http://www.foobar33.com/ Cookie: $Version=1; set_by=x.y.z.foobar.com; $Domain=".foobar33.com" -CHECK http://foobar33.com/ Cookie: $Version=1; set_by=x.y.z.foobar.com; $Domain=".foobar33.com" -CHECK http://x.y.z.foobar.com/ -CHECK http://y.z.foobar.com/ -CHECK http://z.foobar.com/ -CHECK http://www.foobar.com/ -CHECK http://foobar.com/ diff --git a/kioslave/http/kcookiejar/tests/cookie_settings.test b/kioslave/http/kcookiejar/tests/cookie_settings.test deleted file mode 100644 index 7fc1a03a7..000000000 --- a/kioslave/http/kcookiejar/tests/cookie_settings.test +++ /dev/null @@ -1,116 +0,0 @@ -## Check CookieGlobalAdvice setting -COOKIE ASK http://a.b.c/ Set-Cookie: some_value=value1; Path="/"; expires=%NEXTYEAR% -COOKIE ASK http://a.b.c/ Set-Cookie: some_value=value2; Path="/" -CONFIG CookieGlobalAdvice Reject -COOKIE REJECT http://a.b.c/ Set-Cookie: some_value=value3; Path="/"; expires=%NEXTYEAR% -COOKIE REJECT http://a.b.c/ Set-Cookie: some_value=value4; Path="/" -CONFIG CookieGlobalAdvice Accept -COOKIE ACCEPT http://a.b.c/ Set-Cookie: some_value=value5; Path="/"; expires=%NEXTYEAR% -COOKIE ACCEPT http://a.b.c/ Set-Cookie: some_value=value6; Path="/" -CONFIG CookieGlobalAdvice Ask -COOKIE ASK http://a.b.c/ Set-Cookie: some_value=value7; Path="/"; expires=%NEXTYEAR% -COOKIE ASK http://a.b.c/ Set-Cookie: some_value=value8; Path="/" -CONFIG AcceptSessionCookies true -COOKIE ASK http://a.b.c/ Set-Cookie: some_value=value9; Path="/"; expires=%NEXTYEAR% -COOKIE ASK http://a.b.c/ Set-Cookie2: some_value=value10; Version=1; Path="/"; max-age="600" -COOKIE ACCEPT http://a.b.c/ Set-Cookie: some_value=value11; Path="/" -COOKIE ACCEPT http://a.b.c/ Set-Cookie2: some_value=value12; Version=1; Path="/" -# FIXME: Shouldn't this be considered a session cookie? -# COOKIE ACCEPT http://a.b.c/ Set-Cookie2: some_value=value10; Version=1; Path="/"; max-age="0" -# COOKIE ACCEPT http://a.b.c/ Set-Cookie: some_value=value9; Path="/"; expires=%LASTYEAR% -# FIXME: The 'Discard' attribute makes the cookie a session cookie -# COOKIE ACCEPT http://a.b.c/ Set-Cookie2: some_value=value10; Version=1; Path="/"; max-age="600" -## Treat all cookies as session cookies -CONFIG IgnoreExpirationDate true -COOKIE ACCEPT http://a.b.c/ Set-Cookie: some_value=value9; Path="/"; expires=%NEXTYEAR% -COOKIE ACCEPT http://a.b.c/ Set-Cookie2: some_value=value10; Version=1; Path="/"; max-age="600" -COOKIE ACCEPT http://a.b.c/ Set-Cookie: some_value=value11; Path="/" -COOKIE ACCEPT http://a.b.c/ Set-Cookie2: some_value=value12; Version=1; Path="/" -## Check host-based domain policies -CONFIG IgnoreExpirationDate false -CONFIG AcceptSessionCookies false -CONFIG CookieDomainAdvice a.b.c:Reject -COOKIE REJECT http://a.b.c/ Set-Cookie: some_value=value9; Path="/"; expires=%NEXTYEAR% -COOKIE REJECT http://a.b.c/ Set-Cookie2: some_value=value10; Version=1; Path="/"; max-age="600" -COOKIE REJECT http://a.b.c/ Set-Cookie: some_value=value11; Path="/" -COOKIE REJECT http://a.b.c/ Set-Cookie2: some_value=value12; Version=1; Path="/" -COOKIE ASK http://d.b.c/ Set-Cookie: some_value=value9; Path="/"; expires=%NEXTYEAR% -COOKIE ASK http://d.b.c/ Set-Cookie2: some_value=value10; Version=1; Path="/"; max-age="600" -COOKIE ASK http://d.b.c/ Set-Cookie: some_value=value11; Path="/" -COOKIE ASK http://d.b.c/ Set-Cookie2: some_value=value12; Version=1; Path="/" -## Check resetting of domain policies -CONFIG CookieDomainAdvice -COOKIE ASK http://a.b.c/ Set-Cookie: some_value=value9; Path="/"; expires=%NEXTYEAR% -COOKIE ASK http://a.b.c/ Set-Cookie2: some_value=value10; Version=1; Path="/"; max-age="600" -COOKIE ASK http://a.b.c/ Set-Cookie: some_value=value11; Path="/" -COOKIE ASK http://a.b.c/ Set-Cookie2: some_value=value12; Version=1; Path="/" -COOKIE ASK http://d.b.c/ Set-Cookie: some_value=value9; Path="/"; expires=%NEXTYEAR% -COOKIE ASK http://d.b.c/ Set-Cookie2: some_value=value10; Version=1; Path="/"; max-age="600" -COOKIE ASK http://d.b.c/ Set-Cookie: some_value=value11; Path="/" -COOKIE ASK http://d.b.c/ Set-Cookie2: some_value=value12; Version=1; Path="/" -## Check domain policies -CONFIG CookieDomainAdvice .b.c:Reject -COOKIE REJECT http://a.b.c/ Set-Cookie: some_value=value9; Path="/"; expires=%NEXTYEAR% -COOKIE REJECT http://a.b.c/ Set-Cookie2: some_value=value10; Version=1; Path="/"; max-age="600" -COOKIE REJECT http://a.b.c/ Set-Cookie: some_value=value11; Path="/" -COOKIE REJECT http://a.b.c/ Set-Cookie2: some_value=value12; Version=1; Path="/" -COOKIE REJECT http://d.b.c/ Set-Cookie: some_value=value9; Path="/"; expires=%NEXTYEAR% -COOKIE REJECT http://d.b.c/ Set-Cookie2: some_value=value10; Version=1; Path="/"; max-age="600" -COOKIE REJECT http://d.b.c/ Set-Cookie: some_value=value11; Path="/" -COOKIE REJECT http://d.b.c/ Set-Cookie2: some_value=value12; Version=1; Path="/" -## Check overriding of domain policies #1 -CONFIG CookieDomainAdvice .b.c:Reject,a.b.c:Accept -COOKIE ACCEPT http://a.b.c/ Set-Cookie: some_value=value9; Path="/"; expires=%NEXTYEAR% -COOKIE ACCEPT http://a.b.c/ Set-Cookie2: some_value=value10; Version=1; Path="/"; max-age="600" -COOKIE ACCEPT http://a.b.c/ Set-Cookie: some_value=value11; Path="/" -COOKIE ACCEPT http://a.b.c/ Set-Cookie2: some_value=value12; Version=1; Path="/" -COOKIE REJECT http://d.b.c/ Set-Cookie: some_value=value9; Path="/"; expires=%NEXTYEAR% -COOKIE REJECT http://d.b.c/ Set-Cookie2: some_value=value10; Version=1; Path="/"; max-age="600" -COOKIE REJECT http://d.b.c/ Set-Cookie: some_value=value11; Path="/" -COOKIE REJECT http://d.b.c/ Set-Cookie2: some_value=value12; Version=1; Path="/" -## Check overriding of domain policies #2 -CONFIG CookieDomainAdvice a.b.c:Reject,.b.c:Accept -COOKIE REJECT http://a.b.c/ Set-Cookie: some_value=value9; Path="/"; expires=%NEXTYEAR% -COOKIE REJECT http://a.b.c/ Set-Cookie2: some_value=value10; Version=1; Path="/"; max-age="600" -COOKIE REJECT http://a.b.c/ Set-Cookie: some_value=value11; Path="/" -COOKIE REJECT http://a.b.c/ Set-Cookie2: some_value=value12; Version=1; Path="/" -COOKIE ACCEPT http://d.b.c/ Set-Cookie: some_value=value9; Path="/"; expires=%NEXTYEAR% -COOKIE ACCEPT http://d.b.c/ Set-Cookie2: some_value=value10; Version=1; Path="/"; max-age="600" -COOKIE ACCEPT http://d.b.c/ Set-Cookie: some_value=value11; Path="/" -COOKIE ACCEPT http://d.b.c/ Set-Cookie2: some_value=value12; Version=1; Path="/" -## Check resetting of domain policies -CONFIG CookieDomainAdvice -COOKIE ASK http://a.b.c/ Set-Cookie: some_value=value9; Path="/"; expires=%NEXTYEAR% -COOKIE ASK http://a.b.c/ Set-Cookie2: some_value=value10; Version=1; Path="/"; max-age="600" -COOKIE ASK http://a.b.c/ Set-Cookie: some_value=value11; Path="/" -COOKIE ASK http://a.b.c/ Set-Cookie2: some_value=value12; Version=1; Path="/" -COOKIE ASK http://d.b.c/ Set-Cookie: some_value=value9; Path="/"; expires=%NEXTYEAR% -COOKIE ASK http://d.b.c/ Set-Cookie2: some_value=value10; Version=1; Path="/"; max-age="600" -COOKIE ASK http://d.b.c/ Set-Cookie: some_value=value11; Path="/" -COOKIE ASK http://d.b.c/ Set-Cookie2: some_value=value12; Version=1; Path="/" -## Check overriding of domain policies #3 -CONFIG CookieDomainAdvice b.c:Reject,.b.c:Accept -COOKIE REJECT http://b.c/ Set-Cookie: some_value=value9; Path="/"; expires=%NEXTYEAR% -COOKIE REJECT http://b.c/ Set-Cookie2: some_value=value10; Version=1; Path="/"; max-age="600" -COOKIE REJECT http://b.c/ Set-Cookie: some_value=value11; Path="/" -COOKIE REJECT http://b.c/ Set-Cookie2: some_value=value12; Version=1; Path="/" -COOKIE ACCEPT http://a.b.c/ Set-Cookie: some_value=value9; Path="/"; expires=%NEXTYEAR% -COOKIE ACCEPT http://a.b.c/ Set-Cookie2: some_value=value10; Version=1; Path="/"; max-age="600" -COOKIE ACCEPT http://a.b.c/ Set-Cookie: some_value=value11; Path="/" -COOKIE ACCEPT http://a.b.c/ Set-Cookie2: some_value=value12; Version=1; Path="/" -## Check overriding of domain policies #4 -CONFIG CookieDomainAdvice .a.b.c.d:Reject,.b.c.d:Accept,.c.d:Ask -COOKIE REJECT http://www.a.b.c.d/ Set-Cookie: some_value=value9; Path="/"; expires=%NEXTYEAR% -COOKIE ACCEPT http://www.b.c.d/ Set-Cookie: some_value=value9; Path="/"; expires=%NEXTYEAR% -COOKIE ASK http://www.c.d/ Set-Cookie: some_value=value9; Path="/"; expires=%NEXTYEAR% -## Check interaction with session policy -CONFIG AcceptSessionCookies true -CONFIG CookieDomainAdvice .b.c:Reject -COOKIE REJECT http://a.b.c/ Set-Cookie: some_value=value9; Path="/"; expires=%NEXTYEAR% -COOKIE REJECT http://a.b.c/ Set-Cookie2: some_value=value10; Version=1; Path="/"; max-age="600" -COOKIE ACCEPT http://a.b.c/ Set-Cookie: some_value=value11; Path="/" -COOKIE ACCEPT http://a.b.c/ Set-Cookie2: some_value=value12; Version=1; Path="/" -COOKIE REJECT http://d.b.c/ Set-Cookie: some_value=value9; Path="/"; expires=%NEXTYEAR% -COOKIE REJECT http://d.b.c/ Set-Cookie2: some_value=value10; Version=1; Path="/"; max-age="600" -COOKIE ACCEPT http://d.b.c/ Set-Cookie: some_value=value11; Path="/" -COOKIE ACCEPT http://d.b.c/ Set-Cookie2: some_value=value12; Version=1; Path="/" diff --git a/kioslave/http/kcookiejar/tests/kcookiejartest.cpp b/kioslave/http/kcookiejar/tests/kcookiejartest.cpp deleted file mode 100644 index 236e2406b..000000000 --- a/kioslave/http/kcookiejar/tests/kcookiejartest.cpp +++ /dev/null @@ -1,270 +0,0 @@ -/* - This file is part of KDE - - Copyright (C) 2004 Waldo Bastian (bastian@kde.org) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - version 2 as published by the Free Software Foundation. - - This software is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this library; see the file COPYING. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -#include <stdio.h> -#include <stdlib.h> - -#include <tqdatetime.h> -#include <tqstring.h> - -#include <kapplication.h> -#include <kaboutdata.h> -#include <kcmdlineargs.h> -#include <kstandarddirs.h> - -#include "../kcookiejar.cpp" - -static const char *description = "KCookiejar regression test"; - -static KCookieJar *jar; -static TQCString *lastYear; -static TQCString *nextYear; -static TDEConfig *config = 0; - - -static KCmdLineOptions options[] = -{ - { "+testfile", "Regression test to run", 0}, - KCmdLineLastOption -}; - -static void FAIL(const TQString &msg) -{ - tqWarning("%s", msg.local8Bit().data()); - exit(1); -} - -static void popArg(TQCString &command, TQCString & line) -{ - int i = line.find(' '); - if (i != -1) - { - command = line.left(i); - line = line.mid(i+1); - } - else - { - command = line; - line = 0; - } -} - - -static void popArg(TQString &command, TQCString & line) -{ - int i = line.find(' '); - if (i != -1) - { - command = TQString::fromLatin1(line.left(i)); - line = line.mid(i+1); - } - else - { - command = TQString::fromLatin1(line); - line = 0; - } -} - -static void clearConfig() -{ - delete config; - TQString file = locateLocal("config", "kcookiejar-testconfig"); - TQFile::remove(file); - config = new TDEConfig(file); - config->setGroup("Cookie Policy"); - config->writeEntry("RejectCrossDomainCookies", false); - config->writeEntry("AcceptSessionCookies", false); - config->writeEntry("IgnoreExpirationDate", false); - config->writeEntry("CookieGlobalAdvice", "Ask"); - jar->loadConfig(config, false); -} - -static void clearCookies() -{ - jar->eatAllCookies(); -} - -static void saveCookies() -{ - TQString file = locateLocal("config", "kcookiejar-testcookies"); - TQFile::remove(file); - jar->saveCookies(file); - delete jar; - jar = new KCookieJar(); - clearConfig(); - jar->loadCookies(file); -} - -static void processCookie(TQCString &line) -{ - TQString policy; - popArg(policy, line); - KCookieAdvice expectedAdvice = KCookieJar::strToAdvice(policy); - if (expectedAdvice == KCookieDunno) - FAIL(TQString("Unknown accept policy '%1'").arg(policy)); - - TQString urlStr; - popArg(urlStr, line); - KURL url(urlStr); - if (!url.isValid()) - FAIL(TQString("Invalid URL '%1'").arg(urlStr)); - if (url.isEmpty()) - FAIL(TQString("Missing URL")); - - line.replace("%LASTYEAR%", *lastYear); - line.replace("%NEXTYEAR%", *nextYear); - - KHttpCookieList list = jar->makeCookies(urlStr, line, 0); - - if (list.isEmpty()) - FAIL(TQString("Failed to make cookies from: '%1'").arg(line)); - - for(KHttpCookie *cookie = list.first(); - cookie; cookie = list.next()) - { - KCookieAdvice cookieAdvice = jar->cookieAdvice(cookie); - if (cookieAdvice != expectedAdvice) - FAIL(urlStr+TQString("\n'%2'\nGot advice '%3' expected '%4'").arg(line) - .arg(KCookieJar::adviceToStr(cookieAdvice)) - .arg(KCookieJar::adviceToStr(expectedAdvice))); - jar->addCookie(cookie); - } -} - -static void processCheck(TQCString &line) -{ - TQString urlStr; - popArg(urlStr, line); - KURL url(urlStr); - if (!url.isValid()) - FAIL(TQString("Invalid URL '%1'").arg(urlStr)); - if (url.isEmpty()) - FAIL(TQString("Missing URL")); - - TQString expectedCookies = TQString::fromLatin1(line); - - TQString cookies = jar->findCookies(urlStr, false, 0, 0).stripWhiteSpace(); - if (cookies != expectedCookies) - FAIL(urlStr+TQString("\nGot '%1' expected '%2'") - .arg(cookies, expectedCookies)); -} - -static void processClear(TQCString &line) -{ - if (line == "CONFIG") - clearConfig(); - else if (line == "COOKIES") - clearCookies(); - else - FAIL(TQString("Unknown command 'CLEAR %1'").arg(line)); -} - -static void processConfig(TQCString &line) -{ - TQCString key; - popArg(key, line); - - if (key.isEmpty()) - FAIL(TQString("Missing Key")); - - config->setGroup("Cookie Policy"); - config->writeEntry(key.data(), line.data()); - jar->loadConfig(config, false); -} - -static void processLine(TQCString line) -{ - if (line.isEmpty()) - return; - - if (line[0] == '#') - { - if (line[1] == '#') - tqWarning("%s", line.data()); - return; - } - - TQCString command; - popArg(command, line); - if (command.isEmpty()) - return; - - if (command == "COOKIE") - processCookie(line); - else if (command == "CHECK") - processCheck(line); - else if (command == "CLEAR") - processClear(line); - else if (command == "CONFIG") - processConfig(line); - else if (command == "SAVE") - saveCookies(); - else - FAIL(TQString("Unknown command '%1'").arg(command)); -} - -static void runRegression(const TQString &filename) -{ - FILE *file = fopen(filename.local8Bit(), "r"); - if (!file) - FAIL(TQString("Can't open '%1'").arg(filename)); - - char buf[4096]; - while (fgets(buf, sizeof(buf), file)) - { - int l = strlen(buf); - if (l) - { - l--; - buf[l] = 0; - } - processLine(buf); - } - tqWarning("%s OK", filename.local8Bit().data()); -} - -int main(int argc, char *argv[]) -{ - TQString arg1; - TQCString arg2; - TQString result; - - lastYear = new TQCString(TQString("Fri, 04-May-%1 01:00:00 GMT").arg(TQDate::currentDate().year()-1).utf8()); - nextYear = new TQCString(TQString(" expires=Fri, 04-May-%1 01:00:00 GMT").arg(TQDate::currentDate().year()+1).utf8()); - - TDEAboutData about("kcookietest", "kcookietest", "1.0", description, TDEAboutData::License_GPL, "(C) 2004 Waldo Bastian"); - TDECmdLineArgs::init( argc, argv, &about); - - TDECmdLineArgs::addCmdLineOptions( options ); - - TDEInstance a("kcookietest"); - - TDECmdLineArgs *args = TDECmdLineArgs::parsedArgs(); - if (args->count() != 1) - TDECmdLineArgs::usage(); - - jar = new KCookieJar; - - clearConfig(); - - TQString file = args->url(0).path(); - runRegression(file); - return 0; -} diff --git a/kioslave/http/rfc2518.txt b/kioslave/http/rfc2518.txt deleted file mode 100644 index 34d2e942a..000000000 --- a/kioslave/http/rfc2518.txt +++ /dev/null @@ -1 +0,0 @@ -http://www.ietf.org/rfc/rfc2518.txt diff --git a/kioslave/http/rfc2616.txt b/kioslave/http/rfc2616.txt deleted file mode 100644 index 7be662a97..000000000 --- a/kioslave/http/rfc2616.txt +++ /dev/null @@ -1 +0,0 @@ -http://www.ietf.org/rfc/rfc2616.txt diff --git a/kioslave/http/rfc2617.txt b/kioslave/http/rfc2617.txt deleted file mode 100644 index da74cc63a..000000000 --- a/kioslave/http/rfc2617.txt +++ /dev/null @@ -1 +0,0 @@ -http://www.ietf.org/rfc/rfc2617.txt diff --git a/kioslave/http/rfc2817.txt b/kioslave/http/rfc2817.txt deleted file mode 100644 index a29dfc44b..000000000 --- a/kioslave/http/rfc2817.txt +++ /dev/null @@ -1 +0,0 @@ -http://www.ietf.org/rfc/rfc2817.txt diff --git a/kioslave/http/rfc2818.txt b/kioslave/http/rfc2818.txt deleted file mode 100644 index fff91b1a9..000000000 --- a/kioslave/http/rfc2818.txt +++ /dev/null @@ -1 +0,0 @@ -http://www.ietf.org/rfc/rfc2818.txt diff --git a/kioslave/http/rfc3229.txt b/kioslave/http/rfc3229.txt deleted file mode 100644 index 54a19b685..000000000 --- a/kioslave/http/rfc3229.txt +++ /dev/null @@ -1 +0,0 @@ -http://www.ietf.org/rfc/rfc3229.txt diff --git a/kioslave/http/rfc3253.txt b/kioslave/http/rfc3253.txt deleted file mode 100644 index 9968eea02..000000000 --- a/kioslave/http/rfc3253.txt +++ /dev/null @@ -1 +0,0 @@ -http://www.ietf.org/rfc/rfc3253.txt diff --git a/kioslave/http/shoutcast-icecast.txt b/kioslave/http/shoutcast-icecast.txt deleted file mode 100644 index f7bdcf1e7..000000000 --- a/kioslave/http/shoutcast-icecast.txt +++ /dev/null @@ -1,605 +0,0 @@ - -Audio and Apache HTTPD -ApacheCon 2001 -Santa Clara, US - -April 6th, 2001 - -Sander van Zoest <sander@vanZoest.com> -Covalent Technologies, Inc. -<http://www.covalent.net/> - -Latest version can be found at: - <http://www.vanZoest.com/sander/apachecon/2001/> - -Introduction: - -About this paper: - -Contents: - - 1. Why serve Audio on the Net? - - This is almost like asking, why are you reading this? it might be - because of the excitement caused by the new media that has recently - crazed upon the internet. People are looking to bring their lifes onto - the net, one of the things that brings that closer to a reality is the - ability to hear live broadcasts of the worlds news, favorite sport; - hear music and to teleconference with others. Sometimes it is simply - to enhance the mood to a web site or to provide audio feedback of - actions performed by the visitor of the web site. - - 2. What makes delivering audio so different? - - The biggest reason to what makes audio different then traditional - web media such as graphics, text and HTML is the fact that timing - is very important. This caused by the significant increase in size - of the media and the different quality levels that exist. - - There really are two kinds of goals behind audio streams. - In one case there is a need for immediate response the moment - playback is requested and this can sacrifice quality. While - in the other case quality and a non-interrupted stream are much - more important. - - This sort of timing is not really required of any other media, - with the exception of video. In the case of HTML and images the - files sizes are usually a lot smaller which causes the objects - to load much quicker and usually are not very useful without - having the entire file. In audio the middle of a stream can have - useful information and still set a particular mood. - - 3. Different ways of delivery Audio on the Net. - Embedding audio in your Web Page - - This used to be a lot more common in the past. Just like embedding - an image in a web page, it is possible to add a sound clip or score - to the web page. - - The linked in audio files are usually short and of low quality to - avoid a long delay for downloading the rest of the web page and the - audio format needs to be supported by the browser natively or with - a browser plug-in to avoid annoying the visitor. - - This can be accomplished using the HTML 4.0 [HTML4] object element which - works similar to how to specify an applet with the object element. - In the past this could also be accomplished using the embed and bgsound - browser specific additions to HTML. - - example: - <object type="audio/x-midi" data="../media/sound.mid" width="200" height="26"> - <param name="src" value="../media/sound.mid"> - <param name="autostart" value="true"> - <param name="controls" value="ControlPanel"> - </object> - - Each param element is specific to each browser. Please check with each - browser for specific information in regards to what param elements are - available. - - In this method of delivering audio the audio file is served up via the - web server. When using an Apache HTTPD server make sure that the appropriate - mime type is configured for the audio file and that the audio file is - named and referenced by the appropriate extension. - - Although the current HTML 4.01 [HTML4] says to use the object element - many browsers out on the market today still look for the embed element. - Below find a little snipbit that will work work in many browsers. - - <object type="audio/x-midi" data="../media/sound.mid" width="200" height="26"> - <param name="src" value="../media/sound.mid"> - <param name="autostart" value="true"> - <param name="controls" value="ControlPanel"> - - <embed type="audio/x-midi" src="../media/sound.mid" - width="200" height="26" autoplay="true" controls="ControlPanel"> - <noembed>Your browser does not support embedded WAV files.</noembed> - </object> - - With the increasing installation base of the Flash browser plug-in by - Macromedia most developers that are looking to provide this kind of - functionality to a web page are creating flash elements that have their - own way of adding audio that is discussed in Flash specific documents. - - Downloading via HTTP - - Using this method the visitor to the website will have to download the - entire audio file and save it to the hard drive before it can be - listened to. (1) This is very popular with people that want to listen - to high quality streams of audio and have a below ISDN connection to - the internet. In some cases where the demand for a stream is high or - the internet is congested downloading the content even for high bandwidth - users can be affective and useful. - - One of the advantages of downloading audio to the local computer hard - drive is that it can be played back (once downloaded) any time as long - as the audio file is accessable from the computer. - - There are a lot of sites on the internet that provide this functionality - for music and other audio files. It is also one of the easiest ways to - delivery high quality audio to visitors. - - (1) Microsoft Windows Media Player in conjunction with the Microsoft - Internet Explorer Browser will automaticly start playing the - audio stream after a sufficient amount of the file has been - downloaded. This can be accomplished because of the tight - integration of the Browser and Media Player. With most audio players - you can listen to a file being downloaded, but you will have to - envoke the action manually. - - . On-Demand streaming via HTTP - - The real difference between downloading and on-demand streaming is - that in on-demand streaming the audio starts playing before the entire - audio file has been downloaded. This is accomplished by a hand of off - the browser to the audio player via an intermediate file format that - has been configured by the browser to be handled by the audio player. - - Look in a further section entitled "Linking to Audio via Apache HTTPD" - below for more information about the different intermediate file formats. - - This type of streaming is very popular among the open source crowd and - is the most widely implemented using the MP3 file format. Apache, - Shoutcast [SHOUTCAST] and Icecast [ICECAST] are the most common - software components used to provide on-demand streaming via HTTP. Both - Icecast and Shoutcast are not fully HTTP compliant, but Icecast is - becoming closer. For more information about the Shoutcast and Icecast - differences see the section below. - - Sites like Live365.com and MP3.com are huge sites that rely on this - method of delivery of audio. - - . On-Demand Streaming via RTSP/RTP - - RTSP/RTP is a new set of streaming protocols that is getting more - backing and becoming more popular by the second. The specification - was developed by the Internet Engineering Task Force Working Groups - AVT [IETFAVT] and MMUSIC [IETFMMUSIC]. RTP the Realtime Transfer - Protocol has been around longer then RTSP and originally came out - of the work towards a better teleconferencing, mbone, type system. - RTSP is the Real-Time Streaming Protocol that is used as a control - protocol and acts similarily to HTTP except that it maintains state - and is bi-directional. - - Currently the latest Real Networks Streaming Servers support RTSP - and RTP and Real Networks own proprietary transfer protocol RDT. - Apple's Darwin Streaming server is also RTSP/RTP compliant. - - The RTSP/RTP protocol suite is very powerful and flexable in regards - to your streaming needs. It has the ability to suport "server-push" - style stream redirects and has the ability to throttle streams to - ensure the stream can sustain the limited bandwidth over the network. - - For On-Demand streams the RTP protocol would usually stream over - TCP and have a second TCP connection open for RTSP. Because of the - rich features provided by the protocol suite, it is not very well - suited to allow people to download the stream and therefore the - download via HTTP method might still be preferred by some. - - . Live Broadcast Streaming via RTSP/RTP - - In the case of a live broadcast streaming RTSP/RTP shines. RTP allowing - for UDP datagrams to be transmitted to clients allows for fast immediate - delivery of content with the sacrifice of reliability. The RTP stream - can be send over IP Multicast to minimize bandwidth on the network. - - Many Content Delivery Networks (CDNs) are starting to provide support for - RTSP/RTP proxies that should provide a better quality streaming environment - on the internet. - - Much work is also being done in the RTP space to provide transfers over - telecommunication networks such as cellular phones. Although not directly - related, per se, it does provide a positive feeling knowing that all the - audio related transfer groups seem to be working towards a common standard - such as RTP. - - . On-Demand or Live Broadcast streaming via MMS. - - This is the Microsoft Windows Media Technologies Streaming protocol. It - is only supported by Microsoft Windows Media Player and currently only - works on Microsoft Windows. - - 5. Configuring Mime Types - - One of the most hardest things in serving audio has been the wide variety - of audio codecs and mime types available. The battle of mime types on the - audio player side of things isn't over, but it seems to be a little more - controlled. - - On the server side of things provide the appropriate mime type for the - particular audio streams and/or files that are being served to the audio - players. Although some clients and operating systems handle files fully - based on the file extension. The mime type [RFC2045] is more specific - and more defined. - - The registered mime types are maintained by IANA [IANA]. On their site - they have a list of all the registered mime types and their name space. - - If you are planning on using a mime type that isn't registered by IANA - then signal this in the name space by adding a "x-" before the subtype. - Because this was not done very often in the audio space, there was a - lot of confusion to what the real mime type should be. - - For example the MPEG 1.0 Layer 3 Audio (MP3) [ORAMP3BOOK] mime type - was not specified for the longest time. Because of this the mime type - was audio/x-mpeg. Although none of the audio players understood - audio/x-mpeg, but understood audio/mpeg it was not a technically - correct mime type. Later audio players recognized this and started - using the audio/x-mpeg mime type. Which in the end caused a lot - of hassles with clients needing to be configured differently depending - on the website and client that was used. Last november we thanked - Martin Nilsson of the ID3 tagging project for registering audo/mpeg - with IANA. [RFC3003] - - Correct configuration of Mime Types is very important. Apache HTTPD - ships with a fairly up to date copy of the mime.types file, so most - of the default ones (including audio/mpeg) are there. - - But in case you run into some that are not defined use the mod_mime - directives such as AddType to fix this. - - Examples: - AddType audio/x-mpegurl .m3u - AddType audio/x-scpls .pls - AddType application/x-ogg .ogg - - - 6. Common Audio File Formats - - There are many audio formats and metadata formats that exist. Many of - them do not have registered mime types and are hardly documented. - This section is an attempt at providing the most accurate mime type - information for each format with a rough description of what the files - are used for. - - . Real Audio - - Real Networks Proprietary audio format and meta formats. This is one - of the more common streaming audio formats today. It comes in several - sub flavors such as Real 5.0, Real G2 and Real 8.0 etc. The file size - varies depending on the bitrates and what combination of bitrates are - contained within the single file. - The following mime types are used - audio/x-pn-realaudio .ra, .ram, .rm - audio/x-pn-realaudio-plugin .rpm - application/x-pn-realmedia - - . MPEG 1.0 Layer 3 Audio (MP3) - - This is currently one of the most popular downloaded audio formats - that was originally developed by the Motion Pictures Experts Group - and has patents by the Fraunhofer IIS Institute and Thompson - Multimedia. [ORAMP3BOOK] The file is a lossy compression that at - a bitrate of 128kbps reduces the file size to roughly a MB/minute. - The mime type is audio/mpeg with the extension of .mp3 [RFC3003] - - . Windows Media Audio - - Originally known as MS Audio was developed by Microsoft as the MP3 - killer. Still relatively a new format but heavily marketed by - Microsoft and becoming more popular by the minute. It is a successor - to the Microsoft Audio Streaming Format (ASF). - - . WAV - - Windows Audio Format is a pretty semi-complicated encapsulating - format that in the most common case is PCM with a WAV header up front. - It has the mime type audio/x-wav with the extension .wav. - - . Vorbis - - Ogg Vorbis [VORBIS] is still a relatively new format brought to - life by CD Paranoia author Christopher Montgomery; known to the - world as Monty. It is an open source audio format free of patents - and gotchas. It is a codec/file format that is roughly as good as - the MP3 format, if not much better. The mime type for Ogg Vorbis is - application/x-ogg with the extension of .ogg. - - . MIDI - - The MIDI standard and file format [MIDISPEC] have been used by - Musicians for a long time. It is a great format to add music to - a website without the long download times and needing special players - or plug-ins. The mime type is audio/x-midi and the extension is .mid - - . Shockwave Flash (ADPCM/MP3) [FLASH4AUDIO] - - Macromedia Flash [FLASH4AUDIO] uses its own internal audio format - that is often used on Flash websites. It is based on Adaptive - Differential Pulse Code Modulation (ADPCM) and the MP3 file format. - Because it is usually used from within Flash it usually isn't served - up seperatedly but it's extension is .swf - - There are many many many more audio codecs and file formats that exist. - I have listed a few that won't be discussed but should be kept in mind. - Formats such as PCM/Raw Audio (audio/basic), MOD, MIDI (audio/x-midi), - QDesign (used by Quicktime), Beatnik, Sun's AU, Apple/SGI's AIFF, AAC - by the MPEG Group, Liquid Audio and AT&T's a2b (AAC derivatives), - Dolby AC-3, Yamaha's TwinVQ (originally by Nippon Telephone and Telegraph) - and MPEG-4 audio. - - 7. Linking to Audio via Apache HTTPD - - There are many different ways to link to audio from the Apache HTTPD - web server. It seems as if every codec has their own metafile format. - The metafile format is provided to allow the browser to hand off the - job of requesting the audio file to the audio player, because it is - more familiar with the file format and how to handle streaming or how - to actually connect to the audio server then the web browser is. - - This section will discuss the more common methods to provide streaming - links to provide that gateway from the web to the audio world. - - Probably the one that is the most recognized file is the RAM file. - - . RAM - - Real Audio Metafile. It is a pretty straight forward way that Real - Networks allowed their Real Player to take more control over their - proprietary audio streams. The file format is simply a URL on each - line that will be streamed in order by the client. The mime type - is the same as other RealAudio files audio/x-pn-realaudio where - the pn stands for Progressive Networks the old name of the company. - - . M3U - - This next one is the MPEG Layer 3 URL Metafile that has been around - for a very long time as a playlist format for MP3 players. It supported - URLs pretty early on by some players and got the mime type - audio/x-mpegurl and is now used by Icecast and many destination sites - such as MP3.com. The format is exactly the same as that of the RAM - file, just a list of urls that are separated by line feeds. - - . PLS - - This is the playlist files used by Nullsoft's Winamp MP3 Player. Later - on it got more widely used by Nullsoft's Shoutcast and has the mime - type of audio/x-scpls with the extension .pls. Before shoutcast the - mimetype was simply audio/x-pls. As you can see in the example below - it looks very much like a standard windows INI file format. - - Example: - [playlist] - numberofentries=2 - File1=<uri> - Title1=<title> - Length1=<length or -1> - File2=<uri> - Title2=<title> - Length2=<length or -1> - - . SDP - - This is the Session Description Protocol [RFC2327] which is heavily - used within RTSP and is a standard way of describing how to subscribe - to a particular RTP stream. The mime type is application/sdp with the - extension .sdp . - - Sometimes you might see RTSL (Real-Time Streaming Language) floating - around. This was an old Real Networks format that has been succeeded - by SDP. It's mimetype was application/x-rtsl with the extension of .rtsl - - . ASX - - Is a Windows Media Metafile format [MSASX] that is based on early XML - standards. It can be found with many extensions such as .wvx, .wax - and .asx. I am not aware of a mime type for this format. - - . SMIL - - Is the Synchronized Multimedia Integration Language [SMIL20] that - is now a W3C Recommendation [W3SYMM]. It was originally developed - by Real Networks to provide an HTML-like language to their Real Player - that was more focused on multimedia. The mime type is application/smil - with the extensions of either .smil or .smi - - . MHEG - - Is a hypertext language developed by the ISO group. [MHEG1] [MHEG5] - and [MHEG5COR]. It has been adopted by the Digital Audio Visual - Council [DAVIC]. It is more used for teleconferencing, broadcasting - and television, but close enough related that it receives a mention - here. The mime type is application/x-mheg with the extension of - .mheg - - 8. Configuring Apache HTTPD specificly to serve large Audio Files - - Some of the most common things that you will need to adjust to be - able to serve many large audio files via the Apache HTTPD Server. - Because of the difference in size between HTML files and Audio files, - the MaxClients will need to be adjusted appropriatedly depending on - the amount of time listeners end up tieing up a process. If you are - serving high quality MP3 files at 128kbps for example you should - expect more then 5 minute download times for most people. - - This will significantly impact your webserver since this means that - that process is occupied for the entire time. Because of this you - will also want to in crease the TimeOut Directive to a higher - number. This is to ensure that connections do not get disconnected - half way through a transfer and having that person hit "reload" - and connect again. - - Because of the amount of time the downloads tie up the processes - of the server, the smallest footprint of the server in memory would - be recommended because that would mean you could run more processes - on the machine. - - After that normal performance tweaks such as max file descriptor - changes and longer tcp listen queues apply. - - 9. Icecast/Shoutcast Protocol. - - Both protocols are very tightly based on HTTP/1.0. The main difference - is a group of new headers such as the icy headers by Shoutcast and the - new x-audiocast headers provided by Icecast. - - A typical shoutcast request from the client. - - GET / HTTP/1.0 - - ICY 200 OK - icy-notice1:<BR>This stream requires <a href="http://www.winamp.com/"> - Winamp</a><BR> - icy-notice2:SHOUTcast Distributed Network Audio Server/posix v1.0b<BR> - icy-name: Great Songs - icy-genre: Jazz - icy-url: http://shout.serv.dom/ - icy-pub: 1 - icy-br: 24 - - <data><songtitle><data> - - The icy headers display the song title and other formation including if - this stream is public and what the bitrate is. - - A typical icecast request from the client. - - GET / HTTP/1.0 - Host: icecast.serv.dom - x-audiocast-udpport: 6000 - Icy-MetaData: 0 - Accept: */* - - HTTP/1.0 200 OK - Server: Icecast/VERSION - Content-Type: audio/mpeg - x-audiocast-name: Great Songs - x-audiocast-genre: Jazz - x-audiocast-url: http://icecast.serv.dom/ - x-audiocast-streamid: - x-audiocast-public: 0 - x-audiocast-bitrate: 24 - x-audiocast-description: served by Icecast - - <data> - - NOTE: I am mixing the headers of the controlling client with those form - a listening client. This might be better explained at a latter - date. - - The CPAN Perl Package Apache::MP3 by Lincoln Stein implements a little of - each which works because MP3 players tend to support both. - - One of the big differences in implementations between the listening clients - is that Icecast uses an out of band UDP channel to update metadata - while the Shoutcast server gets it meta data from the client embedded within - the MP3 stream. The general meta data for the stream is set up via the - icy and x-audiocast HTTP headers. - - Although the MP3 standard documents were written for interrupted communication - it is not very specific on that. So although it doesn't state that there is - anything wrong with embedding garbage between MPEG frames the players that - do not understand it might make a noisy bleep and chirps because of it. - -References and Further Reading: - -[DAVIC] - Digital Audio Visual Council - <http://www.davic.org/> - -[FLASH4AUDIO] - L. J. Lotus, "Flash 4: Audio Options", ZD, Inc. 2000. - <http://www.zdnet.com/devhead/stories/articles/0,4413,2580376,00.html> - -[HTML4] - D. Ragget, A. Le Hors, I. Jacobs, "HTML 4.01 Specification", W3C - Recommendation, December, 1999. - <http://www.w3.org/TR/html401/> - -[IANA] - Internet Assigned Numbers Authority. - <http:/www.iana.org/> - -[ICECAST] - Icecast Open Source Streaming Audio System. - <http://www.icecast.org/> - -[IETFAVT] - Audio/Video Transport WG, Internet Engineering Task Force. - <http://www.ietf.org/html.charters/avt-charter.html> - -[IETFMMUSIC] - Multiparty Multimedia Session Control WG, Internet Engineering Task - Force. <http://www.ietf.org/html.charters/mmusic-charter.html> - -[IETFSIP] - Session Initiation Protocol WG, Internet Engineering Task Force. - <http://www.ietf.org/html.charters/sip-charter.html> - -[IPMULTICAST] - Transmit information to a group of recipients via a single transmission - by the source, in contrast to unicast. - IP Multicast Initiative - <http://www.ipmulticast.com/> - -[MIDISPEC] - The International MIDI Association,"MIDI File Format Spec 1.1", - <http://www.vanZoest.com/sander/apachecon/2001/midispec.html> - -[MHEG1] - ISO/IEC, "Information Technology - Coding of Multimedia and Hypermedia - Information - Part 1: MHEG Object Representation, Base Notation (ASN.1)"; - Draft International Standard ISO 13522-1;1997; - <http://www.ansi.org/> - <http://www.iso.ch/cate/d22153.html> - -[MHEG5] - ISO/IEC, "Information Technology - Coding of Multimedia and Hypermedia - Information - Part 5: Support for Base-Level Interactive Applications"; - Draft International Standard ISO 13522-5:1997; - <http://www.ansi.org/> - <http://www.iso.ch/cate/d26876.html> - -[MHEG5COR] - Information Technology - Coding of Multimedia and Hypermedia Information - - Part 5: Support for base-level interactive applications - - - Technical Corrigendum 1; ISO/IEC 13552-5:1997/Cor.1:1999(E) - <http://www.ansi.org/> - <http://www.iso.ch/cate/d31582.html> - -[MSASX] - Microsoft Corp. "All About Windows Media Metafiles". October 2000. - <http://msdn.microsoft.com/workshop/imedia/windowsmedia/ - crcontent/asx.asp> - -[ORAMP3] - S. Hacker; MP3: The Definitive Guide; O'Reilly and Associates, Inc. - March, 2000. - <http://www.oreilly.com/catalog/mp3/> -[RFC2045] - N. Freed and N. Borenstein, "Multipurpose Internet Mail - Extensions (MIME) Part One: Format of Internet Message Bodies", - RFC 2045, November 1996. <http://www.ietf.org/rfc/2045.txt> - -[RFC2327] - M. Handley and V. Jacobson, "SDP: Session Description Protocol", - RFC 2327, April 1998. <http://www.ietf.org/rfc/rfc2327.txt> - -[RFC3003] - M. Nilsson, "The audio/mpeg Media Type", RFC 3003, November 2000. - <http://www.ietf.org/rfc/rfc3003.txt> - -[SHOUTCAST] - Nullsoft Shoutcast MP3 Streaming Technology. - <http://www.shoutcast.com/> - -[SMIL20] - L. Rutledge, J. van Ossenbruggen, L. Hardman, D. Bulterman, - "Anticipating SMIL 2.0: The Developing Cooperative Infrastructure - for Multimedia on the Web"; 8th International WWW Conference, - Proc. May, 1999. - <http://www8.org/w8-papers/3c-hypermedia-video/anticipating/ - anticipating.html> - -[W39CIR] - V. Krishnan and S. G. Chang, "Customized Internet Radio"; 9th - International WWW Conference Proc. May 2000. - <http://www9.org/w9cdrom/353/353.html> - -[VORBIS] - Ogg Vorbis - Open Source Audio Codec - <http://www.xiph.org/ogg/vorbis/> - -[W3SYMM] - W3C Synchronized Multimedia Activity (SYMM Working Group); - <http://www.w3.org/AudioVideo/> diff --git a/kioslave/http/webdav.protocol b/kioslave/http/webdav.protocol deleted file mode 100644 index f4f4df462..000000000 --- a/kioslave/http/webdav.protocol +++ /dev/null @@ -1,18 +0,0 @@ -[Protocol] -exec=kio_http -protocol=webdav -input=none -output=filesystem -listing=Name,Type,Size,Date,AccessDate,Access -reading=true -writing=true -makedir=true -deleting=true -moving=true -deleteRecursive=true -defaultMimetype=application/octet-stream -determineMimetypeFromExtension=false -Icon=www -maxInstances=3 -DocPath=kioslave/webdav.html -Class=:internet diff --git a/kioslave/http/webdavs.protocol b/kioslave/http/webdavs.protocol deleted file mode 100644 index c8b7cba3f..000000000 --- a/kioslave/http/webdavs.protocol +++ /dev/null @@ -1,18 +0,0 @@ -[Protocol] -exec=kio_http -protocol=webdavs -input=none -output=filesystem -listing=Name,Type,Size,Date,AccessDate,Access -reading=true -writing=true -makedir=true -deleting=true -moving=true -deleteRecursive=true -defaultMimetype=application/octet-stream -determineMimetypeFromExtension=false -Icon=www -config=webdav -DocPath=kioslave/webdavs.html -Class=:internet |