Chromium Code Reviews| 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 """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 10 matching lines...) Expand all Loading... | |
| 21 import hashlib | 21 import hashlib |
| 22 import json | 22 import json |
| 23 import logging | 23 import logging |
| 24 import minica | 24 import minica |
| 25 import os | 25 import os |
| 26 import random | 26 import random |
| 27 import re | 27 import re |
| 28 import select | 28 import select |
| 29 import socket | 29 import socket |
| 30 import SocketServer | 30 import SocketServer |
| 31 import struct | |
| 31 import sys | 32 import sys |
| 32 import threading | 33 import threading |
| 33 import time | 34 import time |
| 34 import urllib | 35 import urllib |
| 35 import urlparse | 36 import urlparse |
| 36 import zlib | 37 import zlib |
| 37 | 38 |
| 38 import echo_message | 39 import echo_message |
| 39 import pyftpdlib.ftpserver | 40 import pyftpdlib.ftpserver |
| 40 import testserver_base | 41 import testserver_base |
| (...skipping 425 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 466 self.SlowServerHandler, | 467 self.SlowServerHandler, |
| 467 self.ChunkedServerHandler, | 468 self.ChunkedServerHandler, |
| 468 self.ContentTypeHandler, | 469 self.ContentTypeHandler, |
| 469 self.NoContentHandler, | 470 self.NoContentHandler, |
| 470 self.ServerRedirectHandler, | 471 self.ServerRedirectHandler, |
| 471 self.ClientRedirectHandler, | 472 self.ClientRedirectHandler, |
| 472 self.MultipartHandler, | 473 self.MultipartHandler, |
| 473 self.MultipartSlowHandler, | 474 self.MultipartSlowHandler, |
| 474 self.GetSSLSessionCacheHandler, | 475 self.GetSSLSessionCacheHandler, |
| 475 self.CloseSocketHandler, | 476 self.CloseSocketHandler, |
| 477 self.RangeResetHandler, | |
| 476 self.DefaultResponseHandler] | 478 self.DefaultResponseHandler] |
| 477 post_handlers = [ | 479 post_handlers = [ |
| 478 self.EchoTitleHandler, | 480 self.EchoTitleHandler, |
| 479 self.EchoHandler, | 481 self.EchoHandler, |
| 480 self.DeviceManagementHandler, | 482 self.DeviceManagementHandler, |
| 481 self.PostOnlyFileHandler] + get_handlers | 483 self.PostOnlyFileHandler] + get_handlers |
| 482 put_handlers = [ | 484 put_handlers = [ |
| 483 self.EchoTitleHandler, | 485 self.EchoTitleHandler, |
| 484 self.EchoHandler] + get_handlers | 486 self.EchoHandler] + get_handlers |
| 485 head_handlers = [ | 487 head_handlers = [ |
| (...skipping 1128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1614 | 1616 |
| 1615 def CloseSocketHandler(self): | 1617 def CloseSocketHandler(self): |
| 1616 """Closes the socket without sending anything.""" | 1618 """Closes the socket without sending anything.""" |
| 1617 | 1619 |
| 1618 if not self._ShouldHandleRequest('/close-socket'): | 1620 if not self._ShouldHandleRequest('/close-socket'): |
| 1619 return False | 1621 return False |
| 1620 | 1622 |
| 1621 self.wfile.close() | 1623 self.wfile.close() |
| 1622 return True | 1624 return True |
| 1623 | 1625 |
| 1626 def RangeResetHandler(self): | |
| 1627 """Send data broken up by connection resets every N (default 10K) bytes. | |
| 1628 Support range requests. If the data requested doesn't straddle a reset | |
| 1629 boundary, it will all be sent. Used for testing resuming downloads.""" | |
| 1630 | |
| 1631 if not self._ShouldHandleRequest('/rangereset'): | |
| 1632 return False | |
| 1633 | |
| 1634 _, _, url_path, _, query, _ = urlparse.urlparse(self.path) | |
| 1635 | |
| 1636 # Defaults | |
| 1637 size = 15000 | |
| 1638 # Note that the rst is sent just before sending the rst_boundary byte. | |
| 1639 rst_boundary = 10000 | |
| 1640 respond_to_range = True | |
| 1641 hold_for_signal = False | |
| 1642 | |
| 1643 # Parse the query | |
| 1644 if query: | |
| 1645 for ele in query.split('&'): | |
|
Paweł Hajdan Jr.
2013/01/04 22:56:58
Are you doing query string parsing here? Please us
Randy Smith (Not in Mondays)
2013/01/07 20:54:10
Whoops. Very good point. Done.
| |
| 1646 namevalue = ele.split('=') | |
| 1647 name = namevalue[0] | |
| 1648 value = namevalue[1] if len(namevalue) == 2 else None | |
| 1649 if name == 'size': | |
| 1650 size = int(val) | |
| 1651 elif name == 'rst_boundary': | |
| 1652 rst_boundary = int(val) | |
| 1653 elif name == 'bounce_range': | |
| 1654 respond_to_range = False | |
| 1655 elif name == 'hold': | |
| 1656 hold_for_signal = True | |
| 1657 else: | |
| 1658 return False | |
| 1659 | |
| 1660 first_byte = 0 | |
| 1661 last_byte = size - 1 | |
| 1662 | |
| 1663 # Does that define what we want to return, or do we need to apply | |
| 1664 # a range? | |
| 1665 range_response = False | |
| 1666 range_header = self.headers.getheader('range') | |
| 1667 if range_header and respond_to_range: | |
| 1668 mo = re.match("bytes=([0-9]*)-([0-9]*)", range_header) | |
|
Paweł Hajdan Jr.
2013/01/04 22:56:58
nit: Why not \d for the digits?
Randy Smith (Not in Mondays)
2013/01/07 20:54:10
Too much time using emacs regexps + hammering in a
| |
| 1669 if mo.group(1): | |
| 1670 first_byte = int(mo.group(1)) | |
| 1671 if mo.group(2): | |
| 1672 last_byte = int(mo.group(2)) | |
| 1673 if last_byte > size - 1: | |
| 1674 last_byte = size - 1 | |
| 1675 range_response = True | |
| 1676 if last_byte < first_byte: | |
| 1677 return False | |
| 1678 | |
| 1679 if not range_response: | |
|
Paweł Hajdan Jr.
2013/01/04 22:56:58
nit: Reverse the order - put if range_response bra
Randy Smith (Not in Mondays)
2013/01/07 20:54:10
Done.
| |
| 1680 self.send_response(200) | |
| 1681 else: | |
| 1682 self.send_response(206) | |
| 1683 self.send_header('Content-Range', | |
| 1684 'bytes %d-%d/%d' % (first_byte, last_byte, size)) | |
| 1685 self.send_header('Content-Type', 'application/octet-stream') | |
| 1686 self.send_header('Content-Length', last_byte - first_byte + 1) | |
| 1687 self.end_headers() | |
| 1688 | |
| 1689 if hold_for_signal: | |
| 1690 ## Needed to allow server to handle new requests (weird). | |
|
Paweł Hajdan Jr.
2013/01/04 22:56:58
nit: No double # please, and what is really going
Randy Smith (Not in Mondays)
2013/01/07 20:54:10
I've updated the comment; let me know if you want
| |
| 1691 self.wfile.write('X') | |
| 1692 first_byte = first_byte + 1 | |
| 1693 # handle requests until one of them clears this flag. | |
| 1694 self.server.waitForDownload = True | |
| 1695 while self.server.waitForDownload: | |
| 1696 self.server.handle_request() | |
| 1697 | |
| 1698 possible_rst = ((first_byte / rst_boundary) + 1) * rst_boundary | |
| 1699 if possible_rst < last_byte: | |
| 1700 ## We're resetting the conneciton part way in. | |
|
Paweł Hajdan Jr.
2013/01/04 22:56:58
nit: No double #.
benjhayden
2013/01/06 15:46:04
connecTIon
Randy Smith (Not in Mondays)
2013/01/07 20:54:10
Done.
Randy Smith (Not in Mondays)
2013/01/07 20:54:10
Done.
| |
| 1701 self.wfile.write('X' * (possible_rst - first_byte)) | |
| 1702 s = self.connection # This is the request socket. | |
|
Paweł Hajdan Jr.
2013/01/04 22:56:58
nit: Make the comment more meaningful. What is thi
Randy Smith (Not in Mondays)
2013/01/07 20:54:10
Done.
| |
| 1703 l_onoff = 1 # Linger is active. | |
| 1704 l_linger = 0 # Seconds to linger for. | |
| 1705 s.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, | |
| 1706 struct.pack('ii', l_onoff, l_linger)) | |
| 1707 s.close() | |
| 1708 time.sleep(0.05) # Give time to the system. | |
|
Paweł Hajdan Jr.
2013/01/04 22:56:58
Huh? That makes me extremely suspicious. Did you i
Randy Smith (Not in Mondays)
2013/01/07 20:54:10
Interesting. I copied that code, assuming that we
Randy Smith (Not in Mondays)
2013/01/08 19:31:12
Pawel: I was wrong, that sleep was needed for the
| |
| 1709 else: | |
| 1710 ## A more normal response | |
|
Paweł Hajdan Jr.
2013/01/04 22:56:58
nit: No double #, and make it more meaningful plea
Randy Smith (Not in Mondays)
2013/01/07 20:54:10
Done, although I wince a little, as that makes the
| |
| 1711 self.wfile.write('X' * (last_byte - first_byte + 1)) | |
| 1712 | |
| 1713 return True | |
| 1714 | |
| 1624 def DefaultResponseHandler(self): | 1715 def DefaultResponseHandler(self): |
| 1625 """This is the catch-all response handler for requests that aren't handled | 1716 """This is the catch-all response handler for requests that aren't handled |
| 1626 by one of the special handlers above. | 1717 by one of the special handlers above. |
| 1627 Note that we specify the content-length as without it the https connection | 1718 Note that we specify the content-length as without it the https connection |
| 1628 is not closed properly (and the browser keeps expecting data).""" | 1719 is not closed properly (and the browser keeps expecting data).""" |
| 1629 | 1720 |
| 1630 contents = "Default response given for path: " + self.path | 1721 contents = "Default response given for path: " + self.path |
| 1631 self.send_response(200) | 1722 self.send_response(200) |
| 1632 self.send_header('Content-Type', 'text/html') | 1723 self.send_header('Content-Type', 'text/html') |
| 1633 self.send_header('Content-Length', len(contents)) | 1724 self.send_header('Content-Length', len(contents)) |
| (...skipping 808 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2442 'load multipe keys into the server. If the ' | 2533 'load multipe keys into the server. If the ' |
| 2443 'server has multiple keys, it will rotate ' | 2534 'server has multiple keys, it will rotate ' |
| 2444 'through them in at each request a ' | 2535 'through them in at each request a ' |
| 2445 'round-robin fashion. The server will ' | 2536 'round-robin fashion. The server will ' |
| 2446 'generate a random key if none is specified ' | 2537 'generate a random key if none is specified ' |
| 2447 'on the command line.') | 2538 'on the command line.') |
| 2448 | 2539 |
| 2449 | 2540 |
| 2450 if __name__ == '__main__': | 2541 if __name__ == '__main__': |
| 2451 sys.exit(ServerRunner().main()) | 2542 sys.exit(ServerRunner().main()) |
| OLD | NEW |