Coverage for gws-app/gws/base/web/site.py: 69%

93 statements  

« prev     ^ index     » next       coverage.py v7.8.0, created at 2025-04-17 01:37 +0200

1from typing import Optional 

2 

3import re 

4 

5import gws 

6import gws.lib.net 

7 

8 

9class CorsConfig(gws.Config): 

10 """CORS configuration.""" 

11 

12 allowCredentials: bool = False 

13 """Access-Control-Allow-Credentials header.""" 

14 allowHeaders: str = '' 

15 """Access-Control-Allow-Headers header.""" 

16 allowMethods: str = '' 

17 """Access-Control-Allow-Methods header.""" 

18 allowOrigin: str = '' 

19 """Access-Control-Allow-Origin header.""" 

20 maxAge: int = 5 

21 """Access-Control-Max-Age header.""" 

22 

23 

24class RewriteRuleConfig(gws.Config): 

25 """Rewrite rule configuration.""" 

26 

27 pattern: gws.Regex 

28 """Expression to match the url against.""" 

29 target: str 

30 """Target url with placeholders.""" 

31 options: Optional[dict] 

32 """Additional options.""" 

33 reversed: bool = False 

34 """Reversed rewrite rule.""" 

35 

36 

37class SSLConfig(gws.Config): 

38 """SSL configuration.""" 

39 

40 crt: gws.FilePath 

41 """Crt bundle location.""" 

42 key: gws.FilePath 

43 """Key file location.""" 

44 hsts: gws.Duration = "365d" 

45 """HSTS max age. (added in 8.1)""" 

46 

47 

48class WebDocumentRootConfig(gws.Config): 

49 """Web-accessible directory.""" 

50 

51 dir: gws.DirPath 

52 """Directory path.""" 

53 allowMime: Optional[list[str]] 

54 """Allowed mime types.""" 

55 denyMime: Optional[list[str]] 

56 """Disallowed mime types (from the standard list).""" 

57 

58 

59class Config(gws.Config): 

60 """Site (virtual host) configuration""" 

61 

62 assets: Optional[WebDocumentRootConfig] 

63 """Root directory for assets.""" 

64 cors: Optional[CorsConfig] 

65 """Cors configuration.""" 

66 contentSecurityPolicy: str = "default-src 'self'; img-src * data: blob:" 

67 """Content Security Policy for this site. (added in 8.1)""" 

68 permissionsPolicy: str = "geolocation=(self), camera=(), microphone=()" 

69 """Permissions Policy for this site. (added in 8.1)""" 

70 errorPage: Optional[gws.ext.config.template] 

71 """Error page template.""" 

72 host: str = '*' 

73 """Host name.""" 

74 rewrite: Optional[list[RewriteRuleConfig]] 

75 """Rewrite rules.""" 

76 canonicalHost: str = '' 

77 """Hostname for reversed URL rewriting.""" 

78 root: WebDocumentRootConfig 

79 """Root directory for static documents.""" 

80 

81 

82class Object(gws.WebSite): 

83 canonicalHost: str 

84 ssl: bool 

85 contentSecurityPolicy: str 

86 permissionsPolicy: str 

87 

88 def configure(self): 

89 

90 self.host = self.cfg('host', default='*') 

91 self.canonicalHost = self.cfg('canonicalHost') 

92 

93 self.staticRoot = gws.WebDocumentRoot(self.cfg('root')) 

94 

95 p = self.cfg('assets') 

96 self.assetsRoot = gws.WebDocumentRoot(p) if p else None 

97 

98 self.ssl = self.cfg('ssl') 

99 

100 self.rewriteRules = self.cfg('rewrite', default=[]) 

101 for r in self.rewriteRules: 

102 if not gws.lib.net.is_abs_url(r.target): 

103 # ensure rewriting from root 

104 r.target = '/' + r.target.lstrip('/') 

105 

106 self.errorPage = self.create_child_if_configured(gws.ext.object.template, self.cfg('errorPage')) 

107 self.corsOptions = self.cfg('cors') 

108 

109 self.contentSecurityPolicy = self.cfg('contentSecurityPolicy') 

110 self.permissionsPolicy = self.cfg('permissionsPolicy') 

111 

112 def url_for(self, req, path, **params): 

113 if gws.lib.net.is_abs_url(path): 

114 return gws.lib.net.add_params(path, params) 

115 

116 proto = 'https' if self.ssl else 'http' 

117 host = self.canonicalHost or (req.env('HTTP_HOST') if self.host == '*' else self.host) 

118 base = proto + '://' + host 

119 

120 for rule in self.rewriteRules: 

121 if rule.reversed: 

122 m = re.match(rule.pattern, path) 

123 if m: 

124 # we use nginx syntax $1, need python's \1 

125 t = rule.target.replace('$', '\\') 

126 s = re.sub(rule.pattern, t, path) 

127 url = s if gws.lib.net.is_abs_url(s) else base + '/' + s.lstrip('/') 

128 return gws.lib.net.add_params(url, params) 

129 

130 url = base + '/' + path.lstrip('/') 

131 return gws.lib.net.add_params(url, params)