def __call__(self, env, start_response): req = Request(env) try: version, account, container, obj = req.split_path( 2, 4, rest_with_last=True) is_swifty_request = valid_api_version(version) except ValueError: is_swifty_request = False if not is_swifty_request: return self.app(env, start_response) if not obj: typ = 'Container' if container else 'Account' client_header = 'X-%s-Rfc-Compliant-Etags' % typ sysmeta_header = 'X-%s-Sysmeta-Rfc-Compliant-Etags' % typ if client_header in req.headers: if req.headers[client_header]: req.headers[sysmeta_header] = config_true_value( req.headers[client_header]) else: req.headers[sysmeta_header] = '' if req.headers.get(client_header.replace('X-', 'X-Remove-', 1)): req.headers[sysmeta_header] = '' def translating_start_response(status, headers, exc_info=None): return start_response( status, [(client_header if h.title() == sysmeta_header else h, v) for h, v in headers], exc_info) return self.app(env, translating_start_response) container_info = get_container_info(env, self.app, 'EQ') if not container_info or not is_success(container_info['status']): return self.app(env, start_response) flag = container_info.get('sysmeta', {}).get('rfc-compliant-etags') if flag is None: account_info = get_account_info(env, self.app, 'EQ') if not account_info or not is_success(account_info['status']): return self.app(env, start_response) flag = account_info.get('sysmeta', {}).get('rfc-compliant-etags') if flag is None: flag = self.conf.get('enable_by_default', 'false') if not config_true_value(flag): return self.app(env, start_response) status, headers, resp_iter = req.call_application(self.app) headers = [(header, value) if header.lower() != 'etag' or (value.startswith( ('"', 'W/"')) and value.endswith('"')) else (header, '"%s"' % value) for header, value in headers] start_response(status, headers) return resp_iter
def __call__(self, env, start_response): req = Request(env) try: # account and container only version, acct, cont = req.split_path(2, 3) except ValueError: return self.app(env, start_response) if not valid_api_version(version) or req.method not in ('GET', 'HEAD'): return self.app(env, start_response) # OK, definitely have an account/container request. # Get the desired content-type, then force it to a JSON request. try: out_content_type = get_listing_content_type(req) except HTTPException as err: return err(env, start_response) params = req.params params['format'] = 'json' req.params = params status, headers, resp_iter = req.call_application(self.app) header_to_index = {} resp_content_type = resp_length = None for i, (header, value) in enumerate(headers): header = header.lower() if header == 'content-type': header_to_index[header] = i resp_content_type = value.partition(';')[0] elif header == 'content-length': header_to_index[header] = i resp_length = int(value) if not status.startswith('200 '): start_response(status, headers) return resp_iter if resp_content_type != 'application/json': start_response(status, headers) return resp_iter if resp_length is None or \ resp_length > MAX_CONTAINER_LISTING_CONTENT_LENGTH: start_response(status, headers) return resp_iter def set_header(header, value): if value is None: del headers[header_to_index[header]] else: headers[header_to_index[header]] = ( headers[header_to_index[header]][0], str(value)) if req.method == 'HEAD': set_header('content-type', out_content_type + '; charset=utf-8') set_header('content-length', None) # don't know, can't determine start_response(status, headers) return resp_iter body = b''.join(resp_iter) try: listing = json.loads(body) # Do a couple sanity checks if not isinstance(listing, list): raise ValueError if not all(isinstance(item, dict) for item in listing): raise ValueError except ValueError: # Static web listing that's returning invalid JSON? # Just pass it straight through; that's about all we *can* do. start_response(status, headers) return [body] try: if out_content_type.endswith('/xml'): if cont: body = container_to_xml(listing, cont) else: body = account_to_xml(listing, acct) elif out_content_type == 'text/plain': body = listing_to_text(listing) # else, json -- we continue down here to be sure we set charset except KeyError: # listing was in a bad format -- funky static web listing?? start_response(status, headers) return [body] if not body: status = '%s %s' % (HTTP_NO_CONTENT, RESPONSE_REASONS[HTTP_NO_CONTENT][0]) set_header('content-type', out_content_type + '; charset=utf-8') set_header('content-length', len(body)) start_response(status, headers) return [body]
def __call__(self, env, start_response): req = Request(env) try: # account and container only version, acct, cont = req.split_path(2, 3) except ValueError: is_account_or_container_req = False else: is_account_or_container_req = True if not is_account_or_container_req: return self.app(env, start_response) if not valid_api_version(version) or req.method not in ('GET', 'HEAD'): return self.app(env, start_response) # OK, definitely have an account/container request. # Get the desired content-type, then force it to a JSON request. try: out_content_type = get_listing_content_type(req) except HTTPException as err: return err(env, start_response) params = req.params can_vary = 'format' not in params params['format'] = 'json' req.params = params # Give other middlewares a chance to be in charge env.setdefault('swift.format_listing', True) status, headers, resp_iter = req.call_application(self.app) if not env.get('swift.format_listing'): start_response(status, headers) return resp_iter header_to_index = {} resp_content_type = resp_length = None for i, (header, value) in enumerate(headers): header = header.lower() if header == 'content-type': header_to_index[header] = i resp_content_type = value.partition(';')[0] elif header == 'content-length': header_to_index[header] = i resp_length = int(value) elif header == 'vary': header_to_index[header] = i if not status.startswith(('200 ', '204 ')): start_response(status, headers) return resp_iter if can_vary: if 'vary' in header_to_index: value = headers[header_to_index['vary']][1] if 'accept' not in list_from_csv(value.lower()): headers[header_to_index['vary']] = ('Vary', value + ', Accept') else: headers.append(('Vary', 'Accept')) if resp_content_type != 'application/json': start_response(status, headers) return resp_iter if resp_length is None or \ resp_length > MAX_CONTAINER_LISTING_CONTENT_LENGTH: start_response(status, headers) return resp_iter def set_header(header, value): if value is None: del headers[header_to_index[header]] else: headers[header_to_index[header]] = ( headers[header_to_index[header]][0], str(value)) if req.method == 'HEAD': set_header('content-type', out_content_type + '; charset=utf-8') set_header('content-length', None) # don't know, can't determine start_response(status, headers) return resp_iter body = b''.join(resp_iter) try: listing = json.loads(body) # Do a couple sanity checks if not isinstance(listing, list): raise ValueError if not all(isinstance(item, dict) for item in listing): raise ValueError except ValueError: # Static web listing that's returning invalid JSON? # Just pass it straight through; that's about all we *can* do. start_response(status, headers) return [body] if not req.allow_reserved_names: listing = self.filter_reserved(listing, acct, cont) try: if out_content_type.endswith('/xml'): if cont: body = container_to_xml( listing, wsgi_to_bytes(cont).decode('utf-8')) else: body = account_to_xml(listing, wsgi_to_bytes(acct).decode('utf-8')) elif out_content_type == 'text/plain': body = listing_to_text(listing) else: body = json.dumps(listing).encode('ascii') except KeyError: # listing was in a bad format -- funky static web listing?? start_response(status, headers) return [body] if not body: status = '%s %s' % (HTTP_NO_CONTENT, RESPONSE_REASONS[HTTP_NO_CONTENT][0]) set_header('content-type', out_content_type + '; charset=utf-8') set_header('content-length', len(body)) start_response(status, headers) return [body]