appier 1.31.4__py2.py3-none-any.whl → 1.32.0__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- appier/__init__.py +333 -52
- appier/amqp.py +29 -30
- appier/api.py +214 -212
- appier/asgi.py +54 -55
- appier/async_neo.py +46 -35
- appier/async_old.py +55 -42
- appier/asynchronous.py +7 -13
- appier/base.py +1762 -1429
- appier/bus.py +51 -52
- appier/cache.py +99 -84
- appier/common.py +9 -11
- appier/component.py +17 -19
- appier/compress.py +25 -28
- appier/config.py +96 -73
- appier/controller.py +9 -15
- appier/crypt.py +25 -21
- appier/data.py +73 -57
- appier/defines.py +191 -226
- appier/exceptions.py +103 -63
- appier/execution.py +94 -88
- appier/export.py +90 -88
- appier/extra.py +6 -13
- appier/extra_neo.py +8 -11
- appier/extra_old.py +18 -16
- appier/geo.py +57 -47
- appier/git.py +101 -90
- appier/graph.py +23 -24
- appier/http.py +520 -398
- appier/legacy.py +373 -180
- appier/log.py +90 -97
- appier/meta.py +42 -42
- appier/mock.py +32 -34
- appier/model.py +793 -681
- appier/model_a.py +208 -183
- appier/mongo.py +183 -107
- appier/observer.py +39 -31
- appier/part.py +23 -24
- appier/preferences.py +44 -47
- appier/queuing.py +78 -96
- appier/redisdb.py +40 -35
- appier/request.py +227 -175
- appier/scheduler.py +13 -18
- appier/serialize.py +37 -31
- appier/session.py +161 -147
- appier/settings.py +2 -11
- appier/smtp.py +53 -49
- appier/storage.py +39 -33
- appier/structures.py +50 -45
- appier/test/__init__.py +2 -11
- appier/test/base.py +111 -108
- appier/test/cache.py +28 -35
- appier/test/config.py +10 -19
- appier/test/crypt.py +3 -12
- appier/test/data.py +3 -12
- appier/test/exceptions.py +8 -17
- appier/test/export.py +16 -33
- appier/test/graph.py +27 -60
- appier/test/http.py +42 -54
- appier/test/legacy.py +20 -30
- appier/test/log.py +14 -35
- appier/test/mock.py +27 -123
- appier/test/model.py +79 -91
- appier/test/part.py +5 -14
- appier/test/preferences.py +5 -13
- appier/test/queuing.py +29 -37
- appier/test/request.py +61 -73
- appier/test/serialize.py +12 -23
- appier/test/session.py +10 -19
- appier/test/smtp.py +8 -14
- appier/test/structures.py +20 -24
- appier/test/typesf.py +14 -28
- appier/test/util.py +480 -438
- appier/typesf.py +251 -171
- appier/util.py +578 -407
- appier/validation.py +280 -143
- {appier-1.31.4.dist-info → appier-1.32.0.dist-info}/METADATA +6 -1
- appier-1.32.0.dist-info/RECORD +86 -0
- appier-1.31.4.dist-info/RECORD +0 -86
- {appier-1.31.4.dist-info → appier-1.32.0.dist-info}/LICENSE +0 -0
- {appier-1.31.4.dist-info → appier-1.32.0.dist-info}/WHEEL +0 -0
- {appier-1.31.4.dist-info → appier-1.32.0.dist-info}/top_level.txt +0 -0
appier/request.py
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
# -*- coding: utf-8 -*-
|
|
3
3
|
|
|
4
4
|
# Hive Appier Framework
|
|
5
|
-
# Copyright (c) 2008-
|
|
5
|
+
# Copyright (c) 2008-2024 Hive Solutions Lda.
|
|
6
6
|
#
|
|
7
7
|
# This file is part of Hive Appier Framework.
|
|
8
8
|
#
|
|
@@ -22,16 +22,7 @@
|
|
|
22
22
|
__author__ = "João Magalhães <joamag@hive.pt>"
|
|
23
23
|
""" The author(s) of the module """
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
""" The version of the module """
|
|
27
|
-
|
|
28
|
-
__revision__ = "$LastChangedRevision$"
|
|
29
|
-
""" The revision number of the module """
|
|
30
|
-
|
|
31
|
-
__date__ = "$LastChangedDate$"
|
|
32
|
-
""" The last change date of the module """
|
|
33
|
-
|
|
34
|
-
__copyright__ = "Copyright (c) 2008-2022 Hive Solutions Lda."
|
|
25
|
+
__copyright__ = "Copyright (c) 2008-2024 Hive Solutions Lda."
|
|
35
26
|
""" The copyright for the module """
|
|
36
27
|
|
|
37
28
|
__license__ = "Apache License, Version 2.0"
|
|
@@ -49,51 +40,52 @@ from . import session
|
|
|
49
40
|
from . import exceptions
|
|
50
41
|
|
|
51
42
|
CODE_STRINGS = {
|
|
52
|
-
100
|
|
53
|
-
101
|
|
54
|
-
200
|
|
55
|
-
201
|
|
56
|
-
202
|
|
57
|
-
203
|
|
58
|
-
204
|
|
59
|
-
205
|
|
60
|
-
206
|
|
61
|
-
207
|
|
62
|
-
301
|
|
63
|
-
302
|
|
64
|
-
303
|
|
65
|
-
304
|
|
66
|
-
305
|
|
67
|
-
306
|
|
68
|
-
307
|
|
69
|
-
400
|
|
70
|
-
401
|
|
71
|
-
402
|
|
72
|
-
403
|
|
73
|
-
404
|
|
74
|
-
405
|
|
75
|
-
406
|
|
76
|
-
407
|
|
77
|
-
408
|
|
78
|
-
409
|
|
79
|
-
410
|
|
80
|
-
411
|
|
81
|
-
412
|
|
82
|
-
413
|
|
83
|
-
414
|
|
84
|
-
415
|
|
85
|
-
416
|
|
86
|
-
417
|
|
87
|
-
500
|
|
88
|
-
501
|
|
89
|
-
502
|
|
90
|
-
503
|
|
91
|
-
504
|
|
92
|
-
505
|
|
43
|
+
100: "Continue",
|
|
44
|
+
101: "Switching Protocols",
|
|
45
|
+
200: "OK",
|
|
46
|
+
201: "Created",
|
|
47
|
+
202: "Accepted",
|
|
48
|
+
203: "Non-Authoritative Information",
|
|
49
|
+
204: "No Content",
|
|
50
|
+
205: "Reset Content",
|
|
51
|
+
206: "Partial Content",
|
|
52
|
+
207: "Multi-Status",
|
|
53
|
+
301: "Moved permanently",
|
|
54
|
+
302: "Found",
|
|
55
|
+
303: "See Other",
|
|
56
|
+
304: "Not Modified",
|
|
57
|
+
305: "Use Proxy",
|
|
58
|
+
306: "(Unused)",
|
|
59
|
+
307: "Temporary Redirect",
|
|
60
|
+
400: "Bad Request",
|
|
61
|
+
401: "Unauthorized",
|
|
62
|
+
402: "Payment Required",
|
|
63
|
+
403: "Forbidden",
|
|
64
|
+
404: "Not Found",
|
|
65
|
+
405: "Method Not Allowed",
|
|
66
|
+
406: "Not Acceptable",
|
|
67
|
+
407: "Proxy Authentication Required",
|
|
68
|
+
408: "Request Timeout",
|
|
69
|
+
409: "Conflict",
|
|
70
|
+
410: "Gone",
|
|
71
|
+
411: "Length Required",
|
|
72
|
+
412: "Precondition Failed",
|
|
73
|
+
413: "Request Entity Too Large",
|
|
74
|
+
414: "Request-URI Too Long",
|
|
75
|
+
415: "Unsupported Media Type",
|
|
76
|
+
416: "Requested Range Not Satisfiable",
|
|
77
|
+
417: "Expectation Failed",
|
|
78
|
+
500: "Internal Server Error",
|
|
79
|
+
501: "Not Implemented",
|
|
80
|
+
502: "Bad Gateway",
|
|
81
|
+
503: "Service Unavailable",
|
|
82
|
+
504: "Gateway Timeout",
|
|
83
|
+
505: "HTTP Version Not Supported",
|
|
93
84
|
}
|
|
94
85
|
""" Dictionary associating the error code as integers
|
|
95
86
|
with the official descriptive message for it """
|
|
96
87
|
|
|
88
|
+
|
|
97
89
|
class Request(object):
|
|
98
90
|
"""
|
|
99
91
|
Request class that acts as a proxy for the both
|
|
@@ -111,18 +103,18 @@ class Request(object):
|
|
|
111
103
|
|
|
112
104
|
def __init__(
|
|
113
105
|
self,
|
|
114
|
-
owner
|
|
115
|
-
method
|
|
116
|
-
path
|
|
117
|
-
prefix
|
|
118
|
-
query
|
|
119
|
-
scheme
|
|
120
|
-
address
|
|
121
|
-
protocol
|
|
122
|
-
params
|
|
123
|
-
data_j
|
|
124
|
-
environ
|
|
125
|
-
session_c
|
|
106
|
+
owner=None,
|
|
107
|
+
method="GET",
|
|
108
|
+
path="/",
|
|
109
|
+
prefix="/",
|
|
110
|
+
query="",
|
|
111
|
+
scheme=None,
|
|
112
|
+
address=None,
|
|
113
|
+
protocol=None,
|
|
114
|
+
params={},
|
|
115
|
+
data_j={},
|
|
116
|
+
environ={},
|
|
117
|
+
session_c=session.FileSession,
|
|
126
118
|
):
|
|
127
119
|
self.owner = owner
|
|
128
120
|
self.method = method
|
|
@@ -231,7 +223,7 @@ class Request(object):
|
|
|
231
223
|
self._closed = True
|
|
232
224
|
self._params = None
|
|
233
225
|
|
|
234
|
-
def handle(self, code
|
|
226
|
+
def handle(self, code=None, result=""):
|
|
235
227
|
"""
|
|
236
228
|
Handles the current request, setting the response code
|
|
237
229
|
and the resulting data that is going to be returned to
|
|
@@ -289,36 +281,39 @@ class Request(object):
|
|
|
289
281
|
"""
|
|
290
282
|
|
|
291
283
|
return dict(
|
|
292
|
-
method
|
|
293
|
-
path
|
|
294
|
-
prefix
|
|
295
|
-
query
|
|
296
|
-
scheme
|
|
297
|
-
encoding
|
|
298
|
-
content_type
|
|
299
|
-
cache_conrtol
|
|
284
|
+
method=self.method,
|
|
285
|
+
path=self.path,
|
|
286
|
+
prefix=self.prefix,
|
|
287
|
+
query=self.query,
|
|
288
|
+
scheme=self.scheme,
|
|
289
|
+
encoding=self.encoding,
|
|
290
|
+
content_type=self.content_type,
|
|
291
|
+
cache_conrtol=self.cache_control,
|
|
300
292
|
)
|
|
301
293
|
|
|
302
294
|
def warning(self, message):
|
|
303
295
|
message_t = type(message)
|
|
304
296
|
|
|
305
297
|
if message_t in legacy.STRINGS:
|
|
306
|
-
message = dict(message
|
|
298
|
+
message = dict(message=message)
|
|
307
299
|
elif not message_t == dict:
|
|
308
300
|
raise exceptions.OperationalError(
|
|
309
|
-
message
|
|
301
|
+
message="Invalid message type '%s'" % message_t
|
|
310
302
|
)
|
|
311
303
|
|
|
312
304
|
self.warnings.append(message)
|
|
313
305
|
|
|
314
306
|
def get_params(self):
|
|
315
|
-
if self._params:
|
|
307
|
+
if self._params:
|
|
308
|
+
return self._params
|
|
316
309
|
self._params = {}
|
|
317
|
-
for key, value in self.params.items():
|
|
310
|
+
for key, value in self.params.items():
|
|
311
|
+
self._params[key] = value[0]
|
|
318
312
|
return self._params
|
|
319
313
|
|
|
320
|
-
def get_param(self, name, default
|
|
321
|
-
if not name in self.params:
|
|
314
|
+
def get_param(self, name, default=None):
|
|
315
|
+
if not name in self.params:
|
|
316
|
+
return default
|
|
322
317
|
value = self.params[name]
|
|
323
318
|
return value[0] if value else default
|
|
324
319
|
|
|
@@ -354,13 +349,16 @@ class Request(object):
|
|
|
354
349
|
def set_code(self, code):
|
|
355
350
|
self.code = code
|
|
356
351
|
|
|
357
|
-
def get_encoded(self, encoding
|
|
358
|
-
if encoding == None:
|
|
359
|
-
|
|
352
|
+
def get_encoded(self, encoding=None, safe=True):
|
|
353
|
+
if encoding == None:
|
|
354
|
+
encoding = self.get_encoding()
|
|
355
|
+
if not encoding:
|
|
356
|
+
return self.data
|
|
360
357
|
try:
|
|
361
|
-
return legacy.u(self.data, encoding
|
|
358
|
+
return legacy.u(self.data, encoding=encoding, force=True)
|
|
362
359
|
except UnicodeDecodeError:
|
|
363
|
-
if not safe:
|
|
360
|
+
if not safe:
|
|
361
|
+
raise
|
|
364
362
|
return self.data
|
|
365
363
|
|
|
366
364
|
def extend_args(self, args):
|
|
@@ -384,8 +382,10 @@ class Request(object):
|
|
|
384
382
|
self.content_type = content_type
|
|
385
383
|
|
|
386
384
|
def default_content_type(self, default):
|
|
387
|
-
if self.content_type:
|
|
388
|
-
|
|
385
|
+
if self.content_type:
|
|
386
|
+
return
|
|
387
|
+
if self.has_header_out("Content-Type"):
|
|
388
|
+
return
|
|
389
389
|
self.content_type = default
|
|
390
390
|
|
|
391
391
|
def get_cache_control(self):
|
|
@@ -395,24 +395,30 @@ class Request(object):
|
|
|
395
395
|
self.cache_control = cache_control
|
|
396
396
|
|
|
397
397
|
def default_cache_control(self, default):
|
|
398
|
-
if self.cache_control:
|
|
399
|
-
|
|
398
|
+
if self.cache_control:
|
|
399
|
+
return
|
|
400
|
+
if self.has_header_out("Cache-Control"):
|
|
401
|
+
return
|
|
400
402
|
self.cache_control = default
|
|
401
403
|
|
|
402
|
-
def get_header(self, name, default
|
|
403
|
-
if normalize:
|
|
404
|
+
def get_header(self, name, default=None, normalize=True):
|
|
405
|
+
if normalize:
|
|
406
|
+
name = name.title()
|
|
404
407
|
return self.in_headers.get(name, default)
|
|
405
408
|
|
|
406
|
-
def set_header(self, name, value, normalize
|
|
407
|
-
if normalize:
|
|
408
|
-
|
|
409
|
+
def set_header(self, name, value, normalize=False, replace=True):
|
|
410
|
+
if normalize:
|
|
411
|
+
name = name.title()
|
|
412
|
+
if not replace and name in self.out_headers:
|
|
413
|
+
return
|
|
409
414
|
self.out_headers[name] = legacy.ascii(value)
|
|
410
415
|
|
|
411
|
-
def ensure_header(self, name, value, normalize
|
|
412
|
-
self.set_header(name, value, normalize
|
|
416
|
+
def ensure_header(self, name, value, normalize=False):
|
|
417
|
+
self.set_header(name, value, normalize=normalize, replace=False)
|
|
413
418
|
|
|
414
419
|
def set_headers(self, headers):
|
|
415
|
-
if not headers:
|
|
420
|
+
if not headers:
|
|
421
|
+
return
|
|
416
422
|
for name, value in headers.items():
|
|
417
423
|
self.set_header(name, value)
|
|
418
424
|
|
|
@@ -420,21 +426,24 @@ class Request(object):
|
|
|
420
426
|
for name, value in headers_l:
|
|
421
427
|
self.set_header(name, value)
|
|
422
428
|
|
|
423
|
-
def has_header_in(self, name, insensitive
|
|
424
|
-
if insensitive:
|
|
429
|
+
def has_header_in(self, name, insensitive=True):
|
|
430
|
+
if insensitive:
|
|
431
|
+
name = name.title()
|
|
425
432
|
return name in self.in_headers
|
|
426
433
|
|
|
427
|
-
def has_header_out(self, name, insensitive
|
|
428
|
-
if insensitive:
|
|
434
|
+
def has_header_out(self, name, insensitive=True):
|
|
435
|
+
if insensitive:
|
|
436
|
+
name = name.title()
|
|
429
437
|
return name in self.out_headers
|
|
430
438
|
|
|
431
439
|
def set_headers_b(self):
|
|
432
440
|
content_type = self.get_content_type() or "text/plain"
|
|
433
441
|
cache_control = self.get_cache_control()
|
|
434
442
|
self.set_header("Content-Type", content_type)
|
|
435
|
-
if cache_control:
|
|
443
|
+
if cache_control:
|
|
444
|
+
self.set_header("Cache-Control", cache_control)
|
|
436
445
|
|
|
437
|
-
def get_address(self, resolve
|
|
446
|
+
def get_address(self, resolve=True, cleanup=True):
|
|
438
447
|
"""
|
|
439
448
|
Retrieves the client (network) address associated with the
|
|
440
449
|
current request/connection.
|
|
@@ -468,7 +477,7 @@ class Request(object):
|
|
|
468
477
|
address = address[7:]
|
|
469
478
|
return address
|
|
470
479
|
|
|
471
|
-
def get_host(self, resolve
|
|
480
|
+
def get_host(self, resolve=True):
|
|
472
481
|
"""
|
|
473
482
|
Retrieves the hostname (as a string) associated with the
|
|
474
483
|
current request.
|
|
@@ -488,21 +497,26 @@ class Request(object):
|
|
|
488
497
|
server_port = int(self.environ.get("SERVER_PORT", "80"))
|
|
489
498
|
server_host = "%s:%d" % (server_name, server_port)
|
|
490
499
|
host = self.get_header("Host", server_host)
|
|
491
|
-
if resolve:
|
|
500
|
+
if resolve:
|
|
501
|
+
host = self.get_header("X-Forwarded-Host", host)
|
|
492
502
|
return host
|
|
493
503
|
|
|
494
|
-
def get_url(self, resolve
|
|
495
|
-
host = self.get_host(resolve
|
|
496
|
-
if not host:
|
|
497
|
-
|
|
504
|
+
def get_url(self, resolve=True):
|
|
505
|
+
host = self.get_host(resolve=resolve)
|
|
506
|
+
if not host:
|
|
507
|
+
return
|
|
508
|
+
if not self.scheme:
|
|
509
|
+
return
|
|
498
510
|
query_s = "?%s" % self.query if self.query else ""
|
|
499
511
|
return "%s://%s%s%s" % (self.scheme, host, self.path, query_s)
|
|
500
512
|
|
|
501
513
|
def resolve_params(self):
|
|
502
514
|
self.params = self._resolve_p(self.params)
|
|
503
515
|
|
|
504
|
-
def resolve_query_s(self, prefixes
|
|
505
|
-
parts = [
|
|
516
|
+
def resolve_query_s(self, prefixes=("x-",)):
|
|
517
|
+
parts = [
|
|
518
|
+
part for part in self.query.split("&") if not part.startswith(prefixes)
|
|
519
|
+
]
|
|
506
520
|
self.query_s = "&".join(parts)
|
|
507
521
|
self.prefixes = prefixes
|
|
508
522
|
|
|
@@ -522,7 +536,8 @@ class Request(object):
|
|
|
522
536
|
|
|
523
537
|
# verifies if the current data attribute contains a valid value in case
|
|
524
538
|
# it does not returns immediately as there's nothing to be loaded
|
|
525
|
-
if not self.data:
|
|
539
|
+
if not self.data:
|
|
540
|
+
return
|
|
526
541
|
|
|
527
542
|
# tries to retrieve the current content type value set in the environment
|
|
528
543
|
# then splits it around the separator to retrieve the mime type
|
|
@@ -533,14 +548,13 @@ class Request(object):
|
|
|
533
548
|
|
|
534
549
|
if mime_type == "application/json":
|
|
535
550
|
data = self.data.decode("utf-8") if self.data else None
|
|
536
|
-
try:
|
|
537
|
-
|
|
551
|
+
try:
|
|
552
|
+
self.data_j = json.loads(data) if data else None
|
|
553
|
+
except Exception:
|
|
554
|
+
pass
|
|
538
555
|
elif mime_type == "application/x-www-form-urlencoded":
|
|
539
556
|
data = legacy.str(self.data) if self.data else None
|
|
540
|
-
post = legacy.parse_qs(
|
|
541
|
-
data,
|
|
542
|
-
keep_blank_values = True
|
|
543
|
-
) if self.data else {}
|
|
557
|
+
post = legacy.parse_qs(data, keep_blank_values=True) if self.data else {}
|
|
544
558
|
post = util.decode_params(post)
|
|
545
559
|
self.set_post(post)
|
|
546
560
|
elif mime_type == "multipart/form-data":
|
|
@@ -558,23 +572,23 @@ class Request(object):
|
|
|
558
572
|
# components of username and password, in case the structure of the
|
|
559
573
|
# provided string is not compliant an exception is raised
|
|
560
574
|
authorization = self.environ.get("HTTP_AUTHORIZATION", None)
|
|
561
|
-
if not authorization:
|
|
575
|
+
if not authorization:
|
|
576
|
+
return
|
|
562
577
|
parts = authorization.split(" ", 1)
|
|
563
|
-
if not len(parts) == 2:
|
|
564
|
-
message
|
|
565
|
-
)
|
|
578
|
+
if not len(parts) == 2:
|
|
579
|
+
raise exceptions.OperationalError(message="Invalid authorization header")
|
|
566
580
|
_method, value = parts
|
|
567
581
|
value = base64.b64decode(value)
|
|
568
582
|
value = legacy.str(value)
|
|
569
583
|
parts = value.split(":", 1)
|
|
570
|
-
if not len(parts) == 2:
|
|
571
|
-
message
|
|
572
|
-
)
|
|
584
|
+
if not len(parts) == 2:
|
|
585
|
+
raise exceptions.OperationalError(message="Invalid authorization header")
|
|
573
586
|
self.authorization = tuple(parts)
|
|
574
587
|
|
|
575
588
|
def load_headers(self):
|
|
576
589
|
for key, value in self.environ.items():
|
|
577
|
-
if not key.startswith("HTTP_"):
|
|
590
|
+
if not key.startswith("HTTP_"):
|
|
591
|
+
continue
|
|
578
592
|
key = key[5:]
|
|
579
593
|
parts = key.split("_")
|
|
580
594
|
parts = [part.title() for part in parts]
|
|
@@ -594,54 +608,61 @@ class Request(object):
|
|
|
594
608
|
cookie_s = self.environ.get("HTTP_COOKIE", "")
|
|
595
609
|
self.cookies = util.parse_cookie(cookie_s)
|
|
596
610
|
|
|
597
|
-
def locale_s(self, value
|
|
611
|
+
def locale_s(self, value=None):
|
|
598
612
|
value = value or self.locale
|
|
599
613
|
return value.replace("_", "-").lower()
|
|
600
614
|
|
|
601
|
-
def locale_b(self, value
|
|
615
|
+
def locale_b(self, value=None):
|
|
602
616
|
value = value or self.locale
|
|
603
617
|
return value.replace("-", "_").lower()
|
|
604
618
|
|
|
605
|
-
def locale_l(self, value
|
|
619
|
+
def locale_l(self, value=None):
|
|
606
620
|
value = value or self.locale
|
|
607
621
|
return value.split("_", 1)[0]
|
|
608
622
|
|
|
609
|
-
def load_locale(self, available, fallback
|
|
623
|
+
def load_locale(self, available, fallback="en_us", ensure=True):
|
|
610
624
|
# tries to gather the best locale value using the currently
|
|
611
625
|
# available strategies and in case the retrieved local is part
|
|
612
626
|
# of the valid locales for the app returns the locale, otherwise
|
|
613
627
|
# returns the fallback value instead (using the first available
|
|
614
628
|
# locale in case the ensure flag is set)
|
|
615
|
-
locale = self.get_locale(fallback
|
|
629
|
+
locale = self.get_locale(fallback=fallback)
|
|
616
630
|
locale = self.locale_b(locale)
|
|
617
631
|
language = self.locale_l(locale)
|
|
618
|
-
if locale in available:
|
|
619
|
-
|
|
620
|
-
if
|
|
632
|
+
if locale in available:
|
|
633
|
+
return self.set_locale(locale)
|
|
634
|
+
if language in available:
|
|
635
|
+
return self.set_locale(locale)
|
|
636
|
+
if ensure and available:
|
|
637
|
+
return self.set_locale(available[0])
|
|
621
638
|
return self.set_locale(fallback)
|
|
622
639
|
|
|
623
|
-
def get_locale(self, fallback
|
|
640
|
+
def get_locale(self, fallback="en_us"):
|
|
624
641
|
# tries to retrieve the locale value from the provided URL
|
|
625
642
|
# parameters (this is the highest priority) and in case it
|
|
626
643
|
# exists returns this locale immediately
|
|
627
644
|
locale = self.params.get("locale", None)
|
|
628
|
-
if locale:
|
|
645
|
+
if locale:
|
|
646
|
+
return locale[0]
|
|
629
647
|
|
|
630
648
|
# uses the currently loaded session to try to gather the locale
|
|
631
649
|
# value from it and in case it's valid and exists returns it
|
|
632
650
|
locale = self.session.get("locale", None)
|
|
633
|
-
if locale:
|
|
651
|
+
if locale:
|
|
652
|
+
return locale
|
|
634
653
|
|
|
635
654
|
# gathers the complete set of language values set in the accept
|
|
636
655
|
# language header and in case there's at least one value returned
|
|
637
656
|
# returns the first of these values as the locale
|
|
638
657
|
langs = self.get_langs()
|
|
639
|
-
if langs:
|
|
658
|
+
if langs:
|
|
659
|
+
return langs[0]
|
|
640
660
|
|
|
641
661
|
# defines the locale as the global wide appier configuration and
|
|
642
662
|
# tries to retrieve the value of it in case it's valid uses it
|
|
643
663
|
locale = config.conf("LOCALE", None)
|
|
644
|
-
if locale:
|
|
664
|
+
if locale:
|
|
665
|
+
return locale
|
|
645
666
|
|
|
646
667
|
# in case this code entry is reached all the strategies for locale
|
|
647
668
|
# retrieval have failed and so the fallback value is returned
|
|
@@ -658,7 +679,8 @@ class Request(object):
|
|
|
658
679
|
# it's not defined returns immediately as no language can be
|
|
659
680
|
# determined using the currently provided headers
|
|
660
681
|
accept_language = self.in_headers.get("Accept-Language", None)
|
|
661
|
-
if not accept_language:
|
|
682
|
+
if not accept_language:
|
|
683
|
+
return ()
|
|
662
684
|
|
|
663
685
|
# starts the list that is going to be used to store the various
|
|
664
686
|
# languages "recovered" from the accept language header, note that
|
|
@@ -673,8 +695,10 @@ class Request(object):
|
|
|
673
695
|
for part in parts:
|
|
674
696
|
values = part.split(";", 1)
|
|
675
697
|
value_l = len(values)
|
|
676
|
-
if value_l == 1:
|
|
677
|
-
|
|
698
|
+
if value_l == 1:
|
|
699
|
+
(lang,) = values
|
|
700
|
+
else:
|
|
701
|
+
lang, _priority = values
|
|
678
702
|
lang = lang.replace("-", "_")
|
|
679
703
|
lang = lang.lower()
|
|
680
704
|
langs.append(lang)
|
|
@@ -686,18 +710,21 @@ class Request(object):
|
|
|
686
710
|
|
|
687
711
|
def set_alias(self):
|
|
688
712
|
for alias in Request.ALIAS:
|
|
689
|
-
if not alias in self.params:
|
|
713
|
+
if not alias in self.params:
|
|
714
|
+
continue
|
|
690
715
|
self.params["sid"] = self.params[alias]
|
|
691
716
|
|
|
692
717
|
for alias in Request.ALIAS:
|
|
693
|
-
if not alias in self.post:
|
|
718
|
+
if not alias in self.post:
|
|
719
|
+
continue
|
|
694
720
|
self.post["sid"] = self.post[alias]
|
|
695
721
|
|
|
696
722
|
for alias in Request.ALIAS:
|
|
697
|
-
if not alias in self.args:
|
|
723
|
+
if not alias in self.args:
|
|
724
|
+
continue
|
|
698
725
|
self.args["sid"] = self.args[alias]
|
|
699
726
|
|
|
700
|
-
def set_session(self, create
|
|
727
|
+
def set_session(self, create=False):
|
|
701
728
|
# tries to retrieves the session id (SID) from all the
|
|
702
729
|
# possible sources so that something may be used in the
|
|
703
730
|
# identification of the current request
|
|
@@ -714,39 +741,50 @@ class Request(object):
|
|
|
714
741
|
# tries to retrieve the session reference for the
|
|
715
742
|
# provided SID (session id) in case there's an exception
|
|
716
743
|
# defaults to unset session so that a new one gets created
|
|
717
|
-
try:
|
|
718
|
-
|
|
744
|
+
try:
|
|
745
|
+
session = self.session_c.get_s(sid, request=self)
|
|
746
|
+
except Exception:
|
|
747
|
+
session = None
|
|
719
748
|
|
|
720
749
|
# in case no valid session exists a new one must be created
|
|
721
750
|
# so that the user may be able to interact with the system
|
|
722
751
|
# with some kind of memory/persistence otherwise sets the
|
|
723
752
|
# loaded session in the current request (to be used)
|
|
724
|
-
if session:
|
|
725
|
-
|
|
753
|
+
if session:
|
|
754
|
+
self.session = session
|
|
755
|
+
elif create:
|
|
756
|
+
self.session = self.session_c.new(address=self.address)
|
|
726
757
|
|
|
727
758
|
def get_session(self):
|
|
728
759
|
return self.session
|
|
729
760
|
|
|
730
761
|
def get_session_agent(self):
|
|
731
|
-
if not self.session:
|
|
732
|
-
|
|
762
|
+
if not self.session:
|
|
763
|
+
return None
|
|
764
|
+
if not self.session.is_loaded():
|
|
765
|
+
return None
|
|
733
766
|
username = self.session.get("username", None)
|
|
734
|
-
if username:
|
|
767
|
+
if username:
|
|
768
|
+
return username
|
|
735
769
|
email = self.session.get("email", None)
|
|
736
|
-
if email:
|
|
770
|
+
if email:
|
|
771
|
+
return email
|
|
737
772
|
id = self.session.get("id", None)
|
|
738
|
-
if id:
|
|
773
|
+
if id:
|
|
774
|
+
return id
|
|
739
775
|
return None
|
|
740
776
|
|
|
741
777
|
def get_warnings(self):
|
|
742
778
|
return self.warnings
|
|
743
779
|
|
|
744
|
-
def get_set_cookie(self, lang
|
|
780
|
+
def get_set_cookie(self, lang="en", path="/", delta=31536000):
|
|
745
781
|
base = self.set_cookie
|
|
746
|
-
if not base:
|
|
782
|
+
if not base:
|
|
783
|
+
return base
|
|
747
784
|
expires = time.time() + delta
|
|
748
785
|
expires_d = datetime.datetime.fromtimestamp(expires)
|
|
749
|
-
with util.ctx_locale():
|
|
786
|
+
with util.ctx_locale():
|
|
787
|
+
expires_s = expires_d.strftime("%a, %m %b %Y %H:%M:%S GMT")
|
|
750
788
|
set_cookie = "%s%s;lang=%s;path=%s;expires=%s;%s" % (
|
|
751
789
|
self.set_cookie_prefix or self.owner.set_cookie_prefix or "",
|
|
752
790
|
base,
|
|
@@ -773,11 +811,11 @@ class Request(object):
|
|
|
773
811
|
code_s = str(self.code) + " " + code_s
|
|
774
812
|
return code_s
|
|
775
813
|
|
|
776
|
-
def get_sdate(self, format
|
|
814
|
+
def get_sdate(self, format="%d/%b/%Y:%H:%M:%S +0000"):
|
|
777
815
|
sdate = datetime.datetime.utcfromtimestamp(self.stime)
|
|
778
816
|
return sdate.strftime(format)
|
|
779
817
|
|
|
780
|
-
def get_edate(self, format
|
|
818
|
+
def get_edate(self, format="%d/%b/%Y:%H:%M:%S +0000"):
|
|
781
819
|
edate = datetime.datetime.utcfromtimestamp(self.etime)
|
|
782
820
|
return edate.strftime(format)
|
|
783
821
|
|
|
@@ -807,36 +845,48 @@ class Request(object):
|
|
|
807
845
|
return False
|
|
808
846
|
|
|
809
847
|
@property
|
|
810
|
-
def location_f(self, safe
|
|
848
|
+
def location_f(self, safe=True):
|
|
811
849
|
query = self.query_s if safe else self.query
|
|
812
|
-
if not query:
|
|
850
|
+
if not query:
|
|
851
|
+
return self.location
|
|
813
852
|
return self.location + "?" + query
|
|
814
853
|
|
|
815
854
|
@property
|
|
816
|
-
def params_f(self, safe
|
|
817
|
-
if not safe:
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
855
|
+
def params_f(self, safe=True):
|
|
856
|
+
if not safe:
|
|
857
|
+
return self.params_s
|
|
858
|
+
if hasattr(self, "_params_f"):
|
|
859
|
+
return self._params_f
|
|
860
|
+
self._params_f = dict(
|
|
861
|
+
[
|
|
862
|
+
(key, value)
|
|
863
|
+
for key, value in self.params_s.items()
|
|
864
|
+
if not key.startswith(self.prefixes)
|
|
865
|
+
]
|
|
866
|
+
)
|
|
821
867
|
return self._params_f
|
|
822
868
|
|
|
823
869
|
@property
|
|
824
|
-
def duration(self, milliseconds
|
|
825
|
-
if not self.stime:
|
|
826
|
-
|
|
870
|
+
def duration(self, milliseconds=True, safe=True):
|
|
871
|
+
if not self.stime:
|
|
872
|
+
return None
|
|
873
|
+
if not self.etime and not safe:
|
|
874
|
+
return None
|
|
827
875
|
etime = self.etime or time.time()
|
|
828
876
|
duration = etime - self.stime
|
|
829
|
-
if not milliseconds:
|
|
877
|
+
if not milliseconds:
|
|
878
|
+
return duration
|
|
830
879
|
return duration * 1000.0
|
|
831
880
|
|
|
832
881
|
@property
|
|
833
882
|
def in_length(self):
|
|
834
883
|
data = self.get_data()
|
|
835
|
-
if not data:
|
|
884
|
+
if not data:
|
|
885
|
+
return 0
|
|
836
886
|
return len(data)
|
|
837
887
|
|
|
838
888
|
@property
|
|
839
|
-
def out_length(self, safe
|
|
889
|
+
def out_length(self, safe=True):
|
|
840
890
|
return self.result_l or 0
|
|
841
891
|
|
|
842
892
|
@property
|
|
@@ -854,8 +904,10 @@ class Request(object):
|
|
|
854
904
|
|
|
855
905
|
def _resolve_p(self, params):
|
|
856
906
|
secret = self.session.get("secret", None)
|
|
857
|
-
if not secret:
|
|
858
|
-
|
|
907
|
+
if not secret:
|
|
908
|
+
return params
|
|
909
|
+
raise exceptions.AppierException(message="Not implemented")
|
|
910
|
+
|
|
859
911
|
|
|
860
912
|
class MockRequest(Request):
|
|
861
913
|
"""
|
|
@@ -867,7 +919,7 @@ class MockRequest(Request):
|
|
|
867
919
|
per each execution life-cycle.
|
|
868
920
|
"""
|
|
869
921
|
|
|
870
|
-
def __init__(self, locale
|
|
922
|
+
def __init__(self, locale="en_us", *args, **kwargs):
|
|
871
923
|
Request.__init__(self, *args, **kwargs)
|
|
872
924
|
self.files_s = dict()
|
|
873
925
|
self.post_s = dict()
|