Ticket #5192: 5192_4.patch
| File 5192_4.patch, 35.9 KB (added by darfire, 13 months ago) |
|---|
-
twisted/web/_newclient.py
573 573 self.persistent = persistent 574 574 575 575 576 def _writeHeaders(self, transport, TEorCL):576 def _writeHeaders(self, transport, bodyFramingHeader): 577 577 hosts = self.headers.getRawHeaders('host', ()) 578 578 if len(hosts) != 1: 579 579 raise BadHeaders("Exactly one Host header required") … … 586 586 '%s %s HTTP/1.1\r\n' % (self.method, self.uri)) 587 587 if not self.persistent: 588 588 requestLines.append('Connection: close\r\n') 589 if TEorCLis not None:590 requestLines.append( TEorCL)589 if bodyFramingHeader is not None: 590 requestLines.append(bodyFramingHeader) 591 591 for name, values in self.headers.getAllRawHeaders(): 592 592 requestLines.extend(['%s: %s\r\n' % (name, v) for v in values]) 593 593 requestLines.append('\r\n') 594 594 transport.writeSequence(requestLines) 595 595 596 597 def _writeToChunked(self, transport): 596 def _writeBodyToChunked(self, transport): 598 597 """ 599 Write this request to the given transport using chunked598 Write this request's body to the given transport using chunked 600 599 transfer-encoding to frame the body. 601 600 """ 602 self._writeHeaders(transport, 'Transfer-Encoding: chunked\r\n')603 601 encoder = ChunkedEncoder(transport) 604 602 encoder.registerProducer(self.bodyProducer, True) 605 603 d = self.bodyProducer.startProducing(encoder) … … 618 616 return d 619 617 620 618 621 def _write ToContentLength(self, transport):619 def _writeBodyToContentLength(self, transport): 622 620 """ 623 Write this request to the given transport using content-length to frame624 t he body.621 Write this request's body to the given transport using content-length 622 to frame the body. 625 623 """ 626 self._writeHeaders(627 transport,628 'Content-Length: %d\r\n' % (self.bodyProducer.length,))629 624 630 625 # This Deferred is used to signal an error in the data written to the 631 626 # encoder below. It can only errback and it will only do so before too … … 737 732 been completely written to the transport or with a L{Failure} if 738 733 there is any problem generating the request bytes. 739 734 """ 735 self._writeHeadersTo(transport) 736 return self._writeBodyTo(transport) 737 738 def _writeHeadersTo(self, transport): 739 """ 740 Format this L{Request}'s headers as HTTP/1.1 and write them 741 to the given transport. 742 """ 743 bodyFramingHeader = None 740 744 if self.bodyProducer is not None: 745 if self.bodyProducer.length is UNKNOWN_LENGTH: 746 bodyFramingHeader = 'Transfer-Encoding: chunked\r\n' 747 else: 748 bodyFramingHeader = 'Content-Length: %d\r\n' % ( 749 self.bodyProducer.length,) 750 751 self._writeHeaders(transport, bodyFramingHeader) 752 753 def _writeBodyTo(self, transport): 754 """ 755 Write this L{Request}'s body to the given transport, framing it 756 according to the given headers('Transport-Encoding' or 757 'Content-Length'). 758 759 @return: A L{Deferred} which fires with C{None} when the request has 760 been completely written the transport or with a L{Failure} if there 761 is any problem generating the request body bytes. If bodyProducer 762 is None the returned L{Deferred} is already fired. 763 """ 764 if self.bodyProducer is not None: 741 765 if self.bodyProducer.length is UNKNOWN_LENGTH: 742 return self._write ToChunked(transport)766 return self._writeBodyToChunked(transport) 743 767 else: 744 return self._write ToContentLength(transport)768 return self._writeBodyToContentLength(transport) 745 769 else: 746 self._writeHeaders(transport, None)747 770 return succeed(None) 748 771 749 772 … … 1186 1209 self._producer.pauseProducing() 1187 1210 1188 1211 1212 class DiscardWithDeferred(Protocol): 1213 """ 1214 A L{Protocol} that discards all received data and that fires a L{Deferred} 1215 when all data has been received. 1189 1216 1217 @ivar finishedDeferred: L{Deferred} which fires with C{None} when all data 1218 has been received and with L{Failure} on error. 1219 1220 """ 1221 1222 def __init__(self): 1223 self.finishedDeferred = Deferred() 1224 1225 def dataReceived(self, data): 1226 pass 1227 1228 def connectionLost(self, reason): 1229 if reason.type == ResponseDone: 1230 self.finishedDeferred.callback(None) 1231 else: 1232 self.finishedDeferred.errback(reason) 1233 1234 1235 TIMEOUT_100_CONTINUE = 1 1236 1237 1190 1238 class HTTP11ClientProtocol(Protocol): 1191 1239 """ 1192 1240 L{HTTP11ClientProtocol} is an implementation of the HTTP 1.1 client 1193 protocol. It supports as few features as possible.1241 protocol. It supports as few features as possible. 1194 1242 1195 1243 @ivar _parser: After a request is issued, the L{HTTPClientParser} to 1196 1244 which received data making up the response to that request is 1197 1245 delivered. 1198 1246 1247 @ivar _reactor: The reactor used for eventual callLater calls. 1248 1199 1249 @ivar _finishedRequest: After a request is issued, the L{Deferred} which 1200 1250 will fire when a L{Response} object corresponding to that request is 1201 1251 available. This allows L{HTTP11ClientProtocol} to fail the request … … 1216 1266 received. This is eventually chained with C{_finishedRequest}, but 1217 1267 only in certain cases to avoid double firing that Deferred. 1218 1268 1269 @ivar _responseBodyDeferred: After a request is issued, the L{Deferred} 1270 that fires when the C{_parser} has done parsing the entire L{Response}, 1271 including body, with the data that came after the current L{Response}. 1272 This can be used to set another C{_parser} but usually this decision 1273 is done on C{_responseDeferred}'s callback. 1274 1275 @ivar _forcedRequestBody: True if we had an 100-Continue L{Request} whose 1276 body was forcefully written to the transport because the server 1277 did not respond in time with a L{Response} (possibly because of a 1278 buggy server that doesn't implement expectations correctly). 1279 1280 @ivar _firstResponseTimer: A L{Delayed} that fires after 1281 TIMEOUT_100_CONTINUE seconds and forcefully sends the L{Request} body 1282 to the server. 1283 1284 @ivar _firstResponseDeferred: A L{Deferred} that fires with the first 1285 L{Response} to an 100-Continue L{Request}. This may be an 100-Continue 1286 response or a response with a final status. It may fire in the 1287 WAITING_100_CONTINUE_RESPONSE, TRANSMITTING or WAITING states. 1288 1289 @ivar _firstResponseBodyDeferred: A L{Deferred} that fires when the body 1290 of the first L{Response} to an 100-Continue L{Request} has been 1291 successfully parsed. It signals that we can start sending the 1292 L{Request} body. It fires in the WAITING_100_CONTINUE_RESPONSE_BODY, 1293 TRANSMITTING and WAITING states. 1294 1219 1295 @ivar _state: Indicates what state this L{HTTP11ClientProtocol} instance 1220 1296 is in with respect to transmission of a request and reception of a 1221 1297 response. This may be one of the following strings: … … 1236 1312 - GENERATION_FAILED: There was an error while the request. The 1237 1313 request was not fully sent to the network. 1238 1314 1315 - WAITING_100_CONTINUE_RESPONSE: We're waiting for a L{Response} to a 1316 L{Request} that expects 100-Continue. 1317 1318 - WAITING_100_CONTINUE_RESPONSE_BODY: Got an 100 Continue 1319 L{Response} and we're discarding its body before sending the 1320 L{Request}. 1321 1239 1322 - WAITING: The request was fully sent to the network. The 1240 1323 instance is now waiting for the response to be fully received. 1241 1324 … … 1255 1338 _responseDeferred = None 1256 1339 1257 1340 1258 def __init__(self, quiescentCallback=lambda c: None): 1341 def __init__(self, quiescentCallback=lambda c: None, reactor=None): 1342 """ 1343 Initialize this L{HTTP11ClientProtocol}. Optionally a reactor can be 1344 given. Otherwise use the global reactor. 1345 """ 1346 if reactor is None: 1347 from twisted.internet import reactor 1348 self._reactor = reactor 1259 1349 self._quiescentCallback = quiescentCallback 1260 1350 self._abortDeferreds = [] 1261 1351 … … 1284 1374 may errback with L{RequestNotSent} if it is not possible to send 1285 1375 any more requests using this L{HTTP11ClientProtocol}. 1286 1376 """ 1377 1287 1378 if self._state != 'QUIESCENT': 1288 1379 return fail(RequestNotSent()) 1289 1380 1290 self._state = 'TRANSMITTING' 1291 _requestDeferred = maybeDeferred(request.writeTo, self.transport) 1381 if request.headers.hasHeader('expect'): 1382 _expectations = request.headers.getRawHeaders('expect') 1383 _expects100Continue = '100-continue' in [x.lower() for x in 1384 _expectations] 1385 else: 1386 _expects100Continue = False 1387 1292 1388 self._finishedRequest = Deferred() 1293 1389 1294 # Keep track of the Request object in case we need to call stopWriting1295 # on it.1296 1390 self._currentRequest = request 1297 1391 1298 self._transportProxy = TransportProxyProducer(self.transport)1299 self._parser = HTTPClientParser(request, self._finishResponse)1300 self._parser.makeConnection(self._transportProxy)1301 self._responseDeferred = self._parser._responseDeferred1392 if _expects100Continue: 1393 self._handle100ContinueRequest(request) 1394 else: 1395 self._handleRequest(request) 1302 1396 1303 1397 def cbRequestWrotten(ignored): 1304 if self._state == 'TRANSMITTING': 1398 if self._state in ['TRANSMITTING', 1399 'WAITING_100_CONTINUE_RESPONSE', 1400 'WAITING_100_CONTINUE_RESPONSE_BODY']: 1305 1401 self._state = 'WAITING' 1306 1402 self._responseDeferred.chainDeferred(self._finishedRequest) 1307 1403 … … 1315 1411 log.err(err, 'Error writing request, but not in valid state ' 1316 1412 'to finalize request: %s' % self._state) 1317 1413 1318 _requestDeferred.addCallbacks(cbRequestWrotten, ebRequestWriting)1414 self._requestDeferred.addCallbacks(cbRequestWrotten, ebRequestWriting) 1319 1415 1416 self._responseBodyDeferred.addCallback(self._finishResponse) 1417 1320 1418 return self._finishedRequest 1321 1419 1322 1420 … … 1336 1434 # Currently the rest parameter is ignored. Don't forget to use it if 1337 1435 # we ever add support for pipelining. And maybe check what trailers 1338 1436 # mean. 1339 if self._state == 'WAITING': 1437 if self._state in ['WAITING', 1438 'WAITING_100_CONTINUE_RESPONSE']: 1340 1439 self._state = 'QUIESCENT' 1341 1440 else: 1342 1441 # The server sent the entire response before we could send the … … 1369 1468 log.err() 1370 1469 self.transport.loseConnection() 1371 1470 self._disconnectParser(reason) 1471 self._cleanupRequest() 1372 1472 1373 1473 1374 1474 _finishResponse_TRANSMITTING = _finishResponse_WAITING 1475 _finishResponse_WAITING_100_CONTINUE_RESPONSE = _finishResponse_WAITING 1375 1476 1477 def _handleRequest(self, request): 1478 """ 1479 Send a non-100-Continue-expecting L{Request} to the transport. 1376 1480 1481 @param request: The L{Request} to be sent. 1482 1483 """ 1484 self._state = 'TRANSMITTING' 1485 self._requestDeferred = maybeDeferred(request.writeTo, self.transport) 1486 (self._responseDeferred, 1487 self._responseBodyDeferred) = self._setupParser(request) 1488 1489 1490 def _handle100ContinueRequest(self, request): 1491 """ 1492 Send an 100-Continue L{Request} to the transport. 1493 1494 @param request: The L{Request} to be sent. 1495 """ 1496 request._writeHeadersTo(self.transport) 1497 self._state = 'WAITING_100_CONTINUE_RESPONSE' 1498 self._forcedRequestBody = False 1499 self._requestDeferred = Deferred() 1500 self._responseDeferred = Deferred() 1501 self._responseBodyDeferred = Deferred() 1502 (self._firstResponseDeferred, 1503 self._firstResponseBodyDeferred) = self._setupParser(request) 1504 self._firstResponseTimer = self._reactor.callLater( 1505 TIMEOUT_100_CONTINUE, 1506 self._forceRequestBody) 1507 1508 self._firstResponseDeferred.addCallbacks( 1509 self._handleFirstResponse, self._handle100ContinueError) 1510 1511 1512 def _handleFirstResponse(self, response): 1513 """ 1514 Handle the first L{Response} to an 100-Continue L{Request}. This may 1515 be an 100-Continue or a final status L{Response}. If it is an 100 1516 response, consume it's body and then send the L{Request} body, else 1517 forward the response to the user by means of self._finishedRequest. 1518 1519 @param response: The L{Response} to the current L{Request}. 1520 """ 1521 # This may be inactive if this is a response that came after the timer 1522 # fired. 1523 if self._firstResponseTimer.active(): 1524 self._firstResponseTimer.cancel() 1525 1526 if self._state == 'WAITING_100_CONTINUE_RESPONSE': 1527 1528 if response.code == 100: 1529 self._state = 'WAITING_100_CONTINUE_RESPONSE_BODY' 1530 self._discardResponseBody(response, 1531 self._handleFirstResponseBody, 1532 self._handle100ContinueError) 1533 else: 1534 # We're done with this request. 1535 self._requestDeferred.callback(None) 1536 self._forwardFirstResponse(response) 1537 1538 else: 1539 1540 if self._forcedRequestBody and response.code == 100: 1541 # Late arrival, eat it. 1542 self._discardResponseBody(response, 1543 self._handleFirstResponseBody, 1544 self._handle100ContinueError) 1545 1546 else: 1547 # A late response that isn't 100-Continue; could be from a 1548 # server that doesn't implement expectations correctly. 1549 self._forcedRequestBody = False 1550 self._forwardFirstResponse(response) 1551 1552 1553 def _forwardFirstResponse(self, response): 1554 """ 1555 Forward a L{Response} and its body to the caller. 1556 1557 @param response: The L{Response} to be forwarded. 1558 """ 1559 1560 # Save this since it may get cleaned up in _finishResponse 1561 responseDeferred = self._responseDeferred 1562 self._firstResponseBodyDeferred.chainDeferred( 1563 self._responseBodyDeferred) 1564 responseDeferred.callback(response) 1565 1566 1567 def _handleFirstResponseBody(self, rest): 1568 """ 1569 The body of the first L{Response} to the current 100-Continue 1570 L{Request} has been parsed. If the L{Response} wasn't an 100-Continue 1571 forward to self._responseBodyDeferred. Otherwise create a new parser 1572 for the second L{Response}. 1573 1574 @param rest: Data that wasn't parsed by the parser because it came 1575 after the L{Response}. If we reload the parser, initialize it 1576 with this data. 1577 """ 1578 # We've just done discarding an 100-Continue response's body. Might 1579 # be because we're waiting to send the request body or it might be 1580 # that we've ignored a late response. 1581 1582 self._forcedRequestBody = False 1583 1584 if self._state == 'WAITING_100_CONTINUE_RESPONSE_BODY': 1585 self._state = 'TRANSMITTING' 1586 1587 # Send the request body. 1588 1589 _requestBodyDeferred = maybeDeferred( 1590 self._currentRequest._writeBodyTo, 1591 self.transport) 1592 1593 _requestBodyDeferred.chainDeferred(self._requestDeferred) 1594 1595 # In both cases create a new parser. 1596 1597 self._disconnectParser(None) 1598 1599 (_secondResponseDeferred, _secondResponseBodyDeferred) =\ 1600 self._setupParser(self._currentRequest, data=rest) 1601 1602 _secondResponseDeferred.chainDeferred(self._responseDeferred) 1603 _secondResponseBodyDeferred.chainDeferred(self._responseBodyDeferred) 1604 1605 1606 def _discardResponseBody(self, response, callback, errback): 1607 """ 1608 Discard a L{Response}'s body and call callback when done and errback 1609 on error. 1610 1611 @param response: L{Response} that needs to be discarded. 1612 @param callback: function to be called when done. 1613 @param errback: function to be called on error 1614 """ 1615 discarder = DiscardWithDeferred() 1616 1617 # We use discarder.finishedDeferred to catch body parsing 1618 # errors and self._firstResponseBodyDeferred to catch success. 1619 1620 discarder.finishedDeferred.addErrback(errback) 1621 1622 response.deliverBody(discarder) 1623 1624 self._firstResponseBodyDeferred.addCallback(callback) 1625 1626 1627 def _forceRequestBody(self): 1628 """ 1629 Send the current L{Request} body even though we were expecting an 1630 100 or final status L{Response}. It may just be a broken server that 1631 doesn't implement correctly expectations. 1632 """ 1633 self._state = 'TRANSMITTING' 1634 1635 self._forcedRequestBody = True 1636 1637 _requestBodyDeferred = maybeDeferred(self._currentRequest._writeBodyTo, 1638 self.transport) 1639 1640 _requestBodyDeferred.chainDeferred(self._requestDeferred) 1641 1642 1643 def _setupParser(self, request, data=''): 1644 """ 1645 Setup a L{HTTPClientParser} for a L{Response} to a L{Request}. If this 1646 is not the first parser associated with this protocol, call 1647 L{HTTP11ClientProtocol._disconnectParser} first. Pass the given C{data} 1648 to the newly created parser. 1649 1650 @param request: L{Request} waiting for a L{Response}. 1651 @param data: Data to initialize the L{HTTPClientParser} with. 1652 """ 1653 self._transportProxy = TransportProxyProducer(self.transport) 1654 1655 _responseBodyDeferred = Deferred() 1656 1657 def cbOnBodyFinish(rest): 1658 _responseBodyDeferred.callback(rest) 1659 1660 self._parser = HTTPClientParser(request, cbOnBodyFinish) 1661 1662 self._parser.makeConnection(self._transportProxy) 1663 1664 # Grab this before passing data, since it might disappear if data is a 1665 # complete response. 1666 1667 _responseDeferred = self._parser._responseDeferred 1668 1669 self._parser.dataReceived(data) 1670 1671 return (_responseDeferred, _responseBodyDeferred) 1672 1673 1674 def _cleanupOn100ContinueError(self): 1675 """ 1676 State-dependent cleanup on parsing errors while handling an 1677 100-Continue-expecting L{Request}. 1678 """ 1679 _cleanupOn100ContinueError = makeStatefulDispatcher( 1680 'cleanupOn100ContinueError', _cleanupOn100ContinueError) 1681 1682 1683 def _cleanupOn100ContinueError_WAITING_100_CONTINUE_RESPONSE(self): 1684 """ 1685 The L{Request} body no sent yet. Fire self._requestDeferred because 1686 we've basically finished dealing with this L{Request}. Also, this 1687 forwards the L{Failure} to the user. 1688 """ 1689 self._requestDeferred.callback(None) 1690 1691 1692 def _cleanupOn100ContinueError_WAITING_100_CONTINUE_RESPONSE_BODY(self): 1693 """ 1694 The L{Request} body no sent yet. Fire self._requestDeferred because 1695 we've basically finished dealing with this L{Request}. Also, this 1696 forwards the L{Failure} to the user. 1697 """ 1698 self._requestDeferred.callback(None) 1699 1700 1701 def _cleanupOn100ContinueError_TRANSMITTING(self): 1702 """ 1703 We're currently sending the L{Request} body. The error will be sent to 1704 the user after the body has been sent. No cleanup needed. 1705 """ 1706 1707 1708 def _cleanupOn100ContinueError_WAITING(self): 1709 """ 1710 No cleanup needed. 1711 """ 1712 1713 1714 def _handle100ContinueError(self, err): 1715 """ 1716 Handle any L{Failure} that could occur while handling a L{Request} that 1717 expects 100-Continue. These are errors on parsing the first response 1718 and the first response's body and can occur in the 1719 WAITING_100_CONTINUE_RESPONSE/WAITING_100_CONTINUE_RESPONSE_BODY if 1720 the server supports expectations or TRANSMITTING/WAITING if the 1721 L{Request} body was sent after TIMEOUT_100_CONTINUE. Depending on 1722 the current state some cleanup needs to be performed and the L{Failure} 1723 is forwarded to self._responseDeferred. 1724 1725 @param err: L{Failure} to be forwarded. 1726 """ 1727 self._cleanupOn100ContinueError() 1728 self._responseDeferred.errback(err) 1729 1730 1731 def _cleanupRequest(self): 1732 """ 1733 Clean up the L{HTTP11ClientProtocol}'s state after a L{Request} has 1734 been done with. 1735 """ 1736 self._currentRequest = None 1737 self._finishedRequest = None 1738 self._responseDeferred = None 1739 self._firstResponseDeferred = None 1740 self._firstResponseBodyDeferred = None 1741 1742 1377 1743 def _disconnectParser(self, reason): 1378 1744 """ 1379 1745 If there is still a parser, call its C{connectionLost} method with the … … 1384 1750 if self._parser is not None: 1385 1751 parser = self._parser 1386 1752 self._parser = None 1387 self._currentRequest = None1388 self._finishedRequest = None1389 self._responseDeferred = None1390 1753 1391 1754 # The parser is no longer allowed to do anything to the real 1392 1755 # transport. Stop proxying from the parser's transport to the real … … 1488 1851 self._abortDeferreds = [] 1489 1852 1490 1853 1854 def _connectionLost_WAITING_100_CONTINUE_RESPONSE(self, reason): 1855 """ 1856 Disconnect the parser so that it can propagate the event and move to 1857 the C{'CONNECTION_LOST'} state. 1858 """ 1859 self._disconnectParser(reason) 1860 self._state = 'CONNECTION_LOST' 1861 1862 1863 def _connectionLost_WAITING_100_CONTINUE_RESPONSE_BODY(self, reason): 1864 """ 1865 Disconnect the parser so that it can propagate the event and move to 1866 the C{'CONNECTION_LOST'} state. 1867 """ 1868 self._disconnectParser(reason) 1869 self._state = 'CONNECTION_LOST' 1870 1871 1491 1872 def abort(self): 1492 1873 """ 1493 1874 Close the connection and cause all outstanding L{request} L{Deferred}s -
twisted/web/test/test_newclient.py
7 7 8 8 __metaclass__ = type 9 9 10 from StringIO import StringIO 11 10 12 from zope.interface import implements 11 13 from zope.interface.verify import verifyObject 12 14 … … 16 18 from twisted.internet.error import ConnectionDone, ConnectionLost 17 19 from twisted.internet.defer import Deferred, succeed, fail 18 20 from twisted.internet.protocol import Protocol 21 from twisted.internet.task import Clock, Cooperator 19 22 from twisted.trial.unittest import TestCase 20 23 from twisted.test.proto_helpers import StringTransport, AccumulatingProtocol 21 24 from twisted.web._newclient import UNKNOWN_LENGTH, STATUS, HEADER, BODY, DONE … … 27 30 from twisted.web._newclient import ConnectionAborted, ResponseNeverReceived 28 31 from twisted.web._newclient import BadHeaders, ResponseDone, PotentialDataLoss, ExcessWrite 29 32 from twisted.web._newclient import TransportProxyProducer, LengthEnforcingConsumer, makeStatefulDispatcher 33 from twisted.web._newclient import TIMEOUT_100_CONTINUE 30 34 from twisted.web.http_headers import Headers 31 35 from twisted.web.http import _DataLoss 32 36 from twisted.web.iweb import IBodyProducer, IResponse 37 from twisted.web.client import FileBodyProducer 33 38 34 39 35 40 … … 827 832 method = 'GET' 828 833 stopped = False 829 834 persistent = False 835 headers = Headers() 830 836 831 837 def writeTo(self, transport): 832 838 self.finished = Deferred() … … 846 852 L{Request} with no body producer. 847 853 """ 848 854 persistent = False 855 headers = Headers() 849 856 850 857 def writeTo(self, transport): 851 858 transport.write('SOME BYTES') … … 863 870 Create an L{HTTP11ClientProtocol} connected to a fake transport. 864 871 """ 865 872 self.transport = StringTransport() 866 self.protocol = HTTP11ClientProtocol() 873 self.clock = Clock() 874 self.protocol = HTTP11ClientProtocol(reactor=self.clock) 867 875 self.protocol.makeConnection(self.transport) 868 876 869 877 … … 916 924 """ 917 925 class BrokenRequest: 918 926 persistent = False 927 headers = Headers() 919 928 def writeTo(self, transport): 920 929 return fail(ArbitraryException()) 921 930 … … 939 948 """ 940 949 class BrokenRequest: 941 950 persistent = False 951 headers = Headers() 942 952 def writeTo(self, transport): 943 953 raise ArbitraryException() 944 954 … … 1566 1576 self.assertTrue(transport.disconnecting) 1567 1577 1568 1578 1579 def _send100ContinueRequest(self, body, persistent=False): 1580 """ 1581 Send a L{Request} that expects 100-Continue with the given body. 1582 """ 1583 def _immediateScheduler(x): 1584 return succeed(x()) 1569 1585 1586 cooperator = Cooperator(scheduler=_immediateScheduler, started=False) 1587 producer = FileBodyProducer(StringIO(body), cooperator=cooperator) 1588 1589 headers = Headers({'host': ['example.com'], 'expect': ['100-Continue']}) 1590 1591 d = self.protocol.request(Request('POST', '/foo', headers, producer, 1592 persistent=persistent)) 1593 1594 self.transport.clear() 1595 1596 cooperator.start() 1597 1598 self.assertEqual(self.transport.value(), '') 1599 1600 return d 1601 1602 1603 def test_expect100ContinueGetFinalStatus(self): 1604 """ 1605 When we expect 100-Continue and get a final status L{Response} we don't 1606 send the L{Request} body and return the first L{Response} to the user. 1607 """ 1608 d = self._send100ContinueRequest('x' * 10) 1609 1610 def cbResponse(response): 1611 self.assertEqual(response.code, 200) 1612 1613 d.addCallback(cbResponse) 1614 1615 self.protocol.dataReceived( 1616 "HTTP/1.1 200 OK\r\n" 1617 "Content-length: 0\r\n" 1618 "\r\n") 1619 1620 self.assertEqual(self.transport.value(), '') 1621 1622 return d 1623 1624 1625 def test_expect100ContinueGet100Continue(self): 1626 """ 1627 When we expect 100-Continue and get an 100-Continue L{Response} we send 1628 the L{Request} body and return the second L{Response} to the user. 1629 """ 1630 d = self._send100ContinueRequest('x' * 10) 1631 1632 def cbResponse(response): 1633 self.assertEqual(response.code, 200) 1634 1635 d.addCallback(cbResponse) 1636 1637 self.protocol.dataReceived( 1638 "HTTP/1.1 100 Continue\r\n" 1639 "Content-Length: 3\r\n" 1640 "\r\n" 1641 "123") 1642 1643 self.protocol.dataReceived( 1644 "HTTP/1.1 200 OK\r\n" 1645 "Content-Length: 0\r\n" 1646 "\r\n") 1647 1648 self.assertEqual(self.transport.value(), 'x' * 10) 1649 1650 return d 1651 1652 1653 def test_expect100ContinueGet100ContinueBackToBack(self): 1654 """ 1655 When we expect 100-Continue and we get 2 response back to back (100 and 1656 final status) we should act as if they came separately. 1657 """ 1658 d = self._send100ContinueRequest('x' * 10) 1659 1660 def cbResponse(response): 1661 self.assertEqual(response.code, 200) 1662 1663 d.addCallback(cbResponse) 1664 1665 self.protocol.dataReceived( 1666 "HTTP/1.1 100 Continue\r\n" 1667 "Content-Length: 3\r\n" 1668 "\r\n" 1669 "123" 1670 "HTTP/1.1 200 OK\r\n" 1671 "Content-Length: 0\r\n" 1672 "\r\n") 1673 1674 self.assertEqual(self.transport.value(), 'x' * 10) 1675 1676 return d 1677 1678 1679 def test_expect100ContinueServerBroken(self): 1680 """ 1681 When we expect 100-Continue and the server is broken and waits for the 1682 L{Request} body we wait for a limited amount and then send the body. 1683 """ 1684 d = self._send100ContinueRequest('x' * 10) 1685 1686 def cbResponse(response): 1687 self.assertEqual(response.code, 200) 1688 1689 d.addCallback(cbResponse) 1690 1691 self.clock.advance(TIMEOUT_100_CONTINUE + 1) 1692 1693 self.assertEqual(self.transport.value(), 'x' * 10) 1694 1695 self.protocol.dataReceived( 1696 "HTTP/1.1 200 OK\r\n" 1697 "Content-Length: 0\r\n" 1698 "\r\n") 1699 1700 return d 1701 1702 1703 def test_expect100ContinueTimerFiresLate100ContinueResponse(self): 1704 """ 1705 When we expect 100-Continue and the server is slow and sends an 1706 100-Continue after we sent the body we consume the 100-Continue 1707 L{Response} and return the second L{Response} to the user. 1708 """ 1709 d = self._send100ContinueRequest('x' * 10) 1710 1711 def cbResponse(response): 1712 self.assertEqual(response.code, 200) 1713 1714 d.addCallback(cbResponse) 1715 1716 self.clock.advance(TIMEOUT_100_CONTINUE + 1) 1717 1718 self.assertEqual(self.transport.value(), 'x' * 10) 1719 1720 self.protocol.dataReceived( 1721 "HTTP/1.1 100 Continue\r\n" 1722 "Content-length: 3\r\n" 1723 "\r\n" 1724 "123") 1725 1726 self.protocol.dataReceived( 1727 "HTTP/1.1 200 OK\r\n" 1728 "Content-length: 0\r\n" 1729 "\r\n") 1730 1731 return d 1732 1733 1734 _garbageResponse = "unparseable garbage goes here\r\n" 1735 1736 1737 def test_expect100ContinueBrokenFirstResponse(self): 1738 """ 1739 When we expect 100-Continue and the first L{Response} is broken, return 1740 the error to the user. 1741 """ 1742 d = self._send100ContinueRequest('x' * 10) 1743 1744 self.protocol.dataReceived(self._garbageResponse) 1745 1746 self.assertEqual(self.transport.value(), '') 1747 1748 return assertResponseFailed(self, d, [ParseError]) 1749 1750 1751 def test_expect100ContinueBrokenFirstResponseChunkedBody(self): 1752 """ 1753 When we expect 100-Continue and the 100-Continue L{Response} has a 1754 chunked body and it is broken, return the error to the user. 1755 """ 1756 d = self._send100ContinueRequest('x' * 10) 1757 1758 self.protocol.dataReceived( 1759 "HTTP/1.1 100 Continue\r\n" 1760 "Transfer-Encoding: chunked\r\n" 1761 "\r\n") 1762 1763 self.protocol.dataReceived("3\r\nzzz\r\n") 1764 self.protocol.dataReceived("3\r\nzzz\r\nzzz\r\n") #incorrect chunk 1765 1766 self.assertEqual(self.transport.value(), '') 1767 1768 return assertResponseFailed(self, d, [ValueError, _DataLoss]) 1769 1770 1771 def test_expect100ContinueBrokenSecondResponse(self): 1772 """ 1773 When we expect 100-Continue and the 100-Continue L{Response} is ok but 1774 the second L{Response} is broken, return the error to the user. 1775 """ 1776 d = self._send100ContinueRequest('x' * 10) 1777 1778 self.protocol.dataReceived( 1779 "HTTP/1.1 100 Continue\r\n" 1780 "Content-length: 3\r\n" 1781 "\r\n" 1782 "123") 1783 1784 self.protocol.dataReceived(self._garbageResponse) 1785 1786 self.assertEqual(self.transport.value(), 'x' * 10) 1787 1788 return assertResponseFailed(self, d, [ParseError]) 1789 1790 1791 def _setupForQuiescent(self): 1792 self.quiescentResult = [] 1793 1794 def callback(p): 1795 self.assertEqual(p, self.protocol) 1796 self.assertEqual(p.state, "QUIESCENT") 1797 self.quiescentResult.append(p) 1798 1799 self.transport = StringTransport() 1800 self.clock = Clock() 1801 self.protocol = HTTP11ClientProtocol(callback, reactor=self.clock) 1802 self.protocol.makeConnection(self.transport) 1803 1804 1805 def _checkQuiescentCalled(self, requestDeferred, body=''): 1806 # Headers done, but still no quiescent callback: 1807 self.assertEqual(self.quiescentResult, []) 1808 1809 result = [] 1810 requestDeferred.addCallback(result.append) 1811 response = result[0] 1812 1813 # When response body is done (i.e. connectionLost is called), note the 1814 # fact in quiescentResult: 1815 bodyProtocol = AccumulatingProtocol() 1816 bodyProtocol.closedDeferred = Deferred() 1817 bodyProtocol.closedDeferred.addCallback( 1818 lambda ign: self.quiescentResult.append("response done")) 1819 1820 response.deliverBody(bodyProtocol) 1821 self.protocol.dataReceived(body) 1822 bodyProtocol.closedReason.trap(ResponseDone) 1823 # Quiescent callback called *before* self.protocol handling the response 1824 # body gets its connectionLost called: 1825 self.assertEqual(self.quiescentResult, [self.protocol, "response done"]) 1826 1827 # Make sure everything was cleaned up: 1828 self.assertEqual(self.protocol._parser, None) 1829 self.assertEqual(self.protocol._finishedRequest, None) 1830 self.assertEqual(self.protocol._currentRequest, None) 1831 self.assertEqual(self.protocol._transportProxy, None) 1832 self.assertEqual(self.protocol._responseDeferred, None) 1833 1834 1835 def test_expect100ContinueGot100ContinueQuiescentCallbackCalled(self): 1836 """ 1837 We have a persistent connection and we expect 100-Continue. When we 1838 get an 100-Continue L{Response} the quiescent callback needs to be 1839 called. 1840 """ 1841 self._setupForQuiescent() 1842 1843 d = self._send100ContinueRequest('x' * 10, persistent=True) 1844 1845 def cbResponse(response): 1846 self.assertEqual(response.code, 200) 1847 return response 1848 1849 d.addCallback(cbResponse) 1850 1851 self.protocol.dataReceived( 1852 "HTTP/1.1 100 Continue\r\n" 1853 "Content-Length: 3\r\n" 1854 "\r\n" 1855 "123") 1856 1857 self.protocol.dataReceived( 1858 "HTTP/1.1 200 OK\r\n" 1859 "Content-Length: 3\r\n" 1860 "\r\n") 1861 1862 self._checkQuiescentCalled(d, body="abc") 1863 1864 self.assertEqual(self.transport.value(), 'x' * 10) 1865 1866 return d 1867 1868 1869 def test_expect100ContinueGotFinalStatusQuiescentCallbackCalled(self): 1870 """ 1871 We have a persistent connection and we expect 100-Continue. When we 1872 get a L{Response} with a final status the quiescent callback needs to 1873 be called. 1874 """ 1875 self._setupForQuiescent() 1876 1877 d = self._send100ContinueRequest('x' * 10, persistent=True) 1878 1879 def cbResponse(response): 1880 self.assertEqual(response.code, 200) 1881 return response 1882 1883 d.addCallback(cbResponse) 1884 1885 self.protocol.dataReceived( 1886 "HTTP/1.1 200 OK\r\n" 1887 "Content-Length: 3\r\n" 1888 "\r\n") 1889 1890 self._checkQuiescentCalled(d, body='abc') 1891 1892 self.assertEqual(self.transport.value(), '') 1893 1894 return d 1895 1896 1897 def test_expect100ContinueConnectionLostWhileWaitingFirstResponse(self): 1898 """ 1899 When we expect 100-Continue and we get disconnected while waiting for 1900 the first L{Response}, the L{Deferred} return by request() must errback 1901 a ResponseFailed wrapping the underlying failure. 1902 """ 1903 d = self._send100ContinueRequest('x' * 10) 1904 1905 self.assertEqual(self.transport.value(), '') 1906 1907 self.protocol.connectionLost(Failure(ArbitraryException())) 1908 1909 self.assertEqual(self.protocol._state, 'CONNECTION_LOST') 1910 1911 return assertResponseFailed( 1912 self, d, [ArbitraryException]) 1913 1914 1915 def test_expect100ContinueConnectionLostWhileWaitingFirstResponseBody(self): 1916 """ 1917 When we expect 100-Continue and we get an 100-Continue L{Response} 1918 and we get disconnected while waiting for its body, the L{Deferred} 1919 returned by request() must errback a ResponseFailed wrapping the 1920 underlying failure. 1921 """ 1922 d = self._send100ContinueRequest('x' * 10) 1923 1924 self.assertEqual(self.transport.value(), '') 1925 1926 self.protocol.dataReceived( 1927 "HTTP/1.1 100 Continue\r\n" 1928 "Content-length: 10\r\n" 1929 "\r\n") 1930 1931 self.protocol.connectionLost(Failure(ArbitraryException())) 1932 1933 self.assertEqual(self.protocol._state, 'CONNECTION_LOST') 1934 1935 return assertResponseFailed( 1936 self, d, [ArbitraryException, _DataLoss]) 1937 1938 1570 1939 class StringProducer: 1571 1940 """ 1572 1941 L{StringProducer} is a dummy body producer.
