Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright (c) 2011 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2011 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 """This is a simple HTTP/FTP/SYNC/TCP/UDP/ server used for testing Chrome. | 6 """This is a simple HTTP/FTP/SYNC/TCP/UDP/ server used for testing Chrome. |
| 7 | 7 |
| 8 It supports several test URLs, as specified by the handlers in TestPageHandler. | 8 It supports several test URLs, as specified by the handlers in TestPageHandler. |
| 9 By default, it listens on an ephemeral port and sends the port number back to | 9 By default, it listens on an ephemeral port and sends the port number back to |
| 10 the originating process over a pipe. The originating process can specify an | 10 the originating process over a pipe. The originating process can specify an |
| (...skipping 248 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 259 self.stop = False | 259 self.stop = False |
| 260 self.nonce_time = None | 260 self.nonce_time = None |
| 261 while not self.stop: | 261 while not self.stop: |
| 262 self.handle_request() | 262 self.handle_request() |
| 263 self.socket.close() | 263 self.socket.close() |
| 264 | 264 |
| 265 | 265 |
| 266 class BasePageHandler(BaseHTTPServer.BaseHTTPRequestHandler): | 266 class BasePageHandler(BaseHTTPServer.BaseHTTPRequestHandler): |
| 267 | 267 |
| 268 def __init__(self, request, client_address, socket_server, | 268 def __init__(self, request, client_address, socket_server, |
| 269 connect_handlers, get_handlers, post_handlers, put_handlers): | 269 connect_handlers, get_handlers, head_handlers, post_handlers, |
| 270 put_handlers): | |
| 270 self._connect_handlers = connect_handlers | 271 self._connect_handlers = connect_handlers |
| 271 self._get_handlers = get_handlers | 272 self._get_handlers = get_handlers |
| 273 self._head_handlers = head_handlers | |
| 272 self._post_handlers = post_handlers | 274 self._post_handlers = post_handlers |
| 273 self._put_handlers = put_handlers | 275 self._put_handlers = put_handlers |
| 274 BaseHTTPServer.BaseHTTPRequestHandler.__init__( | 276 BaseHTTPServer.BaseHTTPRequestHandler.__init__( |
| 275 self, request, client_address, socket_server) | 277 self, request, client_address, socket_server) |
| 276 | 278 |
| 277 def log_request(self, *args, **kwargs): | 279 def log_request(self, *args, **kwargs): |
| 278 # Disable request logging to declutter test log output. | 280 # Disable request logging to declutter test log output. |
| 279 pass | 281 pass |
| 280 | 282 |
| 281 def _ShouldHandleRequest(self, handler_name): | 283 def _ShouldHandleRequest(self, handler_name): |
| 282 """Determines if the path can be handled by the handler. | 284 """Determines if the path can be handled by the handler. |
| 283 | 285 |
| 284 We consider a handler valid if the path begins with the | 286 We consider a handler valid if the path begins with the |
| 285 handler name. It can optionally be followed by "?*", "/*". | 287 handler name. It can optionally be followed by "?*", "/*". |
| 286 """ | 288 """ |
| 287 | 289 |
| 288 pattern = re.compile('%s($|\?|/).*' % handler_name) | 290 pattern = re.compile('%s($|\?|/).*' % handler_name) |
| 289 return pattern.match(self.path) | 291 return pattern.match(self.path) |
| 290 | 292 |
| 291 def do_CONNECT(self): | 293 def do_CONNECT(self): |
| 292 for handler in self._connect_handlers: | 294 for handler in self._connect_handlers: |
| 293 if handler(): | 295 if handler(): |
| 294 return | 296 return |
| 295 | 297 |
| 296 def do_GET(self): | 298 def do_GET(self): |
| 297 for handler in self._get_handlers: | 299 for handler in self._get_handlers: |
| 298 if handler(): | 300 if handler(): |
| 299 return | 301 return |
| 300 | 302 |
| 303 def do_HEAD(self): | |
| 304 for handler in self._head_handlers: | |
| 305 if handler(): | |
| 306 return | |
| 307 | |
| 301 def do_POST(self): | 308 def do_POST(self): |
| 302 for handler in self._post_handlers: | 309 for handler in self._post_handlers: |
| 303 if handler(): | 310 if handler(): |
| 304 return | 311 return |
| 305 | 312 |
| 306 def do_PUT(self): | 313 def do_PUT(self): |
| 307 for handler in self._put_handlers: | 314 for handler in self._put_handlers: |
| 308 if handler(): | 315 if handler(): |
| 309 return | 316 return |
| 310 | 317 |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 344 self.ChunkedServerHandler, | 351 self.ChunkedServerHandler, |
| 345 self.ContentTypeHandler, | 352 self.ContentTypeHandler, |
| 346 self.NoContentHandler, | 353 self.NoContentHandler, |
| 347 self.ServerRedirectHandler, | 354 self.ServerRedirectHandler, |
| 348 self.ClientRedirectHandler, | 355 self.ClientRedirectHandler, |
| 349 self.MultipartHandler, | 356 self.MultipartHandler, |
| 350 self.MultipartSlowHandler, | 357 self.MultipartSlowHandler, |
| 351 self.DefaultResponseHandler] | 358 self.DefaultResponseHandler] |
| 352 post_handlers = [ | 359 post_handlers = [ |
| 353 self.EchoTitleHandler, | 360 self.EchoTitleHandler, |
| 354 self.EchoAllHandler, | |
| 355 self.EchoHandler, | 361 self.EchoHandler, |
| 356 self.DeviceManagementHandler] + get_handlers | 362 self.DeviceManagementHandler] + get_handlers |
| 357 put_handlers = [ | 363 put_handlers = [ |
| 358 self.EchoTitleHandler, | 364 self.EchoTitleHandler, |
| 359 self.EchoAllHandler, | |
| 360 self.EchoHandler] + get_handlers | 365 self.EchoHandler] + get_handlers |
| 366 head_handlers = [ | |
| 367 self.FileHandler, | |
| 368 self.DefaultHeadResponseHandler] | |
| 361 | 369 |
| 362 self._mime_types = { | 370 self._mime_types = { |
| 363 'crx' : 'application/x-chrome-extension', | 371 'crx' : 'application/x-chrome-extension', |
| 364 'exe' : 'application/octet-stream', | 372 'exe' : 'application/octet-stream', |
| 365 'gif': 'image/gif', | 373 'gif': 'image/gif', |
| 366 'jpeg' : 'image/jpeg', | 374 'jpeg' : 'image/jpeg', |
| 367 'jpg' : 'image/jpeg', | 375 'jpg' : 'image/jpeg', |
| 368 'pdf' : 'application/pdf', | 376 'pdf' : 'application/pdf', |
| 369 'xml' : 'text/xml' | 377 'xml' : 'text/xml' |
| 370 } | 378 } |
| 371 self._default_mime_type = 'text/html' | 379 self._default_mime_type = 'text/html' |
| 372 | 380 |
| 373 BasePageHandler.__init__(self, request, client_address, socket_server, | 381 BasePageHandler.__init__(self, request, client_address, socket_server, |
| 374 connect_handlers, get_handlers, post_handlers, | 382 connect_handlers, get_handlers, head_handlers, |
| 375 put_handlers) | 383 post_handlers, put_handlers) |
| 376 | 384 |
| 377 def GetMIMETypeFromName(self, file_name): | 385 def GetMIMETypeFromName(self, file_name): |
| 378 """Returns the mime type for the specified file_name. So far it only looks | 386 """Returns the mime type for the specified file_name. So far it only looks |
| 379 at the file extension.""" | 387 at the file extension.""" |
| 380 | 388 |
| 381 (shortname, extension) = os.path.splitext(file_name.split("?")[0]) | 389 (shortname, extension) = os.path.splitext(file_name.split("?")[0]) |
| 382 if len(extension) == 0: | 390 if len(extension) == 0: |
| 383 # no extension. | 391 # no extension. |
| 384 return self._default_mime_type | 392 return self._default_mime_type |
| 385 | 393 |
| (...skipping 551 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 937 data = data[start: end + 1] | 945 data = data[start: end + 1] |
| 938 else: | 946 else: |
| 939 self.send_response(200) | 947 self.send_response(200) |
| 940 | 948 |
| 941 self.send_header('Content-type', self.GetMIMETypeFromName(file_path)) | 949 self.send_header('Content-type', self.GetMIMETypeFromName(file_path)) |
| 942 self.send_header('Accept-Ranges', 'bytes') | 950 self.send_header('Accept-Ranges', 'bytes') |
| 943 self.send_header('Content-Length', len(data)) | 951 self.send_header('Content-Length', len(data)) |
| 944 self.send_header('ETag', '\'' + file_path + '\'') | 952 self.send_header('ETag', '\'' + file_path + '\'') |
| 945 self.end_headers() | 953 self.end_headers() |
| 946 | 954 |
| 947 self.wfile.write(data) | 955 if (self.command != 'HEAD'): |
| 956 self.wfile.write(data) | |
| 948 | 957 |
| 949 return True | 958 return True |
| 950 | 959 |
| 951 def SetCookieHandler(self): | 960 def SetCookieHandler(self): |
| 952 """This handler just sets a cookie, for testing cookie handling.""" | 961 """This handler just sets a cookie, for testing cookie handling.""" |
| 953 | 962 |
| 954 if not self._ShouldHandleRequest("/set-cookie"): | 963 if not self._ShouldHandleRequest("/set-cookie"): |
| 955 return False | 964 return False |
| 956 | 965 |
| 957 query_char = self.path.find('?') | 966 query_char = self.path.find('?') |
| (...skipping 386 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1344 return True | 1353 return True |
| 1345 | 1354 |
| 1346 def DefaultResponseHandler(self): | 1355 def DefaultResponseHandler(self): |
| 1347 """This is the catch-all response handler for requests that aren't handled | 1356 """This is the catch-all response handler for requests that aren't handled |
| 1348 by one of the special handlers above. | 1357 by one of the special handlers above. |
| 1349 Note that we specify the content-length as without it the https connection | 1358 Note that we specify the content-length as without it the https connection |
| 1350 is not closed properly (and the browser keeps expecting data).""" | 1359 is not closed properly (and the browser keeps expecting data).""" |
| 1351 | 1360 |
| 1352 contents = "Default response given for path: " + self.path | 1361 contents = "Default response given for path: " + self.path |
| 1353 self.send_response(200) | 1362 self.send_response(200) |
| 1354 self.send_header('Content-type', 'text/html') | 1363 self.send_header('Content-type', 'text/html') |
|
wtc
2011/10/31 23:02:51
Nit: capitalize "Type".
mmenke
2011/10/31 23:29:12
Done. Fixed a bunch of other cases of that, too.
| |
| 1355 self.send_header("Content-Length", len(contents)) | 1364 self.send_header("Content-Length", len(contents)) |
| 1356 self.end_headers() | 1365 self.end_headers() |
| 1357 self.wfile.write(contents) | 1366 self.wfile.write(contents) |
| 1358 return True | 1367 return True |
| 1359 | 1368 |
| 1369 def DefaultHeadResponseHandler(self): | |
| 1370 """This is the catch-all response handler for HEAD requests that aren't | |
| 1371 handled by one of the special handlers above.""" | |
| 1372 | |
| 1373 self.send_response(200) | |
| 1374 self.send_header('Content-Type', 'text/html') | |
| 1375 self.send_header('Content-Length', '0') | |
|
wtc
2011/10/31 23:02:51
An alternative to sending a Content-Length of 0 is
mmenke
2011/10/31 23:29:12
The last suggestion sounds like a good idea to me.
| |
| 1376 self.end_headers() | |
| 1377 return True | |
| 1378 | |
| 1360 def RedirectConnectHandler(self): | 1379 def RedirectConnectHandler(self): |
| 1361 """Sends a redirect to the CONNECT request for www.redirect.com. This | 1380 """Sends a redirect to the CONNECT request for www.redirect.com. This |
| 1362 response is not specified by the RFC, so the browser should not follow | 1381 response is not specified by the RFC, so the browser should not follow |
| 1363 the redirect.""" | 1382 the redirect.""" |
| 1364 | 1383 |
| 1365 if (self.path.find("www.redirect.com") < 0): | 1384 if (self.path.find("www.redirect.com") < 0): |
| 1366 return False | 1385 return False |
| 1367 | 1386 |
| 1368 dest = "http://www.destination.com/foo.js" | 1387 dest = "http://www.destination.com/foo.js" |
| 1369 | 1388 |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1456 self.ChromiumSyncSendNotificationOpHandler, | 1475 self.ChromiumSyncSendNotificationOpHandler, |
| 1457 self.ChromiumSyncBirthdayErrorOpHandler, | 1476 self.ChromiumSyncBirthdayErrorOpHandler, |
| 1458 self.ChromiumSyncTransientErrorOpHandler, | 1477 self.ChromiumSyncTransientErrorOpHandler, |
| 1459 self.ChromiumSyncSyncTabsOpHandler, | 1478 self.ChromiumSyncSyncTabsOpHandler, |
| 1460 self.ChromiumSyncErrorOpHandler, | 1479 self.ChromiumSyncErrorOpHandler, |
| 1461 self.ChromiumSyncCredHandler] | 1480 self.ChromiumSyncCredHandler] |
| 1462 | 1481 |
| 1463 post_handlers = [self.ChromiumSyncCommandHandler, | 1482 post_handlers = [self.ChromiumSyncCommandHandler, |
| 1464 self.ChromiumSyncTimeHandler] | 1483 self.ChromiumSyncTimeHandler] |
| 1465 BasePageHandler.__init__(self, request, client_address, | 1484 BasePageHandler.__init__(self, request, client_address, |
| 1466 sync_http_server, [], get_handlers, | 1485 sync_http_server, [], get_handlers, [], |
| 1467 post_handlers, []) | 1486 post_handlers, []) |
| 1468 | 1487 |
| 1469 | 1488 |
| 1470 def ChromiumSyncTimeHandler(self): | 1489 def ChromiumSyncTimeHandler(self): |
| 1471 """Handle Chromium sync .../time requests. | 1490 """Handle Chromium sync .../time requests. |
| 1472 | 1491 |
| 1473 The syncer sometimes checks server reachability by examining /time. | 1492 The syncer sometimes checks server reachability by examining /time. |
| 1474 """ | 1493 """ |
| 1475 test_name = "/chromiumsync/time" | 1494 test_name = "/chromiumsync/time" |
| 1476 if not self._ShouldHandleRequest(test_name): | 1495 if not self._ShouldHandleRequest(test_name): |
| (...skipping 438 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1915 'random key if none is specified on the command ' | 1934 'random key if none is specified on the command ' |
| 1916 'line.') | 1935 'line.') |
| 1917 option_parser.add_option('', '--policy-user', default='user@example.com', | 1936 option_parser.add_option('', '--policy-user', default='user@example.com', |
| 1918 dest='policy_user', | 1937 dest='policy_user', |
| 1919 help='Specify the user name the server should ' | 1938 help='Specify the user name the server should ' |
| 1920 'report back to the client as the user owning the ' | 1939 'report back to the client as the user owning the ' |
| 1921 'token used for making the policy request.') | 1940 'token used for making the policy request.') |
| 1922 options, args = option_parser.parse_args() | 1941 options, args = option_parser.parse_args() |
| 1923 | 1942 |
| 1924 sys.exit(main(options, args)) | 1943 sys.exit(main(options, args)) |
| OLD | NEW |