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