def getChild(self, path, request): """Find the appropriate child resource depending on request type Possible URLs: - /foo/bar/info/refs -> info refs (file / SmartHTTP hybrid) - /foo/bar/git-upload-pack -> SmartHTTP RPC - /foo/bar/git-receive-pack -> SmartHTTP RPC - /foo/bar/HEAD -> file (dumb http) - /foo/bar/objects/* -> file (dumb http) """ path = request.path # alternatively use path + request.postpath pathparts = path.split('/') writerequired = False script_name = '/' new_path = path resource = NoResource() # Path lookup / translation path_info = self.git_configuration.path_lookup(path, protocol_hint='http') if path_info is None: log.msg('User %s tried to access %s ' 'but the lookup failed' % (self.username, path)) return resource log.msg('Lookup of %s gave %r' % (path, path_info)) if (path_info['repository_fs_path'] is None and path_info['repository_base_fs_path'] is None): log.msg('Neither a repository base nor a repository were returned') return resource # split script_name / new_path according to path info if path_info['repository_base_url_path'] is not None: script_name = '/' script_name += path_info['repository_base_url_path'].strip('/') new_path = path[len(script_name.rstrip('/')):] # since pretty much everything needs read access, check for it now if not self.authnz.can_read(self.username, path_info): if self.username is None: return UnauthorizedResource(self.credentialFactories) else: return ForbiddenResource("You don't have read access") # Smart HTTP requests # /info/refs if (len(pathparts) >= 2 and pathparts[-2] == 'info' and pathparts[-1] == 'refs'): writerequired = ('service' in request.args and request.args['service'][0] == 'git-receive-pack') resource = InfoRefs(path_info['repository_fs_path']) # /git-upload-pack (client pull) elif len(pathparts) >= 1 and pathparts[-1] == 'git-upload-pack': cmd = 'git' args = [ os.path.basename(cmd), 'upload-pack', '--stateless-rpc', path_info['repository_fs_path'] ] resource = GitCommand(cmd, args) request.setHeader('Content-Type', 'application/x-git-upload-pack-result') # /git-receive-pack (client push) elif len(pathparts) >= 1 and pathparts[-1] == 'git-receive-pack': writerequired = True cmd = 'git' args = [ os.path.basename(cmd), 'receive-pack', '--stateless-rpc', path_info['repository_fs_path'] ] resource = GitCommand(cmd, args) request.setHeader('Content-Type', 'application/x-git-receive-pack-result') # static files as specified in file_headers or fallback webfrontend else: # determine the headers for this file filename, headers = None, None for matcher, get_headers in file_headers.items(): m = matcher.match(path) if m: filename = m.group(1) headers = get_headers() break if filename is not None: for key, val in headers.items(): request.setHeader(key, val) log.msg( "Returning file %s" % os.path.join(path_info['repository_fs_path'], filename)) resource = File( os.path.join(path_info['repository_fs_path'], filename), headers['Content-Type']) resource.isLeaf = True # static file -> it is a leaf else: # No match -> fallback to git viewer if script_name is not None: # patch pre/post path of request according to # script_name and path request.prepath = script_name.strip('/').split('/') if request.prepath == ['']: request.prepath = [] request.postpath = new_path.lstrip('/').split('/') log.msg("pre and post: %r %r" % (request.prepath, request.postpath)) # If the resource has a withEnviron function, it's # probably our own flavour of WSGIResource that # supports passing further args for the environ if hasattr(self.git_viewer, "withEnviron"): # set wsgirouting args routing_args = { 'repository_path': path_info['repository_fs_path'], 'repository_base': path_info['repository_base_fs_path'] } if 'repository_clone_urls' in path_info: routing_args['repository_clone_urls'] = path_info[ 'repository_clone_urls'] resource = self.git_viewer.withEnviron( {'wsgiorg.routing_args': ([], routing_args)}) else: resource = self.git_viewer # before returning the resource, check if write access is required # and enforce privileges accordingly # anonymous (username = None) will never be granted write access if writerequired and ( self.username is None or not self.authnz.can_write(self.username, path_info)): if self.username is None: return UnauthorizedResource(self.credentialFactories) else: return ForbiddenResource("You don't have write access") return resource
def getChild(self, path, request): """Find the appropriate child resource depending on request type Possible URLs: - /foo/bar/info/refs -> info refs (file / SmartHTTP hybrid) - /foo/bar/git-upload-pack -> SmartHTTP RPC - /foo/bar/git-receive-pack -> SmartHTTP RPC - /foo/bar/HEAD -> file (dumb http) - /foo/bar/objects/* -> file (dumb http) """ path = request.path # alternatively use path + request.postpath pathparts = path.split('/') writerequired = False script_name = '/' new_path = path resource = NoResource() # Path lookup / translation path_info = self.git_configuration.path_lookup(path, protocol_hint='http') if path_info is None: log.msg('User %s tried to access %s ' 'but the lookup failed' % (self.username, path)) return resource log.msg('Lookup of %s gave %r' % (path, path_info)) if (path_info['repository_fs_path'] is None and path_info['repository_base_fs_path'] is None): log.msg('Neither a repository base nor a repository were returned') return resource # split script_name / new_path according to path info if path_info['repository_base_url_path'] is not None: script_name = '/' script_name += path_info['repository_base_url_path'].strip('/') new_path = path[len(script_name.rstrip('/')):] # since pretty much everything needs read access, check for it now if not self.authnz.can_read(self.username, path_info): if self.username is None: return UnauthorizedResource(self.credentialFactories) else: return ForbiddenResource("You don't have read access") # Smart HTTP requests # /info/refs if (len(pathparts) >= 2 and pathparts[-2] == 'info' and pathparts[-1] == 'refs'): writerequired = ('service' in request.args and request.args['service'][0] == 'git-receive-pack') resource = InfoRefs(path_info['repository_fs_path']) # /git-upload-pack (client pull) elif len(pathparts) >= 1 and pathparts[-1] == 'git-upload-pack': cmd = 'git' args = [os.path.basename(cmd), 'upload-pack', '--stateless-rpc', path_info['repository_fs_path']] resource = GitCommand(cmd, args) request.setHeader('Content-Type', 'application/x-git-upload-pack-result') # /git-receive-pack (client push) elif len(pathparts) >= 1 and pathparts[-1] == 'git-receive-pack': writerequired = True cmd = 'git' args = [os.path.basename(cmd), 'receive-pack', '--stateless-rpc', path_info['repository_fs_path']] resource = GitCommand(cmd, args) request.setHeader('Content-Type', 'application/x-git-receive-pack-result') # static files as specified in file_headers or fallback webfrontend else: # determine the headers for this file filename, headers = None, None for matcher, get_headers in file_headers.items(): m = matcher.match(path) if m: filename = m.group(1) headers = get_headers() break if filename is not None: for key, val in headers.items(): request.setHeader(key, val) log.msg("Returning file %s" % os.path.join( path_info['repository_fs_path'], filename)) resource = File(os.path.join(path_info['repository_fs_path'], filename), headers['Content-Type']) resource.isLeaf = True # static file -> it is a leaf else: # No match -> fallback to git viewer if script_name is not None: # patch pre/post path of request according to # script_name and path request.prepath = script_name.strip('/').split('/') if request.prepath == ['']: request.prepath = [] request.postpath = new_path.lstrip('/').split('/') log.msg("pre and post: %r %r" % (request.prepath, request.postpath)) # If the resource has a withEnviron function, it's # probably our own flavour of WSGIResource that # supports passing further args for the environ if hasattr(self.git_viewer, "withEnviron"): # set wsgirouting args routing_args = { 'repository_path': path_info['repository_fs_path'], 'repository_base': path_info['repository_base_fs_path'] } if 'repository_clone_urls' in path_info: routing_args['repository_clone_urls'] = path_info['repository_clone_urls'] resource = self.git_viewer.withEnviron( {'wsgiorg.routing_args': ([], routing_args)}) else: resource = self.git_viewer # before returning the resource, check if write access is required # and enforce privileges accordingly # anonymous (username = None) will never be granted write access if writerequired and (self.username is None or not self.authnz.can_write(self.username, path_info)): if self.username is None: return UnauthorizedResource(self.credentialFactories) else: return ForbiddenResource("You don't have write access") return resource