Skip to content

Commit b0693cd

Browse files
Cong Liurogerwang
authored andcommitted
support passing Buffer or ArrayBuffer to evalNWBin
fixed nwjs#5220
1 parent 0f3d196 commit b0693cd

File tree

11 files changed

+154
-42
lines changed

11 files changed

+154
-42
lines changed

docs/For Users/Advanced/Protect JavaScript Source Code.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,21 @@ nw.Window.get().evalNWBin(frame, 'binary.bin');
2323
```
2424
The arguments of the [win.evalNWBin()](../../References/Window.md#winevalnwbin) method are similar with the `Window.eval()` method, where the first parameter is the target iframe (`null` for main frame), and the 2nd parameter is the binary code file.
2525

26+
### Load Compiled JavaScript from Remote
27+
28+
Compiled JavaScript can be fetched from remote (e.g. with AJAX) and executed on the fly.
29+
30+
```javascript
31+
var xhr = new XMLHttpRequest();
32+
xhr.responseType = 'arraybuffer'; // make response as ArrayBuffer
33+
xhr.open('GET', url, true);
34+
xhr.send();
35+
xhr.onload = () => {
36+
// xhr.response contains compiled JavaScript as ArrayBuffer
37+
nw.Window.get().evalNWBin(null, xhr.response);
38+
}
39+
```
40+
2641
!!! note
2742
The compiled code is executed in [Browser Context](JavaScript Contexts in NW.js.md#browser-context). You can use any Web APIs (such as DOM) and [access NW.js API and Node API](JavaScript Contexts in NW.js.md#access-nodejs-and-nwjs-api-in-browser-context) like other scripts running in browser context.
2843

docs/References/Window.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -423,7 +423,7 @@ Execute a piece of JavaScript in the frame.
423423
## win.evalNWBin(frame, path)
424424

425425
* `frame` `{HTMLIFrameElement}` the frame to execute in. If `iframe` is `null`, it assumes in current window / frame.
426-
* `path` `{String}` the path of the snapshot file generated by `nwjc`
426+
* `path` `{String|ArrayBuffer|Buffer}` the path or `Buffer` or `ArrayBuffer` of the snapshot file generated by `nwjc`
427427

428428
Load and execute the compiled snapshot in the frame. See [Protect JavaScript Source Code with V8 Snapshot](../For Users/Advanced/Protect JavaScript Source Code.md).
429429

src/nw_custom_bindings.cc

Lines changed: 32 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -215,47 +215,39 @@ void NWCustomBindings::EvalNWBin(
215215
content::RenderFrame* render_frame = context()->GetRenderFrame();
216216
if (!render_frame)
217217
return;
218-
#if defined(OS_WIN)
219-
base::FilePath path((WCHAR*)*v8::String::Value(args[1]));
220-
#else
221-
base::FilePath path(*v8::String::Utf8Value(args[1]));
222-
#endif
223-
base::File file(path, base::File::FLAG_OPEN | base::File::FLAG_READ);
224-
if (file.IsValid()) {
225-
int64_t length = file.GetLength();
226-
if (length > 0 && length < INT_MAX) {
227-
int size = static_cast<int>(length);
228-
std::vector<unsigned char> raw_data;
229-
raw_data.resize(size);
230-
uint8_t* data = reinterpret_cast<uint8_t*>(&(raw_data.front()));
231-
if (file.ReadAtCurrentPos((char*)data, size) == length) {
232-
WebFrame* main_frame = render_frame->GetWebFrame();
233-
v8::Handle<v8::String> source_string = v8::String::NewFromUtf8(isolate, "");
234-
v8::ScriptCompiler::CachedData* cache;
235-
cache = new v8::ScriptCompiler::CachedData(
236-
data, length, v8::ScriptCompiler::CachedData::BufferNotOwned);
237-
v8::ScriptCompiler::Source source(source_string, cache);
238-
v8::Local<v8::UnboundScript> script;
239-
script = v8::ScriptCompiler::CompileUnboundScript(
240-
isolate, &source, v8::ScriptCompiler::kConsumeCodeCache).ToLocalChecked();
241-
ASSERT(!cache->rejected);
242-
v8::Handle<v8::Value> result;
243-
v8::Handle<v8::Object> frm = v8::Handle<v8::Object>::Cast(args[0]);
244-
WebFrame* web_frame = NULL;
245-
if (frm->IsNull()) {
246-
web_frame = main_frame;
247-
}else{
248-
blink::HTMLIFrameElement* iframe = blink::V8HTMLIFrameElement::toImpl(frm);
249-
web_frame = blink::WebFrame::fromFrame(iframe->contentFrame());
250-
}
251-
v8::Context::Scope cscope (web_frame->mainWorldScriptContext());
252-
v8::FixSourceNWBin(isolate, script);
253-
result = script->BindToCurrentContext()->Run();
254-
args.GetReturnValue().Set(result);
255-
}
256-
}
218+
219+
if (!args[1]->IsArrayBuffer()) {
220+
return;
257221
}
258-
return;
222+
223+
v8::Local<v8::ArrayBuffer> ab = args[1].As<v8::ArrayBuffer>();
224+
v8::ArrayBuffer::Contents contents = ab->GetContents();
225+
int64_t length = contents.ByteLength();
226+
uint8_t *data = reinterpret_cast<uint8_t*>(contents.Data());
227+
228+
WebFrame* main_frame = render_frame->GetWebFrame();
229+
v8::Handle<v8::String> source_string = v8::String::NewFromUtf8(isolate, "");
230+
v8::ScriptCompiler::CachedData* cache;
231+
cache = new v8::ScriptCompiler::CachedData(
232+
data, length, v8::ScriptCompiler::CachedData::BufferNotOwned);
233+
v8::ScriptCompiler::Source source(source_string, cache);
234+
v8::Local<v8::UnboundScript> script;
235+
script = v8::ScriptCompiler::CompileUnboundScript(
236+
isolate, &source, v8::ScriptCompiler::kConsumeCodeCache).ToLocalChecked();
237+
ASSERT(!cache->rejected);
238+
v8::Handle<v8::Value> result;
239+
v8::Handle<v8::Object> frm = v8::Handle<v8::Object>::Cast(args[0]);
240+
WebFrame* web_frame = NULL;
241+
if (frm->IsNull()) {
242+
web_frame = main_frame;
243+
}else{
244+
blink::HTMLIFrameElement* iframe = blink::V8HTMLIFrameElement::toImpl(frm);
245+
web_frame = blink::WebFrame::fromFrame(iframe->contentFrame());
246+
}
247+
v8::Context::Scope cscope (web_frame->mainWorldScriptContext());
248+
v8::FixSourceNWBin(isolate, script);
249+
result = script->BindToCurrentContext()->Run();
250+
args.GetReturnValue().Set(result);
259251
}
260252

261253
void NWCustomBindings::GetAbsolutePath(

src/resources/api_nw_window.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -413,7 +413,19 @@ nw_binding.registerCustomHook(function(bindingsAPI) {
413413
return nwNatives.evalScript(frame, script);
414414
};
415415
NWWindow.prototype.evalNWBin = function (frame, path) {
416-
return nwNatives.evalNWBin(frame, path);
416+
var ab;
417+
if (Buffer.isBuffer(path)) {
418+
let buf = path;
419+
ab = new global.ArrayBuffer(path.length);
420+
path.copy(Buffer.from(ab));
421+
} else if ($Object.prototype.toString.apply(path) === '[object ArrayBuffer]') {
422+
ab = path;
423+
} else {
424+
let buf = global.require('fs').readFileSync(path);
425+
ab = new global.ArrayBuffer(buf.length);
426+
buf.copy(Buffer.from(ab));
427+
}
428+
return nwNatives.evalNWBin(frame, ab);
417429
};
418430
NWWindow.prototype.show = function () {
419431
this.appWindow.show();
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
out('ajax-result', 'success:ajax');
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
out('arraybuffer-result', 'success:arraybuffer');
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
out('buffer-result', 'success:buffer');
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta charset="utf-8">
5+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
6+
<title>nwjc-test</title>
7+
</head>
8+
<body>
9+
<button id="eval-path" type="button" onclick="evalPath()">Run with path</button>
10+
<button id="eval-buffer" type="button" onclick="evalBuffer()">Run with Buffer</button>
11+
<button id="eval-arraybuffer" type="button" onclick="evalArrayBuffer()">Run with ArrayBuffer</button>
12+
<button id="eval-ajax" type="button" onclick="evalAjax()">Run with Ajax</button>
13+
<script>
14+
var fs = require('fs');
15+
16+
function out(id, message) {
17+
var h1 = document.createElement('h1');
18+
h1.setAttribute('id', id);
19+
h1.innerHTML = message;
20+
document.body.appendChild(h1);
21+
}
22+
23+
function evalPath() {
24+
evalbin('path.bin');
25+
}
26+
27+
function evalBuffer() {
28+
evalbin(fs.readFileSync('buffer.bin'));
29+
}
30+
31+
function evalArrayBuffer() {
32+
var buf = fs.readFileSync('arraybuffer.bin');
33+
var ab = new global.ArrayBuffer(buf.length);
34+
buf.copy(Buffer.from(ab));
35+
evalbin(ab);
36+
}
37+
38+
function evalAjax() {
39+
var xhr = new XMLHttpRequest();
40+
xhr.responseType = 'arraybuffer';
41+
xhr.open('GET', 'ajax.bin', true);
42+
xhr.send();
43+
xhr.onload = ()=>evalbin(xhr.response);
44+
xhr.onerror = (e)=>out('arraybuffer-result', 'failed:' + e);
45+
}
46+
47+
function evalbin(bin) {
48+
nw.Window.get().evalNWBin(null, bin);
49+
}
50+
</script>
51+
</body>
52+
</html>
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"name": "nwjc-test",
3+
"main": "index.html"
4+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
out('path-result', 'success:path');
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import time
2+
import os
3+
import subprocess
4+
5+
from selenium import webdriver
6+
from selenium.webdriver.chrome.options import Options
7+
8+
testdir = os.path.dirname(os.path.abspath(__file__))
9+
# nwdist = os.path.dirname(os.environ['CHROMEDRIVER'])
10+
nwdist = os.path.join(os.path.dirname(os.environ['CHROMEDRIVER']), 'nwdist')
11+
12+
script_list = ['path', 'buffer', 'arraybuffer', 'ajax']
13+
14+
for script in script_list:
15+
script_path = os.path.join(testdir, script)
16+
child = subprocess.Popen([os.path.join(nwdist, 'nwjc'), script_path + '.js', script_path + '.bin'])
17+
child.wait()
18+
19+
chrome_options = Options()
20+
chrome_options.add_argument("nwapp=" + testdir)
21+
22+
driver = webdriver.Chrome(executable_path=os.environ['CHROMEDRIVER'], chrome_options=chrome_options)
23+
driver.implicitly_wait(2)
24+
time.sleep(1)
25+
try:
26+
print driver.current_url
27+
for script in script_list:
28+
driver.find_element_by_id('eval-%s' % script).click()
29+
result = driver.find_element_by_id('%s-result' % script).get_attribute('innerHTML')
30+
print result
31+
assert("success" in result)
32+
finally:
33+
driver.quit()

0 commit comments

Comments
 (0)