| Index: tools/telemetry/telemetry/core/backends/chrome_inspector/devtools_http.py
|
| diff --git a/tools/telemetry/telemetry/core/backends/chrome_inspector/devtools_http.py b/tools/telemetry/telemetry/core/backends/chrome_inspector/devtools_http.py
|
| index f5fd8afdb9ef2449ad13925020e6d2d955f77526..50271048c8bf3fc0683cfdbf4248e0c68ba37800 100644
|
| --- a/tools/telemetry/telemetry/core/backends/chrome_inspector/devtools_http.py
|
| +++ b/tools/telemetry/telemetry/core/backends/chrome_inspector/devtools_http.py
|
| @@ -2,11 +2,11 @@
|
| # Use of this source code is governed by a BSD-style license that can be
|
| # found in the LICENSE file.
|
|
|
| -import contextlib
|
| +import errno
|
| import httplib
|
| import json
|
| import socket
|
| -import urllib2
|
| +import sys
|
|
|
|
|
| class DevToolsClientConnectionError(Exception):
|
| @@ -18,13 +18,48 @@ class DevToolsClientUrlError(DevToolsClientConnectionError):
|
|
|
|
|
| class DevToolsHttp(object):
|
| - """A helper class to send and parse DevTools HTTP requests."""
|
| + """A helper class to send and parse DevTools HTTP requests.
|
| +
|
| + This class maintains a persistent http connection to Chrome devtools.
|
| + Ideally, owners of instances of this class should call Disconnect() before
|
| + disposing of the instance. Otherwise, the connection will not be closed until
|
| + the instance is garbage collected.
|
| + """
|
|
|
| def __init__(self, devtools_port):
|
| self._devtools_port = devtools_port
|
| + self._conn = None
|
| +
|
| + def __del__(self):
|
| + self.Disconnect()
|
| +
|
| + def _Connect(self, timeout):
|
| + """Attempts to establish a connection to Chrome devtools."""
|
| + assert not self._conn
|
| + try:
|
| + host_port = '127.0.0.1:%i' % self._devtools_port
|
| + self._conn = httplib.HTTPConnection(host_port, timeout=timeout)
|
| + except (socket.error, httplib.HTTPException) as e:
|
| + raise DevToolsClientConnectionError, (e,), sys.exc_info()[2]
|
| +
|
| + def Disconnect(self):
|
| + """Closes the HTTP connection."""
|
| + if not self._conn:
|
| + return
|
| +
|
| + try:
|
| + self._conn.close()
|
| + except (socket.error, httplib.HTTPException) as e:
|
| + raise DevToolsClientConnectionError, (e,), sys.exc_info()[2]
|
| + finally:
|
| + self._conn = None
|
|
|
| def Request(self, path, timeout=30):
|
| - """
|
| + """Sends a request to Chrome devtools.
|
| +
|
| + This method lazily creates an HTTP connection, if one does not already
|
| + exist.
|
| +
|
| Args:
|
| path: The DevTools URL path, without the /json/ prefix.
|
| timeout: Timeout defaults to 30 seconds.
|
| @@ -32,18 +67,27 @@ class DevToolsHttp(object):
|
| Raises:
|
| DevToolsClientConnectionError: If the connection fails.
|
| """
|
| - url = 'http://127.0.0.1:%i/json' % self._devtools_port
|
| + if not self._conn:
|
| + self._Connect(timeout)
|
| +
|
| + endpoint = '/json'
|
| if path:
|
| - url += '/' + path
|
| + endpoint += '/' + path
|
| + if self._conn.sock:
|
| + self._conn.sock.settimeout(timeout)
|
| + else:
|
| + self._conn.timeout = timeout
|
| +
|
| try:
|
| - proxy_handler = urllib2.ProxyHandler({}) # Bypass any system proxy.
|
| - opener = urllib2.build_opener(proxy_handler)
|
| - with contextlib.closing(opener.open(url, timeout=timeout)) as req:
|
| - return req.read()
|
| - except urllib2.URLError as e:
|
| - raise DevToolsClientUrlError(e)
|
| - except (socket.error, httplib.BadStatusLine) as e:
|
| - raise DevToolsClientConnectionError(e)
|
| + # By default, httplib avoids going through the default system proxy.
|
| + self._conn.request('GET', endpoint)
|
| + response = self._conn.getresponse()
|
| + return response.read()
|
| + except (socket.error, httplib.HTTPException) as e:
|
| + self.Disconnect()
|
| + if isinstance(e, socket.error) and e.errno == errno.ECONNREFUSED:
|
| + raise DevToolsClientUrlError, (e,), sys.exc_info()[2]
|
| + raise DevToolsClientConnectionError, (e,), sys.exc_info()[2]
|
|
|
| def RequestJson(self, path, timeout=30):
|
| """Sends a request and parse the response as JSON.
|
|
|