aboutsummaryrefslogtreecommitdiffstats
path: root/cms/wsgi_app.py
blob: 97cf3052b765f1e7a205941563de40fc65dc9c63 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# -*- coding: utf-8 -*-
#
#   CMS WSGI wrapper
#
#   Copyright (C) 2011-2019 Michael Buesch <m@bues.ch>
#
#   This program 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 2 of the License, or
#   (at your option) any later version.
#
#   This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.

import sys
import atexit
from urllib.parse import parse_qs

from cms import *
from cms.util import * #+cimport

__all__ = [
	"application",
]

cms = None
maxPostContentLength = 0

def __initCMS(environ):
	global cms
	global maxPostContentLength

	domain = environ.get("cms.domain", None)
	cmsBase = environ.get("cms.cmsBase", None)
	wwwBase = environ.get("cms.wwwBase", None)
	if domain is None or cmsBase is None or wwwBase is None:
		raise Exception("WSGI environment cms.domain, cms.cmsBase "
				"or cms.wwwBase not set.")
	debug = stringBool(environ.get("cms.debug", "0"), False)
	try:
		maxPostContentLength = int(environ.get("cms.maxPostContentLength", "0"))
	except ValueError as e:
		maxPostContentLength = 0
	# Initialize the CMS module
	cms = CMS(dbPath=(cmsBase + "/db"),
		  wwwPath=wwwBase,
		  domain=domain,
		  debug=debug)
	atexit.register(cms.shutdown)

def __recvBody(environ):
	global maxPostContentLength

	try:
		body_len = int(environ.get("CONTENT_LENGTH", "0"))
	except ValueError as e:
		body_len = 0
	body_type = environ.get("CONTENT_TYPE", "text/plain")
	if (body_len >= 0 and
	    (body_len <= maxPostContentLength or maxPostContentLength < 0)):
		wsgi_input = environ.get("wsgi.input", None)
		if wsgi_input is None:
			raise Exception("WSGI environment 'wsgi.input' not set.")
		body = wsgi_input.read(body_len)
	else:
		body = body_type = None
	return body, body_type

def application(environ, start_response):
	global cms

	if cms is None:
		__initCMS(environ)
	if cms.debug:
		startStamp = datetime.now()

	status = "200 OK"
	additional_headers = []

	method = environ.get("REQUEST_METHOD", "").upper()
	path = environ.get("PATH_INFO", "")
	query = parse_qs(environ.get("QUERY_STRING", ""))
	protocol = environ.get("wsgi.url_scheme", "http").lower()
	try:
		if method == "GET" or method == "HEAD":
			response_body, response_mime = cms.get(path, query, protocol)
			if method == "HEAD":
				response_body = b""
		elif method == "POST":
			body, body_type = __recvBody(environ)
			if body is None:
				response_body, response_mime, status = (
					b"POSTed data is too long\n",
					"text/plain",
					"405 Method Not Allowed"
				)
			else:
				response_body, response_mime = cms.post(path, query,
									body, body_type,
									protocol)
		else:
			response_body, response_mime, status = (
				b"INVALID REQUEST_METHOD\n",
				"text/plain",
				"405 Method Not Allowed"
			)
	except (CMSException) as e:
		status = e.httpStatus
		response_body, response_mime, additional_headers = cms.getErrorPage(e, protocol)
	if cms.debug and response_mime.startswith("text/html"):
		delta = datetime.now() - startStamp
		ms = (float(delta.seconds) * 1e3) + (float(delta.microseconds) * 1e-3)
		response_body += ("\n<!-- generated in %.3f ms -->" % ms).encode("UTF-8", "ignore")
	response_headers = [ ('Content-Type', response_mime),
			     ('Content-Length', str(len(response_body))) ]
	response_headers.extend(additional_headers)
	start_response(status, response_headers)
	return (response_body,)
bues.ch cgit interface