feat: Implement virtual hosting for multi-domain Gemini server
- Add hostname-based request routing for multiple capsules per server - Parse virtual host configs from TOML sections ([hostname]) - Implement per-host certificate and content isolation - Add comprehensive virtual host testing and validation - Update docs and examples for multi-host deployments This enables Pollux to serve multiple Gemini domains from one instance, providing the foundation for multi-tenant Gemini hosting.
This commit is contained in:
parent
c193d831ed
commit
0459cb6220
22 changed files with 2296 additions and 406 deletions
|
|
@ -8,6 +8,7 @@ Used by integration tests for rate limiting validation.
|
|||
Usage: python3 tests/gemini_test_client.py gemini://host:port/path
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import socket
|
||||
import ssl
|
||||
|
|
@ -19,51 +20,65 @@ def main():
|
|||
|
||||
url = sys.argv[1]
|
||||
|
||||
# Parse URL (basic parsing)
|
||||
if not url.startswith('gemini://'):
|
||||
print("Error: URL must start with gemini://", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
url_parts = url[9:].split('/', 1) # Remove gemini://
|
||||
host_port = url_parts[0]
|
||||
path = '/' + url_parts[1] if len(url_parts) > 1 else '/'
|
||||
|
||||
if ':' in host_port:
|
||||
host, port = host_port.rsplit(':', 1)
|
||||
port = int(port)
|
||||
# Parse URL (basic parsing) - allow any protocol for testing
|
||||
if url.startswith('gemini://'):
|
||||
url_parts = url[9:].split('/', 1) # Remove gemini://
|
||||
host = url_parts[0]
|
||||
path = '/' + url_parts[1] if len(url_parts) > 1 else '/'
|
||||
else:
|
||||
host = host_port
|
||||
port = 1965
|
||||
|
||||
# For non-gemini URLs, try to extract host anyway for testing
|
||||
if '://' in url:
|
||||
protocol, rest = url.split('://', 1)
|
||||
url_parts = rest.split('/', 1)
|
||||
host = url_parts[0]
|
||||
path = '/' + url_parts[1] if len(url_parts) > 1 else '/'
|
||||
else:
|
||||
# No protocol, assume it's host/path
|
||||
url_parts = url.split('/', 1)
|
||||
host = url_parts[0]
|
||||
path = '/' + url_parts[1] if len(url_parts) > 1 else '/'
|
||||
|
||||
# Get port from environment or use default
|
||||
port = int(os.environ.get('GEMINI_PORT', '1965'))
|
||||
|
||||
# Allow overriding the connection host (useful for testing with localhost)
|
||||
connect_host = os.environ.get('GEMINI_CONNECT_HOST', host)
|
||||
|
||||
try:
|
||||
# Create SSL connection
|
||||
context = ssl.create_default_context()
|
||||
# Create SSL connection with permissive settings for self-signed certs
|
||||
context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
|
||||
context.check_hostname = False
|
||||
context.verify_mode = ssl.CERT_NONE
|
||||
|
||||
sock = socket.create_connection((host, port), timeout=5.0)
|
||||
# Load default certificates to avoid some SSL issues
|
||||
context.load_default_certs()
|
||||
|
||||
sock = socket.create_connection((connect_host, port), timeout=5.0)
|
||||
ssl_sock = context.wrap_socket(sock, server_hostname=host)
|
||||
|
||||
# Send request
|
||||
|
||||
# Send request (full URL for Gemini protocol over TLS)
|
||||
request = f"{url}\r\n"
|
||||
ssl_sock.send(request.encode('utf-8'))
|
||||
|
||||
# Read response header
|
||||
|
||||
# Read full response (header + body)
|
||||
response = b''
|
||||
while b'\r\n' not in response and len(response) < 1024:
|
||||
data = ssl_sock.recv(1)
|
||||
if not data:
|
||||
while len(response) < 1024: # Read up to 1KB for test responses
|
||||
try:
|
||||
data = ssl_sock.recv(1024)
|
||||
if not data:
|
||||
break
|
||||
response += data
|
||||
except:
|
||||
break
|
||||
response += data
|
||||
|
||||
|
||||
ssl_sock.close()
|
||||
|
||||
|
||||
if response:
|
||||
status_line = response.decode('utf-8', errors='ignore').split('\r\n')[0]
|
||||
print(status_line)
|
||||
# Decode and return the full response
|
||||
full_response = response.decode('utf-8', errors='ignore')
|
||||
print(full_response.strip())
|
||||
else:
|
||||
print("Error: No response")
|
||||
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error: {e}")
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue