- 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.
86 lines
No EOL
2.7 KiB
Python
Executable file
86 lines
No EOL
2.7 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
"""
|
|
Simple Gemini Test Client
|
|
|
|
Makes a single Gemini request and prints the status line.
|
|
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
|
|
|
|
def main():
|
|
if len(sys.argv) != 2:
|
|
print("Usage: python3 gemini_test_client.py <gemini-url>", file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
url = sys.argv[1]
|
|
|
|
# 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:
|
|
# 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 with permissive settings for self-signed certs
|
|
context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
|
|
context.check_hostname = False
|
|
context.verify_mode = ssl.CERT_NONE
|
|
# 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 (full URL for Gemini protocol over TLS)
|
|
request = f"{url}\r\n"
|
|
ssl_sock.send(request.encode('utf-8'))
|
|
|
|
# Read full response (header + body)
|
|
response = b''
|
|
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
|
|
|
|
ssl_sock.close()
|
|
|
|
if response:
|
|
# 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}")
|
|
|
|
if __name__ == '__main__':
|
|
main() |