summaryrefslogtreecommitdiffstats
path: root/ipsilon/util/http.py
diff options
context:
space:
mode:
Diffstat (limited to 'ipsilon/util/http.py')
-rw-r--r--ipsilon/util/http.py68
1 files changed, 68 insertions, 0 deletions
diff --git a/ipsilon/util/http.py b/ipsilon/util/http.py
new file mode 100644
index 0000000..fa9d725
--- /dev/null
+++ b/ipsilon/util/http.py
@@ -0,0 +1,68 @@
+# Copyright (C) 2015 Ipsilon project Contributors, for license see COPYING
+
+import cherrypy
+import fnmatch
+
+
+def require_content_type(required=None, absent_ok=True, debug=False):
+ '''CherryPy Tool that validates request Content-Type.
+
+ This is a CherryPy Tool that checks the Content-Type in a request and
+ raises HTTP Error 415 "Unsupported Media Type" if it does not match.
+
+ The tool accepts a glob style pattern or list of patterns (see fnmatch)
+ and verifies the Content-Type in the request matches at least one of
+ the patterns, if not a HTTP Error 415 "Unsupported Media Type" is raised.
+
+ If absent_ok is False and if the request does not contain a
+ Content-Type header a HTTP Error 415 "Unsupported Media Type" is
+ raised.
+
+ The tool may be deployed use any of the standard methods for
+ invoking CherryPy tools, for example as a decorator:
+
+ @cherrypy.tools.require_content_type(required='text/xml')
+ def POST(self, *args, **kwargs):
+ pass
+
+ :param required: May be a single string or a list of strings. Each
+ string is interpreted as a glob style pattern (see fnmatch).
+ The Content-Type must match at least one pattern.
+
+ :param absent_ok: Boolean specifying if the Content-Type header
+ must be present or if it is OK to be absent.
+
+ '''
+ if required is None:
+ return
+
+ if isinstance(required, basestring):
+ required = [required]
+
+ content_type = cherrypy.request.body.content_type.value
+ pattern = None
+ match = False
+ if content_type:
+ for pattern in required:
+ if fnmatch.fnmatch(content_type, pattern):
+ match = True
+ break
+ else:
+ if absent_ok:
+ return
+
+ if debug:
+ cherrypy.log('require_content_type: required=%s, absent_ok=%s '
+ 'content_type=%s match=%s pattern=%s' %
+ required, absent_ok, content_type, match, pattern)
+
+ if not match:
+ acceptable = ', '.join(['"%s"' % x for x in required])
+ if content_type:
+ content_type = '"%s"' % content_type
+ else:
+ content_type = 'not specified'
+ message = ('Content-Type must match one of following patterns [%s], '
+ 'but the Content-Type was %s' %
+ (acceptable, content_type))
+ raise cherrypy.HTTPError(415, message=message)