X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=apt_p2p%2FHTTPServer.py;h=f3d6de72525281df73660f35adc252f26d630414;hb=40ef1ce5ded865bc9c339d15e667e87fc5775a7c;hp=d252a6386aef205ed397e83579559eb2a33139db;hpb=7b1167d8ce780312d3689c9309c7e9c64060c085;p=quix0rs-apt-p2p.git diff --git a/apt_p2p/HTTPServer.py b/apt_p2p/HTTPServer.py index d252a63..f3d6de7 100644 --- a/apt_p2p/HTTPServer.py +++ b/apt_p2p/HTTPServer.py @@ -9,7 +9,7 @@ from twisted.internet import defer from twisted.web2 import server, http, resource, channel, stream from twisted.web2 import static, http_headers, responsecode -from policies import ThrottlingFactory +from policies import ThrottlingFactory, ThrottlingProtocol, ProtocolWrapper from apt_p2p_Khashmir.bencode import bencode class FileDownloader(static.File): @@ -56,7 +56,7 @@ class FileDownloader(static.File): class FileUploaderStream(stream.FileStream): """Modified to make it suitable for streaming to peers. - Streams the file is small chunks to make it easier to throttle the + Streams the file in small chunks to make it easier to throttle the streaming to peers. @ivar CHUNK_SIZE: the size of chunks of data to send at a time @@ -127,6 +127,31 @@ class FileUploader(static.File): return response +class UploadThrottlingProtocol(ThrottlingProtocol): + """Protocol for throttling uploads. + + Determines whether or not to throttle the upload based on the type of stream. + Uploads use L{FileUploaderStream} or L{twisted.web2.stream.MemorySTream}, + apt uses L{CacheManager.ProxyFileStream} or L{twisted.web.stream.FileStream}. + """ + + def __init__(self, factory, wrappedProtocol): + ThrottlingProtocol.__init__(self, factory, wrappedProtocol) + self.throttle = False + + def write(self, data): + if self.throttle: + ThrottlingProtocol.write(self, data) + else: + ProtocolWrapper.write(self, data) + + def registerProducer(self, producer, streaming): + ThrottlingProtocol.registerProducer(self, producer, streaming) + streamType = getattr(producer, 'stream', None) + if isinstance(streamType, FileUploaderStream) or isinstance(streamType, stream.MemoryStream): + self.throttle = True + + class TopLevel(resource.Resource): """The HTTP server for all requests, both from peers and apt. @@ -137,13 +162,12 @@ class TopLevel(resource.Resource): @type manager: L{apt_p2p.AptP2P} @ivar manager: the main program object to send requests to @type factory: L{twisted.web2.channel.HTTPFactory} or L{policies.ThrottlingFactory} - @ivar factory: the factory to use to server HTTP requests - + @ivar factory: the factory to use to serve HTTP requests """ addSlash = True - def __init__(self, directory, db, manager): + def __init__(self, directory, db, manager, uploadLimit): """Initialize the instance. @type directory: L{twisted.python.filepath.FilePath} @@ -156,6 +180,9 @@ class TopLevel(resource.Resource): self.directory = directory self.db = db self.manager = manager + self.uploadLimit = None + if uploadLimit > 0: + self.uploadLimit = int(uploadLimit*1024) self.factory = None def getHTTPFactory(self): @@ -164,7 +191,8 @@ class TopLevel(resource.Resource): self.factory = channel.HTTPFactory(server.Site(self), **{'maxPipeline': 10, 'betweenRequestsTimeOut': 60}) - self.factory = ThrottlingFactory(self.factory, writeLimit = 30*1024) + self.factory = ThrottlingFactory(self.factory, writeLimit = self.uploadLimit) + self.factory.protocol = UploadThrottlingProtocol return self.factory def render(self, ctx): @@ -172,9 +200,7 @@ class TopLevel(resource.Resource): return http.Response( 200, {'content-type': http_headers.MimeType('text', 'html')}, - """ -

Statistics

-

TODO: eventually some stats will be shown here.""") + self.manager.getStats()) def locateChild(self, request, segments): """Process the incoming request.""" @@ -188,7 +214,8 @@ class TopLevel(resource.Resource): return None, () # Find the file in the database - hash = unquote_plus(segments[1]) + # Have to unquote_plus the uri, because the segments are unquoted by twisted + hash = unquote_plus(request.uri[3:]) files = self.db.lookupHash(hash) if files: # If it is a file, return it @@ -200,13 +227,17 @@ class TopLevel(resource.Resource): log.msg('Sending torrent string %s to %s' % (b2a_hex(hash), request.remoteAddr)) return static.Data(bencode({'t': files[0]['pieces']}), 'application/x-bencoded'), () else: - log.msg('Hash could not be found in database: %s' % hash) + log.msg('Hash could not be found in database: %r' % hash) # Only local requests (apt) get past this point if request.remoteAddr.host != "127.0.0.1": log.msg('Blocked illegal access to %s from %s' % (request.uri, request.remoteAddr)) return None, () - + + # Block access to index .diff files (for now) + if 'Packages.diff' in segments or 'Sources.diff' in segments: + return None, () + if len(name) > 1: # It's a request from apt return FileDownloader(self.directory.path, self.manager), segments[0:] @@ -232,7 +263,7 @@ if __name__ == '__builtin__': return [{'pieces': 'abcdefghij0123456789\xca\xec\xb8\x0c\x00\xe7\x07\xf8~])\x8f\x9d\xe5_B\xff\x1a\xc4!'}] return [{'path': FilePath(os.path.expanduser('~/school/optout'))}] - t = TopLevel(FilePath(os.path.expanduser('~')), DB(), None) + t = TopLevel(FilePath(os.path.expanduser('~')), DB(), None, 0) factory = t.getHTTPFactory() # Standard twisted application Boilerplate