| 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 bisect | 10 import bisect |
| (...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 202 self.timestamp = -1 | 202 self.timestamp = -1 |
| 203 self.wall_time = -1 | 203 self.wall_time = -1 |
| 204 self.initiator = None | 204 self.initiator = None |
| 205 self.resource_type = None | 205 self.resource_type = None |
| 206 self.served_from_cache = False | 206 self.served_from_cache = False |
| 207 self.from_disk_cache = False | 207 self.from_disk_cache = False |
| 208 self.from_service_worker = False | 208 self.from_service_worker = False |
| 209 self.timing = None | 209 self.timing = None |
| 210 self.status = None | 210 self.status = None |
| 211 self.status_text = None | 211 self.status_text = None |
| 212 self.response_headers_length = 0 |
| 212 self.encoded_data_length = 0 | 213 self.encoded_data_length = 0 |
| 213 self.data_chunks = [] | 214 self.data_chunks = [] |
| 214 self.failed = False | 215 self.failed = False |
| 215 self.error_text = None | 216 self.error_text = None |
| 216 | 217 |
| 217 @property | 218 @property |
| 218 def start_msec(self): | 219 def start_msec(self): |
| 219 return self.timing.request_time * 1000 | 220 return self.timing.request_time * 1000 |
| 220 | 221 |
| 221 @property | 222 @property |
| (...skipping 24 matching lines...) Expand all Loading... |
| 246 for (k, v) in data_dict.items(): | 247 for (k, v) in data_dict.items(): |
| 247 setattr(result, k, v) | 248 setattr(result, k, v) |
| 248 if not result.response_headers: | 249 if not result.response_headers: |
| 249 result.response_headers = {} | 250 result.response_headers = {} |
| 250 if result.timing: | 251 if result.timing: |
| 251 result.timing = Timing.FromJsonDict(result.timing) | 252 result.timing = Timing.FromJsonDict(result.timing) |
| 252 else: | 253 else: |
| 253 result.timing = Timing(request_time=result.timestamp) | 254 result.timing = Timing(request_time=result.timestamp) |
| 254 return result | 255 return result |
| 255 | 256 |
| 256 def GetEncodedDataLength(self): | 257 def GetResponseTransportLength(self): |
| 257 """Get the total amount of encoded data no matter whether load has finished | 258 """Get the total amount of encoded data no matter whether load has finished |
| 258 or not. | 259 or not. |
| 259 """ | 260 """ |
| 260 assert self.HasReceivedResponse() | 261 assert self.HasReceivedResponse() |
| 261 assert not self.from_disk_cache and not self.served_from_cache | 262 assert not self.from_disk_cache and not self.served_from_cache |
| 262 assert self.protocol != 'about' | 263 assert self.protocol not in {'about', 'blob', 'data'} |
| 263 if self.failed: | |
| 264 # TODO(gabadie): Once crbug.com/622018 is fixed, remove this branch. | |
| 265 return 0 | |
| 266 if self.timing.loading_finished != Timing.UNVAILABLE: | 264 if self.timing.loading_finished != Timing.UNVAILABLE: |
| 267 encoded_data_length = self.encoded_data_length | 265 encoded_data_length = self.encoded_data_length |
| 268 assert encoded_data_length > 0 | |
| 269 else: | 266 else: |
| 270 encoded_data_length = sum( | 267 encoded_data_length = sum( |
| 271 [chunk_size for _, chunk_size in self.data_chunks]) | 268 [chunk_size for _, chunk_size in self.data_chunks]) |
| 272 assert encoded_data_length > 0 or len(self.data_chunks) == 0 | 269 assert encoded_data_length > 0 or len(self.data_chunks) == 0 |
| 273 return encoded_data_length | 270 return encoded_data_length + self.response_headers_length |
| 274 | 271 |
| 275 def GetHTTPResponseHeader(self, header_name): | 272 def GetHTTPResponseHeader(self, header_name): |
| 276 """Gets the value of a HTTP response header. | 273 """Gets the value of a HTTP response header. |
| 277 | 274 |
| 278 Does a case-insensitive search for the header name in the HTTP response | 275 Does a case-insensitive search for the header name in the HTTP response |
| 279 headers, in order to support servers that use a wrong capitalization. | 276 headers, in order to support servers that use a wrong capitalization. |
| 280 """ | 277 """ |
| 281 lower_case_name = header_name.lower() | 278 lower_case_name = header_name.lower() |
| 282 result = None | 279 result = None |
| 283 for name, value in self.response_headers.iteritems(): | 280 for name, value in self.response_headers.iteritems(): |
| (...skipping 445 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 729 def _HandleRedirect(self, request_id, params): | 726 def _HandleRedirect(self, request_id, params): |
| 730 (r, status) = self._requests_in_flight[request_id] | 727 (r, status) = self._requests_in_flight[request_id] |
| 731 assert status == RequestTrack._STATUS_SENT | 728 assert status == RequestTrack._STATUS_SENT |
| 732 # The second request contains timing information pertaining to the first | 729 # The second request contains timing information pertaining to the first |
| 733 # one. Finalize the first request. | 730 # one. Finalize the first request. |
| 734 assert 'redirectResponse' in params | 731 assert 'redirectResponse' in params |
| 735 redirect_response = params['redirectResponse'] | 732 redirect_response = params['redirectResponse'] |
| 736 | 733 |
| 737 _CopyFromDictToObject(redirect_response, r, | 734 _CopyFromDictToObject(redirect_response, r, |
| 738 (('headers', 'response_headers'), | 735 (('headers', 'response_headers'), |
| 739 ('encodedDataLength', 'encoded_data_length'), | 736 ('encodedDataLength', 'response_headers_length'), |
| 740 ('fromDiskCache', 'from_disk_cache'), | 737 ('fromDiskCache', 'from_disk_cache'), |
| 741 ('protocol', 'protocol'), ('status', 'status'), | 738 ('protocol', 'protocol'), ('status', 'status'), |
| 742 ('statusText', 'status_text'))) | 739 ('statusText', 'status_text'))) |
| 743 r.timing = Timing.FromDevToolsDict(redirect_response['timing']) | 740 r.timing = Timing.FromDevToolsDict(redirect_response['timing']) |
| 744 | 741 |
| 745 redirect_index = self._redirects_count_by_id[request_id] | 742 redirect_index = self._redirects_count_by_id[request_id] |
| 746 self._redirects_count_by_id[request_id] += 1 | 743 self._redirects_count_by_id[request_id] += 1 |
| 747 r.request_id = '%s%s.%d' % (request_id, self._REDIRECT_SUFFIX, | 744 r.request_id = '%s%s.%d' % (request_id, self._REDIRECT_SUFFIX, |
| 748 redirect_index + 1) | 745 redirect_index + 1) |
| 749 initiator = { | 746 initiator = { |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 785 assert r.resource_type == params.get('type', 'Other') | 782 assert r.resource_type == params.get('type', 'Other') |
| 786 response = params['response'] | 783 response = params['response'] |
| 787 _CopyFromDictToObject( | 784 _CopyFromDictToObject( |
| 788 response, r, (('status', 'status'), ('mimeType', 'mime_type'), | 785 response, r, (('status', 'status'), ('mimeType', 'mime_type'), |
| 789 ('fromDiskCache', 'from_disk_cache'), | 786 ('fromDiskCache', 'from_disk_cache'), |
| 790 ('fromServiceWorker', 'from_service_worker'), | 787 ('fromServiceWorker', 'from_service_worker'), |
| 791 ('protocol', 'protocol'), ('statusText', 'status_text'), | 788 ('protocol', 'protocol'), ('statusText', 'status_text'), |
| 792 # Actual request headers are not known before reaching the | 789 # Actual request headers are not known before reaching the |
| 793 # network stack. | 790 # network stack. |
| 794 ('requestHeaders', 'request_headers'), | 791 ('requestHeaders', 'request_headers'), |
| 792 ('encodedDataLength', 'response_headers_length'), |
| 795 ('headers', 'response_headers'))) | 793 ('headers', 'response_headers'))) |
| 796 timing_dict = {} | 794 timing_dict = {} |
| 797 # Some URLs don't have a timing dict (e.g. data URLs), and timings for | 795 # Some URLs don't have a timing dict (e.g. data URLs), and timings for |
| 798 # cached requests are stale. | 796 # cached requests are stale. |
| 799 # TODO(droger): the timestamp is inacurate, get the real timings instead. | 797 # TODO(droger): the timestamp is inacurate, get the real timings instead. |
| 800 if not response.get('timing') or r.served_from_cache: | 798 if not response.get('timing') or r.served_from_cache: |
| 801 timing_dict = {'requestTime': r.timestamp} | 799 timing_dict = {'requestTime': r.timestamp} |
| 802 else: | 800 else: |
| 803 timing_dict = response['timing'] | 801 timing_dict = response['timing'] |
| 804 r.timing = Timing.FromDevToolsDict(timing_dict) | 802 r.timing = Timing.FromDevToolsDict(timing_dict) |
| (...skipping 10 matching lines...) Expand all Loading... |
| 815 r.data_chunks.append((offset, params['encodedDataLength'])) | 813 r.data_chunks.append((offset, params['encodedDataLength'])) |
| 816 self._requests_in_flight[request_id] = (r, RequestTrack._STATUS_DATA) | 814 self._requests_in_flight[request_id] = (r, RequestTrack._STATUS_DATA) |
| 817 | 815 |
| 818 def _LoadingFinished(self, request_id, params): | 816 def _LoadingFinished(self, request_id, params): |
| 819 if request_id not in self._requests_in_flight: | 817 if request_id not in self._requests_in_flight: |
| 820 return | 818 return |
| 821 (r, status) = self._requests_in_flight[request_id] | 819 (r, status) = self._requests_in_flight[request_id] |
| 822 assert (status == RequestTrack._STATUS_RESPONSE | 820 assert (status == RequestTrack._STATUS_RESPONSE |
| 823 or status == RequestTrack._STATUS_DATA) | 821 or status == RequestTrack._STATUS_DATA) |
| 824 r.encoded_data_length = params['encodedDataLength'] | 822 r.encoded_data_length = params['encodedDataLength'] |
| 825 assert (r.encoded_data_length > 0 or r.protocol in {'about', 'data'} or | |
| 826 r.from_disk_cache or r.served_from_cache) | |
| 827 r.timing.loading_finished = r._TimestampOffsetFromStartMs( | 823 r.timing.loading_finished = r._TimestampOffsetFromStartMs( |
| 828 params['timestamp']) | 824 params['timestamp']) |
| 829 self._requests_in_flight[request_id] = (r, RequestTrack._STATUS_FINISHED) | 825 self._requests_in_flight[request_id] = (r, RequestTrack._STATUS_FINISHED) |
| 830 self._FinalizeRequest(request_id) | 826 self._FinalizeRequest(request_id) |
| 831 | 827 |
| 832 def _LoadingFailed(self, request_id, params): | 828 def _LoadingFailed(self, request_id, params): |
| 833 if request_id not in self._requests_in_flight: | 829 if request_id not in self._requests_in_flight: |
| 834 logging.warning('An unknown request failed: %s' % request_id) | 830 logging.warning('An unknown request failed: %s' % request_id) |
| 835 return | 831 return |
| 836 (r, _) = self._requests_in_flight[request_id] | 832 (r, _) = self._requests_in_flight[request_id] |
| (...skipping 29 matching lines...) Expand all Loading... |
| 866 | 862 |
| 867 | 863 |
| 868 if __name__ == '__main__': | 864 if __name__ == '__main__': |
| 869 import json | 865 import json |
| 870 import sys | 866 import sys |
| 871 events = json.load(open(sys.argv[1], 'r')) | 867 events = json.load(open(sys.argv[1], 'r')) |
| 872 request_track = RequestTrack(None) | 868 request_track = RequestTrack(None) |
| 873 for event in events: | 869 for event in events: |
| 874 event_method = event['method'] | 870 event_method = event['method'] |
| 875 request_track.Handle(event_method, event) | 871 request_track.Handle(event_method, event) |
| OLD | NEW |