Call `gzip` in subprocess instead of gzipping in Python in http_server. Before: ``` $ time wget http://127.0.0.1:59993/spinning_cube.mojo (...) real 0m3.987s user 0m0.001s sys 0m0.017s ``` After: ``` $ time wget http://127.0.0.1:55035/spinning_cube.mojo (...) real 0m1.226s user 0m0.004s sys 0m0.014s ``` Fixes domokit/devtools#35. R=piotrt@google.com Review URL: https://codereview.chromium.org/1316443002 . Cr-Mirrored-From: https://github.com/domokit/mojo Cr-Mirrored-Commit: c1d55465d7c2ce8717b59677d08b430344c31dbd
diff --git a/devtoolslib/http_server.py b/devtoolslib/http_server.py index d8a2757..fe2be7a 100644 --- a/devtoolslib/http_server.py +++ b/devtoolslib/http_server.py
@@ -6,15 +6,14 @@ import datetime import email.utils import errno -import gzip import hashlib import logging import math import os.path -import shutil import socket -import threading +import subprocess import tempfile +import threading import SimpleHTTPServer import SocketServer @@ -37,6 +36,24 @@ _UTC = UTC_TZINFO() +def _gzip(file_path): + """Gzips the given file storing the result in a temporary file. + + Returns: + Path to the resulting file. + """ + gzipped_file = tempfile.NamedTemporaryFile(delete=False) + try: + subprocess.check_call(['gzip', '-c', file_path], + stdout=gzipped_file) + except Exception: + print ('http_server: call to gzip failed, make sure that ' + 'gzip is installed on the host.') + raise + gzipped_file.close() + return gzipped_file.name + + class _SilentTCPServer(SocketServer.TCPServer): """A TCPServer that won't display any error, unless debugging is enabled. This is useful because the client might stop while it is fetching an URL, which @@ -73,7 +90,7 @@ def __init__(self, *args, **kwargs): self.etag = None - self.gzipped_file = None + self.gzipped_file_name = None self.original_file_name = None SimpleHTTPServer.SimpleHTTPRequestHandler.__init__(self, *args, **kwargs) @@ -138,7 +155,7 @@ return SimpleHTTPServer.SimpleHTTPRequestHandler.end_headers(self) # pylint: disable=W0221 - def translate_path(self, path, gzipped=True): + def translate_path(self, path, gzip=True): # Parent translate_path() will strip away the query string and fragment # identifier, but also will prepend the cwd to the path. relpath() gives # us the relative path back. @@ -146,24 +163,22 @@ SimpleHTTPServer.SimpleHTTPRequestHandler.translate_path(self, path)) for prefix, local_base_path_list in mappings: - if normalized_path.startswith(prefix): - for local_base_path in local_base_path_list: - candidate = os.path.join(local_base_path, - normalized_path[len(prefix):]) - if os.path.isfile(candidate): - if gzipped: - if not self.gzipped_file: - self.gzipped_file = tempfile.NamedTemporaryFile(delete=False) - self.original_file_name = candidate - with open(candidate, 'rb') as source: - with gzip.GzipFile(fileobj=self.gzipped_file) as target: - shutil.copyfileobj(source, target) - self.gzipped_file.close() - return self.gzipped_file.name - return candidate - else: - self.send_response(404) - return None + if not normalized_path.startswith(prefix): + continue + + for local_base_path in local_base_path_list: + candidate = os.path.join(local_base_path, + normalized_path[len(prefix):]) + if os.path.isfile(candidate): + if gzip: + if not self.gzipped_file_name: + self.original_file_name = candidate + self.gzipped_file_name = _gzip(candidate) + return self.gzipped_file_name + return candidate + else: + self.send_response(404) + return None self.send_response(404) return None @@ -184,8 +199,8 @@ pass def __del__(self): - if self.gzipped_file: - os.remove(self.gzipped_file.name) + if self.gzipped_file_name: + os.remove(self.gzipped_file_name) RequestHandler.protocol_version = 'HTTP/1.1' return RequestHandler
diff --git a/devtoolslib/shell_arguments.py b/devtoolslib/shell_arguments.py index f479248..53e467f 100644 --- a/devtoolslib/shell_arguments.py +++ b/devtoolslib/shell_arguments.py
@@ -159,7 +159,8 @@ """ server_url = shell.serve_local_directories(dev_server_config.mappings) shell_args.append('--map-origin=%s=%s' % (dev_server_config.host, server_url)) - print "Configured %s locally to serve:" % (dev_server_config.host) + print "Configured %s locally at %s to serve:" % (dev_server_config.host, + server_url) for mapping_prefix, mapping_path in dev_server_config.mappings: print " /%s -> %s" % (mapping_prefix, mapping_path) return shell_args