Coverage for gws-app/gws/base/web/wsgi_app.py: 16%
111 statements
« prev ^ index » next coverage.py v7.8.0, created at 2025-04-17 01:37 +0200
« prev ^ index » next coverage.py v7.8.0, created at 2025-04-17 01:37 +0200
1"""web application root"""
3from typing import cast
5import gws
6import gws.base.action
7import gws.base.web
8import gws.config
9import gws.spec.runtime
11_STATE = {
12 'inited': False,
13}
16def application(environ, start_response):
17 if not _STATE['inited']:
18 init()
19 root = gws.config.root()
20 responder = handle_request(root, environ)
21 return responder.send_response(environ, start_response)
24def make_application(root):
25 def fn(environ, start_response):
26 responder = handle_request(root, environ)
27 return responder.send_response(environ, start_response)
29 return fn
32def init():
33 try:
34 gws.log.info('initializing WEB application')
35 gws.log.set_level('DEBUG')
36 root = gws.config.load()
37 gws.log.set_level(root.app.cfg('server.log.level'))
38 _STATE['inited'] = True
39 except:
40 gws.log.exception('UNABLE TO LOAD CONFIGURATION')
41 gws.u.exit(1)
44def reload():
45 _STATE['inited'] = False
46 init()
49def handle_request(root: gws.Root, environ) -> gws.WebResponder:
50 site = root.app.webMgr.site_from_environ(environ)
51 req = gws.base.web.wsgi.Requester(root, environ, site)
53 try:
54 _ = req.params() # enforce parsing
55 except Exception as exc:
56 return handle_error(req, exc)
58 gws.log.if_debug(_debug_repr, f'REQUEST_BEGIN {req.command()}', req.params() or req.struct())
59 gws.debug.time_start(f'REQUEST {req.command()}')
60 res = apply_middleware(root, req)
61 gws.debug.time_end()
62 gws.log.if_debug(_debug_repr, f'REQUEST_END {req.command()}', res)
64 return res
67def apply_middleware(root: gws.Root, req: gws.WebRequester) -> gws.WebResponder:
68 res = None
69 done = []
71 for obj in root.app.middlewareMgr.objects():
72 try:
73 res = obj.enter_middleware(req)
74 done.append(obj)
75 except Exception as exc:
76 res = handle_error(req, exc)
78 if res:
79 break
81 if not res:
82 try:
83 res = handle_action(root, req)
84 except Exception as exc:
85 res = handle_error(req, exc)
87 for obj in reversed(done):
88 try:
89 obj.exit_middleware(req, res)
90 except Exception as exc:
91 res = handle_error(req, exc)
93 return res
96def _debug_repr(prefix, s):
97 s = repr(gws.u.to_dict(s))
98 m = 400
99 n = len(s)
100 if n <= m:
101 return prefix + ': ' + s
102 return prefix + ': ' + s[:m] + ' [...' + str(n - m) + ' more]'
105def handle_error(req: gws.WebRequester, exc: Exception) -> gws.WebResponder:
106 web_exc = gws.base.web.error.from_exception(exc)
107 return handle_http_error(req, web_exc)
110def handle_http_error(req: gws.WebRequester, exc: gws.base.web.error.HTTPException) -> gws.WebResponder:
111 #
112 # @TODO: image errors
114 if req.isApi:
115 return req.api_responder(gws.Response(
116 status=exc.code,
117 error=gws.ResponseError(
118 code=exc.code,
119 info=gws.u.get(exc, 'description', ''))))
121 if not req.site.errorPage:
122 return req.error_responder(exc)
124 args = gws.TemplateArgs(
125 req=req,
126 user=req.user,
127 error=exc.code
128 )
129 res = req.site.errorPage.render(gws.TemplateRenderInput(args=args))
130 res.status = exc.code
131 return req.content_responder(res)
134_relaxed_read_options = {
135 gws.SpecReadOption.caseInsensitive,
136 gws.SpecReadOption.convertValues,
137 gws.SpecReadOption.ignoreExtraProps,
138}
141def handle_action(root: gws.Root, req: gws.WebRequester) -> gws.WebResponder:
142 if not req.command():
143 raise gws.NotFoundError('no command provided')
145 if req.isApi:
146 category = gws.CommandCategory.api
147 params = req.struct()
148 read_options = None
149 elif req.isGet:
150 category = gws.CommandCategory.get
151 params = req.params()
152 read_options = _relaxed_read_options
153 elif req.isPost:
154 category = gws.CommandCategory.post
155 params = req.params()
156 read_options = _relaxed_read_options
157 else:
158 # @TODO: add HEAD
159 raise gws.base.web.error.MethodNotAllowed()
161 fn, request = root.app.actionMgr.prepare_action(
162 category,
163 req.command(),
164 params,
165 req.user,
166 read_options
167 )
169 response = fn(req, request)
171 if response is None:
172 raise gws.NotFoundError(f'action not handled {category!r}:{req.command()!r}')
174 if isinstance(response, gws.ContentResponse):
175 return req.content_responder(response)
177 if isinstance(response, gws.RedirectResponse):
178 return req.redirect_responder(response)
180 return req.api_responder(response)