changeset 931:8a393ae90f8c

server (pages): post requests are now handled: - if a HTTP post request is done, on_data_post is called on the page - LiberviaPage.getPostedData help to get easily needed data
author Goffi <goffi@goffi.org>
date Mon, 17 Apr 2017 20:41:00 +0200
parents b5490fa65348
children af6a62e21053
files src/server/constants.py src/server/server.py
diffstat 2 files changed, 58 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/src/server/constants.py	Sun Apr 16 18:26:31 2017 +0200
+++ b/src/server/constants.py	Mon Apr 17 20:41:00 2017 +0200
@@ -58,6 +58,10 @@
     PAGES_ACCESS_ADMIN = u"admin"  # only profiles set in admins_list can access the page
     PAGES_ACCESS_ALL = (PAGES_ACCESS_NONE, PAGES_ACCESS_PUBLIC, PAGES_ACCESS_PROFILE, PAGES_ACCESS_ADMIN)
 
+    ## HTTP methods ##
+    HTTP_METHOD_GET = u'GET'
+    HTTP_METHOD_POST = u'POST'
+
     ## HTTP codes ##
     HTTP_BAD_REQUEST = 400
     HTTP_UNAUTHORIZED = 401
--- a/src/server/server.py	Sun Apr 16 18:26:31 2017 +0200
+++ b/src/server/server.py	Mon Apr 17 20:41:00 2017 +0200
@@ -1426,7 +1426,7 @@
     uri_callbacks = {}
 
     def __init__(self, host, root_dir, name=None, redirect=None, access=None, parse_url=None,
-                 prepare_render=None, render=None, template=None):
+                 prepare_render=None, render=None, template=None, on_data_post=None):
         """initiate LiberviaPages
 
         LiberviaPages are the main resources of Libervia, using easy to set python files
@@ -1456,6 +1456,8 @@
             This method is mutually exclusive with template and must return a unicode string.
         @param template(unicode, None): path to the template to render.
             This method is mutually exclusive with render
+        @param on_data_post(callable, None): method to call when data is posted
+            None if not post is handled
         """
 
         web_resource.Resource.__init__(self)
@@ -1487,6 +1489,7 @@
         self.prepare_render = prepare_render
         self.template = template
         self.render_method = render
+        self.on_data_post = on_data_post
         if access == C.PAGES_ACCESS_NONE:
             # none pages just return a 404, no further check is needed
             return
@@ -1529,7 +1532,8 @@
                     parse_url=page_data.get('parse_url'),
                     prepare_render=page_data.get('prepare_render'),
                     render=page_data.get('render'),
-                    template=page_data.get('template'))
+                    template=page_data.get('template'),
+                    on_data_post=page_data.get('on_data_post'))
                 parent.putChild(d, resource)
                 new_path = path + [d]
                 log.info(u"Added /{path} page".format(path=u'[...]/'.join(new_path)))
@@ -1690,6 +1694,36 @@
         """don't raise error on CancelError"""
         failure_.trap(exceptions.CancelError)
 
+    def _on_data_post(self, dummy, request):
+        return defer.maybeDeferred(self.on_data_post, self, request)
+
+    def getPostedData(self, request, keys, multiple=False):
+        """get data from a POST request and decode it
+
+        @param request(server.Request): request linked to the session
+        @param keys(unicode, iterable[unicode]): name of the value(s) to get
+            unicode to get one value
+            iterable to get more than one
+        @param multiple(bool): True if multiple values are possible/expected
+            if False, the first value is returned
+        @return (iterator[unicode], list[iterator[unicode], unicode, list[unicode]): values received for this(these) key(s)
+        """
+        if isinstance(keys, basestring):
+            keys = [keys]
+            get_first = True
+        else:
+            get_first = False
+
+        ret = []
+        for key in keys:
+            gen = (urllib.unquote(v).decode('utf-8') for v in request.args.get(key,[]))
+            if multiple:
+                ret.append(gen)
+            else:
+                ret.append(next(gen))
+
+        return ret[0] if get_first else ret
+
     def getProfile(self, request):
         """helper method to easily get current profile
 
@@ -1750,6 +1784,21 @@
 
         d.addCallback(self._subpagesHandler, request)
 
+        if request.method not in (C.HTTP_METHOD_GET, C.HTTP_METHOD_POST):
+            # only HTTP GET and POST are handled so far
+            d.addCallback(lambda dummy: self.pageError(request, C.HTTP_BAD_REQUEST))
+
+
+        if request.method == C.HTTP_METHOD_POST:
+            if self.on_data_post is None:
+                # if we don't have on_data_post, the page was not expecting POST
+                # so we return an error
+                d.addCallback(lambda dummy: self.pageError(request, C.HTTP_BAD_REQUEST))
+            else:
+                d.addCallback(self._on_data_post, request)
+            # by default, POST follow normal behaviour after on_data_post is called
+            # this can be changed by a redirection or other method call in on_data_post
+
         if self.prepare_render:
             d.addCallback(self._prepare_render, request)
 
@@ -1766,6 +1815,9 @@
     def render_GET(self, request):
         return self.renderPage(request)
 
+    def render_POST(self, request):
+        return self.renderPage(request)
+
 
 class Libervia(service.Service):