Extract read*_request_body methods
This commit is contained in:
parent
42ad18bc84
commit
0ce90d6b34
@ -99,30 +99,6 @@ class Application(
|
|||||||
|
|
||||||
return request_environ
|
return request_environ
|
||||||
|
|
||||||
def _decode(self, text, environ):
|
|
||||||
"""Try to magically decode ``text`` according to given ``environ``."""
|
|
||||||
# List of charsets to try
|
|
||||||
charsets = []
|
|
||||||
|
|
||||||
# First append content charset given in the request
|
|
||||||
content_type = environ.get("CONTENT_TYPE")
|
|
||||||
if content_type and "charset=" in content_type:
|
|
||||||
charsets.append(
|
|
||||||
content_type.split("charset=")[1].split(";")[0].strip())
|
|
||||||
# Then append default Radicale charset
|
|
||||||
charsets.append(self._encoding)
|
|
||||||
# Then append various fallbacks
|
|
||||||
charsets.append("utf-8")
|
|
||||||
charsets.append("iso8859-1")
|
|
||||||
|
|
||||||
# Try to decode
|
|
||||||
for charset in charsets:
|
|
||||||
try:
|
|
||||||
return text.decode(charset)
|
|
||||||
except UnicodeDecodeError:
|
|
||||||
pass
|
|
||||||
raise UnicodeDecodeError
|
|
||||||
|
|
||||||
def __call__(self, environ, start_response):
|
def __call__(self, environ, start_response):
|
||||||
with log.register_stream(environ["wsgi.errors"]):
|
with log.register_stream(environ["wsgi.errors"]):
|
||||||
try:
|
try:
|
||||||
@ -244,8 +220,9 @@ class Application(
|
|||||||
login, password = login or "", password or ""
|
login, password = login or "", password or ""
|
||||||
elif authorization.startswith("Basic"):
|
elif authorization.startswith("Basic"):
|
||||||
authorization = authorization[len("Basic"):].strip()
|
authorization = authorization[len("Basic"):].strip()
|
||||||
login, password = self._decode(base64.b64decode(
|
login, password = httputils.decode_request(
|
||||||
authorization.encode("ascii")), environ).split(":", 1)
|
self.configuration, environ, base64.b64decode(
|
||||||
|
authorization.encode("ascii"))).split(":", 1)
|
||||||
|
|
||||||
user = self._auth.login(login, password) or "" if login else ""
|
user = self._auth.login(login, password) or "" if login else ""
|
||||||
if user and login == user:
|
if user and login == user:
|
||||||
@ -317,22 +294,10 @@ class Application(
|
|||||||
|
|
||||||
return response(status, headers, answer)
|
return response(status, headers, answer)
|
||||||
|
|
||||||
def _read_raw_content(self, environ):
|
def _read_xml_request_body(self, environ):
|
||||||
content_length = int(environ.get("CONTENT_LENGTH") or 0)
|
content = httputils.decode_request(
|
||||||
if not content_length:
|
self.configuration, environ,
|
||||||
return b""
|
httputils.read_raw_request_body(self.configuration, environ))
|
||||||
content = environ["wsgi.input"].read(content_length)
|
|
||||||
if len(content) < content_length:
|
|
||||||
raise RuntimeError("Request body too short: %d" % len(content))
|
|
||||||
return content
|
|
||||||
|
|
||||||
def _read_content(self, environ):
|
|
||||||
content = self._decode(self._read_raw_content(environ), environ)
|
|
||||||
logger.debug("Request content:\n%s", content)
|
|
||||||
return content
|
|
||||||
|
|
||||||
def _read_xml_content(self, environ):
|
|
||||||
content = self._decode(self._read_raw_content(environ), environ)
|
|
||||||
if not content:
|
if not content:
|
||||||
return None
|
return None
|
||||||
try:
|
try:
|
||||||
|
@ -33,7 +33,7 @@ class ApplicationMkcalendarMixin:
|
|||||||
if "w" not in self._rights.authorization(user, path):
|
if "w" not in self._rights.authorization(user, path):
|
||||||
return httputils.NOT_ALLOWED
|
return httputils.NOT_ALLOWED
|
||||||
try:
|
try:
|
||||||
xml_content = self._read_xml_content(environ)
|
xml_content = self._read_xml_request_body(environ)
|
||||||
except RuntimeError as e:
|
except RuntimeError as e:
|
||||||
logger.warning(
|
logger.warning(
|
||||||
"Bad MKCALENDAR request on %r: %s", path, e, exc_info=True)
|
"Bad MKCALENDAR request on %r: %s", path, e, exc_info=True)
|
||||||
|
@ -34,7 +34,7 @@ class ApplicationMkcolMixin:
|
|||||||
if not rights.intersect(permissions, "Ww"):
|
if not rights.intersect(permissions, "Ww"):
|
||||||
return httputils.NOT_ALLOWED
|
return httputils.NOT_ALLOWED
|
||||||
try:
|
try:
|
||||||
xml_content = self._read_xml_content(environ)
|
xml_content = self._read_xml_request_body(environ)
|
||||||
except RuntimeError as e:
|
except RuntimeError as e:
|
||||||
logger.warning(
|
logger.warning(
|
||||||
"Bad MKCOL request on %r: %s", path, e, exc_info=True)
|
"Bad MKCOL request on %r: %s", path, e, exc_info=True)
|
||||||
|
@ -347,7 +347,7 @@ class ApplicationPropfindMixin:
|
|||||||
if not access.check("r"):
|
if not access.check("r"):
|
||||||
return httputils.NOT_ALLOWED
|
return httputils.NOT_ALLOWED
|
||||||
try:
|
try:
|
||||||
xml_content = self._read_xml_content(environ)
|
xml_content = self._read_xml_request_body(environ)
|
||||||
except RuntimeError as e:
|
except RuntimeError as e:
|
||||||
logger.warning(
|
logger.warning(
|
||||||
"Bad PROPFIND request on %r: %s", path, e, exc_info=True)
|
"Bad PROPFIND request on %r: %s", path, e, exc_info=True)
|
||||||
|
@ -91,7 +91,7 @@ class ApplicationProppatchMixin:
|
|||||||
if not access.check("w"):
|
if not access.check("w"):
|
||||||
return httputils.NOT_ALLOWED
|
return httputils.NOT_ALLOWED
|
||||||
try:
|
try:
|
||||||
xml_content = self._read_xml_content(environ)
|
xml_content = self._read_xml_request_body(environ)
|
||||||
except RuntimeError as e:
|
except RuntimeError as e:
|
||||||
logger.warning(
|
logger.warning(
|
||||||
"Bad PROPPATCH request on %r: %s", path, e, exc_info=True)
|
"Bad PROPPATCH request on %r: %s", path, e, exc_info=True)
|
||||||
|
@ -118,7 +118,7 @@ class ApplicationPutMixin:
|
|||||||
if not access.check("w"):
|
if not access.check("w"):
|
||||||
return httputils.NOT_ALLOWED
|
return httputils.NOT_ALLOWED
|
||||||
try:
|
try:
|
||||||
content = self._read_content(environ)
|
content = httputils.read_request_body(self.configuration, environ)
|
||||||
except RuntimeError as e:
|
except RuntimeError as e:
|
||||||
logger.warning("Bad PUT request on %r: %s", path, e, exc_info=True)
|
logger.warning("Bad PUT request on %r: %s", path, e, exc_info=True)
|
||||||
return httputils.BAD_REQUEST
|
return httputils.BAD_REQUEST
|
||||||
|
@ -262,7 +262,7 @@ class ApplicationReportMixin:
|
|||||||
if not access.check("r"):
|
if not access.check("r"):
|
||||||
return httputils.NOT_ALLOWED
|
return httputils.NOT_ALLOWED
|
||||||
try:
|
try:
|
||||||
xml_content = self._read_xml_content(environ)
|
xml_content = self._read_xml_request_body(environ)
|
||||||
except RuntimeError as e:
|
except RuntimeError as e:
|
||||||
logger.warning(
|
logger.warning(
|
||||||
"Bad REPORT request on %r: %s", path, e, exc_info=True)
|
"Bad REPORT request on %r: %s", path, e, exc_info=True)
|
||||||
|
@ -24,6 +24,8 @@ Helper functions for HTTP.
|
|||||||
|
|
||||||
from http import client
|
from http import client
|
||||||
|
|
||||||
|
from radicale.log import logger
|
||||||
|
|
||||||
NOT_ALLOWED = (
|
NOT_ALLOWED = (
|
||||||
client.FORBIDDEN, (("Content-Type", "text/plain"),),
|
client.FORBIDDEN, (("Content-Type", "text/plain"),),
|
||||||
"Access to the requested resource forbidden.")
|
"Access to the requested resource forbidden.")
|
||||||
@ -61,3 +63,45 @@ INTERNAL_SERVER_ERROR = (
|
|||||||
"A server error occurred. Please contact the administrator.")
|
"A server error occurred. Please contact the administrator.")
|
||||||
|
|
||||||
DAV_HEADERS = "1, 2, 3, calendar-access, addressbook, extended-mkcol"
|
DAV_HEADERS = "1, 2, 3, calendar-access, addressbook, extended-mkcol"
|
||||||
|
|
||||||
|
|
||||||
|
def decode_request(configuration, environ, text):
|
||||||
|
"""Try to magically decode ``text`` according to given ``environ``."""
|
||||||
|
# List of charsets to try
|
||||||
|
charsets = []
|
||||||
|
|
||||||
|
# First append content charset given in the request
|
||||||
|
content_type = environ.get("CONTENT_TYPE")
|
||||||
|
if content_type and "charset=" in content_type:
|
||||||
|
charsets.append(
|
||||||
|
content_type.split("charset=")[1].split(";")[0].strip())
|
||||||
|
# Then append default Radicale charset
|
||||||
|
charsets.append(configuration.get("encoding", "request"))
|
||||||
|
# Then append various fallbacks
|
||||||
|
charsets.append("utf-8")
|
||||||
|
charsets.append("iso8859-1")
|
||||||
|
|
||||||
|
# Try to decode
|
||||||
|
for charset in charsets:
|
||||||
|
try:
|
||||||
|
return text.decode(charset)
|
||||||
|
except UnicodeDecodeError:
|
||||||
|
pass
|
||||||
|
raise UnicodeDecodeError
|
||||||
|
|
||||||
|
|
||||||
|
def read_raw_request_body(configuration, environ):
|
||||||
|
content_length = int(environ.get("CONTENT_LENGTH") or 0)
|
||||||
|
if not content_length:
|
||||||
|
return b""
|
||||||
|
content = environ["wsgi.input"].read(content_length)
|
||||||
|
if len(content) < content_length:
|
||||||
|
raise RuntimeError("Request body too short: %d" % len(content))
|
||||||
|
return content
|
||||||
|
|
||||||
|
|
||||||
|
def read_request_body(configuration, environ):
|
||||||
|
content = decode_request(
|
||||||
|
configuration, environ, read_raw_request_body(configuration, environ))
|
||||||
|
logger.debug("Request content:\n%s", content)
|
||||||
|
return content
|
||||||
|
@ -21,7 +21,7 @@ Custom web plugin.
|
|||||||
|
|
||||||
from http import client
|
from http import client
|
||||||
|
|
||||||
from radicale import web
|
from radicale import httputils, web
|
||||||
|
|
||||||
|
|
||||||
class Web(web.BaseWeb):
|
class Web(web.BaseWeb):
|
||||||
@ -29,5 +29,5 @@ class Web(web.BaseWeb):
|
|||||||
return client.OK, {"Content-Type": "text/plain"}, "custom"
|
return client.OK, {"Content-Type": "text/plain"}, "custom"
|
||||||
|
|
||||||
def post(self, environ, base_prefix, path, user):
|
def post(self, environ, base_prefix, path, user):
|
||||||
answer = "echo:" + environ["wsgi.input"].read().decode()
|
content = httputils.read_request_body(self.configuration, environ)
|
||||||
return client.OK, {"Content-Type": "text/plain"}, answer
|
return client.OK, {"Content-Type": "text/plain"}, "echo:" + content
|
||||||
|
@ -63,5 +63,8 @@ class BaseWeb:
|
|||||||
|
|
||||||
``user`` is empty for anonymous users.
|
``user`` is empty for anonymous users.
|
||||||
|
|
||||||
|
Use ``httputils.read*_request_body(self.configuration, environ)`` to
|
||||||
|
read the body.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return httputils.METHOD_NOT_ALLOWED
|
return httputils.METHOD_NOT_ALLOWED
|
||||||
|
Loading…
Reference in New Issue
Block a user