#!/usr/bin/env python3 # This script acts as a stateful proxy for retrieving files. When the state is set to # offline, it simulates a network error with a nonsense response. import os import sys import tempfile from datetime import datetime from portabilityLayer import get_state, set_state from urllib.parse import parse_qs query = parse_qs(os.environ.get('QUERY_STRING', ''), keep_blank_values=True) test = query.get('test', [None])[0] command = query.get('command', [None])[0] if test is None: sys.stdout.write( 'status: 500\r\n' 'Content-Type: text/html\r\n\r\n' 'test parameter must be specified for a unique test name\n' ) sys.exit(0) def temp_path_base(): return os.path.join(tempfile.gettempdir(), test) state_file = temp_path_base() + '-state' def generate_no_cache_http_header(): sys.stdout.write( 'Expires: Thu, 01 Dec 2003 16:00:00 GMT\r\n' 'Cache-Control: no-cache, no-store, must-revalidate\r\n' 'Pragma: no-cache\r\n' ) def content_type(path): return { 'html': 'text/html', 'manifest': 'text/cache-manifest', 'js': 'text/javascript', 'xml': 'application/xml', 'xhtml': 'application/xhtml+xml', 'svg': 'application/svg+xml', 'xsl': 'application/xslt+xml', 'gif': 'image/gif', 'jpg': 'image/jpeg', 'png': 'image/png' }.get(path.split('.')[-1], 'text/plain') def generate_response(path): state = get_state(state_file) if state == 'Offline': # Simulate a network error by replying with a nonsense response. sys.stdout.write( 'status: 307\r\n' 'Location: {}\r\n\r\n' # Redirect to self. 'Intentionally incorrect response.'.format(os.environ.get('REQUEST_URI', '')) ) else: # A little securuty checking can't hurt. if '..' in path: sys.stdout.write('Content-Type: text/html\r\n\r\n') sys.exit(0) if len(path) > 0 and path[0] == '/': path = '..' + path if 'allow-caching' not in query.keys(): generate_no_cache_http_header() if os.path.isfile(path): sys.stdout.write( 'Last-Modified: {} GMT\r\n' 'Content-Type: {}\r\n\r\n'.format(datetime.utcfromtimestamp(os.stat(path).st_mtime).strftime('%a, %d %b %Y %H:%M:%S'), content_type(path)) ) with open(path, 'rb') as open_file: sys.stdout.flush() sys.stdout.buffer.write(open_file.read()) else: sys.stdout.write('status: 404\r\n\r\n') def handle_increate_resource_count_command(path): resource_count_file = temp_path_base() + '-count' resource_count = get_state(resource_count_file) pieces = resource_count.split(' ') count = 0 if len(pieces) == 2 and pieces[0] == path: count = 1 + int(pieces[1]) else: count = 1 set_state(resource_count_file, '{} {}'.format(path, count)) generate_response(path) def handle_reset_resource_count_command(): resource_count_file = temp_path_base() + '-count' set_state(resource_count_file, '0') generate_no_cache_http_header() sys.stdout.write('status: 200\r\n\r\n') def handle_get_resource_count_command(path): resource_count_file = temp_path_base() + '-count' resource_count = get_state(resource_count_file) pieces = resource_count.split(' ') generate_no_cache_http_header() sys.stdout.write('status: 200\r\n\r\n') if len(pieces) == 2 and pieces[0] == path: sys.stdout.write(str(pieces[1])) else: sys.stdout.write('0') def handle_start_resource_requests_log(): resource_log_file = temp_path_base() + '-log' set_state(resource_log_file, '') sys.stdout.write('Content-Type: text/html\r\n\r\n') def handle_get_resource_requests_log(): resource_log_file = temp_path_base() + '-log' generate_no_cache_http_header() sys.stdout.write('Content-Type: text/html\r\n\r\n') with open(resource_log_file, 'r') as open_file: sys.stdout.write(open_file.read()) def handle_log_resource_request(path): resource_log_file = temp_path_base() + '-log' new_data = '\n' + path with open(resource_log_file, 'a') as open_file: open_file.write(new_data) sys.stdout.write('Content-Type: text/html\r\n\r\n') if command is not None: if command == 'connect': set_state(state_file, 'Online') sys.stdout.write('Content-Type: text/html\r\n\r\n') elif command == 'disconnect': set_state(state_file, 'Offline') sys.stdout.write('Content-Type: text/html\r\n\r\n') elif command == 'increase-resource-count': handle_increate_resource_count_command(query.get('path', [''])[0]) elif command == 'reset-resource-count': handle_reset_resource_count_command() elif command == 'get-resource-count': handle_get_resource_count_command(query.get('path', [''])[0]) elif command == 'start-resource-request-log': handle_start_resource_requests_log() elif command == 'lear-resource-request-log': handle_start_resource_requests_log() elif command == 'get-resource-request-log': handle_get_resource_requests_log() elif command == 'log-resource-request': handle_log_resource_request(query.get('path', [''])[0]) else: sys.stdout.write( 'Content-Type: text/html\r\n\r\n' 'Unknown command: {}\n'.format(command) ) sys.exit(0) else: request_path = query.get('path', [''])[0] generate_response(request_path)