Files
uwsgi/contrib/twuwsgi.py
T

120 lines
3.9 KiB
Python

from twisted.internet import defer, protocol, reactor
from twisted.protocols import basic
from twisted.web2 import server, http, resource, responsecode, stream, channel
from twisted.application import service, strports
import struct
class uWSGIClientResource(resource.LeafResource):
def __init__(self,app='', port=3030, host='localhost'):
resource.LeafResource.__init__(self)
self.host = host
self.port = port
self.app = app
def renderHTTP(self, request):
return uWSGI(request, self.app, self.host, self.port)
def uWSGI(request, app, host, port):
if request.stream.length is None:
return http.Response(responsecode.LENGTH_REQUIRED)
request.uwsgi_app = app
factory = uWSGIClientProtocolFactory(request)
reactor.connectTCP(host, port, factory)
return factory.deferred
class uWSGIClientProtocol(basic.LineReceiver):
def __init__(self, request, deferred):
self.request = request
self.deferred = deferred
self.stream = stream.ProducerStream()
self.response = http.Response(stream=self.stream)
self.status_parsed = None
def build_uwsgi_var(self,key,value):
return struct.pack('<H',len(key)) + key + struct.pack('<H',len(value)) + value
def connectionMade(self):
print self.request.__dict__
# reset response parser
self.status_parsed = None
# build header and vars
vars = ''
if self.request.stream.length:
vars += self.build_uwsgi_var('CONTENT_LENGTH',str(self.request.stream.length))
for hkey, hval in self.request.headers.getAllRawHeaders():
# use a list, probably it will be extended
if hkey.lower() not in ('content-type'):
vars += self.build_uwsgi_var('HTTP_'+hkey.upper().replace('-','_'),','.join(hval))
else:
vars += self.build_uwsgi_var(hkey.upper().replace('-','_'),','.join(hval))
vars += self.build_uwsgi_var('REQUEST_METHOD', self.request.method)
vars += self.build_uwsgi_var('SCRIPT_NAME', self.request.uwsgi_app)
vars += self.build_uwsgi_var('PATH_INFO', self.request.path[len(self.request.uwsgi_app):])
vars += self.build_uwsgi_var('QUERY_STRING', self.request.querystring)
vars += self.build_uwsgi_var('SERVER_NAME', self.request.host)
vars += self.build_uwsgi_var('SERVER_PORT', str(self.request.port))
vars += self.build_uwsgi_var('SERVER_PROTOCOL', self.request.scheme.upper()+'/'+str(self.request.clientproto[0]) +'.'+str(self.request.clientproto[1]))
vars += self.build_uwsgi_var('REQUEST_URI', self.request.uri)
vars += self.build_uwsgi_var('REMOTE_ADDR', self.request.remoteAddr.host)
self.transport.write(struct.pack('<BHB',0, len(vars),0))
self.transport.write(vars)
# send request data
stream.StreamProducer(self.request.stream).beginProducing(self.transport)
def lineReceived(self, line):
if self.status_parsed is None:
self.response.code = line.split(' ',2)[1]
self.status_parsed = True
return
# end of headers
if line == '':
self.setRawMode()
self.deferred.callback(self.response)
self.response = None
return
name, value = line.split(':',1)
value = value.strip()
self.response.headers.addRawHeader(name, value)
def rawDataReceived(self, data):
self.stream.write(data)
def connectionLost(self, reason):
self.stream.finish()
class uWSGIClientProtocolFactory(protocol.ClientFactory):
protocol = uWSGIClientProtocol
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)