Coverage for gws-app/gws/base/web/wsgi_app.py: 68%
116 statements
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-24 12:46 +0200
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-24 12:46 +0200
1"""web application root"""
3import gws
4import gws.base.web
5import gws.config
7_STATE = {
8 'inited': False,
9}
12def application(environ, start_response):
13 if not _STATE['inited']:
14 init()
15 root = gws.config.get_root()
16 responder = handle_request(root, environ)
17 return responder.send_response(environ, start_response)
20def make_application(root):
21 def fn(environ, start_response):
22 responder = handle_request(root, environ)
23 return responder.send_response(environ, start_response)
25 return fn
28def init():
29 try:
30 gws.log.info('initializing WEB application')
31 gws.log.set_level('DEBUG')
32 root = gws.config.load()
33 gws.log.set_level(root.app.cfg('server.log.level'))
34 _STATE['inited'] = True
35 except:
36 gws.log.exception('UNABLE TO LOAD CONFIGURATION')
37 gws.u.exit(1)
40def reload():
41 _STATE['inited'] = False
42 init()
45def handle_request(root: gws.Root, environ) -> gws.WebResponder:
46 req = gws.base.web.wsgi.Requester(root, environ, root.app.webMgr.site)
48 try:
49 req.parse()
50 except Exception as exc:
51 return handle_error(req, exc)
53 gws.log.if_debug(_debug_repr, f'REQUEST_BEGIN <{req.method}> {req.command()}', req.params() or req.struct())
54 gws.debug.time_start(f'REQUEST <{req.method}> {req.command()}')
55 res = apply_middleware(root, req)
56 gws.debug.time_end()
57 gws.log.if_debug(_debug_repr, f'REQUEST_END <{req.method}> {req.command()}', res)
59 return res
62def apply_middleware(root: gws.Root, req: gws.WebRequester) -> gws.WebResponder:
63 res = None
64 done = []
66 for obj in root.app.middlewareMgr.objects():
67 try:
68 res = obj.enter_middleware(req)
69 done.append(obj)
70 except Exception as exc:
71 res = handle_error(req, exc)
73 if res:
74 break
76 if not res:
77 try:
78 m = req.method
79 if m == gws.RequestMethod.GET or m == gws.RequestMethod.POST:
80 res = handle_action(root, req)
81 elif m == gws.RequestMethod.HEAD or m == gws.RequestMethod.OPTIONS:
82 res = req.content_responder(gws.ContentResponse(mime='text/plain', content=''))
83 else:
84 raise gws.base.web.error.MethodNotAllowed(['GET', 'POST', 'HEAD', 'OPTIONS'])
85 except Exception as exc:
86 res = handle_error(req, exc)
88 for obj in reversed(done):
89 try:
90 obj.exit_middleware(req, res)
91 except Exception as exc:
92 res = handle_error(req, exc)
94 return res
97def _debug_repr(prefix, s):
98 s = repr(gws.u.to_dict(s))
99 m = 400
100 n = len(s)
101 if n <= m:
102 return prefix + ': ' + s
103 return prefix + ': ' + s[:m] + ' [...' + str(n - m) + ' more]'
106def handle_error(req: gws.WebRequester, exc: Exception) -> gws.WebResponder:
107 gws.log.if_debug(_debug_repr, f'REQUEST_ERROR', exc)
108 web_exc = gws.base.web.error.from_exception(exc)
109 return handle_http_error(req, web_exc)
112def handle_http_error(req: gws.WebRequester, exc: gws.base.web.error.HTTPException) -> gws.WebResponder:
113 #
114 # @TODO: image errors
116 if req.isApi:
117 return req.api_responder(
118 gws.Response(
119 status=exc.code,
120 error=gws.ResponseError(
121 code=exc.code,
122 info=gws.u.get(exc, 'description', ''),
123 ),
124 )
125 )
127 error_template = getattr(req.site, 'errorPage', None)
128 if not error_template:
129 error_template = req.root.app.templateMgr.find_template('application.error', where=[])
130 if not error_template:
131 return req.error_responder(exc)
133 args = gws.TemplateArgs(req=req, user=req.user, error=exc.code, status=exc.code or 500)
134 res = error_template.render(gws.TemplateRenderInput(args=args))
135 res.status = exc.code or 500
136 return req.content_responder(res)
139_relaxed_read_options = {
140 gws.SpecReadOption.caseInsensitive,
141 gws.SpecReadOption.convertValues,
142 gws.SpecReadOption.ignoreExtraProps,
143}
146def handle_action(root: gws.Root, req: gws.WebRequester) -> gws.WebResponder:
147 if not req.command():
148 raise gws.NotFoundError('no command provided')
150 if req.isApi:
151 category = gws.CommandCategory.api
152 params = req.struct()
153 read_options = None
154 elif req.isGet:
155 category = gws.CommandCategory.get
156 params = req.params()
157 read_options = _relaxed_read_options
158 elif req.isPost:
159 category = gws.CommandCategory.post
160 params = req.params()
161 read_options = _relaxed_read_options
162 else:
163 # @TODO: add HEAD
164 raise gws.base.web.error.MethodNotAllowed()
166 fn, request = root.app.actionMgr.prepare_action(
167 category,
168 req.command(),
169 params,
170 req.path(),
171 req.user,
172 read_options,
173 )
175 response = fn(req, request)
177 if response is None:
178 raise gws.NotFoundError(f'action not handled {category!r}:{req.command()!r}')
180 if isinstance(response, gws.ContentResponse):
181 return req.content_responder(response)
183 if isinstance(response, gws.RedirectResponse):
184 return req.redirect_responder(response)
186 return req.api_responder(response)