http.cc
来自「konqueror3 embedded版本, KDE环境下的当家浏览器的嵌入式版」· CC 代码 · 共 2,361 行 · 第 1/5 页
CC
2,361 行
/* 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 <qdom.h>#include <qfile.h>#include <qregexp.h>#include <qdatetime.h>#include <qstringlist.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 */#ifndef KONQ_EMBEDDED#include <misc/kntlm/kntlm.h>#endifusing namespace KIO;extern "C" { KDE_EXPORT int http_kdemain(int argc, char **argv);}int http_kdemain( int argc, char **argv ){ KLocale::setMainCatalogue("kdelibs"); KInstance instance( "kio_http" ); ( void ) KGlobal::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 QString& fqdn, const QString& originURL ){ if (originURL == "true") // Backwards compatibility return true; KURL url ( originURL ); // Document Origin domain QString a = url.host(); // Current request domain QString b = fqdn; if (a == b) return false; QStringList l1 = QStringList::split('.', a); QStringList l2 = QStringList::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 QString sanitizeCustomHTTPHeader(const QString& _header){ QString sanitizedHeaders; QStringList headers = QStringList::split("\r\n", _header); for(QStringList::Iterator it = headers.begin(); it != headers.end(); ++it) { QString 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 ((KIO::filesize_t) -1)#ifdef HAVE_STRTOLL#define STRTOLL strtoll#else#define STRTOLL strtol#endif/************************************** HTTPProtocol **********************************************/HTTPProtocol::HTTPProtocol( const QCString &protocol, const QCString &pool, const QCString &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 = QString::null; m_strProxyAuthorization = QString::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 = QString::null; m_strMimeType = QString::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 = QString::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 QString protocol = referrerURL.protocol(); if (protocol.startsWith("webdav")) { protocol.replace(0, 6, "http"); referrerURL.setProtocol(protocol); } if (protocol.startsWith("http")) { referrerURL.setRef(QString::null); referrerURL.setUser(QString::null); referrerURL.setPass(QString::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 = QString::null; m_request.languages = QString::null; } // Adjust the offset value based on the "resume" meta-data. QString 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 = QString::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( QString::null); } m_responseCode = 0; m_prevResponseCode = 0; m_strRealm = QString::null; m_strAuthorization = QString::null; Authentication = AUTH_None; // Obtain the proxy and remote server timeout values m_proxyConnTimeout = proxyConnectTimeout(); m_remoteConnTimeout = connectTimeout(); m_remoteRespTimeout = responseTimeout(); // Bounce back the actual referrer sent setMetaData("referrer", m_request.referrer); // Set the SSL meta-data here... setSSLMetaData(); // 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 QString& host, int port, const QString& user, const QString& pass ){#if !defined(QT_NO_DOM) // Reset the webdav-capable flags for this host if ( m_request.hostname != host ) m_davHostOk = m_davHostUnsupported = false;#endif // 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( KIO::ERR_UNKNOWN_HOST, i18n("No host specified.")); return false; }
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?