WhakerPy 1.3

https://sourceforge.net/projects/whakerpy/

Module whakerpy.httpd

Class HTTPDHandler

Description

Web-based application HTTPD handler.

This class is used to handle the HTTP requests that arrive at the server.

This class is instantiated by the server each time a request is received and then a response is created. This is an HTTPD handler for any Web-based application server. It parses the request and the headers, then call a specific method depending on the request type.

In this handler, HTML pages are supposed to not be static. Instead, they are serialized from an HTMLTree instance -- so not read from disk. The server contains the page's bakery, the handler is then asking the server page's bakery to get the html content and response status.

The parent server is supposed to have all the pages as members in a dictionary, i.e. it's a sppasBaseHTTPDServer. Each page has a bakery to create the response content. However, this handler can also be used with any other http.server.ThreadingHTTPServer.

The currently supported HTTPD responses status are:

  • 200: OK
  • 205: Reset Content
  • 403: Forbidden
  • 404: Not Found
  • 410: Gone
  • 418: I'm not a teapot

Constructor

View Source
def __init__(self, request, client_address, server):
    self.request = request
    self.client_address = client_address
    self.server = server
    self.setup()
    try:
        self.handle()
    finally:
        self.finish()

Public functions

get_default_page

Retrieve the server default page name.

This method first checks if the server has a callable 'default' method to determine the default page name. If not, it falls back to the provided default value.

Parameters
  • default: (str) The fallback default page name, if no server-specific method is found. Defaults to "index.html".
Returns
  • (str) The name of the default page.
View Source
def get_default_page(self, default: str='index.html') -> str:
    """Retrieve the server default page name.

        This method first checks if the server has a callable 'default' method
        to determine the default page name. If not, it falls back to the
        provided default value.

        :param default: (str) The fallback default page name, if no server-specific
                               method is found. Defaults to "index.html".
        :return: (str) The name of the default page.

        """
    if hasattr(self.server, 'default') and callable(self.server.default):
        return self.server.default()
    return default

do_HEAD

Prepare the response to a HEAD request.

View Source
def do_HEAD(self) -> None:
    """Prepare the response to a HEAD request.

        """
    logging.debug('HEAD -- requested: {}'.format(self.path))
    self._set_headers(200)

do_GET

Prepare the response to a GET request.

View Source
def do_GET(self) -> None:
    """Prepare the response to a GET request.

        """
    logging.debug(' ---- DO GET -- requested: {}'.format(self.path))
    handler_utils = HTTPDHandlerUtils(self.headers, self.path, self.get_default_page())
    self.path = handler_utils.get_path()
    mime_type = HTTPDHandlerUtils.get_mime_type(self.path)
    if os.path.exists(handler_utils.get_path()) or os.path.exists(handler_utils.get_path()[1:]):
        content, status = handler_utils.static_content(self.path[1:])
    elif mime_type == 'text/html':
        content, status = self._bakery(handler_utils, dict(), mime_type)
    else:
        content, status = handler_utils.static_content(self.path[1:])
    self._response(content, status.code, mime_type)

do_POST

Prepare the response to a POST request.

View Source
def do_POST(self) -> None:
    """Prepare the response to a POST request.

        """
    logging.debug(' ----- DO POST -- requested: {}'.format(self.path))
    handler_utils = HTTPDHandlerUtils(self.headers, self.path, self.get_default_page())
    self.path = handler_utils.get_path()
    events, accept = handler_utils.process_post(self.rfile)
    content, status = self._bakery(handler_utils, events, accept)
    self._response(content, status.code, accept)

log_request

Override. For a quiet handler pls!!!.

Parameters
  • code
  • size
View Source
def log_request(self, code='-', size='-') -> None:
    """Override. For a quiet handler pls!!!."""
    pass

Private functions

_set_headers

Set the HTTPD response headers.

Parameters
  • status: (int) A response status.
  • mime_type: (str) The mime type of the file response
Raises

sppasHTTPDValueError

View Source
def _set_headers(self, status: int, mime_type: str=None) -> None:
    """Set the HTTPD response headers.

        :param status: (int) A response status.
        :param mime_type: (str) The mime type of the file response
        :raises: sppasHTTPDValueError

        """
    status = HTTPDStatus.check(status)
    self.send_response(status)
    if mime_type is not None:
        self.send_header('Content-Type', mime_type)
    self.end_headers()

_response

Make the appropriate HTTPD response.

Parameters
  • content: (bytes|iterator) The HTML response content or an iterator yielding chunks of bytes.
  • status: (int) The HTTPD status code of the response.
  • mime_type: (str) The mime type of the file response.
View Source
def _response(self, content, status: int, mime_type: str=None) -> None:
    """Make the appropriate HTTPD response.

        :param content: (bytes|iterator) The HTML response content or an iterator
                        yielding chunks of bytes.
        :param status: (int) The HTTPD status code of the response.
        :param mime_type: (str) The mime type of the file response.

        """
    self._set_headers(status, mime_type)
    if isinstance(content, types.GeneratorType) is True:
        for chunk in content:
            self.wfile.write(chunk)
    else:
        self.wfile.write(content)
    if status == 410:
        self.server.shutdown()

_bakery

Process the events and return the html page content or json data and status.

Parameters
  • handler_utils: (HTTPDhandlerUtils)
  • events: (dict) key=event name, value=event value
  • mime_type: (str) The mime type of the file response
Returns
  • tuple(bytes, HTTPDStatus) the content of the response the httpd status
View Source
def _bakery(self, handler_utils: HTTPDHandlerUtils, events: dict, mime_type: str) -> tuple:
    """Process the events and return the html page content or json data and status.

        :param handler_utils: (HTTPDhandlerUtils)
        :param events: (dict) key=event name, value=event value
        :param mime_type: (str) The mime type of the file response
        :return: tuple(bytes, HTTPDStatus) the content of the response the httpd status

        """
    if hasattr(self.server, 'page_bakery') is False:
        return handler_utils.static_content(self.path[1:])
    content, status = self.server.page_bakery(handler_utils.get_page_name(), self.headers, events, handler_utils.has_to_return_data(mime_type))
    return (content, status)