producers.py :  » Web-Frameworks » Zope » Zope-2.6.0 » ZServer » medusa » Python Open Source

Home
Python Open Source
1.3.1.2 Python
2.Ajax
3.Aspect Oriented
4.Blog
5.Build
6.Business Application
7.Chart Report
8.Content Management Systems
9.Cryptographic
10.Database
11.Development
12.Editor
13.Email
14.ERP
15.Game 2D 3D
16.GIS
17.GUI
18.IDE
19.Installer
20.IRC
21.Issue Tracker
22.Language Interface
23.Log
24.Math
25.Media Sound Audio
26.Mobile
27.Network
28.Parser
29.PDF
30.Project Management
31.RSS
32.Search
33.Security
34.Template Engines
35.Test
36.UML
37.USB Serial
38.Web Frameworks
39.Web Server
40.Web Services
41.Web Unit
42.Wiki
43.Windows
44.XML
Python Open Source » Web Frameworks » Zope 
Zope » Zope 2.6.0 » ZServer » medusa » producers.py
# -*- Mode: Python; tab-width: 4 -*-

RCS_ID = '$Id: producers.py,v 1.10 2001/05/01 11:44:48 andreas Exp $'

import string

"""
A collection of producers.
Each producer implements a particular feature:  They can be combined
in various ways to get interesting and useful behaviors.

For example, you can feed dynamically-produced output into the compressing
producer, then wrap this with the 'chunked' transfer-encoding producer.
"""

class simple_producer:
    "producer for a string"
    def __init__ (self, data, buffer_size=1024):
        self.data = data
        self.buffer_size = buffer_size
        
    def more (self):
        if len (self.data) > self.buffer_size:
            result = self.data[:self.buffer_size]
            self.data = self.data[self.buffer_size:]
            return result
        else:
            result = self.data
            self.data = ''
            return result
            
class scanning_producer:
    "like simple_producer, but more efficient for large strings"
    def __init__ (self, data, buffer_size=1024):
        self.data = data
        self.buffer_size = buffer_size
        self.pos = 0
        
    def more (self):
        if self.pos < len(self.data):
            lp = self.pos
            rp = min (
                    len(self.data),
                    self.pos + self.buffer_size
                    )
            result = self.data[lp:rp]
            self.pos = self.pos + len(result)
            return result
        else:
            return ''
            
class lines_producer:
    "producer for a list of lines"
    
    def __init__ (self, lines):
        self.lines = lines
        
    def ready (self):
        return len(self.lines)
        
    def more (self):
        if self.lines:
            chunk = self.lines[:50]
            self.lines = self.lines[50:]
            return string.join (chunk, '\r\n') + '\r\n'
        else:
            return ''
            
class buffer_list_producer:
    "producer for a list of buffers"
    
    # i.e., data == string.join (buffers, '')
    
    def __init__ (self, buffers):
    
        self.index = 0
        self.buffers = buffers
        
    def more (self):
        if self.index >= len(self.buffers):
            return ''
        else:
            data = self.buffers[self.index]
            self.index = self.index + 1
            return data
            
class file_producer:
    "producer wrapper for file[-like] objects"
    
    # match http_channel's outgoing buffer size
    out_buffer_size = 1<<16
    
    def __init__ (self, file):
        self.done = 0
        self.file = file
        
    def more (self):
        if self.done:
            return ''
        else:
            data = self.file.read (self.out_buffer_size)
            if not data:
                self.file.close()
                del self.file
                self.done = 1
                return ''
            else:
                return data
                
                # A simple output producer.  This one does not [yet] have
                # the safety feature builtin to the monitor channel:  runaway
                # output will not be caught.
                
                # don't try to print from within any of the methods
                # of this object.
                
class output_producer:
    "Acts like an output file; suitable for capturing sys.stdout"
    def __init__ (self):
        self.data = ''
        
    def write (self, data):
        lines = string.splitfields (data, '\n')
        data = string.join (lines, '\r\n')
        self.data = self.data + data
        
    def writeline (self, line):
        self.data = self.data + line + '\r\n'
        
    def writelines (self, lines):
        self.data = self.data + string.joinfields (
                lines,
                '\r\n'
                ) + '\r\n'
        
    def ready (self):
        return (len (self.data) > 0)
        
    def flush (self):
        pass
        
    def softspace (self, *args):
        pass
        
    def more (self):
        if self.data:
            result = self.data[:512]
            self.data = self.data[512:]
            return result
        else:
            return ''
            
class composite_producer:
    "combine a fifo of producers into one"
    def __init__ (self, producers):
        self.producers = producers
        
    def more (self):
        while len(self.producers):
            p = self.producers.first()
            d = p.more()
            if d:
                return d
            else:
                self.producers.pop()
        else:
            return ''
            
            
