Coverage for gws-app/gws/base/web/wsgi_app.py: 60%
108 statements
« prev ^ index » next coverage.py v7.11.0, created at 2025-10-16 23:09 +0200
« prev ^ index » next coverage.py v7.11.0, created at 2025-10-16 23:09 +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 site = root.app.webMgr.site_from_environ(environ)
47 req = gws.base.web.wsgi.Requester(root, environ, site)
49 try:
50 _ = req.params() # enforce parsing
51 except Exception as exc:
52 return handle_error(req, exc)
54 gws.log.if_debug(_debug_repr, f'REQUEST_BEGIN {req.command()}', req.params() or req.struct())
55 gws.debug.time_start(f'REQUEST {req.command()}')
56 res = apply_middleware(root, req)
57 gws.debug.time_end()
58 gws.log.if_debug(_debug_repr, f'REQUEST_END {req.command()}', res)
60 return res
63def apply_middleware(root: gws.Root, req: gws.WebRequester) -> gws.WebResponder:
64 res = None
65 done = []
67 for obj in root.app.middlewareMgr.objects():
68 try:
69 res = obj.enter_middleware(req)
70 done.append(obj)
71 except Exception as exc:
72 res = handle_error(req, exc)
74 if res:
75 break
77 if not res:
78 try:
79 res = handle_action(root, req)
80 except Exception as exc:
81 res = handle_error(req, exc)
83 for obj in reversed(done):
84 try:
85 obj.exit_middleware(req, res)
86 except Exception as exc:
87 res = handle_error(req, exc)
89 return res
92def _debug_repr(prefix, s):
93 s = repr(gws.u.to_dict(s))
94 m = 400
95 n = len(s)
96 if n <= m:
97 return prefix + ': ' + s
98 return prefix + ': ' + s[:m] + ' [...' + str(n - m) + ' more]'
101def handle_error(req: gws.WebRequester, exc: Exception) -> gws.WebResponder:
102 web_exc = gws.base.web.error.from_exception(exc)
103 return handle_http_error(req, web_exc)
106def handle_http_error(req: gws.WebRequester, exc: gws.base.web.error.HTTPException) -> gws.WebResponder:
107 #
108 # @TODO: image errors
110 if req.isApi:
111 return req.api_responder(gws.Response(
112 status=exc.code,
113 error=gws.ResponseError(
114 code=exc.code,
115 info=gws.u.get(exc, 'description', ''))))
117 if not req.site.errorPage:
118 return req.error_responder(exc)
120 args = gws.TemplateArgs(
121 req=req,
122 user=req.user,
123 error=exc.code
124 )
125 res = req.site.errorPage.render(gws.TemplateRenderInput(args=args))
126 res.status = exc.code
127 return req.content_responder(res)
130_relaxed_read_options = {
131 gws.SpecReadOption.caseInsensitive,
132 gws.SpecReadOption.convertValues,
133 gws.SpecReadOption.ignoreExtraProps,
134}
137def handle_action(root: gws.Root, req: gws.WebRequester) -> gws.WebResponder:
138 if not req.command():
139 raise gws.NotFoundError('no command provided')
141 if req.isApi:
142 category = gws.CommandCategory.api
143 params = req.struct()
144 read_options = None
145 elif req.isGet:
146 category = gws.CommandCategory.get
147 params = req.params()
148 read_options = _relaxed_read_options
149 elif req.isPost:
150 category = gws.CommandCategory.post
151 params = req.params()
152 read_options = _relaxed_read_options
153 else:
154 # @TODO: add HEAD
155 raise gws.base.web.error.MethodNotAllowed()
157 fn, request = root.app.actionMgr.prepare_action(
158 category,
159 req.command(),
160 params,
161 req.user,
162 read_options
163 )
165 response = fn(req, request)
167 if response is None:
168 raise gws.NotFoundError(f'action not handled {category!r}:{req.command()!r}')
170 if isinstance(response, gws.ContentResponse):
171 return req.content_responder(response)
173 if isinstance(response, gws.RedirectResponse):
174 return req.redirect_responder(response)
176 return req.api_responder(response)