OLD | NEW |
---|---|
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
5 | 5 |
6 """Constrained Network Server. Serves files with supplied network constraints. | 6 """Constrained Network Server. Serves files with supplied network constraints. |
7 | 7 |
8 The CNS exposes a web based API allowing network constraints to be imposed on | 8 The CNS exposes a web based API allowing network constraints to be imposed on |
9 file serving. | 9 file serving. |
10 | 10 |
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
178 | 178 |
179 Args: | 179 Args: |
180 options: optparse based class returned by ParseArgs() | 180 options: optparse based class returned by ParseArgs() |
181 port_allocator: A port allocator instance. | 181 port_allocator: A port allocator instance. |
182 """ | 182 """ |
183 self._options = options | 183 self._options = options |
184 self._port_allocator = port_allocator | 184 self._port_allocator = port_allocator |
185 | 185 |
186 @cherrypy.expose | 186 @cherrypy.expose |
187 def ServeConstrained(self, f=None, bandwidth=None, latency=None, loss=None, | 187 def ServeConstrained(self, f=None, bandwidth=None, latency=None, loss=None, |
188 new_port=False): | 188 new_port=False, no_cache=False, **kwargs): |
189 """Serves the requested file with the requested constraints. | 189 """Serves the requested file with the requested constraints. |
190 | 190 |
191 Subsequent requests for the same constraints from the same IP will share the | 191 Subsequent requests for the same constraints from the same IP will share the |
192 previously created port unless new_port equals True. If no constraints | 192 previously created port unless new_port equals True. If no constraints |
193 are provided the file is served as is. | 193 are provided the file is served as is. |
194 | 194 |
195 Args: | 195 Args: |
196 f: path relative to http root of file to serve. | 196 f: path relative to http root of file to serve. |
197 bandwidth: maximum allowed bandwidth for the provided port (integer | 197 bandwidth: maximum allowed bandwidth for the provided port (integer |
198 in kbit/s). | 198 in kbit/s). |
199 latency: time to add to each packet (integer in ms). | 199 latency: time to add to each packet (integer in ms). |
200 loss: percentage of packets to drop (integer, 0-100). | 200 loss: percentage of packets to drop (integer, 0-100). |
201 new_port: whether to use a new port for this request or not. | 201 new_port: whether to use a new port for this request or not. |
202 no_cache: Set reponse's cache-control to no-cache. | |
202 """ | 203 """ |
203 cherrypy.log('Got request for %s, bandwidth=%s, latency=%s, loss=%s, ' | 204 cherrypy.log('Got request for %s, bandwidth=%s, latency=%s, loss=%s, ' |
204 'new_port=%s' % (f, bandwidth, latency, loss, new_port)) | 205 'new_port=%s' % (f, bandwidth, latency, loss, new_port)) |
206 if no_cache: | |
207 response = cherrypy.response | |
208 response.headers['Pragma'] = 'no-cache' | |
209 response.headers['Cache-Control'] = 'no-cache' | |
210 | |
shadi
2012/04/18 02:03:17
I do not use this yet since <video> caches anyway
| |
205 # CherryPy is a bit wonky at detecting parameters, so just make them all | 211 # CherryPy is a bit wonky at detecting parameters, so just make them all |
206 # optional and validate them ourselves. | 212 # optional and validate them ourselves. |
207 if not f: | 213 if not f: |
208 raise cherrypy.HTTPError(400, 'Invalid request. File must be specified.') | 214 raise cherrypy.HTTPError(400, 'Invalid request. File must be specified.') |
209 | 215 |
210 # Sanitize and check the path to prevent www-root escapes. | 216 # Sanitize and check the path to prevent www-root escapes. |
211 sanitized_path = os.path.abspath(os.path.join(self._options.www_root, f)) | 217 sanitized_path = os.path.abspath(os.path.join(self._options.www_root, f)) |
212 if not sanitized_path.startswith(self._options.www_root): | 218 if not sanitized_path.startswith(self._options.www_root): |
213 raise cherrypy.HTTPError(403, 'Invalid file requested.') | 219 raise cherrypy.HTTPError(403, 'Invalid file requested.') |
214 | 220 |
(...skipping 25 matching lines...) Expand all Loading... | |
240 loss=loss, new_port=new_port) | 246 loss=loss, new_port=new_port) |
241 end_time = time.time() | 247 end_time = time.time() |
242 | 248 |
243 if not constrained_port: | 249 if not constrained_port: |
244 raise cherrypy.HTTPError(503, 'Service unavailable. Out of ports.') | 250 raise cherrypy.HTTPError(503, 'Service unavailable. Out of ports.') |
245 | 251 |
246 cherrypy.log('Time to set up port %d = %ssec.' % | 252 cherrypy.log('Time to set up port %d = %ssec.' % |
247 (constrained_port, end_time - start_time)) | 253 (constrained_port, end_time - start_time)) |
248 | 254 |
249 # Build constrained URL. Only pass on the file parameter. | 255 # Build constrained URL. Only pass on the file parameter. |
250 constrained_url = '%s?f=%s' % ( | 256 constrained_url = '%s?f=%s&no_cache=%s' % ( |
251 cherrypy.url().replace( | 257 cherrypy.url().replace( |
252 ':%d' % self._options.port, ':%d' % constrained_port), | 258 ':%d' % self._options.port, ':%d' % constrained_port), |
253 f) | 259 f, |
260 no_cache) | |
254 | 261 |
255 # Redirect request to the constrained port. | 262 # Redirect request to the constrained port. |
256 cherrypy.lib.cptools.redirect(constrained_url, internal=False) | 263 cherrypy.lib.cptools.redirect(constrained_url, internal=False) |
257 | 264 |
258 def _ParseIntParameter(self, param, msg, check): | 265 def _ParseIntParameter(self, param, msg, check): |
259 """Returns integer value of param and verifies it satisfies the check. | 266 """Returns integer value of param and verifies it satisfies the check. |
260 | 267 |
261 Args: | 268 Args: |
262 param: Parameter name to check. | 269 param: Parameter name to check. |
263 msg: Message in error if raised. | 270 msg: Message in error if raised. |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
360 try: | 367 try: |
361 cherrypy.quickstart(ConstrainedNetworkServer(options, pa)) | 368 cherrypy.quickstart(ConstrainedNetworkServer(options, pa)) |
362 finally: | 369 finally: |
363 # Disable Ctrl-C handler to prevent interruption of cleanup. | 370 # Disable Ctrl-C handler to prevent interruption of cleanup. |
364 signal.signal(signal.SIGINT, lambda signal, frame: None) | 371 signal.signal(signal.SIGINT, lambda signal, frame: None) |
365 pa.Cleanup(options.interface, all_ports=True) | 372 pa.Cleanup(options.interface, all_ports=True) |
366 | 373 |
367 | 374 |
368 if __name__ == '__main__': | 375 if __name__ == '__main__': |
369 Main() | 376 Main() |
OLD | NEW |