OLD | NEW |
1 # Copyright (c) 2017 The Chromium Authors. All rights reserved. | 1 # Copyright (c) 2017 The Chromium Authors. All rights reserved. |
2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
5 import os | 5 import os |
| 6 import json |
| 7 import sys |
6 | 8 |
7 from telemetry.core import util | 9 from telemetry.core import util |
8 from telemetry.internal.browser import browser_finder | 10 from telemetry.internal.browser import browser_finder |
9 | 11 |
10 | 12 |
| 13 def _TransmitLargeJSONToTab(tab, json_obj, js_holder_name): |
| 14 tab.ExecuteJavaScript( |
| 15 'var {{ @js_holder_name }} = "";', js_holder_name=js_holder_name) |
| 16 |
| 17 # To avoid crashing devtool connection (details in crbug.com/763119#c16), |
| 18 # we break down the json string to chunks which each chunk has a maximum |
| 19 # size of 100000 characters (100000 seems to not break the connection and |
| 20 # makes sending data reasonably fast). |
| 21 k = 0 |
| 22 step_size = 100000 |
| 23 json_obj_string = json.dumps(json_obj) |
| 24 while k < len(json_obj_string): |
| 25 sub_string_chunk = json_obj_string[k: k + step_size] |
| 26 k += step_size |
| 27 tab.ExecuteJavaScript( |
| 28 '{{ @js_holder_name }} += {{ sub_string_chunk }};', |
| 29 js_holder_name=js_holder_name, sub_string_chunk=sub_string_chunk) |
| 30 |
| 31 tab.ExecuteJavaScript( |
| 32 '{{ @js_holder_name }} = JSON.parse({{ @js_holder_name }});', |
| 33 js_holder_name=js_holder_name) |
| 34 |
11 def SnapPage(finder_options, url, interactive, snapshot_file): | 35 def SnapPage(finder_options, url, interactive, snapshot_file): |
12 """ Save the HTML snapshot of the page whose address is |url| to | 36 """ Save the HTML snapshot of the page whose address is |url| to |
13 |snapshot_file|. | 37 |snapshot_file|. |
14 """ | 38 """ |
15 possible_browser = browser_finder.FindBrowser(finder_options) | 39 possible_browser = browser_finder.FindBrowser(finder_options) |
16 browser = possible_browser.Create(finder_options) | 40 browser = possible_browser.Create(finder_options) |
17 try: | 41 try: |
18 tab = browser.tabs[0] | 42 tab = browser.tabs[0] |
19 tab.Navigate(url) | 43 tab.Navigate(url) |
20 tab.WaitForDocumentReadyStateToBeComplete() | |
21 if interactive: | 44 if interactive: |
22 raw_input( | 45 raw_input( |
23 'Activating interactive mode. Press enter after you finish ' | 46 'Activating interactive mode. Press enter after you finish ' |
24 "interacting with the page to snapshot the page's DOM content.") | 47 "interacting with the page to snapshot the page's DOM content.") |
25 with open( | 48 |
26 os.path.join(util.GetTelemetryThirdPartyDir(), 'snap-it', | 49 sys.stdout.write( |
27 'HTMLSerializer.js')) as f: | 50 'Snapshotting content of %s. This could take a while...\n' % url) |
| 51 tab.WaitForDocumentReadyStateToBeComplete() |
| 52 tab.action_runner.WaitForNetworkQuiescence() |
| 53 |
| 54 with open(os.path.join(util.GetTelemetryThirdPartyDir(), 'snap-it', |
| 55 'HTMLSerializer.js')) as f: |
28 snapit_script = f.read() | 56 snapit_script = f.read() |
29 tab.ExecuteJavaScript(snapit_script) | 57 |
30 tab.ExecuteJavaScript( | 58 with open(os.path.join(util.GetTelemetryThirdPartyDir(), 'snap-it', |
31 ''' | 59 'popup.js')) as f: |
32 var serializedDomArray; | 60 dom_combining_script = f.read() |
33 var htmlSerializer = new HTMLSerializer(); | 61 |
34 htmlSerializer.processDocument(document); | 62 serialized_doms = [] |
35 htmlSerializer.fillHolesAsync(document, function(s) { | 63 |
36 serializedDomArray = s.html; | 64 # Serialize the dom in each frame. |
37 }); | 65 for context_id in tab.EnableAllContexts(): |
38 ''') | 66 tab.ExecuteJavaScript(snapit_script, context_id=context_id) |
39 print 'Snapshotting content of %s. This could take a while...' % url | 67 tab.ExecuteJavaScript( |
40 tab.WaitForJavaScriptCondition('serializedDomArray !== undefined') | 68 ''' |
41 serialized_dom = ''.join(tab.EvaluateJavaScript('serializedDomArray')) | 69 var serializedDom; |
42 snapshot_file.write(serialized_dom) | 70 var htmlSerializer = new HTMLSerializer(); |
| 71 htmlSerializer.processDocument(document); |
| 72 htmlSerializer.fillHolesAsync(document, function(s) { |
| 73 serializedDom = s.asDict(); |
| 74 }); |
| 75 ''', context_id=context_id) |
| 76 tab.WaitForJavaScriptCondition( |
| 77 'serializedDom !== undefined', context_id=context_id) |
| 78 serialized_doms.append(tab.EvaluateJavaScript( |
| 79 'serializedDom', context_id=context_id)) |
| 80 |
| 81 # Execute doms combining code in blank page to minimize the chance of V8 |
| 82 # OOM. |
| 83 tab.Navigate('about:blank') |
| 84 tab.WaitForDocumentReadyStateToBeComplete() |
| 85 |
| 86 # Sending all the serialized doms back to tab execution context. |
| 87 tab.ExecuteJavaScript('var serializedDoms = [];') |
| 88 for i in xrange(len(serialized_doms)): |
| 89 sys.stdout.write('Processing dom of frame #%i / %i\r' % |
| 90 (i, len(serialized_doms))) |
| 91 sys.stdout.flush() |
| 92 _TransmitLargeJSONToTab(tab, serialized_doms[i], 'sub_dom') |
| 93 tab.ExecuteJavaScript('serializedDoms.push(sub_dom);') |
| 94 |
| 95 # Combine all the doms to one HTML string. |
| 96 tab.EvaluateJavaScript(dom_combining_script) |
| 97 page_snapshot = tab.EvaluateJavaScript('outputHTMLString(serializedDoms);') |
| 98 |
| 99 snapshot_file.write(page_snapshot) |
43 finally: | 100 finally: |
44 browser.Close() | 101 browser.Close() |
OLD | NEW |