| | 69 | |
|---|
| | 70 | request = cherrypy.request |
|---|
| | 71 | input_types = fi.input_types |
|---|
| | 72 | |
|---|
| | 73 | # the _tgws keyword is used when a web service system, such as |
|---|
| | 74 | # SOAP, is calling the function rather than a call that is being |
|---|
| | 75 | # made via direct URL traversal. |
|---|
| | 76 | if "_tgws" in kw: |
|---|
| | 77 | webservice = True |
|---|
| | 78 | del kw["_tgws"] |
|---|
| | 79 | else: |
|---|
| | 80 | webservice = False |
|---|
| | 81 | |
|---|
| | 82 | if "xml_body" in kw: |
|---|
| | 83 | kw = iconv.handle_xml_params(kw["xml_body"], input_types) |
|---|
| | 84 | elif request.headers.get("Content-Type", "") \ |
|---|
| | 85 | .startswith("text/xml"): |
|---|
| | 86 | try: |
|---|
| | 87 | clen = int(request.headers.get('Content-Length')) or 0 |
|---|
| | 88 | data = request.body.read(clen) |
|---|
| | 89 | body = et.fromstring(data) |
|---|
| | 90 | except SyntaxError: |
|---|
| | 91 | raise validators.Invalid("Request XML is invalid", "", |
|---|
| | 92 | None) |
|---|
| | 93 | kw = iconv.handle_xml_params(body, input_types) |
|---|
| | 94 | elif request.headers.get("Content-Type", "") \ |
|---|
| | 95 | .startswith("application/json"): |
|---|
| | 96 | clen = int(request.headers.get('Content-Length')) or 0 |
|---|
| | 97 | data = request.body.read(clen) |
|---|
| | 98 | kw = iconv.handle_json_params(data, input_types) |
|---|
| | 99 | else: |
|---|
| | 100 | iconv.handle_keyword_params(kw, input_types) |
|---|
| | 101 | |
|---|
| 112 | | def boolean_converter(value): |
|---|
| 113 | | value = value.lower() |
|---|
| 114 | | if value in ["", "false", "0", "no", "off"]: |
|---|
| 115 | | return False |
|---|
| 116 | | if value in ["true", "1", "yes", "on"]: |
|---|
| 117 | | return True |
|---|
| 118 | | raise validators.Invalid("%s is not a legal boolean value" % (value), |
|---|
| 119 | | value, None) |
|---|
| 120 | | |
|---|
| 121 | | def _get_single_value(elem, itype): |
|---|
| 122 | | """Converts a single XML element into the given type""" |
|---|
| 123 | | if isinstance(itype, list): |
|---|
| 124 | | itemtype = itype[0] |
|---|
| 125 | | items = [] |
|---|
| 126 | | for subelem in elem.getchildren(): |
|---|
| 127 | | items.append(_get_single_value(subelem, itemtype)) |
|---|
| 128 | | return items |
|---|
| 129 | | if not isinstance(itype, type): |
|---|
| 130 | | itype = type(itype) |
|---|
| 131 | | if itype not in primitives: |
|---|
| 132 | | return _xml_to_instance(elem, itype) |
|---|
| 133 | | if itype == bool: |
|---|
| 134 | | itype = boolean_converter |
|---|
| 135 | | |
|---|
| 136 | | if elem.text is None: |
|---|
| 137 | | text = "" |
|---|
| 138 | | else: |
|---|
| 139 | | text = elem.text |
|---|
| 140 | | |
|---|
| 141 | | try: |
|---|
| 142 | | return itype(text) |
|---|
| 143 | | except ValueError: |
|---|
| 144 | | raise validators.Invalid( |
|---|
| 145 | | "%s value for the '%s' parameter is not a " |
|---|
| 146 | | "valid %s" % (text, soap.namespace_expr.sub("", elem.tag), |
|---|
| 147 | | itype.__name__), |
|---|
| 148 | | text, None) |
|---|
| 149 | | |
|---|
| 150 | | def _xml_to_instance(input, cls): |
|---|
| 151 | | """Converts an input element into a new instance of cls.""" |
|---|
| 152 | | instance = cls() |
|---|
| 153 | | for elem in input.getchildren(): |
|---|
| 154 | | tag = soap.namespace_expr.sub("", elem.tag) |
|---|
| 155 | | try: |
|---|
| 156 | | itype = getattr(cls, tag) |
|---|
| 157 | | except AttributeError: |
|---|
| 158 | | raise validators.Invalid("%s is an unknown tag for a %s" |
|---|
| 159 | | % (tag, cls.__name__), |
|---|
| 160 | | tag, None) |
|---|
| 161 | | setattr(instance, tag, _get_single_value(elem, itype)) |
|---|
| 162 | | return instance |
|---|
| 163 | | |
|---|
| 164 | | def _handle_xml_params(body, input_types): |
|---|
| 165 | | kw = {} |
|---|
| 166 | | for elem in body.getchildren(): |
|---|
| 167 | | param = soap.namespace_expr.sub("", elem.tag) |
|---|
| 168 | | try: |
|---|
| 169 | | itype = input_types[param] |
|---|
| 170 | | except KeyError: |
|---|
| 171 | | raise validators.Invalid( |
|---|
| 172 | | "%s is not a valid parameter (valid values are: %s)" |
|---|
| 173 | | % (param, input_types.keys()), param, None |
|---|
| 174 | | ) |
|---|
| 175 | | kw[param] = _get_single_value(elem, itype) |
|---|
| 176 | | return kw |
|---|
| 177 | | |
|---|
| 178 | | def _handle_keyword_params(kw, input_types): |
|---|
| 179 | | # convert the input parameters to appropriate types |
|---|
| 180 | | for key in kw: |
|---|
| 181 | | if key in input_types: |
|---|
| 182 | | try: |
|---|
| 183 | | converter = input_types[key] |
|---|
| 184 | | if converter == bool: |
|---|
| 185 | | converter = boolean_converter |
|---|
| 186 | | kw[key] = converter(kw[key]) |
|---|
| 187 | | except ValueError: |
|---|
| 188 | | raise validators.Invalid( |
|---|
| 189 | | "%s value for the '%s' parameter is not a " |
|---|
| 190 | | "valid %s" % (kw[key], key, |
|---|
| 191 | | input_types[key].__name__), |
|---|
| 192 | | kw[key], None) |
|---|
| 193 | | else: |
|---|
| 194 | | raise validators.Invalid( |
|---|
| 195 | | "%s is not a valid parameter (valid values are: %s)" |
|---|
| 196 | | % (key, input_types.keys()), key, None |
|---|
| 197 | | ) |
|---|
| 198 | | |
|---|
| 199 | | def _get_json_value(value, itype): |
|---|
| 200 | | if isinstance(itype, list): |
|---|
| 201 | | itemtype = itype[0] |
|---|
| 202 | | return [_get_json_value(item, itemtype) for item in value] |
|---|
| 203 | | elif not isinstance(itype, type): |
|---|
| 204 | | return _get_json_value(value, type(itype)) |
|---|
| 205 | | elif itype not in primitives and isinstance(value, dict): |
|---|
| 206 | | return _create_instance_from_json(value, itype) |
|---|
| 207 | | return itype(value) |
|---|
| 208 | | |
|---|
| 209 | | def _create_instance_from_json(value, cls): |
|---|
| 210 | | instance = cls() |
|---|
| 211 | | for key in value: |
|---|
| 212 | | try: |
|---|
| 213 | | itype = getattr(cls, key) |
|---|
| 214 | | except AttributeError: |
|---|
| 215 | | raise validators.Invalid("%s is an unknown parameter for a %s" |
|---|
| 216 | | % (key, cls.__name__), |
|---|
| 217 | | key, None) |
|---|
| 218 | | setattr(instance, str(key), _get_json_value(value[key], itype)) |
|---|
| 219 | | return instance |
|---|
| 220 | | |
|---|
| 221 | | def _handle_json_params(input, input_types): |
|---|
| 222 | | if isinstance(input, basestring): |
|---|
| 223 | | try: |
|---|
| 224 | | input = simplejson.loads(input) |
|---|
| 225 | | except ValueError: |
|---|
| 226 | | raise validators.Invalid("Invalid JSON input") |
|---|
| 227 | | kw = {} |
|---|
| 228 | | for key in input: |
|---|
| 229 | | if key in input_types: |
|---|
| 230 | | kw[str(key)] = _get_json_value(input[key], input_types[key]) |
|---|
| 231 | | else: |
|---|
| 232 | | raise validators.Invalid( |
|---|
| 233 | | "%s is not a valid parameter (valid values are: %s)" |
|---|
| 234 | | % (key, input_types.keys()), key, None |
|---|
| 235 | | ) |
|---|
| 236 | | return kw |
|---|
| 237 | | |
|---|
| 238 | | |
|---|
| 258 | | |
|---|
| 259 | | def newfunc(self, **kw): |
|---|
| 260 | | request = cherrypy.request |
|---|
| 261 | | if "xml_body" in kw and len(kw) == 1: |
|---|
| 262 | | body = kw.pop("xml_body") |
|---|
| 263 | | kw = _handle_xml_params(body, input_types) |
|---|
| 264 | | elif request.headers.get("Content-Type", "") \ |
|---|
| 265 | | .startswith("text/xml"): |
|---|
| 266 | | try: |
|---|
| 267 | | clen = int(request.headers.get('Content-Length')) or 0 |
|---|
| 268 | | data = request.body.read(clen) |
|---|
| 269 | | body = et.fromstring(data) |
|---|
| 270 | | except SyntaxError: |
|---|
| 271 | | raise validators.Invalid("Request XML is invalid", "", |
|---|
| 272 | | None) |
|---|
| 273 | | kw = _handle_xml_params(body, input_types) |
|---|
| 274 | | elif request.headers.get("Content-Type", "") \ |
|---|
| 275 | | .startswith("application/json"): |
|---|
| 276 | | clen = int(request.headers.get('Content-Length')) or 0 |
|---|
| 277 | | data = request.body.read(clen) |
|---|
| 278 | | kw = _handle_json_params(data, input_types) |
|---|
| 279 | | else: |
|---|
| 280 | | _handle_keyword_params(kw, input_types) |
|---|
| 281 | | |
|---|
| 282 | | return func(self, **kw) |
|---|
| 283 | | newfunc.__name__ = func.__name__ |
|---|
| 284 | | newfunc.__doc__ = func.__doc__ |
|---|
| 285 | | newfunc._ws_func_info = func._ws_func_info |
|---|
| 286 | | return newfunc |
|---|
| | 159 | return func |
|---|