|  | 
| 39 | 39 | 
 | 
| 40 | 40 | _logger = logging.getLogger(__name__) | 
| 41 | 41 | 
 | 
| 42 |  | -_js_agent_header_fragment = '<script type="text/javascript">%s</script>' | 
| 43 |  | -_js_agent_footer_fragment = '<script type="text/javascript">'\ | 
| 44 |  | -                            'window.NREUM||(NREUM={});NREUM.info=%s</script>' | 
|  | 42 | +_js_agent_header_fragment = '<script type="text/javascript"%s>%s</script>' | 
|  | 43 | +_js_agent_footer_fragment = '<script type="text/javascript"%s>window.NREUM||(NREUM={});NREUM.info=%s</script>' | 
| 45 | 44 | 
 | 
| 46 | 45 | # Seconds since epoch for Jan 1 2000 | 
| 47 | 46 | JAN_1_2000 = time.mktime((2000, 1, 1, 0, 0, 0, 0, 0, 0)) | 
| @@ -156,6 +155,13 @@ def _is_websocket(environ): | 
| 156 | 155 |     return environ.get('HTTP_UPGRADE', '').lower() == 'websocket' | 
| 157 | 156 | 
 | 
| 158 | 157 | 
 | 
|  | 158 | +def _encode_nonce(nonce): | 
|  | 159 | +    if not nonce: | 
|  | 160 | +        return "" | 
|  | 161 | +    else: | 
|  | 162 | +        return ' nonce="%s"' % ensure_str(nonce)  # Extra space intentional | 
|  | 163 | + | 
|  | 164 | + | 
| 159 | 165 | class WebTransaction(Transaction): | 
| 160 | 166 |     unicode_error_reported = False | 
| 161 | 167 |     QUEUE_TIME_HEADERS = ('x-request-start', 'x-queue-start') | 
| @@ -386,7 +392,7 @@ def _update_agent_attributes(self): | 
| 386 | 392 | 
 | 
| 387 | 393 |         return super(WebTransaction, self)._update_agent_attributes() | 
| 388 | 394 | 
 | 
| 389 |  | -    def browser_timing_header(self): | 
|  | 395 | +    def browser_timing_header(self, nonce=None): | 
| 390 | 396 |         """Returns the JavaScript header to be included in any HTML | 
| 391 | 397 |         response to perform real user monitoring. This function returns | 
| 392 | 398 |         the header as a native Python string. In Python 2 native strings | 
| @@ -437,7 +443,7 @@ def browser_timing_header(self): | 
| 437 | 443 |         # 'none'. | 
| 438 | 444 | 
 | 
| 439 | 445 |         if self._settings.js_agent_loader: | 
| 440 |  | -            header = _js_agent_header_fragment % self._settings.js_agent_loader | 
|  | 446 | +            header = _js_agent_header_fragment % (_encode_nonce(nonce), self._settings.js_agent_loader) | 
| 441 | 447 | 
 | 
| 442 | 448 |             # To avoid any issues with browser encodings, we will make sure | 
| 443 | 449 |             # that the javascript we inject for the browser agent is ASCII | 
| @@ -476,7 +482,7 @@ def browser_timing_header(self): | 
| 476 | 482 | 
 | 
| 477 | 483 |         return header | 
| 478 | 484 | 
 | 
| 479 |  | -    def browser_timing_footer(self): | 
|  | 485 | +    def browser_timing_footer(self, nonce=None): | 
| 480 | 486 |         """Returns the JavaScript footer to be included in any HTML | 
| 481 | 487 |         response to perform real user monitoring. This function returns | 
| 482 | 488 |         the footer as a native Python string. In Python 2 native strings | 
| @@ -541,7 +547,7 @@ def browser_timing_footer(self): | 
| 541 | 547 |             attributes = obfuscate(json_encode(attributes), obfuscation_key) | 
| 542 | 548 |             footer_data['atts'] = attributes | 
| 543 | 549 | 
 | 
| 544 |  | -        footer = _js_agent_footer_fragment % json_encode(footer_data) | 
|  | 550 | +        footer = _js_agent_footer_fragment % (_encode_nonce(nonce), json_encode(footer_data)) | 
| 545 | 551 | 
 | 
| 546 | 552 |         # To avoid any issues with browser encodings, we will make sure that | 
| 547 | 553 |         # the javascript we inject for the browser agent is ASCII encodable. | 
|  | 
0 commit comments