(self, status=200, content_type="text/html", noscript=False, allow_ajax=False, script_nonce=None, extra_headers=[])
| 256 | |
| 257 | # Send response headers |
| 258 | def sendHeader(self, status=200, content_type="text/html", noscript=False, allow_ajax=False, script_nonce=None, extra_headers=[]): |
| 259 | headers = {} |
| 260 | headers["Version"] = "HTTP/1.1" |
| 261 | headers["Connection"] = "Keep-Alive" |
| 262 | headers["Keep-Alive"] = "max=25, timeout=30" |
| 263 | headers["X-Frame-Options"] = "SAMEORIGIN" |
| 264 | if content_type != "text/html" and self.env.get("HTTP_REFERER") and self.isSameOrigin(self.getReferer(), self.getRequestUrl()): |
| 265 | headers["Access-Control-Allow-Origin"] = "*" # Allow load font files from css |
| 266 | if content_type == "text/javascript" and not self.env.get("HTTP_REFERER"): |
| 267 | headers["Access-Control-Allow-Origin"] = "*" # Allow loading JavaScript modules in Chrome |
| 268 | |
| 269 | if noscript: |
| 270 | headers["Content-Security-Policy"] = "default-src 'none'; sandbox allow-top-navigation allow-forms; img-src 'self'; font-src 'self'; media-src 'self'; style-src 'self' 'unsafe-inline';" |
| 271 | elif script_nonce and self.isScriptNonceSupported(): |
| 272 | headers["Content-Security-Policy"] = "default-src 'none'; script-src 'nonce-{0}'; img-src 'self' blob:; style-src 'self' blob: 'unsafe-inline'; connect-src *; frame-src 'self' blob:".format(script_nonce) |
| 273 | |
| 274 | if allow_ajax: |
| 275 | headers["Access-Control-Allow-Origin"] = "null" |
| 276 | |
| 277 | if self.env["REQUEST_METHOD"] == "OPTIONS": |
| 278 | # Allow json access |
| 279 | headers["Access-Control-Allow-Headers"] = "Origin, X-Requested-With, Content-Type, Accept, Cookie, Range" |
| 280 | headers["Access-Control-Allow-Credentials"] = "true" |
| 281 | |
| 282 | if content_type == "text/html": |
| 283 | content_type = "text/html; charset=utf-8" |
| 284 | if content_type == "text/plain": |
| 285 | content_type = "text/plain; charset=utf-8" |
| 286 | |
| 287 | # Download instead of display file types that can be dangerous |
| 288 | if re.findall("/svg|/xml|/x-shockwave-flash|/pdf", content_type): |
| 289 | headers["Content-Disposition"] = "attachment" |
| 290 | |
| 291 | cacheable_type = ( |
| 292 | content_type == "text/css" or content_type.startswith("image") or content_type.startswith("video") or |
| 293 | self.env["REQUEST_METHOD"] == "OPTIONS" or content_type == "application/javascript" |
| 294 | ) |
| 295 | |
| 296 | if status in (200, 206) and cacheable_type: # Cache Css, Js, Image files for 10min |
| 297 | headers["Cache-Control"] = "public, max-age=600" # Cache 10 min |
| 298 | else: |
| 299 | headers["Cache-Control"] = "no-cache, no-store, private, must-revalidate, max-age=0" # No caching at all |
| 300 | headers["Content-Type"] = content_type |
| 301 | headers.update(extra_headers) |
| 302 | return self.start_response(status_texts[status], list(headers.items())) |
| 303 | |
| 304 | # Renders a template |
| 305 | def render(self, template_path, *args, **kwargs): |
no test coverage detected