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 1129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1615 | 1617 |
1616 def CloseSocketHandler(self): | 1618 def CloseSocketHandler(self): |
1617 """Closes the socket without sending anything.""" | 1619 """Closes the socket without sending anything.""" |
1618 | 1620 |
1619 if not self._ShouldHandleRequest('/close-socket'): | 1621 if not self._ShouldHandleRequest('/close-socket'): |
1620 return False | 1622 return False |
1621 | 1623 |
1622 self.wfile.close() | 1624 self.wfile.close() |
1623 return True | 1625 return True |
1624 | 1626 |
1627 def RangeResetHandler(self): | |
1628 """Send data broken up by connection resets every N (default 4K) bytes. | |
1629 Support range requests. If the data requested doesn't straddle a reset | |
1630 boundary, it will all be sent. Used for testing resuming downloads.""" | |
1631 | |
1632 if not self._ShouldHandleRequest('/rangereset'): | |
1633 return False | |
1634 | |
1635 _, _, url_path, _, query, _ = urlparse.urlparse(self.path) | |
1636 | |
1637 # Defaults | |
1638 size = 8000 | |
1639 # Note that the rst is sent just before sending the rst_boundary byte. | |
1640 rst_boundary = 4000 | |
1641 respond_to_range = True | |
1642 hold_for_signal = False | |
1643 | |
1644 # Parse the query | |
1645 qdict = urlparse.parse_qs(query, True) | |
1646 if 'size' in qdict: | |
1647 size = int(qdict['size']) | |
1648 if 'rst_boundary' in qdict: | |
1649 rst_boundary = int(qdict['rst_boundary']) | |
1650 if 'bounce_range' in qdict: | |
1651 respond_to_range = False | |
1652 if 'hold' in qdict: | |
1653 hold_for_signal = True | |
1654 | |
1655 first_byte = 0 | |
1656 last_byte = size - 1 | |
1657 | |
1658 # Does that define what we want to return, or do we need to apply | |
1659 # a range? | |
1660 range_response = False | |
1661 range_header = self.headers.getheader('range') | |
1662 if range_header and respond_to_range: | |
1663 mo = re.match("bytes=(\d*)-(\d*)", range_header) | |
1664 if mo.group(1): | |
1665 first_byte = int(mo.group(1)) | |
1666 if mo.group(2): | |
1667 last_byte = int(mo.group(2)) | |
1668 if last_byte > size - 1: | |
1669 last_byte = size - 1 | |
1670 range_response = True | |
1671 if last_byte < first_byte: | |
1672 return False | |
1673 | |
1674 # Set socket send buf high enough that we don't need to worry | |
1675 # about asynchronous closes when sending RSTs. | |
1676 self.connection.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, | |
1677 16284) | |
1678 | |
1679 if range_response: | |
1680 self.send_response(206) | |
1681 self.send_header('Content-Range', | |
1682 'bytes %d-%d/%d' % (first_byte, last_byte, size)) | |
1683 else: | |
1684 self.send_response(200) | |
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 # Hack alert/explanation: Without writing a single byte, the | |
Paweł Hajdan Jr.
2013/01/10 23:50:22
Please file a bug for this and put a TODO here.
Randy Smith (Not in Mondays)
2013/01/11 19:28:34
Done.
| |
1691 # self.server.handle_request() below hangs without processing | |
1692 # new incoming requests. Presumably this is due to a bug in | |
1693 # BaseHTTPRequestHandler. | |
1694 self.wfile.write('X') | |
1695 first_byte = first_byte + 1 | |
1696 # handle requests until one of them clears this flag. | |
1697 self.server.waitForDownload = True | |
1698 while self.server.waitForDownload: | |
1699 self.server.handle_request() | |
1700 | |
1701 possible_rst = ((first_byte / rst_boundary) + 1) * rst_boundary | |
1702 if possible_rst >= last_byte: | |
1703 # No RST has been requested in this range, so we don't need to | |
1704 # do anything fancy; just write the data and let the python | |
1705 # infrastructure close the connection. | |
1706 self.wfile.write('X' * (last_byte - first_byte + 1)) | |
1707 self.wfile.flush() | |
1708 return True | |
1709 | |
1710 # We're resetting the connection part way in; go to the RST | |
1711 # boundary and then send an RST. | |
1712 # WINDOWS WARNING: On windows, if the amount of data sent before the | |
1713 # reset is > 4096, only 4096 bytes will make it across before the RST | |
1714 # despite the flush. This is hypothesized to be due to an underlying | |
1715 # asynchronous sending implementation, which the 0 second linger | |
1716 # forcibly terminates. The amount of data pre-RST should be kept below | |
1717 # 4096 for this reason. | |
1718 self.wfile.write('X' * (possible_rst - first_byte)) | |
1719 self.wfile.flush() | |
1720 l_onoff = 1 # Linger is active. | |
1721 l_linger = 0 # Seconds to linger for. | |
1722 self.connection.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, | |
1723 struct.pack('ii', l_onoff, l_linger)) | |
1724 | |
1725 # Close all duplicates of the underlying socket to force the RST. | |
1726 self.wfile.close() | |
1727 self.rfile.close() | |
1728 self.connection.close() | |
1729 | |
1730 return True | |
1731 | |
1625 def DefaultResponseHandler(self): | 1732 def DefaultResponseHandler(self): |
1626 """This is the catch-all response handler for requests that aren't handled | 1733 """This is the catch-all response handler for requests that aren't handled |
1627 by one of the special handlers above. | 1734 by one of the special handlers above. |
1628 Note that we specify the content-length as without it the https connection | 1735 Note that we specify the content-length as without it the https connection |
1629 is not closed properly (and the browser keeps expecting data).""" | 1736 is not closed properly (and the browser keeps expecting data).""" |
1630 | 1737 |
1631 contents = "Default response given for path: " + self.path | 1738 contents = "Default response given for path: " + self.path |
1632 self.send_response(200) | 1739 self.send_response(200) |
1633 self.send_header('Content-Type', 'text/html') | 1740 self.send_header('Content-Type', 'text/html') |
1634 self.send_header('Content-Length', len(contents)) | 1741 self.send_header('Content-Length', len(contents)) |
(...skipping 808 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2443 'load multipe keys into the server. If the ' | 2550 'load multipe keys into the server. If the ' |
2444 'server has multiple keys, it will rotate ' | 2551 'server has multiple keys, it will rotate ' |
2445 'through them in at each request a ' | 2552 'through them in at each request a ' |
2446 'round-robin fashion. The server will ' | 2553 'round-robin fashion. The server will ' |
2447 'generate a random key if none is specified ' | 2554 'generate a random key if none is specified ' |
2448 'on the command line.') | 2555 'on the command line.') |
2449 | 2556 |
2450 | 2557 |
2451 if __name__ == '__main__': | 2558 if __name__ == '__main__': |
2452 sys.exit(ServerRunner().main()) | 2559 sys.exit(ServerRunner().main()) |
OLD | NEW |