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, post_handlers, put_handlers, |
270 head_handlers): | |
wtc
2011/10/31 19:21:00
Nit: list 'head_handlers' and 'do_HEAD' in alphabe
mmenke
2011/10/31 20:46:40
Done.
| |
270 self._connect_handlers = connect_handlers | 271 self._connect_handlers = connect_handlers |
271 self._get_handlers = get_handlers | 272 self._get_handlers = get_handlers |
272 self._post_handlers = post_handlers | 273 self._post_handlers = post_handlers |
273 self._put_handlers = put_handlers | 274 self._put_handlers = put_handlers |
275 self._head_handlers = head_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 |
(...skipping 17 matching lines...) Expand all Loading... | |
301 def do_POST(self): | 303 def do_POST(self): |
302 for handler in self._post_handlers: | 304 for handler in self._post_handlers: |
303 if handler(): | 305 if handler(): |
304 return | 306 return |
305 | 307 |
306 def do_PUT(self): | 308 def do_PUT(self): |
307 for handler in self._put_handlers: | 309 for handler in self._put_handlers: |
308 if handler(): | 310 if handler(): |
309 return | 311 return |
310 | 312 |
313 def do_HEAD(self): | |
314 for handler in self._head_handlers: | |
315 if handler(): | |
316 return | |
317 | |
311 | 318 |
312 class TestPageHandler(BasePageHandler): | 319 class TestPageHandler(BasePageHandler): |
313 | 320 |
314 def __init__(self, request, client_address, socket_server): | 321 def __init__(self, request, client_address, socket_server): |
315 connect_handlers = [ | 322 connect_handlers = [ |
316 self.RedirectConnectHandler, | 323 self.RedirectConnectHandler, |
317 self.ServerAuthConnectHandler, | 324 self.ServerAuthConnectHandler, |
318 self.DefaultConnectResponseHandler] | 325 self.DefaultConnectResponseHandler] |
319 get_handlers = [ | 326 get_handlers = [ |
320 self.NoCacheMaxAgeTimeHandler, | 327 self.NoCacheMaxAgeTimeHandler, |
(...skipping 23 matching lines...) Expand all 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, | |
wtc
2011/10/31 19:21:00
Why did you remove self.EchoAllHandler from post_h
mmenke
2011/10/31 20:46:40
It's in get_handlers already, so there's no reason
| |
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, post_handlers, |
375 put_handlers) | 383 put_handlers, head_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 501 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
887 entries = sub_path.split('/') | 895 entries = sub_path.split('/') |
888 file_path = os.path.join(self.server.data_dir, *entries) | 896 file_path = os.path.join(self.server.data_dir, *entries) |
889 if os.path.isdir(file_path): | 897 if os.path.isdir(file_path): |
890 file_path = os.path.join(file_path, 'index.html') | 898 file_path = os.path.join(file_path, 'index.html') |
891 | 899 |
892 if not os.path.isfile(file_path): | 900 if not os.path.isfile(file_path): |
893 print "File not found " + sub_path + " full path:" + file_path | 901 print "File not found " + sub_path + " full path:" + file_path |
894 self.send_error(404) | 902 self.send_error(404) |
895 return True | 903 return True |
896 | 904 |
897 f = open(file_path, "rb") | 905 data = ''; |
898 data = f.read() | 906 if (self.command != 'HEAD'): |
899 f.close() | 907 f = open(file_path, "rb") |
908 data = f.read() | |
909 f.close() | |
900 | 910 |
901 data = self._ReplaceFileData(data, query) | 911 data = self._ReplaceFileData(data, query) |
wtc
2011/10/31 19:21:00
Just wanted to confirm that this statement should
mmenke
2011/10/31 20:46:40
It didn't matter, either way. Removed the if stat
| |
902 | 912 |
903 # If file.mock-http-headers exists, it contains the headers we | 913 # If file.mock-http-headers exists, it contains the headers we |
904 # should send. Read them in and parse them. | 914 # should send. Read them in and parse them. |
905 headers_path = file_path + '.mock-http-headers' | 915 headers_path = file_path + '.mock-http-headers' |
906 if os.path.isfile(headers_path): | 916 if os.path.isfile(headers_path): |
907 f = open(headers_path, "r") | 917 f = open(headers_path, "r") |
908 | 918 |
909 # "HTTP/1.1 200 OK" | 919 # "HTTP/1.1 200 OK" |
910 response = f.readline() | 920 response = f.readline() |
911 status_code = re.findall('HTTP/\d+.\d+ (\d+)', response)[0] | 921 status_code = re.findall('HTTP/\d+.\d+ (\d+)', response)[0] |
(...skipping 21 matching lines...) Expand all Loading... | |
933 self.send_response(206) | 943 self.send_response(206) |
934 content_range = 'bytes ' + str(start) + '-' + str(end) + '/' + \ | 944 content_range = 'bytes ' + str(start) + '-' + str(end) + '/' + \ |
935 str(len(data)) | 945 str(len(data)) |
936 self.send_header('Content-Range', content_range) | 946 self.send_header('Content-Range', content_range) |
937 data = data[start: end + 1] | 947 data = data[start: end + 1] |
938 else: | 948 else: |
939 self.send_response(200) | 949 self.send_response(200) |
940 | 950 |
941 self.send_header('Content-type', self.GetMIMETypeFromName(file_path)) | 951 self.send_header('Content-type', self.GetMIMETypeFromName(file_path)) |
942 self.send_header('Accept-Ranges', 'bytes') | 952 self.send_header('Accept-Ranges', 'bytes') |
943 self.send_header('Content-Length', len(data)) | 953 if (self.command != 'HEAD'): |
954 self.send_header('Content-Length', len(data)) | |
wtc
2011/10/31 19:21:00
Just curious: are HEAD responses forbidden to have
wtc
2011/10/31 19:59:41
julian.reschke: thank you for the reply.
mmenke:
mmenke
2011/10/31 20:46:40
Done. You're right. I misread the RFC.
| |
944 self.send_header('ETag', '\'' + file_path + '\'') | 955 self.send_header('ETag', '\'' + file_path + '\'') |
945 self.end_headers() | 956 self.end_headers() |
946 | 957 |
947 self.wfile.write(data) | 958 self.wfile.write(data) |
948 | 959 |
949 return True | 960 return True |
950 | 961 |
951 def SetCookieHandler(self): | 962 def SetCookieHandler(self): |
952 """This handler just sets a cookie, for testing cookie handling.""" | 963 """This handler just sets a cookie, for testing cookie handling.""" |
953 | 964 |
(...skipping 396 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1350 is not closed properly (and the browser keeps expecting data).""" | 1361 is not closed properly (and the browser keeps expecting data).""" |
1351 | 1362 |
1352 contents = "Default response given for path: " + self.path | 1363 contents = "Default response given for path: " + self.path |
1353 self.send_response(200) | 1364 self.send_response(200) |
1354 self.send_header('Content-type', 'text/html') | 1365 self.send_header('Content-type', 'text/html') |
1355 self.send_header("Content-Length", len(contents)) | 1366 self.send_header("Content-Length", len(contents)) |
1356 self.end_headers() | 1367 self.end_headers() |
1357 self.wfile.write(contents) | 1368 self.wfile.write(contents) |
1358 return True | 1369 return True |
1359 | 1370 |
1371 def DefaultHeadResponseHandler(self): | |
1372 """This is the catch-all response handler for head requests that aren't | |
wtc
2011/10/31 19:21:00
Capitalize "HEAD".
mmenke
2011/10/31 20:46:40
Done.
| |
1373 handled by one of the special handlers above.""" | |
1374 | |
1375 self.send_response(200) | |
1376 self.send_header('Content-type', 'text/html') | |
wtc
2011/10/31 19:21:00
Since there is no |contents|, it seems that we sho
mmenke
2011/10/31 20:46:40
Not done (As per spec - "The Content-Type entity-h
mmenke
2011/10/31 20:49:25
On second thought, you're right, with a 0 content-
mmenke
2011/10/31 20:52:14
Or maybe not? Honestly, I have no idea. Suppose
| |
1377 self.end_headers() | |
1378 return True | |
1379 | |
1360 def RedirectConnectHandler(self): | 1380 def RedirectConnectHandler(self): |
1361 """Sends a redirect to the CONNECT request for www.redirect.com. This | 1381 """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 | 1382 response is not specified by the RFC, so the browser should not follow |
1363 the redirect.""" | 1383 the redirect.""" |
1364 | 1384 |
1365 if (self.path.find("www.redirect.com") < 0): | 1385 if (self.path.find("www.redirect.com") < 0): |
1366 return False | 1386 return False |
1367 | 1387 |
1368 dest = "http://www.destination.com/foo.js" | 1388 dest = "http://www.destination.com/foo.js" |
1369 | 1389 |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1457 self.ChromiumSyncBirthdayErrorOpHandler, | 1477 self.ChromiumSyncBirthdayErrorOpHandler, |
1458 self.ChromiumSyncTransientErrorOpHandler, | 1478 self.ChromiumSyncTransientErrorOpHandler, |
1459 self.ChromiumSyncSyncTabsOpHandler, | 1479 self.ChromiumSyncSyncTabsOpHandler, |
1460 self.ChromiumSyncErrorOpHandler, | 1480 self.ChromiumSyncErrorOpHandler, |
1461 self.ChromiumSyncCredHandler] | 1481 self.ChromiumSyncCredHandler] |
1462 | 1482 |
1463 post_handlers = [self.ChromiumSyncCommandHandler, | 1483 post_handlers = [self.ChromiumSyncCommandHandler, |
1464 self.ChromiumSyncTimeHandler] | 1484 self.ChromiumSyncTimeHandler] |
1465 BasePageHandler.__init__(self, request, client_address, | 1485 BasePageHandler.__init__(self, request, client_address, |
1466 sync_http_server, [], get_handlers, | 1486 sync_http_server, [], get_handlers, |
1467 post_handlers, []) | 1487 post_handlers, [], []) |
1468 | 1488 |
1469 | 1489 |
1470 def ChromiumSyncTimeHandler(self): | 1490 def ChromiumSyncTimeHandler(self): |
1471 """Handle Chromium sync .../time requests. | 1491 """Handle Chromium sync .../time requests. |
1472 | 1492 |
1473 The syncer sometimes checks server reachability by examining /time. | 1493 The syncer sometimes checks server reachability by examining /time. |
1474 """ | 1494 """ |
1475 test_name = "/chromiumsync/time" | 1495 test_name = "/chromiumsync/time" |
1476 if not self._ShouldHandleRequest(test_name): | 1496 if not self._ShouldHandleRequest(test_name): |
1477 return False | 1497 return False |
(...skipping 437 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1915 'random key if none is specified on the command ' | 1935 'random key if none is specified on the command ' |
1916 'line.') | 1936 'line.') |
1917 option_parser.add_option('', '--policy-user', default='user@example.com', | 1937 option_parser.add_option('', '--policy-user', default='user@example.com', |
1918 dest='policy_user', | 1938 dest='policy_user', |
1919 help='Specify the user name the server should ' | 1939 help='Specify the user name the server should ' |
1920 'report back to the client as the user owning the ' | 1940 'report back to the client as the user owning the ' |
1921 'token used for making the policy request.') | 1941 'token used for making the policy request.') |
1922 options, args = option_parser.parse_args() | 1942 options, args = option_parser.parse_args() |
1923 | 1943 |
1924 sys.exit(main(options, args)) | 1944 sys.exit(main(options, args)) |
OLD | NEW |