summaryrefslogtreecommitdiff
path: root/contrib/twuwsgi.py
blob: a20400c05b3ab752835b3bcb9cb1b6649b173293 (plain)
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
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)