class globbing_producer:
    """
    'glob' the output from a producer into a particular buffer size.
    helps reduce the number of calls to send().  [this appears to
    gain about 30% performance on requests to a single channel]
    """
    
    def __init__ (self, producer, buffer_size=1<<16):
        self.producer = producer
        self.buffer = ''
        self.buffer_size = buffer_size
        
    def more (self):
        while len(self.buffer) < self.buffer_size:
            data = self.producer.more()
            if data:
                self.buffer = self.buffer + data
            else:
                break
        r = self.buffer
        self.buffer = ''
        return r
        
        
class hooked_producer:
    """
    A producer that will call <function> when it empties,.
    with an argument of the number of bytes produced.  Useful
    for logging/instrumentation purposes.
    """
    
    def __init__ (self, producer, function):
        self.producer = producer
        self.function = function
        self.bytes = 0
        
    def more (self):
        if self.producer:
            result = self.producer.more()
            if not result:
                self.producer = None
                self.function (self.bytes)
            else:
                self.bytes = self.bytes + len(result)
            return result
        else:
            return ''
            
            # HTTP 1.1 emphasizes that an advertised Content-Length header MUST be
            # correct.  In the face of Strange Files, it is conceivable that
            # reading a 'file' may produce an amount of data not matching that
            # reported by os.stat() [text/binary mode issues, perhaps the file is
            # being appended to, etc..]  This makes the chunked encoding a True
            # Blessing, and it really ought to be used even with normal files.
            # How beautifully it blends with the concept of the producer.
            
class chunked_producer:
    """A producer that implements the 'chunked' transfer coding for HTTP/1.1.
    Here is a sample usage:
            request['Transfer-Encoding'] = 'chunked'
            request.push (
                    producers.chunked_producer (your_producer)
                    )
            request.done()
    """
    
    def __init__ (self, producer, footers=None):
        self.producer = producer
        self.footers = footers
        
    def more (self):
        if self.producer:
            data = self.producer.more()
            if data:
                return '%x\r\n%s\r\n' % (len(data), data)
            else:
                self.producer = None
                if self.footers:
                    return string.join (
                            ['0'] + self.footers,
                            '\r\n'
                            ) + '\r\n\r\n'
                else:
                    return '0\r\n\r\n'
        else:
            return ''
            
            # Unfortunately this isn't very useful right now (Aug 97), because
            # apparently the browsers don't do on-the-fly decompression.  Which
            # is sad, because this could _really_ speed things up, especially for
            # low-bandwidth clients (i.e., most everyone).
            
try:
    import zlib
except ImportError:
    zlib = None
    
class compressed_producer:
    """
    Compress another producer on-the-fly, using ZLIB
    [Unfortunately, none of the current browsers seem to support this]
    """
    
    # Note: It's not very efficient to have the server repeatedly
    # compressing your outgoing files: compress them ahead of time, or
    # use a compress-once-and-store scheme.  However, if you have low
    # bandwidth and low traffic, this may make more sense than
    # maintaining your source files compressed.
    #
    # Can also be used for compressing dynamically-produced output.
    
    def __init__ (self, producer, level=5):
        self.producer = producer
        self.compressor = zlib.compressobj (level)
        
    def more (self):
        if self.producer:
            cdata = ''
            # feed until we get some output
            while not cdata:
                data = self.producer.more()
                if not data:
                    self.producer = None
                    return self.compressor.flush()
                else:
                    cdata = self.compressor.compress (data)
            return cdata
        else:
            return ''
            
class escaping_producer:

    "A producer that escapes a sequence of characters"
    " Common usage: escaping the CRLF.CRLF sequence in SMTP, NNTP, etc..."
    
    def __init__ (self, producer, esc_from='\r\n.', esc_to='\r\n..'):
        self.producer = producer
        self.esc_from = esc_from
        self.esc_to = esc_to
        self.buffer = ''
        from asynchat import find_prefix_at_end
        self.find_prefix_at_end = find_prefix_at_end
        
    def more (self):
        esc_from = self.esc_from
        esc_to   = self.esc_to
        
        buffer = self.buffer + self.producer.more()
        
        if buffer:
            buffer = string.replace (buffer, esc_from, esc_to)
            i = self.find_prefix_at_end (buffer, esc_from)
            if i:
                    # we found a prefix
                self.buffer = buffer[-i:]
                return buffer[:-i]
            else:
                    # no prefix, return it all
                self.buffer = ''
                return buffer
        else:
            return buffer
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.