def _isValidZIPLink(self, link, subPath): ''' Returns true if the file identified by subpath exists in the given link to a ZIP archive, false otherwise. @param link: list Link description in JSON format. @param subPath: string The path inside the linked directory (if needed) ''' zipFilePath = normOSPath(link[1]) inFilePath = normOSPath(link[2], True) zipFile = ZipFile(zipFilePath) inZipFile = normZipPath(join(inFilePath, subPath)) if subPath else normZipPath(inFilePath) return inZipFile in zipFile.NameToInfo
def _copyZipDir(self, zipFilePath, inDirPath, path): ''' Copy a directory from a ZIP archive to a filesystem directory @param zipFilePath: string The path of the ZIP archive @param inDirPath: string The path to the file in the ZIP archive @param path: string Destination path where the ZIP directory is copied ''' # make sure the ZIP file path is normalized and uses the OS separator zipFilePath = normOSPath(zipFilePath) # make sure the ZIP file path is normalized and uses the ZIP separator inDirPath = normZipPath(inDirPath) zipFile = ZipFile(zipFilePath) if isdir(path): if self._isSyncFile(zipFilePath, path): return rmtree(path) entries = [ent for ent in zipFile.namelist() if ent.startswith(inDirPath)] tmpDir = TemporaryDirectory() zipFile.extractall(tmpDir.name, entries) tmpDirPath = join(tmpDir.name, normOSPath(inDirPath)) os.makedirs(path) for entry in os.listdir(tmpDirPath): move(join(tmpDirPath, entry), path)
def _copyZipDir(self, zipFilePath, inDirPath, path): ''' Copy a directory from a ZIP archive to a filesystem directory @param zipFilePath: string The path of the ZIP archive @param inDirPath: string The path to the file in the ZIP archive @param path: string Destination path where the ZIP directory is copied ''' # make sure the ZIP file path is normalized and uses the OS separator zipFilePath = normOSPath(zipFilePath) # make sure the ZIP file path is normalized and uses the ZIP separator inDirPath = normZipPath(inDirPath) zipFile = ZipFile(zipFilePath) entries = [ent for ent in zipFile.namelist() if ent.startswith(inDirPath)] tmpDir = TemporaryDirectory() zipFile.extractall(tmpDir.name, entries) tmpDirPath = join(tmpDir.name, normOSPath(inDirPath)) if not isdir(path): os.makedirs(path) for entry in os.listdir(tmpDirPath): dstPath = join(path, entry) if isfile(dstPath): os.remove(dstPath) elif isdir(dstPath): rmtree(dstPath) move(join(tmpDirPath, entry), path)
def process(self, errorProcessing, chain, request, response, responseCnt, **keyargs): ''' @see: HandlerProcessor.process Provide the file content as a response. ''' assert isinstance(errorProcessing, Processing), 'Invalid processing %s' % errorProcessing assert isinstance(chain, Chain), 'Invalid processors chain %s' % chain assert isinstance(request, Request), 'Invalid request %s' % request assert isinstance(response, Response), 'Invalid response %s' % response assert isinstance(responseCnt, ResponseContent), 'Invalid response content %s' % responseCnt if request.method != GET: response.allows = GET response.code, response.text = METHOD_NOT_AVAILABLE, 'Path only available for GET' else: chain.proceed() # Make sure the given path points inside the repository entryPath = normOSPath(join(self.repositoryPath, normZipPath(unquote(request.uri)))) if not entryPath.startswith(self.repositoryPath): response.code, response.text = RESOURCE_NOT_FOUND, 'Out of repository path' else: # Initialize the read file handler with None value # This will be set upon successful file open rf = None if isfile(entryPath): rf, size = open(entryPath, 'rb'), os.path.getsize(entryPath) else: linkPath = entryPath while len(linkPath) > len(self.repositoryPath): if isfile(linkPath + self._linkExt): with open(linkPath + self._linkExt) as f: links = json.load(f) subPath = normOSPath(entryPath[len(linkPath):]).lstrip(sep) for linkType, *data in links: if linkType in self._linkTypes: # make sure the subpath is normalized and uses the OS separator if not self._isPathDeleted(join(linkPath, subPath)): entry = self._linkTypes[linkType](subPath, *data) if entry is not None: rf, size = entry break break subLinkPath = dirname(linkPath) if subLinkPath == linkPath: break linkPath = subLinkPath if rf is None: response.code, response.text = METHOD_NOT_AVAILABLE, 'Invalid content resource' else: response.code, response.text = RESOURCE_FOUND, 'Resource found' responseCnt.source = rf responseCnt.length = size responseCnt.type, _encoding = guess_type(entryPath) if not responseCnt.type: responseCnt.type = self.defaultContentType return chain.branch(errorProcessing)
def process(self, request:Request, response:Response, responseCnt:ResponseContent, **keyargs): ''' @see: HandlerProcessorProceed.process Provide the file content as a response. ''' assert isinstance(request, Request), 'Invalid request %s' % request assert isinstance(response, Response), 'Invalid response %s' % response assert isinstance(responseCnt, ResponseContent), 'Invalid response content %s' % responseCnt if request.method != HTTP_GET: if response.allows is not None: response.allows.append(HTTP_GET) else: response.allows = [HTTP_GET] response.code, response.status, response.isSuccess = METHOD_NOT_AVAILABLE else: # Make sure the given path points inside the repository entryPath = normOSPath(join(self.repositoryPath, normZipPath(unquote(request.uri)))) if not entryPath.startswith(self.repositoryPath): response.code, response.status, response.isSuccess = PATH_NOT_FOUND else: # Initialize the read file handler with None value # This will be set upon successful file open rf = None if isfile(entryPath): rf, size = open(entryPath, 'rb'), os.path.getsize(entryPath) else: linkPath = entryPath while len(linkPath) > len(self.repositoryPath): if isfile(linkPath + self._linkExt): with open(linkPath + self._linkExt) as f: links = json.load(f) subPath = normOSPath(entryPath[len(linkPath):]).lstrip(sep) for linkType, *data in links: if linkType in self._linkTypes: # make sure the subpath is normalized and uses the OS separator if not self._isPathDeleted(join(linkPath, subPath)): entry = self._linkTypes[linkType](subPath, *data) if entry is not None: rf, size = entry break break subLinkPath = dirname(linkPath) if subLinkPath == linkPath: break linkPath = subLinkPath if rf is None: response.code, response.status, response.isSuccess = PATH_NOT_FOUND else: response.code, response.status, response.isSuccess = PATH_FOUND responseCnt.source = rf responseCnt.length = size responseCnt.type, _encoding = guess_type(entryPath) if not responseCnt.type: responseCnt.type = self.defaultContentType responseCnt.type += '; charset=utf-8' return
def _createLinkToZipFile(self, path, zipFilePath, inFilePath): repFilePath = self._getItemPath(path) + self._linkExt if isfile(repFilePath): with open(repFilePath, 'r') as f: links = json.load(f) else: links = [] inFilePath = normZipPath(inFilePath) for k, entry in enumerate(links): if entry and entry[0] == self._zipHeader: if entry[1] == zipFilePath and entry[2] == inFilePath: if k > 0: links.insert(0, links.pop(k)) break else: links.insert(0, (self._zipHeader, zipFilePath, inFilePath)) with open(repFilePath, 'w') as f: json.dump(links, f)
def _processZiplink(self, subPath, zipFilePath, inFilePath): ''' Reads a link description file and returns a file handler to the linked file inside the ZIP archive. ''' # make sure the ZIP file path uses the OS separator zipFilePath = normOSPath(zipFilePath) # convert the internal ZIP path to OS format in order to use standard path functions inFilePath = normOSPath(inFilePath) zipFile = ZipFile(zipFilePath) # resource internal ZIP path should be in ZIP format resPath = normZipPath(join(inFilePath, subPath)) if resPath in zipFile.NameToInfo: return zipFile.open(resPath, 'r'), zipFile.getinfo(resPath).file_size
def _removeZiplink(self, link, path, entryPath, subPath): ''' Removes a link to a file or directory in a ZIP archive. @param link: list Link description in JSON format. @param path: string The repository path to remove. @param entryPath: string The full path for which to create the deletion mark. @param subPath: string The path inside the linked ZIP archive. ''' zipFilePath = normOSPath(link[1]) inFilePath = normOSPath(link[2], True) zipFile = ZipFile(zipFilePath) inZipFile = normZipPath(join(inFilePath, subPath)) if not inZipFile in zipFile.NameToInfo: raise PathNotFound(path) self._createDelMark(entryPath)
def process(self, request: Request, response: Response, responseCnt: ResponseContent, **keyargs): ''' @see: HandlerProcessorProceed.process Provide the file content as a response. ''' assert isinstance(request, Request), 'Invalid request %s' % request assert isinstance(response, Response), 'Invalid response %s' % response assert isinstance( responseCnt, ResponseContent), 'Invalid response content %s' % responseCnt if request.method != HTTP_GET: if response.allows is not None: response.allows.append(HTTP_GET) else: response.allows = [HTTP_GET] response.code, response.status, response.isSuccess = METHOD_NOT_AVAILABLE else: # Make sure the given path points inside the repository entryPath = normOSPath( join(self.repositoryPath, normZipPath(unquote(request.uri)))) if not entryPath.startswith(self.repositoryPath): response.code, response.status, response.isSuccess = PATH_NOT_FOUND else: # Initialize the read file handler with None value # This will be set upon successful file open rf = None if isfile(entryPath): rf, size = open(entryPath, 'rb'), os.path.getsize(entryPath) else: linkPath = entryPath while len(linkPath) > len(self.repositoryPath): if isfile(linkPath + self._linkExt): with open(linkPath + self._linkExt) as f: links = json.load(f) subPath = normOSPath( entryPath[len(linkPath):]).lstrip(sep) for linkType, *data in links: if linkType in self._linkTypes: # make sure the subpath is normalized and uses the OS separator if not self._isPathDeleted( join(linkPath, subPath)): entry = self._linkTypes[linkType]( subPath, *data) if entry is not None: rf, size = entry break break subLinkPath = dirname(linkPath) if subLinkPath == linkPath: break linkPath = subLinkPath if rf is None: response.code, response.status, response.isSuccess = PATH_NOT_FOUND else: response.code, response.status, response.isSuccess = PATH_FOUND responseCnt.source = rf responseCnt.length = size responseCnt.type, _encoding = guess_type(entryPath) if not responseCnt.type: responseCnt.type = self.defaultContentType responseCnt.type += '; charset=utf-8' return
def _validatePath(self, path): path = normZipPath(path) fullPath = normOSPath(self._getItemPath(path), True) if not fullPath.startswith(self.delivery.getRepositoryPath()): raise PathNotFound(path) return (path, fullPath)