############################################################################### # Copyright (c) 2011 Linaro # All rights reserved. This program and the accompanying materials # are made available under the terms of the Eclipse Public License v1.0 # which accompanies this distribution, and is available at # http://www.eclipse.org/legal/epl-v10.html ############################################################################### import re import urlparse from urllib import quote as urlquote from twisted.application import ( internet, service, ) from twisted.internet import reactor from twisted.web import ( proxy, rewrite, static, server, resource, ) class ReverseProxyResource(resource.Resource): proxyClientFactoryClass = proxy.ProxyClientFactory def __init__(self, host, port, path, reactor=reactor): resource.Resource.__init__(self) self.host = host self.port = port self.path = path self.reactor = reactor def getChild(self, path, request): """ Create and return a proxy resource with the same proxy configuration as this one, except that its path also contains the segment given by C{path} at the end. """ return ReverseProxyResource( self.host, self.port, self.path + '/' + urlquote(path, safe=""), self.reactor) def render(self, request): """ Render a request by forwarding it to the proxied server. """ # RFC 2616 tells us that we can omit the port if it's the default port, # but we have to provide it otherwise #if self.port == 80: # host = self.host #else: # host = "%s:%d" % (self.host, self.port) #request.received_headers['host'] = host request.content.seek(0, 0) qs = urlparse.urlparse(request.uri)[4] if qs: rest = self.path + '?' + qs else: rest = self.path clientFactory = self.proxyClientFactoryClass( request.method, rest, request.clientproto, request.getAllHeaders(), request.content.read(), request) self.reactor.connectTCP(self.host, self.port, clientFactory) return server.NOT_DONE_YET jenkins_proxy = ReverseProxyResource('localhost', 9090, '/jenkins') class OutputRedirectingResource(resource.Resource): def __init__(self, orig): resource.Resource.__init__(self) self.orig = orig def getChild(self, segment, request): path = '/'.join(request.prepath + request.postpath[:4]) m = re.match('^builds/~([a-z][-a-z0-9]+)/([-A-Za-z0-9_]+)/([0-9]+)/output', path) if m: request.prepath.extend(request.postpath[:3]) del request.postpath[:4] job_name = '%s_%s' % (m.group(1), m.group(2)) return ReverseProxyResource( 'localhost', 10102, '/' + job_name + '/builds/' + m.group(3) + '/archive') return self.orig.getChildWithDefault(segment, request) def render(request): return self.orig.render(request) django_proxy = ReverseProxyResource('localhost', 9000, '') static_root = static.File('static') root = django_proxy root.putChild('static', static_root) root.putChild('jenkins', jenkins_proxy) site = server.Site(root) application = service.Application("linaro-android-build demo") internet.TCPServer( 10101, server.Site(OutputRedirectingResource(root)) ).setServiceParent(application) internet.TCPServer( 10102, server.Site(static.File('/var/lib/hudson/jobs')) ).setServiceParent(application)