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 |