def handle_request(self, env, start_response): try: return self._handle_request(env, start_response) except UnicodeDecodeError: self.logger.exception('Failed to decode request %r', env) resp = swob.HTTPBadRequest('Failed to decode request') return resp(env, start_response)
def initialize_request(self): """ Basic validation of request and mount check. This function will be called before attempting to acquire a replication semaphore lock, so contains only quick checks. """ # This environ override has been supported since eventlet 0.14: # https://bitbucket.org/eventlet/eventlet/commits/ \ # 4bd654205a4217970a57a7c4802fed7ff2c8b770 self.request.environ['eventlet.minimum_write_chunk_size'] = 0 self.device, self.partition, self.policy = \ request_helpers.get_name_and_placement(self.request, 2, 2, False) self.frag_index = self.node_index = None if self.request.headers.get('X-Backend-Ssync-Frag-Index'): self.frag_index = int( self.request.headers['X-Backend-Ssync-Frag-Index']) if self.request.headers.get('X-Backend-Ssync-Node-Index'): self.node_index = int( self.request.headers['X-Backend-Ssync-Node-Index']) if self.node_index != self.frag_index: # a primary node should only receive it's own fragments raise swob.HTTPBadRequest( 'Frag-Index (%s) != Node-Index (%s)' % (self.frag_index, self.node_index)) utils.validate_device_partition(self.device, self.partition) self.diskfile_mgr = self.app._diskfile_router[self.policy] if not self.diskfile_mgr.get_dev_path(self.device): raise swob.HTTPInsufficientStorage(drive=self.device) self.fp = self.request.environ['wsgi.input']
def __call__(self, req): try: vrs, acc, con, obj = req.split_path(2, 4, rest_with_last=True) except ValueError: return self.app # All requests if req.method == 'GET': account_info = get_account_info(req.environ, self.app) if account_info: recycled = account_info['meta'].get('recycled', '') delete_date = account_info['meta'].get('earliest-delete-date', '') if recycled == 'yes' and delete_date != '': return swob.HTTPNotFound( headers={ 'x-account-meta-recycled': 'yes', 'x-account-meta-earliest-delete-date': delete_date }, body= ("Account is marked for deletion. " "Send X-Remove-Account-Meta-Recycled header via POST to undelete." )) # Account specific requests if con is None: if req.method == 'DELETE': account_info = get_account_info(req.environ, self.app) if account_info: try: recycled = account_info['meta'].get('recycled', '') delete_date = int(account_info['meta'].get( 'earliest-delete-date', '0')) if recycled != "yes": return swob.HTTPMethodNotAllowed( content_type="text/plain", body= ("Account cannot be deleted directly. " "Send 'X-Account-Meta-Recycled: yes' in POST request to mark for deletion.\n" )) if time() < delete_date: return swob.HTTPMethodNotAllowed( content_type="text/plain", headers={ 'x-account-meta-recycled': 'yes', 'x-account-meta-earliest-delete-date': delete_date }, body= ("Account cannot be deleted yet, " "X-Account-Meta-Earliest-Delete-Date not reached yet.\n" )) return self.app except ValueError: return swob.HTTPInternalError( content_type="text/plain", body=( "Internal error. Cannot read recycled state.\n" )) if req.method == 'POST': if 'x-account-meta-earliest-delete-date' in req.headers or 'x-remove-account-meta-earliest-delete-date' in req.headers: return swob.HTTPMethodNotAllowed( content_type="text/plain", body=("Header X-Account-Meta-Earliest-Delete-Date " "cannot be set manually.\n")) if 'x-account-meta-recycled' in req.headers and req.headers[ 'x-account-meta-recycled'] == "yes": req.headers['x-account-meta-recycled'] = "yes" req.headers['x-account-meta-earliest-delete-date'] = str( int(time()) + self.account_recycled_seconds) return self.app if 'x-remove-account-meta-recycled' in req.headers: req.headers['x-remove-account-meta-recycled'] = "x" req.headers[ 'x-remove-account-meta-earliest-delete-date'] = "x" return self.app return self.app # Container specific requests if obj is None: return self.app # Object specific requests if req.method == 'GET': object_info = get_object_info(req.environ, self.app) if object_info: recycled = object_info['meta'].get('recycled', '') delete_date = object_info['meta'].get('delete-date', '') if recycled == 'yes': return swob.HTTPNotFound( headers={ 'x-object-meta-recycled': 'yes', 'x-object-meta-delete-date': delete_date }, body= ("Object is marked for deletion. " "Send X-Remove-Object-Meta-Recycled header via POST to undelete.\n" )) if req.method == 'DELETE': return swob.HTTPMethodNotAllowed( content_type="text/plain", body=( "DELETE requests are not allowed. " "Use POST with 'X-Object-Meta-Recycled: yes' instead.\n")) if req.method == 'POST' or req.method == 'PUT': if 'x-delete-at' in req.headers or 'x-delete-after' in req.headers or 'x-object-meta-delete-date' in req.headers: return swob.HTTPMethodNotAllowed( content_type="text/plain", body= ("Setting X-Delete-At/X-Delete-After/X-Object-Meta-Delete-Date directly is not allowed. " "Use POST with 'X-Object-Meta-Recycled: yes' instead.\n")) if 'x-object-meta-recycled' in req.headers: if req.headers['x-object-meta-recycled'] != "yes": return swob.HTTPBadRequest( content_type="text/plain", body=("Invalid value for X-Object-Meta-Recycled. " "Only 'yes' is allowed.\n")) req.headers['x-object-meta-recycled'] = "yes" req.headers['x-object-meta-delete-date'] = str( int(time()) + self.object_recycle_keep_seconds) req.headers['x-delete-after'] = str( self.object_recycle_keep_seconds) return self.app if 'x-remove-object-meta-recycled' in req.headers: req.headers['x-remove-object-meta-recycled'] = "x" req.headers['x-remove-object-meta-delete-date'] = "x" req.headers['x-remove-delete-at'] = "x" req.headers['x-remove-delete-after'] = "x" return self.app return self.app
def GET(self, req): """Serves a GET to the middleware.""" try: version, account, path = swift_utils.split_path( req.path, 2, 3, True) except ValueError: return swob.HTTPBadRequest(request=req) if path: path = utils.unicode_unquote(path).rstrip("/") self.logger.debug("Searching") # Get all of the request variables that we need. fmt = req.params.get('format', '').lower() accept_header = req.headers.get('Accept', '').lower() # Check for Accept header as well if fmt == '' and accept_header != '': if 'json' in accept_header: fmt = 'json' elif 'xml' in accept_header: fmt = 'xml' queries = [] for key, value in req.str_params.items(): if key.startswith('q.'): val = value.decode("utf-8").strip('*') queries.append((key[2:], val)) query = req.str_params.get('q') if query: query = query.decode("utf-8").strip('*') limit = int(req.params.get('limit', 0) or req.params.get('rows', 0)) or 100 start = int(req.params.get('start', 0) or req.params.get('offset', 0)) sort = req.params.get('sort', None) _type = req.params.get('type', None) if _type not in ['object', 'container', None, '']: return swob.HTTPBadRequest(request=req) field = (req.params.get('field', None) or req.params.get('df', None) or '_all') marker = req.params.get('marker', None) recursive = req.params.get('recursive', True) if type(recursive) is not bool: if recursive.lower() in ['false', '0', 'f']: recursive = False else: recursive = True srch = index.Searcher(self.elastic_hosts, self.search_index_name, account, logger=self.logger) srch.logger = self.logger if query: srch.add_condition(field, query) for f, q in queries: if f.startswith("meta-"): f = "meta." + f[5:] srch.add_condition(f, q) srch.path = path srch.recursive = recursive srch.type = _type srch.sort = sort srch.limit = limit srch.start = start srch.marker = marker try: results = srch.execute() except socket.timeout: return swob.HTTPServiceUnavailable(req=req) self.logger.debug(results) result_list = [] for item in results: t = index.filter_result_props(item) result_list.append(t) headers = [ ('X-Search-Items-Count', len(result_list)), ('X-Search-Items-Total', results.total), ('X-Search-Items-Offset', start), ] if fmt == 'json': headers.append(('Content-Type', 'application/json; charset=utf-8')) return swob.Response(request=req, body=json.dumps(result_list), headers=headers) elif fmt == 'xml': headers.append(('Content-Type', 'application/xml; charset=utf-8')) output_list = [ '<?xml version="1.0" encoding="UTF-8"?>', '<results>' ] for res in result_list: item = '<object>' for key, val in res.iteritems(): item += '<%s>%s</%s>' % (key, saxutils.escape( str(val)), key) item += '</object>' output_list.append(item) output_list.append('</results>') res_body = '\n'.join(output_list) return swob.Response(request=req, body=res_body, headers=headers) else: headers.append(('Content-Type', 'text/plain')) res_body = '' for res in result_list: for key, val in res.iteritems(): res_body += str(key) + ': ' + str(val) + '\n' res_body += '\n' return swob.Response(request=req, body=res_body, headers=headers)