def POST(self, req): """ Handles Delete Multiple Objects. """ def object_key_iter(xml): dom = parseString(xml) delete = dom.getElementsByTagName('Delete')[0] for obj in delete.getElementsByTagName('Object'): key = obj.getElementsByTagName('Key')[0].firstChild.data version = None if obj.getElementsByTagName('VersionId').length > 0: version = obj.getElementsByTagName('VersionId')[0]\ .firstChild.data yield (key, version) def get_deleted_elem(key): return ' <Deleted>\r\n' \ ' <Key>%s</Key>\r\n' \ ' </Deleted>\r\n' % (key) def get_err_elem(key, err_code, message): return ' <Error>\r\n' \ ' <Key>%s</Key>\r\n' \ ' <Code>%s</Code>\r\n' \ ' <Message>%s</Message>\r\n' \ ' </Error>\r\n' % (key, err_code, message) body = '<?xml version="1.0" encoding="UTF-8"?>\r\n' \ '<DeleteResult ' \ 'xmlns="http://doc.s3.amazonaws.com/2006-03-01">\r\n' for key, version in object_key_iter(req.body): if version is not None: # TODO: delete the specific version of the object return get_err_response('Unsupported') sub_req = Request(req.environ.copy()) sub_req.query_string = '' sub_req.content_length = 0 sub_req.method = 'DELETE' controller = ObjectController(sub_req, self.app, self.account_name, req.environ['HTTP_X_AUTH_TOKEN'], self.container_name, key) sub_resp = controller.DELETE(sub_req) status = sub_resp.status_int if status == HTTP_NO_CONTENT or status == HTTP_NOT_FOUND: body += get_deleted_elem(key) else: if status == HTTP_UNAUTHORIZED: body += get_err_elem(key, 'AccessDenied', 'Access Denied') else: body += get_err_elem(key, 'InvalidURI', 'Invalid URI') body += '</DeleteResult>\r\n' return HTTPOk(body=body)
def _delete_multiple_objects(self, req): def _object_key_iter(xml): dom = parseString(xml) delete = dom.getElementsByTagName('Delete')[0] for obj in delete.getElementsByTagName('Object'): key = obj.getElementsByTagName('Key')[0].firstChild.data version = None if obj.getElementsByTagName('VersionId').length > 0: version = obj.getElementsByTagName('VersionId')[0]\ .firstChild.data yield (key, version) def _get_deleted_elem(key): return ' <Deleted>\r\n' \ ' <Key>%s</Key>\r\n' \ ' </Deleted>\r\n' % (key) def _get_err_elem(key, err_code, message): return ' <Error>\r\n' \ ' <Key>%s</Key>\r\n' \ ' <Code>%s</Code>\r\n' \ ' <Message>%s</Message>\r\n' \ ' </Error>\r\n' % (key, err_code, message) body = '<?xml version="1.0" encoding="UTF-8"?>\r\n' \ '<DeleteResult ' \ 'xmlns="http://doc.s3.amazonaws.com/2006-03-01">\r\n' for key, version in _object_key_iter(req.body): if version is not None: # TODO: delete the specific version of the object return get_err_response('Unsupported') sub_req = Request(req.environ.copy()) sub_req.query_string = '' sub_req.content_length = 0 sub_req.method = 'DELETE' controller = ObjectController(sub_req, self.app, self.account_name, req.environ['HTTP_X_AUTH_TOKEN'], self.container_name, key) sub_resp = controller.DELETE(sub_req) status = sub_resp.status_int if status == HTTP_NO_CONTENT or status == HTTP_NOT_FOUND: body += _get_deleted_elem(key) else: if status == HTTP_UNAUTHORIZED: body += _get_err_elem(key, 'AccessDenied', 'Access Denied') else: body += _get_err_elem(key, 'InvalidURI', 'Invalid URI') body += '</DeleteResult>\r\n' return HTTPOk(body=body)
def transition(self, env): # GET Object body req = Request(copy(env)) req.method = 'GET' resp = req.get_response(self.app) obj_body = resp.body # Glacier로 업로드 tmpfile = self.save_to_tempfile(obj_body) try: glacier = self._init_glacier() archive_id = glacier.upload_archive(tmpfile) glacier_obj = make_glacier_hidden_object_name(self.obj, archive_id) except Exception as e: return Response(status=HTTP_INTERNAL_SERVER_ERROR, body=e.message) finally: self.delete_tempfile(tmpfile) # Object를 0KB로 만들기 req = Request(copy(env)) req.headers[GLACIER_FLAG_META] = True resp = req.get_response(self.app) # Glacier Hidden account에 기록 glacier_account = self.glacier_account_prefix + self.account part, nodes = self.container_ring.get_nodes(glacier_account, self.container) hidden_path = '/%s/%s/%s' % (glacier_account, self.container, glacier_obj) for node in nodes: ip = node['ip'] port = node['port'] dev = node['device'] headers = dict() headers['user-agent'] = 'transition-middleware' headers['X-Timestamp'] = normalize_timestamp(time.time()) headers['referer'] = req.as_referer() headers['x-size'] = '0' headers['x-content-type'] = 'text/plain' headers['x-etag'] = 'd41d8cd98f00b204e9800998ecf8427e' conn = http_connect(ip, port, dev, part, 'PUT', hidden_path, headers) conn.getresponse().read() return Response(status=HTTP_NO_CONTENT)
def _initialize(self): resp = None if self.swift_client: resp = self.swift_client.make_request('HEAD', self.path, {}, (2, 4)) elif self.env: req = Request(self.env) req.method = 'HEAD' req.path_info = self.path req.headers['Content-Length'] = '0' resp = req.get_response(self.app) if resp is None: return self.status = resp.status_int if is_success(self.status): self.headers = resp.headers
def DELETE(self, env, start_response): req = Request(env) def deleteSegmentObj(env, auth, container, obj): req.method = 'DELETE' env['PATH_INFO'] = ('/v1/%s/%s_segments/%s' % (auth, container, obj['name'])) env['RAW_PATH_INFO'] = ('/v1/%s/%s_segments/%s' % (auth, container, obj['name'])) env['SCRIPT_NAME'] = '' self.app(env, start_response) status = self._get_status_int() return status if 'QUERY_STRING' in env: args = dict(urlparse.parse_qsl(env['QUERY_STRING'], 1)) else: args = {} if 'uploadId' not in args: return self.app(env, start_response) uploadId = args['uploadId'] parts = urlparse.urlparse(req.url) version, auth, container, obj = split_path(parts.path, 0, 4, True) # # First check to see if this multi-part upload was already # completed. Look in the primary container, if the object exists, # then it was completed and we return an error here. # req.method = 'GET' env['PATH_INFO'] = ('/%s/%s/%s/%s' % (version, auth, container, obj)) env['RAW_PATH_INFO'] = ('/%s/%s/%s/%s' % (version, auth, container, obj)) del env['QUERY_STRING'] env['SCRIPT_NAME'] = '' body_iter = self._app_call(env) status = self._get_status_int() if is_success(status): # The object was found, so we must return an error return get_err_response('NoSuchUpload') elif status == HTTP_UNAUTHORIZED: return get_err_response('AccessDenied') elif status != HTTP_NOT_FOUND: return get_err_response('InvalidURI') # # The completed object was not found so this # must be a multipart upload abort. # We must delete any uploaded segments for this UploadID and then # delete the object in the main container as well # req.method = 'GET' env['PATH_INFO'] = ('/%s/%s/%s_segments/' % (version, auth, container)) env['RAW_PATH_INFO'] = ('/%s/%s/%s_segments/' % (version, auth, container)) env['QUERY_STRING'] = 'format=json&limit=1001&prefix=%s/%s/' \ '&delimiter=/' % (obj, uploadId) env['SCRIPT_NAME'] = '' body_iter = self._app_call(env) status = self._get_status_int() if not is_success(status): if status == HTTP_UNAUTHORIZED: return get_err_response('AccessDenied') elif status == HTTP_NOT_FOUND: return get_err_response('NoSuchUpload') else: return get_err_response('InvalidURI') # # Iterate over the segment objects and delete them individually # del env['QUERY_STRING'] objects = loads(''.join(list(body_iter))) for o in objects: status = deleteSegmentObj(env, auth, container, o) if not is_success(status): if status == HTTP_UNAUTHORIZED: return get_err_response('AccessDenied') elif status == HTTP_NOT_FOUND: return get_err_response('NoSuchObject') else: return get_err_response('InvalidURI') # # Delete the object from the segment container # req.method = 'DELETE' env['PATH_INFO'] = ('/%s/%s/%s_segments/%s' % (version, auth, container, obj)) env['RAW_PATH_INFO'] = ('/%s/%s/%s_segments/%s' % (version, auth, container, obj)) env['SCRIPT_NAME'] = '' body_iter = self._app_call(env) status = self._get_status_int() if is_success(status) is False and status != HTTP_NOT_FOUND: if status == HTTP_UNAUTHORIZED: return get_err_response('AccessDenied') else: return get_err_response('InvalidURI') resp = Response(status=204, body='') return resp(env, start_response)
def POST(self, env, start_response): req = Request(env) if 'QUERY_STRING' in env: args = dict(urlparse.parse_qsl(env['QUERY_STRING'], 1)) else: args = {} if 'uploads' in args: # # return multi-upload body start # parts = urlparse.urlparse(req.url) version, auth, cont = split_path(parts.path, 0, 3, True) path = env['RAW_PATH_INFO'] container, obj = split_path(path, 0, 2, True) # # Create a unique S3 upload id from the request string and salt # it with the current time to avoid duplicates. # m = md5.new(('/%s/%s/%s/%s-%d' % (version, auth, container, obj, time.time()))) upload_id = m.hexdigest() req.method = 'PUT' env['PATH_INFO'] = ('/v1/%s/%s_segments' % (auth, container)) env['RAW_PATH_INFO'] = ('/v1/%s/%s_segments' % (auth, container)) env['SCRIPT_NAME'] = '' env['QUERY_STRING'] = '' self._app_call(env) status = self._get_status_int() if not is_success(status): if status == HTTP_UNAUTHORIZED: return get_err_response('AccessDenied') elif status == HTTP_NOT_FOUND: return get_err_response('NoSuchBucket') else: return get_err_response('InvalidURI') # # Return the S3 response # body = ('<?xml version="1.0" encoding="UTF-8"?>\r\n' '<InitiateMultipartUploadResult xmlns=' '"http://doc.s3.amazonaws.com/2006-03-01/">\r\n' '<Bucket>%s</Bucket>\r\n' '<Key>%s</Key>\r\n' '<UploadId>%s</UploadId>\r\n' '</InitiateMultipartUploadResult>\r\n' % (container, obj, upload_id)) resp = Response(status=200, body=body, content_type='application/xml') return resp elif 'uploadId' in args: # Handle an individual S3 multipart upload segment return self.completeMultipartUpload(env, start_response) else: return self.app(env, start_response)
def completeMultipartUpload(self, env, start_response): req = Request(env) if 'QUERY_STRING' in env: args = dict(urlparse.parse_qsl(env['QUERY_STRING'], 1)) else: args = {} uploadId = args['uploadId'] urlparts = urlparse.urlparse(req.url) version, auth, ignored = split_path(urlparts.path, 2, 3, True) # We must get the actual container/object info from the RAW_PATH_INFO path = env['RAW_PATH_INFO'] container, obj = split_path(path, 0, 2, True) if obj is None: obj = os.path.basename(env['RAW_PATH_INFO']) # # Query for the objects in the segments area to make sure it completed # env['REQUEST_METHOD'] = 'GET' env['PATH_INFO'] = ('/%s/%s/%s_segments' % (version, auth, container)) env['RAW_PATH_INFO'] = ('/%s/%s/%s_segments' % (version, auth, container)) env['QUERY_STRING'] = 'format=json&limit=1001&prefix=%s/%s/' \ '&delimiter=/' % (obj, uploadId) env['SCRIPT_NAME'] = '' req = Request(env) body_iter = self._app_call(env) status = self._get_status_int() objinfo = loads(''.join(list(body_iter))) if len(objinfo) == 0: return get_err_response('NoSuchBucket') # # Tell Swift the manifest info # The content length should be 0 and the manifest should point to # the segment container. # req.method = 'PUT' req.headers['X-Object-Manifest'] = ('%s_segments/%s/%s' % (container, obj, uploadId)) req.headers['Content-Length'] = '0' env['PATH_INFO'] = ('/%s/%s/%s/%s' % (version, auth, container, obj)) env['RAW_PATH_INFO'] = ('/%s/%s/%s/%s' % (version, auth, container, obj)) del env['QUERY_STRING'] env['SCRIPT_NAME'] = '' req.body = '' body_iter = self._app_call(env) status = self._get_status_int() if status != HTTP_OK and status != HTTP_CREATED: if status == HTTP_UNAUTHORIZED: return get_err_response('AccessDenied') elif status == HTTP_NOT_FOUND: return get_err_response('NoSuchBucket') else: return get_err_response('InvalidURI') o = objinfo[0] body = ('<?xml version="1.0" encoding="UTF-8"?>' '<CompleteMultipartUploadResult ' 'xmlns="http://s3.amazonaws.com/doc/2006-03-01">' '<Location>%s://%s/%s/%s</Location>' '<Bucket>%s</Bucket>' '<Key>%s</Key>' '<ETag>"%s"</ETag>' '</CompleteMultipartUploadResult>' % (urlparts.scheme, urlparts.netloc, container, obj, container, o['name'], o['hash'])) resp = Response(body=body, content_type="application/xml") return resp
def GET(self, env, start_response): if 'QUERY_STRING' in env: args = dict(urlparse.parse_qsl(env['QUERY_STRING'], 1)) else: args = {} # # If 'uploadId' parameter is not present, then pass it along as a # standard 'GET' request # if 'uploadId' not in args and 'uploads' not in args: return self.app req = Request(env) if 'uploadId' in args: uploadId = args['uploadId'] if 'Authorization' not in req.headers: return get_err_response('AccessDenied') try: keyword, info = req.headers['Authorization'].split(' ') except: return get_err_response('AccessDenied') if keyword != 'AWS': return get_err_response('AccessDenied') try: account, signature = info.rsplit(':', 1) except: return get_err_response('InvalidArgument') if 'uploads' in args: return self.GET_uploads(env, start_response) maxparts = 1000 partNumMarker = 0 if 'max-parts' in args: try: maxparts = int(args['max-parts']) except: maxparts = 1000 if 'part-number-marker' in args: try: partNumMarker = int(args['part-number-marker']) except: partNumMarker = 0 parts = urlparse.urlparse(req.url) version, auth, container, obj = split_path(parts.path, 0, 4, True) # check if upload was completed or not. req.method = 'GET' env['PATH_INFO'] = ('/%s/%s/%s/%s' % (version, auth, container, obj)) env['RAW_PATH_INFO'] = ('/%s/%s/%s/%s' % (version, auth, container, obj)) del env['QUERY_STRING'] env['SCRIPT_NAME'] = '' body_iter = self._app_call(env) status = self._get_status_int() if is_success(status): return get_err_response('NoSuchUpload') # fetch all upload parts. env['PATH_INFO'] = ('/%s/%s/%s_segments/' % (version, auth, container)) env['RAW_PATH_INFO'] = ('/%s/%s/%s_segments/' % (version, auth, container)) env['QUERY_STRING'] = 'format=json&limit=1001&prefix=%s/%s/' \ '&delimiter=/' % (obj, uploadId) body_iter = self._app_call(env) status = self._get_status_int() if is_success(status) is False: if status == HTTP_UNAUTHORIZED: return get_err_response('AccessDenied') elif status == HTTP_NOT_FOUND: return get_err_response('NoSuchBucket') else: return get_err_response('InvalidURI') objects = loads(''.join(list(body_iter))) lastPart = '' firstPart = '' objList = [] # # If the caller requested a list starting at a specific part number, # construct a sub-set of the object list. # if partNumMarker > 0 and len(objects) > 0: for o in objects: num = self.getObjNum(o) if num >= partNumMarker: objList.append(o) else: objList = objects if maxparts > 0 and len(objList) == (maxparts + 1): truncated = True o = objList[-1] lastPart = os.path.basename(o['name']) else: truncated = False body = ('<?xml version="1.0" encoding="UTF-8"?>' '<ListPartsResult ' 'xmlns="http://s3.amazonaws.com/doc/2006-03-01">' '<Bucket>%s</Bucket>' '<Key>%s</Key>' '<UploadId>%s</UploadId>' '<Initiator><ID>%s</ID><DisplayName>%s</DisplayName>' '</Initiator>' '<Owner><ID>%s</ID><DisplayName>%s</DisplayName></Owner>' '<StorageClass>STANDARD</StorageClass>' '<IsTruncated>%s</IsTruncated>' '<MaxParts>%d</MaxParts>' % (xml_escape(container), xml_escape(obj), uploadId, account, account, account, account, 'true' if truncated else 'false', maxparts)) if len(objList) > 0: o = objList[0] firstPart = os.path.basename(o['name']) looped = "".join(['<Part><PartNumber>%s</PartNumber>' '<ETag>%s</ETag>' '<LastModified>%s</LastModified>' '<Size>%s</Size></Part>' % (xml_escape(unquote(os.path.basename( i['name']))), i['hash'], i['last_modified'], i['bytes']) for i in objList[:maxparts] if 'subdir' not in i]) body = body + ('<PartNumberMarker>%s</PartNumberMarker>' % firstPart) + \ ('%s' % ('<NextPartNumberMarker>%s</NextPartNumberMarker>' % lastPart) if truncated else '') + \ looped body = body + '</ListPartsResult>' return Response(status=HTTP_OK, body=body, content_type='application/xml')
def DELETE(self, env, start_response): req = Request(env) def deleteSegmentObj(env, auth, container, obj): req.method = "DELETE" env["PATH_INFO"] = "/v1/%s/%s_segments/%s" % (auth, container, obj["name"]) env["RAW_PATH_INFO"] = "/v1/%s/%s_segments/%s" % (auth, container, obj["name"]) env["SCRIPT_NAME"] = "" self.app(env, start_response) status = self._get_status_int() return status if "QUERY_STRING" in env: args = dict(urlparse.parse_qsl(env["QUERY_STRING"], 1)) else: args = {} if "uploadId" not in args: return self.app(env, start_response) uploadId = args["uploadId"] parts = urlparse.urlparse(req.url) version, auth, container, obj = split_path(parts.path, 0, 4, True) # # First check to see if this multi-part upload was already # completed. Look in the primary container, if the object exists, # then it was completed and we return an error here. # req.method = "GET" env["PATH_INFO"] = "/%s/%s/%s/%s" % (version, auth, container, obj) env["RAW_PATH_INFO"] = "/%s/%s/%s/%s" % (version, auth, container, obj) del env["QUERY_STRING"] env["SCRIPT_NAME"] = "" body_iter = self._app_call(env) status = self._get_status_int() if is_success(status): # The object was found, so we must return an error return get_err_response("NoSuchUpload") elif status == HTTP_UNAUTHORIZED: return get_err_response("AccessDenied") elif status != HTTP_NOT_FOUND: return get_err_response("InvalidURI") # # The completed object was not found so this # must be a multipart upload abort. # We must delete any uploaded segments for this UploadID and then # delete the object in the main container as well # req.method = "GET" env["PATH_INFO"] = "/%s/%s/%s_segments/" % (version, auth, container) env["RAW_PATH_INFO"] = "/%s/%s/%s_segments/" % (version, auth, container) env["QUERY_STRING"] = "format=json&limit=1001&prefix=%s/%s/" "&delimiter=/" % (obj, uploadId) env["SCRIPT_NAME"] = "" body_iter = self._app_call(env) status = self._get_status_int() if not is_success(status): if status == HTTP_UNAUTHORIZED: return get_err_response("AccessDenied") elif status == HTTP_NOT_FOUND: return get_err_response("NoSuchUpload") else: return get_err_response("InvalidURI") # # Iterate over the segment objects and delete them individually # del env["QUERY_STRING"] objects = loads("".join(list(body_iter))) for o in objects: status = deleteSegmentObj(env, auth, container, o) if not is_success(status): if status == HTTP_UNAUTHORIZED: return get_err_response("AccessDenied") elif status == HTTP_NOT_FOUND: return get_err_response("NoSuchObject") else: return get_err_response("InvalidURI") # # Delete the object from the segment container # req.method = "DELETE" env["PATH_INFO"] = "/%s/%s/%s_segments/%s" % (version, auth, container, obj) env["RAW_PATH_INFO"] = "/%s/%s/%s_segments/%s" % (version, auth, container, obj) env["SCRIPT_NAME"] = "" body_iter = self._app_call(env) status = self._get_status_int() if is_success(status) is False and status != HTTP_NOT_FOUND: if status == HTTP_UNAUTHORIZED: return get_err_response("AccessDenied") else: return get_err_response("InvalidURI") return Response(status=204, body="")
def completeMultipartUpload(self, env, start_response): req = Request(env) if "QUERY_STRING" in env: args = dict(urlparse.parse_qsl(env["QUERY_STRING"], 1)) else: args = {} uploadId = args["uploadId"] parts = urlparse.urlparse(req.url) version, auth, container, obj = split_path(parts.path, 0, 4, True) if obj is None: obj = os.path.basename(env["RAW_PATH_INFO"]) # # Query for the objects in the segments area to make sure it completed # env["REQUEST_METHOD"] = "GET" env["PATH_INFO"] = "/%s/%s/%s_segments" % (version, auth, container) env["RAW_PATH_INFO"] = "/%s/%s/%s_segments" % (version, auth, container) env["QUERY_STRING"] = "format=json&limit=1001&prefix=%s/%s/" "&delimiter=/" % (obj, uploadId) env["SCRIPT_NAME"] = "" req = Request(env) body_iter = self._app_call(env) status = self._get_status_int() objinfo = loads("".join(list(body_iter))) if len(objinfo) == 0: return get_err_response("NoSuchBucket") # # Tell Swift the manifest info # The content length should be 0 and the manifest should point to # the segment container. # req.method = "PUT" req.headers["X-Object-Manifest"] = "%s_segments/%s/%s" % (container, obj, uploadId) req.headers["Content-Length"] = "0" env["PATH_INFO"] = "/%s/%s/%s/%s" % (version, auth, container, obj) env["RAW_PATH_INFO"] = "/%s/%s/%s/%s" % (version, auth, container, obj) del env["QUERY_STRING"] env["SCRIPT_NAME"] = "" req.body = "" body_iter = self._app_call(env) status = self._get_status_int() if status != HTTP_OK and status != HTTP_CREATED: if status == HTTP_UNAUTHORIZED: return get_err_response("AccessDenied") elif status == HTTP_NOT_FOUND: return get_err_response("NoSuchBucket") else: return get_err_response("InvalidURI") o = objinfo[0] body = ( '<?xml version="1.0" encoding="UTF-8"?>' "<CompleteMultipartUploadResult " 'xmlns="http://s3.amazonaws.com/doc/2006-03-01">' "<Location>%s://%s/%s/%s</Location>" "<Bucket>%s</Bucket>" "<Key>%s</Key>" '<ETag>"%s"</ETag>' "</CompleteMultipartUploadResult>" % (parts.scheme, parts.netloc, container, obj, container, o["name"], o["hash"]) ) resp = Response(body=body, content_type="application/xml") return resp
def DELETE(self, env, start_response): req = Request(env) def deleteSegmentObj(env, auth, container, obj): req.method = 'DELETE' env['PATH_INFO'] = ('/v1/%s/%s_segments/%s' % (auth, container, obj['name'])) env['RAW_PATH_INFO'] = ('/v1/%s/%s_segments/%s' % (auth, container, obj['name'])) env['SCRIPT_NAME'] = '' self.app(env, start_response) status = self._get_status_int() return status if 'QUERY_STRING' in env: args = dict(urlparse.parse_qsl(env['QUERY_STRING'], 1)) else: args = {} if 'uploadId' not in args: return self.app(env, start_response) uploadId = args['uploadId'] parts = urlparse.urlparse(req.url) version, auth, container, obj = split_path(parts.path, 0, 4, True) # # First check to see if this multi-part upload was already # completed. Look in the primary container, if the object exists, # then it was completed and we return an error here. # req.method = 'GET' env['PATH_INFO'] = ('/%s/%s/%s/%s' % (version, auth, container, obj)) env['RAW_PATH_INFO'] = ('/%s/%s/%s/%s' % (version, auth, container, obj)) del env['QUERY_STRING'] env['SCRIPT_NAME'] = '' body_iter = self._app_call(env) status = self._get_status_int() if is_success(status): # The object was found, so we must return an error return get_err_response('NoSuchUpload') elif status == HTTP_UNAUTHORIZED: return get_err_response('AccessDenied') elif status != HTTP_NOT_FOUND: return get_err_response('InvalidURI') # # The completed object was not found so this # must be a multipart upload abort. # We must delete any uploaded segments for this UploadID and then # delete the object in the main container as well # req.method = 'GET' env['PATH_INFO'] = ('/%s/%s/%s_segments/' % (version, auth, container)) env['RAW_PATH_INFO'] = ('/%s/%s/%s_segments/' % (version, auth, container)) env['QUERY_STRING'] = 'format=json&limit=1001&prefix=%s/%s/' \ '&delimiter=/' % (obj, uploadId) env['SCRIPT_NAME'] = '' body_iter = self._app_call(env) status = self._get_status_int() if not is_success(status): if status == HTTP_UNAUTHORIZED: return get_err_response('AccessDenied') elif status == HTTP_NOT_FOUND: return get_err_response('NoSuchUpload') else: return get_err_response('InvalidURI') # # Iterate over the segment objects and delete them individually # del env['QUERY_STRING'] objects = loads(''.join(list(body_iter))) for o in objects: status = deleteSegmentObj(env, auth, container, o) if not is_success(status): if status == HTTP_UNAUTHORIZED: return get_err_response('AccessDenied') elif status == HTTP_NOT_FOUND: return get_err_response('NoSuchObject') else: return get_err_response('InvalidURI') # # Delete the object from the segment container # req.method = 'DELETE' env['PATH_INFO'] = ('/%s/%s/%s_segments/%s' % (version, auth, container, obj)) env['RAW_PATH_INFO'] = ('/%s/%s/%s_segments/%s' % (version, auth, container, obj)) env['SCRIPT_NAME'] = '' body_iter = self._app_call(env) status = self._get_status_int() if is_success(status) is False and status != HTTP_NOT_FOUND: if status == HTTP_UNAUTHORIZED: return get_err_response('AccessDenied') else: return get_err_response('InvalidURI') return Response(status=204, body='')
def completeMultipartUpload(self, env, start_response): req = Request(env) if 'QUERY_STRING' in env: args = dict(urlparse.parse_qsl(env['QUERY_STRING'], 1)) else: args = {} uploadId = args['uploadId'] parts = urlparse.urlparse(req.url) version, auth, container, obj = split_path(parts.path, 0, 4, True) if obj is None: obj = os.path.basename(env['RAW_PATH_INFO']) # # Query for the objects in the segments area to make sure it completed # env['REQUEST_METHOD'] = 'GET' env['PATH_INFO'] = ('/%s/%s/%s_segments' % (version, auth, container)) env['RAW_PATH_INFO'] = ('/%s/%s/%s_segments' % (version, auth, container)) env['QUERY_STRING'] = 'format=json&limit=1001&prefix=%s/%s/' \ '&delimiter=/' % (obj, uploadId) env['SCRIPT_NAME'] = '' req = Request(env) body_iter = self._app_call(env) status = self._get_status_int() objinfo = loads(''.join(list(body_iter))) if len(objinfo) == 0: return get_err_response('NoSuchBucket') # # Tell Swift the manifest info # The content length should be 0 and the manifest should point to # the segment container. # req.method = 'PUT' req.headers['X-Object-Manifest'] = ('%s_segments/%s/%s' % (container, obj, uploadId)) req.headers['Content-Length'] = '0' env['PATH_INFO'] = ('/%s/%s/%s/%s' % (version, auth, container, obj)) env['RAW_PATH_INFO'] = ('/%s/%s/%s/%s' % (version, auth, container, obj)) del env['QUERY_STRING'] env['SCRIPT_NAME'] = '' req.body = '' body_iter = self._app_call(env) status = self._get_status_int() if status != HTTP_OK and status != HTTP_CREATED: if status == HTTP_UNAUTHORIZED: return get_err_response('AccessDenied') elif status == HTTP_NOT_FOUND: return get_err_response('NoSuchBucket') else: return get_err_response('InvalidURI') o = objinfo[0] body = ('<?xml version="1.0" encoding="UTF-8"?>' '<CompleteMultipartUploadResult ' 'xmlns="http://s3.amazonaws.com/doc/2006-03-01">' '<Location>%s://%s/%s/%s</Location>' '<Bucket>%s</Bucket>' '<Key>%s</Key>' '<ETag>"%s"</ETag>' '</CompleteMultipartUploadResult>' % (parts.scheme, parts.netloc, container, obj, container, o['name'], o['hash'])) resp = Response(body=body, content_type="application/xml") return resp