/*! @file @id $Id$ */ // 1 2 3 4 5 6 7 8 // 45678901234567890123456789012345678901234567890123456789012345678901234567890 #ifndef PROXYFACE_HXX #define PROXYFACE_HXX #ifdef QT_NETWORK_LIB #include #include #include #include #include #include #endif #include #include #include //! auto proxy configuration namespace proxy { //! exceptions namespace exc { //! unspecific error class error: std::exception { public: virtual const char* what() const throw() { return "Auto Proxy Detection Error"; } }; } //! Proxy types enum Type { DIRECT, //< direct connection, no proxy DEFAULT, //< default proxy HTTP, //< HTTP proxy host SOCKS //>port; } Type type; std::string host; unsigned int port; }; //! List of proxies, type -> url and port typedef std::list List; //! Unified Interface for accessing proxy::Face /*! Abstract interface, impementation for Unix and Windoze differs. Instanciate proxy::Face, which is a typedef to your platform's implementation. @code proxy::Auto pf; // keep for program life time (because of caching) proxy::List pf.proxies("http://swisssign.com"); [...] // set proxy, read from http://swisssign.com @endcode @example test.cxx */ class Interface #ifdef QT_NETWORK_LIB : public QObject #endif { #ifdef QT_NETWORK_LIB Q_OBJECT; #endif public: //! Keep your instance as long as possible, because of caching. Interface() { #ifdef QT_NETWORK_LIB if (!connect(&_timeout, SIGNAL(timeout()), SLOT(timeout()))) qFatal("connect failed"); #endif } virtual ~Interface() {} //! Get list of proxies for a given URL. virtual List proxies(const std::string& url) = 0; #ifdef QT_NETWORK_LIB //! If Qt Network is available you may check the proxies found /*! First checks for direct access to the target. If this is not possible, starts scan for proxies. Returns immediately and signals proxyFound() if a valid configuration has been found, or proxyError() in case of timeout. You should wait for either of the signals, before you can call this method again. @param url the url to find a proxy for @param timeout [ms] time to give up search */ void proxy(const std::string& url, int timeout=2000) { qDebug()<<"Search proxy for URL, direct and default" <<"url="<second.first; _requests.clear(); _direct = true; // first try direct access QNetworkProxy directProxy(QNetworkProxy::NoProxy); setupProxyCheck(directProxy, url); QNetworkProxy defaultProxy; setupProxyCheck(defaultProxy, url); _timeout.setSingleShot(true); _timeout.setInterval(timeout); _timeout.start(); } //! If Qt Network is available you may check the proxies found /*! @copydoc proxy(const std::string&, int) */ void proxy(const QUrl& url, int timeout=2000) { proxy(url.toString().toStdString(), timeout); } //! If Qt Network is available you may check the proxies found /*! @copydoc proxy(const std::string&, int) */ void proxy(const QString& url, int timeout=2000) { proxy(url.toStdString(), timeout); } static QString toString(const QNetworkProxy& p) { switch (p.type()) { case QNetworkProxy::NoProxy: return QString("direct://"); case QNetworkProxy::DefaultProxy: if (QNetworkProxy::applicationProxy().type() !=QNetworkProxy::DefaultProxy) return QString("Default Proxy: %1") .arg(toString(QNetworkProxy::applicationProxy())); else return QString("Default Proxy: **ERROR**" " application proxy is configured as" " QNetworkProxy::DefaultProxy"); case QNetworkProxy::Socks5Proxy: return QString("socks://%1:%2").arg(p.hostName()).arg(p.port()); case QNetworkProxy::HttpProxy: return QString("http://%1:%2").arg(p.hostName()).arg(p.port()); case QNetworkProxy::HttpCachingProxy: return QString("http-cache://%1:%2").arg(p.hostName()).arg(p.port()); case QNetworkProxy::FtpCachingProxy: return QString("ftp-cache://%1:%2").arg(p.hostName()).arg(p.port()); } return QString("**ERROR** illegal proxy type"); } Q_SIGNALS: //! Signals a valid proxy for the URL requested earlier. void proxyFound(const QUrl&, const QNetworkProxy&); //! Signals a timeout, and no valid proxy for the URL requested earlier. void proxyError(QNetworkReply::NetworkError); private: void setupProxyCheck(const QNetworkProxy& prxy, const std::string& url) { qDebug()<<"Testing proxy for url:"<setProxy(prxy); if (!connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*)))) qFatal("connect failed"); _requests.insert (std::make_pair(manager->head (QNetworkRequest (QUrl(QString::fromStdString(url)))), std::make_pair(manager, prxy))); } private Q_SLOTS: void timeout() { _timeout.stop(); std::string url; for (Requests::iterator it(_requests.begin()); it!=_requests.end(); ++it) { url = it->first->url().toString().toStdString(); delete it->second.first; } _requests.clear(); qDebug()<<"Proxy detection timed out"<<"url="<type==DEFAULT?QNetworkProxy::DefaultProxy :(it->type==HTTP?QNetworkProxy::HttpProxy :(it->type==SOCKS?QNetworkProxy::Socks5Proxy :QNetworkProxy::NoProxy))), QString::fromStdString(it->host), it->port); setupProxyCheck(prxy, url); } _timeout.start(); } else { qDebug()<<"No proxy at all, giving up - offline?"; proxyError(QNetworkReply::TimeoutError); } } void replyFinished(QNetworkReply* reply) { _timeout.stop(); QNetworkProxy prxy(_requests[reply].second); QUrl url(reply->url()); for (Requests::iterator it(_requests.begin()); it!=_requests.end(); ++it) delete it->second.first; _requests.clear(); qDebug()<<"SUCCESS - Valid proxy found for url:" <<"url="< > Requests; Requests _requests; bool _direct; QTimer _timeout; #endif }; } #ifdef WIN32 // use windoze proprietary winhttp #include namespace proxy { typedef Windoze Face; } #else // normal operating systems: use http://code.google.com/p/libproxy #include namespace proxy { typedef Unix Face; } #endif #endif