Commit fce5d8f0 authored by Amos Latteier's avatar Amos Latteier

Convert FTPResponse to use the same tricks as the HTTPResponse for returning...

Convert FTPResponse to use the same tricks as the HTTPResponse for returning large amounts of data without using too much memory.
parent 48364ffe
...@@ -86,17 +86,24 @@ ...@@ -86,17 +86,24 @@
Response class for the FTP Server. Response class for the FTP Server.
""" """
from ZPublisher.HTTPResponse import HTTPResponse from ZServer.HTTPResponse import ZServerHTTPResponse
from PubCore.ZEvent import Wakeup from PubCore.ZEvent import Wakeup
from cStringIO import StringIO from cStringIO import StringIO
import marshal import marshal
class FTPResponse(HTTPResponse): class FTPResponse(ZServerHTTPResponse):
""" """
Response to an FTP command Response to an FTP command
""" """
def __str__(self):
ZServerHTTPResponse.__str__(self)
return
def outputBody(self):
pass
def setCookie(self, name, value, **kw): def setCookie(self, name, value, **kw):
self.cookies[name]=value self.cookies[name]=value
...@@ -109,9 +116,6 @@ class FTPResponse(HTTPResponse): ...@@ -109,9 +116,6 @@ class FTPResponse(HTTPResponse):
def _cookie_list(self): def _cookie_list(self):
return [] return []
def _finish(self):
self.stdout.finish(self)
def _marshalledBody(self): def _marshalledBody(self):
return marshal.loads(self.body) return marshal.loads(self.body)
...@@ -124,13 +128,15 @@ class CallbackPipe: ...@@ -124,13 +128,15 @@ class CallbackPipe:
def __init__(self, callback, args): def __init__(self, callback, args):
self._callback=callback self._callback=callback
self._args=args self._args=args
self._producers=[]
def write(self, text):
pass
def close(self): def close(self):
pass pass
def write(self, text, l=None):
if text:
self._producers.append(text)
def finish(self, response): def finish(self, response):
self._response=response self._response=response
Wakeup(self.apply) # move callback to medusas thread Wakeup(self.apply) # move callback to medusas thread
...@@ -138,7 +144,7 @@ class CallbackPipe: ...@@ -138,7 +144,7 @@ class CallbackPipe:
def apply(self): def apply(self):
result=apply(self._callback, self._args+(self._response,)) result=apply(self._callback, self._args+(self._response,))
# is this necessary to break cycles? # break cycles
self._callback=None self._callback=None
self._response=None self._response=None
self._args=None self._args=None
......
...@@ -354,7 +354,11 @@ class zope_ftp_channel(ftp_channel): ...@@ -354,7 +354,11 @@ class zope_ftp_channel(ftp_channel):
status=response.getStatus() status=response.getStatus()
if status==200: if status==200:
self.make_xmit_channel() self.make_xmit_channel()
if not response._wrote:
self.client_dc.push(response.body) self.client_dc.push(response.body)
else:
for producer in response.stdout._producers:
self.client_dc.push_with_producer(producer)
self.client_dc.close_when_done() self.client_dc.close_when_done()
self.respond( self.respond(
"150 Opening %s mode data connection for file '%s'" % ( "150 Opening %s mode data connection for file '%s'" % (
......
...@@ -86,17 +86,24 @@ ...@@ -86,17 +86,24 @@
Response class for the FTP Server. Response class for the FTP Server.
""" """
from ZPublisher.HTTPResponse import HTTPResponse from ZServer.HTTPResponse import ZServerHTTPResponse
from PubCore.ZEvent import Wakeup from PubCore.ZEvent import Wakeup
from cStringIO import StringIO from cStringIO import StringIO
import marshal import marshal
class FTPResponse(HTTPResponse): class FTPResponse(ZServerHTTPResponse):
""" """
Response to an FTP command Response to an FTP command
""" """
def __str__(self):
ZServerHTTPResponse.__str__(self)
return
def outputBody(self):
pass
def setCookie(self, name, value, **kw): def setCookie(self, name, value, **kw):
self.cookies[name]=value self.cookies[name]=value
...@@ -109,9 +116,6 @@ class FTPResponse(HTTPResponse): ...@@ -109,9 +116,6 @@ class FTPResponse(HTTPResponse):
def _cookie_list(self): def _cookie_list(self):
return [] return []
def _finish(self):
self.stdout.finish(self)
def _marshalledBody(self): def _marshalledBody(self):
return marshal.loads(self.body) return marshal.loads(self.body)
...@@ -124,13 +128,15 @@ class CallbackPipe: ...@@ -124,13 +128,15 @@ class CallbackPipe:
def __init__(self, callback, args): def __init__(self, callback, args):
self._callback=callback self._callback=callback
self._args=args self._args=args
self._producers=[]
def write(self, text):
pass
def close(self): def close(self):
pass pass
def write(self, text, l=None):
if text:
self._producers.append(text)
def finish(self, response): def finish(self, response):
self._response=response self._response=response
Wakeup(self.apply) # move callback to medusas thread Wakeup(self.apply) # move callback to medusas thread
...@@ -138,7 +144,7 @@ class CallbackPipe: ...@@ -138,7 +144,7 @@ class CallbackPipe:
def apply(self): def apply(self):
result=apply(self._callback, self._args+(self._response,)) result=apply(self._callback, self._args+(self._response,))
# is this necessary to break cycles? # break cycles
self._callback=None self._callback=None
self._response=None self._response=None
self._args=None self._args=None
......
...@@ -354,7 +354,11 @@ class zope_ftp_channel(ftp_channel): ...@@ -354,7 +354,11 @@ class zope_ftp_channel(ftp_channel):
status=response.getStatus() status=response.getStatus()
if status==200: if status==200:
self.make_xmit_channel() self.make_xmit_channel()
if not response._wrote:
self.client_dc.push(response.body) self.client_dc.push(response.body)
else:
for producer in response.stdout._producers:
self.client_dc.push_with_producer(producer)
self.client_dc.close_when_done() self.client_dc.close_when_done()
self.respond( self.respond(
"150 Opening %s mode data connection for file '%s'" % ( "150 Opening %s mode data connection for file '%s'" % (
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment