CBDATA_CLASS_INIT(Downloader);
-Downloader::Downloader(SBuf &url, const MasterXaction::Pointer &xact, AsyncCall::Pointer &aCallback):
+Downloader::Downloader(SBuf &url, const MasterXaction::Pointer &xact, AsyncCall::Pointer &aCallback, unsigned int level):
AsyncJob("Downloader"),
ConnStateData(xact),
url_(url),
callback(aCallback),
- status(Http::scNone)
+ status(Http::scNone),
+ level_(level)
{
maxObjectSize = 512*1024;
}
Http::StatusCode status;
};
- explicit Downloader(SBuf &url, const MasterXaction::Pointer &xact, AsyncCall::Pointer &aCallback);
+ explicit Downloader(SBuf &url, const MasterXaction::Pointer &xact, AsyncCall::Pointer &aCallback, unsigned int level = 0);
virtual ~Downloader();
void downloadFinished();
+
+ /// The nested level of Downloader object (downloads inside downloads)
+ unsigned int nestedLevel() const {return level_;}
/* ConnStateData API */
virtual bool isOpen() const;
Http::StatusCode status;
SBuf object; //object data
size_t maxObjectSize;
+ unsigned int level_; ///< Holds the nested downloads level
};
#endif
callback(aCallback),
negotiationTimeout(timeout),
startTime(squid_curtime),
- useCertValidator_(false)
+ useCertValidator_(false),
+ certsDownloads(0)
{
// if this throws, the caller's cb dialer is not our CbDialer
Must(dynamic_cast<CbDialer*>(callback->getDialer()));
"Ssl::PeerConnector::certDownloadingDone",
PeerConnectorCertDownloaderDialer(&Ssl::PeerConnector::certDownloadingDone, this));
+ const Downloader *csd = dynamic_cast<const Downloader*>(request->clientConnectionManager.valid());
MasterXaction *xaction = new MasterXaction;
- Downloader *dl = new Downloader(url, xaction, certCallback);
+ Downloader *dl = new Downloader(url, xaction, certCallback, csd ? csd->nestedLevel() + 1 : 1);
AsyncJob::Start(dl);
}
void
Ssl::PeerConnector::certDownloadingDone(SBuf &obj, int downloadStatus)
{
+ certsDownloads++;
debugs(81, 5, "OK! certificate downloaded, status: " << downloadStatus << " data size: " << obj.length());
// Get ServerBio from SSL object
}
// Check if has uri to donwload and add it to urlsOfMissingCerts
- if (urlsOfMissingCerts.size()) {
+ if (urlsOfMissingCerts.size() && certsDownloads <= MaxCertsDownloads) {
startCertDownloading(urlsOfMissingCerts.front());
urlsOfMissingCerts.pop();
return;
bool
Ssl::PeerConnector::checkForMissingCertificates ()
{
+ // Check for nested SSL certificates downloads. For example when the
+ // certificate located in an SSL site which requires to download a
+ // a missing certificate (... from an SSL site which requires to ...)
+ const Downloader *csd = dynamic_cast<const Downloader*>(request->clientConnectionManager.valid());
+ if (csd && csd->nestedLevel() >= MaxNestedDownloads)
+ return false;
+
const int fd = serverConnection()->fd;
SSL *ssl = fd_table[fd].ssl;
BIO *b = SSL_get_rbio(ssl);
/// A wrapper function for negotiateSsl for use with Comm::SetSelect
static void NegotiateSsl(int fd, void *data);
+
+ /// The maximum allowed missing certificates downloads
+ static const unsigned int MaxCertsDownloads = 10;
+ /// The maximum allowed nested certificates downloads
+ static const unsigned int MaxNestedDownloads = 3;
+
AsyncCall::Pointer callback; ///< we call this with the results
AsyncCall::Pointer closeHandler; ///< we call this when the connection closed
time_t negotiationTimeout; ///< the SSL connection timeout to use
time_t startTime; ///< when the peer connector negotiation started
bool useCertValidator_; ///< whether the certificate validator should bypassed
-
+ /// The list of URLs where missing certificates should be downloaded
std::queue<SBuf> urlsOfMissingCerts;
+ unsigned int certsDownloads; ///< The number of downloaded missing certificates
};
/// A simple PeerConnector for SSL/TLS cache_peers. No SslBump capabilities.