370125784f
This patch consolidates the string literals spreading everywhere into a constant module for ease of maintenance. Change-Id: Iac3c9d298983019e63d6d629affe5fedf05d05fe
132 lines
4.7 KiB
Python
132 lines
4.7 KiB
Python
# Copyright (c) 2015 Red Hat, Inc.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
|
# use this file except in compliance with the License. You may obtain a copy
|
|
# of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations under
|
|
# the License.
|
|
|
|
from zaqar.api.v2 import endpoints
|
|
from zaqar.api.v2 import request as schema_validator
|
|
|
|
from zaqar.common.api import request
|
|
from zaqar.common.api import response
|
|
from zaqar.common import consts
|
|
from zaqar.common import errors
|
|
from zaqar.common import urls
|
|
|
|
|
|
class Handler(object):
|
|
"""Defines API handler
|
|
|
|
The handler validates and process the requests
|
|
"""
|
|
|
|
_actions_mapping = {
|
|
consts.MESSAGE_LIST: 'GET',
|
|
consts.MESSAGE_GET: 'GET',
|
|
consts.MESSAGE_GET_MANY: 'GET',
|
|
consts.MESSAGE_POST: 'POST',
|
|
consts.MESSAGE_DELETE: 'DELETE',
|
|
consts.MESSAGE_DELETE_MANY: 'DELETE'
|
|
}
|
|
|
|
def __init__(self, storage, control, validate, defaults):
|
|
self.v2_endpoints = endpoints.Endpoints(storage, control,
|
|
validate, defaults)
|
|
self._subscription_factory = None
|
|
|
|
def set_subscription_factory(self, factory):
|
|
self._subscription_factory = factory
|
|
|
|
def clean_subscriptions(self, subscriptions):
|
|
for resp in subscriptions:
|
|
body = {'queue_name': resp._request._body.get('queue_name'),
|
|
'subscription_id': resp._body.get('subscription_id')}
|
|
payload = {'body': body, 'headers': resp._request._headers}
|
|
req = self.create_request(payload)
|
|
self.v2_endpoints.subscription_delete(req)
|
|
|
|
def process_request(self, req, protocol):
|
|
# FIXME(vkmc): Control API version
|
|
if req._action == consts.SUBSCRIPTION_CREATE:
|
|
subscriber = req._body.get('subscriber')
|
|
if not subscriber:
|
|
# Default to the connected websocket as subscriber
|
|
subscriber = self._subscription_factory.get_subscriber(
|
|
protocol)
|
|
return self.v2_endpoints.subscription_create(req, subscriber)
|
|
|
|
return getattr(self.v2_endpoints, req._action)(req)
|
|
|
|
@staticmethod
|
|
def validate_request(payload, req):
|
|
"""Validate a request and its payload against a schema.
|
|
|
|
:return: a Response object if validation failed, None otherwise.
|
|
"""
|
|
try:
|
|
action = payload.get('action')
|
|
validator = schema_validator.RequestSchema()
|
|
is_valid = validator.validate(action=action, body=payload)
|
|
except errors.InvalidAction as ex:
|
|
body = {'error': str(ex)}
|
|
headers = {'status': 400}
|
|
return response.Response(req, body, headers)
|
|
else:
|
|
if not is_valid:
|
|
body = {'error': 'Schema validation failed.'}
|
|
headers = {'status': 400}
|
|
return response.Response(req, body, headers)
|
|
|
|
def create_response(self, code, body, req=None):
|
|
if req is None:
|
|
req = self.create_request()
|
|
headers = {'status': code}
|
|
return response.Response(req, body, headers)
|
|
|
|
@staticmethod
|
|
def create_request(payload=None, env=None):
|
|
if payload is None:
|
|
payload = {}
|
|
action = payload.get('action')
|
|
body = payload.get('body', {})
|
|
headers = payload.get('headers')
|
|
|
|
return request.Request(action=action, body=body,
|
|
headers=headers, api="v2", env=env)
|
|
|
|
def get_defaults(self):
|
|
return self.v2_endpoints._defaults
|
|
|
|
def verify_signature(self, key, payload):
|
|
action = payload.get('action')
|
|
method = self._actions_mapping.get(action)
|
|
|
|
headers = payload.get('headers', {})
|
|
project = headers.get('X-Project-ID')
|
|
expires = headers.get('URL-Expires')
|
|
methods = headers.get('URL-Methods')
|
|
paths = headers.get('URL-Paths')
|
|
signature = headers.get('URL-Signature')
|
|
|
|
if not method or method not in methods:
|
|
return False
|
|
|
|
try:
|
|
verified = urls.verify_signed_headers_data(key, paths,
|
|
project=project,
|
|
methods=methods,
|
|
expires=expires,
|
|
signature=signature)
|
|
except ValueError:
|
|
return False
|
|
|
|
return verified
|