Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Side by Side Diff: src/WebRequestJsObject.cpp

Issue 29369520: Issue #4692 - Rewrite web request task to avoid engine self-reference
Patch Set: Created Dec. 24, 2016, 4:58 p.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/WebRequestJsObject.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * This file is part of Adblock Plus <https://adblockplus.org/>, 2 * This file is part of Adblock Plus <https://adblockplus.org/>,
3 * Copyright (C) 2006-2016 Eyeo GmbH 3 * Copyright (C) 2006-2016 Eyeo GmbH
4 * 4 *
5 * Adblock Plus is free software: you can redistribute it and/or modify 5 * Adblock Plus is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 3 as 6 * it under the terms of the GNU General Public License version 3 as
7 * published by the Free Software Foundation. 7 * published by the Free Software Foundation.
8 * 8 *
9 * Adblock Plus is distributed in the hope that it will be useful, 9 * Adblock Plus is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details. 12 * GNU General Public License for more details.
13 * 13 *
14 * You should have received a copy of the GNU General Public License 14 * You should have received a copy of the GNU General Public License
15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. 15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
16 */ 16 */
17 17
18 #include <map> 18 #include <map>
19 #include <AdblockPlus/JsValue.h> 19 #include <AdblockPlus/JsValue.h>
20 #include <AdblockPlus/WebRequest.h> 20 #include <AdblockPlus/WebRequest.h>
21 21
22 #include "JsContext.h" 22 #include "JsEngineInternal.h"
23 #include "JsEngineTransition.h"
23 #include "Utils.h" 24 #include "Utils.h"
24 #include "Scheduler.h" 25 #include "Scheduler.h"
26 #include "V8Upgrade.h"
27 #include "Value.h"
25 #include "WebRequestJsObject.h" 28 #include "WebRequestJsObject.h"
26 29
27 namespace 30 namespace
28 { 31 {
29 class WebRequestTask 32 class WebRequestTask
30 { 33 {
31 public: 34 public:
32 WebRequestTask(AdblockPlus::JsEnginePtr jsEngine, AdblockPlus::JsValueList& arguments) 35 WebRequestTask(
33 : jsEngine(jsEngine), url(arguments[0]->AsString()) 36 JsEngineInternal *engine,
34 { 37 std::string url,
35 if (!url.length()) 38 AdblockPlus::HeaderList headers,
36 throw std::runtime_error("Invalid string passed as first argument to GET "); 39 V8PersistentNG<v8::Function> callbackFunction
37 40 )
38 { 41 : jsEngine(engine->shared_from_this()),
39 AdblockPlus::JsValuePtr headersObj = arguments[1]; 42 url(url), headers(headers), callbackFunction(callbackFunction)
40 if (!headersObj->IsObject()) 43 {}
41 throw std::runtime_error("Second argument to GET must be an object");
42
43 std::vector<std::string> properties = headersObj->GetOwnPropertyNames();
44 for (std::vector<std::string>::iterator it = properties.begin();
45 it != properties.end(); ++it)
46 {
47 std::string header = *it;
48 std::string headerValue = headersObj->GetProperty(header)->AsString();
49 if (header.length() && headerValue.length())
50 headers.push_back(std::pair<std::string, std::string>(header, header Value));
51 }
52 }
53
54 callback = arguments[2];
55 if (!callback->IsFunction())
56 throw std::runtime_error("Third argument to GET must be a function");
57 }
58 44
59 void operator()() 45 void operator()()
60 { 46 {
61 AdblockPlus::ServerResponse result = jsEngine->GetWebRequest()->GET(url, h eaders); 47 auto engine = ToInternal(jsEngine); // temporary statement while task keep s its own engine alive
48 /*
49 * Synchronous HTTP GET request is arbitrary-duration and not interruptibl e
50 */
51 AdblockPlus::ServerResponse result = engine->GetWebRequest()->GET(url, hea ders);
52 /*
53 * Instantiate our scope after the long-lived operation above.
54 */
55 V8ExecutionScope sentry(engine);
56 auto isolate = engine->GetIsolate();
62 57
63 AdblockPlus::JsContext context(jsEngine); 58 // Create the response object to pass to the callback function
59 auto response = v8::Object::New();
60 SetPropertyOnV8Object(isolate, response, "status", result.status);
61 SetPropertyOnV8Object(isolate, response, "responseStatus", result.response Status);
62 SetPropertyOnV8Object(isolate, response, "responseText", result.responseTe xt);
63 auto responseHeaders = v8::Object::New();
64 for (auto it = result.responseHeaders.begin(); it != result.responseHeader s.end(); ++it)
65 {
66 SetPropertyOnV8Object(isolate, responseHeaders, it->first, it->second);
67 }
68 SetPropertyOnV8Object(isolate, response, "responseHeaders", responseHeader s);
64 69
65 AdblockPlus::JsValuePtr resultObject = jsEngine->NewObject(); 70 // Call the callback
66 resultObject->SetProperty("status", result.status); 71 auto args = AllocatedArray<v8::Local<v8::Value>>(1);
67 resultObject->SetProperty("responseStatus", result.responseStatus); 72 args[0] = response;
68 resultObject->SetProperty("responseText", result.responseText); 73 engine->ApplyFunction(callbackFunction.Get(isolate), std::move(args));
69
70 AdblockPlus::JsValuePtr headersObject = jsEngine->NewObject();
71 for (AdblockPlus::HeaderList::iterator it = result.responseHeaders.begin() ;
72 it != result.responseHeaders.end(); ++it)
73 {
74 headersObject->SetProperty(it->first, it->second);
75 }
76 resultObject->SetProperty("responseHeaders", headersObject);
77
78 AdblockPlus::JsValueList params;
79 params.push_back(resultObject);
80 callback->Call(params);
81 } 74 }
82 75
83 private: 76 private:
77 /**
78 * Engine pointer keeps engine in existence across thread boundary
79 */
84 AdblockPlus::JsEnginePtr jsEngine; 80 AdblockPlus::JsEnginePtr jsEngine;
85 std::string url; 81 std::string url;
86 AdblockPlus::HeaderList headers; 82 AdblockPlus::HeaderList headers;
87 AdblockPlus::JsValuePtr callback; 83 V8PersistentNG<v8::Function> callbackFunction;
88 }; 84 };
89
90 v8::Handle<v8::Value> GETCallback(const v8::Arguments& arguments)
91 {
92 std::shared_ptr<WebRequestTask> thread;
93 AdblockPlus::JsEnginePtr jsEngine;
94 try
95 {
96 jsEngine = AdblockPlus::JsEngine::FromArguments(arguments);
97 AdblockPlus::JsValueList converted = jsEngine->ConvertArguments(arguments) ;
98 if (converted.size() != 3u)
99 throw std::runtime_error("GET requires exactly 3 arguments");
100 thread = std::make_shared<WebRequestTask>(jsEngine, converted);
101 }
102 catch (const std::exception& e)
103 {
104 using AdblockPlus::Utils::ToV8String;
105 v8::Isolate* isolate = arguments.GetIsolate();
106 return v8::ThrowException(ToV8String(isolate, e.what()));
107 }
108 jsEngine->Schedule(AdblockPlus::MakeHeapFunction(thread), AdblockPlus::Immed iateSingleUseThread);
109 return v8::Undefined();
110 }
111 } 85 }
112 86
113 AdblockPlus::JsValuePtr AdblockPlus::WebRequestJsObject::Setup( 87 /**
114 AdblockPlus::JsEnginePtr jsEngine, AdblockPlus::JsValuePtr obj) 88 * Implementing function for JS "<global>._webrequest.GET()".
89 *
90 * Used in "compat.js" to implement "XMLHttpRequest.send()" for GET requests.
91 *
92 * \par JavaScript arguments
93 * 1. url.
94 * The URL of the resource to which the request will be sent.
95 * 2. requestHeaders.
96 * An object whose properties represent HTTP GET request headers.
97 * These properties are added to the GET request.
98 * 3. readyCallback.
99 * A function to be executed when the GET response is ready.
100 * The argument of this call is an object encoding the GET response.
101 */
102 v8::Handle<v8::Value> GETCallback(const v8::Arguments& arguments)
115 { 103 {
116 obj->SetProperty("GET", jsEngine->NewCallback(::GETCallback)); 104 auto engine = JsEngineInternal::ExtractEngine(arguments);
117 return obj; 105 V8ExecutionScope sentry(engine);
106
107 /*
108 * Factory block for WebRequest tasks.
109 */
110 std::shared_ptr<WebRequestTask> task;
111 try
112 {
113 std::string url;
114 if (arguments.Length() != 3u)
115 {
116 throw std::runtime_error("GET requires exactly 3 arguments");
117 }
118 bool b;
119 std::tie(b, url) = ConvertString(arguments[0]);
120 if (!b)
121 {
122 throw std::runtime_error("First argument to GET must be a string");
123 }
124 if (!url.length())
125 {
126 throw std::runtime_error("Invalid string passed as first argument to GET") ;
127 }
128
129 AdblockPlus::HeaderList headers;
130 auto headersArg = arguments[1];
131 if (!headersArg->IsObject())
132 {
133 throw std::runtime_error("Second argument to GET must be an object");
134 }
135 auto headersObj = v8::Local<v8::Object>::Cast(headersArg);
136 auto headersProperties = headersObj->GetOwnPropertyNames();
137 uint32_t length = headersProperties->Length();
138 for (uint32_t i = 0; i < length; i++)
139 {
140 auto v8PropertyName(headersProperties->Get(i));
141 auto v8PropertyValue(headersObj->Get(v8PropertyName));
142 auto propertyName(AdblockPlus::Utils::FromV8String(v8PropertyName));
143 auto propertyValue(AdblockPlus::Utils::FromV8String(v8PropertyValue));
144 if (propertyName.length() > 0 && propertyValue.length() > 0)
145 {
146 headers.push_back(std::make_pair(propertyName, propertyValue));
147 }
148 }
149
150 auto callbackArg = arguments[2];
151 if (!callbackArg->IsFunction())
152 {
153 throw std::runtime_error("Third argument to GET must be a function");
154 }
155 task = std::make_shared<WebRequestTask>(engine, url, headers,
156 V8PersistentNG<v8::Function>(engine->GetIsolate(), v8::Local<v8::Function> ::Cast(arguments[2])));
157 }
158 catch (const std::exception& e)
159 {
160 using AdblockPlus::Utils::ToV8String;
161 v8::Isolate* isolate = arguments.GetIsolate();
162 return v8::ThrowException(ToV8String(isolate, e.what()));
163 }
164 /*
165 * Run the task
166 */
167 engine->Schedule(AdblockPlus::MakeHeapFunction(task), AdblockPlus::ImmediateSi ngleUseThread);
168 return v8::Undefined();
118 } 169 }
OLDNEW
« no previous file with comments | « src/WebRequestJsObject.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld