📄 http.cc
字号:
#include "http.h"#include <kio_manager.h>#include <kio_rename_dlg.h>#include <kio_skip_dlg.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <sys/wait.h>#include <sys/types.h>#include <unistd.h>#include <signal.h>#include <time.h>#include <assert.h>#include <k2url.h>bool open_CriticalDlg( const char *_titel, const char *_message, const char *_but1, const char *_but2 = 0L );bool open_PassDlg( const char *_head, string& _user, string& _pass );void sig_handler( int );void sig_handler2( int );int main( int argc, char **argv ){ signal(SIGCHLD,sig_handler); signal(SIGSEGV,sig_handler2); ProtocolManager manager; Connection parent( 0, 1 ); HTTPProtocol http( &parent ); http.dispatchLoop(); debug( "kio_http : Done" );}void sig_handler2( int ){ debug( "kio_http : ###############SEG FILE#############" ); exit(1);}void sig_handler( int ){ int pid; int status; while( 1 ) { pid = waitpid( -1, &status, WNOHANG ); if ( pid <= 0 ) { // Reinstall signal handler, since Linux resets to default after // the signal occured ( BSD handles it different, but it should do // no harm ). signal( SIGCHLD, sig_handler ); return; } }}/* * We'll use an alarm that will set this flag when transfer has timed out */char sigbreak = 0;void sig_alarm(int signo){ sigbreak = 1;} void setup_alarm(unsigned int timeout){ sigbreak = 0; alarm(timeout); signal(SIGALRM, sig_alarm);}/************************** Authorization stuff: copied from wget-source *****//* Encode a zero-terminated string in base64. Returns the malloc-ed encoded line. This is useful for HTTP only. Note that the string may not contain NUL characters. */char* base64_encode_line( const char *s ){ /* Conversion table. */ static char tbl[64] = { 'A','B','C','D','E','F','G','H', 'I','J','K','L','M','N','O','P', 'Q','R','S','T','U','V','W','X', 'Y','Z','a','b','c','d','e','f', 'g','h','i','j','k','l','m','n', 'o','p','q','r','s','t','u','v', 'w','x','y','z','0','1','2','3', '4','5','6','7','8','9','+','/' }; int len, i; char *res; unsigned char *p; len = strlen(s); res = (char *)malloc(4 * ((len + 2) / 3) + 1); p = (unsigned char *)res; /* Transform the 3x8 bits to 4x6 bits, as required by base64. */ for (i = 0; i < len; i += 3) { *p++ = tbl[s[0] >> 2]; *p++ = tbl[((s[0] & 3) << 4) + (s[1] >> 4)]; *p++ = tbl[((s[1] & 0xf) << 2) + (s[2] >> 6)]; *p++ = tbl[s[2] & 0x3f]; s += 3; } /* Pad the result if necessary... */ if (i == len + 1) *(p - 1) = '='; else if (i == len + 2) *(p - 1) = *(p - 2) = '='; /* ...and zero-teminate it. */ *p = '\0'; return res;}char *create_generic_auth (const char *prefix, const char *user, const char *passwd ){ char *wwwauth; if (user && passwd) { char *t1, *t2; t1 = (char *)malloc(strlen(user) + 1 + 2 * strlen(passwd) + 1); sprintf(t1, "%s:%s", user, passwd); t2 = base64_encode_line(t1); free(t1); // wwwauth = (char *)malloc(strlen(t2) + 24); // sprintf(wwwauth, "Authorization: Basic %s\r\n", t2); wwwauth = (char *)malloc(strlen(t2) + strlen(prefix) + 11 /* UPDATE WHEN FORMAT BELOW CHANGES !!! */); sprintf(wwwauth, "%s: Basic %s\r\n", prefix, t2); free(t2); } else wwwauth = NULL; return(wwwauth);}char *create_www_auth(const char *user, const char *passwd){ return create_generic_auth("Authorization",user, passwd);}/*****************************************************************************//* Domain suffix match. E.g. return 1 if host is "cuzco.inka.de" and nplist is "inka.de,hadiko.de" or if host is "localhost" and nplist is "localhost" */ int revmatch(const char *host, const char *nplist){ const char *hptr = host + strlen( host ) - 1; const char *nptr = nplist + strlen( nplist ) - 1; const char *shptr = hptr; while( nptr >= nplist ) { if ( *hptr != *nptr ) { hptr = shptr; // Try to find another domain or host in the list while ( --nptr>=nplist && *nptr!=',' && *nptr!=' ') ; while ( --nptr>=nplist && (*nptr==',' || *nptr==' ')) ; } else { if ( nptr==nplist || nptr[-1]==',' || nptr[-1]==' ') { return 1; } hptr--; nptr--; } } return 0;}/*****************************************************************************/HTTPProtocol::HTTPProtocol( Connection *_conn ) : IOProtocol( _conn ){ m_cmd = CMD_NONE; m_fsocket = 0L; m_sock = 0; m_bUseProxy = false; m_bIgnoreJobErrors = false; m_bIgnoreErrors = false; m_iSavedError = 0; m_iSize = 0; m_bCanResume = true; // most of http servers support resuming ?}bool HTTPProtocol::initSockaddr( struct sockaddr_in *server_name, const char *hostname, int port){ struct hostent *hostinfo; server_name->sin_family = AF_INET; server_name->sin_port = htons( port ); hostinfo = gethostbyname( hostname ); if ( hostinfo == 0L ) return false; server_name->sin_addr = *(struct in_addr*) hostinfo->h_addr; return true;}bool HTTPProtocol::http_open( K2URL &_url, const char* _post_data, int _post_data_size, bool _reload, unsigned long _offset ){ string url = _url.url(); int port = _url.port(); if ( port == -1 ) port = 80; m_sock = ::socket(PF_INET,SOCK_STREAM,0); if ( m_sock < 0 ) { error( ERR_COULD_NOT_CREATE_SOCKET, url.c_str() ); return false; } int do_proxy = m_bUseProxy; if ( do_proxy && !m_strNoProxyFor.empty() ) do_proxy = !revmatch( _url.host(), m_strNoProxyFor.c_str() ); if( do_proxy ) { if( ::connect( m_sock, (struct sockaddr*)(&m_proxySockaddr), sizeof( m_proxySockaddr ) ) ) { error( ERR_COULD_NOT_CONNECT, m_strProxyHost.c_str() ); return false; } } else { struct sockaddr_in server_name; if( !initSockaddr( &server_name, _url.host(), port ) ) { error( ERR_UNKNOWN_HOST, _url.host() ); return false; } if( ::connect( m_sock, (struct sockaddr*)( &server_name ), sizeof( server_name ) ) ) { error( ERR_COULD_NOT_CONNECT, _url.host() ); return false; } } m_fsocket = fdopen( m_sock, "r+" ); if( !m_fsocket ) { error( ERR_COULD_NOT_CONNECT, _url.host() ); return false; } string command; if ( _post_data ) { _reload = true; /* no caching allowed */ command = "POST "; } else command = "GET "; if( do_proxy ) { char buffer[ 100 ]; sprintf( buffer, ":%i", port ); command += "http://"; command += _url.host(); command += buffer; } // Let the path be "/" if it is empty ( => true ) string tmp = _url.encodedPathAndQuery( 0, true ); command += tmp; command += " HTTP/1.0\r\n"; /* start header */ command += "User-Agent: Konqueror/1.0\r\n"; /* User agent */ if ( _offset > 0 ) { char buffer[ 100 ]; sprintf( buffer, "Range: bytes=%li-\r\n", _offset ); command += buffer; debug( "kio_http : Range = %s", buffer ); } if ( _reload ) /* No caching for reload */ { command += "Pragma: no-cache\r\n"; /* for HTTP/1.0 caches */ command += "Cache-control: no-cache\r\n"; /* for HTTP/>=1.1 caches */ } // Charset negotiation: if ( !m_strCharsets.empty() ) command += "Accept-Charset: " + m_strCharsets + "\r\n"; // Language negotiation: if ( !m_strLanguages.empty() ) command += "Accept-Language: " + m_strLanguages + "\r\n"; command += "Host: "; /* support for virtual hosts */ command += _url.host(); if ( _url.port() != 0 ) { char buffer[ 100 ]; sprintf( buffer, ":%i", port ); command += buffer; } command += "\r\n"; if ( _post_data ) { command += "Content-Type: application/x-www-form-urlencoded\r\nContent-Length: "; char buffer[ 100 ]; sprintf( buffer, "%i\r\n", _post_data_size ); command += buffer; } if( strlen( _url.user() ) != 0 ) { char *www_auth = create_www_auth( _url.user(), _url.pass() ); command += www_auth; free(www_auth); } if( do_proxy ) { if( m_strProxyUser != "" && m_strProxyPass != "" ) { char *www_auth = create_generic_auth("Proxy-authorization", m_strProxyUser.c_str(), m_strProxyPass.c_str() ); command += www_auth; free(www_auth); } } command += "\r\n"; /* end header */ int n;repeat1: if ( ( n = write( m_sock, command.c_str(), command.size() ) ) != (int)command.size() ) { if ( n == -1 && errno == EINTR ) goto repeat1; error( ERR_CONNECTION_BROKEN, _url.host() ); return false; }repeat2: if ( _post_data && ( n = write( m_sock, _post_data, _post_data_size ) != _post_data_size ) ) { if ( n == -1 && errno == EINTR ) goto repeat2; error( ERR_CONNECTION_BROKEN, _url.host() ); return false; } // Jacek: // to get rid of those "Open with" dialogs... // however at least extensions should be checked m_strMimeType = "text/html"; string realm; bool unauthorized = false; char buffer[ 1024 ]; int len = 1; char* ret = 0L; while( len && ( ret = fgets( buffer, 1024, m_fsocket ) ) ) { len = strlen( buffer ); while( len && (buffer[ len-1 ] == '\n' || buffer[ len-1 ] == '\r') ) buffer[ --len ] = 0; if ( strncmp( buffer, "Accept-Ranges: none", 19 ) == 0 ) m_bCanResume = false; // debug( "kio_http : Header: %s", buffer ); else if ( strncmp( buffer, "Content-length: ", 16 ) == 0 || strncmp( buffer, "Content-Length: ", 16 ) == 0 ) m_iSize = atol( buffer + 16 ); else if ( strncmp( buffer, "Content-Type: ", 14 ) == 0 || strncmp( buffer, "Content-type: ", 14 ) == 0 ) { // Jacek: We can't send mimeType signal now, // because there may be another Content-Type to come m_strMimeType = buffer + 14; } else if ( strncmp( buffer, "HTTP/1.0 ", 9 ) == 0 || strncmp( buffer, "HTTP/1.1 ", 9 ) == 0 ) { // Unauthorized access if ( strncmp( buffer + 9, "401", 3 ) == 0 ) unauthorized = true; //Jacek: server error codes added (5xx) else if ( buffer[9] == '4' || buffer[9] == '5' ) { http_close(); // Let's first send an error message error( ERR_ACCESS_DENIED, url.c_str() ); return false; // Tell that we will only get an error page here. errorPage(); } } // In fact we should do redirection only if we got redirection code else if ( strncmp( buffer, "Location: ", 10 ) == 0 ) { http_close(); K2URL u( _url, buffer + 10 ); string url = u.url(); redirection( url.c_str() ); return http_open( u, _post_data, _post_data_size, _reload, _offset ); } else if ( strncmp( buffer, "WWW-Authenticate:", 17 ) == 0 ) { const char *p = buffer + 17; while( *p == ' ' ) p++; if ( strncmp( p, "Basic", 5 ) != 0 ) continue; p += 5; while( *p == ' ' ) p++; if ( strncmp( p, "realm=\"", 7 ) != 0 ) continue; p += 7; int i = 0; while( p[i] != '"' ) i++; realm.assign( p, i ); } } if ( unauthorized ) { http_close(); string user = _url.user(); string pass = _url.pass(); if ( realm.empty() ) realm = _url.host(); if ( !open_PassDlg( realm.c_str(), user, pass ) ) { string url = _url.url(); error( ERR_ACCESS_DENIED, url.c_str() ); return false; } K2URL u( _url ); u.setUser( user.c_str() ); u.setPass( pass.c_str() ); return http_open( u, _post_data, _post_data_size, _reload, _offset ); } mimeType( m_strMimeType.c_str() ); return true;}void HTTPProtocol::http_close(){ if ( m_sock ) close( m_sock ); m_sock = 0;}void HTTPProtocol::slotGetSize( const char *_url ){ string url = _url; K2URL usrc( _url ); if ( usrc.isMalformed() ) { error( ERR_MALFORMED_URL, url.c_str() ); m_cmd = CMD_NONE; return; } if ( strcmp( usrc.protocol(), "http" ) != 0 ) { error( ERR_INTERNAL, "kio_http got non http url" ); m_cmd = CMD_NONE; return; } m_cmd = CMD_GET_SIZE; m_bIgnoreErrors = false; if ( !http_open( usrc, 0L, 0, false ) ) { m_cmd = CMD_NONE; return; } totalSize( m_iSize ); http_close(); finished(); m_cmd = CMD_NONE;}void HTTPProtocol::slotGet( const char *_url ){ string url = _url; K2URL usrc( _url ); if ( usrc.isMalformed() ) { error( ERR_MALFORMED_URL, url.c_str() );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -