Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(167)

Side by Side Diff: mojo/devtools/common/devtoolslib/http_server.py

Issue 1316443002: Call `gzip` in subprocess instead of gzipping in Python in http_server. (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Address Piotr's comments. Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | mojo/devtools/common/devtoolslib/shell_arguments.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # Copyright 2015 The Chromium Authors. All rights reserved. 1 # Copyright 2015 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 import atexit 5 import atexit
6 import datetime 6 import datetime
7 import email.utils 7 import email.utils
8 import errno 8 import errno
9 import gzip
10 import hashlib 9 import hashlib
11 import logging 10 import logging
12 import math 11 import math
13 import os.path 12 import os.path
14 import shutil
15 import socket 13 import socket
14 import subprocess
15 import tempfile
16 import threading 16 import threading
17 import tempfile
18 17
19 import SimpleHTTPServer 18 import SimpleHTTPServer
20 import SocketServer 19 import SocketServer
21 20
22 _ZERO = datetime.timedelta(0) 21 _ZERO = datetime.timedelta(0)
23 22
24 23
25 class UTC_TZINFO(datetime.tzinfo): 24 class UTC_TZINFO(datetime.tzinfo):
26 """UTC time zone representation.""" 25 """UTC time zone representation."""
27 26
28 def utcoffset(self, _): 27 def utcoffset(self, _):
29 return _ZERO 28 return _ZERO
30 29
31 def tzname(self, _): 30 def tzname(self, _):
32 return "UTC" 31 return "UTC"
33 32
34 def dst(self, _): 33 def dst(self, _):
35 return _ZERO 34 return _ZERO
36 35
37 _UTC = UTC_TZINFO() 36 _UTC = UTC_TZINFO()
38 37
39 38
39 def _gzip(file_path):
40 """Gzips the given file storing the result in a temporary file.
41
42 Returns:
43 Path to the resulting file.
44 """
45 gzipped_file = tempfile.NamedTemporaryFile(delete=False)
46 try:
47 subprocess.check_call(['gzip', '-c', file_path],
48 stdout=gzipped_file)
49 except Exception:
50 print ('http_server: call to gzip failed, make sure that '
51 'gzip is installed on the host.')
52 raise
53 gzipped_file.close()
54 return gzipped_file.name
55
56
40 class _SilentTCPServer(SocketServer.TCPServer): 57 class _SilentTCPServer(SocketServer.TCPServer):
41 """A TCPServer that won't display any error, unless debugging is enabled. This 58 """A TCPServer that won't display any error, unless debugging is enabled. This
42 is useful because the client might stop while it is fetching an URL, which 59 is useful because the client might stop while it is fetching an URL, which
43 causes spurious error messages. 60 causes spurious error messages.
44 """ 61 """
45 allow_reuse_address = True 62 allow_reuse_address = True
46 63
47 def handle_error(self, request, client_address): 64 def handle_error(self, request, client_address):
48 """Override the base class method to have conditional logging.""" 65 """Override the base class method to have conditional logging."""
49 if logging.getLogger().isEnabledFor(logging.DEBUG): 66 if logging.getLogger().isEnabledFor(logging.DEBUG):
(...skipping 16 matching lines...) Expand all
66 83
67 class RequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): 84 class RequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
68 """Handler for SocketServer.TCPServer that will serve the files from 85 """Handler for SocketServer.TCPServer that will serve the files from
69 local directiories over http. 86 local directiories over http.
70 87
71 A new instance is created for each request. 88 A new instance is created for each request.
72 """ 89 """
73 90
74 def __init__(self, *args, **kwargs): 91 def __init__(self, *args, **kwargs):
75 self.etag = None 92 self.etag = None
76 self.gzipped_file = None 93 self.gzipped_file_name = None
77 self.original_file_name = None 94 self.original_file_name = None
78 SimpleHTTPServer.SimpleHTTPRequestHandler.__init__(self, *args, **kwargs) 95 SimpleHTTPServer.SimpleHTTPRequestHandler.__init__(self, *args, **kwargs)
79 96
80 def get_etag(self): 97 def get_etag(self):
81 if self.etag: 98 if self.etag:
82 return self.etag 99 return self.etag
83 100
84 path = self.translate_path(self.path, False) 101 path = self.translate_path(self.path, False)
85 if not os.path.isfile(path): 102 if not os.path.isfile(path):
86 return None 103 return None
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
131 if os.path.isfile(path): 148 if os.path.isfile(path):
132 self.send_header('Content-Encoding', 'gzip') 149 self.send_header('Content-Encoding', 'gzip')
133 etag = self.get_etag() 150 etag = self.get_etag()
134 if etag: 151 if etag:
135 self.send_header('ETag', etag) 152 self.send_header('ETag', etag)
136 self.send_header('Cache-Control', 'must-revalidate') 153 self.send_header('Cache-Control', 'must-revalidate')
137 154
138 return SimpleHTTPServer.SimpleHTTPRequestHandler.end_headers(self) 155 return SimpleHTTPServer.SimpleHTTPRequestHandler.end_headers(self)
139 156
140 # pylint: disable=W0221 157 # pylint: disable=W0221
141 def translate_path(self, path, gzipped=True): 158 def translate_path(self, path, gzip=True):
142 # Parent translate_path() will strip away the query string and fragment 159 # Parent translate_path() will strip away the query string and fragment
143 # identifier, but also will prepend the cwd to the path. relpath() gives 160 # identifier, but also will prepend the cwd to the path. relpath() gives
144 # us the relative path back. 161 # us the relative path back.
145 normalized_path = os.path.relpath( 162 normalized_path = os.path.relpath(
146 SimpleHTTPServer.SimpleHTTPRequestHandler.translate_path(self, path)) 163 SimpleHTTPServer.SimpleHTTPRequestHandler.translate_path(self, path))
147 164
148 for prefix, local_base_path_list in mappings: 165 for prefix, local_base_path_list in mappings:
149 if normalized_path.startswith(prefix): 166 if not normalized_path.startswith(prefix):
150 for local_base_path in local_base_path_list: 167 continue
151 candidate = os.path.join(local_base_path, 168
152 normalized_path[len(prefix):]) 169 for local_base_path in local_base_path_list:
153 if os.path.isfile(candidate): 170 candidate = os.path.join(local_base_path,
154 if gzipped: 171 normalized_path[len(prefix):])
155 if not self.gzipped_file: 172 if os.path.isfile(candidate):
156 self.gzipped_file = tempfile.NamedTemporaryFile(delete=False) 173 if gzip:
157 self.original_file_name = candidate 174 if not self.gzipped_file_name:
158 with open(candidate, 'rb') as source: 175 self.original_file_name = candidate
159 with gzip.GzipFile(fileobj=self.gzipped_file) as target: 176 self.gzipped_file_name = _gzip(candidate)
160 shutil.copyfileobj(source, target) 177 return self.gzipped_file_name
161 self.gzipped_file.close() 178 return candidate
162 return self.gzipped_file.name 179 else:
163 return candidate 180 self.send_response(404)
164 else: 181 return None
165 self.send_response(404)
166 return None
167 self.send_response(404) 182 self.send_response(404)
168 return None 183 return None
169 184
170 def guess_type(self, path): 185 def guess_type(self, path):
171 # This is needed so that exploded Sky apps without shebang can still run 186 # This is needed so that exploded Sky apps without shebang can still run
172 # thanks to content-type mappings. 187 # thanks to content-type mappings.
173 # TODO(ppi): drop this part once we can rely on the Sky files declaring 188 # TODO(ppi): drop this part once we can rely on the Sky files declaring
174 # correct shebang. 189 # correct shebang.
175 actual_path = self.original_file_name or path 190 actual_path = self.original_file_name or path
176 191
177 if actual_path.endswith('.dart'): 192 if actual_path.endswith('.dart'):
178 return 'application/dart' 193 return 'application/dart'
179 return SimpleHTTPServer.SimpleHTTPRequestHandler.guess_type(self, 194 return SimpleHTTPServer.SimpleHTTPRequestHandler.guess_type(self,
180 actual_path) 195 actual_path)
181 196
182 def log_message(self, *_): 197 def log_message(self, *_):
183 """Override the base class method to disable logging.""" 198 """Override the base class method to disable logging."""
184 pass 199 pass
185 200
186 def __del__(self): 201 def __del__(self):
187 if self.gzipped_file: 202 if self.gzipped_file_name:
188 os.remove(self.gzipped_file.name) 203 os.remove(self.gzipped_file_name)
189 204
190 RequestHandler.protocol_version = 'HTTP/1.1' 205 RequestHandler.protocol_version = 'HTTP/1.1'
191 return RequestHandler 206 return RequestHandler
192 207
193 208
194 def start_http_server(mappings, host_port=0): 209 def start_http_server(mappings, host_port=0):
195 """Starts an http server serving files from |local_dir_path| on |host_port|. 210 """Starts an http server serving files from |local_dir_path| on |host_port|.
196 211
197 Args: 212 Args:
198 mappings: List of tuples (prefix, local_base_path_list) mapping URLs that 213 mappings: List of tuples (prefix, local_base_path_list) mapping URLs that
(...skipping 21 matching lines...) Expand all
220 except socket.error as v: 235 except socket.error as v:
221 error_code = v[0] 236 error_code = v[0]
222 print 'Failed to start http server for %s on port %d: %s.' % ( 237 print 'Failed to start http server for %s on port %d: %s.' % (
223 str(mappings), host_port, os.strerror(error_code)) 238 str(mappings), host_port, os.strerror(error_code))
224 if error_code == errno.EADDRINUSE: 239 if error_code == errno.EADDRINUSE:
225 print (' Run `fuser %d/tcp` to find out which process is using the port;' 240 print (' Run `fuser %d/tcp` to find out which process is using the port;'
226 % host_port) 241 % host_port)
227 print (' or `fuser -k %d/tcp` terminate it.' % host_port) 242 print (' or `fuser -k %d/tcp` terminate it.' % host_port)
228 print '---' 243 print '---'
229 raise 244 raise
OLDNEW
« no previous file with comments | « no previous file | mojo/devtools/common/devtoolslib/shell_arguments.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698