This file is indexed.

/usr/share/pyshared/twisted/web2/twscgi.py is in python-twisted-web2 8.1.0-3build1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
"""SCGI client resource and protocols.
"""

# TODO:
#   * Handle scgi server death, half way through a resonse.


from zope.interface import implements
from twisted.internet import defer, protocol, reactor
from twisted.protocols import basic
from twisted.web2 import http, iweb, resource, responsecode, stream, twcgi


class SCGIClientResource(resource.LeafResource):
    """A resource that connects to an SCGI server and relays the server's
    response to the browser.
    
    This resource connects to a SCGI server on a known host ('localhost', by
    default) and port. It has no responsibility for starting the SCGI server.
    
    If the server is not running when a client connects then a BAD_GATEWAY
    response will be returned immediately.
    """
    
    def __init__(self, port, host='localhost'):
        """Initialise a SCGI client resource
        """
        resource.LeafResource.__init__(self)
        self.host = host
        self.port = port
    
    def renderHTTP(self, request):
        return doSCGI(request, self.host, self.port)

def doSCGI(request, host, port):
    if request.stream.length is None:
        return http.Response(responsecode.LENGTH_REQUIRED)
    factory = SCGIClientProtocolFactory(request)
    reactor.connectTCP(host, port, factory)
    return factory.deferred
    
class SCGIClientProtocol(basic.LineReceiver):
    """Protocol for talking to a SCGI server.
    """
    
    def __init__(self, request, deferred):
        self.request = request
        self.deferred = deferred
        self.stream = stream.ProducerStream()
        self.response = http.Response(stream=self.stream)

    def connectionMade(self):
        # Ooh, look someone did all the hard work for me :).
        env = twcgi.createCGIEnvironment(self.request)
        # Send the headers. The Content-Length header should always be sent
        # first and must be 0 if not present.
        # The whole lot is sent as one big netstring with each name and value
        # separated by a '\0'.
        contentLength = str(env.pop('CONTENT_LENGTH', 0))
        env['SCGI'] = '1'
        scgiHeaders = []
        scgiHeaders.append('%s\x00%s\x00'%('CONTENT_LENGTH', str(contentLength)))
        scgiHeaders.append('SCGI\x001\x00')
        for name, value in env.iteritems():
            if name in ('CONTENT_LENGTH', 'SCGI'):
                continue
            scgiHeaders.append('%s\x00%s\x00'%(name,value))
        scgiHeaders = ''.join(scgiHeaders)
        self.transport.write('%d:%s,' % (len(scgiHeaders), scgiHeaders))
        stream.StreamProducer(self.request.stream).beginProducing(self.transport)
        
    def lineReceived(self, line):
        # Look for end of headers
        if line == '':
            # Switch into raw mode to recieve data and callback the deferred
            # with the response instance. The data will be streamed as it
            # arrives.  Callback the deferred and set self.response to None,
            # because there are no promises that the response will not be
            # mutated by a resource higher in the tree, such as 
            # log.LogWrapperResource
            self.setRawMode()
            self.deferred.callback(self.response)
            self.response = None
            return

        # Split the header into name and value. The 'Status' header is handled
        # specially; all other headers are simply passed onto the response I'm
        # building.
        name, value = line.split(':',1)
        value = value.strip()
        if name.lower() == 'status':
            value = value.split(None,1)[0]
            self.response.code = int(value)
        else:
            self.response.headers.addRawHeader(name, value)
        
    def rawDataReceived(self, data):
        self.stream.write(data)
        
    def connectionLost(self, reason):
        # The connection is closed and all data has been streamed via the
        # response. Tell the response stream it's over.
        self.stream.finish()
    
    
class SCGIClientProtocolFactory(protocol.ClientFactory):
    """SCGI client protocol factory.
    
    I am created by a SCGIClientResource to connect to an SCGI server. When I
    connect I create a SCGIClientProtocol instance to do all the talking with
    the server.
    
    The ``deferred`` attribute is passed on to the protocol and is fired with
    the HTTP response from the server once it has been recieved.
    """
    protocol = SCGIClientProtocol
    noisy = False # Make Factory shut up
    
    def __init__(self, request):
        self.request = request
        self.deferred = defer.Deferred()
        
    def buildProtocol(self, addr):
        return self.protocol(self.request, self.deferred)
        
    def clientConnectionFailed(self, connector, reason):
        self.sendFailureResponse(reason)
        
    def sendFailureResponse(self, reason):
        response = http.Response(code=responsecode.BAD_GATEWAY, stream=str(reason.value))
        self.deferred.callback(response)
        
__all__ = ['SCGIClientResource']