From 3c5ac474f4fd2a06dd7aea7843ddc9bea5a006f4 Mon Sep 17 00:00:00 2001 From: David Rose Date: Sat, 8 Nov 2008 02:36:33 +0000 Subject: [PATCH] vfs-mount-url --- panda/src/downloader/config_downloader.cxx | 56 +----------- panda/src/downloader/config_downloader.h | 9 -- panda/src/downloader/httpClient.cxx | 58 +++++++++++++ panda/src/downloader/virtualFileMountHTTP.cxx | 86 +++++++++++++++++++ panda/src/downloader/virtualFileMountHTTP.h | 2 + panda/src/express/virtualFileSystem.cxx | 41 +++++---- panda/src/express/virtualFileSystem.h | 5 +- 7 files changed, 171 insertions(+), 86 deletions(-) diff --git a/panda/src/downloader/config_downloader.cxx b/panda/src/downloader/config_downloader.cxx index ed1bb58fb0..79296a5f14 100644 --- a/panda/src/downloader/config_downloader.cxx +++ b/panda/src/downloader/config_downloader.cxx @@ -61,43 +61,12 @@ ConfigVariableInt patcher_buffer_size "Patcher::run(). Increasing this may help the Patcher " "perform more work before returning.")); -ConfigVariableBool verify_ssl -("verify-ssl", true, - PRC_DESC("Configure this true (the default) to insist on verifying all SSL " - "(e.g. https) servers against a known certificate, or false to allow " - "an unverified connection. This controls the default behavior; the " - "specific behavior for a particular HTTPClient can be adjusted at " - "runtime with set_verify_ssl().")); - -ConfigVariableString ssl_cipher_list -("ssl-cipher-list", "DEFAULT", - PRC_DESC("This is the default value for HTTPClient::set_cipher_list().")); - ConfigVariableList expected_ssl_server ("expected-ssl-server"); ConfigVariableList ssl_certificates ("ssl-certificates"); -ConfigVariableString http_proxy -("http-proxy", "", - PRC_DESC("This specifies the default value for HTTPClient::set_proxy_spec(). " - "It is a semicolon-delimited list of proxies that we use to contact " - "all HTTP hosts that don't specify otherwise. See " - "set_proxy_spec() for more information.")); -ConfigVariableString http_direct_hosts -("http-direct-hosts", "", - PRC_DESC("This specifies the default value for HTTPClient::set_direct_host_spec(). " - "It is a semicolon-delimited list of host names that do not require a " - "proxy. See set_direct_host_spec() for more information.")); -ConfigVariableBool http_try_all_direct -("http-try-all-direct", true, - PRC_DESC("This specifies the default value for HTTPClient::set_try_all_direct(). " - "If this is true, a direct connection will always be attempted after an " - "attempt to connect through a proxy fails.")); -ConfigVariableString http_proxy_username -("http-proxy-username", "", - PRC_DESC("This specifies a default username:password to pass to the proxy.")); ConfigVariableBool http_proxy_tunnel ("http-proxy-tunnel", false, PRC_DESC("This specifies the default value for HTTPChannel::set_proxy_tunnel(). " @@ -140,29 +109,6 @@ ConfigVariableInt http_max_connect_count "prevent the code from attempting runaway connections; this limit " "should never be reached in practice.")); -ConfigVariableFilename http_client_certificate_filename -("http-client-certificate-filename", "", - PRC_DESC("This provides a default client certificate to offer up should an " - "SSL server demand one. The file names a PEM-formatted file " - "that includes a public and private key specification. A " - "connection-specific certificate may also be specified at runtime on " - "the HTTPClient object, but this will require having a different " - "HTTPClient object for each differently-certificated connection.")); - -ConfigVariableString http_client_certificate_passphrase -("http-client-certificate-passphrase", "", - PRC_DESC("This specifies the passphrase to use to decode the certificate named " - "by http-client-certificate-filename.")); - -ConfigVariableList http_username -("http-username", - PRC_DESC("Adds one or more username/password pairs to all HTTP clients. The client " - "will present this username/password when asked to authenticate a request " - "for a particular server and/or realm. The username is of the form " - "server:realm:username:password, where either or both of server and " - "realm may be empty, or just realm:username:password or username:password. " - "If the server or realm is empty, they will match anything.")); - ConfigureFn(config_downloader) { init_libdownloader(); } @@ -188,6 +134,8 @@ init_libdownloader() { VirtualFileHTTP::init_type(); VirtualFileMountHTTP::init_type(); + VirtualFileMountHTTP::reload_vfs_mount_url(); + // We need to define this here, rather than above, to guarantee that // it has been initialized by the time we check it. ConfigVariableBool early_random_seed diff --git a/panda/src/downloader/config_downloader.h b/panda/src/downloader/config_downloader.h index 24ad92ac13..4e2cd2e7da 100644 --- a/panda/src/downloader/config_downloader.h +++ b/panda/src/downloader/config_downloader.h @@ -38,24 +38,15 @@ extern ConfigVariableDouble decompressor_step_time; extern ConfigVariableDouble extractor_step_time; extern ConfigVariableInt patcher_buffer_size; -extern ConfigVariableBool verify_ssl; -extern ConfigVariableString ssl_cipher_list; extern ConfigVariableList expected_ssl_server; extern ConfigVariableList ssl_certificates; -extern ConfigVariableString http_proxy; -extern ConfigVariableString http_direct_hosts; -extern ConfigVariableBool http_try_all_direct; -extern ConfigVariableString http_proxy_username; extern ConfigVariableBool http_proxy_tunnel; extern ConfigVariableDouble http_connect_timeout; extern ConfigVariableDouble http_timeout; extern ConfigVariableInt http_skip_body_size; extern ConfigVariableDouble http_idle_timeout; extern ConfigVariableInt http_max_connect_count; -extern ConfigVariableFilename http_client_certificate_filename; -extern ConfigVariableString http_client_certificate_passphrase; -extern ConfigVariableList http_username; extern EXPCL_PANDAEXPRESS void init_libdownloader(); diff --git a/panda/src/downloader/httpClient.cxx b/panda/src/downloader/httpClient.cxx index 73f9cd5daa..2f66fb2ca8 100644 --- a/panda/src/downloader/httpClient.cxx +++ b/panda/src/downloader/httpClient.cxx @@ -94,6 +94,64 @@ tokenize(const string &str, vector_string &words, const string &delimiters) { //////////////////////////////////////////////////////////////////// HTTPClient:: HTTPClient() { + ConfigVariableBool verify_ssl + ("verify-ssl", true, + PRC_DESC("Configure this true (the default) to insist on verifying all SSL " + "(e.g. https) servers against a known certificate, or false to allow " + "an unverified connection. This controls the default behavior; the " + "specific behavior for a particular HTTPClient can be adjusted at " + "runtime with set_verify_ssl().")); + + ConfigVariableString ssl_cipher_list + ("ssl-cipher-list", "DEFAULT", + PRC_DESC("This is the default value for HTTPClient::set_cipher_list().")); + + ConfigVariableString http_proxy + ("http-proxy", "", + PRC_DESC("This specifies the default value for HTTPClient::set_proxy_spec(). " + "It is a semicolon-delimited list of proxies that we use to contact " + "all HTTP hosts that don't specify otherwise. See " + "set_proxy_spec() for more information.")); + + ConfigVariableString http_direct_hosts + ("http-direct-hosts", "", + PRC_DESC("This specifies the default value for HTTPClient::set_direct_host_spec(). " + "It is a semicolon-delimited list of host names that do not require a " + "proxy. See set_direct_host_spec() for more information.")); + + ConfigVariableBool http_try_all_direct + ("http-try-all-direct", true, + PRC_DESC("This specifies the default value for HTTPClient::set_try_all_direct(). " + "If this is true, a direct connection will always be attempted after an " + "attempt to connect through a proxy fails.")); + + ConfigVariableString http_proxy_username + ("http-proxy-username", "", + PRC_DESC("This specifies a default username:password to pass to the proxy.")); + + ConfigVariableList http_username + ("http-username", + PRC_DESC("Adds one or more username/password pairs to all HTTP clients. The client " + "will present this username/password when asked to authenticate a request " + "for a particular server and/or realm. The username is of the form " + "server:realm:username:password, where either or both of server and " + "realm may be empty, or just realm:username:password or username:password. " + "If the server or realm is empty, they will match anything.")); + + ConfigVariableFilename http_client_certificate_filename + ("http-client-certificate-filename", "", + PRC_DESC("This provides a default client certificate to offer up should an " + "SSL server demand one. The file names a PEM-formatted file " + "that includes a public and private key specification. A " + "connection-specific certificate may also be specified at runtime on " + "the HTTPClient object, but this will require having a different " + "HTTPClient object for each differently-certificated connection.")); + + ConfigVariableString http_client_certificate_passphrase + ("http-client-certificate-passphrase", "", + PRC_DESC("This specifies the passphrase to use to decode the certificate named " + "by http-client-certificate-filename.")); + _http_version = HTTPEnum::HV_11; _verify_ssl = verify_ssl ? VS_normal : VS_no_verify; _ssl_ctx = (SSL_CTX *)NULL; diff --git a/panda/src/downloader/virtualFileMountHTTP.cxx b/panda/src/downloader/virtualFileMountHTTP.cxx index 0fb463391f..7ae992f8e9 100644 --- a/panda/src/downloader/virtualFileMountHTTP.cxx +++ b/panda/src/downloader/virtualFileMountHTTP.cxx @@ -50,6 +50,92 @@ VirtualFileMountHTTP:: } +//////////////////////////////////////////////////////////////////// +// Function: VirtualFileMountHTTP::reload_vfs_mount_url +// Access: Published, Static +// Description: Reads all of the vfs-mount-url lines in the +// Config.prc file and replaces the mount settings to +// match them. +// +// This will mount any url's mentioned in the config +// file, and unmount and unmount any url's no longer +// mentioned in the config file. Normally, it is called +// automatically at startup, and need not be called +// again, unless you have fiddled with some config +// settings. +//////////////////////////////////////////////////////////////////// +void VirtualFileMountHTTP:: +reload_vfs_mount_url() { + VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr(); + + // First, unload the existing mounts. + int n = 0; + while (n < vfs->get_num_mounts()) { + PT(VirtualFileMount) mount = vfs->get_mount(n); + if (mount->is_of_type(VirtualFileMountHTTP::get_class_type())) { + vfs->unmount(mount); + // Don't increment n. + } else { + ++n; + } + } + + // Now, reload the newly specified mounts. + ConfigVariableList mounts + ("vfs-mount-url", + PRC_DESC("vfs-mount-url http://site/path[:port] mount-point [options]")); + + int num_unique_values = mounts.get_num_unique_values(); + for (int i = 0; i < num_unique_values; i++) { + string mount_desc = mounts.get_unique_value(i); + + size_t space = mount_desc.rfind(' '); + if (space == string::npos) { + downloader_cat.warning() + << "No space in vfs-mount-url descriptor: " << mount_desc << "\n"; + + } else { + string mount_point = mount_desc.substr(space + 1); + while (space > 0 && isspace(mount_desc[space - 1])) { + space--; + } + mount_desc = mount_desc.substr(0, space); + string options; + + space = mount_desc.rfind(' '); + if (space != string::npos) { + // If there's another space, we have the optional options field. + options = mount_point; + mount_point = mount_desc.substr(space + 1); + while (space > 0 && isspace(mount_desc[space - 1])) { + --space; + } + mount_desc = mount_desc.substr(0, space); + } + + mount_desc = ExecutionEnvironment::expand_string(mount_desc); + URLSpec root(mount_desc); + + int flags = 0; + string password; + + // Split the options up by commas. + size_t p = 0; + size_t q = options.find(',', p); + while (q != string::npos) { + vfs->parse_option(options.substr(p, q - p), + flags, password); + p = q + 1; + q = options.find(',', p); + } + vfs->parse_option(options.substr(p), flags, password); + + PT(VirtualFileMount) mount = new VirtualFileMountHTTP(root); + vfs->mount(mount, mount_point, flags); + } + } +} + //////////////////////////////////////////////////////////////////// // Function: VirtualFileMountHTTP::has_file // Access: Public, Virtual diff --git a/panda/src/downloader/virtualFileMountHTTP.h b/panda/src/downloader/virtualFileMountHTTP.h index 3676b8b41b..3a8cda52af 100644 --- a/panda/src/downloader/virtualFileMountHTTP.h +++ b/panda/src/downloader/virtualFileMountHTTP.h @@ -39,6 +39,8 @@ PUBLISHED: INLINE HTTPClient *get_http_client() const; INLINE const URLSpec &get_root() const; + static void reload_vfs_mount_url(); + public: virtual PT(VirtualFile) make_virtual_file(const string &local_filename, const Filename &original_filename, diff --git a/panda/src/express/virtualFileSystem.cxx b/panda/src/express/virtualFileSystem.cxx index 53db182426..96d742ef89 100644 --- a/panda/src/express/virtualFileSystem.cxx +++ b/panda/src/express/virtualFileSystem.cxx @@ -544,7 +544,6 @@ find_all_files(const Filename &filename, const DSearchPath &searchpath, void VirtualFileSystem:: write(ostream &out) const { ((VirtualFileSystem *)this)->_lock.acquire(); - out << "_cwd" << _cwd << "\n_mounts:\n"; Mounts::const_iterator mi; for (mi = _mounts.begin(); mi != _mounts.end(); ++mi) { VirtualFileMount *mount = (*mi); @@ -745,6 +744,26 @@ scan_mount_points(vector_string &names, const Filename &path) const { } } +//////////////////////////////////////////////////////////////////// +// Function: VirtualFileSystem::parse_option +// Access: Public, Static +// Description: Parses one of the option flags in the options list on +// the vfs-mount Config.prc line. +//////////////////////////////////////////////////////////////////// +void VirtualFileSystem:: +parse_option(const string &option, int &flags, string &password) { + if (option == "0" || option.empty()) { + // 0 is the null option. + } else if (option == "ro") { + flags |= MF_read_only; + } else if (option.substr(0, 3) == "pw:") { + password = option.substr(3); + } else { + express_cat.warning() + << "Invalid option on vfs-mount: \"" << option << "\"\n"; + } +} + //////////////////////////////////////////////////////////////////// // Function: VirtualFileSystem::normalize_mount_point // Access: Private @@ -1008,23 +1027,3 @@ consider_mount_mf(const Filename &filename) { // Recurse. return consider_mount_mf(dirname); } - -//////////////////////////////////////////////////////////////////// -// Function: VirtualFileSystem::parse_option -// Access: Private, Static -// Description: Parses one of the option flags in the options list on -// the vfs-mount Config.prc line. -//////////////////////////////////////////////////////////////////// -void VirtualFileSystem:: -parse_option(const string &option, int &flags, string &password) { - if (option == "0" || option.empty()) { - // 0 is the null option. - } else if (option == "ro") { - flags |= MF_read_only; - } else if (option.substr(0, 3) == "pw:") { - password = option.substr(3); - } else { - express_cat.warning() - << "Invalid option on vfs-mount: \"" << option << "\"\n"; - } -} diff --git a/panda/src/express/virtualFileSystem.h b/panda/src/express/virtualFileSystem.h index cda07fd671..0f89a75197 100644 --- a/panda/src/express/virtualFileSystem.h +++ b/panda/src/express/virtualFileSystem.h @@ -95,6 +95,9 @@ public: void scan_mount_points(vector_string &names, const Filename &path) const; + static void parse_option(const string &option, + int &flags, string &password); + private: Filename normalize_mount_point(const string &mount_point) const; bool do_mount(VirtualFileMount *mount, const string &mount_point, int flags); @@ -104,8 +107,6 @@ private: const Filename &original_filename, bool implicit_pz_file, bool status_only) const; bool consider_mount_mf(const Filename &filename); - static void parse_option(const string &option, - int &flags, string &password); MutexImpl _lock; typedef pvector Mounts;