#!/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 ", 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()