1424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)# Copyright 2013 The Chromium Authors. All rights reserved. 2eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch# Use of this source code is governed by a BSD-style license that can be 3eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch# found in the LICENSE file. 4a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)import logging 5a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 6a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)from telemetry.core import util 7a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)from telemetry.core.backends.chrome import timeline_recorder 8f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)from telemetry.timeline import inspector_timeline_data 9a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 10a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 11a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)class InspectorNetworkException(Exception): 12a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) pass 13a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 14a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 15a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)class InspectorNetworkResponseData(object): 16a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) def __init__(self, inspector_network, params): 17a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self._inspector_network = inspector_network 18a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self._request_id = params['requestId'] 19a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self._timestamp = params['timestamp'] 20a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 21a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self._response = params['response'] 22a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if not self._response: 23a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) raise InspectorNetworkException('response must exist') 24a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 25a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) # Response headers. 26a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) headers = self._response['headers'] 27a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self._header_map = {} 28a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) for k, v in headers.iteritems(): 29a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) # Camel-case header keys. 30a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self._header_map[k.title()] = v 31a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 32a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) # Request headers. 33a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self._request_header_map = {} 34a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if 'requestHeaders' in self._response: 35a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) # Camel-case header keys. 36a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) for k, v in self._response['requestHeaders'].iteritems(): 37a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self._request_header_map[k.title()] = v 38a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 39a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self._body = None 40a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self._base64_encoded = False 41a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if self._inspector_network: 42a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self._served_from_cache = ( 43a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self._inspector_network.HTTPResponseServedFromCache(self._request_id)) 44a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) else: 45a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self._served_from_cache = False 46a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 47a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) # Whether constructed from a timeline event. 48a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self._from_event = False 49a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 50a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) @property 51a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) def status(self): 52a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return self._response['status'] 53a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 54a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) def status_text(self): 55a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return self._response['status_text'] 56a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 57a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) @property 58a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) def headers(self): 59a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return self._header_map 60a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 61a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) @property 62a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) def request_headers(self): 63a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return self._request_header_map 64a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 65a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) @property 66a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) def timestamp(self): 67a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return self._timestamp 68a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 69a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) @property 70a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) def timing(self): 71a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if 'timing' in self._response: 72a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return self._response['timing'] 73a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return None 74a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 75a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) @property 76a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) def url(self): 77a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return self._response['url'] 78a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 79a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) @property 80a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) def request_id(self): 81a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return self._request_id 82a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 83a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) @property 84a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) def served_from_cache(self): 8523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) return self._served_from_cache 86a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 87a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) def GetHeader(self, name): 88a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if name in self.headers: 89a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return self.headers[name] 90a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return None 91a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 92a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) def GetBody(self, timeout=60): 93a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if not self._body and not self._from_event: 94a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self._body, self._base64_encoded = ( 95a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self._inspector_network.GetHTTPResponseBody(self._request_id, timeout)) 96a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return self._body, self._base64_encoded 97a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 98a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) def AsTimelineEvent(self): 99a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) event = {} 100a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) event['type'] = 'HTTPResponse' 101a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) event['startTime'] = self.timestamp 102a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) # There is no end time. Just return the timestamp instead. 103a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) event['endTime'] = self.timestamp 104a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) event['requestId'] = self.request_id 105a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) event['response'] = self._response 106a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) event['body'], event['base64_encoded_body'] = self.GetBody() 107a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) event['served_from_cache'] = self.served_from_cache 108a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return event 109a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 110a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) @staticmethod 111a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) def FromTimelineEvent(event): 112a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) assert event.name == 'HTTPResponse' 113a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) params = {} 114a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) params['timestamp'] = event.start 115a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) params['requestId'] = event.args['requestId'] 116a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) params['response'] = event.args['response'] 117a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) recorded = InspectorNetworkResponseData(None, params) 118a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) recorded._body = event.args['body'] 119a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) recorded._base64_encoded = event.args['base64_encoded_body'] 120a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) recorded._served_from_cache = event.args['served_from_cache'] 121a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) recorded._from_event = True 122a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return recorded 123a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 124eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 125eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochclass InspectorNetwork(object): 126eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch def __init__(self, inspector_backend): 127eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch self._inspector_backend = inspector_backend 128a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self._http_responses = [] 129a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self._served_from_cache = set() 130a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self._timeline_recorder = None 131eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 132eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch def ClearCache(self, timeout=60): 133eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch """Clears the browser's disk and memory cache.""" 134eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch res = self._inspector_backend.SyncRequest({ 135eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 'method': 'Network.canClearBrowserCache' 136eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch }, timeout) 137a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) assert res['result'], 'Cache clearing is not supported by this browser.' 138eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch self._inspector_backend.SyncRequest({ 139eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 'method': 'Network.clearBrowserCache' 140eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch }, timeout) 141a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 142a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) def StartMonitoringNetwork(self): 143a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) """Starts monitoring network notifications and recording HTTP responses.""" 144a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self.ClearResponseData() 145a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self._inspector_backend.RegisterDomain( 146a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 'Network', 147a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self._OnNetworkNotification, 148a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self._OnClose) 149a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) request = { 150a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 'method': 'Network.enable' 151a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 152a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self._inspector_backend.SyncRequest(request) 153a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 154a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) def StopMonitoringNetwork(self): 155a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) """Stops monitoring network notifications and recording HTTP responses.""" 156a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self._inspector_backend.UnregisterDomain('Network') 157a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) request = { 158a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 'method': 'Network.disable' 159a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 160a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self._inspector_backend.SyncRequest(request) 161a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 162a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) def GetResponseData(self): 163a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) """Returns all recorded HTTP responses.""" 164a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return self._http_responses 165a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 166a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) def ClearResponseData(self): 167a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) """Clears recorded HTTP responses.""" 168a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self._http_responses = [] 169a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self._served_from_cache.clear() 170a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 171a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) def _OnNetworkNotification(self, msg): 172a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if msg['method'] == 'Network.responseReceived': 173a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self._RecordHTTPResponse(msg['params']) 174a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) elif msg['method'] == 'Network.requestServedFromCache': 175a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self._served_from_cache.add(msg['params']['requestId']) 176a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 177a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) def _RecordHTTPResponse(self, params): 178a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) required_fields = ['requestId', 'timestamp', 'response'] 179a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) for field in required_fields: 180a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if field not in params: 181a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) logging.waring('HTTP Response missing required field: %s', field) 182a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return 183a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self._http_responses.append(InspectorNetworkResponseData(self, params)) 184a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 185a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) def GetHTTPResponseBody(self, request_id, timeout=60): 186a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) try: 187a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) res = self._inspector_backend.SyncRequest({ 188a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 'method': 'Network.getResponseBody', 189a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 'params': { 190a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 'requestId': request_id, 191a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 192a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) }, timeout) 193a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) except util.TimeoutException: 194a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) logging.warning('Timeout during fetching body for %s' % request_id) 195a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return None, False 196a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if 'error' in res: 197a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return None, False 198a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return res['result']['body'], res['result']['base64Encoded'] 199a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 200a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) def HTTPResponseServedFromCache(self, request_id): 201a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return request_id and request_id in self._served_from_cache 202a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 203a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) def _OnClose(self): 204a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) pass 205a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 206a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) @property 207a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) def timeline_recorder (self): 208a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if not self._timeline_recorder: 209a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self._timeline_recorder = TimelineRecorder(self) 210a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return self._timeline_recorder 211a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 212a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 213a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)class TimelineRecorder(timeline_recorder.TimelineRecorder): 214a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) def __init__(self, inspector_network): 215a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) super(TimelineRecorder, self).__init__() 216a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self._inspector_network = inspector_network 217a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self._is_recording = False 218a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 219a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) def Start(self): 220a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) assert not self._is_recording, 'Start should only be called once.' 221a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self._is_recording = True 222a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self._inspector_network.StartMonitoringNetwork() 223a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 224a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) def Stop(self): 225a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if not self._is_recording: 226a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return None 227a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) responses = self._inspector_network.GetResponseData() 228a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) events = [r.AsTimelineEvent() for r in list(responses)] 229a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self._inspector_network.StopMonitoringNetwork() 230a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self._is_recording = False 231a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if len(events) == 0: 232a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return None 233a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return inspector_timeline_data.InspectorTimelineData(events) 234