WhakerPy 2.0

https://github.com/brigitte-bigi/WhakerPy/

Module whakerpy.webapp

Class WSGIApplication

Description

Create the default application for an UWSGI server.

WSGI response is created from given "environ" parameters and communicated with start_response.

This class checks if the request comes from a blacklisted URL ASAP.

Constructor

Initialize the WSGIApplication instance.

Parameters
  • default_path: (str) Default root path for static or dynamic pages
  • default_filename: (str) Default filename to serve if none is provided
  • webpagemaker: (callable) A callable used to generate dynamic pages
  • defaultwebjson: (str) Path to the JSON file for dynamic page definitions
View Source
def __init__(self, default_path: str='', default_filename: str='index.html', web_page_maker=WebSiteResponse, default_web_json: str=None):
    """Initialize the WSGIApplication instance.

    :param default_path: (str) Default root path for static or dynamic pages
    :param default_filename: (str) Default filename to serve if none is provided
    :param web_page_maker: (callable) A callable used to generate dynamic pages
    :param default_web_json: (str) Path to the JSON file for dynamic page definitions

    """
    self.__default_path = default_path
    self.__default_file = default_filename
    self.__policy = HTTPDPolicy()
    web_json_path = None
    if default_web_json is not None:
        web_json_path = os.path.join(self.__default_path, default_web_json)
    self.__dynamic_pages = (web_page_maker, web_json_path)
    if hasattr(self.__dynamic_pages[0], 'bake_response'):
        self.__web_site_data = self.__dynamic_pages[0](self.__dynamic_pages[1])
    else:
        self.__web_site_data = WebSiteData(self.__dynamic_pages[1])
    self._pages = dict()
    if default_web_json is not None:
        self.__policy.configure({'blacklist': self.__web_site_data.blacklist, 'signed_url': self.__web_site_data.signed_url})

Public functions

add_page

Add a page to the list of available pages.

False is returned if the page already exists or the response has a wrong type.

Parameters
  • page_name: (str) the name of the page
  • response: (BaseResponseRecipe) the response object of the page (has to inherited of BaseResponseRecipe)
Returns
  • (bool) True if we successfully added the page
View Source
def add_page(self, page_name: str, response: BaseResponseRecipe) -> bool:
    """Add a page to the list of available pages.

        False is returned if the page already exists or the response has a wrong type.

        :param page_name: (str) the name of the page
        :param response: (BaseResponseRecipe) the response object of the page (has to inherited of BaseResponseRecipe)
        :return: (bool) True if we successfully added the page

        """
    if page_name in self._pages.keys():
        return False
    if isinstance(response, BaseResponseRecipe) is False:
        return False
    self._pages[page_name] = response
    return True

Protected functions

__create_dynamic_page

Create page dynamically from the json config file.

Parameters
  • page_name: (str) Name of the page to bake
View Source
def __create_dynamic_page(self, page_name: str) -> None:
    """Create page dynamically from the json config file.

        :param page_name: (str) Name of the page to bake

        """
    web_data = self.__dynamic_pages[0]
    if hasattr(web_data, 'bake_response'):
        page = self.__web_site_data.bake_response(page_name, default=self.__default_path)
        if page is not None:
            self._pages[page_name] = page
    elif page_name in self.__web_site_data:
        self._pages[page_name] = web_data(page_name)

__serve_dynamic_content

Handle requests for dynamic content or return a 404 if not found.

Parameters
  • page_name: (str) Name of the page to bake
  • filepath: (str) Path to the file to bake
  • environ: (dict) WSGI environment dictionary with request data
  • handler_utils: (HTTPDHandlerUtils) Handler utils
Returns
  • (tuple) Return content and status code
View Source
def __serve_dynamic_content(self, page_name: str, filepath: str, environ, handler_utils) -> tuple:
    """Handle requests for dynamic content or return a 404 if not found.

        :param page_name: (str) Name of the page to bake
        :param filepath: (str) Path to the file to bake
        :param environ: (dict) WSGI environment dictionary with request data
        :param handler_utils: (HTTPDHandlerUtils) Handler utils
        :return: (tuple) Return content and status code

        """
    if self.__dynamic_pages[1] is not None and page_name not in self._pages:
        self.__create_dynamic_page(page_name)
    if page_name not in self._pages or filepath != f'{self.__default_path}/{page_name}':
        status = HTTPDStatus(404)
        content = status.to_html(encode=True, msg_error=f'Page not found: {filepath}')
    else:
        events, accept = handler_utils.process_post(environ['wsgi.input'])
        has_to_return_data = HTTPDHandlerUtils.has_to_return_data(accept)
        content, status = HTTPDHandlerUtils.bakery(self._pages, page_name, environ['PATH_INFO'], events, has_to_return_data)
        if has_to_return_data is False:
            content = self.__policy.finalize_html(content)
    return (content, status)

__check_policy_compliance

View Source
def __check_policy_compliance(self, requested_path: str, filepath: str, environ: dict, start_response):
    query = environ.get('QUERY_STRING', '')
    allowed, content, status, mime = self.__policy.check(requested_path, query, environ)
    if allowed is False:
        headers = HTTPDHandlerUtils.build_default_headers(filepath, content, browser_cache=False, varnish=False)
        start_response(repr(status), headers)
        return content
    return None

Overloads

__call__

Handle WSGI requests.

Process the incoming "environ" dictionary and respond using the given start_response callable.

Parameters
  • environ: (dict) WSGI environment dictionary with request data
  • start_response: (callable) Function to start the HTTP response
Returns
  • (bytes|iterable) Response content to send back to the client
View Source
def __call__(self, environ, start_response):
    """Handle WSGI requests.

        Process the incoming "environ" dictionary and respond using the given
        start_response callable.

        :param environ: (dict) WSGI environment dictionary with request data
        :param start_response: (callable) Function to start the HTTP response
        :return: (bytes|iterable) Response content to send back to the client

        """
    if 'HTTP_ACCEPT' in environ:
        environ['Accept'] = environ['HTTP_ACCEPT']
    handler_utils = HTTPDHandlerUtils(environ, environ['PATH_INFO'], self.__default_file)
    requested_path = handler_utils.get_path()
    filepath = self.__default_path + handler_utils.get_path()
    filepath = filepath.replace('//', '/')
    page_name = handler_utils.get_page_name()
    content = self.__check_policy_compliance(requested_path, filepath, environ, start_response)
    if content is not None:
        return [content]
    use_cache = True
    if os.path.exists(filepath) is True:
        content, status = handler_utils.static_content(filepath)
    elif os.path.isfile(handler_utils.get_path()[1:]) is True:
        content, status = handler_utils.static_content(handler_utils.get_path()[1:])
    else:
        content, status = self.__serve_dynamic_content(page_name, filepath, environ, handler_utils)
        use_cache = False
    if isinstance(content, types.GeneratorType):
        headers = HTTPDHandlerUtils.build_default_headers(filepath, content, browser_cache=use_cache, varnish=use_cache)
        start_response(repr(status), headers)
        return [c for c in content]
    headers = HTTPDHandlerUtils.build_default_headers(filepath, content, browser_cache=use_cache, varnish=use_cache)
    start_response(repr(status), headers)
    return [content]

__contains__

Check if a page name exists in the application.

Parameters
  • page_name: (str) Name of the page to check
Returns
  • (bool) True if the page exists, False otherwise
View Source
def __contains__(self, page_name: str) -> bool:
    """Check if a page name exists in the application.

        :param page_name: (str) Name of the page to check
        :return: (bool) True if the page exists, False otherwise

        """
    return page_name in self._pages