blob: b6a7d090d79ec62fc995357b568edfe0995df058 [file] [log] [blame]
# Copyright (c) 2025 Project CHIP Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import http.server
import logging
import socketserver
import ssl
from pathlib import Path
from handler import createMockServerHandler
from route_configuration import Configuration, load_configurations
def run_server(port: int, config_path: Path, routing_config_dir: Path, cert_path: Path, key_path: Path) -> None:
"""
Starts a secure HTTPS server with mock endpoints defined by configuration files.
Initializes and runs a threaded HTTPS server that handles requests according to
configured routes. The server uses TLS for secure communication and supports
multiple concurrent connections.
Args:
port (int): Port number on which the server will listen
config_path (Path): Path to the main configuration file
routing_config_dir (Path): Directory containing additional routing configuration files
cert_path (Path): Path to the SSL/TLS certificate file
key_path (Path): Path to the SSL/TLS private key file
Returns:
None
Raises:
ssl.SSLError: If there are issues with the SSL/TLS certificate or key
OSError: If the port is already in use or permission is denied
ValueError: If configuration files are invalid or missing
KeyboardInterrupt: When the server is stopped using Ctrl+C
Example:
run_server(
port=8443,
config_path=Path("config/main.json"),
routing_config_dir=Path("config/routes"),
cert_path=Path("certs/server.crt"),
key_path=Path("certs/server.key")
)
Note:
- Server runs until interrupted by keyboard (Ctrl+C)
- Logs are written to stdout with DEBUG level
- Server binds to all available network interfaces ("")
- Uses ThreadingHTTPServer for concurrent request handling
- TLS configuration uses server's default security settings
- All endpoints are HTTPS-only
"""
logging.basicConfig(level=logging.DEBUG, format="[%(levelname)s] %(message)s")
if not config_path.is_file():
raise ValueError(f"'{config_path}' is not a file")
if not routing_config_dir.is_dir():
raise ValueError(f"'{routing_config_dir}' is not a directory")
if not cert_path.is_file():
raise ValueError(f"'{cert_path}' is not a file")
if not key_path.is_file():
raise ValueError(f"'{key_path}' is not a file")
config: Configuration = load_configurations(config_path, routing_config_dir)
server_address: socketserver._AfInetAddress = ("", port)
context: ssl.SSLContext = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
context.load_cert_chain(certfile=cert_path, keyfile=key_path)
theMockServerHandler = createMockServerHandler(config)
httpd = http.server.ThreadingHTTPServer(server_address, theMockServerHandler)
logging.info("Server starting on port %s", port)
with context.wrap_socket(httpd.socket, server_side=True) as httpd.socket:
logging.info("Server started on port %s", port)
logging.info("HTTPS enabled with cert: %s and key: %s", cert_path, key_path)
try:
httpd.serve_forever()
except KeyboardInterrupt:
logging.info("Server is shutting down due to keyboard interrupt.")
httpd.server_close()