gloox  1.0
connectionhttpproxy.cpp
00001 /*
00002   Copyright (c) 2004-2009 by Jakob Schroeter <js@camaya.net>
00003   This file is part of the gloox library. http://camaya.net/gloox
00004 
00005   This software is distributed under a license. The full license
00006   agreement can be found in the file LICENSE in this distribution.
00007   This software may not be copied, modified, sold or distributed
00008   other than expressed in the named license agreement.
00009 
00010   This software is distributed without any warranty.
00011 */
00012 
00013 
00014 
00015 #include "gloox.h"
00016 
00017 #include "connectionhttpproxy.h"
00018 #include "dns.h"
00019 #include "logsink.h"
00020 #include "prep.h"
00021 #include "base64.h"
00022 #include "util.h"
00023 
00024 #include <string>
00025 
00026 namespace gloox
00027 {
00028 
00029   ConnectionHTTPProxy::ConnectionHTTPProxy( ConnectionBase* connection,
00030                                             const LogSink& logInstance,
00031                                             const std::string& server, int port )
00032     : ConnectionBase( 0 ), m_connection( connection ),
00033       m_logInstance( logInstance ), m_http11( false )
00034   {
00035 // FIXME check return value?
00036     prep::idna( server, m_server );
00037     m_port = port;
00038 
00039     if( m_connection )
00040       m_connection->registerConnectionDataHandler( this );
00041   }
00042 
00043   ConnectionHTTPProxy::ConnectionHTTPProxy( ConnectionDataHandler* cdh,
00044                                             ConnectionBase* connection,
00045                                             const LogSink& logInstance,
00046                                             const std::string& server, int port )
00047     : ConnectionBase( cdh ), m_connection( connection ),
00048       m_logInstance( logInstance )
00049   {
00050 // FIXME check return value?
00051     prep::idna( server, m_server );
00052     m_port = port;
00053 
00054     if( m_connection )
00055       m_connection->registerConnectionDataHandler( this );
00056   }
00057 
00058   ConnectionHTTPProxy::~ConnectionHTTPProxy()
00059   {
00060     delete m_connection;
00061   }
00062 
00063   ConnectionBase* ConnectionHTTPProxy::newInstance() const
00064   {
00065     ConnectionBase* conn = m_connection ? m_connection->newInstance() : 0;
00066     return new ConnectionHTTPProxy( m_handler, conn, m_logInstance, m_server, m_port );
00067   }
00068 
00069   void ConnectionHTTPProxy::setConnectionImpl( ConnectionBase* connection )
00070   {
00071     if( m_connection )
00072       delete m_connection;
00073 
00074     m_connection = connection;
00075   }
00076 
00077   ConnectionError ConnectionHTTPProxy::connect()
00078   {
00079     if( m_connection && m_handler )
00080     {
00081       m_state = StateConnecting;
00082       return m_connection->connect();
00083     }
00084 
00085     return ConnNotConnected;
00086   }
00087 
00088   void ConnectionHTTPProxy::disconnect()
00089   {
00090     m_state = StateDisconnected;
00091     if( m_connection )
00092       m_connection->disconnect();
00093   }
00094 
00095   ConnectionError ConnectionHTTPProxy::recv( int timeout )
00096   {
00097     return m_connection ? m_connection->recv( timeout ) : ConnNotConnected;
00098   }
00099 
00100   ConnectionError ConnectionHTTPProxy::receive()
00101   {
00102     return m_connection ? m_connection->receive() : ConnNotConnected;
00103   }
00104 
00105   bool ConnectionHTTPProxy::send( const std::string& data )
00106   {
00107     return m_connection && m_connection->send( data );
00108   }
00109 
00110   void ConnectionHTTPProxy::cleanup()
00111   {
00112     m_state = StateDisconnected;
00113 
00114     if( m_connection )
00115       m_connection->cleanup();
00116   }
00117 
00118   void ConnectionHTTPProxy::getStatistics( long int& totalIn, long int& totalOut )
00119   {
00120     if( m_connection )
00121       m_connection->getStatistics( totalIn, totalOut );
00122     else
00123       totalIn = totalOut = 0;
00124   }
00125 
00126   void ConnectionHTTPProxy::handleReceivedData( const ConnectionBase* /*connection*/,
00127                                                 const std::string& data )
00128   {
00129     if( !m_handler )
00130       return;
00131 
00132     if( m_state == StateConnecting )
00133     {
00134       m_proxyHandshakeBuffer += data;
00135       if( ( !m_proxyHandshakeBuffer.compare( 0, 12, "HTTP/1.0 200" )
00136          || !m_proxyHandshakeBuffer.compare( 0, 12, "HTTP/1.1 200" ) )
00137          && !m_proxyHandshakeBuffer.compare( m_proxyHandshakeBuffer.length() - 4, 4, "\r\n\r\n" ) )
00138       {
00139         m_proxyHandshakeBuffer = EmptyString;
00140         m_state = StateConnected;
00141         m_logInstance.dbg( LogAreaClassConnectionHTTPProxy,
00142                            "http proxy connection established" );
00143         m_handler->handleConnect( this );
00144       }
00145       else if( !m_proxyHandshakeBuffer.compare( 9, 3, "407" ) )
00146       {
00147         m_handler->handleDisconnect( this, ConnProxyAuthRequired );
00148         m_connection->disconnect();
00149       }
00150       else if( !m_proxyHandshakeBuffer.compare( 9, 3, "403" )
00151             || !m_proxyHandshakeBuffer.compare( 9, 3, "404" ) )
00152       {
00153         m_handler->handleDisconnect( this, ConnProxyAuthFailed );
00154         m_connection->disconnect();
00155       }
00156     }
00157     else if( m_state == StateConnected )
00158       m_handler->handleReceivedData( this, data );
00159   }
00160 
00161   void ConnectionHTTPProxy::handleConnect( const ConnectionBase* /*connection*/ )
00162   {
00163     if( m_connection )
00164     {
00165       std::string server = m_server;
00166       int port = m_port;
00167       if( port == -1 )
00168       {
00169         const DNS::HostMap& servers = DNS::resolve( m_server, m_logInstance );
00170         if( !servers.empty() )
00171         {
00172           const std::pair< std::string, int >& host = *servers.begin();
00173           server = host.first;
00174           port = host.second;
00175         }
00176       }
00177       std::string message = "Requesting http proxy connection to " + server + ":"
00178           + util::int2string( port );
00179       m_logInstance.dbg( LogAreaClassConnectionHTTPProxy, message );
00180 
00181       std::string os = "CONNECT " + server + ":" + util::int2string( port ) + " HTTP/1."
00182           + util::int2string( m_http11 ? 1 : 0 ) + "\r\n"
00183           "Host: " + server + "\r\n"
00184           "Content-Length: 0\r\n"
00185           "Proxy-Connection: Keep-Alive\r\n"
00186           "Pragma: no-cache\r\n"
00187           "User-Agent: gloox/" + GLOOX_VERSION + "\r\n";
00188 
00189       if( !m_proxyUser.empty() && !m_proxyPwd.empty() )
00190       {
00191         os += "Proxy-Authorization: Basic " + Base64::encode64( m_proxyUser + ":" + m_proxyPwd )
00192             + "\r\n";
00193       }
00194       os += "\r\n";
00195 
00196       if( !m_connection->send( os ) )
00197       {
00198         m_state = StateDisconnected;
00199         if( m_handler )
00200           m_handler->handleDisconnect( this, ConnIoError );
00201       }
00202     }
00203   }
00204 
00205   void ConnectionHTTPProxy::handleDisconnect( const ConnectionBase* /*connection*/,
00206                                               ConnectionError reason )
00207   {
00208     m_state = StateDisconnected;
00209     m_logInstance.dbg( LogAreaClassConnectionHTTPProxy, "HTTP Proxy connection closed" );
00210 
00211     if( m_handler )
00212       m_handler->handleDisconnect( this, reason );
00213   }
00214 
00215 }