- content_range_text = headers.get("Content-Range")
- transaction_id = headers.get("Transaction-Id")
- filename = headers.get("Content-Filename", "pkg")
- # TODO change to Content-Disposition filename https://tools.ietf.org/html/rfc6266
- expected_md5 = headers.get("Content-File-MD5")
- compressed = None
- if "application/gzip" in headers.get("Content-Type") or "application/x-gzip" in headers.get("Content-Type") or \
- "application/zip" in headers.get("Content-Type"):
- compressed = "gzip"
- file_pkg = None
- error_text = ""
- try:
- if content_range_text:
- content_range = content_range_text.replace("-", " ").replace("/", " ").split()
- if content_range[0] != "bytes": # TODO check x<y not negative < total....
- raise IndexError()
- start = int(content_range[1])
- end = int(content_range[2]) + 1
- total = int(content_range[3])
- if len(indata) != end-start:
- raise EngineException("Mismatch between Content-Range header {}-{} and body length of {}".format(
- start, end-1, len(indata)), HTTPStatus.BAD_REQUEST)
- else:
- start = 0
- total = end = len(indata)
- if not transaction_id:
- # generate transaction
- transaction_id = str(uuid4())
- self.fs.mkdir(transaction_id)
- # control_file = open(self.storage["path"] + transaction_id + "/.osm.yaml", 'wb')
- # control = {"received": 0}
- elif not self.fs.file_exists(transaction_id):
- raise EngineException("invalid Transaction-Id header", HTTPStatus.NOT_FOUND)
- else:
- pass
- # control_file = open(self.storage["path"] + transaction_id + "/.osm.yaml", 'rw')
- # control = yaml.load(control_file)
- # control_file.seek(0, 0)
- storage = self.fs.get_params()
- storage["folder"] = transaction_id
- storage["file"] = filename
-
- file_path = (transaction_id, filename)
- if self.fs.file_exists(file_path):
- file_size = self.fs.file_size(file_path)
- else:
- file_size = 0
- if file_size != start:
- raise EngineException("invalid upload transaction sequence, expected '{}' but received '{}'".format(
- file_size, start), HTTPStatus.BAD_REQUEST)
- file_pkg = self.fs.file_open(file_path, 'a+b')
- file_pkg.write(indata)
- if end != total:
- return {"_id": transaction_id, "storage": storage}
- if expected_md5:
- file_pkg.seek(0, 0)
- file_md5 = md5()
- chunk_data = file_pkg.read(1024)
- while chunk_data:
- file_md5.update(chunk_data)
- chunk_data = file_pkg.read(1024)
- if expected_md5 != file_md5.hexdigest():
- raise EngineException("Error, MD5 mismatch", HTTPStatus.CONFLICT)
- file_pkg.seek(0, 0)
- if compressed == "gzip":
- # TODO unzip,
- storage["tarfile"] = filename
- tar = tarfile.open(mode='r', fileobj=file_pkg)
- descriptor_file_name = None
- for tarinfo in tar:
- tarname = tarinfo.name
- tarname_path = tarname.split("/")
- if not tarname_path[0] or ".." in tarname_path: # if start with "/" means absolute path
- raise EngineException("Absolute path or '..' are not allowed for package descriptor tar.gz")
- if len(tarname_path) == 1 and not tarinfo.isdir():
- raise EngineException("All files must be inside a dir for package descriptor tar.gz")
- if tarname.endswith(".yaml") or tarname.endswith(".json") or tarname.endswith(".yml"):
- storage["file"] = tarname_path[0]
- if len(tarname_path) == 2:
- if descriptor_file_name:
- raise EngineException("Found more than one descriptor file at package descriptor tar.gz")
- descriptor_file_name = tarname
- if not descriptor_file_name:
- raise EngineException("Not found any descriptor file at package descriptor tar.gz")
- self.fs.file_extract(tar, transaction_id)
- with self.fs.file_open((transaction_id, descriptor_file_name), "r") as descriptor_file:
- content = descriptor_file.read()
- else:
- content = file_pkg.read()
- tarname = ""
-
- if tarname.endswith(".json"):
- error_text = "Invalid json format "
- indata = json.load(content)
- else:
- error_text = "Invalid yaml format "
- indata = yaml.load(content)
- return {"_id": transaction_id, "storage": storage, "desc": indata}
- except EngineException:
- raise
- except IndexError:
- raise EngineException("invalid Content-Range header format. Expected 'bytes start-end/total'",
- HTTPStatus.BAD_REQUEST)
- except IOError as e:
- raise EngineException("invalid upload transaction sequence: '{}'".format(e), HTTPStatus.BAD_REQUEST)
- except (ValueError, yaml.YAMLError) as e:
- raise EngineException(error_text + str(e))
- finally:
- if file_pkg:
- file_pkg.close()
-
- def new_nsr(self, session, ns_request):