OLD | NEW |
| (Empty) |
1 #!/usr/bin/env python | |
2 # Copyright 2013 Google Inc. All Rights Reserved. | |
3 # | |
4 # Licensed under the Apache License, Version 2.0 (the "License"); | |
5 # you may not use this file except in compliance with the License. | |
6 # You may obtain a copy of the License at | |
7 # | |
8 # http://www.apache.org/licenses/LICENSE-2.0 | |
9 # | |
10 # Unless required by applicable law or agreed to in writing, software | |
11 # distributed under the License is distributed on an "AS IS" BASIS, | |
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 # See the License for the specific language governing permissions and | |
14 # limitations under the License. | |
15 | |
16 """Inject javascript into html page source code.""" | |
17 | |
18 import logging | |
19 import os | |
20 import re | |
21 import util | |
22 | |
23 DOCTYPE_RE = re.compile(r'^.{,256}?(<!--.*-->)?.{,256}?<!doctype html>', | |
24 re.IGNORECASE | re.DOTALL) | |
25 HTML_RE = re.compile(r'^.{,256}?(<!--.*-->)?.{,256}?<html.*?>', | |
26 re.IGNORECASE | re.DOTALL) | |
27 HEAD_RE = re.compile(r'^.{,256}?(<!--.*-->)?.{,256}?<head.*?>', | |
28 re.IGNORECASE | re.DOTALL) | |
29 | |
30 | |
31 def GetInjectScript(scripts): | |
32 """Loads |scripts| from disk and returns a string of their content.""" | |
33 lines = [] | |
34 if scripts: | |
35 if not isinstance(scripts, list): | |
36 scripts = scripts.split(',') | |
37 for script in scripts: | |
38 if os.path.exists(script): | |
39 with open(script) as f: | |
40 lines.extend(f.read()) | |
41 elif util.resource_exists(script): | |
42 lines.extend(util.resource_string(script)) | |
43 else: | |
44 raise Exception('Script does not exist: %s', script) | |
45 | |
46 def MinifyScript(script): | |
47 """Remove C-style comments and line breaks from script. | |
48 Note: statements must be ';' terminated, and not depending on newline""" | |
49 # Regex adapted from http://ostermiller.org/findcomment.html. | |
50 MULTILINE_COMMENT_RE = re.compile(r'/\*.*?\*/', re.DOTALL | re.MULTILINE) | |
51 SINGLELINE_COMMENT_RE = re.compile(r'//.*', re.MULTILINE) | |
52 # Remove C-style comments from JS. | |
53 script = re.sub(MULTILINE_COMMENT_RE, '', script) | |
54 script = re.sub(SINGLELINE_COMMENT_RE, '', script) | |
55 # Remove line breaks. | |
56 script = script.translate(None, '\r\n') | |
57 return script | |
58 | |
59 return MinifyScript(''.join(lines)) | |
60 | |
61 | |
62 def InjectScript(content, content_type, script_to_inject): | |
63 """Inject |script_to_inject| into |content| if |content_type| is 'text/html'. | |
64 | |
65 Inject |script_to_inject| into |content| immediately after <head>, <html> or | |
66 <!doctype html>, if one of them is found. Otherwise, inject at the beginning. | |
67 | |
68 Returns: | |
69 content, already_injected | |
70 |content| is the new content if script is injected, otherwise the original. | |
71 |already_injected| indicates if |script_to_inject| is already in |content|. | |
72 """ | |
73 already_injected = False | |
74 if content_type and content_type == 'text/html': | |
75 already_injected = not content or script_to_inject in content | |
76 if not already_injected: | |
77 def InsertScriptAfter(matchobj): | |
78 return '%s<script>%s</script>' % (matchobj.group(0), script_to_inject) | |
79 | |
80 content, is_injected = HEAD_RE.subn(InsertScriptAfter, content, 1) | |
81 if not is_injected: | |
82 content, is_injected = HTML_RE.subn(InsertScriptAfter, content, 1) | |
83 if not is_injected: | |
84 content, is_injected = DOCTYPE_RE.subn(InsertScriptAfter, content, 1) | |
85 if not is_injected: | |
86 content = '<script>%s</script>%s' % (script_to_inject, content) | |
87 logging.warning('Inject at the very beginning, because no tag of ' | |
88 '<head>, <html> or <!doctype html> is found.') | |
89 return content, already_injected | |
OLD | NEW |