Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(236)

Side by Side Diff: net/tools/testserver/testserver.py

Issue 1203983004: Stop using SpawnedTestServer in DownloadContentTest.* (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Move If-Range change out to a separate CL. Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright 2013 The Chromium Authors. All rights reserved. 2 # Copyright 2013 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/TCP/UDP/BASIC_AUTH_PROXY/WEBSOCKET server used for 6 """This is a simple HTTP/FTP/TCP/UDP/BASIC_AUTH_PROXY/WEBSOCKET server used for
7 testing Chrome. 7 testing Chrome.
8 8
9 It supports several test URLs, as specified by the handlers in TestPageHandler. 9 It supports several test URLs, as specified by the handlers in TestPageHandler.
10 By default, it listens on an ephemeral port and sends the port number back to 10 By default, it listens on an ephemeral port and sends the port number back to
(...skipping 325 matching lines...) Expand 10 before | Expand all | Expand 10 after
336 self.NoContentHandler, 336 self.NoContentHandler,
337 self.ServerRedirectHandler, 337 self.ServerRedirectHandler,
338 self.CrossSiteRedirectHandler, 338 self.CrossSiteRedirectHandler,
339 self.ClientRedirectHandler, 339 self.ClientRedirectHandler,
340 self.GetSSLSessionCacheHandler, 340 self.GetSSLSessionCacheHandler,
341 self.SSLManySmallRecords, 341 self.SSLManySmallRecords,
342 self.GetChannelID, 342 self.GetChannelID,
343 self.GetClientCert, 343 self.GetClientCert,
344 self.ClientCipherListHandler, 344 self.ClientCipherListHandler,
345 self.CloseSocketHandler, 345 self.CloseSocketHandler,
346 self.RangeResetHandler,
347 self.DefaultResponseHandler] 346 self.DefaultResponseHandler]
348 post_handlers = [ 347 post_handlers = [
349 self.EchoTitleHandler, 348 self.EchoTitleHandler,
350 self.EchoHandler, 349 self.EchoHandler,
351 self.PostOnlyFileHandler, 350 self.PostOnlyFileHandler,
352 self.EchoMultipartPostHandler] + get_handlers 351 self.EchoMultipartPostHandler] + get_handlers
353 put_handlers = [ 352 put_handlers = [
354 self.EchoTitleHandler, 353 self.EchoTitleHandler,
355 self.EchoHandler] + get_handlers 354 self.EchoHandler] + get_handlers
356 head_handlers = [ 355 head_handlers = [
(...skipping 1196 matching lines...) Expand 10 before | Expand all | Expand 10 after
1553 1552
1554 def CloseSocketHandler(self): 1553 def CloseSocketHandler(self):
1555 """Closes the socket without sending anything.""" 1554 """Closes the socket without sending anything."""
1556 1555
1557 if not self._ShouldHandleRequest('/close-socket'): 1556 if not self._ShouldHandleRequest('/close-socket'):
1558 return False 1557 return False
1559 1558
1560 self.wfile.close() 1559 self.wfile.close()
1561 return True 1560 return True
1562 1561
1563 def RangeResetHandler(self):
1564 """Send data broken up by connection resets every N (default 4K) bytes.
1565 Support range requests. If the data requested doesn't straddle a reset
1566 boundary, it will all be sent. Used for testing resuming downloads."""
1567
1568 def DataForRange(start, end):
1569 """Data to be provided for a particular range of bytes."""
1570 # Offset and scale to avoid too obvious (and hence potentially
1571 # collidable) data.
1572 return ''.join([chr(y % 256)
1573 for y in range(start * 2 + 15, end * 2 + 15, 2)])
1574
1575 if not self._ShouldHandleRequest('/rangereset'):
1576 return False
1577
1578 # HTTP/1.1 is required for ETag and range support.
1579 self.protocol_version = 'HTTP/1.1'
1580 _, _, url_path, _, query, _ = urlparse.urlparse(self.path)
1581
1582 # Defaults
1583 size = 8000
1584 # Note that the rst is sent just before sending the rst_boundary byte.
1585 rst_boundary = 4000
1586 respond_to_range = True
1587 hold_for_signal = False
1588 rst_limit = -1
1589 token = 'DEFAULT'
1590 fail_precondition = 0
1591 send_verifiers = True
1592
1593 # Parse the query
1594 qdict = urlparse.parse_qs(query, True)
1595 if 'size' in qdict:
1596 size = int(qdict['size'][0])
1597 if 'rst_boundary' in qdict:
1598 rst_boundary = int(qdict['rst_boundary'][0])
1599 if 'token' in qdict:
1600 # Identifying token for stateful tests.
1601 token = qdict['token'][0]
1602 if 'rst_limit' in qdict:
1603 # Max number of rsts for a given token.
1604 rst_limit = int(qdict['rst_limit'][0])
1605 if 'bounce_range' in qdict:
1606 respond_to_range = False
1607 if 'hold' in qdict:
1608 # Note that hold_for_signal will not work with null range requests;
1609 # see TODO below.
1610 hold_for_signal = True
1611 if 'no_verifiers' in qdict:
1612 send_verifiers = False
1613 if 'fail_precondition' in qdict:
1614 fail_precondition = int(qdict['fail_precondition'][0])
1615
1616 # Record already set information, or set it.
1617 rst_limit = TestPageHandler.rst_limits.setdefault(token, rst_limit)
1618 if rst_limit != 0:
1619 TestPageHandler.rst_limits[token] -= 1
1620 fail_precondition = TestPageHandler.fail_precondition.setdefault(
1621 token, fail_precondition)
1622 if fail_precondition != 0:
1623 TestPageHandler.fail_precondition[token] -= 1
1624
1625 first_byte = 0
1626 last_byte = size - 1
1627
1628 # Does that define what we want to return, or do we need to apply
1629 # a range?
1630 range_response = False
1631 range_header = self.headers.getheader('range')
1632 if range_header and respond_to_range:
1633 mo = re.match("bytes=(\d*)-(\d*)", range_header)
1634 if mo.group(1):
1635 first_byte = int(mo.group(1))
1636 if mo.group(2):
1637 last_byte = int(mo.group(2))
1638 if last_byte > size - 1:
1639 last_byte = size - 1
1640 range_response = True
1641 if last_byte < first_byte:
1642 return False
1643
1644 if fail_precondition and self.headers.getheader('If-Range'):
1645 self.send_response(412)
1646 self.end_headers()
1647 return True
1648
1649 if range_response:
1650 self.send_response(206)
1651 self.send_header('Content-Range',
1652 'bytes %d-%d/%d' % (first_byte, last_byte, size))
1653 else:
1654 self.send_response(200)
1655 self.send_header('Content-Type', 'application/octet-stream')
1656 self.send_header('Content-Length', last_byte - first_byte + 1)
1657 if send_verifiers:
1658 # If fail_precondition is non-zero, then the ETag for each request will be
1659 # different.
1660 etag = "%s%d" % (token, fail_precondition)
1661 self.send_header('ETag', etag)
1662 self.send_header('Last-Modified', 'Tue, 19 Feb 2013 14:32 EST')
1663 self.end_headers()
1664
1665 if hold_for_signal:
1666 # TODO(rdsmith/phajdan.jr): http://crbug.com/169519: Without writing
1667 # a single byte, the self.server.handle_request() below hangs
1668 # without processing new incoming requests.
1669 self.wfile.write(DataForRange(first_byte, first_byte + 1))
1670 first_byte = first_byte + 1
1671 # handle requests until one of them clears this flag.
1672 self.server.wait_for_download = True
1673 while self.server.wait_for_download:
1674 self.server.handle_request()
1675
1676 possible_rst = ((first_byte / rst_boundary) + 1) * rst_boundary
1677 if possible_rst >= last_byte or rst_limit == 0:
1678 # No RST has been requested in this range, so we don't need to
1679 # do anything fancy; just write the data and let the python
1680 # infrastructure close the connection.
1681 self.wfile.write(DataForRange(first_byte, last_byte + 1))
1682 self.wfile.flush()
1683 return True
1684
1685 # We're resetting the connection part way in; go to the RST
1686 # boundary and then send an RST.
1687 # Because socket semantics do not guarantee that all the data will be
1688 # sent when using the linger semantics to hard close a socket,
1689 # we send the data and then wait for our peer to release us
1690 # before sending the reset.
1691 data = DataForRange(first_byte, possible_rst)
1692 self.wfile.write(data)
1693 self.wfile.flush()
1694 self.server.wait_for_download = True
1695 while self.server.wait_for_download:
1696 self.server.handle_request()
1697 l_onoff = 1 # Linger is active.
1698 l_linger = 0 # Seconds to linger for.
1699 self.connection.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER,
1700 struct.pack('ii', l_onoff, l_linger))
1701
1702 # Close all duplicates of the underlying socket to force the RST.
1703 self.wfile.close()
1704 self.rfile.close()
1705 self.connection.close()
1706
1707 return True
1708
1709 def DefaultResponseHandler(self): 1562 def DefaultResponseHandler(self):
1710 """This is the catch-all response handler for requests that aren't handled 1563 """This is the catch-all response handler for requests that aren't handled
1711 by one of the special handlers above. 1564 by one of the special handlers above.
1712 Note that we specify the content-length as without it the https connection 1565 Note that we specify the content-length as without it the https connection
1713 is not closed properly (and the browser keeps expecting data).""" 1566 is not closed properly (and the browser keeps expecting data)."""
1714 1567
1715 contents = "Default response given for path: " + self.path 1568 contents = "Default response given for path: " + self.path
1716 self.send_response(200) 1569 self.send_response(200)
1717 self.send_header('Content-Type', 'text/html') 1570 self.send_header('Content-Type', 'text/html')
1718 self.send_header('Content-Length', len(contents)) 1571 self.send_header('Content-Length', len(contents))
(...skipping 589 matching lines...) Expand 10 before | Expand all | Expand 10 after
2308 'an anonymous user.') 2161 'an anonymous user.')
2309 self.option_parser.add_option('--disable-channel-id', action='store_true') 2162 self.option_parser.add_option('--disable-channel-id', action='store_true')
2310 self.option_parser.add_option('--disable-extended-master-secret', 2163 self.option_parser.add_option('--disable-extended-master-secret',
2311 action='store_true') 2164 action='store_true')
2312 self.option_parser.add_option('--token-binding-params', action='append', 2165 self.option_parser.add_option('--token-binding-params', action='append',
2313 default=[], type='int') 2166 default=[], type='int')
2314 2167
2315 2168
2316 if __name__ == '__main__': 2169 if __name__ == '__main__':
2317 sys.exit(ServerRunner().main()) 2170 sys.exit(ServerRunner().main())
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698