Skip to main content

A tiny, programmable http-server crafting-framework that is built with security and simplicity in mind.

Project description

Sonoma

PyPI version

A tiny, programmable http-server crafting-framework that is built with security and simplicity in mind.



Setup

pip install sonoma


Basic Usage

Server

from sonoma import httpServer

server = httpServer('127.0.0.1', 8888)

server.run()

Browser

                Hello World!
This is the default webpage for Sonoma/1.0.x.

Basic Usage: Custom Response

Server

from sonoma import defaults, httpServer

server = httpServer('127.0.0.1', 8888)

defaults['defaultResponse'] = """ 
    <!DOCTYPE html><html><head>
    <style>html, body{ margin: 0 auto;text-align:center; }</style>
    </head><body>
    <h1 style=\"text-align:center;\">Hello World!</h1>
    <span>This is a modified version of the default webpage for %s.</span>
    </body></html>
    """ % defaults['serverName'] 

server.run()

Browser

                        Hello World!
This is a modified version of the default webpage for Sonoma/1.0.12.

Advanced Usage: Custom Handler

Server

from sonoma import httpServer, defaults, sonomaPrint
from sonoma import setCookie, parseCookies
from http import HTTPStatus


# DEFINES CUSTOM HANDLER
def myHandler(self, REQUEST, CONNECTION):
    """
    ## Supported Methods:
    - GET
    - HEAD
    """

    # UNPACK "REQUEST" TUPLE 
    requestStatusLine, requestHeaders, requestBody = REQUEST

    # UNPACK CONNECTION TUPLE
    client_connection, client_address = CONNECTION

    # LOG THE REQUEST TO STDOUT
    sonomaPrint("%s -> %s Request: %s" % (str(self.vector), str(client_address), str(requestStatusLine),))

    #
    # RESOLVE THE REQUEST METHOD AND RESPOND ACCORDINGLY:
    #

    # SERVE GET
    if requestStatusLine.split()[0].lower() == "get":

        # GET OUR DEFAULT HEADERS + STATUS LINE
        responseStatusLine, responseHeaders = self.httpHeaders(HTTPStatus.OK, contentType="html")


        # CREATE A LIST OF STRINGS OF EACH REQUEST HEADER FOR USE IN OUR EXAMPLE
        headerStrings = ["%s: %s\n" % (header[0], header[1]) for header in requestHeaders]


        # HERES HOW WE CAN WORK WITH COOKIES, BOTH REQUEST AND RESPONSE:
        requestCookies = parseCookies(requestHeaders) # GET REQUEST COOKIES
        #sonomaPrint(requestCookies)        

        setCookie(responseHeaders, "cookieName", "cookieValue", ['Secure', 'HttpOnly']) # SET A RESPONSE COOKIE
        #sonomaPrint(responseHeaders)


        # CREATE A CUSTOM RESPONSE
        responseBody = ("""
            <!DOCTYPE html><html><head>
            <style>html, body{ margin: 0 auto;text-align:center; }</style>
            </head><body>
            <h1 style=\"text-align:center;\">Hello World!</h1>
            <span>This is a custom response from %s.</span>
            <br/><br/>
            <span>Request Headers:</span>
            <br/>
            <textarea cols="100" rows="100" style="width: 75%%;height: 100%%;margin: 0 auto;">%s</textarea>
            </body></html>
        """ % (defaults['serverName'], "".join(headerStrings))).encode() 

        return (responseStatusLine, responseHeaders, responseBody)

    # RESPOND WITH 405 STATUS - METHOD NOT ALLOWED
    else:
        responseStatusLine, responseHeaders = self.httpHeaders(HTTPStatus.METHOD_NOT_ALLOWED, contentType="text")
        return (responseStatusLine, responseHeaders, "")   

# INITIALIZE THE SERVER BUT SET OUR CUSTOM HANDLER BEFORE RUNNING.
server = httpServer('127.0.0.1', 8888)

server.set_handler(myHandler)

server.run()

Browser


Advanced Handler: JSON API

Server

from sonoma import httpServer, HTTPStatus, sonomaPrint, serverGmtTime
from json import dumps
from urllib.parse import urlparse, parse_qs

