| Index: tools/android/loading/log_parser.py
|
| diff --git a/tools/android/loading/log_parser.py b/tools/android/loading/log_parser.py
|
| deleted file mode 100644
|
| index a58bd55a1b5f8b2ccdd87742afb1ccf69a3f37e2..0000000000000000000000000000000000000000
|
| --- a/tools/android/loading/log_parser.py
|
| +++ /dev/null
|
| @@ -1,218 +0,0 @@
|
| -# Copyright 2015 The Chromium Authors. All rights reserved.
|
| -# Use of this source code is governed by a BSD-style license that can be
|
| -# found in the LICENSE file.
|
| -
|
| -"""Parses a JSON request log created by log_requests.py."""
|
| -
|
| -import collections
|
| -import json
|
| -import operator
|
| -import urlparse
|
| -
|
| -Timing = collections.namedtuple(
|
| - 'Timing',
|
| - ['connectEnd', 'connectStart', 'dnsEnd', 'dnsStart', 'proxyEnd',
|
| - 'proxyStart', 'receiveHeadersEnd', 'requestTime', 'sendEnd', 'sendStart',
|
| - 'sslEnd', 'sslStart', 'workerReady', 'workerStart', 'loadingFinished'])
|
| -
|
| -
|
| -class Resource(object):
|
| - """Describes a resource."""
|
| -
|
| - def __init__(self, url, content_type):
|
| - """Creates an instance of Resource.
|
| -
|
| - Args:
|
| - url: URL of the resource
|
| - content_type: Content-Type of the resources.
|
| - """
|
| - self.url = url
|
| - self.content_type = content_type
|
| -
|
| - def GetShortName(self):
|
| - """Returns either the hostname of the resource, or the filename,
|
| - or the end of the path. Tries to include the domain as much as possible.
|
| - """
|
| - parsed = urlparse.urlparse(self.url)
|
| - path = parsed.path
|
| - if path != '' and path != '/':
|
| - last_path = parsed.path.split('/')[-1]
|
| - if len(last_path) < 10:
|
| - if len(path) < 10:
|
| - return parsed.hostname + '/' + path
|
| - else:
|
| - return parsed.hostname + '/..' + parsed.path[-10:]
|
| - elif len(last_path) > 10:
|
| - return parsed.hostname + '/..' + last_path[:5]
|
| - else:
|
| - return parsed.hostname + '/..' + last_path
|
| - else:
|
| - return parsed.hostname
|
| -
|
| - def GetContentType(self):
|
| - mime = self.content_type
|
| - if 'magic-debug-content' in mime:
|
| - # A silly hack to make the unittesting easier.
|
| - return 'magic-debug-content'
|
| - elif mime == 'text/html':
|
| - return 'html'
|
| - elif mime == 'text/css':
|
| - return 'css'
|
| - elif mime in ('application/x-javascript', 'text/javascript',
|
| - 'application/javascript'):
|
| - return 'script'
|
| - elif mime == 'application/json':
|
| - return 'json'
|
| - elif mime == 'image/gif':
|
| - return 'gif_image'
|
| - elif mime.startswith('image/'):
|
| - return 'image'
|
| - else:
|
| - return 'other'
|
| -
|
| - @classmethod
|
| - def FromRequest(cls, request):
|
| - """Creates a Resource from an instance of RequestData."""
|
| - return Resource(request.url, request.GetContentType())
|
| -
|
| - def __Fields(self):
|
| - return (self.url, self.content_type)
|
| -
|
| - def __eq__(self, o):
|
| - return self.__Fields() == o.__Fields()
|
| -
|
| - def __hash__(self):
|
| - return hash(self.__Fields())
|
| -
|
| -
|
| -class RequestData(object):
|
| - """Represents a request, as dumped by log_requests.py."""
|
| -
|
| - def __init__(self, status, headers, request_headers, timestamp, timing, url,
|
| - served_from_cache, initiator):
|
| - self.status = status
|
| - self.headers = headers
|
| - self.request_headers = request_headers
|
| - self.timestamp = timestamp
|
| - self.timing = Timing(**timing) if timing else None
|
| - self.url = url
|
| - self.served_from_cache = served_from_cache
|
| - self.initiator = initiator
|
| -
|
| - def IsDataUrl(self):
|
| - return self.url.startswith('data:')
|
| -
|
| - def GetContentType(self):
|
| - content_type = self.headers['Content-Type']
|
| - if ';' in content_type:
|
| - return content_type[:content_type.index(';')]
|
| - else:
|
| - return content_type
|
| -
|
| - @classmethod
|
| - def FromDict(cls, r):
|
| - """Creates a RequestData object from a dict."""
|
| - return RequestData(r['status'], r['headers'], r['request_headers'],
|
| - r['timestamp'], r['timing'], r['url'],
|
| - r['served_from_cache'], r['initiator'])
|
| -
|
| -
|
| -def ParseJsonFile(filename):
|
| - """Converts a JSON file to a sequence of RequestData."""
|
| - with open(filename) as f:
|
| - json_data = json.load(f)
|
| - return [RequestData.FromDict(r) for r in json_data]
|
| -
|
| -
|
| -def FilterRequests(requests):
|
| - """Filters a list of requests.
|
| -
|
| - Args:
|
| - requests: [RequestData, ...]
|
| -
|
| - Returns:
|
| - A list of requests that are not data URL, have a Content-Type, and are
|
| - not served from the cache.
|
| - """
|
| - return [r for r in requests if not r.IsDataUrl()
|
| - and 'Content-Type' in r.headers and not r.served_from_cache]
|
| -
|
| -
|
| -def ResourceToRequestMap(requests):
|
| - """Returns a Resource -> Request map.
|
| -
|
| - A resource can be requested several times in a single page load. Keeps the
|
| - first request in this case.
|
| -
|
| - Args:
|
| - requests: [RequestData, ...]
|
| -
|
| - Returns:
|
| - [Resource, ...]
|
| - """
|
| - # reversed(requests) because we want the first one to win.
|
| - return dict([(Resource.FromRequest(r), r) for r in reversed(requests)])
|
| -
|
| -
|
| -def GetResources(requests):
|
| - """Returns an ordered list of resources from a list of requests.
|
| -
|
| - The same resource can be requested several time for a single page load. This
|
| - keeps only the first request.
|
| -
|
| - Args:
|
| - requests: [RequestData]
|
| -
|
| - Returns:
|
| - [Resource]
|
| - """
|
| - resources = []
|
| - known_resources = set()
|
| - for r in requests:
|
| - resource = Resource.FromRequest(r)
|
| - if r in known_resources:
|
| - continue
|
| - known_resources.add(resource)
|
| - resources.append(resource)
|
| - return resources
|
| -
|
| -
|
| -def ParseCacheControl(headers):
|
| - """Parses the "Cache-Control" header and returns a dict representing it.
|
| -
|
| - Args:
|
| - headers: (dict) Response headers.
|
| -
|
| - Returns:
|
| - {Directive: Value, ...}
|
| - """
|
| - # TODO(lizeb): Handle the "Expires" header as well.
|
| - result = {}
|
| - cache_control = headers.get('Cache-Control', None)
|
| - if cache_control is None:
|
| - return result
|
| - directives = [s.strip() for s in cache_control.split(',')]
|
| - for directive in directives:
|
| - parts = [s.strip() for s in directive.split('=')]
|
| - if len(parts) == 1:
|
| - result[parts[0]] = True
|
| - else:
|
| - result[parts[0]] = parts[1]
|
| - return result
|
| -
|
| -
|
| -def MaxAge(request):
|
| - """Returns the max-age of a resource, or -1."""
|
| - cache_control = ParseCacheControl(request.headers)
|
| - if (u'no-store' in cache_control
|
| - or u'no-cache' in cache_control
|
| - or len(cache_control) == 0):
|
| - return -1
|
| - if 'max-age' in cache_control:
|
| - return int(cache_control['max-age'])
|
| - return -1
|
| -
|
| -
|
| -def SortedByCompletion(requests):
|
| - """Returns the requests, sorted by completion time."""
|
| - return sorted(requests, key=operator.attrgetter('timestamp'))
|
|
|