## Simple HTTP Server Example with Cellframe Node The [[Node|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 [[Cellframe Node General Config|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: 1. Define handler functions for processing HTTP requests. 2. Set up the server and register the handler functions. 3. Make GET and POST requests to the server using the `ClientHTTP` class. 4. 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: 1. Initialize the server and register the handler functions. 2. Make GET and POST requests to the server using the `ClientHTTP` class. 3. Log the responses and any errors. > [!warning] Warning > You should **never** use blocking and time-heavy methods in plugins `init()` function ```python 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 ``` > [!hint] Note > - Ensure that the Cellframe Node configuration is set up correctly to allow the server to accept requests. > - Use the `ClientHTTP` class or standard python `urllib` 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.