Ticket #6104: get-page-cancel.diff

File get-page-cancel.diff, 6.0 KB (added by luks, 22 months ago)
  • twisted/web/client.py

    === modified file 'twisted/web/client.py'
     
    311311    def __init__(self, url, method='GET', postdata=None, headers=None, 
    312312                 agent="Twisted PageGetter", timeout=0, cookies=None, 
    313313                 followRedirect=True, redirectLimit=20, 
    314                  afterFoundGet=False): 
     314                 afterFoundGet=False, canceller=None): 
    315315        self.followRedirect = followRedirect 
    316316        self.redirectLimit = redirectLimit 
    317317        self._redirectCount = 0 
     
    336336 
    337337        self.waiting = 1 
    338338        self._disconnectedDeferred = defer.Deferred() 
    339         self.deferred = defer.Deferred() 
     339        self.deferred = defer.Deferred(canceller) 
    340340        # Make sure the first callback on the result Deferred pauses the 
    341341        # callback chain until the request connection is closed. 
    342342        self.deferred.addBoth(self._waitForDisconnect) 
     
    408408        result has yet been provided to the result Deferred, provide the 
    409409        connection failure reason as an error result. 
    410410        """ 
    411         if self.waiting: 
    412             self.waiting = 0 
    413             # If the connection attempt failed, there is nothing more to 
    414             # disconnect, so just fire that Deferred now. 
    415             self._disconnectedDeferred.callback(None) 
    416             self.deferred.errback(reason) 
     411        self.noPage(reason) 
     412        # If the connection attempt failed, there is nothing more to 
     413        # disconnect, so just fire that Deferred now. 
     414        self._disconnectedDeferred.callback(None) 
    417415 
    418416 
    419417 
     
    427425                 method='GET', postdata=None, headers=None, 
    428426                 agent="Twisted client", supportPartial=0, 
    429427                 timeout=0, cookies=None, followRedirect=1, 
    430                  redirectLimit=20, afterFoundGet=False): 
     428                 redirectLimit=20, afterFoundGet=False, 
     429                 canceller=None): 
    431430        self.requestedPartial = 0 
    432431        if isinstance(fileOrName, types.StringTypes): 
    433432            self.fileName = fileOrName 
     
    445444            self, url, method=method, postdata=postdata, headers=headers, 
    446445            agent=agent, timeout=timeout, cookies=cookies, 
    447446            followRedirect=followRedirect, redirectLimit=redirectLimit, 
    448             afterFoundGet=afterFoundGet) 
     447            afterFoundGet=afterFoundGet, canceller=canceller) 
    449448 
    450449 
    451450    def gotHeaders(self, headers): 
     
    596595 
    597596    @return: The factory created by C{factoryFactory} 
    598597    """ 
     598    def cancel(d): 
     599        factory.noPage(defer.CancelledError()) 
     600        connector.disconnect() 
    599601    scheme, host, port, path = _parse(url) 
    600     factory = factoryFactory(url, *args, **kwargs) 
     602    factory = factoryFactory(url, canceller=cancel, *args, **kwargs) 
    601603    if scheme == 'https': 
    602604        from twisted.internet import ssl 
    603605        if contextFactory is None: 
    604606            contextFactory = ssl.ClientContextFactory() 
    605         reactor.connectSSL(host, port, factory, contextFactory) 
     607        connector = reactor.connectSSL(host, port, factory, contextFactory) 
    606608    else: 
    607         reactor.connectTCP(host, port, factory) 
     609        connector = reactor.connectTCP(host, port, factory) 
    608610    return factory 
    609611 
    610612 
     
    615617    Download a page. Return a deferred, which will callback with a 
    616618    page (as a string) or errback with a description of the error. 
    617619 
     620    If the deferred is cancelled before the request completes, the 
     621    connection is closed and the deferred will fire with a 
     622    L{defer.CancelledError}. 
     623 
    618624    See L{HTTPClientFactory} to see what extra arguments can be passed. 
    619625    """ 
    620626    return _makeGetterFactory( 
     
    628634    """ 
    629635    Download a web page to a file. 
    630636 
     637    Download a page. Return a deferred, which will callback with None 
     638    or errback with a description of the error. 
     639 
     640    If the deferred is cancelled before the request completes, the 
     641    connection is closed and the deferred will fire with a 
     642    L{defer.CancelledError}. 
     643 
    631644    @param file: path to file on filesystem, or file-like object. 
    632645 
    633     See HTTPDownloader to see what extra args can be passed. 
     646    See L{HTTPDownloader} to see what extra args can be passed. 
    634647    """ 
    635648    factoryFactory = lambda url, *a, **kw: HTTPDownloader(url, file, *a, **kw) 
    636649    return _makeGetterFactory( 
  • twisted/web/test/test_webclient.py

    === modified file 'twisted/web/test/test_webclient.py'
     
    507507            defer.TimeoutError) 
    508508 
    509509 
     510    def test_getPageCancelImmediately(self): 
     511        """ 
     512        Call L{getPage} and cancel it before it has chance to try to 
     513        connect to the server. The L{Deferred} returned by L{getPage} 
     514        fails with L{defer.CancelledError}. 
     515        """ 
     516        d = client.getPage(self.getURL("wait"), timeout=10) 
     517        d.cancel() 
     518        return self.assertFailure(d, defer.CancelledError) 
     519 
     520 
     521    def test_getPageCancelLater(self): 
     522        """ 
     523        Call L{getPage} and cancel it after it has connected to the server, 
     524        but before it was able to deliver the results. The L{Deferred} 
     525        returned by L{getPage} fails with L{defer.CancelledError}. 
     526        """ 
     527        d = client.getPage(self.getURL("wait"), timeout=10) 
     528        reactor.callLater(0.01, d.cancel) 
     529        return self.assertFailure(d, defer.CancelledError) 
     530 
     531 
     532    def test_getPageCancelAfter(self): 
     533        """ 
     534        Call L{getPage} and attempt to cancel it after it has delivered 
     535        the results. The cancellation is ignored and the L{Deferred} 
     536        returned by L{getPage} is called back with the page contents. 
     537        """ 
     538        d = client.getPage(self.getURL("file")) 
     539        def cancelRequest(content): 
     540            d.cancel() 
     541            return content 
     542        d.addCallback(cancelRequest) 
     543        d.addCallback(self.assertEqual, "0123456789") 
     544        return d 
     545 
     546 
    510547    def testDownloadPage(self): 
    511548        downloads = [] 
    512549        downloadData = [("file", self.mktemp(), "0123456789"),