📄 http.cc
字号:
/* Copyright (C) 2000,2001 Waldo Bastian <bastian@kde.org> Copyright (C) 2000,2001 George Staikos <staikos@kde.org> Copyright (C) 2000,2001 Dawit Alemayehu <adawit@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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.*/#include <config.h>#ifdef HAVE_SYS_SELECT_H#include <sys/select.h> // Needed on some systems.#endif#ifdef HAVE_LIBZ#define DO_GZIP#endif#ifdef DO_GZIP#include <zlib.h>#endif#include <sys/time.h>#include <sys/wait.h>#include <sys/stat.h>#include <sys/socket.h>#include <netinet/in.h>#include <netinet/tcp.h>#include <assert.h>#include <signal.h>#include <stdlib.h>#include <unistd.h>#include <fcntl.h>#include <utime.h>#include <errno.h>#include <netdb.h>#include <qregexp.h>#include <kapp.h>#include <kurl.h>#include <ksocks.h>#include <kdebug.h>#include <klocale.h>#include <kconfig.h>#include <kextsock.h>#include <kstddirs.h>#include <kservice.h>#include <krfcdate.h>#include <kinstance.h>#include <kmimemagic.h>#include <dcopclient.h>#include <kdatastream.h>#include "kio/ioslave_defaults.h"#include "kio/http_slave_defaults.h"#include "http.h"using namespace KIO;extern "C" { void sigalrm_handler(int); int http_kdemain(int argc, char **argv);};int http_kdemain( int argc, char **argv ){ KLocale::setMainCatalogue("kdelibs"); KInstance instance( "kio_http" ); ( void ) KGlobal::locale(); kdDebug(7113) << "(" << getpid() << ") Starting " << getpid() << endl; 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;}/* * We'll use an alarm that will set this flag when transfer has timed out */char sigbreak = 0;void sigalrm_handler(int ){ sigbreak = 1;}void setup_alarm(unsigned int timeout){ sigbreak = 0; alarm(timeout); signal(SIGALRM, sigalrm_handler);}/*********************************** Generic utility functions ********************/static char * trimLead (char *orig_string){ while (*orig_string == ' ') orig_string++; return orig_string;}/************************************** HTTPProtocol **********************************************/HTTPProtocol::HTTPProtocol( const QCString &protocol, const QCString &pool, const QCString &app ) :TCPSlaveBase( 0, protocol, pool, app, (protocol == "https") ){ m_lineBufUnget = 0; m_protocol = protocol; m_bKeepAlive = false; m_bUseCache = true; m_maxCacheAge = 0; m_fcache = 0; m_iSize = -1; m_HTTPrev = HTTP_Unknown; m_maxCacheAge = DEFAULT_MAX_CACHE_AGE; m_dcopClient = new DCOPClient(); if (!m_dcopClient->attach()) { kdDebug(7113) << "(" << getpid() << ") Can't connect with DCOP server." << endl; } setMultipleAuthCaching( true ); reparseConfiguration();}HTTPProtocol::~HTTPProtocol(){ delete m_dcopClient; m_bKeepAlive = false; http_close();}void HTTPProtocol::reparseConfiguration(){ kdDebug(7113) << "(" << getpid() << ") Reparse Configuration!" << endl; m_strProxyRealm = QString::null; m_strProxyAuthorization = QString::null; ProxyAuthentication = AUTH_None; struct servent *sent = getservbyname(m_protocol, "tcp"); if (!sent) { if (m_protocol == "https") m_iDefaultPort = DEFAULT_HTTPS_PORT; else if (m_protocol == "ftp") m_iDefaultPort = DEFAULT_FTP_PORT; else m_iDefaultPort = DEFAULT_HTTP_PORT; } else { m_iDefaultPort = ntohs(sent->s_port); }}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_proxyURL = proxy; m_bUseProxy = m_proxyURL.isValid(); kdDebug(7103) << "(" << getpid() << ") Proxy realm value: " << m_strRealm << endl; kdDebug(7103) << "(" << getpid() << ") Proxy URL is now: " << m_proxyURL.url() << endl; } m_bUseCookiejar = config()->readBoolEntry("Cookies"); m_bUseCache = config()->readBoolEntry("UseCache"); m_strCacheDir = config()->readEntry("CacheDir"); m_maxCacheAge = config()->readNumEntry("MaxCacheAge"); m_request.window = config()->readEntry("window-id"); // Deal with cache cleaning. // TODO: Find a smart way to deal with caching. if ( m_bUseCache ) cleanCache(); // Deal with HTTP tunneling if ( m_bIsSSL && m_bUseProxy && m_proxyURL.protocol() != "https" ) { // Tell parent class about the real hostname setRealHost( m_request.hostname ); setEnableSSLTunnel( true ); } else { // Should never be needed! Being overcautious! setRealHost( QString::null ); setEnableSSLTunnel( false ); } 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(); m_bCanResume = false; m_bUnauthorized = false; m_bIsTunneled = false;}void HTTPProtocol::setHost( const QString& host, int port, const QString& user, const QString& pass ){ kdDebug(7103) << "(" << getpid() << ") Hostname is now: " << host << endl; m_request.hostname = host; m_request.port = (port == 0) ? m_iDefaultPort : port; m_request.user = user; m_request.passwd = pass;}bool HTTPProtocol::checkRequestURL( const KURL& u ){ if (m_request.hostname.isEmpty()) { error( KIO::ERR_UNKNOWN_HOST, i18n("No host specified!")); 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(){ if ( !retrieveHeader(false) ) { if ( m_bError ) { return; } } else { if ( !readBody() && m_bError ) { return; } } http_close(); finished();}bool HTTPProtocol::retrieveHeader( bool close_connection ){ while ( 1 ) { if (!http_open()) return false; if (!readHeader()) { if ( m_bError ) return false; } else { // Do not save authorization if the current response code is // 4xx (client error) or 5xx (server error). kdDebug(7113) << "(" << getpid() << ") Previous Response: " << m_prevResponseCode << ", Current Response: " << m_responseCode << endl; if ( m_responseCode < 400 && (m_prevResponseCode == 401 || m_prevResponseCode == 407) ) saveAuthorization(); if ( isSSLTunnelEnabled() && m_bIsSSL && !m_bUnauthorized && !m_bError ) { // Only disable tunneling if the error if ( m_responseCode < 400 ) { kdDebug(7113) << "(" << getpid() << ") Unsetting tunneling flag!" << endl; setEnableSSLTunnel( false ); m_bIsTunneled = true; continue; } else { if ( !m_bErrorPage ) { kdDebug(7113) << "(" << getpid() << ") Sending an error message!" << endl; error( ERR_UNKNOWN_PROXY_HOST, m_proxyURL.host() ); return false; } kdDebug(7113) << "(" << getpid() << ") Sending an error page!" << endl; } } break; } } if ( close_connection ) { http_close(); finished(); } return true;}void HTTPProtocol::stat(const KURL& url){ if ( !checkRequestURL( url ) ) return; kdDebug(7103) << "(" << getpid() << ") HTTPProtocol::stat " << url.prettyURL() << endl; UDSEntry entry; UDSAtom atom; atom.m_uds = KIO::UDS_NAME; atom.m_str = url.fileName(); entry.append( atom ); atom.m_uds = KIO::UDS_FILE_TYPE; atom.m_long = S_IFREG; // a file entry.append( atom ); atom.m_uds = KIO::UDS_ACCESS; atom.m_long = S_IRUSR | S_IRGRP | S_IROTH; // readable by everybody entry.append( atom ); statEntry( entry ); finished();}void HTTPProtocol::get( const KURL& url ){ if ( !checkRequestURL( url ) ) return; kdDebug(7103) << "(" << getpid() << ") HTTPProtocol::get " << url.url() << endl; m_request.method = HTTP_GET; m_request.path = url.path(); m_request.query = url.query(); QString tmp = config()->readEntry("cache"); if (!tmp.isEmpty()) m_request.cache = parseCacheControl(tmp); else m_request.cache = DEFAULT_CACHE_CONTROL; m_request.offset = 0; m_request.url = url; m_request.passwd = url.pass(); m_request.user = url.user(); m_request.doProxy = m_bUseProxy; retrieveContent();}void HTTPProtocol::put( const KURL &url, int, bool, bool){ if ( !checkRequestURL( url ) ) return; kdDebug(7103) << "(" << getpid() << ") HTTPProtocol::put " << url.prettyURL() << endl; m_request.method = HTTP_PUT; m_request.path = url.path(); m_request.query = QString::null; m_request.cache = CC_Reload; m_request.offset = 0; m_request.doProxy = m_bUseProxy; m_request.url = url; retrieveContent();}void HTTPProtocol::post( const KURL& url){ if ( !checkRequestURL( url ) ) return; kdDebug(7103) << "(" << getpid() << ") HTTPProtocol::post " << url.prettyURL() << endl; m_request.method = HTTP_POST; m_request.path = url.path(); m_request.query = url.query(); m_request.cache = CC_Reload; m_request.offset = 0; m_request.doProxy = m_bUseProxy; m_request.url = url; retrieveContent();}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 = Write(buf, nbytes); if ( n <= 0 ) { // remote side closed connection ? if ( n == 0 ) break; // a valid exception(s) occured, let's retry... if (n < 0 && ((errno == EINTR) || (errno == EAGAIN))) continue; // some other error occured ? return -1; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -