def setup(configuration_filename=None, use_tori_custom_error_page=False, support_unicode=True, enable_compression=False, auto_config=False, additional_config=None): """ Set up the environment `configuration_filename` is the name of the configuration file in XML. By default, it is null and instruct the system to use the default settings. `use_tori_custome_error_page` is a flag to tell whether the application process should use the nicer custom error page. Please note that enabling this feature will slightly decrease performance. This is a known issue for CherryPy 3.1+. `support_unicode` is a flag to tell whether the application process should support unicode. Please note that enabling this feature will slightly decrease performance. `enable_compression` is a flag to tell whether the application process should compress the output. Please note that enabling this feature will decrease performance and possibly mess up JavaScript. This feature is disabled by default when the X/HTML document contains **pre** elements. Use with caution. `auto_config` is a flag to tell whether the application process should create a configuration file (named by `configuration_filename`) automatically if not existed. When the function detect that the configuration file doesn't exist, with this flag enabled, it will create the configuration file with the default configuration. Then, it will terminated the process. This gives the developers an opportunity to config the settings before proceeding. `additional_config` is a configuration dictionary for CherryPy 3.1+. It is for adding some additional configuration directly to CherryPy which is the underlying framework. Please note that this will override any configuration from the configuration file. """ global mode global base_uri global base_path global path global error_template global static_routing global settings global template global debug # Initialization __base_config_key = 'tools.static' mode = 'local' port = 8080 base_uri = '' base_path = '' path = {} error_template = None static_routing = {} default_config = { 'global': { 'server.thread_pool': 10, 'server.socket_queue_size': 10, 'server.socket_host': '0.0.0.0', 'server.socket_port': port, 'tools.decode.encoding': 'utf-8', 'tools.encode.encoding': 'utf-8', 'tools.decode.on': support_unicode, 'tools.encode.on': support_unicode, 'tools.gzip.on': enable_compression, 'log.screen': False # Disable trackback information } } if use_tori_custom_error_page: # Use the custom error response from Tori default_config['global']['error_page.default'] = DefaultErrorPage.response settings = {} standard_config = """<?xml version="1.0" encoding="UTF-8"?> <webconfig> <mode>local</mode> <rendering>mako</rendering> <base_path> <static>static</static> <template>template</template> <session>memory</session> </base_path> <!-- <port>8080</port> --> <base_uri>/</base_uri> <static_routing> <!-- <file link="favicon.ico" ref="favicon.ico" /> <dir link="image" ref="image" /> <dir link="css" ref="css" /> <dir link="js" ref="js" /> --> </static_routing> <settings> <option name="debug">false</option> <option name="text_minification">false</option> <option name="no_cache">true</option> </settings> </webconfig> """ # Get the reference to the calling function f = sys._getframe(1) c = f.f_code reference_to_caller = c.co_filename # Base path base_path = os.path.abspath(os.path.dirname(os.path.abspath(reference_to_caller))) # Get the location of the given the configuration files target_destination = configuration_filename if not re.search('^/', configuration_filename): target_destination = "%s/%s" % (base_path, configuration_filename) try: # Load the configuration files xmldoc = Kotoba() xmldoc.read(target_destination) except: if auto_config: fs.write(target_destination, standard_config, "w") xmldoc = Kotoba(target_destination) else: raise WebFrameworkException("Error while reading configuration from %s" % target_destination) try: # Get operational mode xml_on_mode = xmldoc.get("mode") if len(xml_on_mode) > 0: mode = xml_on_mode.data() except: raise WebFrameworkException("Error while determining the running mode") try: # Get operational port. This will be ignored in GAE mode xml_on_port = xmldoc.get("port") if len(xml_on_port) > 0: port = base.convertToInteger(xml_on_port.data()) default_config['global']['server.socket_port'] = port except: raise WebFrameworkException("Error while determining the running port") try: # Store the basic paths in the memory. Make the directory for the destination if necessary. path_indices = xmldoc.get('base_path *') for path_index in path_indices: pathName = path_index.name path[pathName] = os.path.join(base_path, path_index.data()) make_directory_if_not_existed(path[pathName]) except: raise WebFrameworkException("Error while setting up the directories") try: # Get application settings xml_on_settings = xmldoc.get("settings option") if xml_on_settings: for option in xml_on_settings: option_data = option.data() option_data_as_floating_number = base.convertToFloatingNumber(option_data) option_data_as_integer = base.convertToInteger(option_data) option_data_as_boolean = base.convertToBoolean(option_data) if re.match("^\d+(\.\d+)?$", option_data): if option_data_as_floating_number is not None: # the option data is integer-convertible. option_data = option_data_as_floating_number elif option_data_as_integer is not None: # the option data is integer-convertible. option_data = option_data_as_integer elif option_data_as_boolean is not None: # the option data is boolean-convertible. option_data = option_data_as_boolean settings[option.attrs['name']] = option_data # Recognized options by framework (with the default value) recognized_options = { 'debug': True, 'no_cache': True, 'direct_rendering': True, 'text_minification': False } for recognized_option, default_option in recognized_options.iteritems(): if recognized_option not in settings: settings[recognized_option] = default_option if 'debug' in settings: debug = settings['debug'] except: raise WebFrameworkException("Error while reading anonymous settings for this application") try: # Get the base URI base_uri = xmldoc.get('base_uri').data() base_uri = base_uri.strip() base_uri = re.sub("^/", "", base_uri) base_uri = re.sub("/$", "", base_uri) static_routing[base_uri + '/'] = { 'tools.caching.on': True, 'tools.caching.cache_class': cherrypy.lib.caching.MemoryCache, 'tools.caching.delay': 259200, # 3 days 'tools.caching.maxobjsize': 26214400, # 25 MB 'tools.caching.maxsize': 104857600, # 100 MB 'tools.sessions.on': True, 'tools.sessions.timeout': 10, 'tools.sessions.storage_type': 'file', 'tools.sessions.storage_path': path['session'] } default_config['global']['tools.staticdir.root'] = path['static'] default_config['global']['tools.staticfile.root'] = path['static'] if settings['no_cache']: doc_root_settings = static_routing[base_uri + '/'] doc_root_settings['tools.caching.on'] = False if mode == ServiceMode.GAE: doc_root_settings = static_routing[base_uri + '/'] doc_root_settings['tools.caching.on'] = False del doc_root_settings['tools.sessions.storage_type'] del doc_root_settings['tools.sessions.storage_path'] xmldocOnstatic_routing = xmldoc.get('static_routing file, static_routing dir') for referenceSetting in xmldocOnstatic_routing: __type = referenceSetting.name __ref = referenceSetting.attrs['ref'] __link = referenceSetting.attrs['link'] __cBaseKey = "%s%s" % (__base_config_key, __type) __cKeyFlag = "%s.on" % (__cBaseKey) __cKeyPath = "%s.%s" % (__cBaseKey, __type) if __type == 'file' and __ref is not None: __cKeyPath += 'name' #__ref = os.path.join(path['static'], __ref) if __type == 'dir': make_directory_if_not_existed(os.path.join(path['static'], __ref)) static_routing[base_uri + '/' + __link] = { str(__cKeyFlag): True, str(__cKeyPath): __ref } items_in_static = fs.browse(path['static']) for item_type in items_in_static: for item in items_in_static[item_type]: if item[0] == ".": continue __type = item_type == "files" and "file" or "dir" __ref = item __link = item __route_address = '%s/%s' % (base_uri, __link) if __route_address in static_routing: continue __cBaseKey = "%s%s" % (__base_config_key, __type) __cKeyFlag = "%s.on" % (__cBaseKey) __cKeyPath = "%s.%s" % (__cBaseKey, __type) if __type == 'file' and __ref is not None: __cKeyPath += 'name' if __type == 'dir': make_directory_if_not_existed(os.path.join(path['static'], __ref)) static_routing[__route_address] = { str(__cKeyFlag): True, str(__cKeyPath): __ref } except: raise WebFrameworkException("Error while setting up routing") try: # Determine the template system xml_on_rendering = xmldoc.get("rendering") if xml_on_rendering: template['use'] = xml_on_rendering.data() else: template['use'] = 'mako' if template['use'] == 'tenjin': enable_caching = not settings['no_cache'] if enable_caching: enable_caching = MemoryCacheStorage() template['tenjin']['engine'] = Engine( path=[path['template']], cache = enable_caching ) else: template_filesystem_checks = settings['no_cache'] if mode == ServiceMode.GAE: template['mako']['engine'] = TemplateLookup( directories = [path['template']], filesystem_checks=template_filesystem_checks, **template['mako']['options'] ) else: template['mako']['engine'] = TemplateLookup( directories = [path['template']], module_directory=os.path.join(path['session'], 'cache', 'template'), # disable for GAE apps filesystem_checks=template_filesystem_checks, **template['mako']['options'] ) template['mako']['get'] = template['mako']['engine'].get_template except: raise WebFrameworkException("Error while setting up the template system") try: # Add custom error pages xml_on_error_template = xmldoc.get('error_template') if xml_on_error_template: error_template = xml_on_error_template.data() error_template = fs.read(os.path.join(path['template'], error_template)) except: raise WebFrameworkException("Error while setting up a custom error error page.") cherrypy.config.update(default_config) if additional_config is not None: cherrypy.config.update(additional_config)
def default(self, *paths): cacheBlockName = "%s/%s" % (self.name, '/'.join(paths)) if self.isGET() and self.cache(cacheBlockName) is not None: return self.cache(cacheBlockName) # Response context response_context = None # Disable editor mode by default editor_called = False # Page mode: reading, editing, overview (TOC) page_mode = len(paths) > 1 and paths[-1] or None if page_mode not in [RegisteredMode.edit_content, RegisteredMode.list_page_hierarchy]: page_mode = None # Assume the reading mode # Get the whole request path (in array bit) without the page mode path = len(paths) == 0 and RegisteredPage.index or '/'.join(page_mode == None and paths or paths[:-1]) # Breadcrumb breadcrumb = [] requested_path = None if len(paths) > 0: urlpath = [] requested_path = '/'.join(paths[1:]) for p in paths: urlpath.append(p) current_path = '/'.join(urlpath) p = self.convert_to_full_name(p) breadcrumb.append({ 'URL': current_path, 'Full name': p, 'Short name': self.convert_to_shortname(p) }) del urlpath current_page = len(breadcrumb) > 0 and breadcrumb[-1] or None page_object = self.get_page_object(path) backup_page_object = self.get_backup_page_object(path) if self.isGET() and page_mode == None: is_index_page = path == RegisteredPage.index do_page_existed = is_index_page or page_object is not None or backup_page_object is not None # General information general_information = { 'breadcrumb': breadcrumb, 'current_page': current_page } # [General procedure] # 1. Retrieve the subpages (1 level deep) if necessary # 2. Render the page object by prioritizing the (HTML) sources in the following order: # 1. Database entry # 2. Flat file from archive # 3. Flat file from template # Prioritize the one in the database first. if page_object is not None and not self.use_static_file: pass # Prioritize the one in the database first. if page_object is not None and self.use_static_file: # Initialize data templateID = "default" # templateID subpages = None # list of subpages path_to_page_object = self.get_absolute_path_to_page_object(path) # path to the page object pre_processed_page_data = fs.read(path_to_page_object) # pre-processed page data # Look for requirements local_flags = re.search("<!--\s*require\s*([a-zA-Z0-9\-\+_]+)\s*-->", pre_processed_page_data) if local_flags is not None: # If detect the traversal flag for subpages, do it. if 'subpages' in local_flags.groups(): subpages = [] possible_directory = self.remove_extension(path_to_page_object) if fs.exists(possible_directory): raw_subpages = fs.browse(possible_directory, True)['files'] for p in raw_subpages: p = re.sub("^" + possible_directory + "/", "", p) p = self.remove_extension(p) if p == "index" or p[0] == "_": continue subpages.append((self.convert_to_full_name(p), p)) general_information['subpages'] = subpages # If detect the traversal flag for neighbours, do it. if 'neighbours' in local_flags.groups(): neighbours = [] possible_directory = re.sub("/[^/]+$", "", self.remove_extension(path_to_page_object)) if fs.exists(possible_directory): raw_subpages = fs.browse(possible_directory, True)['files'] for p in raw_subpages: p = re.sub("^" + possible_directory + "/", "", p) p = self.remove_extension(p) if p == "index" or p[0] == "_": continue neighbours.append((self.convert_to_full_name(p), p)) general_information['neighbours'] = neighbours # If require syntax highlighting, add the JS code if 'syntax_highlight' in local_flags.groups(): pre_processed_page_data += self.__JS_code_rendering # Determine if it needs a special template local_flags = re.search("<!--\s*template\s*([^ ]+)\s*-->", pre_processed_page_data) if local_flags is not None: local_templateID = local_flags.groups()[0] if local_templateID in self.__templates: templateID = local_templateID response_context = self.local_render(pre_processed_page_data, **general_information) response_context = self.local_render(self.__templates[templateID], response_context = response_context, **general_information) elif backup_page_object is not None: response_context = self.local_render(backup_page_object, **general_information) if not do_page_existed and self.isAdmin() and False: editor_called = True elif self.isGET() and page_mode in RegisteredMode.edit_content: editor_called = True elif self.isGET() and page_mode == RegisteredMode.list_page_hierarchy: response_context = tori.UserInterface.response("Table of content (index mode) requested") elif self.isPOST(): response_context = tori.UserInterface.response("Creating/updating called") elif self.isDELETE(): response_context = tori.UserInterface.response("Creating/updating called") # endif if editor_called: response_context = self.load_editor(page_mode, '/'.join(len(paths) > 1 and paths[1:-1] or [])) elif not editor_called and response_context is None: self.respond_status(404) else: self.cache(cacheBlockName, response_context, self.__cache_duration) return response_context