def getChild(self, path, request): path = path.decode() log.debug("%s - %s" % (request.client.host, path)) resource = path.split('/')[0].encode() path = '/'.join(path.split('/')[1:]) host = '127.0.0.1' x_forwarded_for = request.client.host x_for_host = request.requestHeaders.getRawHeaders('host') x_for_host = x_for_host[0].split(':')[0] x_for_port = request.host.port if x_for_port == args.SSL_PORT: x_for_proto = "https" else: x_for_proto = "http" for header in [ ('X-Forwarded-For', x_forwarded_for), ('X-Forwarded-Host', x_for_host), ('X-Forwarded-Port', str(x_for_port)), ('X-Forwarded-Proto', x_for_proto), ]: request.requestHeaders.addRawHeader(*header) path = path.encode() if resource.startswith(b"webdav"): new_path = b'/%s' % (resource, ) if path: new_path += b'/%s' % path log.debug("Forwarding request to WebDAV server: %s" % path.decode()) return ReverseProxyResource(host, args.WEBDAV_PORT, new_path) else: log.debug("Forwarding request to Flask server") new_path = b'/%s' % (resource, ) if path: new_path += b'/%s' % path return ReverseProxyResource(host, args.FLASK_PORT, new_path)
def test_getChildWithSpecial(self): """ The L{ReverseProxyResource} return by C{getChild} has a path which has already been quoted. """ resource = ReverseProxyResource("127.0.0.1", 1234, "/path") child = resource.getChild(" /%", None) self.assertEqual(child.path, "/path/%20%2F%25")
def test_getChildWithSpecial(self): """ The L{ReverseProxyResource} return by C{getChild} has a path which has already been quoted. """ resource = ReverseProxyResource("127.0.0.1", 1234, b"/path") child = resource.getChild(b" /%", None) self.assertEqual(child.path, b"/path/%20%2F%25")
def __init__(self, host, port, path, forwarded_port=None, forwarded_proto=None): # host:port/path => target server self._forwarded_port = forwarded_port self._forwarded_proto = forwarded_proto ReverseProxyResource.__init__(self, host, port, path)
def test_getChild(self): """ The L{ReverseProxyResource.getChild} method should return a resource instance with the same class as the originating resource, forward port and host values, and update the path value with the value passed. """ resource = ReverseProxyResource("127.0.0.1", 1234, "/path") child = resource.getChild('foo', None) # The child should keep the same class self.assertIsInstance(child, ReverseProxyResource) self.assertEquals(child.path, "/path/foo") self.assertEquals(child.port, 1234) self.assertEquals(child.host, "127.0.0.1")
def test_getChild(self): """ The L{ReverseProxyResource.getChild} method should return a resource instance with the same class as the originating resource, forward port and host values, and update the path value with the value passed. """ resource = ReverseProxyResource("127.0.0.1", 1234, "/path") child = resource.getChild("foo", None) # The child should keep the same class self.assertIsInstance(child, ReverseProxyResource) self.assertEquals(child.path, "/path/foo") self.assertEquals(child.port, 1234) self.assertEquals(child.host, "127.0.0.1")
def __init__(self, server_pool, config=None, reactor=reactor): ReverseProxyResource.__init__(self, host="", port=80, path="", reactor=reactor) self.isLeaf = True self.server_pool = server_pool if config is None: config = DEFAULT_CONFIG else: aux = DEFAULT_CONFIG.copy() aux.update(config) config = aux self.config = config
def start_server(port, destport): revproxy = ReverseProxyResource("127.0.0.1", destport, "/blobs") resource = Resource() resource.putChild("", DummyResource()) resource.putChild("blobs", revproxy) site = Site(resource) reactor.listenTCP(port, site)
def _testRender(self, uri, expectedURI): """ Check that a request pointing at C{uri} produce a new proxy connection, with the path of this request pointing at C{expectedURI}. """ root = Resource() reactor = FakeReactor() resource = ReverseProxyResource("127.0.0.1", 1234, "/path", reactor) root.putChild('index', resource) site = Site(root) transport = StringTransportWithDisconnection() channel = site.buildProtocol(None) channel.makeConnection(transport) # Clear the timeout if the tests failed self.addCleanup(channel.connectionLost, None) channel.dataReceived("GET %s HTTP/1.1\r\nAccept: text/html\r\n\r\n" % (uri, )) # Check that one connection has been created, to the good host/port self.assertEquals(len(reactor.connect), 1) self.assertEquals(reactor.connect[0][0], "127.0.0.1") self.assertEquals(reactor.connect[0][1], 1234) # Check the factory passed to the connect, and its given path factory = reactor.connect[0][2] self.assertIsInstance(factory, ProxyClientFactory) self.assertEquals(factory.rest, expectedURI) self.assertEquals(factory.headers["host"], "127.0.0.1:1234")
def _testRender(self, uri, expectedURI): """ Check that a request pointing at C{uri} produce a new proxy connection, with the path of this request pointing at C{expectedURI}. """ root = Resource() reactor = MemoryReactor() resource = ReverseProxyResource("127.0.0.1", 1234, b"/path", reactor) root.putChild(b"index", resource) site = Site(root) transport = StringTransportWithDisconnection() channel = site.buildProtocol(None) channel.makeConnection(transport) # Clear the timeout if the tests failed self.addCleanup(channel.connectionLost, None) channel.dataReceived(b"GET " + uri + b" HTTP/1.1\r\nAccept: text/html\r\n\r\n") [(host, port, factory, _timeout, _bind_addr)] = reactor.tcpClients # Check that one connection has been created, to the good host/port self.assertEqual(host, "127.0.0.1") self.assertEqual(port, 1234) # Check the factory passed to the connect, and its given path self.assertIsInstance(factory, ProxyClientFactory) self.assertEqual(factory.rest, expectedURI) self.assertEqual(factory.headers[b"host"], b"127.0.0.1:1234")
def test_getChild(self): """ The L{ReverseProxyResource.getChild} method should return a resource instance with the same class as the originating resource, forward port, host, and reactor values, and update the path value with the value passed. """ reactor = MemoryReactor() resource = ReverseProxyResource("127.0.0.1", 1234, b"/path", reactor) child = resource.getChild(b"foo", None) # The child should keep the same class self.assertIsInstance(child, ReverseProxyResource) self.assertEqual(child.path, b"/path/foo") self.assertEqual(child.port, 1234) self.assertEqual(child.host, "127.0.0.1") self.assertIdentical(child.reactor, resource.reactor)
def test_getChild(self): """ The L{ReverseProxyResource.getChild} method should return a resource instance with the same class as the originating resource, forward port, host, and reactor values, and update the path value with the value passed. """ reactor = MemoryReactor() resource = ReverseProxyResource("127.0.0.1", 1234, "/path", reactor) child = resource.getChild('foo', None) # The child should keep the same class self.assertIsInstance(child, ReverseProxyResource) self.assertEqual(child.path, "/path/foo") self.assertEqual(child.port, 1234) self.assertEqual(child.host, "127.0.0.1") self.assertIdentical(child.reactor, resource.reactor)
def __init__(self, *arg, **kwarg): log.debug("WebProxy called") try: if 'remove' in kwarg.keys(): self.remove=int(kwarg['remove']) del kwarg['remove'] except: log.debug("error in remove") return ReverseProxyResource.__init__(self, *arg, **kwarg)
def create(transport, path, config): personality = transport.worker.personality personality.WEB_SERVICE_CHECKERS['reverseproxy'](personality, config) host = config['host'] port = int(config.get('port', 80)) resource = ReverseProxyResource(host, port, path) return RouterWebServiceReverseWeb(transport, path, config, resource)
def as_resource(self): # TODO there's a delay before gunicorn actually finishes starting; Do # Something in the meantime? if self.runner is not None and self.runner.failure_count > 0: return _app_failing elif self.runner_port is None: return _app_down else: self.log_request() return ReverseProxyResource('localhost', self.runner_port, self.mount_url)
def __init__(self, host, path, port=80, cache=None, pool_maxsize=4, downloader=None, filter_fun=None, reactor=reactor): path = path[:-1] if path.endswith('/') else path paths = path.split('/') root_path = paths[0] ReverseProxyResource.__init__(self, host, port, root_path, reactor) self._sub_paths = paths[1:] self._downloader = downloader \ or IllustrationDownloader(host=host, pool_maxsize=pool_maxsize) self._cache = cache self._filter = filter_fun
def getChild(self, path, request): token = request.getCookie('token') if token is None: self._setToken(request) if path == 'api': return APIResource() elif path == 'ws': return self._ws.getResource(request) else: return ReverseProxyResource('127.0.0.1', 8080, os.path.join('/', path)) if not path: return File(os.path.join(self._static_path, 'index.html')) return self
def __init__(self, port): ReverseProxyResource.__init__(self, 'localhost', port, b'')
def __init__(self, host, port, path, module_registry, reactor=reactor): self.module_registry = module_registry ReverseProxyResource.__init__(self, host, port, path, reactor)
file = open(settings['logfile'], "wa") log.startLogging(file, setStdout=False) else: log.startLogging(sys.stdout, setStdout=False) if settings.has_key('starturl'): log.msg('Open', settings['starturl']) if settings.has_key('jsonconfigfile'): file = open(settings['jsonconfigfile'], 'w') import json json.dump(settings, file) log.msg(os.getcwd()) log.msg(settings['rootdir']) root = CacheFile(settings['rootdir']) from twisted.web.proxy import ReverseProxyResource proxy = ReverseProxyResource('windpowerhub.com', 80, '/~albatros/php') root.putChild("php", proxy) #phproot = static.File('src/com/kk_electronic/public/clsrv/') #phproot.processors = { # '.php':PHP5Script # } #root.putChild("messagebox", MessageBoxRoot()) root.putChild("websocket", WebSocketRoot()) #root.putChild("clsrv", phproot) site = server.Site(root) reactor.listenTCP(settings.as_int('port'), site) #@UndefinedVariable reactor.run() #@UndefinedVariable if __name__ == "__main__":
def _create_resource(self, path_config, nested=True): """ Creates child resource to be added to the parent. :param path_config: Configuration for the new child resource. :type path_config: dict :returns: Resource -- the new child resource """ # WAMP-WebSocket resource # if path_config['type'] == 'websocket': ws_factory = WampWebSocketServerFactory(self._router_session_factory, self.config.extra.cbdir, path_config, self._templates) # FIXME: Site.start/stopFactory should start/stop factories wrapped as Resources ws_factory.startFactory() return WebSocketResource(ws_factory) # Static file hierarchy resource # elif path_config['type'] == 'static': static_options = path_config.get('options', {}) if 'directory' in path_config: static_dir = os.path.abspath(os.path.join(self.config.extra.cbdir, path_config['directory'])) elif 'package' in path_config: if 'resource' not in path_config: raise ApplicationError(u"crossbar.error.invalid_configuration", "missing resource") try: mod = importlib.import_module(path_config['package']) except ImportError as e: emsg = "Could not import resource {} from package {}: {}".format(path_config['resource'], path_config['package'], e) self.log.error(emsg) raise ApplicationError(u"crossbar.error.invalid_configuration", emsg) else: try: static_dir = os.path.abspath(pkg_resources.resource_filename(path_config['package'], path_config['resource'])) except Exception as e: emsg = "Could not import resource {} from package {}: {}".format(path_config['resource'], path_config['package'], e) self.log.error(emsg) raise ApplicationError(u"crossbar.error.invalid_configuration", emsg) else: raise ApplicationError(u"crossbar.error.invalid_configuration", "missing web spec") static_dir = static_dir.encode('ascii', 'ignore') # http://stackoverflow.com/a/20433918/884770 # create resource for file system hierarchy # if static_options.get('enable_directory_listing', False): static_resource_class = StaticResource else: static_resource_class = StaticResourceNoListing cache_timeout = static_options.get('cache_timeout', DEFAULT_CACHE_TIMEOUT) allow_cross_origin = static_options.get('allow_cross_origin', True) static_resource = static_resource_class(static_dir, cache_timeout=cache_timeout, allow_cross_origin=allow_cross_origin) # set extra MIME types # static_resource.contentTypes.update(EXTRA_MIME_TYPES) if 'mime_types' in static_options: static_resource.contentTypes.update(static_options['mime_types']) patchFileContentTypes(static_resource) # render 404 page on any concrete path not found # static_resource.childNotFound = Resource404(self._templates, static_dir) return static_resource # WSGI resource # elif path_config['type'] == 'wsgi': if not _HAS_WSGI: raise ApplicationError(u"crossbar.error.invalid_configuration", "WSGI unsupported") if 'module' not in path_config: raise ApplicationError(u"crossbar.error.invalid_configuration", "missing WSGI app module") if 'object' not in path_config: raise ApplicationError(u"crossbar.error.invalid_configuration", "missing WSGI app object") # import WSGI app module and object mod_name = path_config['module'] try: mod = importlib.import_module(mod_name) except ImportError as e: raise ApplicationError(u"crossbar.error.invalid_configuration", "WSGI app module '{}' import failed: {} - Python search path was {}".format(mod_name, e, sys.path)) else: obj_name = path_config['object'] if obj_name not in mod.__dict__: raise ApplicationError(u"crossbar.error.invalid_configuration", "WSGI app object '{}' not in module '{}'".format(obj_name, mod_name)) else: app = getattr(mod, obj_name) # Create a threadpool for running the WSGI requests in pool = ThreadPool(maxthreads=path_config.get("maxthreads", 20), minthreads=path_config.get("minthreads", 0), name="crossbar_wsgi_threadpool") self._reactor.addSystemEventTrigger('before', 'shutdown', pool.stop) pool.start() # Create a Twisted Web WSGI resource from the user's WSGI application object try: wsgi_resource = WSGIResource(self._reactor, pool, app) if not nested: wsgi_resource = WSGIRootResource(wsgi_resource, {}) except Exception as e: raise ApplicationError(u"crossbar.error.invalid_configuration", "could not instantiate WSGI resource: {}".format(e)) else: return wsgi_resource # Redirecting resource # elif path_config['type'] == 'redirect': redirect_url = path_config['url'].encode('ascii', 'ignore') return RedirectResource(redirect_url) # Node info resource # elif path_config['type'] == 'nodeinfo': return NodeInfoResource(self._templates, self) # Reverse proxy resource # elif path_config['type'] == 'reverseproxy': # Import late because t.w.proxy imports the reactor from twisted.web.proxy import ReverseProxyResource host = path_config['host'] port = int(path_config.get('port', 80)) path = path_config.get('path', '').encode('ascii', 'ignore') return ReverseProxyResource(host, port, path) # JSON value resource # elif path_config['type'] == 'json': value = path_config['value'] return JsonResource(value) # CGI script resource # elif path_config['type'] == 'cgi': cgi_processor = path_config['processor'] cgi_directory = os.path.abspath(os.path.join(self.config.extra.cbdir, path_config['directory'])) cgi_directory = cgi_directory.encode('ascii', 'ignore') # http://stackoverflow.com/a/20433918/884770 return CgiDirectory(cgi_directory, cgi_processor, Resource404(self._templates, cgi_directory)) # WAMP-Longpoll transport resource # elif path_config['type'] == 'longpoll': path_options = path_config.get('options', {}) lp_resource = WampLongPollResource(self._router_session_factory, timeout=path_options.get('request_timeout', 10), killAfter=path_options.get('session_timeout', 30), queueLimitBytes=path_options.get('queue_limit_bytes', 128 * 1024), queueLimitMessages=path_options.get('queue_limit_messages', 100), debug_transport_id=path_options.get('debug_transport_id', None) ) lp_resource._templates = self._templates return lp_resource # Publisher resource (part of REST-bridge) # elif path_config['type'] == 'publisher': # create a vanilla session: the publisher will use this to inject events # publisher_session_config = ComponentConfig(realm=path_config['realm'], extra=None) publisher_session = ApplicationSession(publisher_session_config) # add the publisher session to the router # self._router_session_factory.add(publisher_session, authrole=path_config.get('role', 'anonymous')) # now create the publisher Twisted Web resource # return PublisherResource(path_config.get('options', {}), publisher_session) # Webhook resource (part of REST-bridge) # elif path_config['type'] == 'webhook': # create a vanilla session: the webhook will use this to inject events # webhook_session_config = ComponentConfig(realm=path_config['realm'], extra=None) webhook_session = ApplicationSession(webhook_session_config) # add the webhook session to the router # self._router_session_factory.add(webhook_session, authrole=path_config.get('role', 'anonymous')) # now create the webhook Twisted Web resource # return WebhookResource(path_config.get('options', {}), webhook_session) # Caller resource (part of REST-bridge) # elif path_config['type'] == 'caller': # create a vanilla session: the caller will use this to inject calls # caller_session_config = ComponentConfig(realm=path_config['realm'], extra=None) caller_session = ApplicationSession(caller_session_config) # add the calling session to the router # self._router_session_factory.add(caller_session, authrole=path_config.get('role', 'anonymous')) # now create the caller Twisted Web resource # return CallerResource(path_config.get('options', {}), caller_session) # File Upload resource # elif path_config['type'] == 'upload': upload_directory = os.path.abspath(os.path.join(self.config.extra.cbdir, path_config['directory'])) upload_directory = upload_directory.encode('ascii', 'ignore') # http://stackoverflow.com/a/20433918/884770 if not os.path.isdir(upload_directory): emsg = "configured upload directory '{}' in file upload resource isn't a directory".format(upload_directory) self.log.error(emsg) raise ApplicationError(u"crossbar.error.invalid_configuration", emsg) if 'temp_directory' in path_config: temp_directory = os.path.abspath(os.path.join(self.config.extra.cbdir, path_config['temp_directory'])) temp_directory = temp_directory.encode('ascii', 'ignore') # http://stackoverflow.com/a/20433918/884770 else: temp_directory = os.path.abspath(tempfile.gettempdir()) temp_directory = os.path.join(temp_directory, 'crossbar-uploads') if not os.path.exists(temp_directory): os.makedirs(temp_directory) if not os.path.isdir(temp_directory): emsg = "configured temp directory '{}' in file upload resource isn't a directory".format(temp_directory) self.log.error(emsg) raise ApplicationError(u"crossbar.error.invalid_configuration", emsg) # file upload progress and finish events are published via this session # upload_session_config = ComponentConfig(realm=path_config['realm'], extra=None) upload_session = ApplicationSession(upload_session_config) self._router_session_factory.add(upload_session, authrole=path_config.get('role', 'anonymous')) self.log.info("File upload resource started. Uploads to {upl} using temp folder {tmp}.", upl=upload_directory, tmp=temp_directory) return FileUploadResource(upload_directory, temp_directory, path_config['form_fields'], upload_session, path_config.get('options', {})) # Generic Twisted Web resource # elif path_config['type'] == 'resource': try: klassname = path_config['classname'] self.log.debug("Starting class '{name}'", name=klassname) c = klassname.split('.') module_name, klass_name = '.'.join(c[:-1]), c[-1] module = importlib.import_module(module_name) make = getattr(module, klass_name) return make(path_config.get('extra', {})) except Exception as e: emsg = "Failed to import class '{}' - {}".format(klassname, e) self.log.error(emsg) self.log.error("PYTHONPATH: {pythonpath}", pythonpath=sys.path) raise ApplicationError(u"crossbar.error.class_import_failed", emsg) # Schema Docs resource # elif path_config['type'] == 'schemadoc': realm = path_config['realm'] if realm not in self.realm_to_id: raise ApplicationError(u"crossbar.error.no_such_object", "No realm with URI '{}' configured".format(realm)) realm_id = self.realm_to_id[realm] realm_schemas = self.realms[realm_id].session._schemas return SchemaDocResource(self._templates, realm, realm_schemas) # Nested subpath resource # elif path_config['type'] == 'path': nested_paths = path_config.get('paths', {}) if '/' in nested_paths: nested_resource = self._create_resource(nested_paths['/']) else: nested_resource = Resource404(self._templates, b'') # nest subpaths under the current entry # self._add_paths(nested_resource, nested_paths) return nested_resource else: raise ApplicationError(u"crossbar.error.invalid_configuration", "invalid Web path type '{}' in {} config".format(path_config['type'], 'nested' if nested else 'root'))
def __init__(self,*args,**kwargs): ReverseProxyResource.__init__(self,*args,**kwargs)