OLD | NEW |
1 # Copyright (c) 2016 The Chromium Authors. All rights reserved. | 1 # Copyright (c) 2016 The Chromium Authors. All rights reserved. |
2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
5 """The request data track. | 5 """The request data track. |
6 | 6 |
7 When executed, parses a JSON dump of DevTools messages. | 7 When executed, parses a JSON dump of DevTools messages. |
8 """ | 8 """ |
9 | 9 |
10 import collections | 10 import collections |
11 import copy | 11 import copy |
| 12 import json |
12 import logging | 13 import logging |
| 14 import re |
13 | 15 |
14 import devtools_monitor | 16 import devtools_monitor |
15 | 17 |
16 | 18 |
17 _TIMING_NAMES_MAPPING = { | 19 _TIMING_NAMES_MAPPING = { |
18 'connectEnd': 'connect_end', 'connectStart': 'connect_start', | 20 'connectEnd': 'connect_end', 'connectStart': 'connect_start', |
19 'dnsEnd': 'dns_end', 'dnsStart': 'dns_start', 'proxyEnd': 'proxy_end', | 21 'dnsEnd': 'dns_end', 'dnsStart': 'dns_start', 'proxyEnd': 'proxy_end', |
20 'proxyStart': 'proxy_start', 'receiveHeadersEnd': 'receive_headers_end', | 22 'proxyStart': 'proxy_start', 'receiveHeadersEnd': 'receive_headers_end', |
21 'requestTime': 'request_time', 'sendEnd': 'send_end', | 23 'requestTime': 'request_time', 'sendEnd': 'send_end', |
22 'sendStart': 'send_start', 'sslEnd': 'ssl_end', 'sslStart': 'ssl_start', | 24 'sendStart': 'send_start', 'sslEnd': 'ssl_end', 'sslStart': 'ssl_start', |
23 'workerReady': 'worker_ready', 'workerStart': 'worker_start', | 25 'workerReady': 'worker_ready', 'workerStart': 'worker_start', |
24 'loadingFinished': 'loading_finished'} | 26 'loadingFinished': 'loading_finished'} |
25 | 27 |
26 Timing = collections.namedtuple('Timing', _TIMING_NAMES_MAPPING.values()) | 28 Timing = collections.namedtuple('Timing', _TIMING_NAMES_MAPPING.values()) |
27 | 29 |
| 30 def TimingAsList(timing): |
| 31 """Transform Timing to a list, eg as is used in JSON output. |
| 32 |
| 33 Args: |
| 34 timing: a Timing. |
| 35 |
| 36 Returns: |
| 37 A list identical to what the eventual JSON output will be (eg, |
| 38 Request.ToJsonDict). |
| 39 """ |
| 40 return json.loads(json.dumps(timing)) |
28 | 41 |
29 class Request(object): | 42 class Request(object): |
30 """Represents a single request. | 43 """Represents a single request. |
31 | 44 |
32 Generally speaking, fields here closely mirror those documented in | 45 Generally speaking, fields here closely mirror those documented in |
33 third_party/WebKit/Source/devtools/protocol.json. | 46 third_party/WebKit/Source/devtools/protocol.json. |
34 | 47 |
35 Fields: | 48 Fields: |
36 request_id: (str) unique request ID. Postfixed with REDIRECT_SUFFIX for | 49 request_id: (str) unique request ID. Postfixed with REDIRECT_SUFFIX for |
37 redirects. | 50 redirects. |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
95 return (timestamp - request_time) * 1000 | 108 return (timestamp - request_time) * 1000 |
96 | 109 |
97 def ToJsonDict(self): | 110 def ToJsonDict(self): |
98 return copy.deepcopy(self.__dict__) | 111 return copy.deepcopy(self.__dict__) |
99 | 112 |
100 @classmethod | 113 @classmethod |
101 def FromJsonDict(cls, data_dict): | 114 def FromJsonDict(cls, data_dict): |
102 result = Request() | 115 result = Request() |
103 for (k, v) in data_dict.items(): | 116 for (k, v) in data_dict.items(): |
104 setattr(result, k, v) | 117 setattr(result, k, v) |
| 118 if not result.response_headers: |
| 119 result.response_headers = {} |
105 if result.timing: | 120 if result.timing: |
106 result.timing = Timing(*result.timing) | 121 result.timing = Timing(*result.timing) |
| 122 else: |
| 123 result.timing = TimingFromDict({'requestTime': result.timestamp}) |
107 return result | 124 return result |
108 | 125 |
109 def GetContentType(self): | 126 def GetContentType(self): |
110 """Returns the content type, or None.""" | 127 """Returns the content type, or None.""" |
111 content_type = self.response_headers.get('Content-Type', None) | 128 content_type = self.response_headers.get('Content-Type', None) |
112 if not content_type or ';' not in content_type: | 129 if not content_type or ';' not in content_type: |
113 return content_type | 130 return content_type |
114 else: | 131 else: |
115 return content_type[:content_type.index(';')] | 132 return content_type[:content_type.index(';')] |
116 | 133 |
(...skipping 13 matching lines...) Expand all Loading... |
130 parts = [s.strip() for s in directive.split('=')] | 147 parts = [s.strip() for s in directive.split('=')] |
131 if len(parts) == 1: | 148 if len(parts) == 1: |
132 cache_control[parts[0]] = True | 149 cache_control[parts[0]] = True |
133 else: | 150 else: |
134 cache_control[parts[0]] = parts[1] | 151 cache_control[parts[0]] = parts[1] |
135 if (u'no-store' in cache_control | 152 if (u'no-store' in cache_control |
136 or u'no-cache' in cache_control | 153 or u'no-cache' in cache_control |
137 or len(cache_control) == 0): | 154 or len(cache_control) == 0): |
138 return -1 | 155 return -1 |
139 if 'max-age' in cache_control: | 156 if 'max-age' in cache_control: |
140 return int(cache_control['max-age']) | 157 age_match = re.match(r'\s*(\d+)+', cache_control['max-age']) |
| 158 if not age_match: |
| 159 return -1 |
| 160 return int(age_match.group(1)) |
141 return -1 | 161 return -1 |
142 | 162 |
143 def __eq__(self, o): | 163 def __eq__(self, o): |
144 return self.__dict__ == o.__dict__ | 164 return self.__dict__ == o.__dict__ |
145 | 165 |
146 def __hash__(self): | 166 def __hash__(self): |
147 return hash(self.request_id) | 167 return hash(self.request_id) |
148 | 168 |
149 | 169 |
150 class RequestTrack(devtools_monitor.Track): | 170 class RequestTrack(devtools_monitor.Track): |
(...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
330 | 350 |
331 | 351 |
332 if __name__ == '__main__': | 352 if __name__ == '__main__': |
333 import json | 353 import json |
334 import sys | 354 import sys |
335 events = json.load(open(sys.argv[1], 'r')) | 355 events = json.load(open(sys.argv[1], 'r')) |
336 request_track = RequestTrack(None) | 356 request_track = RequestTrack(None) |
337 for event in events: | 357 for event in events: |
338 event_method = event['method'] | 358 event_method = event['method'] |
339 request_track.Handle(event_method, event) | 359 request_track.Handle(event_method, event) |
OLD | NEW |