summaryrefslogtreecommitdiff
path: root/libproxy/proxy.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libproxy/proxy.cpp')
-rw-r--r--libproxy/proxy.cpp500
1 files changed, 0 insertions, 500 deletions
diff --git a/libproxy/proxy.cpp b/libproxy/proxy.cpp
deleted file mode 100644
index 5db3033..0000000
--- a/libproxy/proxy.cpp
+++ /dev/null
@@ -1,500 +0,0 @@
-/*******************************************************************************
- * libproxy - A library for proxy configuration
- * Copyright (C) 2006 Nathaniel McCallum <nathaniel@natemccallum.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- ******************************************************************************/
-
-#include <vector>
-#include <cstring> // For strdup()
-#include <iostream> // For cerr
-#include <stdexcept> // For exception
-#include <typeinfo> // Only for debug messages.
-
-#include <libmodman/module_manager.hpp>
-
-#include "extension_config.hpp"
-#include "extension_ignore.hpp"
-#include "extension_network.hpp"
-#include "extension_pacrunner.hpp"
-#include "extension_wpad.hpp"
-
-#ifdef WIN32
-#define strdup _strdup
-#endif
-
-#define X(m) MM_DEF_BUILTIN(m);
-BUILTIN_MODULES
-#undef X
-
-#define X(m) &MM_BUILTIN(m),
-static struct mm_module* builtin_modules[] = {
- BUILTIN_MODULES
- NULL
-};
-#undef X
-
-namespace libproxy {
-using namespace std;
-
-class proxy_factory {
-public:
- proxy_factory();
- ~proxy_factory();
- vector<string> get_proxies(const string &url);
-
-private:
- void lock();
- void unlock();
-
- void check_network_topology();
- void get_config(url &realurl, vector<url> &configs, string &ignore);
- bool is_ignored(url &realurl, const string &ignore);
- bool expand_wpad(const url &confurl);
- bool expand_pac(url &configurl);
- void run_pac(url &realurl, const url &confurl, vector<string> &response);
- void clear_cache();
-
-#ifdef WIN32
- HANDLE mutex;
-#else
- pthread_mutex_t mutex;
-#endif
- module_manager mm;
- char* pac;
- url* pacurl;
- bool wpad;
- bool debug;
-};
-
-static bool istringcmp(string a, string b) {
- transform( a.begin(), a.end(), a.begin(), ::tolower );
- transform( b.begin(), b.end(), b.begin(), ::tolower );
- return ( a == b );
-}
-
-// Convert the PAC formatted response into our proxy URL array response
-static void format_pac_response(string response, vector<string> &retval)
-{
- // Skip ahead one character if we start with ';'
- if (response[0] == ';') {
- format_pac_response(response.substr(1), retval);
- return;
- }
-
- // If the string contains a delimiter (';')
- if (response.find(';') != string::npos) {
- format_pac_response(response.substr(response.find(';') + 1), retval);
- response = response.substr(0, response.find(';'));
- }
-
- // Strip whitespace
- if (response.size() > 0)
- response = response.substr(response.find_first_not_of(" \t\n"), response.find_last_not_of(" \t\n")+1);
-
- // Get the method and the server
- string method = "";
- string server = "";
- if (response.find_first_of(" \t") == string::npos)
- method = response;
- else {
- method = response.substr(0, response.find_first_of(" \t"));
- server = response.substr(response.find_first_of(" \t") + 1);
- }
-
- // Insert our url value
- if (istringcmp(method, "proxy") && url::is_valid("http://" + server))
- retval.insert(retval.begin(), string("http://") + server);
- else if (istringcmp(method, "socks") && url::is_valid("http://" + server))
- retval.insert(retval.begin(), string("socks://") + server);
- else if (istringcmp(method, "socks4") && url::is_valid("http://" + server))
- retval.insert(retval.begin(), string("socks4://") + server);
- else if (istringcmp(method, "socks4a") && url::is_valid("http://" + server))
- retval.insert(retval.begin(), string("socks4a://") + server);
- else if (istringcmp(method, "socks5") && url::is_valid("http://" + server))
- retval.insert(retval.begin(), string("socks5://") + server);
- else if (istringcmp(method, "direct"))
- retval.insert(retval.begin(), string("direct://"));
-}
-
-proxy_factory::proxy_factory() {
- const char *module_dir;
-
-#ifdef WIN32
- this->mutex = CreateMutex(NULL, false, NULL);
- WSADATA wsadata;
- WORD vers = MAKEWORD(2, 2);
- WSAStartup(vers, &wsadata);
-#else
- pthread_mutex_init(&this->mutex, NULL);
-#endif
-
- lock();
-
- this->pac = NULL;
- this->pacurl = NULL;
- this->wpad = false;
-
- // Register our types
- this->mm.register_type<config_extension>();
- this->mm.register_type<ignore_extension>();
- this->mm.register_type<network_extension>();
- this->mm.register_type<pacrunner_extension>();
- this->mm.register_type<wpad_extension>();
-
- // Load builtin modules
- for (int i=0 ; builtin_modules[i] ; i++)
- this->mm.load_builtin(builtin_modules[i]);
-
- // Load all modules
- module_dir = getenv("PX_MODULE_PATH");
- if (!module_dir)
- module_dir = MODULEDIR;
- this->mm.load_dir(module_dir);
- this->mm.load_dir(module_dir, false);
-
- this->debug = (getenv("_PX_DEBUG") != NULL);
-
- unlock();
-}
-
-proxy_factory::~proxy_factory() {
- lock();
-
- if (this->pac) delete[] this->pac;
- if (this->pacurl) delete this->pacurl;
-
- unlock();
-
-#ifdef WIN32
- WSACleanup();
- ReleaseMutex(this->mutex);
-#else
- pthread_mutex_destroy(&this->mutex);
-#endif
-}
-
-
-vector<string> proxy_factory::get_proxies(const string &realurl) {
- vector<string> response;
-
- // Check to make sure our url is valid
- if (!url::is_valid(realurl))
- goto do_return;
-
- lock();
-
- // Let trap and forward exceptions so we don't deadlock
- try {
- vector<url> configs;
- string ignore;
- url dst(realurl);
-
- check_network_topology();
- get_config(dst, configs, ignore);
-
- if (debug) cerr << "Config is: " << endl;
-
- for (vector<url>::iterator i=configs.begin() ; i != configs.end() ; i++) {
- url confurl(*i);
-
- if (debug) cerr << "\t" << confurl.to_string() << endl;
-
- if (expand_wpad(confurl) || expand_pac(confurl)) {
- run_pac(dst, confurl, response);
- } else {
- clear_cache();
- response.push_back(confurl.to_string());
- }
- }
-
- unlock();
- } catch (exception &e) {
- unlock();
- throw e;
- }
-
-do_return:
- if (response.size() == 0)
- response.push_back("direct://");
- return response;
-}
-
-void proxy_factory::check_network_topology() {
- vector<network_extension*> networks;
-
- // Check to see if our network topology has changed...
- networks = this->mm.get_extensions<network_extension>();
- for (vector<network_extension*>::iterator i=networks.begin() ; i != networks.end() ; i++) {
- // If it has, reset our wpad/pac setup and we'll retry our config
- if ((*i)->changed()) {
- if (debug) cerr << "Network changed" << endl;
- vector<wpad_extension*> wpads = this->mm.get_extensions<wpad_extension>();
- for (vector<wpad_extension*>::iterator j=wpads.begin() ; j != wpads.end() ; j++)
- (*j)->rewind();
- if (this->pac) delete[] this->pac;
- this->pac = NULL;
- break;
- }
- }
-}
-
-void proxy_factory::get_config(url &realurl, vector<url> &config, string &ignore) {
- vector<config_extension*> configs;
-
- configs = this->mm.get_extensions<config_extension>();
- for (vector<config_extension*>::iterator i=configs.begin() ; i != configs.end() ; i++) {
- config_extension *configurator = *i;
-
- // Try to get the configuration
- try {
- ignore = configurator->get_ignore(realurl);
- if (!is_ignored(realurl, ignore))
- config = configurator->get_config(realurl);
- if (debug) {
- if (configurator) {
- cerr << "Configuration extension is: " << typeid(*configurator).name() << endl;
- cerr << "Ignored list is: " << ignore << endl;
- } else {
- cerr << "No configuration extension found." << endl;
- }
- }
- break;
- }
- catch (runtime_error e) {
- ignore = "";
- }
- }
-}
-
-bool proxy_factory::is_ignored(url &realurl, const string &ignore) {
- vector<ignore_extension*> ignores;
- bool ignored = false, invign = false;
- string confign = ignore;
-
- /* Check our ignore patterns */
- ignores = this->mm.get_extensions<ignore_extension>();
- invign = confign.size() > 0 && confign[0] == '-';
- if (invign) confign = confign.substr(1);
- for (size_t i=0 ; i < confign.size() && !ignored;) {
- size_t next = confign.find(',', i);
- if (next == string::npos) next = confign.length();
- if (next > (i+1)) {
- string ignorestr = confign.substr (i, next - i);
- ignorestr = ignorestr.substr(ignorestr.find_first_not_of(" \t\n"), ignorestr.find_last_not_of(" \t\n")+1);
- for (vector<ignore_extension*>::iterator it=ignores.begin() ; it != ignores.end() && !ignored ; it++)
- ignored = ((*it)->ignore(realurl, ignorestr));
- }
- i = next+1;
- }
-
- if (invign)
- return !ignored;
- else
- return ignored;
-}
-
-bool proxy_factory::expand_wpad(const url &confurl)
-{
- bool rtv = false;
- if (confurl.get_scheme() == "wpad") {
- rtv = true;
- /* If the config has just changed from PAC to WPAD, clear the PAC */
- if (!this->wpad) {
- if (this->pac) delete[] this->pac;
- if (this->pacurl) delete this->pacurl;
- this->pac = NULL;
- this->pacurl = NULL;
- this->wpad = true;
- }
-
- /* If we have no PAC, get one */
- if (!this->pac) {
- if (debug) cerr << "Trying to find the PAC using WPAD..." << endl;
- vector<wpad_extension*> wpads = this->mm.get_extensions<wpad_extension>();
- for (vector<wpad_extension*>::iterator i=wpads.begin() ; i != wpads.end() ; i++) {
- if (debug) cerr << "WPAD search via: " << typeid(**i).name() << endl;
- if ((this->pacurl = (*i)->next(&this->pac))) {
- if (debug) cerr << "PAC found!" << endl;
- break;
- }
- }
-
- /* If getting the PAC fails, but the WPAD cycle worked, restart the cycle */
- if (!this->pac) {
- if (debug) cerr << "No PAC found..." << endl;
- for (vector<wpad_extension*>::iterator i=wpads.begin() ; i != wpads.end() ; i++) {
- if ((*i)->found()) {
- if (debug) cerr << "Resetting WPAD search..." << endl;
-
- /* Since a PAC was found at some point,
- * rewind all the WPADS to start from the beginning */
- /* Yes, the reuse of 'i' here is intentional...
- * This is because if *any* of the wpads have found a pac,
- * we need to reset them all to keep consistent state. */
- for (i=wpads.begin() ; i != wpads.end() ; i++)
- (*i)->rewind();
-
- // Attempt to find a PAC
- for (i=wpads.begin() ; i != wpads.end() ; i++) {
- if (debug) cerr << "WPAD search via: " << typeid(**i).name() << endl;
- if ((this->pacurl = (*i)->next(&this->pac))) {
- if (debug) cerr << "PAC found!" << endl;
- break;
- }
- }
- break;
- }
- }
- }
- }
- }
-
- return rtv;
-}
-
-bool proxy_factory::expand_pac(url &confurl)
-{
- bool rtv = false;
-
- // If we have a PAC config
- if (confurl.get_scheme().substr(0, 4) == "pac+") {
- rtv = true;
-
- /* Save the PAC config */
- if (this->wpad)
- this->wpad = false;
-
- /* If a PAC already exists, but came from a different URL than the one specified, remove it */
- if (this->pac) {
- if (this->pacurl->to_string() != confurl.to_string()) {
- delete this->pacurl;
- delete[] this->pac;
- this->pacurl = NULL;
- this->pac = NULL;
- }
- }
-
- /* Try to load the PAC if it is not already loaded */
- if (!this->pac) {
- this->pacurl = new url(confurl);
- this->pac = confurl.get_pac();
- if (debug) {
- if (!this->pac)
- cerr << "Unable to download PAC!" << endl;
- else
- cerr << "PAC received!" << endl;
- }
- }
- }
-
- return rtv;
-}
-
-void proxy_factory::run_pac(url &realurl, const url &confurl, vector<string> &response) {
- /* In case of either PAC or WPAD, we'll run the PAC */
- if (this->pac && (confurl.get_scheme() == "wpad" || confurl.get_scheme().substr(0, 4) == "pac+") ) {
- vector<pacrunner_extension*> pacrunners = this->mm.get_extensions<pacrunner_extension>();
-
- /* No PAC runner found, fall back to direct */
- if (pacrunners.size() == 0) {
- if (debug) cerr << "Unable to find a required pacrunner!" << endl;
- return;
- }
-
- /* Run the PAC, but only try one PACRunner */
- if (debug) cerr << "Using pacrunner: " << typeid(*pacrunners[0]).name() << endl;
- pacrunner* runner = pacrunners[0]->get(this->pac, this->pacurl->to_string());
- string pacresp = runner->run(realurl);
- delete runner;
- if (debug) cerr << "Pacrunner returned: " << pacresp << endl;
- format_pac_response(pacresp, response);
- }
-}
-
-void proxy_factory::clear_cache() {
- this->wpad = false;
- if (this->pac) { delete[] this->pac; this->pac = NULL; }
- if (this->pacurl) { delete this->pacurl; this->pacurl = NULL; }
-}
-
-void proxy_factory::lock() {
-#ifdef WIN32
- WaitForSingleObject(this->mutex, INFINITE);
-#else
- pthread_mutex_lock(&this->mutex);
-#endif
-}
-
-void proxy_factory::unlock() {
-#ifdef WIN32
- ReleaseMutex(this->mutex);
-#else
- pthread_mutex_unlock(&this->mutex);
-#endif
-}
-
-};
-
-struct pxProxyFactory_ {
- libproxy::proxy_factory pf;
-};
-
-extern "C" DLL_PUBLIC struct pxProxyFactory_ *px_proxy_factory_new(void) {
- return new struct pxProxyFactory_;
-}
-
-extern "C" DLL_PUBLIC char** px_proxy_factory_get_proxies(struct pxProxyFactory_ *self, const char *url) {
- std::vector<std::string> proxies;
- char** retval;
-
- // Call the main method
- try {
- proxies = self->pf.get_proxies(url);
- retval = (char**) malloc(sizeof(char*) * (proxies.size() + 1));
- if (!retval) return NULL;
- } catch (std::exception&) {
- // Return NULL on any exception
- return NULL;
- }
-
- // Copy the results into an array
- // Return NULL on memory allocation failure
- retval[proxies.size()] = NULL;
- for (size_t i=0 ; i < proxies.size() ; i++) {
- retval[i] = strdup(proxies[i].c_str());
- if (retval[i] == NULL) {
- for (int j=i-1 ; j >= 0 ; j--)
- free(retval[j]);
- free(retval);
- return NULL;
- }
- }
- return retval;
-}
-
-extern "C" DLL_PUBLIC void px_proxy_factory_free_proxies(char ** const proxies) {
- if (!proxies)
- return;
-
- for (size_t i = 0; proxies[i]; ++i)
- free(proxies[i]);
-
- free(proxies);
-}
-
-extern "C" DLL_PUBLIC void px_proxy_factory_free(struct pxProxyFactory_ *self) {
- delete self;
-}