--HG-- rename : wsme/protocols/__init__.py => wsme/protocol.py rename : wsme/protocols/commons.py => wsme/rest/args.py rename : wsme/protocols/restjson.py => wsme/rest/json.py rename : wsme/protocols/rest.py => wsme/rest/protocol.py rename : wsme/protocols/restxml.py => wsme/rest/xml.py
102 lines
3.4 KiB
Python
102 lines
3.4 KiB
Python
import logging
|
|
import six
|
|
|
|
from six import u
|
|
|
|
from wsme.exc import ClientSideError, UnknownArgument
|
|
from wsme.protocol import CallContext, Protocol
|
|
from wsme.rest.args import from_params
|
|
from wsme.types import Unset
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
|
|
class RestProtocol(Protocol):
|
|
def iter_calls(self, request):
|
|
yield CallContext(request)
|
|
|
|
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('/')
|
|
|
|
if path[-1].endswith('.' + self.dataformat):
|
|
path[-1] = path[-1][:-len(self.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
|
|
|
|
if 'Content-Type' in request.headers \
|
|
and ("application/x-www-form-urlencoded"
|
|
in request.headers['Content-Type']
|
|
or "multipart/form-data"
|
|
in request.headers['Content-Type']):
|
|
# The params were read from the body, ignoring the body then
|
|
pass
|
|
elif len(request.params) and request.content_length:
|
|
log.warning("The request has both a body and params.")
|
|
log.debug("Params: %s" % request.params)
|
|
log.debug("Body: %s" % request.body)
|
|
raise ClientSideError(
|
|
"Cannot read parameters from both a body and GET/POST params")
|
|
|
|
body = None
|
|
if 'body' in request.params:
|
|
body = request.params['body']
|
|
|
|
if body is None and len(request.params):
|
|
kw = {}
|
|
hit_paths = set()
|
|
for argdef in funcdef.arguments:
|
|
value = from_params(
|
|
argdef.datatype, request.params, argdef.name, hit_paths)
|
|
if value is not Unset:
|
|
kw[argdef.name] = value
|
|
paths = set(request.params.keys())
|
|
unknown_paths = paths - hit_paths
|
|
if unknown_paths:
|
|
raise UnknownArgument(', '.join(unknown_paths))
|
|
return kw
|
|
else:
|
|
if body is None:
|
|
body = request.body
|
|
if isinstance(body, six.binary_type):
|
|
body = body.decode('utf8')
|
|
if body:
|
|
parsed_args = self.parse_args(body)
|
|
else:
|
|
parsed_args = {}
|
|
|
|
kw = {}
|
|
|
|
for arg in funcdef.arguments:
|
|
if arg.name not in parsed_args:
|
|
continue
|
|
|
|
value = parsed_args.pop(arg.name)
|
|
kw[arg.name] = self.decode_arg(value, arg)
|
|
|
|
if parsed_args:
|
|
raise UnknownArgument(u(', ').join(parsed_args.keys()))
|
|
return kw
|