#!/usr/bin/env python3 """ Validate that the generated FastCGI test cases are properly formatted. """ import struct import os import glob def parse_record_header(data): """Parse a FastCGI record header.""" if len(data) < 8: return None version, record_type, request_id, content_length, padding_length, reserved = struct.unpack('>BBHHBB', data[:8]) return { 'version': version, 'type': record_type, 'request_id': request_id, 'content_length': content_length, 'padding_length': padding_length, 'reserved': reserved, 'total_length': 8 + content_length + padding_length } def validate_file(filename): """Validate a single test case file.""" print(f"\nValidating {filename}:") with open(filename, 'rb') as f: data = f.read() if len(data) < 8: print(f" ❌ File too short: {len(data)} bytes") return False # Parse all records in the file offset = 0 record_count = 0 while offset < len(data): if offset + 8 > len(data): print(f" ❌ Incomplete header at offset {offset}") return False header = parse_record_header(data[offset:]) if not header: print(f" ❌ Failed to parse header at offset {offset}") return False record_count += 1 print(f" Record {record_count}:") print(f" Version: {header['version']}") print(f" Type: {header['type']}") print(f" Request ID: {header['request_id']}") print(f" Content Length: {header['content_length']}") print(f" Padding Length: {header['padding_length']}") print(f" Reserved: {header['reserved']}") # Validate header fields if header['version'] != 1: print(f" ❌ Invalid version: {header['version']}") return False if header['type'] < 1 or header['type'] > 11: print(f" ❌ Invalid record type: {header['type']}") return False if header['reserved'] != 0: print(f" ❌ Reserved field not zero: {header['reserved']}") return False # Check if we have enough data for content and padding expected_end = offset + header['total_length'] if expected_end > len(data): print(f" ❌ Not enough data: need {header['total_length']}, have {len(data) - offset}") return False # Extract content content_start = offset + 8 content_end = content_start + header['content_length'] content = data[content_start:content_end] # Extract padding padding_start = content_end padding_end = padding_start + header['padding_length'] padding = data[padding_start:padding_end] print(f" Content: {len(content)} bytes") if header['padding_length'] > 0: print(f" Padding: {len(padding)} bytes") # Show content preview for small records if len(content) <= 32: print(f" Content hex: {content.hex()}") else: print(f" Content preview: {content[:16].hex()}...") print(f" ✅ Record valid") offset = expected_end print(f" ✅ File valid: {record_count} record(s), {len(data)} total bytes") return True def main(): """Validate all test case files.""" test_files = glob.glob("*.bin") test_files.sort() print(f"Found {len(test_files)} test case files") valid_count = 0 for filename in test_files: if validate_file(filename): valid_count += 1 print(f"\n{'='*50}") print(f"Validation complete: {valid_count}/{len(test_files)} files valid") if valid_count == len(test_files): print("✅ All test cases are valid!") else: print("❌ Some test cases failed validation") return 1 return 0 if __name__ == "__main__": import sys sys.exit(main())