diff options
author | mcorino <mcorino@ae88bc3d-4319-0410-8dbf-d08b4c9d3795> | 2010-07-17 10:29:57 +0000 |
---|---|---|
committer | mcorino <mcorino@ae88bc3d-4319-0410-8dbf-d08b4c9d3795> | 2010-07-17 10:29:57 +0000 |
commit | fc613365076f33584680f484b28d6d5a0691e465 (patch) | |
tree | ee38af158bb6e0847af16873ba98214aad9a034d | |
parent | 40055ec908c4203bad26c8ecd1a462f316e9491c (diff) | |
download | ATCD-fc613365076f33584680f484b28d6d5a0691e465.tar.gz |
Sat Jul 17 10:26:30 UTC 2010 Martin Corino <mcorino@remedy.nl>
* bin/MakeProjectCreator/config/inetssl.mpb:
* bin/MakeProjectCreator/config/inet.mpb:
Added feature project for SSL based parts of INet.
Setting feature ssl=1 will automatically cause correct
dependencies for SSL to be generated in INet based projects.
* protocols/ace/INet/HTTPS_Context.cpp:
* protocols/ace/INet/HTTPS_Context.h:
* protocols/ace/INet/HTTPS_Context.inl:
* protocols/ace/INet/HTTP_SessionBase.cpp:
* protocols/ace/INet/HTTP_SessionBase.h:
* protocols/ace/INet/HTTP_SessionBase.inl:
* protocols/ace/INet/HTTPS_Session.cpp:
* protocols/ace/INet/HTTPS_SessionFactory.cpp:
* protocols/ace/INet/HTTPS_SessionFactory.h:
* protocols/ace/INet/HTTPS_Session.h:
* protocols/ace/INet/HTTPS_URL.cpp:
* protocols/ace/INet/HTTPS_URL.h:
* protocols/ace/INet/HTTPS_URL.inl:
* protocols/ace/INet/SSL_CallbackManager.cpp:
* protocols/ace/INet/SSL_CallbackManager.h:
* protocols/ace/INet/SSL_CallbackManager.inl:
* protocols/ace/INet/SSL_CertificateCallback.cpp:
* protocols/ace/INet/SSL_CertificateCallback.h:
* protocols/ace/INet/SSL_CertificateCallback.inl:
* protocols/ace/INet/SSL_PasswordCallback.cpp:
* protocols/ace/INet/SSL_PasswordCallback.h:
* protocols/ace/INet/SSL_Proxy_Connector.cpp:
* protocols/ace/INet/SSL_Proxy_Connector.h:
* protocols/ace/INet/SSLSock_IOStream.cpp:
* protocols/ace/INet/SSLSock_IOStream.h:
* protocols/ace/INet/SSL_X509Cert.cpp:
* protocols/ace/INet/SSL_X509Cert.h:
* protocols/ace/INet/SSL_X509Cert.inl:
New files implementing SSL/HTTPS support.
Includes support for proxy CONNECT tunneling.
* protocols/ace/INet/inet_ssl.mpb:
Feature project which will include SSL/HTTPS support
into INet when MPC feature ssl=1 is set.
* protocols/ace/INet/ClientRequestHandler.cpp:
* protocols/ace/INet/ClientRequestHandler.h:
* protocols/ace/INet/ConnectionCache.cpp:
* protocols/ace/INet/ConnectionCache.h:
* protocols/ace/INet/FTP_ClientRequestHandler.cpp:
* protocols/ace/INet/FTP_URL.cpp:
* protocols/ace/INet/FTP_URL.h:
* protocols/ace/INet/FTP_URL.inl:
* protocols/ace/INet/HeaderBase.h:
* protocols/ace/INet/HTTP_ClientRequestHandler.cpp:
* protocols/ace/INet/HTTP_ClientRequestHandler.h:
* protocols/ace/INet/HTTP_ClientRequestHandler.inl:
* protocols/ace/INet/HTTP_Session.cpp:
* protocols/ace/INet/HTTP_Session.h:
* protocols/ace/INet/HTTP_StreamPolicyBase.h:
* protocols/ace/INet/HTTP_StreamPolicy.h:
* protocols/ace/INet/HTTP_URL.cpp:
* protocols/ace/INet/HTTP_URL.h:
* protocols/ace/INet/HTTP_URL.inl:
* protocols/ace/INet/inet.mpc:
* protocols/ace/INet/RequestHandler.h:
* protocols/ace/INet/StreamHandler.cpp:
* protocols/ace/INet/StreamInterceptor.h:
* protocols/ace/INet/URLBase.h:
Some redesign to accomodate addition of HTTPS.
Some additional logging.
Some additional documentation.
* protocols/ace/INet/HTTP_Simple_exec.cpp:
Extended to include HTTPS support.
* protocols/tests/INet/MT_Get/Main.cpp:
Added some traces.
58 files changed, 3567 insertions, 540 deletions
diff --git a/ACE/ChangeLog b/ACE/ChangeLog index e31a732c557..e4fb4cb24c4 100644 --- a/ACE/ChangeLog +++ b/ACE/ChangeLog @@ -1,3 +1,80 @@ +Sat Jul 17 10:26:30 UTC 2010 Martin Corino <mcorino@remedy.nl> + + * bin/MakeProjectCreator/config/inetssl.mpb: + * bin/MakeProjectCreator/config/inet.mpb: + Added feature project for SSL based parts of INet. + Setting feature ssl=1 will automatically cause correct + dependencies for SSL to be generated in INet based projects. + + * protocols/ace/INet/HTTPS_Context.cpp: + * protocols/ace/INet/HTTPS_Context.h: + * protocols/ace/INet/HTTPS_Context.inl: + * protocols/ace/INet/HTTP_SessionBase.cpp: + * protocols/ace/INet/HTTP_SessionBase.h: + * protocols/ace/INet/HTTP_SessionBase.inl: + * protocols/ace/INet/HTTPS_Session.cpp: + * protocols/ace/INet/HTTPS_SessionFactory.cpp: + * protocols/ace/INet/HTTPS_SessionFactory.h: + * protocols/ace/INet/HTTPS_Session.h: + * protocols/ace/INet/HTTPS_URL.cpp: + * protocols/ace/INet/HTTPS_URL.h: + * protocols/ace/INet/HTTPS_URL.inl: + * protocols/ace/INet/SSL_CallbackManager.cpp: + * protocols/ace/INet/SSL_CallbackManager.h: + * protocols/ace/INet/SSL_CallbackManager.inl: + * protocols/ace/INet/SSL_CertificateCallback.cpp: + * protocols/ace/INet/SSL_CertificateCallback.h: + * protocols/ace/INet/SSL_CertificateCallback.inl: + * protocols/ace/INet/SSL_PasswordCallback.cpp: + * protocols/ace/INet/SSL_PasswordCallback.h: + * protocols/ace/INet/SSL_Proxy_Connector.cpp: + * protocols/ace/INet/SSL_Proxy_Connector.h: + * protocols/ace/INet/SSLSock_IOStream.cpp: + * protocols/ace/INet/SSLSock_IOStream.h: + * protocols/ace/INet/SSL_X509Cert.cpp: + * protocols/ace/INet/SSL_X509Cert.h: + * protocols/ace/INet/SSL_X509Cert.inl: + New files implementing SSL/HTTPS support. + Includes support for proxy CONNECT tunneling. + + * protocols/ace/INet/inet_ssl.mpb: + Feature project which will include SSL/HTTPS support + into INet when MPC feature ssl=1 is set. + + * protocols/ace/INet/ClientRequestHandler.cpp: + * protocols/ace/INet/ClientRequestHandler.h: + * protocols/ace/INet/ConnectionCache.cpp: + * protocols/ace/INet/ConnectionCache.h: + * protocols/ace/INet/FTP_ClientRequestHandler.cpp: + * protocols/ace/INet/FTP_URL.cpp: + * protocols/ace/INet/FTP_URL.h: + * protocols/ace/INet/FTP_URL.inl: + * protocols/ace/INet/HeaderBase.h: + * protocols/ace/INet/HTTP_ClientRequestHandler.cpp: + * protocols/ace/INet/HTTP_ClientRequestHandler.h: + * protocols/ace/INet/HTTP_ClientRequestHandler.inl: + * protocols/ace/INet/HTTP_Session.cpp: + * protocols/ace/INet/HTTP_Session.h: + * protocols/ace/INet/HTTP_StreamPolicyBase.h: + * protocols/ace/INet/HTTP_StreamPolicy.h: + * protocols/ace/INet/HTTP_URL.cpp: + * protocols/ace/INet/HTTP_URL.h: + * protocols/ace/INet/HTTP_URL.inl: + * protocols/ace/INet/inet.mpc: + * protocols/ace/INet/RequestHandler.h: + * protocols/ace/INet/StreamHandler.cpp: + * protocols/ace/INet/StreamInterceptor.h: + * protocols/ace/INet/URLBase.h: + Some redesign to accomodate addition of HTTPS. + Some additional logging. + Some additional documentation. + + * protocols/ace/INet/HTTP_Simple_exec.cpp: + Extended to include HTTPS support. + + * protocols/tests/INet/MT_Get/Main.cpp: + Added some traces. + Fri Jul 16 22:08:05 UTC 2010 Phil Mesnier <mesnier_p@ociweb.com> * ace/Service_Gestalt.h: diff --git a/ACE/bin/MakeProjectCreator/config/inet.mpb b/ACE/bin/MakeProjectCreator/config/inet.mpb index 56efc1b9542..e596af03f56 100644 --- a/ACE/bin/MakeProjectCreator/config/inet.mpb +++ b/ACE/bin/MakeProjectCreator/config/inet.mpb @@ -1,7 +1,7 @@ // -*- MPC -*- // $Id$ -project : acelib { +project : acelib, inetssl { avoids += wince avoids += old_stdstream after += INet diff --git a/ACE/bin/MakeProjectCreator/config/inetssl.mpb b/ACE/bin/MakeProjectCreator/config/inetssl.mpb new file mode 100644 index 00000000000..92e0d5d7036 --- /dev/null +++ b/ACE/bin/MakeProjectCreator/config/inetssl.mpb @@ -0,0 +1,2 @@ +feature(ssl) : ssl { +} diff --git a/ACE/protocols/ace/INet/ClientRequestHandler.cpp b/ACE/protocols/ace/INet/ClientRequestHandler.cpp index 5f58ff8d053..3a0a12d6eb5 100644 --- a/ACE/protocols/ace/INet/ClientRequestHandler.cpp +++ b/ACE/protocols/ace/INet/ClientRequestHandler.cpp @@ -57,8 +57,13 @@ namespace ACE bool ClientINetRequestHandler::INetConnectionKey::equal (const ConnectionKey& key) const { - const INetConnectionKey& ikey = dynamic_cast<const INetConnectionKey&> (key); - return this->host_ == ikey.host_ && this->port_ == ikey.port_; + try { + const INetConnectionKey& ikey = dynamic_cast<const INetConnectionKey&> (key); + return this->host_ == ikey.host_ && this->port_ == ikey.port_; + } + catch (...) { + return false; + } } } diff --git a/ACE/protocols/ace/INet/ClientRequestHandler.h b/ACE/protocols/ace/INet/ClientRequestHandler.h index 227934c89e7..212adeb98d8 100644 --- a/ACE/protocols/ace/INet/ClientRequestHandler.h +++ b/ACE/protocols/ace/INet/ClientRequestHandler.h @@ -67,7 +67,6 @@ namespace ACE ClientINetRequestHandler (); virtual ~ClientINetRequestHandler (); - protected: /** * @class ACE_INet_INetConnectionKey * diff --git a/ACE/protocols/ace/INet/ConnectionCache.cpp b/ACE/protocols/ace/INet/ConnectionCache.cpp index dda10d74208..ed3bb000b92 100644 --- a/ACE/protocols/ace/INet/ConnectionCache.cpp +++ b/ACE/protocols/ace/INet/ConnectionCache.cpp @@ -153,8 +153,8 @@ namespace ACE } else { - ACE_ERROR ((LM_ERROR, ACE_TEXT ("%P|%t) ConnectionCache::claim_existing_connection - ") - ACE_TEXT ("failed to claim connection entry"))); + INET_ERROR (1, (LM_ERROR, DLINFO ACE_TEXT ("ConnectionCache::claim_existing_connection - ") + ACE_TEXT ("failed to claim connection entry"))); } } } @@ -181,6 +181,8 @@ namespace ACE if (this->claim_existing_connection (key, connection, state)) { + INET_DEBUG (9, (LM_INFO, DLINFO ACE_TEXT ("%P|%t) ConnectionCache::claim_connection - ") + ACE_TEXT ("successfully claimed existing connection\n"))); return true; } @@ -193,8 +195,8 @@ namespace ACE { if (!this->set_connection (key, ConnectionCacheValue ())) { - ACE_ERROR ((LM_ERROR, ACE_TEXT ("%P|%t) ConnectionCache::claim_connection - ") - ACE_TEXT ("failed to initialize connection entry"))); + INET_ERROR (1, (LM_ERROR, DLINFO ACE_TEXT ("ConnectionCache::claim_connection - ") + ACE_TEXT ("failed to initialize connection entry"))); return false; } @@ -202,13 +204,17 @@ namespace ACE } else { + INET_DEBUG (9, (LM_INFO, DLINFO ACE_TEXT ("ConnectionCache::claim_connection - ") + ACE_TEXT ("waiting for connection to become available\n"))); // wait for connection to become ready/free if (this->condition_.wait () != 0) { - ACE_ERROR ((LM_ERROR, ACE_TEXT ("%P|%t) ConnectionCache::claim_connection - ") - ACE_TEXT ("error waiting for connection condition (%p)\n"))); + INET_ERROR (1, (LM_ERROR, DLINFO ACE_TEXT ("(%P|%t) ConnectionCache::claim_connection - ") + ACE_TEXT ("error waiting for connection condition (%p)\n"))); return false; } + INET_DEBUG (9, (LM_INFO, DLINFO ACE_TEXT ("ConnectionCache::claim_connection - ") + ACE_TEXT ("awoken and retrying to claim connection\n"))); } } while (0); @@ -218,6 +224,9 @@ namespace ACE connection = connection_factory.create_connection (key); if (connection) { + INET_DEBUG (9, (LM_INFO, DLINFO ACE_TEXT ("ConnectionCache::claim_connection - ") + ACE_TEXT ("successfully created new connection\n"))); + ACE_MT (ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, guard_, this->lock_, @@ -227,6 +236,8 @@ namespace ACE cacheval.state (ConnectionCacheValue::CST_BUSY); return this->set_connection (key, cacheval); } + else + return false; } } } @@ -236,6 +247,9 @@ namespace ACE { INET_TRACE ("ConnectionCache::release_connection"); + INET_DEBUG (9, (LM_INFO, DLINFO ACE_TEXT ("ConnectionCache::release_connection - ") + ACE_TEXT ("releasing connection\n"))); + ACE_MT (ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, guard_, this->lock_, @@ -255,8 +269,8 @@ namespace ACE } else { - ACE_ERROR ((LM_ERROR, ACE_TEXT ("%P|%t) ConnectionCache::release_connection - ") - ACE_TEXT ("failed to release connection entry"))); + INET_ERROR (1, (LM_ERROR, DLINFO ACE_TEXT ("ConnectionCache::release_connection - ") + ACE_TEXT ("failed to release connection entry"))); return false; } } @@ -269,6 +283,9 @@ namespace ACE { INET_TRACE ("ConnectionCache::close_connection"); + INET_DEBUG (9, (LM_INFO, DLINFO ACE_TEXT ("ConnectionCache::close_connection - ") + ACE_TEXT ("closing connection\n"))); + ACE_MT (ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, guard_, this->lock_, @@ -291,8 +308,8 @@ namespace ACE } else { - ACE_ERROR ((LM_ERROR, ACE_TEXT ("%P|%t) ConnectionCache::close_connection - ") - ACE_TEXT ("failed to close connection entry"))); + INET_ERROR (1, (LM_ERROR, DLINFO ACE_TEXT ("ConnectionCache::close_connection - ") + ACE_TEXT ("failed to close connection entry"))); return false; } } diff --git a/ACE/protocols/ace/INet/ConnectionCache.h b/ACE/protocols/ace/INet/ConnectionCache.h index 194f4fc67fa..0776fe295da 100644 --- a/ACE/protocols/ace/INet/ConnectionCache.h +++ b/ACE/protocols/ace/INet/ConnectionCache.h @@ -31,7 +31,7 @@ namespace ACE * @brief Base class for connection keys. * */ - class ConnectionKey + class ACE_INET_Export ConnectionKey { public: ConnectionKey (); @@ -85,7 +85,7 @@ namespace ACE * @brief Generic base for connection wrappers. * */ - class ConnectionHolder + class ACE_INET_Export ConnectionHolder { public: virtual ~ConnectionHolder (); @@ -103,7 +103,7 @@ namespace ACE * return those for caching wrapped in a connection * holder. */ - class ConnectionFactory + class ACE_INET_Export ConnectionFactory { public: ConnectionFactory (); diff --git a/ACE/protocols/ace/INet/FTP_ClientRequestHandler.cpp b/ACE/protocols/ace/INet/FTP_ClientRequestHandler.cpp index 08d2f2686ee..0234c74fb10 100644 --- a/ACE/protocols/ace/INet/FTP_ClientRequestHandler.cpp +++ b/ACE/protocols/ace/INet/FTP_ClientRequestHandler.cpp @@ -79,7 +79,7 @@ namespace ACE const ACE_CString& ClientRequestHandler::Authentication::scheme () const { - return URL::PROTOCOL; + return URL::protocol (); } const ACE_CString& ClientRequestHandler::Authentication::realm () const diff --git a/ACE/protocols/ace/INet/FTP_URL.cpp b/ACE/protocols/ace/INet/FTP_URL.cpp index 3a07ad3c965..b6a8118a2d0 100644 --- a/ACE/protocols/ace/INet/FTP_URL.cpp +++ b/ACE/protocols/ace/INet/FTP_URL.cpp @@ -15,7 +15,13 @@ namespace ACE { namespace FTP { - const ACE_CString URL::PROTOCOL ("ftp"); + const char* URL::PROTOCOL = "ftp"; + + const ACE_CString& URL::protocol () + { + static const ACE_CString protocol_ (PROTOCOL); + return protocol_; + } URL::URL () : URL_INetAuthBase (FTP_PORT) @@ -75,7 +81,7 @@ namespace ACE const ACE_CString& URL::Factory::protocol () { - return URL::PROTOCOL; + return URL::protocol (); } ACE::INet::URL_Base* URL::Factory::create_from_string (const ACE_CString& url_string) diff --git a/ACE/protocols/ace/INet/FTP_URL.h b/ACE/protocols/ace/INet/FTP_URL.h index d33cfd29732..68f505e550d 100644 --- a/ACE/protocols/ace/INet/FTP_URL.h +++ b/ACE/protocols/ace/INet/FTP_URL.h @@ -49,7 +49,9 @@ namespace ACE virtual u_short default_port () const; - static const ACE_CString PROTOCOL; + static const char* PROTOCOL; + + static const ACE_CString& protocol (); enum { diff --git a/ACE/protocols/ace/INet/FTP_URL.inl b/ACE/protocols/ace/INet/FTP_URL.inl index b5ae8aebde6..0a5cd7fb23d 100644 --- a/ACE/protocols/ace/INet/FTP_URL.inl +++ b/ACE/protocols/ace/INet/FTP_URL.inl @@ -12,7 +12,7 @@ namespace ACE ACE_INLINE const ACE_CString& URL::get_scheme () const { - return PROTOCOL; + return protocol (); } ACE_INLINE diff --git a/ACE/protocols/ace/INet/HTTPS_Context.cpp b/ACE/protocols/ace/INet/HTTPS_Context.cpp new file mode 100644 index 00000000000..6eff53b4daf --- /dev/null +++ b/ACE/protocols/ace/INet/HTTPS_Context.cpp @@ -0,0 +1,125 @@ +// $Id$ + +#include "ace/INet/HTTPS_Context.h" + +#if !defined (__ACE_INLINE__) +#include "ace/INet/HTTPS_Context.inl" +#endif + +#include "ace/OS_NS_stdlib.h" +#include "ace/OS_NS_unistd.h" +#include "ace/OS_NS_sys_stat.h" +#include "ace/INet/INet_Log.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +namespace ACE +{ + namespace HTTPS + { + + int Context::ssl_mode_ = ACE_SSL_Context::SSLv3; + bool Context::ssl_strict_ = false; + bool Context::ssl_once_ = true; + int Context::ssl_depth_ = 0; + bool Context::ssl_verify_peer_ = true; + + Context::Context (bool verify_peer, + bool strict, + bool once, + int depth, + int ssl_mode, + ACE_SSL_Context* ssl_ctx, + bool release, + ACE::INet::SSL_CallbackManager* ssl_cbmngr) + : ssl_ctx_ (0) + { + if (ssl_ctx == 0) + { + ACE_NEW_NORETURN (ssl_ctx, ACE_SSL_Context ()); + release = true; + } + if (ssl_ctx != 0) + { + if (release) + { + this->alloc_safe.reset (ssl_ctx); + } + this->ssl_ctx_ = ssl_ctx; + + this->ssl_ctx_->set_mode (ssl_mode); + if (verify_peer) + this->ssl_ctx_->set_verify_peer (strict ? 1 : 0, + once ? 1 : 0, + depth); + if (ssl_cbmngr != 0) + ssl_cbmngr->initialize_callbacks (this->ssl_ctx_); + // do this to be sure that these settings have been properly set + // ACE_SSL_Context does not handle this quite correctly + ::SSL_CTX_set_verify (this->ssl_ctx_->context (), + this->ssl_ctx_->default_verify_mode (), + this->ssl_ctx_->default_verify_callback ()); + INET_DEBUG (9,(LM_INFO, DLINFO + ACE_TEXT ("HTTPS_Context::ctor - ") + ACE_TEXT ("ssl_mode = [%d], ") + ACE_TEXT ("verify_peer = [%d], ") + ACE_TEXT ("verify_mode = [%d]\n"), + this->ssl_ctx_->get_mode (), + (verify_peer ? 1 : 0), + this->ssl_ctx_->default_verify_mode ())); + } + } + + Context::Context (ACE_SSL_Context* ssl_ctx, + bool release, + ACE::INet::SSL_CallbackManager* ssl_cbmngr) + : ssl_ctx_ (ssl_ctx) + { + if (this->ssl_ctx_ != 0) + { + if (release) + this->alloc_safe.reset (this->ssl_ctx_); + + if (ssl_cbmngr != 0) + ssl_cbmngr->initialize_callbacks (this->ssl_ctx_); + } + } + + Context& Context::instance () + { + return *ACE_Unmanaged_Singleton<Context, ACE_SYNCH::MUTEX>::instance (); + } + + Context::Context (const Context&) + { + } + + Context::~Context () + { + } + + bool Context::load_trusted_ca (const char* ca_location) + { + ACE_stat stat; + if (ca_location != 0 && ACE_OS::stat (ca_location, &stat) == 0) + { + bool is_dir = ((stat.st_mode & S_IFMT) == S_IFDIR); + if (this->ssl_ctx_->load_trusted_ca (is_dir ? 0 : ca_location, + is_dir ? ca_location : 0, + false) == 0) + return true; + } + else + { + INET_ERROR (1, (LM_ERROR, DLINFO + ACE_TEXT ("Context::load_trusted_ca - ") + ACE_TEXT ("invalid ca_location [%C]\n"), + ca_location == 0 ? "(null)" : ca_location)); + } + return false; + } + + } +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/ACE/protocols/ace/INet/HTTPS_Context.h b/ACE/protocols/ace/INet/HTTPS_Context.h new file mode 100644 index 00000000000..713bd7dde97 --- /dev/null +++ b/ACE/protocols/ace/INet/HTTPS_Context.h @@ -0,0 +1,105 @@ +// $Id$ + +/** + * @file HTTPS_Context.h + * + * @author Martin Corino <mcorino@remedy.nl> + */ + +#ifndef ACE_HTTPS_CONTEXT_H +#define ACE_HTTPS_CONTEXT_H + +#include /**/ "ace/pre.h" + +#include "ace/SString.h" +#include "ace/Auto_Ptr.h" +#include "ace/Singleton.h" +#include "ace/SSL/SSL_Context.h" +#include "ace/INet/SSL_CallbackManager.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +namespace ACE + { + namespace HTTPS + { + /** + * @class ACE_HTTPS_Context + * + * @brief Implements security (SSL) context for HTTPS sessions. + * + */ + class ACE_INET_Export Context + { + public: + Context (bool verify_peer = Context::ssl_verify_peer_, + bool strict = Context::ssl_strict_, + bool once = Context::ssl_once_, + int depth = Context::ssl_depth_, + int ssl_mode = Context::ssl_mode_, + ACE_SSL_Context* ssl_ctx = + ACE_SSL_Context::instance (), + bool release = false, + ACE::INet::SSL_CallbackManager* ssl_cbmngr = + ACE::INet::SSL_CallbackManager::instance ()); + + Context (ACE_SSL_Context* ssl_ctx, + bool release = false, + ACE::INet::SSL_CallbackManager* ssl_cbmngr = 0); + + ~Context (); + + operator bool (void) const; + + bool operator ! (void) const; + + ACE_SSL_Context& ssl_context (void); + + const ACE_SSL_Context& ssl_context (void) const; + + bool use_default_ca (); + + bool set_key_files (const char* certificate_filename, + const char* private_key_filename, + int file_type = SSL_FILETYPE_PEM); + + bool load_trusted_ca (const char* ca_location); + + int has_trusted_ca (); + + static void set_default_ssl_mode (int ssl_mode); + + static void set_default_verify_mode (bool verify_peer); + + static void set_default_verify_settings (bool strict, + bool once = true, + int depth = 0); + + static Context& instance (); + + private: + friend class ACE_Singleton<Context, ACE_SYNCH::MUTEX>; + + //Context (); + Context (const Context&); + + ACE_SSL_Context* ssl_ctx_; + ACE_Auto_Ptr<ACE_SSL_Context> alloc_safe; + + static int ssl_mode_; + static bool ssl_strict_; + static bool ssl_once_; + static int ssl_depth_; + static bool ssl_verify_peer_; + }; + } + } + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/INet/HTTPS_Context.inl" +#endif + +#include /**/ "ace/post.h" +#endif /* ACE_SSL_CALLBACKMANAGER_H */ diff --git a/ACE/protocols/ace/INet/HTTPS_Context.inl b/ACE/protocols/ace/INet/HTTPS_Context.inl new file mode 100644 index 00000000000..d4aaee7e8c8 --- /dev/null +++ b/ACE/protocols/ace/INet/HTTPS_Context.inl @@ -0,0 +1,94 @@ +// -*- C++ -*- +// +// $Id$ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +namespace ACE +{ + namespace HTTPS + { + + ACE_INLINE + Context::operator bool (void) const + { + return this->ssl_ctx_ != 0; + } + + ACE_INLINE + bool Context::operator ! (void) const + { + return this->ssl_ctx_ == 0; + } + + ACE_INLINE + ACE_SSL_Context& Context::ssl_context (void) + { + return *this->ssl_ctx_; + } + + ACE_INLINE + const ACE_SSL_Context& Context::ssl_context (void) const + { + return *this->ssl_ctx_; + } + + ACE_INLINE + bool Context::use_default_ca () + { + if (::SSL_CTX_set_default_verify_paths(this->ssl_ctx_->context ()) != 1) + { + ACE_SSL_Context::report_error (); + return false; + } + return true; + } + + ACE_INLINE + bool Context::set_key_files (const char* certificate_filename, + const char* private_key_filename, + int file_type) + { + if (this->ssl_ctx_->certificate (certificate_filename, file_type) == 0) + { + if (this->ssl_ctx_->private_key (private_key_filename, file_type) == 0) + { + return true; + } + } + return false; + } + + ACE_INLINE + int Context::has_trusted_ca () + { + return this->ssl_ctx_->have_trusted_ca (); + } + + ACE_INLINE + void Context::set_default_ssl_mode (int ssl_mode) + { + Context::ssl_mode_ = ssl_mode; + } + + ACE_INLINE + void Context::set_default_verify_mode (bool verify_peer) + { + Context::ssl_verify_peer_ = verify_peer; + } + + ACE_INLINE + void Context::set_default_verify_settings (bool strict, + bool once, + int depth) + { + Context::ssl_strict_ = strict; + Context::ssl_once_ = once; + Context::ssl_depth_ = depth; + } + + + } +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/ACE/protocols/ace/INet/HTTPS_Session.cpp b/ACE/protocols/ace/INet/HTTPS_Session.cpp new file mode 100644 index 00000000000..da6098dfc1a --- /dev/null +++ b/ACE/protocols/ace/INet/HTTPS_Session.cpp @@ -0,0 +1,265 @@ +// $Id$ + +#ifndef ACE_HTTPS_SESSION_CPP +#define ACE_HTTPS_SESSION_CPP + +#include "ace/INet/HTTPS_Session.h" +#include "ace/INet/INet_Log.h" +#include "ace/INet/IOS_util.h" +#include "ace/INet/HTTPS_URL.h" +#include "ace/INet/Sock_IOStream.h" +#include "ace/INet/String_IOStream.h" +#include "ace/INet/SSL_Proxy_Connector.h" +#include "ace/INET_Addr.h" +#include "ace/Event_Handler.h" +#include "ace/Connector.h" +#include "ace/SSL/SSL_SOCK_Connector.h" +#include "ace/String_Base.h" +#include <istream> +#include <ostream> + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +namespace ACE +{ + namespace HTTPS + { + + template <ACE_SYNCH_DECL> + Session_T<ACE_SYNCH_USE>::Session_T (bool keep_alive, Context& ctx) + : SessionBase (URL::HTTPS_PORT, keep_alive), + connection_ (0), + sock_stream_ (0), + context_ (ctx) + { + INET_TRACE ("ACE_HTTPS_Session - ctor"); + } + + template <ACE_SYNCH_DECL> + Session_T<ACE_SYNCH_USE>::Session_T (const ACE_Time_Value& timeout, + bool keep_alive, + const ACE_Time_Value* alive_timeout, + Context& ctx) + : SessionBase (URL::HTTPS_PORT, timeout, keep_alive, alive_timeout), + connection_ (0), + sock_stream_ (0), + context_ (ctx) + { + INET_TRACE ("ACE_HTTPS_Session - ctor"); + this->close_streams (); + this->close_connection (); + } + + template <ACE_SYNCH_DECL> + Session_T<ACE_SYNCH_USE>::~Session_T () + { + INET_TRACE ("ACE_HTTPS_Session - dtor"); + } + + template <ACE_SYNCH_DECL> + bool Session_T<ACE_SYNCH_USE>::is_connected () const + { + return this->connection_ && this->connection_->is_connected (); + } + + template <ACE_SYNCH_DECL> + bool Session_T<ACE_SYNCH_USE>::connect_i (const ACE_Synch_Options& sync_opt) + { + INET_TRACE ("ACE_HTTPS_Session::connect_i"); + + connection_type* new_connection = 0; + + if (this->is_proxy_connection ()) + { + typedef ACE::IOS::StreamHandler<ACE_SOCK_STREAM, ACE_SYNCH_USE> proxy_connection_type; + typedef ACE_Connector<proxy_connection_type, ACE_SOCK_CONNECTOR> proxy_connector_type; + typedef ACE::IOS::Sock_IOStreamBase<ACE_SYNCH_USE> proxy_stream_type; + + proxy_connection_type proxy_connection(sync_opt); + proxy_connector_type proxy_connector; + + proxy_connection_type* proxy_connection_ptr = &proxy_connection; + if (proxy_connector.connect (proxy_connection_ptr, + ACE_INET_Addr (this->port_, + this->host_.c_str ()), + ACE_Synch_Options (0,this->http_timeout_)) == -1) + { + INET_ERROR (1, (LM_ERROR, DLINFO + ACE_TEXT ("(%d) ACE_HTTPS_Session::connect_i - ") + ACE_TEXT ("failed to connect to proxy; host=%C, port=%d\n"), + ACE_OS::last_error (), this->host_.c_str (), this->port_)); + return false; + } + + proxy_stream_type proxy_stream (&proxy_connection); + ACE::IOS::CString_OStream target_address; + target_address << this->proxy_target_host_ << ':' << this->proxy_target_port_; + ACE::HTTP::Request connect_request (ACE::HTTP::Request::HTTP_CONNECT, + target_address.str ().c_str (), + ACE::HTTP::Request::HTTP_1_1); + connect_request.set("Proxy-Connection", "keep-alive"); + connect_request.set_host(this->proxy_target_host_); + ACE::HTTP::Response connect_response; + + connect_request.write (proxy_stream); + proxy_stream.flush (); + if (!connect_response.read (proxy_stream) || + !connect_response.get_status ().is_ok ()) + { + INET_ERROR (1, (LM_ERROR, DLINFO + ACE_TEXT ("ACE_HTTPS_Session::connect_i - ") + ACE_TEXT ("cannot setup proxy tunnel; proxy replied: %d:%C\n"), + connect_response.get_status ().get_status(), + connect_response.get_status ().get_reason().c_str ())); + return false; + } + + ACE_NEW_RETURN (new_connection, + connection_type(sync_opt), + false); + // set the provided SSL context for the SSL structure of the SSL_SOCK_Stream + ::SSL * ssl_ptr = new_connection->peer ().ssl (); + ::SSL_set_SSL_CTX (ssl_ptr, this->context_.ssl_context ().context ()); + + ACE_HANDLE proxy_conn_handle = proxy_connection.peer ().get_handle (); + proxy_connection.peer ().set_handle (ACE_INVALID_HANDLE); + + ACE::INet::SSL_Proxy_Connector proxy_ssl_connector; + ACE_Time_Value conn_timeout (this->http_timeout_); + if (proxy_ssl_connector.connect (new_connection->peer (), + proxy_conn_handle, + &conn_timeout) != 0) + { + INET_ERROR (1, (LM_ERROR, DLINFO + ACE_TEXT ("ACE_HTTPS_Session::connect_i - ") + ACE_TEXT ("failed to setup proxy SSL connection\n"))); + return false; + } + new_connection->open (); // mark stream handler as connected + } + else + { + ACE_NEW_RETURN (new_connection, + connection_type(sync_opt), + false); + // set the provided SSL context for the SSL structure of the SSL_SOCK_Stream + ::SSL * ssl_ptr = new_connection->peer ().ssl (); + ::SSL_set_SSL_CTX (ssl_ptr, this->context_.ssl_context ().context ()); + + typedef ACE_Connector<connection_type, ACE_SSL_SOCK_Connector> connector_type; + + connector_type connector; + + if (connector.connect (new_connection, + ACE_INET_Addr (this->port_, + this->host_.c_str ()), + ACE_Synch_Options (0,this->http_timeout_)) == -1) + { + INET_ERROR (1, (LM_ERROR, DLINFO + ACE_TEXT ("(%d) ACE_HTTPS_Session::connect_i - ") + ACE_TEXT ("failed to connect; host=%C, port=%d\n"), + ACE_OS::last_error (), this->host_.c_str (), this->port_)); + // as the connection was dynamically allocated + // the connector causes it to be destroyed after + // the connection failure + return false; + } + } + + this->connection_ = new_connection; + this->connection_->reference_counting_policy ().value ( + ACE_Event_Handler::Reference_Counting_Policy::ENABLED); + + ACE_NEW_NORETURN (this->sock_stream_, + sock_stream_type (this->connection_)); + if (this->sock_stream_) + { + this->cannot_reconnect_ = false; + this->reactive_ = sync_opt[ACE_Synch_Options::USE_REACTOR]; + + // reset reconnect timer + this->reconnect_timer_ = this->keep_alive_timeout_; + this->reconnect_countdown_.start (); + + return true; + } + else + { + this->close (); + return false; + } + } + + template <ACE_SYNCH_DECL> + bool Session_T<ACE_SYNCH_USE>::attach_connection (connection_type* connection) + { + INET_TRACE ("ACE_HTTPS_Session::attach_connection"); + + if (!connection->is_connected ()) + return false; + + this->close (); + + ACE_INET_Addr remote; + connection->peer ().get_remote_addr (remote); + this->host_ = remote.get_host_name (); + this->port_ = remote.get_port_number (); + + this->connection_ = connection; + this->connection_->add_reference (); + + ACE_NEW_NORETURN (this->sock_stream_, + sock_stream_type (this->connection_)); + + if (this->sock_stream_) + { + this->keep_alive_ = true; + this->keep_alive_timeout_ = ACE_Time_Value::zero; + this->cannot_reconnect_ = true; + return true; + } + else + { + this->close (); + return false; + } + } + + template <ACE_SYNCH_DECL> + void Session_T<ACE_SYNCH_USE>::close_connection () + { + if (this->sock_stream_) + { + delete this->sock_stream_; + this->sock_stream_ = 0; + } + + if (this->connection_) + { + // this should be the last referece and removing it + // causes the connection to be destroyed + this->connection_->remove_reference (); + this->connection_ = 0; + } + } + + template <ACE_SYNCH_DECL> + void Session_T<ACE_SYNCH_USE>::close_i () + { + INET_TRACE ("ACE_HTTPS_Session::close_i"); + + this->close_connection (); + } + + template <ACE_SYNCH_DECL> + std::iostream& Session_T<ACE_SYNCH_USE>::sock_stream () + { + return *this->sock_stream_; + } + + } +} + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* ACE_HTTPS_SESSION_CPP */ diff --git a/ACE/protocols/ace/INet/HTTPS_Session.h b/ACE/protocols/ace/INet/HTTPS_Session.h new file mode 100644 index 00000000000..5738ced375e --- /dev/null +++ b/ACE/protocols/ace/INet/HTTPS_Session.h @@ -0,0 +1,85 @@ +// $Id$ + +/** + * @file HTTPS_Session.h + * + * @author Martin Corino <mcorino@remedy.nl> + */ + +#ifndef ACE_HTTPS_SESSION_H +#define ACE_HTTPS_SESSION_H + +#include /**/ "ace/pre.h" + +#include "ace/SSL/SSL_SOCK_Connector.h" +#include "ace/INet/HTTP_SessionBase.h" +#include "ace/INet/StreamHandler.h" +#include "ace/INet/SSLSock_IOStream.h" +#include "ace/INet/HTTPS_Context.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +namespace ACE + { + namespace HTTPS + { + /** + * @class ACE_HTTPS_Session + * + * @brief Encapsulates HTTPS session. + * + */ + template <ACE_SYNCH_DECL> + class Session_T : public ACE::HTTP::SessionBase + { + public: + typedef ACE::IOS::StreamHandler<ACE_SSL_SOCK_Stream, ACE_SYNCH_USE> connection_type; + + Session_T (bool keep_alive = true, + Context& ctx = Context::instance ()); + + Session_T (const ACE_Time_Value& timeout, + bool keep_alive = true, + const ACE_Time_Value* alive_timeout = 0, + Context& ctx = Context::instance ()); + + virtual ~Session_T (); + + virtual bool is_connected () const; + + bool attach_connection (connection_type* connection); + + protected: + + void close_connection (); + + virtual bool connect_i (const ACE_Synch_Options& sync_opt); + + virtual void close_i (); + + virtual std::iostream& sock_stream (); + + private: + typedef ACE::IOS::SSLSock_IOStreamBase<ACE_SYNCH_USE> sock_stream_type; + + connection_type* connection_; + sock_stream_type* sock_stream_; + Context& context_; + }; + + typedef Session_T<ACE_NULL_SYNCH> Session; + } + } + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (ACE_TEMPLATES_REQUIRE_SOURCE) +#include "ace/INet/HTTPS_Session.cpp" +#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */ + +#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA) +#pragma implementation ("HTTPS_Session.cpp") +#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */ + +#include /**/ "ace/post.h" +#endif /* ACE_HTTPS_SESSION_H */ diff --git a/ACE/protocols/ace/INet/HTTPS_SessionFactory.cpp b/ACE/protocols/ace/INet/HTTPS_SessionFactory.cpp new file mode 100644 index 00000000000..787fc56c963 --- /dev/null +++ b/ACE/protocols/ace/INet/HTTPS_SessionFactory.cpp @@ -0,0 +1,77 @@ +// $Id$ + +#include "ace/INet/HTTPS_SessionFactory.h" + +#include "ace/INet/INet_Log.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +namespace ACE +{ + namespace HTTPS + { + + SessionFactory_Impl::SessionHolder_Impl::SessionHolder_Impl () + : session_ (true) + { + } + + SessionFactory_Impl::SessionHolder_Impl::~SessionHolder_Impl() + { + } + + ACE::HTTP::SessionBase& SessionFactory_Impl::SessionHolder_Impl::session () + { + return this->session_; + } + + SessionFactory_Impl& SessionFactory_Impl::factory_ = + *ACE_Singleton<SessionFactory_Impl,ACE_SYNCH::NULL_MUTEX>::instance (); + + SessionFactory_Impl::SessionFactory_Impl () + { + INET_DEBUG (6, (LM_INFO, DLINFO + ACE_TEXT ("HTTPS_SessionFactory_Impl::ctor - ") + ACE_TEXT ("registering session factory for scheme [%C]\n"), + URL::protocol ().c_str ())); + ACE::HTTP::SessionFactoryRegistry::instance ().register_session_factory (URL::protocol (), this); + } + + SessionFactory_Impl::~SessionFactory_Impl () + { + } + + ACE::INet::ConnectionHolder* + SessionFactory_Impl::create_connection ( + const ACE::INet::ConnectionKey& key) const + { + INET_TRACE ("HTTPS_SessionFactory_Impl::create_connection"); + + const ACE::HTTP::ClientRequestHandler::HttpConnectionKey& ikey = + dynamic_cast<const ACE::HTTP::ClientRequestHandler::HttpConnectionKey&> (key); + + SessionHolder_Impl* session_holder = 0; + ACE_NEW_RETURN (session_holder, + SessionHolder_Impl (), + 0); + ACE_Auto_Ptr<SessionHolder_Impl> session_safe_ref (session_holder); + + (*session_holder)->set_host (ikey.host (), ikey.port ()); + if (ikey.is_proxy_connection ()) + { + (*session_holder)->set_proxy_target (ikey.proxy_target_host (), + ikey.proxy_target_port ()); + } + + if ((*session_holder)->connect (true)) + { + return session_safe_ref.release (); + } + + return 0; + } + + } +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/ACE/protocols/ace/INet/HTTPS_SessionFactory.h b/ACE/protocols/ace/INet/HTTPS_SessionFactory.h new file mode 100644 index 00000000000..41dd3da5282 --- /dev/null +++ b/ACE/protocols/ace/INet/HTTPS_SessionFactory.h @@ -0,0 +1,70 @@ +// $Id$ + +/** + * @file HTTPS_SessionFactory.h + * + * @author Martin Corino <mcorino@remedy.nl> + */ + +#ifndef ACE_HTTPS_SESSION_FACTORY_H +#define ACE_HTTPS_SESSION_FACTORY_H + +#include /**/ "ace/pre.h" + +#include /**/ "ace/config-all.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/INet/HTTP_ClientRequestHandler.h" +#include "ace/INet/HTTPS_Session.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +namespace ACE + { + namespace HTTPS + { + /** + * @class ACE_HTTPS_SessionFactory_Impl + * + * @brief Implements HTTPS session factory. + * + */ + class ACE_INET_Export SessionFactory_Impl + : public ACE::HTTP::SessionFactory + { + private: + SessionFactory_Impl (); + virtual ~SessionFactory_Impl (); + + friend class ACE_Singleton<SessionFactory_Impl, ACE_SYNCH::NULL_MUTEX>; + + static SessionFactory_Impl& factory_; + + class SessionHolder_Impl : public ACE::HTTP::SessionHolder + { + public: + SessionHolder_Impl (); + virtual ~SessionHolder_Impl(); + + protected: + virtual ACE::HTTP::SessionBase& session (); + + private: + Session_T<ACE_SYNCH> session_; + }; + + public: + virtual ACE::INet::ConnectionHolder* create_connection ( + const ACE::INet::ConnectionKey& key) const; + }; + + } + } + +ACE_END_VERSIONED_NAMESPACE_DECL + +#include /**/ "ace/post.h" +#endif /* ACE_HTTPS_SESSION_FACTORY_H */ diff --git a/ACE/protocols/ace/INet/HTTPS_URL.cpp b/ACE/protocols/ace/INet/HTTPS_URL.cpp new file mode 100644 index 00000000000..0e0b0e35071 --- /dev/null +++ b/ACE/protocols/ace/INet/HTTPS_URL.cpp @@ -0,0 +1,109 @@ +// $Id$ + +#include "ace/INet/HTTPS_URL.h" + +#if !defined (__ACE_INLINE__) +#include "ace/INet/HTTPS_URL.inl" +#endif + +#include "ace/INet/String_IOStream.h" +#include "ace/INet/HTTP_ClientRequestHandler.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +namespace ACE +{ + namespace HTTPS + { + const char* URL::PROTOCOL = "https"; + + const ACE_CString& URL::protocol () + { + static const ACE_CString protocol_ (PROTOCOL); + return protocol_; + } + + URL::URL () + : ACE::HTTP::URL (HTTPS_PORT) + { + } + + URL::URL (const ACE_CString& url_string) + : ACE::HTTP::URL (HTTPS_PORT) + { + this->parse (url_string); + } + + URL::URL (const URL& url) + : ACE::HTTP::URL (0) + { + *this = url; + } + + URL::~URL () + { + } + + URL& URL::operator =(const URL& url) + { + ACE::HTTP::URL::operator=(url); + return *this; + } + + ACE_CString URL::get_request_uri () const + { + ACE::IOS::CString_OStream sos; +#if 0 + if (!this->proxy_host_.empty ()) + { + sos << this->get_scheme ().c_str () << "://" + << ACE::INet::URL_INetBase::get_host ().c_str (); + if (ACE::INet::URL_INetBase::get_port () != HTTP_PORT) + { + sos << ':' << ACE::INet::URL_INetBase::get_port (); + } + } +#endif + // if path is empty we're requesting the root + sos << (this->get_path ().empty () ? + "/" : + this->get_path ().c_str ()); + if (!this->get_query ().empty ()) + sos << '?' << this->get_query ().c_str (); + if (!this->get_fragment ().empty ()) + sos << '#' << this->get_fragment ().c_str (); + return sos.str (); + } + + ACE::INet::ClientRequestHandler* URL::create_default_request_handler () const + { + ACE::INet::ClientRequestHandler* prh = 0; + ACE_NEW_NORETURN (prh, ACE::HTTP::ClientRequestHandler ()); + return prh; + } + + const URL::Factory& URL::factory_ = *URL::TURLFactorySingleton::instance (); + + URL::Factory::Factory () + { + ACE::INet::URL_Base::register_factory (this); + } + + URL::Factory::~Factory () + {} + + const ACE_CString& URL::Factory::protocol () + { + return URL::protocol (); + } + + ACE::INet::URL_Base* URL::Factory::create_from_string (const ACE_CString& url_string) + { + URL* purl = 0; + ACE_NEW_NORETURN (purl, URL (url_string)); + return purl; + } + } +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/ACE/protocols/ace/INet/HTTPS_URL.h b/ACE/protocols/ace/INet/HTTPS_URL.h new file mode 100644 index 00000000000..b4ab3a53bd4 --- /dev/null +++ b/ACE/protocols/ace/INet/HTTPS_URL.h @@ -0,0 +1,89 @@ +// $Id$ + +/** + * @file HTTPS_URL.h + * + * @author Martin Corino <mcorino@remedy.nl> + */ + +#ifndef ACE_HTTPS_URL_H +#define ACE_HTTPS_URL_H + +#include /**/ "ace/pre.h" + +#include /**/ "ace/config-all.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/INet/INet_Export.h" +#include "ace/INet/HTTP_URL.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +namespace ACE + { + namespace HTTPS + { + /** + * @class ACE_HTTPS_URL + * + * @brief Implements HTTPS url support. + * + */ + class ACE_INET_Export URL + : public ACE::HTTP::URL + { + public: + URL (); + URL (const ACE_CString& url_string); + URL (const URL& url); + virtual ~URL (); + + URL& operator =(const URL& url); + + virtual const ACE_CString& get_scheme () const; + + virtual ACE_CString get_request_uri () const; + + virtual u_short default_port () const; + + static const char* PROTOCOL; + + static const ACE_CString& protocol (); + + enum + { + HTTPS_PORT = 443, + }; + + protected: + virtual ACE::INet::ClientRequestHandler* create_default_request_handler () const; + + private: + class Factory + : public ACE::INet::URL_Base::Factory + { + public: + Factory (); + virtual ~Factory (); + virtual const ACE_CString& protocol (); + virtual ACE::INet::URL_Base* create_from_string (const ACE_CString& url_string); + }; + + typedef ACE_Singleton<Factory, + ACE_Null_Mutex> TURLFactorySingleton; + static const Factory& factory_; + }; + } + } + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/INet/HTTPS_URL.inl" +#endif + +#include /**/ "ace/post.h" +#endif /* ACE_HTTPS_URL_H */ diff --git a/ACE/protocols/ace/INet/HTTPS_URL.inl b/ACE/protocols/ace/INet/HTTPS_URL.inl new file mode 100644 index 00000000000..4502825a57c --- /dev/null +++ b/ACE/protocols/ace/INet/HTTPS_URL.inl @@ -0,0 +1,27 @@ +// -*- C++ -*- +// +// $Id$ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +namespace ACE +{ + namespace HTTPS + { + + ACE_INLINE + const ACE_CString& URL::get_scheme () const + { + return protocol (); + } + + ACE_INLINE + u_short URL::default_port () const + { + return HTTPS_PORT; + } + + } +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/ACE/protocols/ace/INet/HTTP_ClientRequestHandler.cpp b/ACE/protocols/ace/INet/HTTP_ClientRequestHandler.cpp index ab2014e36cc..ade87052b37 100644 --- a/ACE/protocols/ace/INet/HTTP_ClientRequestHandler.cpp +++ b/ACE/protocols/ace/INet/HTTP_ClientRequestHandler.cpp @@ -6,9 +6,9 @@ #include "ace/INet/HTTP_ClientRequestHandler.inl" #endif +#include "ace/INet/INet_Log.h" #include "ace/Auto_Ptr.h" - -ACE_RCSID(NET_CLIENT,ACE_HTTP_ClientRequestHandler,"$Id$") +#include "ace/Functor_String.h" ACE_BEGIN_VERSIONED_NAMESPACE_DECL @@ -17,38 +17,96 @@ namespace ACE namespace HTTP { - ClientRequestHandler::SessionHolder::SessionHolder () + SessionFactoryRegistry::SessionFactoryRegistry () + { + } + + SessionFactoryRegistry::~SessionFactoryRegistry () + { + } + + void SessionFactoryRegistry::register_session_factory ( + const ACE_CString& scheme, + SessionFactory* factory) + { + if (factory == 0) + this->factory_map_.unbind (scheme); + else + this->factory_map_.rebind (scheme, factory); + } + + SessionFactory* + SessionFactoryRegistry::find_session_factory (const ACE_CString& scheme) + { + SessionFactory* factory = 0; + this->factory_map_.find (scheme, factory); + return factory; + } + + SessionFactoryRegistry& SessionFactoryRegistry::instance () + { + return *ACE_Singleton<SessionFactoryRegistry, ACE_SYNCH::MUTEX>::instance (); + } + + SessionHolder::SessionHolder () + { + } + + SessionHolder::~SessionHolder() + { + } + + SessionFactory_Impl::SessionHolder_Impl::SessionHolder_Impl () : session_ (true) { } - ClientRequestHandler::SessionHolder::~SessionHolder() + SessionFactory_Impl::SessionHolder_Impl::~SessionHolder_Impl() { } - ClientRequestHandler::SessionFactory::SessionFactory () + SessionBase& SessionFactory_Impl::SessionHolder_Impl::session () + { + return this->session_; + } + + SessionFactory_Impl& SessionFactory_Impl::factory_ = + *ACE_Singleton<SessionFactory_Impl,ACE_SYNCH::NULL_MUTEX>::instance (); + + SessionFactory_Impl::SessionFactory_Impl () { + INET_DEBUG (6, (LM_INFO, DLINFO + ACE_TEXT ("HTTP_SessionFactory_Impl::ctor - ") + ACE_TEXT ("registering session factory for scheme [%C]\n"), + URL::protocol ().c_str ())); + SessionFactoryRegistry::instance ().register_session_factory (URL::protocol (), this); } - ClientRequestHandler::SessionFactory::~SessionFactory () + SessionFactory_Impl::~SessionFactory_Impl () { } ACE::INet::ConnectionHolder* - ClientRequestHandler::SessionFactory::create_connection ( + SessionFactory_Impl::create_connection ( const ACE::INet::ConnectionKey& key) const { - INET_TRACE ("ClientRequestHandler::SessionFactory::create_connection"); + INET_TRACE ("HTTP_SessionFactory_Impl::create_connection"); - const INetConnectionKey& ikey = dynamic_cast<const INetConnectionKey&> (key); + const ClientRequestHandler::HttpConnectionKey& ikey = + dynamic_cast<const ClientRequestHandler::HttpConnectionKey&> (key); - SessionHolder* session_holder = 0; + SessionHolder_Impl* session_holder = 0; ACE_NEW_RETURN (session_holder, - SessionHolder (), + SessionHolder_Impl (), 0); - ACE_Auto_Ptr<SessionHolder> session_safe_ref (session_holder); + ACE_Auto_Ptr<SessionHolder_Impl> session_safe_ref (session_holder); (*session_holder)->set_host (ikey.host (), ikey.port ()); + if (ikey.is_proxy_connection ()) + { + (*session_holder)->set_proxy_target (ikey.proxy_target_host (), + ikey.proxy_target_port ()); + } if ((*session_holder)->connect (true)) { @@ -58,6 +116,77 @@ namespace ACE return 0; } + ClientRequestHandler::HttpConnectionKey::HttpConnectionKey ( + const ACE_CString& host, + u_short port) + : INetConnectionKey (host, port), + proxy_connection_ (false), + proxy_target_port_ (0) + { + } + + ClientRequestHandler::HttpConnectionKey::HttpConnectionKey ( + const ACE_CString& proxy_host, + u_short proxy_port, + const ACE_CString& host, + u_short port) + : INetConnectionKey (proxy_host, proxy_port), + proxy_connection_ (true), + proxy_target_host_ (host), + proxy_target_port_ (port) + { + } + + ClientRequestHandler::HttpConnectionKey::~HttpConnectionKey() + { + } + + u_long ClientRequestHandler::HttpConnectionKey::hash () const + { + if (this->proxy_connection_) + return ACE_Hash<ACE_CString>()(this->proxy_target_host_) + + this->proxy_target_port_ + + (this->proxy_connection_ ? 1 : 0); + else + return INetConnectionKey::hash () + + (this->proxy_connection_ ? 1 : 0); + } + + ACE::INet::ConnectionKey* ClientRequestHandler::HttpConnectionKey::duplicate () const + { + ConnectionKey* k = 0; + if (this->proxy_connection_) + { + ACE_NEW_RETURN (k, + HttpConnectionKey (this->host (), this->port (), + this->proxy_target_host_, + this->proxy_target_port_), + 0); + } + else + { + ACE_NEW_RETURN (k, + HttpConnectionKey (this->host (), this->port ()), + 0); + } + return k; + } + + bool ClientRequestHandler::HttpConnectionKey::equal (const ACE::INet::ConnectionKey& key) const + { + try { + const HttpConnectionKey& http_key = dynamic_cast<const HttpConnectionKey&> (key); + return (INetConnectionKey::equal (key) && + this->proxy_connection_ == http_key.is_proxy_connection () && + (!this->proxy_connection_ || + (this->proxy_target_host_ == http_key.proxy_target_host () && + this->proxy_target_port_ == http_key.proxy_target_port ()))); + } + catch (...) { + return false; + } + } + ClientRequestHandler::ClientRequestHandler () : request_ (Request::HTTP_1_0), session_ (0) @@ -85,12 +214,20 @@ namespace ACE std::istream& ClientRequestHandler::handle_get_request ( const URL& http_url) { - if (this->initialize_connection (http_url.has_proxy () ? - http_url.get_proxy_host () : - http_url.get_host (), - http_url.has_proxy () ? - http_url.get_proxy_port () : - http_url.get_port ())) + bool connected = false; + if (http_url.has_proxy ()) + connected = this->initialize_connection (http_url.get_scheme (), + http_url.get_host(), + http_url.get_port (), + true, + http_url.get_proxy_host(), + http_url.get_proxy_port ()); + else + connected = this->initialize_connection (http_url.get_scheme (), + http_url.get_host(), + http_url.get_port ()); + + if (connected) { this->request_.reset (Request::HTTP_GET, http_url.get_request_uri (), @@ -121,21 +258,47 @@ namespace ACE this->release_connection (); } - bool ClientRequestHandler::initialize_connection (const ACE_CString& host, - u_short port) + bool ClientRequestHandler::initialize_connection (const ACE_CString& scheme, + const ACE_CString& host, + u_short port, + bool proxy_conn, + const ACE_CString& proxy_host, + u_short proxy_port) { - static const SessionFactory session_factory; + SessionFactory* session_factory = + SessionFactoryRegistry::instance ().find_session_factory (scheme); + + if (session_factory == 0) + { + INET_ERROR (1, (LM_ERROR, DLINFO + ACE_TEXT ("ClientRequestHandler::initialize_connection - ") + ACE_TEXT ("unable to find session factory for scheme [%C]\n"), + scheme.c_str ())); + return false; + } ACE::INet::ConnectionHolder* pch = 0; - if (this->connection_cache ().claim_connection (INetConnectionKey (host, port), - pch, - session_factory)) + if (proxy_conn) { - this->session (dynamic_cast<SessionHolder*> (pch)); - return true; + if (!this->connection_cache ().claim_connection (HttpConnectionKey (proxy_host, + proxy_port, + host, + port), + pch, + *session_factory)) + return false; } else - return false; + { + if (!this->connection_cache ().claim_connection (HttpConnectionKey (host, + port), + pch, + *session_factory)) + return false; + } + + this->session (dynamic_cast<SessionHolder*> (pch)); + return true; } void ClientRequestHandler::initialize_request (const URL& /*url*/, Request& /*request*/) @@ -154,10 +317,22 @@ namespace ACE { if (this->session_) { - this->connection_cache ().release_connection ( - INetConnectionKey (this->session ()->get_host (), - this->session ()->get_port ()), - this->session_); + if (this->session ()->is_proxy_connection ()) + { + this->connection_cache ().release_connection ( + HttpConnectionKey (this->session ()->get_host (), + this->session ()->get_port (), + this->session ()->get_proxy_target_host (), + this->session ()->get_proxy_target_port ()), + this->session_); + } + else + { + this->connection_cache ().release_connection ( + HttpConnectionKey (this->session ()->get_host (), + this->session ()->get_port ()), + this->session_); + } this->session_ = 0; } } @@ -166,10 +341,22 @@ namespace ACE { if (this->session_) { - this->connection_cache ().close_connection ( - INetConnectionKey (this->session ()->get_host (), - this->session ()->get_port ()), - this->session_); + if (this->session ()->is_proxy_connection ()) + { + this->connection_cache ().release_connection ( + HttpConnectionKey (this->session ()->get_host (), + this->session ()->get_port (), + this->session ()->get_proxy_target_host (), + this->session ()->get_proxy_target_port ()), + this->session_); + } + else + { + this->connection_cache ().release_connection ( + HttpConnectionKey (this->session ()->get_host (), + this->session ()->get_port ()), + this->session_); + } this->session_ = 0; } } diff --git a/ACE/protocols/ace/INet/HTTP_ClientRequestHandler.h b/ACE/protocols/ace/INet/HTTP_ClientRequestHandler.h index 9e987bc03ba..9cade87bf0e 100644 --- a/ACE/protocols/ace/INet/HTTP_ClientRequestHandler.h +++ b/ACE/protocols/ace/INet/HTTP_ClientRequestHandler.h @@ -18,6 +18,7 @@ #endif /* ACE_LACKS_PRAGMA_ONCE */ #include "ace/Synch_Traits.h" +#include "ace/Singleton.h" #include "ace/Thread_Mutex.h" #include "ace/INet/INet_Export.h" #include "ace/INet/IOS_util.h" @@ -25,8 +26,8 @@ #include "ace/INet/ClientRequestHandler.h" #include "ace/INet/HTTP_Request.h" #include "ace/INet/HTTP_Response.h" -#include "ace/INet/HTTP_Session.h" #include "ace/INet/HTTP_URL.h" +#include "ace/INet/HTTP_Session.h" ACE_BEGIN_VERSIONED_NAMESPACE_DECL @@ -35,10 +36,110 @@ namespace ACE namespace HTTP { /** + * @class ACE_HTTP_SessionHolder + * + * @brief Abstract base class for HTTP session objects. + * + */ + class ACE_INET_Export SessionHolder + : public ACE::INet::ConnectionHolder + { + protected: + SessionHolder (); + virtual ~SessionHolder(); + + virtual SessionBase& session () = 0; + + public: + SessionBase& operator *(); + SessionBase* operator ->(); + }; + + /** + * @class ACE_HTTP_SessionFactory + * + * @brief Abstract base class for HTTP session factories. + * + */ + class ACE_INET_Export SessionFactory + : public ACE::INet::ConnectionFactory + { + protected: + SessionFactory () {} + virtual ~SessionFactory () {} + }; + + /** + * @class ACE_HTTP_SessionFactory_Impl + * + * @brief Implementation of HTTP session factory. + * + */ + class ACE_INET_Export SessionFactory_Impl + : public SessionFactory + { + private: + SessionFactory_Impl (); + virtual ~SessionFactory_Impl (); + + friend class ACE_Singleton<SessionFactory_Impl, ACE_SYNCH::NULL_MUTEX>; + + static SessionFactory_Impl& factory_; + + class SessionHolder_Impl : public SessionHolder + { + public: + SessionHolder_Impl (); + virtual ~SessionHolder_Impl(); + + protected: + virtual SessionBase& session (); + + private: + Session_T<ACE_SYNCH> session_; + }; + + public: + virtual ACE::INet::ConnectionHolder* create_connection ( + const ACE::INet::ConnectionKey& key) const; + }; + + /** + * @class ACE_HTTP_SessionFactoryRegistry + * + * @brief Implements registry of HTTP session factories. + * + */ + class ACE_INET_Export SessionFactoryRegistry + { + private: + SessionFactoryRegistry (); + ~SessionFactoryRegistry (); + + friend class ACE_Singleton<SessionFactoryRegistry, ACE_SYNCH::MUTEX>; + + public: + + void register_session_factory (const ACE_CString& scheme, + SessionFactory* factory); + + SessionFactory* find_session_factory (const ACE_CString& scheme); + + static SessionFactoryRegistry& instance (); + + private: + typedef ACE_Map_Manager<ACE_CString, + SessionFactory*, + ACE_SYNCH::MUTEX> TSessionFactoryMap; + + TSessionFactoryMap factory_map_; + }; + + /** * @class ACE_HTTP_ClientRequestHandler * * @brief This class implements clientside request handling - * for HTTP URLs. + * for HTTP(S) URLs. * * The class supports the HTTP protocol as specified in RFC 2616. */ @@ -74,42 +175,51 @@ namespace ACE virtual std::istream& handle_put_request (const URL& url, std::istream* put_data = 0); */ - protected: - virtual void on_eof (); - class SessionHolder - : public ACE::INet::ConnectionHolder + class HttpConnectionKey + : public INetConnectionKey { public: - typedef Session_T<ACE_SYNCH> session_type; + HttpConnectionKey (const ACE_CString& host, + u_short port); + HttpConnectionKey (const ACE_CString& proxy_host, + u_short proxy_port, + const ACE_CString& target_host, + u_short target_port); + virtual ~HttpConnectionKey(); - SessionHolder (); - virtual ~SessionHolder(); + virtual u_long hash () const; - session_type& operator *(); - session_type* operator ->(); + virtual ConnectionKey* duplicate () const; - private: - session_type session_; - }; + bool is_proxy_connection () const; - class SessionFactory - : public ACE::INet::ConnectionFactory - { - public: - SessionFactory (); - virtual ~SessionFactory (); + const ACE_CString& proxy_target_host () const; + + u_short proxy_target_port () const; + + protected: + virtual bool equal (const ConnectionKey& key) const; - virtual ACE::INet::ConnectionHolder* create_connection ( - const ACE::INet::ConnectionKey& key) const; + private: + bool proxy_connection_; + ACE_CString proxy_target_host_; + u_short proxy_target_port_; }; + protected: + virtual void on_eof (); + SessionHolder& session (); void session (SessionHolder* session); - virtual bool initialize_connection (const ACE_CString& host, - u_short port); + virtual bool initialize_connection (const ACE_CString& scheme, + const ACE_CString& host, + u_short port, + bool proxy_conn = false, + const ACE_CString& proxy_host = Request::EMPTY, + u_short proxy_port = 0); virtual void initialize_request (const URL& url, Request& request); diff --git a/ACE/protocols/ace/INet/HTTP_ClientRequestHandler.inl b/ACE/protocols/ace/INet/HTTP_ClientRequestHandler.inl index 1540651f7af..3e023ecd6e7 100644 --- a/ACE/protocols/ace/INet/HTTP_ClientRequestHandler.inl +++ b/ACE/protocols/ace/INet/HTTP_ClientRequestHandler.inl @@ -9,15 +9,33 @@ namespace ACE namespace HTTP { ACE_INLINE - ClientRequestHandler::SessionHolder::session_type& ClientRequestHandler::SessionHolder::operator *() + SessionBase& SessionHolder::operator *() { - return this->session_; + return this->session (); } ACE_INLINE - ClientRequestHandler::SessionHolder::session_type* ClientRequestHandler::SessionHolder::operator -> () + SessionBase* SessionHolder::operator -> () { - return &this->session_; + return &this->session (); + } + + ACE_INLINE + bool ClientRequestHandler::HttpConnectionKey::is_proxy_connection () const + { + return this->proxy_connection_; + } + + ACE_INLINE + const ACE_CString& ClientRequestHandler::HttpConnectionKey::proxy_target_host () const + { + return this->proxy_target_host_; + } + + ACE_INLINE + u_short ClientRequestHandler::HttpConnectionKey::proxy_target_port () const + { + return this->proxy_target_port_; } ACE_INLINE @@ -45,7 +63,7 @@ namespace ACE } ACE_INLINE - ClientRequestHandler::SessionHolder& ClientRequestHandler::session () + SessionHolder& ClientRequestHandler::session () { return *this->session_; } diff --git a/ACE/protocols/ace/INet/HTTP_Session.cpp b/ACE/protocols/ace/INet/HTTP_Session.cpp index 10d1df95ff6..a0e37795799 100644 --- a/ACE/protocols/ace/INet/HTTP_Session.cpp +++ b/ACE/protocols/ace/INet/HTTP_Session.cpp @@ -3,11 +3,10 @@ #ifndef ACE_HTTP_SESSION_CPP #define ACE_HTTP_SESSION_CPP -#include "ace/INet/INet_Log.h" #include "ace/INet/HTTP_Session.h" -#include "ace/INet/HTTP_StreamPolicy.h" -#include "ace/INet/String_IOStream.h" +#include "ace/INet/INet_Log.h" #include "ace/INet/IOS_util.h" +#include "ace/INet/HTTP_URL.h" #include "ace/INET_Addr.h" #include "ace/Event_Handler.h" #include "ace/Connector.h" @@ -24,20 +23,9 @@ namespace ACE template <ACE_SYNCH_DECL> Session_T<ACE_SYNCH_USE>::Session_T (bool keep_alive) - : port_ (HTTP_PORT), - reactive_ (false), + : SessionBase (URL::HTTP_PORT, keep_alive), connection_ (0), - sock_stream_ (0), - in_stream_ (0), - out_stream_ (0), - http_timeout_ (DEFAULT_TIMEOUT), - keep_alive_timeout_ (DEFAULT_KEEP_ALIVE_TIMEOUT), - reconnect_timer_ (DEFAULT_KEEP_ALIVE_TIMEOUT), - reconnect_countdown_ (&reconnect_timer_), - keep_alive_ (keep_alive), - needs_reconnect_ (false), - cannot_reconnect_ (false), - expects_response_body_ (false) + sock_stream_ (0) { INET_TRACE ("ACE_HTTP_Session - ctor"); } @@ -46,45 +34,19 @@ namespace ACE Session_T<ACE_SYNCH_USE>::Session_T (const ACE_Time_Value& timeout, bool keep_alive, const ACE_Time_Value* alive_timeout) - : port_ (HTTP_PORT), - reactive_ (false), + : SessionBase (URL::HTTP_PORT, timeout, keep_alive, alive_timeout), connection_ (0), - sock_stream_ (0), - in_stream_ (0), - out_stream_ (0), - http_timeout_ (timeout), - keep_alive_timeout_ (DEFAULT_KEEP_ALIVE_TIMEOUT), - reconnect_timer_ (DEFAULT_KEEP_ALIVE_TIMEOUT), - reconnect_countdown_ (&reconnect_timer_), - keep_alive_ (keep_alive), - needs_reconnect_ (false), - cannot_reconnect_ (false), - expects_response_body_ (false) + sock_stream_ (0) { INET_TRACE ("ACE_HTTP_Session - ctor"); - if (keep_alive && alive_timeout) - { - this->keep_alive_timeout_ = *alive_timeout; - } } template <ACE_SYNCH_DECL> Session_T<ACE_SYNCH_USE>::~Session_T () { INET_TRACE ("ACE_HTTP_Session - dtor"); - this->close (); - } - - template <ACE_SYNCH_DECL> - void Session_T<ACE_SYNCH_USE>::set_keep_alive (bool f) - { - this->keep_alive_ = f; - } - - template <ACE_SYNCH_DECL> - bool Session_T<ACE_SYNCH_USE>::keep_alive () const - { - return this->keep_alive_; + this->close_streams (); + this->close_connection (); } template <ACE_SYNCH_DECL> @@ -94,57 +56,12 @@ namespace ACE } template <ACE_SYNCH_DECL> - void Session_T<ACE_SYNCH_USE>::set_host (const ACE_CString& host, u_short port) - { - if (!this->is_connected ()) - { - this->host_ = host; - this->port_ = port; - } - } - - template <ACE_SYNCH_DECL> - void Session_T<ACE_SYNCH_USE>::set_host (const ACE_CString& host) - { - if (!this->is_connected ()) - { - this->host_ = host; - } - } - - template <ACE_SYNCH_DECL> - void Session_T<ACE_SYNCH_USE>::set_port (u_short port) - { - if (!this->is_connected ()) - { - this->port_ = port; - } - } - - template <ACE_SYNCH_DECL> - const ACE_CString& Session_T<ACE_SYNCH_USE>::get_host () const + bool Session_T<ACE_SYNCH_USE>::connect_i (const ACE_Synch_Options& sync_opt) { - return this->host_; - } - - template <ACE_SYNCH_DECL> - u_short Session_T<ACE_SYNCH_USE>::get_port () const - { - return this->port_; - } - - template <ACE_SYNCH_DECL> - bool Session_T<ACE_SYNCH_USE>::connect (bool use_reactor) - { - INET_TRACE ("ACE_HTTP_Session::connect"); + INET_TRACE ("ACE_HTTP_Session::connect_i"); typedef ACE_Connector<connection_type, ACE_SOCK_CONNECTOR> connector_type; - this->close (); - - unsigned long f_reactor = use_reactor ? ACE_Synch_Options::USE_REACTOR : 0; - ACE_Synch_Options sync_opt (ACE_Synch_Options::USE_TIMEOUT | f_reactor, - this->http_timeout_); connector_type connector; connection_type* new_connection = 0; @@ -157,8 +74,8 @@ namespace ACE ACE_Synch_Options (0,this->http_timeout_)) == -1) { INET_ERROR (1, (LM_ERROR, DLINFO - ACE_TEXT ("(%d) ACE_HTTP_Session::connect - ") - ACE_TEXT ("failed to connect; host=%C, port=%d"), + ACE_TEXT ("(%d) ACE_HTTP_Session::connect_i - ") + ACE_TEXT ("failed to connect; host=%C, port=%d\n"), ACE_OS::last_error (), this->host_.c_str (), this->port_)); // as the connection was dynamically allocated // the connector causes it to be destroyed after @@ -175,7 +92,7 @@ namespace ACE if (this->sock_stream_) { this->cannot_reconnect_ = false; - this->reactive_ = use_reactor; + this->reactive_ = sync_opt[ACE_Synch_Options::USE_REACTOR]; // reset reconnect timer this->reconnect_timer_ = this->keep_alive_timeout_; @@ -191,35 +108,19 @@ namespace ACE } template <ACE_SYNCH_DECL> - bool Session_T<ACE_SYNCH_USE>::connect (connection_type* connection) + bool Session_T<ACE_SYNCH_USE>::attach_connection (connection_type* connection) { - INET_TRACE ("ACE_HTTP_Session::connect(connection)"); + INET_TRACE ("ACE_HTTP_Session::attach_connection"); - this->close (); + if (!connection->is_connected ()) + return false; - if (connection->is_connected ()) - { - ACE_INET_Addr remote; - connection->peer ().get_remote_addr (remote); - this->host_ = remote.get_host_name (); - this->port_ = remote.get_port_number (); - } - else - { - typedef ACE_Connector<connection_type, ACE_SOCK_CONNECTOR> connector_type; + this->close (); - connector_type connector; - if (connector.connect (connection, - ACE_INET_Addr (this->host_.c_str (), - this->port_)) == -1) - { - INET_ERROR (1, (LM_ERROR, DLINFO - ACE_TEXT ("(%d) ACE_HTTP_Session::connect(connection) - ") - ACE_TEXT ("failed to connect; host=%C, port=%d"), - ACE_OS::last_error (), this->host_.c_str (), this->port_)); - return false; - } - } + ACE_INET_Addr remote; + connection->peer ().get_remote_addr (remote); + this->host_ = remote.get_host_name (); + this->port_ = remote.get_port_number (); this->connection_ = connection; this->connection_->add_reference (); @@ -242,243 +143,16 @@ namespace ACE } template <ACE_SYNCH_DECL> - std::ostream& Session_T<ACE_SYNCH_USE>::send_request (Request& request) + void Session_T<ACE_SYNCH_USE>::close_connection () { - INET_TRACE ("ACE_HTTP_Session::send_request"); - - if (this->in_stream_) - { - delete this->in_stream_; - this->in_stream_ = 0; - } - - bool keep_alive = this->keep_alive (); - if ((this->is_connected () && !keep_alive) || this->reconnect_needed ()) - { - close(); - this->needs_reconnect_ = false; - } - - if (this->out_stream_) - { - delete this->out_stream_; - this->out_stream_ = 0; - } - - if (!this->is_connected ()) - { - if (this->cannot_reconnect_ || !this->connect(this->reactive_)) - { - if (!this->cannot_reconnect_) - INET_ERROR (1, (LM_ERROR, DLINFO - ACE_TEXT ("(%d) HTTP_Session::send_request - ") - ACE_TEXT ("reconnect failed\n"), - ACE_OS::last_error ())); - return ACE::IOS::Null::out_stream_; - } - } - if (!keep_alive) - request.set_keep_alive (false); - if (!request.has_host ()) - { - if (this->port_ == HTTP_PORT) - request.set_host (this->host_); - else - request.set_host (this->host_, this->port_); - } - - this->expects_response_body_ = request.get_method() != Request::HTTP_HEAD; - - if (request.has_chunked_transfer_encoding ()) - { - request.write (*this->sock_stream_); - ChunkedTransferStreamPolicy* pol; - ACE_NEW_RETURN (pol, - ChunkedTransferStreamPolicy (), - ACE::IOS::Null::out_stream_); - ACE_NEW_RETURN (this->out_stream_, - OStream (*this->sock_stream_, pol), - ACE::IOS::Null::out_stream_); - } - else if (request.get_content_length () != Header::UNKNOWN_CONTENT_LENGTH) - { - ACE::IOS::CString_OStream cs; - request.write (cs); - FixedLengthStreamPolicy* pol; - ACE_NEW_RETURN (pol, - FixedLengthStreamPolicy (cs.str ().length () + request.get_content_length ()), - ACE::IOS::Null::out_stream_); - ACE_NEW_RETURN (this->out_stream_, - OStream (*this->sock_stream_, pol), - ACE::IOS::Null::out_stream_); - (*this->out_stream_) << cs.str ().c_str (); - } - else if (request.get_method () != Request::HTTP_PUT && request.get_method() != Request::HTTP_POST) - { - ACE::IOS::CString_OStream cs; - request.write (cs); - FixedLengthStreamPolicy* pol; - ACE_NEW_RETURN (pol, - FixedLengthStreamPolicy (cs.str ().length ()), - ACE::IOS::Null::out_stream_); - ACE_NEW_RETURN (this->out_stream_, - OStream (*this->sock_stream_, pol), - ACE::IOS::Null::out_stream_); - (*this->out_stream_) << cs.str ().c_str (); - } - else - { - ACE_NEW_RETURN (this->out_stream_, - OStream (*this->sock_stream_), - ACE::IOS::Null::out_stream_); - request.write (*this->out_stream_); - } - // reset reconnect timer - this->reconnect_timer_ = this->keep_alive_timeout_; - this->reconnect_countdown_.start (); - - return *this->out_stream_; - } - - template <ACE_SYNCH_DECL> - std::ostream& Session_T<ACE_SYNCH_USE>::request_stream () - { - return this->out_stream_ ? *this->out_stream_ : ACE::IOS::Null::out_stream_; - } - - template <ACE_SYNCH_DECL> - std::ostream& Session_T<ACE_SYNCH_USE>::request_stream ( - ACE::IOS::StreamInterceptor& interceptor) - { - if (this->out_stream_) - { - this->out_stream_->set_interceptor (interceptor); - return *this->out_stream_; - } - else - return ACE::IOS::Null::out_stream_; - } - - template <ACE_SYNCH_DECL> - std::istream& Session_T<ACE_SYNCH_USE>::receive_response (Response& response) - { - INET_TRACE ("ACE_HTTP_Session::receive_response"); - - if (this->in_stream_) - { - INET_ERROR (1, (LM_ERROR, DLINFO - ACE_TEXT ("HTTP_Session::receive_response - ") - ACE_TEXT ("invalid invocation without send_request\n"))); - // receive_response called second time without - // new send_request in between - return ACE::IOS::Null::in_stream_; - } - - if (this->out_stream_) - { - delete this->out_stream_; - this->out_stream_ = 0; - } - - this->sock_stream_->flush (); - - do - { - response.clear (); - if (!response.read (*this->sock_stream_)) - { - INET_ERROR (1, (LM_ERROR, DLINFO - ACE_TEXT ("(%d) HTTP_Session::receive_response - ") - ACE_TEXT ("failed to read response\n"), - ACE_OS::last_error ())); - return ACE::IOS::Null::in_stream_; - } - } - while (response.get_status ().get_status() == Status::HTTP_CONTINUE); - - this->needs_reconnect_ = this->keep_alive () && !response.has_keep_alive (); - - if (!this->expects_response_body_) - { - FixedLengthStreamPolicy* pol; - ACE_NEW_RETURN (pol, - FixedLengthStreamPolicy (0), - ACE::IOS::Null::in_stream_); - ACE_NEW_RETURN (this->in_stream_, - IStream (*this->sock_stream_, pol), - ACE::IOS::Null::in_stream_); - } - else if (response.has_chunked_transfer_encoding ()) - { - ChunkedTransferStreamPolicy* pol; - ACE_NEW_RETURN (pol, - ChunkedTransferStreamPolicy (), - ACE::IOS::Null::in_stream_); - ACE_NEW_RETURN (this->in_stream_, - IStream (*this->sock_stream_, pol), - ACE::IOS::Null::in_stream_); - } - else if (response.get_content_length () != Header::UNKNOWN_CONTENT_LENGTH) - { - FixedLengthStreamPolicy* pol; - ACE_NEW_RETURN (pol, - FixedLengthStreamPolicy (response.get_content_length ()), - ACE::IOS::Null::in_stream_); - ACE_NEW_RETURN (this->in_stream_, - IStream (*this->sock_stream_, pol), - ACE::IOS::Null::in_stream_); - } - else - { - ACE_NEW_RETURN (this->in_stream_, - IStream (*this->sock_stream_), - ACE::IOS::Null::in_stream_); - } - - return *this->in_stream_; - } - - template <ACE_SYNCH_DECL> - std::istream& Session_T<ACE_SYNCH_USE>::response_stream () - { - return this->in_stream_ ? *this->in_stream_ : ACE::IOS::Null::in_stream_; - } - - template <ACE_SYNCH_DECL> - std::istream& Session_T<ACE_SYNCH_USE>::response_stream ( - ACE::IOS::StreamInterceptor& interceptor) - { - if (this->in_stream_) + if (this->sock_stream_) { - this->in_stream_->set_interceptor (interceptor); - return *this->in_stream_; + delete this->sock_stream_; + this->sock_stream_ = 0; } - else - return ACE::IOS::Null::in_stream_; - } - - template <ACE_SYNCH_DECL> - void Session_T<ACE_SYNCH_USE>::close () - { - INET_TRACE ("ACE_HTTP_Session::close"); if (this->connection_) { - if (this->in_stream_) - { - delete this->in_stream_; - this->in_stream_ = 0; - } - if (this->out_stream_) - { - delete this->out_stream_; - this->out_stream_ = 0; - } - if (this->sock_stream_) - { - delete this->sock_stream_; - this->sock_stream_ = 0; - } // this should be the last referece and removing it // causes the connection to be destroyed this->connection_->remove_reference (); @@ -487,16 +161,17 @@ namespace ACE } template <ACE_SYNCH_DECL> - bool Session_T<ACE_SYNCH_USE>::reconnect_needed () + void Session_T<ACE_SYNCH_USE>::close_i () { - if (this->cannot_reconnect_) - return false; - if (!this->needs_reconnect_) - { - this->reconnect_countdown_.update (); - return this->reconnect_timer_ == ACE_Time_Value::zero; - } - return true; + INET_TRACE ("ACE_HTTP_Session::close_i"); + + this->close_connection (); + } + + template <ACE_SYNCH_DECL> + std::iostream& Session_T<ACE_SYNCH_USE>::sock_stream () + { + return *this->sock_stream_; } } diff --git a/ACE/protocols/ace/INet/HTTP_Session.h b/ACE/protocols/ace/INet/HTTP_Session.h index 518b0402856..0eac1ba24ff 100644 --- a/ACE/protocols/ace/INet/HTTP_Session.h +++ b/ACE/protocols/ace/INet/HTTP_Session.h @@ -11,15 +11,10 @@ #include /**/ "ace/pre.h" -#include "ace/SString.h" -#include "ace/Countdown_Time.h" +#include "ace/INet/HTTP_SessionBase.h" #include "ace/SOCK_Connector.h" -#include "ace/INet/INet_Export.h" -#include "ace/INet/HTTP_Request.h" -#include "ace/INet/HTTP_Response.h" #include "ace/INet/StreamHandler.h" #include "ace/INet/Sock_IOStream.h" -#include "ace/INet/HTTP_IOStream.h" ACE_BEGIN_VERSIONED_NAMESPACE_DECL @@ -34,16 +29,11 @@ namespace ACE * */ template <ACE_SYNCH_DECL> - class Session_T + class Session_T : public SessionBase { public: typedef ACE::IOS::StreamHandler<ACE_SOCK_STREAM, ACE_SYNCH_USE> connection_type; - enum - { - HTTP_PORT = 80 - }; - Session_T (bool keep_alive = false); Session_T (const ACE_Time_Value& timeout, @@ -52,69 +42,25 @@ namespace ACE virtual ~Session_T (); - void set_keep_alive (bool f); - - bool keep_alive () const; - - bool is_connected () const; - - void set_host (const ACE_CString& host, u_short port); - - void set_host (const ACE_CString& host); - - void set_port (u_short port); - - const ACE_CString& get_host () const; - - u_short get_port () const; - - bool connect (bool use_reactor = false); + virtual bool is_connected () const; - bool connect (connection_type* connection); + bool attach_connection (connection_type* connection); - std::ostream& send_request (Request& request); - - std::ostream& request_stream (); - - std::ostream& request_stream (ACE::IOS::StreamInterceptor& interceptor); - - std::istream& receive_response (Response& response); - - std::istream& response_stream (); + protected: - std::istream& response_stream (ACE::IOS::StreamInterceptor& interceptor); + void close_connection (); - void close (); + virtual bool connect_i (const ACE_Synch_Options& sync_opt); - protected: + virtual void close_i (); - bool reconnect_needed (); + virtual std::iostream& sock_stream (); private: - enum - { - DEFAULT_TIMEOUT = 30, // sec - DEFAULT_KEEP_ALIVE_TIMEOUT = 8 // sec - }; - - ACE_CString host_; - u_short port_; - typedef ACE::IOS::Sock_IOStreamBase<ACE_SYNCH_USE> sock_stream_type; - bool reactive_; connection_type* connection_; sock_stream_type* sock_stream_; - IStream* in_stream_; - OStream* out_stream_; - ACE_Time_Value http_timeout_; - ACE_Time_Value keep_alive_timeout_; - ACE_Time_Value reconnect_timer_; - ACE_Countdown_Time reconnect_countdown_; - bool keep_alive_; - bool needs_reconnect_; - bool cannot_reconnect_; - bool expects_response_body_; }; typedef Session_T<ACE_NULL_SYNCH> Session; diff --git a/ACE/protocols/ace/INet/HTTP_SessionBase.cpp b/ACE/protocols/ace/INet/HTTP_SessionBase.cpp new file mode 100644 index 00000000000..d16188d51a6 --- /dev/null +++ b/ACE/protocols/ace/INet/HTTP_SessionBase.cpp @@ -0,0 +1,308 @@ +// $Id$ + +#include "ace/INet/HTTP_SessionBase.h" + +#if !defined (__ACE_INLINE__) +#include "ace/INet/HTTP_SessionBase.inl" +#endif + +#include "ace/INet/INet_Log.h" +#include "ace/INet/HTTP_StreamPolicy.h" +#include "ace/INet/String_IOStream.h" +#include "ace/INet/IOS_util.h" +#include "ace/INet/HTTP_URL.h" +#include "ace/INET_Addr.h" +#include "ace/String_Base.h" +#include <istream> +#include <ostream> + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +namespace ACE +{ + namespace HTTP + { + + SessionBase::SessionBase (u_short port, bool keep_alive) + : port_ (port), + reactive_ (false), + in_stream_ (0), + out_stream_ (0), + http_timeout_ (DEFAULT_TIMEOUT), + keep_alive_timeout_ (DEFAULT_KEEP_ALIVE_TIMEOUT), + reconnect_timer_ (DEFAULT_KEEP_ALIVE_TIMEOUT), + reconnect_countdown_ (&reconnect_timer_), + keep_alive_ (keep_alive), + needs_reconnect_ (false), + cannot_reconnect_ (false), + expects_response_body_ (false) + { + INET_TRACE ("ACE_HTTP_SessionBase - ctor"); + } + + SessionBase::SessionBase (u_short port, + const ACE_Time_Value& timeout, + bool keep_alive, + const ACE_Time_Value* alive_timeout) + : port_ (port), + reactive_ (false), + in_stream_ (0), + out_stream_ (0), + http_timeout_ (timeout), + keep_alive_timeout_ (DEFAULT_KEEP_ALIVE_TIMEOUT), + reconnect_timer_ (DEFAULT_KEEP_ALIVE_TIMEOUT), + reconnect_countdown_ (&reconnect_timer_), + keep_alive_ (keep_alive), + needs_reconnect_ (false), + cannot_reconnect_ (false), + expects_response_body_ (false) + { + INET_TRACE ("ACE_HTTP_SessionBase - ctor"); + if (keep_alive && alive_timeout) + { + this->keep_alive_timeout_ = *alive_timeout; + } + } + + SessionBase::~SessionBase () + { + INET_TRACE ("ACE_HTTP_SessionBase - dtor"); + this->close_streams (); + } + + bool SessionBase::connect (bool use_reactor) + { + INET_TRACE ("ACE_HTTP_SessionBase::connect"); + + this->close (); + + unsigned long f_reactor = use_reactor ? ACE_Synch_Options::USE_REACTOR : 0; + ACE_Synch_Options sync_opt (ACE_Synch_Options::USE_TIMEOUT | f_reactor, + this->http_timeout_); + + return this->connect_i (sync_opt); + } + + std::ostream& SessionBase::send_request (Request& request) + { + INET_TRACE ("ACE_HTTP_SessionBase::send_request"); + + if (this->in_stream_) + { + delete this->in_stream_; + this->in_stream_ = 0; + } + + bool keep_alive = this->keep_alive (); + if ((this->is_connected () && !keep_alive) || this->reconnect_needed ()) + { + close(); + this->needs_reconnect_ = false; + } + + if (this->out_stream_) + { + delete this->out_stream_; + this->out_stream_ = 0; + } + + if (!this->is_connected ()) + { + if (this->cannot_reconnect_ || !this->connect(this->reactive_)) + { + if (!this->cannot_reconnect_) + INET_ERROR (1, (LM_ERROR, DLINFO + ACE_TEXT ("(%d) HTTP_SessionBase::send_request - ") + ACE_TEXT ("reconnect failed\n"), + ACE_OS::last_error ())); + return ACE::IOS::Null::out_stream_; + } + } + if (!keep_alive) + request.set_keep_alive (false); + if (!request.has_host ()) + { + if (this->port_ == URL::HTTP_PORT) + request.set_host (this->host_); + else + request.set_host (this->host_, this->port_); + } + + this->expects_response_body_ = request.get_method() != Request::HTTP_HEAD; + + if (request.has_chunked_transfer_encoding ()) + { + request.write (this->sock_stream ()); + ChunkedTransferStreamPolicy* pol; + ACE_NEW_RETURN (pol, + ChunkedTransferStreamPolicy (), + ACE::IOS::Null::out_stream_); + ACE_NEW_RETURN (this->out_stream_, + OStream (this->sock_stream (), pol), + ACE::IOS::Null::out_stream_); + } + else if (request.get_content_length () != Header::UNKNOWN_CONTENT_LENGTH) + { + ACE::IOS::CString_OStream cs; + request.write (cs); + FixedLengthStreamPolicy* pol; + ACE_NEW_RETURN (pol, + FixedLengthStreamPolicy (cs.str ().length () + request.get_content_length ()), + ACE::IOS::Null::out_stream_); + ACE_NEW_RETURN (this->out_stream_, + OStream (this->sock_stream (), pol), + ACE::IOS::Null::out_stream_); + (*this->out_stream_) << cs.str ().c_str (); + } + else if (request.get_method () != Request::HTTP_PUT && request.get_method() != Request::HTTP_POST) + { + ACE::IOS::CString_OStream cs; + request.write (cs); + FixedLengthStreamPolicy* pol; + ACE_NEW_RETURN (pol, + FixedLengthStreamPolicy (cs.str ().length ()), + ACE::IOS::Null::out_stream_); + ACE_NEW_RETURN (this->out_stream_, + OStream (this->sock_stream (), pol), + ACE::IOS::Null::out_stream_); + (*this->out_stream_) << cs.str ().c_str (); + } + else + { + ACE_NEW_RETURN (this->out_stream_, + OStream (this->sock_stream ()), + ACE::IOS::Null::out_stream_); + request.write (*this->out_stream_); + } + // reset reconnect timer + this->reconnect_timer_ = this->keep_alive_timeout_; + this->reconnect_countdown_.start (); + + return *this->out_stream_; + } + + std::ostream& SessionBase::request_stream () + { + return this->out_stream_ ? *this->out_stream_ : ACE::IOS::Null::out_stream_; + } + + std::ostream& SessionBase::request_stream ( + ACE::IOS::StreamInterceptor& interceptor) + { + if (this->out_stream_) + { + this->out_stream_->set_interceptor (interceptor); + return *this->out_stream_; + } + else + return ACE::IOS::Null::out_stream_; + } + + std::istream& SessionBase::receive_response (Response& response) + { + INET_TRACE ("ACE_HTTP_SessionBase::receive_response"); + + if (this->in_stream_) + { + INET_ERROR (1, (LM_ERROR, DLINFO + ACE_TEXT ("HTTP_Session::receive_response - ") + ACE_TEXT ("invalid invocation without send_request\n"))); + // receive_response called second time without + // new send_request in between + return ACE::IOS::Null::in_stream_; + } + + if (this->out_stream_) + { + delete this->out_stream_; + this->out_stream_ = 0; + } + + this->sock_stream ().flush (); + + do + { + response.clear (); + if (!response.read (this->sock_stream ())) + { + INET_ERROR (1, (LM_ERROR, DLINFO + ACE_TEXT ("(%d) HTTP_Session::receive_response - ") + ACE_TEXT ("failed to read response\n"), + ACE_OS::last_error ())); + return ACE::IOS::Null::in_stream_; + } + } + while (response.get_status ().get_status() == Status::HTTP_CONTINUE); + + this->needs_reconnect_ = this->keep_alive () && !response.has_keep_alive (); + + if (!this->expects_response_body_) + { + FixedLengthStreamPolicy* pol; + ACE_NEW_RETURN (pol, + FixedLengthStreamPolicy (0), + ACE::IOS::Null::in_stream_); + ACE_NEW_RETURN (this->in_stream_, + IStream (this->sock_stream (), pol), + ACE::IOS::Null::in_stream_); + } + else if (response.has_chunked_transfer_encoding ()) + { + ChunkedTransferStreamPolicy* pol; + ACE_NEW_RETURN (pol, + ChunkedTransferStreamPolicy (), + ACE::IOS::Null::in_stream_); + ACE_NEW_RETURN (this->in_stream_, + IStream (this->sock_stream (), pol), + ACE::IOS::Null::in_stream_); + } + else if (response.get_content_length () != Header::UNKNOWN_CONTENT_LENGTH) + { + FixedLengthStreamPolicy* pol; + ACE_NEW_RETURN (pol, + FixedLengthStreamPolicy (response.get_content_length ()), + ACE::IOS::Null::in_stream_); + ACE_NEW_RETURN (this->in_stream_, + IStream (this->sock_stream (), pol), + ACE::IOS::Null::in_stream_); + } + else + { + ACE_NEW_RETURN (this->in_stream_, + IStream (this->sock_stream ()), + ACE::IOS::Null::in_stream_); + } + + return *this->in_stream_; + } + + std::istream& SessionBase::response_stream () + { + return this->in_stream_ ? *this->in_stream_ : ACE::IOS::Null::in_stream_; + } + + std::istream& SessionBase::response_stream ( + ACE::IOS::StreamInterceptor& interceptor) + { + if (this->in_stream_) + { + this->in_stream_->set_interceptor (interceptor); + return *this->in_stream_; + } + else + return ACE::IOS::Null::in_stream_; + } + + void SessionBase::close () + { + INET_TRACE ("ACE_HTTP_SessionBase::close"); + + this->close_streams (); + + this->close_i (); + } + + } +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/ACE/protocols/ace/INet/HTTP_SessionBase.h b/ACE/protocols/ace/INet/HTTP_SessionBase.h new file mode 100644 index 00000000000..6233f80c6dd --- /dev/null +++ b/ACE/protocols/ace/INet/HTTP_SessionBase.h @@ -0,0 +1,134 @@ +// $Id$ + +/** + * @file HTTP_SessionBase.h + * + * @author Martin Corino <mcorino@remedy.nl> + */ + +#ifndef ACE_HTTP_SESSION_BASE_H +#define ACE_HTTP_SESSION_BASE_H + +#include /**/ "ace/pre.h" + +#include "ace/SString.h" +#include "ace/Countdown_Time.h" +#include "ace/Synch_Options.h" +#include "ace/INet/INet_Export.h" +#include "ace/INet/HTTP_Request.h" +#include "ace/INet/HTTP_Response.h" +#include "ace/INet/HTTP_IOStream.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +namespace ACE + { + namespace HTTP + { + /** + * @class ACE_HTTP_SessionBase + * + * @brief Abstract base class for HTTP(S) sessions. + * + */ + class ACE_INET_Export SessionBase + { + public: + SessionBase (u_short port, + bool keep_alive = false); + + SessionBase (u_short port, + const ACE_Time_Value& timeout, + bool keep_alive = false, + const ACE_Time_Value* alive_timeout = 0); + + virtual ~SessionBase (); + + void set_keep_alive (bool f); + + bool keep_alive () const; + + virtual bool is_connected () const = 0; + + void set_host (const ACE_CString& host, + u_short port); + + void set_host (const ACE_CString& host); + + void set_port (u_short port); + + void set_proxy_target (const ACE_CString& host, u_short port); + + const ACE_CString& get_host () const; + + u_short get_port () const; + + bool is_proxy_connection () const; + + const ACE_CString& get_proxy_target_host () const; + + u_short get_proxy_target_port () const; + + bool connect (bool use_reactor = false); + + std::ostream& send_request (Request& request); + + std::ostream& request_stream (); + + std::ostream& request_stream (ACE::IOS::StreamInterceptor& interceptor); + + std::istream& receive_response (Response& response); + + std::istream& response_stream (); + + std::istream& response_stream (ACE::IOS::StreamInterceptor& interceptor); + + void close (); + + protected: + + bool reconnect_needed (); + + void close_streams (); + + virtual bool connect_i (const ACE_Synch_Options& sync_opt) = 0; + + virtual void close_i () = 0; + + virtual std::iostream& sock_stream () = 0; + + enum + { + DEFAULT_TIMEOUT = 30, // sec + DEFAULT_KEEP_ALIVE_TIMEOUT = 8 // sec + }; + + ACE_CString host_; + u_short port_; + bool proxy_connection_; + ACE_CString proxy_target_host_; + u_short proxy_target_port_; + + bool reactive_; + IStream* in_stream_; + OStream* out_stream_; + ACE_Time_Value http_timeout_; + ACE_Time_Value keep_alive_timeout_; + ACE_Time_Value reconnect_timer_; + ACE_Countdown_Time reconnect_countdown_; + bool keep_alive_; + bool needs_reconnect_; + bool cannot_reconnect_; + bool expects_response_body_; + }; + } + } + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/INet/HTTP_SessionBase.inl" +#endif + +#include /**/ "ace/post.h" +#endif /* ACE_HTTP_SESSION_BASE_H */ diff --git a/ACE/protocols/ace/INet/HTTP_SessionBase.inl b/ACE/protocols/ace/INet/HTTP_SessionBase.inl new file mode 100644 index 00000000000..6539f51b284 --- /dev/null +++ b/ACE/protocols/ace/INet/HTTP_SessionBase.inl @@ -0,0 +1,124 @@ +// -*- C++ -*- +// +// $Id$ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +namespace ACE +{ + namespace HTTP + { + ACE_INLINE + void SessionBase::set_keep_alive (bool f) + { + this->keep_alive_ = f; + } + + ACE_INLINE + bool SessionBase::keep_alive () const + { + return this->keep_alive_; + } + + ACE_INLINE + void SessionBase::set_host (const ACE_CString& host, u_short port) + { + if (!this->is_connected ()) + { + this->host_ = host; + this->port_ = port; + this->proxy_connection_ = false; + } + } + + ACE_INLINE + void SessionBase::set_host (const ACE_CString& host) + { + if (!this->is_connected ()) + { + this->host_ = host; + this->proxy_connection_ = false; + } + } + + ACE_INLINE + void SessionBase::set_port (u_short port) + { + if (!this->is_connected ()) + { + this->port_ = port; + } + } + + ACE_INLINE + void SessionBase::set_proxy_target (const ACE_CString& host, u_short port) + { + if (!this->is_connected ()) + { + this->proxy_target_host_ = host; + this->proxy_target_port_ = port; + this->proxy_connection_ = true; + } + } + + ACE_INLINE + const ACE_CString& SessionBase::get_host () const + { + return this->host_; + } + + ACE_INLINE + u_short SessionBase::get_port () const + { + return this->port_; + } + + ACE_INLINE + bool SessionBase::is_proxy_connection () const + { + return this->proxy_connection_; + } + + ACE_INLINE + const ACE_CString& SessionBase::get_proxy_target_host () const + { + return this->proxy_target_host_; + } + + ACE_INLINE + u_short SessionBase::get_proxy_target_port () const + { + return this->proxy_target_port_; + } + + ACE_INLINE + bool SessionBase::reconnect_needed () + { + if (this->cannot_reconnect_) + return false; + if (!this->needs_reconnect_) + { + this->reconnect_countdown_.update (); + return this->reconnect_timer_ == ACE_Time_Value::zero; + } + return true; + } + + ACE_INLINE + void SessionBase::close_streams () + { + if (this->in_stream_) + { + delete this->in_stream_; + this->in_stream_ = 0; + } + if (this->out_stream_) + { + delete this->out_stream_; + this->out_stream_ = 0; + } + } + } +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/ACE/protocols/ace/INet/HTTP_Simple_exec.cpp b/ACE/protocols/ace/INet/HTTP_Simple_exec.cpp index 224c8851755..bf82a88fb5a 100644 --- a/ACE/protocols/ace/INet/HTTP_Simple_exec.cpp +++ b/ACE/protocols/ace/INet/HTTP_Simple_exec.cpp @@ -3,8 +3,11 @@ #include "ace/Get_Opt.h" #include "ace/Auto_Ptr.h" #include "ace/OS_NS_errno.h" -#include "HTTP_URL.h" -#include "HTTP_ClientRequestHandler.h" +#include "ace/INet/HTTP_URL.h" +#include "ace/INet/HTTP_ClientRequestHandler.h" +#include "ace/INet/SSL_CallbackManager.h" +#include "ace/INet/HTTPS_Context.h" +#include "ace/INet/INet_Log.h" #include <iostream> #include <fstream> @@ -12,21 +15,33 @@ ACE_CString proxy_hostname; u_short proxy_port = ACE::HTTP::URL::HTTP_PROXY_PORT; ACE_CString url; ACE_CString outfile; +int ssl_mode = ACE_SSL_Context::SSLv3; +bool verify_peer = true; +bool ignore_verify = false; +ACE_CString certificate; +ACE_CString private_key; +ACE_CString ca_location; void usage (void) { std::cout << "usage: http_simple_wget [options] <url>\n"; std::cout << "Executes an HTTP GET request and sends the result to STDOUT or file\n"; - std::cout << "\t-H <hostname>\t\tproxy host to connect to\n"; - std::cout << "\t-p <port>\t\tproxy port to connect to\n"; - std::cout << "\t-o <filename>\t\tfile to write output to\n"; + std::cout << "\t-H <hostname> \t\tproxy host to connect to\n"; + std::cout << "\t-p <port> \t\tproxy port to connect to\n"; + std::cout << "\t-o <filename> \t\tfile to write output to\n"; + std::cout << "\t-v <ssl version>\t\tSSL version to use: 2, 23, 3\n"; + std::cout << "\t-n \t\tno peer certificate verification\n"; + std::cout << "\t-i \t\tignore peer certificate verification failures\n"; + std::cout << "\t-c <filename> \t\tcertificate file (PEM format)\n"; + std::cout << "\t-k <filename> \t\tprivate key file (PEM format); requires -c\n"; + std::cout << "\t-C <path> \t\ttrusted CA file or directory\n"; } bool parse_args (int argc, ACE_TCHAR *argv []) { - ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("H:p:o:h"), 0, 0, ACE_Get_Opt::RETURN_IN_ORDER); + ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("H:p:o:hv:nic:k:C:"), 0, 0, ACE_Get_Opt::RETURN_IN_ORDER); int c; ACE_CString s; @@ -49,6 +64,41 @@ parse_args (int argc, ACE_TCHAR *argv []) outfile = ACE_TEXT_ALWAYS_CHAR (get_opt.opt_arg ()); break; + case 'v': + { + ACE_CString ver = ACE_TEXT_ALWAYS_CHAR (get_opt.opt_arg ()); + if (ver == "2") + ssl_mode = ACE_SSL_Context::SSLv2; + else if (ver == "23") + ssl_mode = ACE_SSL_Context::SSLv23; + else if (ver != "3") // default mode + { + std::cerr << "ERROR: Invalid SSL mode [" << ver << "] specfied!" << std::endl; + return false; + } + } + break; + + case 'n': + verify_peer = false; + break; + + case 'i': + ignore_verify = true; + break; + + case 'c': + certificate = ACE_TEXT_ALWAYS_CHAR (get_opt.opt_arg ()); + break; + + case 'k': + private_key = ACE_TEXT_ALWAYS_CHAR (get_opt.opt_arg ()); + break; + + case 'C': + ca_location = ACE_TEXT_ALWAYS_CHAR (get_opt.opt_arg ()); + break; + case 'h': default: usage (); @@ -119,6 +169,35 @@ ACE_TMAIN (int argc, ACE_TCHAR *argv []) return 1; } + ACE::HTTPS::Context::set_default_ssl_mode (ssl_mode); + ACE::HTTPS::Context::set_default_verify_mode (verify_peer); + ACE::HTTPS::Context::instance ().use_default_ca (); + if (!private_key.empty ()) + { + if (certificate.empty ()) + { + std::cerr << "ERROR: private key file [" << private_key << "] requires certificate file to be specified." << std::endl; + return 1; + } + if (!ACE::HTTPS::Context::instance ().set_key_files (private_key.c_str (), certificate.c_str ())) + { + std::cerr << "ERROR: failed to set private key [" << private_key << "]." << std::endl; + return 1; + } + } + if (!ca_location.empty ()) + { + INET_DEBUG (6, (LM_INFO, DLINFO ACE_TEXT ("loading trusted CA [%C]\n"), ca_location.c_str ())); + if (!ACE::HTTPS::Context::instance ().load_trusted_ca (ca_location.c_str ())) + { + std::cerr << "ERROR: failed to load trusted CA from [" << ca_location << "]." << std::endl; + return 1; + } + INET_DEBUG (6, (LM_INFO, DLINFO ACE_TEXT ("loaded [%d] trusted CA\n"), ACE::HTTPS::Context::instance ().has_trusted_ca ())); + } + if (ignore_verify) + ACE::INet::SSL_CallbackManager::instance ()->set_certificate_callback (new ACE::INet::SSL_CertificateAcceptor); + std::cout << "Starting..." << std::endl; if (!url.empty ()) @@ -136,17 +215,19 @@ ACE_TMAIN (int argc, ACE_TCHAR *argv []) sout = fout.get (); } - ACE::HTTP::URL http_url; - std::cout << "Parsing url [" << url.c_str () << "]" << std::endl; - if (!http_url.parse (url)) + ACE_Auto_Ptr<ACE::INet::URL_Base> url_safe (ACE::INet::URL_Base::create_from_string (url)); + + if (url_safe.get () == 0 || url != url_safe->to_string ()) { std::cerr << "Failed parsing url [" << url << "]" << std::endl; - std::cerr << "\tresult = " << http_url.to_string ().c_str (); + std::cerr << "\tresult = " << (url_safe.get () == 0 ? "(null)" : url_safe->to_string ().c_str ()) << std::endl; return 1; } + ACE::HTTP::URL& http_url = *dynamic_cast<ACE::HTTP::URL*> (url_safe.get ()); + if (!proxy_hostname.empty ()) { std::cout << "Setting proxy: " << proxy_hostname.c_str () << ':' << proxy_port << std::endl; diff --git a/ACE/protocols/ace/INet/HTTP_StreamPolicy.h b/ACE/protocols/ace/INet/HTTP_StreamPolicy.h index c9c139a003e..9ec94680c97 100644 --- a/ACE/protocols/ace/INet/HTTP_StreamPolicy.h +++ b/ACE/protocols/ace/INet/HTTP_StreamPolicy.h @@ -25,7 +25,8 @@ namespace ACE /** * @class ACE_HTTP_FixedLengthStreamPolicy * - * @brief + * @brief Implements stream policy for fixed length data stream + * in HTTP response or request. * */ template <class STREAM_BUFFER> @@ -53,7 +54,8 @@ namespace ACE /** * @class ACE_HTTP_ChunkedTransferStreamPolicy * - * @brief + * @brief Implements stream policy for chunked data streams + * in HTTP response or request. * */ template <class STREAM_BUFFER> diff --git a/ACE/protocols/ace/INet/HTTP_StreamPolicyBase.h b/ACE/protocols/ace/INet/HTTP_StreamPolicyBase.h index 814377b7050..2000eb3087e 100644 --- a/ACE/protocols/ace/INet/HTTP_StreamPolicyBase.h +++ b/ACE/protocols/ace/INet/HTTP_StreamPolicyBase.h @@ -23,7 +23,7 @@ namespace ACE /** * @class ACE_IOS_StreamPolicyBase * - * @brief + * @brief Abstract base for HTTP stream policies. * */ template <class STREAM_BUFFER> diff --git a/ACE/protocols/ace/INet/HTTP_URL.cpp b/ACE/protocols/ace/INet/HTTP_URL.cpp index 6a7803d8408..01498682691 100644 --- a/ACE/protocols/ace/INet/HTTP_URL.cpp +++ b/ACE/protocols/ace/INet/HTTP_URL.cpp @@ -15,7 +15,13 @@ namespace ACE { namespace HTTP { - const ACE_CString URL::PROTOCOL ("http"); + const char* URL::PROTOCOL = "http"; + + const ACE_CString& URL::protocol () + { + static const ACE_CString protocol_ (PROTOCOL); + return protocol_; + } URL::URL () : URL_INetAuthBase (HTTP_PORT), @@ -36,6 +42,12 @@ namespace ACE *this = url; } + URL::URL (u_short port) + : URL_INetAuthBase (port), + proxy_port_ (HTTP_PROXY_PORT) + { + } + URL::~URL () { } @@ -107,7 +119,7 @@ namespace ACE const ACE_CString& URL::Factory::protocol () { - return URL::PROTOCOL; + return URL::protocol (); } ACE::INet::URL_Base* URL::Factory::create_from_string (const ACE_CString& url_string) diff --git a/ACE/protocols/ace/INet/HTTP_URL.h b/ACE/protocols/ace/INet/HTTP_URL.h index e392c17d727..7217ab6851d 100644 --- a/ACE/protocols/ace/INet/HTTP_URL.h +++ b/ACE/protocols/ace/INet/HTTP_URL.h @@ -29,7 +29,7 @@ namespace ACE /** * @class ACE_HTTP_URL * - * @brief + * @brief Implements HTTP url support. * */ class ACE_INET_Export URL @@ -49,7 +49,7 @@ namespace ACE virtual const ACE_CString& get_fragment () const; - ACE_CString get_request_uri () const; + virtual ACE_CString get_request_uri () const; virtual void set_query (const ACE_CString& query); @@ -67,7 +67,9 @@ namespace ACE virtual u_short default_port () const; - static const ACE_CString PROTOCOL; + static const char* PROTOCOL; + + static const ACE_CString& protocol (); enum { @@ -76,6 +78,8 @@ namespace ACE }; protected: + URL (u_short port); + virtual ACE::INet::ClientRequestHandler* create_default_request_handler () const; private: diff --git a/ACE/protocols/ace/INet/HTTP_URL.inl b/ACE/protocols/ace/INet/HTTP_URL.inl index df6a2a0cebc..398f4dc7c8d 100644 --- a/ACE/protocols/ace/INet/HTTP_URL.inl +++ b/ACE/protocols/ace/INet/HTTP_URL.inl @@ -12,7 +12,7 @@ namespace ACE ACE_INLINE const ACE_CString& URL::get_scheme () const { - return PROTOCOL; + return protocol (); } ACE_INLINE diff --git a/ACE/protocols/ace/INet/HeaderBase.h b/ACE/protocols/ace/INet/HeaderBase.h index bb6f61e16a3..67b10282192 100644 --- a/ACE/protocols/ace/INet/HeaderBase.h +++ b/ACE/protocols/ace/INet/HeaderBase.h @@ -30,6 +30,12 @@ namespace ACE { namespace INet { + /** + * @class ACE_INet_NVPair + * + * @brief Name/Value pair holder class. + * + */ class NVPair { public: @@ -110,15 +116,25 @@ namespace ACE static const ACE_CString EMPTY; - protected: + /// Sets header <name> to <value>. Overwrites existing vaues. void set (const ACE_CString& name, const ACE_CString& value); + + /// Adds header <name> with <value>. Allows duplicates. void add (const ACE_CString& name, const ACE_CString& value); + + /// Removes header <name> (first found). void remove (const ACE_CString& name); + + /// Retrieves value for header <name> into <value> (first found). bool get (const ACE_CString& name, ACE_CString& value) const; + + /// Returns true if a header <name> exists (1 or more), false otherwise. bool has (const ACE_CString& name) const; + /// Retrieves values for all headers <name> into <values>. void get_values (const ACE_CString& name, ACE_Array<ACE_CString>& values) const; + protected: int read_field (std::istream& str, ACE_CString& var, size_t maxlen, char delim); int read_ws_field (std::istream& str, ACE_CString& var, size_t maxlen); diff --git a/ACE/protocols/ace/INet/RequestHandler.h b/ACE/protocols/ace/INet/RequestHandler.h index 360d1e6f9de..73e1a7e7e70 100644 --- a/ACE/protocols/ace/INet/RequestHandler.h +++ b/ACE/protocols/ace/INet/RequestHandler.h @@ -25,7 +25,7 @@ namespace ACE /** * @class ACE_INet_RequestHandler * - * @brief + * @brief Abstract base for request handlers. * */ class ACE_INET_Export RequestHandler diff --git a/ACE/protocols/ace/INet/SSLSock_IOStream.cpp b/ACE/protocols/ace/INet/SSLSock_IOStream.cpp new file mode 100644 index 00000000000..62de4128853 --- /dev/null +++ b/ACE/protocols/ace/INet/SSLSock_IOStream.cpp @@ -0,0 +1,130 @@ +// $Id$ + +#ifndef ACE_IOS_SSLSOCK_IOSTREAM_CPP +#define ACE_IOS_SSLSOCK_IOSTREAM_CPP + +#include "ace/INet/SSLSock_IOStream.h" +#include "ace/INet/IOS_util.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +namespace ACE +{ + namespace IOS + { + + template <ACE_SYNCH_DECL> + SSLSock_StreamBufferBase<ACE_SYNCH_USE>::SSLSock_StreamBufferBase (stream_type* stream) + : BidirStreamBuffer<StreamHandler<ACE_SSL_SOCK_Stream, ACE_SYNCH_USE> > ( + stream, + BUFFER_SIZE, + std::ios::in | std::ios::out) + { + } + + template <ACE_SYNCH_DECL> + SSLSock_StreamBufferBase<ACE_SYNCH_USE>::~SSLSock_StreamBufferBase () + { + } + + template <ACE_SYNCH_DECL> + SSLSock_IOSBase<ACE_SYNCH_USE>::SSLSock_IOSBase (stream_type* stream) + : streambuf_ (stream) + { + ace_ios_init (&this->streambuf_); + } + + template <ACE_SYNCH_DECL> + SSLSock_IOSBase<ACE_SYNCH_USE>::~SSLSock_IOSBase () + { + try + { + this->streambuf_.sync(); + } + catch (...) + { + } + } + + template <ACE_SYNCH_DECL> + typename SSLSock_IOSBase<ACE_SYNCH_USE>::buffer_type* + SSLSock_IOSBase<ACE_SYNCH_USE>::rdbuf () + { + return &this->streambuf_; + } + + template <ACE_SYNCH_DECL> + void SSLSock_IOSBase<ACE_SYNCH_USE>::close () + { + this->streambuf_.sync (); + this->streambuf_.close_stream (); + } + + template <ACE_SYNCH_DECL> + const typename SSLSock_IOSBase<ACE_SYNCH_USE>::stream_type& + SSLSock_IOSBase<ACE_SYNCH_USE>::stream () const + { + return this->streambuf_.stream (); + } + + + template <ACE_SYNCH_DECL> + SSLSock_OStreamBase<ACE_SYNCH_USE>::SSLSock_OStreamBase(stream_type* stream) + : SSLSock_IOSBase<ACE_SYNCH_USE> (stream), std::ostream (SSLSock_IOSBase<ACE_SYNCH_USE>::rdbuf ()) + { + } + + template <ACE_SYNCH_DECL> + SSLSock_OStreamBase<ACE_SYNCH_USE>::~SSLSock_OStreamBase() + { + } + + template <ACE_SYNCH_DECL> + void SSLSock_OStreamBase<ACE_SYNCH_USE>::set_interceptor ( + typename buffer_type::interceptor_type& interceptor) + { + this->rdbuf ()->set_interceptor (interceptor); + } + + template <ACE_SYNCH_DECL> + SSLSock_IStreamBase<ACE_SYNCH_USE>::SSLSock_IStreamBase(stream_type* stream) + : SSLSock_IOSBase<ACE_SYNCH_USE> (stream), std::istream (SSLSock_IOSBase<ACE_SYNCH_USE>::rdbuf ()) + { + } + + template <ACE_SYNCH_DECL> + SSLSock_IStreamBase<ACE_SYNCH_USE>::~SSLSock_IStreamBase () + { + } + + template <ACE_SYNCH_DECL> + void SSLSock_IStreamBase<ACE_SYNCH_USE>::set_interceptor ( + typename buffer_type::interceptor_type& interceptor) + { + this->rdbuf ()->set_interceptor (interceptor); + } + + template <ACE_SYNCH_DECL> + SSLSock_IOStreamBase<ACE_SYNCH_USE>::SSLSock_IOStreamBase(stream_type* stream) + : SSLSock_IOSBase<ACE_SYNCH_USE> (stream), std::iostream (SSLSock_IOSBase<ACE_SYNCH_USE>::rdbuf ()) + { + } + + template <ACE_SYNCH_DECL> + SSLSock_IOStreamBase<ACE_SYNCH_USE>::~SSLSock_IOStreamBase () + { + } + + template <ACE_SYNCH_DECL> + void SSLSock_IOStreamBase<ACE_SYNCH_USE>::set_interceptor ( + typename buffer_type::interceptor_type& interceptor) + { + this->rdbuf ()->set_interceptor (interceptor); + } + + } +} + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* ACE_IOS_SSLSOCK_IOSTREAM_CPP */ diff --git a/ACE/protocols/ace/INet/SSLSock_IOStream.h b/ACE/protocols/ace/INet/SSLSock_IOStream.h new file mode 100644 index 00000000000..ad6df10810f --- /dev/null +++ b/ACE/protocols/ace/INet/SSLSock_IOStream.h @@ -0,0 +1,169 @@ +// $Id$ + +/** + * @file SSLSock_IOStream.h + * + * @author Martin Corino <mcorino@remedy.nl> + */ + +#ifndef ACE_IOS_SSLSOCK_IOSTREAM_H +#define ACE_IOS_SSLSOCK_IOSTREAM_H + +#include /**/ "ace/pre.h" + +#include /**/ "ace/config-all.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/SSL/SSL_SOCK_Stream.h" +#include "ace/INet/BidirStreamBuffer.h" +#include "ace/INet/StreamHandler.h" +#include "ace/INet/StreamInterceptor.h" +#include <istream> +#include <ostream> + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +namespace ACE + { + namespace IOS + { + /** + * @class ACE_IOS_SSLSock_StreamBuffer + * + * @brief + * + */ + template <ACE_SYNCH_DECL> + class SSLSock_StreamBufferBase + : public BidirStreamBuffer<StreamHandler<ACE_SSL_SOCK_Stream, ACE_SYNCH_USE> > + { + public: + typedef StreamHandler<ACE_SSL_SOCK_Stream, ACE_SYNCH_USE> stream_type; + + SSLSock_StreamBufferBase (stream_type* stream); + virtual ~SSLSock_StreamBufferBase (); + + private: + enum + { + BUFFER_SIZE = 1024 + }; + }; + + /** + * @class ACE_IOS_SSLSock_IOS + * + * @brief + * + */ + template <ACE_SYNCH_DECL> + class SSLSock_IOSBase + : public virtual std::ios + { + public: + typedef SSLSock_StreamBufferBase<ACE_SYNCH_USE> buffer_type; + typedef typename buffer_type::stream_type stream_type; + + SSLSock_IOSBase (stream_type* stream); + ~SSLSock_IOSBase (); + + buffer_type* rdbuf (); + + void close (); + + const stream_type& stream () const; + + protected: + buffer_type streambuf_; + }; + + /** + * @class ACE_IOS_SSLSock_OStream + * + * @brief + * + */ + template <ACE_SYNCH_DECL> + class SSLSock_OStreamBase + : public SSLSock_IOSBase<ACE_SYNCH_USE>, public std::ostream + { + public: + typedef SSLSock_IOSBase<ACE_SYNCH_USE> ios_base; + typedef typename ios_base::stream_type stream_type; + typedef SSLSock_StreamBufferBase<ACE_SYNCH_USE> buffer_type; + + explicit SSLSock_OStreamBase(stream_type* stream); + + ~SSLSock_OStreamBase(); + + void set_interceptor (typename buffer_type::interceptor_type& interceptor); + }; + + /** + * @class ACE_IOS_SSLSock_IStream + * + * @brief + * + */ + template <ACE_SYNCH_DECL> + class SSLSock_IStreamBase + : public SSLSock_IOSBase<ACE_SYNCH_USE>, public std::istream + { + public: + typedef SSLSock_IOSBase<ACE_SYNCH_USE> ios_base; + typedef typename ios_base::stream_type stream_type; + typedef SSLSock_StreamBufferBase<ACE_SYNCH_USE> buffer_type; + + explicit SSLSock_IStreamBase(stream_type* stream); + + ~SSLSock_IStreamBase(); + + void set_interceptor (typename buffer_type::interceptor_type& interceptor); + }; + + /** + * @class ACE_IOS_SSLSock_IOStream + * + * @brief + * + */ + template <ACE_SYNCH_DECL> + class SSLSock_IOStreamBase + : public SSLSock_IOSBase<ACE_SYNCH_USE>, public std::iostream + { + public: + typedef SSLSock_IOSBase<ACE_SYNCH_USE> ios_base; + typedef typename ios_base::stream_type stream_type; + typedef SSLSock_StreamBufferBase<ACE_SYNCH_USE> buffer_type; + + explicit SSLSock_IOStreamBase(stream_type* stream); + + ~SSLSock_IOStreamBase(); + + void set_interceptor (typename buffer_type::interceptor_type& interceptor); + }; + + typedef SSLSock_StreamBufferBase<ACE_NULL_SYNCH> SSLSock_StreamBuffer; + typedef SSLSock_IOSBase<ACE_NULL_SYNCH> SSLSock_IOS; + typedef SSLSock_IStreamBase<ACE_NULL_SYNCH> SSLSock_IStream; + typedef SSLSock_OStreamBase<ACE_NULL_SYNCH> SSLSock_OStream; + typedef SSLSock_IOStreamBase<ACE_NULL_SYNCH> SSLSock_IOStream; + + } + } + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (ACE_TEMPLATES_REQUIRE_SOURCE) +#include "ace/INet/SSLSock_IOStream.cpp" +#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */ + +#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA) +#pragma implementation ("SSLSock_IOStream.cpp") +#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */ + +#include /**/ "ace/post.h" +#endif /* ACE_IOS_SSLSOCK_IOSTREAM_H */ diff --git a/ACE/protocols/ace/INet/SSL_CallbackManager.cpp b/ACE/protocols/ace/INet/SSL_CallbackManager.cpp new file mode 100644 index 00000000000..db93abb18de --- /dev/null +++ b/ACE/protocols/ace/INet/SSL_CallbackManager.cpp @@ -0,0 +1,122 @@ +// $Id$ + +#include "ace/INet/SSL_CallbackManager.h" + +#if !defined (__ACE_INLINE__) +#include "ace/INet/SSL_CallbackManager.inl" +#endif + +#include "ace/Truncate.h" +#include "ace/Singleton.h" +#include "ace/INet/INet_Log.h" + +#include <openssl/x509.h> + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +namespace ACE +{ + namespace INet + { + + int SSL_CallbackManager::ssl_ctx_mngr_index_ = (-2); + + SSL_CallbackManager::SSL_CallbackManager () + { + } + + SSL_CallbackManager::~SSL_CallbackManager () + { + } + + void SSL_CallbackManager::initialize_callbacks (ACE_SSL_Context* ssl_ctx) + { + if (ssl_ctx_mngr_index_ < -1) + { + ssl_ctx_mngr_index_ = ::SSL_CTX_get_ex_new_index (0, 0, 0,0,0); + if (ssl_ctx_mngr_index_ < 0) + { + INET_ERROR (1, (LM_ERROR, DLINFO + ACE_TEXT ("SSL_CallbackManager::initialize_callbacks - ") + ACE_TEXT ("failed to allocate SSL_CTX ex_data index.\n"))); + return; + } + } + + this->ssl_ctx_ = ssl_ctx == 0 ? ACE_SSL_Context::instance () : ssl_ctx; + ::SSL_CTX_set_ex_data (this->ssl_ctx_->context (), ssl_ctx_mngr_index_, this); + this->ssl_ctx_->default_verify_callback (&verify_certificate_callback); + ::SSL_CTX_set_default_passwd_cb (ssl_ctx->context(), &passwd_callback); + ::SSL_CTX_set_default_passwd_cb_userdata (ssl_ctx->context(), this); + } + + SSL_CallbackManager* SSL_CallbackManager::instance () + { + return ACE_Singleton<SSL_CallbackManager, ACE_SYNCH::MUTEX>::instance (); + } + + int SSL_CallbackManager::verify_certificate_callback (SSL_CertificateCallbackArg& arg) + { + TCertificateCallback cert_cb = this->cert_callback_; + if (cert_cb) + { + cert_cb->handle_certificate_failure (arg); + } + return (arg.ignore_error () ? 1 : 0); + } + + void SSL_CallbackManager::passwd_callback (ACE_CString& pwd) + { + TPasswordCallback pw_cb = passwd_callback_; + if (pw_cb) + { + pw_cb->get_privatekey_password (pwd); + } + } + + int SSL_CallbackManager::verify_certificate_callback (int ok, X509_STORE_CTX* cert_ctx) + { + if (!ok && ssl_ctx_mngr_index_>=0) + { + // Retrieve the pointer to the SSL of the connection currently treated + void* ex_data = ::X509_STORE_CTX_get_ex_data (cert_ctx, ::SSL_get_ex_data_X509_STORE_CTX_idx()); + ::SSL* ssl = reinterpret_cast< ::SSL* > (ex_data); + // Retrieve SSL_CTX pointer of the connection currently treated + ::SSL_CTX* ssl_ctx = ::SSL_get_SSL_CTX (ssl); + // Retrieve our SSL_CallbackManager + ex_data = ::SSL_CTX_get_ex_data (ssl_ctx, ssl_ctx_mngr_index_); + SSL_CallbackManager* cbmngr = reinterpret_cast<SSL_CallbackManager*> (ex_data); + + SSL_CertificateCallbackArg arg (cbmngr->context(), cert_ctx); + ok = cbmngr->verify_certificate_callback (arg); + } + + return ok; + } + + int SSL_CallbackManager::passwd_callback (char* buf, int size, int /*rwflag*/, void* user_data) + { + if (user_data == 0) + return 0; + + SSL_CallbackManager* cbmngr = reinterpret_cast<SSL_CallbackManager*> (user_data); + + ACE_CString pwd; + cbmngr->passwd_callback (pwd); + if (!pwd.empty ()) + { + ACE_OS::strncpy (buf, pwd.c_str (), size); + buf[size - 1] = '\0'; + if (size > ACE_Utils::truncate_cast<int> (pwd.length ())) + size = ACE_Utils::truncate_cast<int> (pwd.length ()); + + return size; + } + else + return 0; + } + + } +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/ACE/protocols/ace/INet/SSL_CallbackManager.h b/ACE/protocols/ace/INet/SSL_CallbackManager.h new file mode 100644 index 00000000000..80c51f81ec2 --- /dev/null +++ b/ACE/protocols/ace/INet/SSL_CallbackManager.h @@ -0,0 +1,78 @@ +// $Id$ + +/** + * @file SSL_CertificateManager.h + * + * @author Martin Corino <mcorino@remedy.nl> + */ + +#ifndef ACE_SSL_CALLBACKMANAGER_H +#define ACE_SSL_CALLBACKMANAGER_H + +#include /**/ "ace/pre.h" + +#include "ace/SString.h" +#include "ace/Refcounted_Auto_Ptr.h" +#include "ace/SSL/SSL_Context.h" +#include "ace/INet/SSL_CertificateCallback.h" +#include "ace/INet/SSL_PasswordCallback.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +namespace ACE + { + namespace INet + { + /** + * @class ACE_INet_SSL_CallbackManager + * + * @brief Implements manager class for configuring and handling + * SSL callbacks. + * + */ + class ACE_INET_Export SSL_CallbackManager + { + public: + SSL_CallbackManager (); + ~SSL_CallbackManager (); + + void initialize_callbacks (ACE_SSL_Context* ssl_ctx = ACE_SSL_Context::instance ()); + + const ACE_SSL_Context* context () const; + + void set_certificate_callback (ACE::INet::SSL_CertificateCallback* cb); + void set_password_callback (ACE::INet::SSL_PasswordCallback* cb); + + static SSL_CallbackManager* instance (); + + private: + int verify_certificate_callback (SSL_CertificateCallbackArg& arg); + void passwd_callback (ACE_CString& pwd); + + ACE_SSL_Context* ssl_ctx_; + + typedef ACE_Refcounted_Auto_Ptr<ACE::INet::SSL_CertificateCallback, + ACE_SYNCH::MUTEX> TCertificateCallback; + typedef ACE_Refcounted_Auto_Ptr<ACE::INet::SSL_PasswordCallback, + ACE_SYNCH::MUTEX> TPasswordCallback; + + TCertificateCallback cert_callback_; + TPasswordCallback passwd_callback_; + + static int verify_certificate_callback (int ok, X509_STORE_CTX* cert_ctx); + static int passwd_callback (char* buf, int size, int rwflag, void* user_data); + + static int ssl_ctx_mngr_index_; + }; + + } + } + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/INet/SSL_CallbackManager.inl" +#endif + +#include /**/ "ace/post.h" +#endif /* ACE_SSL_CALLBACKMANAGER_H */ diff --git a/ACE/protocols/ace/INet/SSL_CallbackManager.inl b/ACE/protocols/ace/INet/SSL_CallbackManager.inl new file mode 100644 index 00000000000..3728957c3f6 --- /dev/null +++ b/ACE/protocols/ace/INet/SSL_CallbackManager.inl @@ -0,0 +1,33 @@ +// -*- C++ -*- +// +// $Id$ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +namespace ACE +{ + namespace INet + { + + ACE_INLINE + const ACE_SSL_Context* SSL_CallbackManager::context () const + { + return this->ssl_ctx_; + } + + ACE_INLINE + void SSL_CallbackManager::set_certificate_callback (ACE::INet::SSL_CertificateCallback* cb) + { + this->cert_callback_.reset (cb); + } + + ACE_INLINE + void SSL_CallbackManager::set_password_callback (ACE::INet::SSL_PasswordCallback* cb) + { + this->passwd_callback_.reset (cb); + } + + } +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/ACE/protocols/ace/INet/SSL_CertificateCallback.cpp b/ACE/protocols/ace/INet/SSL_CertificateCallback.cpp new file mode 100644 index 00000000000..e1a4b0bce2e --- /dev/null +++ b/ACE/protocols/ace/INet/SSL_CertificateCallback.cpp @@ -0,0 +1,62 @@ +// $Id$ + +#include "ace/INet/SSL_CertificateCallback.h" + +#if !defined (__ACE_INLINE__) +#include "ace/INet/SSL_CertificateCallback.inl" +#endif + +#include "ace/Log_Msg.h" +#include "ace/INet/INet_Log.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +namespace ACE +{ + namespace INet + { + + SSL_CertificateCallbackArg::SSL_CertificateCallbackArg (const ACE_SSL_Context* ssl_ctx, + ::X509_STORE_CTX* cert_ctx) + : ssl_ctx_ (ssl_ctx), + err_depth_ (0), + err_code_ (0), + ignore_err_ (false) + { + this->ssl_cert_ = ::X509_STORE_CTX_get_current_cert (cert_ctx); + this->err_depth_ = ::X509_STORE_CTX_get_error_depth (cert_ctx); + this->err_code_ = ::X509_STORE_CTX_get_error (cert_ctx); + } + + SSL_CertificateCallbackArg::~SSL_CertificateCallbackArg () + { + } + + SSL_CertificateCallback::SSL_CertificateCallback () + { + } + + SSL_CertificateCallback::~SSL_CertificateCallback () + { + } + + SSL_CertificateAcceptor::SSL_CertificateAcceptor () + { + } + + SSL_CertificateAcceptor::~SSL_CertificateAcceptor () + { + } + + void SSL_CertificateAcceptor::handle_certificate_failure (SSL_CertificateCallbackArg& arg) + { + INET_DEBUG (3, (LM_INFO, DLINFO + ACE_TEXT ("SSL_CertificateAcceptor::handle_certificate_failure - ") + ACE_TEXT ("ignored certificate verification error: %C\n"), + arg.error_message ().c_str ())); + arg.ignore_error (true); + } + } +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/ACE/protocols/ace/INet/SSL_CertificateCallback.h b/ACE/protocols/ace/INet/SSL_CertificateCallback.h new file mode 100644 index 00000000000..c48f7ab1f71 --- /dev/null +++ b/ACE/protocols/ace/INet/SSL_CertificateCallback.h @@ -0,0 +1,102 @@ +// $Id$ + +/** + * @file SSL_CertificateCallback.h + * + * @author Martin Corino <mcorino@remedy.nl> + */ + +#ifndef ACE_SSL_CERTIFICATECALLBACK_H +#define ACE_SSL_CERTIFICATECALLBACK_H + +#include /**/ "ace/pre.h" + +#include "ace/SString.h" +#include "ace/SSL/SSL_Context.h" +#include "ace/INet/SSL_X509Cert.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +namespace ACE + { + namespace INet + { + /** + * @class ACE_INet_SSL_CertificateCallbackArg + * + * @brief Encapsulates the arguments for an SSL certificate + * verification callback. + * + */ + class ACE_INET_Export SSL_CertificateCallbackArg + { + public: + SSL_CertificateCallbackArg (const ACE_SSL_Context* ssl_ctx, + ::X509_STORE_CTX* cert_ctx); + ~SSL_CertificateCallbackArg (); + + const ACE_SSL_Context& context () const; + + SSL_X509Cert& certificate (void); + + int error_depth () const; + + int error_code () const; + + ACE_CString error_message () const; + + bool ignore_error () const; + + void ignore_error (bool f); + + private: + const ACE_SSL_Context* ssl_ctx_; + SSL_X509Cert ssl_cert_; + int err_depth_; + int err_code_; + bool ignore_err_; + }; + + /** + * @class ACE_INet_SSL_CertificateCallback + * + * @brief Abstract base class for SSL certificate + * verification callbacks. + * + */ + class ACE_INET_Export SSL_CertificateCallback + { + public: + SSL_CertificateCallback (); + virtual ~SSL_CertificateCallback (); + + virtual void handle_certificate_failure (SSL_CertificateCallbackArg& arg) = 0; + }; + + /** + * @class ACE_INet_SSL_CertificateAcceptor + * + * @brief Implements an SSL certificate callback that accepts + * all peer certificates. + * + */ + class ACE_INET_Export SSL_CertificateAcceptor + : public SSL_CertificateCallback + { + public: + SSL_CertificateAcceptor (); + virtual ~SSL_CertificateAcceptor (); + + virtual void handle_certificate_failure (SSL_CertificateCallbackArg& arg); + }; + } + } + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/INet/SSL_CertificateCallback.inl" +#endif + +#include /**/ "ace/post.h" +#endif /* ACE_SSL_CERTIFICATECALLBACK_H */ diff --git a/ACE/protocols/ace/INet/SSL_CertificateCallback.inl b/ACE/protocols/ace/INet/SSL_CertificateCallback.inl new file mode 100644 index 00000000000..614db4394ac --- /dev/null +++ b/ACE/protocols/ace/INet/SSL_CertificateCallback.inl @@ -0,0 +1,57 @@ +// -*- C++ -*- +// +// $Id$ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +namespace ACE +{ + namespace INet + { + + ACE_INLINE + const ACE_SSL_Context& SSL_CertificateCallbackArg::context () const + { + return *this->ssl_ctx_; + } + + ACE_INLINE + SSL_X509Cert& SSL_CertificateCallbackArg::certificate (void) + { + return this->ssl_cert_; + } + + ACE_INLINE + int SSL_CertificateCallbackArg::error_depth () const + { + return this->err_depth_; + } + + ACE_INLINE + int SSL_CertificateCallbackArg::error_code () const + { + return this->err_code_; + } + + ACE_INLINE + ACE_CString SSL_CertificateCallbackArg::error_message () const + { + return ACE_CString (X509_verify_cert_error_string (this->err_code_)); + } + + ACE_INLINE + bool SSL_CertificateCallbackArg::ignore_error () const + { + return this->ignore_err_; + } + + ACE_INLINE + void SSL_CertificateCallbackArg::ignore_error (bool f) + { + this->ignore_err_ = f; + } + + } +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/ACE/protocols/ace/INet/SSL_PasswordCallback.cpp b/ACE/protocols/ace/INet/SSL_PasswordCallback.cpp new file mode 100644 index 00000000000..08811a19563 --- /dev/null +++ b/ACE/protocols/ace/INet/SSL_PasswordCallback.cpp @@ -0,0 +1,23 @@ +// $Id$ + +#include "ace/INet/SSL_PasswordCallback.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +namespace ACE +{ + namespace INet + { + + SSL_PasswordCallback::SSL_PasswordCallback () + { + } + + SSL_PasswordCallback::~SSL_PasswordCallback () + { + } + + } +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/ACE/protocols/ace/INet/SSL_PasswordCallback.h b/ACE/protocols/ace/INet/SSL_PasswordCallback.h new file mode 100644 index 00000000000..8c301964f03 --- /dev/null +++ b/ACE/protocols/ace/INet/SSL_PasswordCallback.h @@ -0,0 +1,44 @@ +// $Id$ + +/** + * @file SSL_PasswordCallback.h + * + * @author Martin Corino <mcorino@remedy.nl> + */ + +#ifndef ACE_SSL_PASSWORDCALLBACK_H +#define ACE_SSL_PASSWORDCALLBACK_H + +#include /**/ "ace/pre.h" + +#include "ace/SString.h" +#include "ace/INet/INet_Log.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +namespace ACE + { + namespace INet + { + /** + * @class ACE_INet_SSL_PasswordCallback + * + * @brief Abstract base class for SSL private key + * password callback. + * + */ + class ACE_INET_Export SSL_PasswordCallback + { + public: + SSL_PasswordCallback (); + virtual ~SSL_PasswordCallback (); + + virtual void get_privatekey_password (ACE_CString& pwd) = 0; + }; + } + } + +ACE_END_VERSIONED_NAMESPACE_DECL + +#include /**/ "ace/post.h" +#endif /* ACE_SSL_PASSWORDCALLBACK_H */ diff --git a/ACE/protocols/ace/INet/SSL_Proxy_Connector.cpp b/ACE/protocols/ace/INet/SSL_Proxy_Connector.cpp new file mode 100644 index 00000000000..d1ffcbf7c1e --- /dev/null +++ b/ACE/protocols/ace/INet/SSL_Proxy_Connector.cpp @@ -0,0 +1,212 @@ +// $Id$ + +#include "ace/INet/SSL_Proxy_Connector.h" +#include "ace/INet/INet_Log.h" + +#include "ace/OS_NS_errno.h" +#include "ace/Handle_Set.h" +#include "ace/Log_Msg.h" +#include "ace/Countdown_Time.h" +#include "ace/Truncate.h" + +#include <openssl/err.h> + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +namespace ACE +{ + namespace INet + { + + SSL_Proxy_Connector::SSL_Proxy_Connector () {} + + SSL_Proxy_Connector::~SSL_Proxy_Connector () {} + + /* + * This code is copied from ace/SSL/SSL_SOCK_Connector.cpp + */ + int + SSL_Proxy_Connector::ssl_connect (ACE_SSL_SOCK_Stream &new_stream, + const ACE_Time_Value *timeout) + { + SSL *ssl = new_stream.ssl (); + + if (SSL_is_init_finished (ssl)) + return 0; + + // Check if a connection is already pending for the given SSL + // structure. + if (!SSL_in_connect_init (ssl)) + ::SSL_set_connect_state (ssl); + + ACE_HANDLE handle = new_stream.get_handle (); + + // We're going to call SSL_connect, optionally doing ACE::select and + // retrying the SSL_connect, until the SSL handshake is done or + // it fails. + // To get the timeout affect, set the socket to nonblocking mode + // before beginning if there is a timeout specified. If the timeout + // is 0 (wait as long as it takes) then don't worry about the blocking + // status; we'll block in SSL_connect if the socket is blocking, and + // block in ACE::select if not. + int reset_blocking_mode = 0; + if (timeout != 0) + { + reset_blocking_mode = ACE_BIT_DISABLED (ACE::get_flags (handle), + ACE_NONBLOCK); + // Set the handle into non-blocking mode if it's not already + // in it. + if (reset_blocking_mode + && ACE::set_flags (handle, + ACE_NONBLOCK) == -1) + return -1; + } + + ACE_Time_Value t; + if (timeout != 0) + t = *timeout; // Need a non-const copy. + + // Take into account the time between each select() call below. + ACE_Countdown_Time countdown ((timeout == 0 ? 0 : &t)); + + int status; + + do + { + // These handle sets are used to set up for whatever SSL_connect + // says it wants next. They're reset on each pass around the loop. + ACE_Handle_Set rd_handle; + ACE_Handle_Set wr_handle; + + status = ::SSL_connect (ssl); + switch (::SSL_get_error (ssl, status)) + { + case SSL_ERROR_NONE: + // Start out with non-blocking disabled on the SSL stream. + new_stream.disable (ACE_NONBLOCK); + status = 0; // To tell caller about success + break; // Done + + case SSL_ERROR_WANT_WRITE: + wr_handle.set_bit (handle); + status = 1; // Wait for more activity + break; + + case SSL_ERROR_WANT_READ: + rd_handle.set_bit (handle); + status = 1; // Wait for more activity + break; + + case SSL_ERROR_ZERO_RETURN: + // The peer has notified us that it is shutting down via + // the SSL "close_notify" message so we need to + // shutdown, too. + status = -1; + break; + + case SSL_ERROR_SYSCALL: + // On some platforms (e.g. MS Windows) OpenSSL does not + // store the last error in errno so explicitly do so. + // + // Explicitly check for EWOULDBLOCK since it doesn't get + // converted to an SSL_ERROR_WANT_{READ,WRITE} on some + // platforms. If SSL_connect failed outright, though, don't + // bother checking more. This can happen if the socket gets + // closed during the handshake. + if (ACE_OS::set_errno_to_last_error () == EWOULDBLOCK && + status == -1) + { + // Although the SSL_ERROR_WANT_READ/WRITE isn't getting + // set correctly, the read/write state should be valid. + // Use that to decide what to do. + status = 1; // Wait for more activity + if (SSL_want_write (ssl)) + { + wr_handle.set_bit (handle); + } + else if (SSL_want_read (ssl)) + { + rd_handle.set_bit (handle); + } + else + { + status = -1; // Doesn't want anything - bail out + } + } + else + { + status = -1; + } + break; + + default: + ACE_SSL_Context::report_error (); + status = -1; + break; + } + + if (status == 1) + { + // Must have at least one handle to wait for at this point. + ACE_ASSERT (rd_handle.num_set () == 1 || wr_handle.num_set () == 1); + + // Block indefinitely if timeout pointer is zero. + status = ACE::select (int (handle) + 1, + &rd_handle, + &wr_handle, + 0, + (timeout == 0 ? 0 : &t)); + + (void) countdown.update (); + + // 0 is timeout, so we're done. + // -1 is error, so we're done. + // Could be both handles set (same handle in both masks) so set to 1. + if (status >= 1) + { + status = 1; + } + else // Timeout or socket failure + { + status = -1; + } + } + + } while (status == 1 && !SSL_is_init_finished (ssl)); + + if (reset_blocking_mode) + { + ACE_Errno_Guard eguard (errno); + ACE::clr_flags (handle, ACE_NONBLOCK); + } + + return (status == -1 ? -1 : 0); + } + + int + SSL_Proxy_Connector::connect (ACE_SSL_SOCK_Stream &new_stream, + ACE_HANDLE proxy_handle, + const ACE_Time_Value *timeout) + { + INET_TRACE ("SSL_Proxy_Connector::connect"); + + if (new_stream.get_handle () != ACE_INVALID_HANDLE) + return -1; // SSL already connected, somebody made a mistake here + + // Set the handle from the established proxy connection in the + // SSL_SOCK_Stream. + new_stream.set_handle (proxy_handle); + + // Finalize the connection by performing the SSL handshake + int result = this->ssl_connect (new_stream, timeout); + + if (result == -1) + new_stream.close (); + + return result; + } + + } +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/ACE/protocols/ace/INet/SSL_Proxy_Connector.h b/ACE/protocols/ace/INet/SSL_Proxy_Connector.h new file mode 100644 index 00000000000..501e22401ee --- /dev/null +++ b/ACE/protocols/ace/INet/SSL_Proxy_Connector.h @@ -0,0 +1,60 @@ +// $Id$ + +/** + * @file SSL_Proxy_Connector.h + * + * @author Martin Corino <mcorino@remedy.nl> + */ + +#ifndef ACE_SSL_PROXY_CONNECTOR_H +#define ACE_SSL_PROXY_CONNECTOR_H + +#include /**/ "ace/pre.h" + +#include "ace/SSL/SSL_SOCK_Stream.h" +#include "ace/Time_Value.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +namespace ACE + { + namespace INet + { + /** + * @class ACE_INet_SSL_Proxy_Connector + * + * @brief Provides the functionality to attach an SSL_SOCK_Stream + * to an established socket of a proxy tunneling service. + * + * The <connect> method will finalize the setting up an SSL connection + * over the tunnel by performing an SSL handhake after setting the socket + * in the @c SSL_SOCK_Stream. + */ + class SSL_Proxy_Connector + { + public: + SSL_Proxy_Connector (); + ~SSL_Proxy_Connector (); + + /** + * Actively connect to an already connected proxy peer, producing a + * connected @c ACE_SSL_SOCK_Stream object if the connection succeeds. + * This method uses the provided connection (socket) handle to initialize + * the @c ACE_SSL_SOCK_Stream object and than finalizes the connection + * by performing the SSL handshake. + */ + int connect (ACE_SSL_SOCK_Stream& new_stream, + ACE_HANDLE proxy_handle, + const ACE_Time_Value *timeout = 0); + protected: + /// Complete non-blocking SSL active connection. + int ssl_connect (ACE_SSL_SOCK_Stream &new_stream, + const ACE_Time_Value *timeout); + }; + } + } + +ACE_END_VERSIONED_NAMESPACE_DECL + +#include /**/ "ace/post.h" +#endif /* ACE_SSL_PROXY_CONNECTOR_H */ diff --git a/ACE/protocols/ace/INet/SSL_X509Cert.cpp b/ACE/protocols/ace/INet/SSL_X509Cert.cpp new file mode 100644 index 00000000000..44845a70352 --- /dev/null +++ b/ACE/protocols/ace/INet/SSL_X509Cert.cpp @@ -0,0 +1,18 @@ +// $Id$ + +#include "ace/INet/SSL_X509Cert.h" + +#if !defined (__ACE_INLINE__) +#include "ace/INet/SSL_X509Cert.inl" +#endif + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +namespace ACE +{ + namespace INet + { + } +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/ACE/protocols/ace/INet/SSL_X509Cert.h b/ACE/protocols/ace/INet/SSL_X509Cert.h new file mode 100644 index 00000000000..250c8c8e19c --- /dev/null +++ b/ACE/protocols/ace/INet/SSL_X509Cert.h @@ -0,0 +1,57 @@ +// $Id$ + +/** + * @file SSL_X509Cert.h + * + * @author Martin Corino <mcorino@remedy.nl> + */ + +#ifndef ACE_SSL_X509CERT_H +#define ACE_SSL_X509CERT_H + +#include /**/ "ace/pre.h" + +#include <openssl/x509.h> +#include <openssl/crypto.h> +#include "ace/INet/INet_Export.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +namespace ACE + { + namespace INet + { + /** + * @class ACE_INet_SSL_X509Cert + * + * @brief Encapsulates an SSL X509 certificate object. + * + * Provides reference counting for the X509 certificate object. + */ + class ACE_INET_Export SSL_X509Cert + { + public: + SSL_X509Cert (); + SSL_X509Cert (::X509* ssl_cert); + SSL_X509Cert (const SSL_X509Cert& cert); + ~SSL_X509Cert (); + + SSL_X509Cert& operator= (::X509* ssl_cert); + SSL_X509Cert& operator= (const SSL_X509Cert& ssl_cert); + + ::X509* operator & (void); + + private: + ::X509* ssl_cert_; + }; + } + } + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/INet/SSL_X509Cert.inl" +#endif + +#include /**/ "ace/post.h" +#endif /* ACE_SSL_X509CERT_H */ diff --git a/ACE/protocols/ace/INet/SSL_X509Cert.inl b/ACE/protocols/ace/INet/SSL_X509Cert.inl new file mode 100644 index 00000000000..0c0c0f8a88c --- /dev/null +++ b/ACE/protocols/ace/INet/SSL_X509Cert.inl @@ -0,0 +1,65 @@ +// -*- C++ -*- +// +// $Id$ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +namespace ACE +{ + namespace INet + { + + ACE_INLINE + SSL_X509Cert::SSL_X509Cert () + : ssl_cert_ (0) + { + } + + ACE_INLINE + SSL_X509Cert::SSL_X509Cert (::X509* ssl_cert) + : ssl_cert_ (0) + { + *this = ssl_cert; + } + + ACE_INLINE + SSL_X509Cert::SSL_X509Cert (const SSL_X509Cert& cert) + { + *this = cert; + } + + ACE_INLINE + SSL_X509Cert::~SSL_X509Cert () + { + } + + ACE_INLINE + SSL_X509Cert& SSL_X509Cert::operator= (::X509* ssl_cert) + { + if (this->ssl_cert_ != 0) + ::X509_free (this->ssl_cert_); + + if (ssl_cert != 0) + CRYPTO_add (&(ssl_cert->references), + 1, + CRYPTO_LOCK_X509); + this->ssl_cert_ = ssl_cert; + return *this; + } + + ACE_INLINE + SSL_X509Cert& SSL_X509Cert::operator= (const SSL_X509Cert& ssl_cert) + { + return (*this = &(const_cast<SSL_X509Cert&> (ssl_cert))); + } + + ACE_INLINE + ::X509* SSL_X509Cert::operator & (void) + { + return this->ssl_cert_; + } + + } +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/ACE/protocols/ace/INet/StreamHandler.cpp b/ACE/protocols/ace/INet/StreamHandler.cpp index c779692f384..083f0539296 100644 --- a/ACE/protocols/ace/INet/StreamHandler.cpp +++ b/ACE/protocols/ace/INet/StreamHandler.cpp @@ -160,8 +160,8 @@ namespace ACE } if (send_cnt <= 0) { - ACE_ERROR ((LM_ERROR, - ACE_TEXT ("(%P|%t) %p; ACE_IOS_StreamHandler - "), + INET_ERROR (1, (LM_ERROR, DLINFO + ACE_TEXT ("%p; ACE_IOS_StreamHandler - "), ACE_TEXT ("send failed\n"))); this->connected_ = false; return this->using_reactor () ? -1 : 0; diff --git a/ACE/protocols/ace/INet/StreamInterceptor.h b/ACE/protocols/ace/INet/StreamInterceptor.h index 326f95b1739..94cf93125ac 100644 --- a/ACE/protocols/ace/INet/StreamInterceptor.h +++ b/ACE/protocols/ace/INet/StreamInterceptor.h @@ -30,7 +30,7 @@ namespace ACE /** * @class ACE_IOS_StreamInterceptorBase * - * @brief + * @brief Abstract base for stream interceptors. * */ template <class ACE_CHAR_T, class TR = std::char_traits<ACE_CHAR_T> > diff --git a/ACE/protocols/ace/INet/URLBase.h b/ACE/protocols/ace/INet/URLBase.h index 01daed0b87f..923b6db07c1 100644 --- a/ACE/protocols/ace/INet/URLBase.h +++ b/ACE/protocols/ace/INet/URLBase.h @@ -32,8 +32,11 @@ namespace ACE /** * @class ACE_INet_URLStream * - * @brief + * @brief Provides abstracted wrapper class for the resulting + * stream of an URL <open> operation. * + * Provides proper life cycle management for either factory provided + * or user provided request handlers. */ class ACE_INET_Export URLStream { @@ -142,7 +145,7 @@ namespace ACE private: typedef ACE_Map_Manager<ACE_CString, Factory*, - ACE_SYNCH::RECURSIVE_MUTEX> TURLFactoryMap; + ACE_SYNCH::MUTEX> TURLFactoryMap; typedef ACE_Singleton<TURLFactoryMap, ACE_SYNCH::NULL_MUTEX> TURLFactorySingleton; static TURLFactoryMap* factories_; diff --git a/ACE/protocols/ace/INet/inet.mpc b/ACE/protocols/ace/INet/inet.mpc index 16e08e5a92c..a15427f79c0 100644 --- a/ACE/protocols/ace/INet/inet.mpc +++ b/ACE/protocols/ace/INet/inet.mpc @@ -1,7 +1,7 @@ // -*- MPC -*- // $Id$ -project(INet) : acelib, ace_output, install { +project(INet) : acelib, ace_output, install, inet_ssl { sharedname = ACE_INet dynamicflags += ACE_INET_BUILD_DLL includes += $(ACE_ROOT)/protocols @@ -21,6 +21,7 @@ project(INet) : acelib, ace_output, install { HTTP_Response.cpp HTTP_Request.cpp HTTP_IOStream.cpp + HTTP_SessionBase.cpp URLBase.cpp AuthenticationBase.cpp HTTP_URL.cpp diff --git a/ACE/protocols/ace/INet/inet_ssl.mpb b/ACE/protocols/ace/INet/inet_ssl.mpb new file mode 100644 index 00000000000..5442cfaedd5 --- /dev/null +++ b/ACE/protocols/ace/INet/inet_ssl.mpb @@ -0,0 +1,18 @@ +feature(ssl) : ace_openssl { + Source_Files { + SSL_X509Cert.cpp + SSL_CertificateCallback.cpp + SSL_PasswordCallback.cpp + SSL_CallbackManager.cpp + HTTPS_Context.cpp + HTTPS_URL.cpp + HTTPS_SessionFactory.cpp + SSL_Proxy_Connector.cpp + } + Template_Files { + SSLSock_IOStream.cpp + HTTPS_Session.cpp + } + Header_Files { + } +} diff --git a/ACE/protocols/tests/INet/MT_Get/Main.cpp b/ACE/protocols/tests/INet/MT_Get/Main.cpp index e24c831bee6..a106c5e6fab 100644 --- a/ACE/protocols/tests/INet/MT_Get/Main.cpp +++ b/ACE/protocols/tests/INet/MT_Get/Main.cpp @@ -37,8 +37,10 @@ Get_Task::Get_Task (ACE_Thread_Manager *thr_mgr, n_threads_ (n_threads) { // Create worker threads. - if (this->activate (THR_NEW_LWP, n_threads) == -1) + if (this->activate (THR_NEW_LWP, n_threads_) == -1) ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("activate failed"))); + else + ACE_DEBUG ((LM_INFO, ACE_TEXT ("(%P|%t) started %d threads\n"), n_threads_)); } void Get_Task::shutdown () @@ -48,7 +50,7 @@ void Get_Task::shutdown () lock_); --n_threads_; - if (n_threads_ >= 0) + if (n_threads_ <= 0) { ACE_DEBUG ((LM_INFO, ACE_TEXT ("(%P|%t) ending event loop\n"))); ACE_Reactor::instance ()->end_event_loop (); @@ -178,7 +180,7 @@ void Get_MultiTask::shutdown () lock_); --n_threads_; - if (n_threads_ >= 0) + if (n_threads_ <= 0) { ACE_DEBUG ((LM_INFO, ACE_TEXT ("(%P|%t) ending event loop\n"))); ACE_Reactor::instance ()->end_event_loop (); |