
These are not discoverable and, in this particular instance, unnecessary. Change-Id: I43757263ebbb009d10a6023bbd126b41408cbdc0 Signed-off-by: Stephen Finucane <stephenfin@redhat.com>
140 lines
4.4 KiB
Python
140 lines
4.4 KiB
Python
import os.path
|
|
import logging
|
|
|
|
from wsme.utils import OrderedDict
|
|
from wsme.protocol import CallContext, Protocol, media_type_accept
|
|
|
|
import wsme.rest
|
|
from wsme.rest import json
|
|
from wsme.rest import xml
|
|
import wsme.runtime
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
|
|
class RestProtocol(Protocol):
|
|
name = 'rest'
|
|
displayname = 'REST'
|
|
formatters = {
|
|
'json': json,
|
|
'xml': xml,
|
|
}
|
|
|
|
def __init__(self, dataformats=None):
|
|
if dataformats is None:
|
|
dataformats = ('json', 'xml')
|
|
|
|
self.dataformats = OrderedDict()
|
|
self.content_types = []
|
|
|
|
for dataformat in dataformats:
|
|
formatter = self.formatters[dataformat]
|
|
self.dataformats[dataformat] = formatter
|
|
self.content_types.extend(formatter.accept_content_types)
|
|
|
|
def accept(self, request):
|
|
for dataformat in self.dataformats:
|
|
if request.path.endswith('.' + dataformat):
|
|
return True
|
|
return media_type_accept(request, self.content_types)
|
|
|
|
def iter_calls(self, request):
|
|
context = CallContext(request)
|
|
context.outformat = None
|
|
ext = os.path.splitext(request.path.split('/')[-1])[1]
|
|
inmime = request.content_type
|
|
try:
|
|
offers = request.accept.acceptable_offers(self.content_types)
|
|
outmime = offers[0][0]
|
|
except IndexError:
|
|
outmime = None
|
|
|
|
outformat = None
|
|
informat = None
|
|
for dfname, df in self.dataformats.items():
|
|
if ext == '.' + dfname:
|
|
outformat = df
|
|
if not inmime:
|
|
informat = df
|
|
|
|
if outformat is None and request.accept:
|
|
for dfname, df in self.dataformats.items():
|
|
if outmime in df.accept_content_types:
|
|
outformat = df
|
|
if not inmime:
|
|
informat = df
|
|
|
|
if outformat is None:
|
|
for dfname, df in self.dataformats.items():
|
|
if inmime == df.content_type:
|
|
outformat = df
|
|
|
|
context.outformat = outformat
|
|
context.outformat_options = {
|
|
'nest_result': getattr(self, 'nest_result', False)
|
|
}
|
|
if not inmime and informat:
|
|
inmime = informat.content_type
|
|
log.debug("Inferred input type: %s" % inmime)
|
|
context.inmime = inmime
|
|
yield context
|
|
|
|
def extract_path(self, context):
|
|
path = context.request.path
|
|
assert path.startswith(self.root._webpath)
|
|
path = path[len(self.root._webpath):]
|
|
path = path.strip('/').split('/')
|
|
|
|
for dataformat in self.dataformats:
|
|
if path[-1].endswith('.' + dataformat):
|
|
path[-1] = path[-1][:-len(dataformat) - 1]
|
|
|
|
# Check if the path is actually a function, and if not
|
|
# see if the http method make a difference
|
|
# TODO Re-think the function lookup phases. Here we are
|
|
# doing the job that will be done in a later phase, which
|
|
# is sub-optimal
|
|
for p, fdef in self.root.getapi():
|
|
if p == path:
|
|
return path
|
|
|
|
# No function at this path. Now check for function that have
|
|
# this path as a prefix, and declared an http method
|
|
for p, fdef in self.root.getapi():
|
|
if len(p) == len(path) + 1 and p[:len(path)] == path and \
|
|
fdef.extra_options.get('method') == context.request.method:
|
|
return p
|
|
|
|
return path
|
|
|
|
def read_arguments(self, context):
|
|
request = context.request
|
|
funcdef = context.funcdef
|
|
|
|
body = None
|
|
if request.content_length not in (None, 0, '0'):
|
|
body = request.body
|
|
if not body and '__body__' in request.params:
|
|
body = request.params['__body__']
|
|
|
|
args, kwargs = wsme.rest.args.combine_args(
|
|
funcdef,
|
|
(wsme.rest.args.args_from_params(funcdef, request.params),
|
|
wsme.rest.args.args_from_body(funcdef, body, context.inmime))
|
|
)
|
|
wsme.runtime.check_arguments(funcdef, args, kwargs)
|
|
return kwargs
|
|
|
|
def encode_result(self, context, result):
|
|
out = context.outformat.encode_result(
|
|
result, context.funcdef.return_type,
|
|
**context.outformat_options
|
|
)
|
|
return out
|
|
|
|
def encode_error(self, context, errordetail):
|
|
out = context.outformat.encode_error(
|
|
context, errordetail
|
|
)
|
|
return out
|