#!/usr/bin/env python # Copyright (c) 2011 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. """Issue a series of GetHash requests to the SafeBrowsing servers and measure the response times. Usage: $ ./gethash_timer.py --period=600 --samples=20 --output=resp.csv --period (or -p): The amount of time (in seconds) to wait between GetHash requests. Using a value of more than 300 (5 minutes) to include the effect of DNS. --samples (or -s): The number of requests to issue. If this parameter is not specified, the test will run indefinitely. --output (or -o): The path to a file where the output will be written in CSV format: sample_number,response_code,elapsed_time_ms """ import getopt import httplib import sys import time _GETHASH_HOST = 'safebrowsing.clients.google.com' _GETHASH_REQUEST = ( '/safebrowsing/gethash?client=googleclient&appver=1.0&pver=2.1') # Global logging file handle. g_file_handle = None def IssueGetHash(prefix): '''Issue one GetHash request to the safebrowsing servers. Args: prefix: A 4 byte value to look up on the server. Returns: The HTTP response code for the GetHash request. ''' body = '4:4\n' + prefix h = httplib.HTTPConnection(_GETHASH_HOST) h.putrequest('POST', _GETHASH_REQUEST) h.putheader('content-length', str(len(body))) h.endheaders() h.send(body) response_code = h.getresponse().status h.close() return response_code def TimedGetHash(prefix): '''Measure the amount of time it takes to receive a GetHash response. Args: prefix: A 4 byte value to look up on the the server. Returns: A tuple of HTTP resonse code and the response time (in milliseconds). ''' start = time.time() response_code = IssueGetHash(prefix) return response_code, (time.time() - start) * 1000 def RunTimedGetHash(period, samples=None): '''Runs an experiment to measure the amount of time it takes to receive multiple responses from the GetHash servers. Args: period: A floating point value that indicates (in seconds) the delay between requests. samples: An integer value indicating the number of requests to make. If 'None', the test continues indefinitely. Returns: None. ''' global g_file_handle prefix = '\x50\x61\x75\x6c' sample_count = 1 while True: response_code, elapsed_time = TimedGetHash(prefix) LogResponse(sample_count, response_code, elapsed_time) sample_count += 1 if samples is not None and sample_count == samples: break time.sleep(period) def LogResponse(sample_count, response_code, elapsed_time): '''Output the response for one GetHash query. Args: sample_count: The current sample number. response_code: The HTTP response code for the GetHash request. elapsed_time: The round-trip time (in milliseconds) for the GetHash request. Returns: None. ''' global g_file_handle output_list = (sample_count, response_code, elapsed_time) print 'Request: %d, status: %d, elapsed time: %f ms' % output_list if g_file_handle is not None: g_file_handle.write(('%d,%d,%f' % output_list) + '\n') g_file_handle.flush() def SetupOutputFile(file_name): '''Open a file for logging results. Args: file_name: A path to a file to store the output. Returns: None. ''' global g_file_handle g_file_handle = open(file_name, 'w') def main(): period = 10 samples = None options, args = getopt.getopt(sys.argv[1:], 's:p:o:', ['samples=', 'period=', 'output=']) for option, value in options: if option == '-s' or option == '--samples': samples = int(value) elif option == '-p' or option == '--period': period = float(value) elif option == '-o' or option == '--output': file_name = value else: print 'Bad option: %s' % option return 1 try: print 'Starting Timed GetHash ----------' SetupOutputFile(file_name) RunTimedGetHash(period, samples) except KeyboardInterrupt: pass print 'Timed GetHash complete ----------' g_file_handle.close() if __name__ == '__main__': sys.exit(main())