def _gen_head_range_resp(self, req_range, resp): """ Swift doesn't handle Range header for HEAD requests. So, this method generates HEAD range response from HEAD response. S3 return HEAD range response, if the value of range satisfies the conditions which are described in the following document. - http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35 """ length = long(resp.headers.get('Content-Length')) try: content_range = Range(req_range) except ValueError: return resp ranges = content_range.ranges_for_length(length) if ranges == []: raise InvalidRange() elif ranges: if len(ranges) == 1: start, end = ranges[0] resp.headers['Content-Range'] = \ content_range_header_value(start, end, length) resp.headers['Content-Length'] = (end - start) resp.status = HTTP_PARTIAL_CONTENT return resp else: # TODO: It is necessary to confirm whether need to respond to # multi-part response.(e.g. bytes=0-10,20-30) pass return resp
def GETorHEAD(self, req): """ Handled GET or HEAD request on a part of a multipart object. """ part_number = self.parse_part_number(req) # Get the list of parts. Must be raw to get all response headers. slo_req = req.to_swift_req('GET', req.container_name, req.object_name, query={'multipart-manifest': 'get', 'format': 'raw'}) slo_resp = slo_req.get_response(self.app) # Check if the object is really a SLO. If not, and user asked # for the first part, do a regular request. if 'X-Static-Large-Object' not in slo_resp.headers: close_if_possible(slo_resp.app_iter) if part_number == 1: return req.get_response(self.app) else: raise InvalidRange() # Locate the part slo = json.loads(slo_resp.body) try: part = slo[part_number - 1] except IndexError: raise InvalidRange() # Redirect the request on the part _, req.container_name, req.object_name = part['path'].split('/', 2) # XXX enforce container_name and object_name to be <str> # or it will rise issues in swift3/requests when merging both req.container_name = req.container_name.encode('utf-8') req.object_name = req.object_name.encode('utf8') resp = req.get_response(self.app) # Get the content-type and etag of the object, not the part ctype, etag = extract_s3_etag(slo_resp.headers['Content-Type']) resp.headers['Content-Type'] = ctype if etag: resp.headers['ETag'] = '"%s"' % etag resp.headers['X-Amz-Mp-Parts-Count'] = len(slo) return resp
def GETorHEAD(self, req): """ Handled GET or HEAD request on a part of a multipart object. """ part_number = self.parse_part_number(req) had_match = False for match_header in ('if-match', 'if-none-match'): if match_header not in req.headers: continue had_match = True for value in list_from_csv(req.headers[match_header]): if value.startswith('"') and value.endswith('"'): value = value[1:-1] if value.endswith('-N'): # Deal with fake S3-like etags for SLOs uploaded via Swift req.headers[match_header] += ', ' + value[:-2] if had_match: # Update where to look update_etag_is_at_header(req, sysmeta_header('object', 'etag')) # Get the list of parts. Must be raw to get all response headers. slo_resp = req.get_response(self.app, 'GET', req.container_name, req.object_name, query={ 'multipart-manifest': 'get', 'format': 'raw' }) # Check if the object is really a SLO. If not, and user asked # for the first part, do a regular request. if 'X-Static-Large-Object' not in slo_resp.sw_headers: if part_number == 1: if slo_resp.is_success and req.method == 'HEAD': # Clear body slo_resp.body = '' return slo_resp else: close_if_possible(slo_resp.app_iter) raise InvalidRange() # Locate the part slo = json.loads(slo_resp.body) try: part = slo[part_number - 1] except IndexError: raise InvalidRange() # Redirect the request on the part _, req.container_name, req.object_name = part['path'].split('/', 2) # XXX enforce container_name and object_name to be <str> # or it will rise issues in swift3/requests when merging both req.container_name = req.container_name.encode('utf-8') req.object_name = req.object_name.encode('utf8') # The etag check was performed with the manifest if had_match: for match_header in ('if-match', 'if-none-match'): req.headers.pop(match_header, None) resp = req.get_response(self.app) # Replace status slo_resp.status = resp.status # Replace body slo_resp.app_iter = resp.app_iter # Update with the size of the part slo_resp.headers['Content-Length'] = \ resp.headers.get('Content-Length', 0) slo_resp.sw_headers['Content-Length'] = \ slo_resp.headers['Content-Length'] # Add the number of parts in this object slo_resp.headers['X-Amz-Mp-Parts-Count'] = len(slo) return slo_resp