Viewing file: FtssInputSource.py (11.72 KB) -rw-r--r-- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
######################################################################## # $Header: /var/local/cvsroot/4Suite/Ft/Server/Server/Drivers/FtssInputSource.py,v 1.30 2005/03/22 17:36:57 mbrown Exp $ """ A subclass of InputSource that provides access to repo resources.
Copyright 2005 Fourthought, Inc. (USA). Detailed license and copyright information: http://4suite.org/COPYRIGHT Project home, documentation, distributions: http://4suite.org/ """
import cStringIO
from Ft.Lib import Uri, Uuid from Ft.Xml import InputSource, Domlette, Catalog from Ft.Server import FTSS_URI_SCHEME from Ft.Server.Common.ResourceTypes import ResourceType from Ft.Server.Server import FtServerServerException, Error
import PathImp
FTSS_RESOLVER = Uri.FtUriResolver() FTSS_RESOLVER.supportedSchemes.append(FTSS_URI_SCHEME)
class FtssInputSource(InputSource.InputSource): """ Wraps content that streams from the local repository.
The required uri argument given in the constructor must represent the stream's repo path in the form of a URI that uses the %s scheme. Although the URI will be resolved to absolute form using the base %s:/// if it is given as a relative (schemeless) URI that starts with '/', has an empty authority component, and has UTF-8 based %%-escaping where necessary, it is preferable to just construct an FtssInputSource from the absolute URI that is returned by calling RepoPathToUri() on the desired path.
The required driver argument given in the constructor must be a repo driver (FtssDriver) instance. """ % (FTSS_URI_SCHEME, FTSS_URI_SCHEME)
FORBIDDEN_HINTS = ["REPO APPLYXSLT", 'STYLESHEET IMPORT', 'STYLESHEET INCLUDE'] PERMITTED_HINTS = ["XSLT DOCUMENT FUNCTION", "EXTERNAL ENTITY"] #file:// forbidden until further security review FORBIDDEN_SCHEMES = ["file"]
def __init__(self, stream, uri, driver, *v_args, **kw_args): # uri formats: # (None or '') # /absolute%20path # //authority/absolute%20path # relative%20path # scheme://authority/absolute%20path # scheme:opaque%20part%20or%20relpath # scheme:/absolute%20path # 1. ensure that the uri was given if not uri: raise FtServerServerException( Error.RELATIVE_PATH_IN_FTSS_URI, uri=uri, ftssScheme=FTSS_URI_SCHEME) # 2. ensure that the path part of the uri is # absolute. if the uri has no scheme, assume the # correct one. origUri = uri[:] (scheme, authority, path) = Uri.SplitUriRef(uri)[0:3] if not scheme: if uri.startswith('/'): base = FTSS_URI_SCHEME+':///' uri = Uri.Absolutize(uri, base) scheme = FTSS_URI_SCHEME else: raise FtServerServerException( Error.RELATIVE_PATH_IN_FTSS_URI, uri=uri, ftssScheme=FTSS_URI_SCHEME) elif not path or path and not path.startswith('/'): raise FtServerServerException( Error.RELATIVE_PATH_IN_FTSS_URI, uri=uri, ftssScheme=FTSS_URI_SCHEME) # 3. uri is now absolute. # is scheme ok? (should be FTSS_URI_SCHEME) if scheme != FTSS_URI_SCHEME: raise FtServerServerException( Error.UNSUPPORTED_FTSS_URI_SCHEME, uri=uri, ftssScheme=FTSS_URI_SCHEME, scheme=scheme) # 4. authority ok? (should indicate a local repo) if authority: raise FtServerServerException( Error.NO_REMOTE_REPO_ACCESS, uri=uri) # 5. uri is good. convert path component to repo path, # in case we need it later. self._repo_path = unicode(Uri.PercentDecode(path.encode('ascii')), 'utf-8') # 6. finish setting up instance self._driver = driver
#7. Force the factory to be a FtssInputSourceFactory kw_args['factory'] = _FtssInputSourceFactory(driver)
InputSource.InputSource.__init__(self, stream, uri, *v_args, **kw_args)
# if the regular InputSource constructor caused an encoding # to be set, unset it here, because for now, we don't support # external encoding declarations on repo resources, plus we # don't want 'text/xml' repo streams to be assumed us-ascii. self.encoding = None #print "%r for path %r created w/URI %r (from %r)" % (self, self._repo_path, uri, origUri) return
def resolve(self, sysid, pubid=None, hint=None, ignoreErrors=0): """ Resolves a system identifier (fragmentless URI reference) or a public identifier into a new input source. It is typically used when a URI reference is encountered in the original stream and needs to be resolved (e.g. to support an external entity reference, XInclude, xsl:include/import, document(), etc.).
The hint parameter is used to give a hint as to what the resolution will be used for. It is generally used for security checks for the repository.
If the ignoreErrors flag is set, an error during resolution (such as "file not found") will result in None being returned, rather than raising an exception. """ sysid = self.resolveEntity(pubid, sysid) uri = self._normalize(sysid) stream = self._openStream(uri, ignoreErrors, hint) return self.clone(stream, uri, hint)
def _openStream(self, uri, ignoreErrors=0, hint=None): """ Returns a representation of a resource as a stream by resolving the given URI. If ignoreErrors is set, failure to obtain the stream will result in None being returned, rather than an exception (e.g. "file not found") being raised.
Differs from the base class's version in that if the URI indicates a local repo resource, an attempt is made to obtain the stream directly, to avoid a possible deadlock. Any other URI is passed to the base class's _openStream(). """ #print "_openStream(%r) called on %r for URI %r" % (uri, self, self.uri) (scheme, authority, path) = Uri.SplitUriRef(uri)[0:3] if scheme == FTSS_URI_SCHEME: # URI is pointing to a repo resource if authority: raise FtServerServerException( Error.NO_REMOTE_REPO_ACCESS, uri=uri) if not path or path and not path.startswith('/'): raise FtServerServerException( Error.RELATIVE_PATH_IN_FTSS_URI, uri=uri, ftssScheme=FTSS_URI_SCHEME) self._repo_path = unicode(Uri.PercentDecode(path.encode( 'ascii')), 'utf-8') root = PathImp.CreateInitialPath('/', self._driver) path = root.normalize(uri[7:]) #Remove Scheme if self._driver.hasResource(path): # in repo #print "returning repo doc %s" % self._repo_path if self._driver.getType(path) != ResourceType.RDF_DOCUMENT: # Fast track; bypass the repository and get the content # directly from the driver content = self._driver.fetchResource(path) else: # WARNING - BIG UGLY HACK!!!!!!!! # Generated content; use a repository to get the resource # object on which to call getContent(). from Ft.Server.Server.SCore import RepositoryImp repo = RepositoryImp.RepositoryImp(root, self._driver, "") content = repo._fetchResource(path).getContent() return cStringIO.StringIO(content) else: # not in repo; don't try anywhere else #print "repo doc %s not found" % self._repo_path if ignoreErrors: return None raise FtServerServerException( Error.RESOURCE_NOT_FOUND, uri=uri) else: # non-repo #print "non-repo URI, so calling InputSource._openStream(%r)" % uri return InputSource.InputSource._openStream(self, uri)
def clone(self, stream, uri=None, hint=None): """ Clones this input source, creating a new instance with the known params. """ #print "cloning %r with URI %r; new uri given was %r" % (self, self.uri, uri) if uri is None: uri = self.uri if stream is None: return InputSource.NullInputSource(uri) try: return FtssInputSource(stream, uri, self._driver, processIncludes=self.processIncludes, stripElements=self.stripElements, resolver=self._resolver) except FtServerServerException, e: if e.errorCode == Error.UNSUPPORTED_FTSS_URI_SCHEME: if hint in self.FORBIDDEN_HINTS: raise if e.params["scheme"] in self.FORBIDDEN_SCHEMES: raise if hint not in self.PERMITTED_HINTS: classname = self.__class__.__name__ print ("%s resolution attempted with hint" " %r. This will not be allowed until this hint" " is added to %s.PERMITTED_HINTS") % (classname, hint, classname) raise return InputSource.InputSource( stream, uri, processIncludes=self.processIncludes, stripElements=self.stripElements, resolver=self._resolver) raise
def __getstate__(self): #Must not pickle the driver state = InputSource.InputSource.__getstate__(self) state['_driver'] = None return state
class _FtssInputSourceFactory(InputSource.InputSourceFactory):
def __init__(self, driver, *v_args, **kw_args): kw_args['inputSourceClass'] = FtssInputSource kw_args['resolver'] = FTSS_RESOLVER InputSource.InputSourceFactory.__init__(self, *v_args, **kw_args) #self._fallbackFactory = InputSource.DefaultFactory self._driver = driver self.catalog = Catalog.GetDefaultCatalog('ftss-default.cat') return
def fromStream(self, stream, uri=None, *v_args, **kw_args): #Must be either in the first v_arg, or in the kw_args (or have self._driver set) if len(v_args) == 0 and not kw_args.has_key('driver'): if self._driver is None: raise RuntimeError("You must specify a driver when using the global input source factory.") kw_args['driver'] = self._driver #try: # return apply(InputSource.InputSourceFactory.fromStream, # (self, stream, uri) + v_args, kw_args) #except FtServerServerException, e: # if e.errorCode == Error.UNSUPPORTED_FTSS_URI_SCHEME: # return apply(self._fallbackFactory.fromStream, # (self, stream, uri) + v_args, kw_args) if 'catalog' not in kw_args: kw_args['catalog'] = self.catalog return InputSource.InputSourceFactory.fromStream(self, stream, uri, *v_args, **kw_args)
# Set up defaults FtssInputSourceFactory = _FtssInputSourceFactory(None)
ValidatingReader = Domlette.ValidatingReaderBase(FtssInputSourceFactory) NonvalidatingReader = Domlette.NonvalidatingReaderBase(FtssInputSourceFactory) NoExtDtdReader = Domlette.NoExtDtdReaderBase(FtssInputSourceFactory)
|