1#!/usr/bin/env python
2# Copyright (c) 2011 The Chromium Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6"""Issue a series of GetHash requests to the SafeBrowsing servers and measure
7the response times.
8
9Usage:
10
11  $ ./gethash_timer.py --period=600 --samples=20 --output=resp.csv
12
13  --period (or -p):  The amount of time (in seconds) to wait between GetHash
14                     requests. Using a value of more than 300 (5 minutes) to
15                     include the effect of DNS.
16
17  --samples (or -s): The number of requests to issue. If this parameter is not
18                     specified, the test will run indefinitely.
19
20  --output (or -o):  The path to a file where the output will be written in
21                     CSV format: sample_number,response_code,elapsed_time_ms
22"""
23
24import getopt
25import httplib
26import sys
27import time
28
29_GETHASH_HOST = 'safebrowsing.clients.google.com'
30_GETHASH_REQUEST = (
31    '/safebrowsing/gethash?client=googleclient&appver=1.0&pver=2.1')
32
33# Global logging file handle.
34g_file_handle = None
35
36
37def IssueGetHash(prefix):
38  '''Issue one GetHash request to the safebrowsing servers.
39  Args:
40    prefix: A 4 byte value to look up on the server.
41  Returns:
42    The HTTP response code for the GetHash request.
43  '''
44  body = '4:4\n' + prefix
45  h = httplib.HTTPConnection(_GETHASH_HOST)
46  h.putrequest('POST', _GETHASH_REQUEST)
47  h.putheader('content-length', str(len(body)))
48  h.endheaders()
49  h.send(body)
50  response_code = h.getresponse().status
51  h.close()
52  return response_code
53
54
55def TimedGetHash(prefix):
56  '''Measure the amount of time it takes to receive a GetHash response.
57  Args:
58    prefix: A 4 byte value to look up on the the server.
59  Returns:
60    A tuple of HTTP resonse code and the response time (in milliseconds).
61  '''
62  start = time.time()
63  response_code = IssueGetHash(prefix)
64  return response_code, (time.time() - start) * 1000
65
66
67def RunTimedGetHash(period, samples=None):
68  '''Runs an experiment to measure the amount of time it takes to receive
69  multiple responses from the GetHash servers.
70
71  Args:
72    period:  A floating point value that indicates (in seconds) the delay
73             between requests.
74    samples: An integer value indicating the number of requests to make.
75             If 'None', the test continues indefinitely.
76  Returns:
77    None.
78  '''
79  global g_file_handle
80  prefix = '\x50\x61\x75\x6c'
81  sample_count = 1
82  while True:
83    response_code, elapsed_time = TimedGetHash(prefix)
84    LogResponse(sample_count, response_code, elapsed_time)
85    sample_count += 1
86    if samples is not None and sample_count == samples:
87      break
88    time.sleep(period)
89
90
91def LogResponse(sample_count, response_code, elapsed_time):
92  '''Output the response for one GetHash query.
93  Args:
94    sample_count:  The current sample number.
95    response_code: The HTTP response code for the GetHash request.
96    elapsed_time:  The round-trip time (in milliseconds) for the
97                   GetHash request.
98  Returns:
99    None.
100  '''
101  global g_file_handle
102  output_list = (sample_count, response_code, elapsed_time)
103  print 'Request: %d, status: %d, elapsed time: %f ms' % output_list
104  if g_file_handle is not None:
105    g_file_handle.write(('%d,%d,%f' % output_list) + '\n')
106    g_file_handle.flush()
107
108
109def SetupOutputFile(file_name):
110  '''Open a file for logging results.
111  Args:
112    file_name: A path to a file to store the output.
113  Returns:
114    None.
115  '''
116  global g_file_handle
117  g_file_handle = open(file_name, 'w')
118
119
120def main():
121  period = 10
122  samples = None
123
124  options, args = getopt.getopt(sys.argv[1:],
125                                's:p:o:',
126                                ['samples=', 'period=', 'output='])
127  for option, value in options:
128    if option == '-s' or option == '--samples':
129      samples = int(value)
130    elif option == '-p' or option == '--period':
131      period = float(value)
132    elif option == '-o' or option == '--output':
133      file_name = value
134    else:
135      print 'Bad option: %s' % option
136      return 1
137  try:
138    print 'Starting Timed GetHash ----------'
139    SetupOutputFile(file_name)
140    RunTimedGetHash(period, samples)
141  except KeyboardInterrupt:
142    pass
143
144  print 'Timed GetHash complete ----------'
145  g_file_handle.close()
146
147
148if __name__ == '__main__':
149  sys.exit(main())
150