OLD | NEW |
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 } |
OLD | NEW |