Web: add support for the POST HTTP method. (#1097)

* Web: add support for the POST HTTP method.

This patch adds support for POST in addition to the already supported GET.

This is needed for implementing more complex web modules that also
support configuration modifications and advanced queries.

* Base web: return METHOD_NOT_ALLOWED when method isn't implemenetd.

Co-authored-by: Unrud <Unrud@users.noreply.github.com>
This commit is contained in:
Tom Hacohen 2020-09-14 19:17:45 +03:00 committed by GitHub
parent 6091bd46a3
commit d3bb19800c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 58 additions and 3 deletions

View File

@ -49,6 +49,7 @@ from radicale.app.mkcalendar import ApplicationMkcalendarMixin
from radicale.app.mkcol import ApplicationMkcolMixin from radicale.app.mkcol import ApplicationMkcolMixin
from radicale.app.move import ApplicationMoveMixin from radicale.app.move import ApplicationMoveMixin
from radicale.app.options import ApplicationOptionsMixin from radicale.app.options import ApplicationOptionsMixin
from radicale.app.post import ApplicationPostMixin
from radicale.app.propfind import ApplicationPropfindMixin from radicale.app.propfind import ApplicationPropfindMixin
from radicale.app.proppatch import ApplicationProppatchMixin from radicale.app.proppatch import ApplicationProppatchMixin
from radicale.app.put import ApplicationPutMixin from radicale.app.put import ApplicationPutMixin
@ -63,7 +64,8 @@ class Application(
ApplicationMkcalendarMixin, ApplicationMkcolMixin, ApplicationMkcalendarMixin, ApplicationMkcolMixin,
ApplicationMoveMixin, ApplicationOptionsMixin, ApplicationMoveMixin, ApplicationOptionsMixin,
ApplicationPropfindMixin, ApplicationProppatchMixin, ApplicationPropfindMixin, ApplicationProppatchMixin,
ApplicationPutMixin, ApplicationReportMixin): ApplicationPostMixin, ApplicationPutMixin,
ApplicationReportMixin):
"""WSGI application.""" """WSGI application."""

30
radicale/app/post.py Normal file
View File

@ -0,0 +1,30 @@
# This file is part of Radicale Server - Calendar Server
# Copyright © 2008 Nicolas Kandel
# Copyright © 2008 Pascal Halter
# Copyright © 2008-2017 Guillaume Ayoub
# Copyright © 2017-2018 Unrud <unrud@outlook.com>
# Copyright © 2020 Tom Hacohen <tom@stosb.com>
#
# This library is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Radicale. If not, see <http://www.gnu.org/licenses/>.
from radicale import httputils
class ApplicationPostMixin:
def do_POST(self, environ, base_prefix, path, user):
"""Manage POST request."""
if path == "/.web" or path.startswith("/.web/"):
return self._web.post(environ, base_prefix, path, user)
return httputils.METHOD_NOT_ALLOWED

View File

@ -104,6 +104,11 @@ class BaseTest:
self._check_status(status, 200, check) self._check_status(status, 200, check)
return status, answer return status, answer
def post(self, path, check=True, **args):
status, _, answer = self.request("POST", path, **args)
self._check_status(status, 200, check)
return status, answer
def put(self, path, data, check=True, **args): def put(self, path, data, check=True, **args):
status, _, answer = self.request("PUT", path, data, **args) status, _, answer = self.request("PUT", path, data, **args)
self._check_status(status, 201, check) self._check_status(status, 201, check)

View File

@ -27,3 +27,6 @@ from radicale import web
class Web(web.BaseWeb): class Web(web.BaseWeb):
def get(self, environ, base_prefix, path, user): def get(self, environ, base_prefix, path, user):
return client.OK, {"Content-Type": "text/plain"}, "custom" return client.OK, {"Content-Type": "text/plain"}, "custom"
def post(self, environ, base_prefix, path, user):
return client.OK, {"Content-Type": "text/plain"}, "custom post"

View File

@ -63,3 +63,6 @@ class TestBaseWebRequests(BaseTest):
self.application = Application(self.configuration) self.application = Application(self.configuration)
_, answer = self.get("/.web") _, answer = self.get("/.web")
assert answer == "custom" assert answer == "custom"
_, answer = self.post("/.web")
assert answer == "custom post"

View File

@ -21,7 +21,7 @@ Take a look at the class ``BaseWeb`` if you want to implement your own.
""" """
from radicale import utils from radicale import httputils, utils
INTERNAL_TYPES = ("none", "internal") INTERNAL_TYPES = ("none", "internal")
@ -52,4 +52,16 @@ class BaseWeb:
``user`` is empty for anonymous users. ``user`` is empty for anonymous users.
""" """
raise NotImplementedError return httputils.METHOD_NOT_ALLOWED
def post(self, environ, base_prefix, path, user):
"""POST request.
``base_prefix`` is sanitized and never ends with "/".
``path`` is sanitized and always starts with "/.web"
``user`` is empty for anonymous users.
"""
return httputils.METHOD_NOT_ALLOWED