# DEFINES CUSTOM HANDLER
def myHandler(self, REQUEST, CONNECTION):
    """
    ## Supported Methods:
    - GET
    - HEAD
    """

    # UNPACK "REQUEST" TUPLE 
    requestStatusLine, requestHeaders, requestBody = REQUEST

    # UNPACK CONNECTION TUPLE
    client_connection, client_address = CONNECTION

    # LOG THE REQUEST TO STDOUT
    sonomaPrint("%s -> %s Request: %s" % (str(self.vector), str(client_address), str(requestStatusLine),))

    #
    # RESOLVE THE REQUEST METHOD AND RESPOND ACCORDINGLY:
    #

    # SERVE GET-JSON
    if requestStatusLine.split()[0].lower() == "get":

        # GET OUR JSON HEADERS + STATUS LINE
        responseStatusLine, responseHeaders = self.httpHeaders(HTTPStatus.OK, contentType="json")

        # PARSE THE GET QUERY
        try:
            clientQuery = parse_qs(urlparse(requestStatusLine.split()[1]).query)
        except:
            # IF QUERY CANNOT BE PARSED THEN RESPOND WITH AN ERROR MESSAGE
            return (responseStatusLine, responseHeaders, dumps({'error': 'Invalid url query!'}))

        # GET TIME FOR ONE OF OUR SERVERSIDE PROCESSING EXAMPLES
        tstamp = serverGmtTime()

        responseBody = dumps({
            'query': clientQuery,
            'time_gmt': tstamp
            }, indent=4)

        return (responseStatusLine, responseHeaders, responseBody)

    # RESPOND WITH 405 STATUS - METHOD NOT ALLOWED
    else:
        responseStatusLine, responseHeaders = self.httpHeaders(HTTPStatus.METHOD_NOT_ALLOWED, contentType="text")
        return (responseStatusLine, responseHeaders, "")   

# INITIALIZE THE SERVER BUT SET OUR CUSTOM HANDLER BEFORE RUNNING.
server = httpServer('127.0.0.1', 8888)

server.set_handler(myHandler)

server.run()

Browser

http://127.0.0.1:8888/?testQuery=1

{
    "query": {
        "testQuery": [
            "1"
        ]
    },
    "time_gmt": "Sat, 20 Feb 2021 20:18:51 GMT"
}

Conclusion

  • Adding better documentation soon!

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

sonoma-1.0.12.tar.gz (9.7 kB view details)

Uploaded Source

Built Distribution

sonoma-1.0.12-py3-none-any.whl (8.8 kB view details)

Uploaded Python 3

File details

Details for the file sonoma-1.0.12.tar.gz.

File metadata

  • Download URL: sonoma-1.0.12.tar.gz
  • Upload date:
  • Size: 9.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.3.0 pkginfo/1.7.0 requests/2.25.1 setuptools/49.2.1 requests-toolbelt/0.9.1 tqdm/4.56.1 CPython/3.9.1

File hashes

Hashes for sonoma-1.0.12.tar.gz
Algorithm Hash digest
SHA256 3da022911746924f23f591290d090fa550f21c5d3d89cec3a3e8efc2f6f7b259
MD5 b347f2c5adbfedaae23bdb0d5f0edb0e
BLAKE2b-256 9f56e874d6e3cecde2555204194b4dbf312e281f13a203a5c5e34c396029549d

See more details on using hashes here.

File details

Details for the file sonoma-1.0.12-py3-none-any.whl.

File metadata

  • Download URL: sonoma-1.0.12-py3-none-any.whl
  • Upload date:
  • Size: 8.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.3.0 pkginfo/1.7.0 requests/2.25.1 setuptools/49.2.1 requests-toolbelt/0.9.1 tqdm/4.56.1 CPython/3.9.1

File hashes

Hashes for sonoma-1.0.12-py3-none-any.whl
Algorithm Hash digest
SHA256 3fa987cdee5ba5bec33d4a493f652fed2e56146c1a3ea16db902abd485e37ea1
MD5 52ed5c7dd873f49ec5a4b78509f95089
BLAKE2b-256 97f4150737ec532042c88a94496102688df6665c44bc5800d9066d20cc174179

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page