Simple HTTP Server Example with Cellframe Node
The Cellframe Node python extensions provide classes and functions for implementing a simple HTTP server and handling HTTP requests. This example demonstrates how to set up an HTTP server, define request handlers, and make self-requests to the server for testing purposes.
Prerequisites
To allow the Cellframe Node to accept HTTP requests, you need to enable the HTTP server in the config file. Set enabled=true
and specify listen_port_tcp
and listen_address
values under the [[Cellframe Node General Config#Section [notify_server]|notify_server]] section.
Overview
In this example, we will:
- Define handler functions for processing HTTP requests.
- Set up the server and register the handler functions.
- Make GET and POST requests to the server using the
ClientHTTP
class. - Log the responses and any errors.
Handler Functions
We define two handler functions for processing HTTP requests:
example_1_handler(request: HttpSimple, httpCode: HttpCode)
: Processes the request and returns a predefined response.example_2_handler(request: HttpSimple, httpCode: HttpCode)
: Processes the request, including headers and body, and returns the information in a formatted response.
Initialization and Making Requests
In the init
function, we:
- Initialize the server and register the handler functions.
- Make GET and POST requests to the server using the
ClientHTTP
class. - Log the responses and any errors.
Warning
You should never use blocking and time-heavy methods in plugins
init()
function
from DAP.Core import logIt, AppContext
from DAP.Network import HttpSimple, Server, ClientHTTP, HttpHeader, HttpCode
from DAP import configGetItem
from urllib.parse import unquote
import time
# Constants for URI paths WITHOUT prefix "/"
EXAMPLE_1_URI = "example_1"
EXAMPLE_2_URI = "example_2"
# Fetch configuration settings
SERVER_PORT = int(configGetItem("server", "listen_port_tcp"))
SERVER_ADDRESS = configGetItem("notify_server", "listen_address")
HTTP_REPLY_SIZE_MAX = 10 * 1024 * 102
# Handler for Example 1 URI
def example_1_handler(request: HttpSimple, httpCode: HttpCode):
"""
Handles requests to the /example_1 endpoint.
Args:
request (HttpSimple): The incoming HTTP request.
httpCode (HttpCode): The HTTP status code to set in the response.
"""
logIt.notice("Handling request for /example_1")
# Log request headers
for header in request.requestHeader:
logIt.notice(str(header))
# Prepare response
response_message = "Hello world! This is API for test plugin"
request.replyAdd(response_message.encode('utf-8'))
# Set a custom response header
custom_header = HttpHeader("Response-Test", "OK")
request.setResponseHeader(custom_header)
# Set the HTTP status code
httpCode.set(200)
return
# Handler for Example 2 URI
def example_2_handler(request: HttpSimple, httpCode: HttpCode):
"""
Handles requests to the /example_2 endpoint.
Args:
request (HttpSimple): The incoming HTTP request.
httpCode (HttpCode): The HTTP status code to set in the response.
"""
logIt.notice("Handling request for /example_2")
# Set a custom response header
custom_response_header = HttpHeader("Custom-Response-Header", "Custom-Value")
request.setResponseHeader(custom_response_header)
# Get request details
url = request.urlPath
method = request.action
body = request.request
query = request.query
request_headers = request.requestHeader
response_headers = request.getResponseHeader()
# Decode the body if it's not None
decoded_body = unquote(body) if body is not None else 'None'
# Create response content
response_content = [
"Greetings from the Node!",
f"URL = {url}",
f"Method = {method}",
f"Query = [{query}]",
f"Body = {decoded_body}",
"Request Headers:"
]
# Add request headers to response content
for header in request_headers:
response_content.append(str(header))
response_content.append("Response Headers:")
response_content.append(f"{response_headers.name}: {response_headers.value}")
# Join all parts into a single response body and encode
response_body = "\n".join(response_content).encode("utf-8")
# Add the response to the request
request.replyAdd(response_body)
# Set the HTTP status code
httpCode.set(200)
return
# Function to log the HTTP response
def log_http_response(data, args):
"""
Logs the HTTP response.
Args:
data (bytes): The response data.
argv (Any): Additional arguments.
"""
logIt.notice("Received Response:")
logIt.notice(f"Arguments: {args}")
# Decode response data and log each line
decoded_data = data.decode('utf-8')
for line in decoded_data.split("\n"):
logIt.notice(line)
return
# Function to log HTTP errors
def log_http_error(code_err, args):
"""
Logs HTTP errors.
Args:
code_err (int): The error code.
argv (Any): Additional arguments.
"""
logIt.notice("Error:")
logIt.notice(f"Arguments: {args}")
logIt.notice(f"Error Code: {code_err}")
return
def init():
# Create server and set it up with the application context
server_instance = Server()
AppContext.getServer(server_instance)
# Register handlers for the URIs
HttpSimple.addProc(server_instance,
f"/{EXAMPLE_1_URI}", HTTP_REPLY_SIZE_MAX, example_1_handler)
HttpSimple.addProc(server_instance,
f"/{EXAMPLE_2_URI}", HTTP_REPLY_SIZE_MAX, example_2_handler)
# Custom headers for requests
custom_headers = ["Custom-Request-Header: Custom-Value"]
# Message body for POST request
post_request_body = "Hello, World!".encode("utf-8")
# Send a GET request to the /example_1 endpoint
ClientHTTP(SERVER_ADDRESS, SERVER_PORT, "GET", "application/json",
EXAMPLE_1_URI, None, "", log_http_response, log_http_error,
None, custom_headers, False)
# Send a POST request to the /example_2 endpoint
ClientHTTP(SERVER_ADDRESS, SERVER_PORT, "POST", "application/json",
EXAMPLE_2_URI, post_request_body, "", log_http_response,
log_http_error, None, custom_headers, False)
return 0
Note
- Ensure that the Cellframe Node configuration is set up correctly to allow the server to accept requests.
- Use the
ClientHTTP
class or standard pythonurllib
to send requests to the server for testing purposes.
This example demonstrates a basic implementation of an HTTP server and client in the Cellframe framework, showcasing how to handle HTTP requests and responses effectively.