| 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 <sstream> | 18 #include <sstream> | 
| 19 #include "BaseJsTest.h" | 19 #include "BaseJsTest.h" | 
| 20 #include "../src/Thread.h" | 20 #include "../src/Thread.h" | 
|  | 21 #include <atomic> | 
|  | 22 #include <mutex> | 
|  | 23 | 
|  | 24 using namespace AdblockPlus; | 
| 21 | 25 | 
| 22 namespace | 26 namespace | 
| 23 { | 27 { | 
| 24   class MockWebRequest : public AdblockPlus::WebRequest | 28   class MockWebRequest : public AdblockPlus::WebRequest | 
| 25   { | 29   { | 
| 26   public: | 30   public: | 
| 27     AdblockPlus::ServerResponse GET(const std::string& url, const AdblockPlus::H
     eaderList& requestHeaders) const | 31     AdblockPlus::ServerResponse GET(const std::string& url, const AdblockPlus::H
     eaderList& requestHeaders) const | 
| 28     { | 32     { | 
| 29       AdblockPlus::Sleep(50); | 33       AdblockPlus::Sleep(50); | 
| 30 | 34 | 
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 67 { | 71 { | 
| 68   jsEngine->Evaluate("_webRequest.GET('http://example.com/', {X: 'Y'}, function(
     result) {foo = result;} )"); | 72   jsEngine->Evaluate("_webRequest.GET('http://example.com/', {X: 'Y'}, function(
     result) {foo = result;} )"); | 
| 69   ASSERT_TRUE(jsEngine->Evaluate("this.foo")->IsUndefined()); | 73   ASSERT_TRUE(jsEngine->Evaluate("this.foo")->IsUndefined()); | 
| 70   AdblockPlus::Sleep(200); | 74   AdblockPlus::Sleep(200); | 
| 71   ASSERT_EQ(AdblockPlus::WebRequest::NS_OK, jsEngine->Evaluate("foo.status")->As
     Int()); | 75   ASSERT_EQ(AdblockPlus::WebRequest::NS_OK, jsEngine->Evaluate("foo.status")->As
     Int()); | 
| 72   ASSERT_EQ(123, jsEngine->Evaluate("foo.responseStatus")->AsInt()); | 76   ASSERT_EQ(123, jsEngine->Evaluate("foo.responseStatus")->AsInt()); | 
| 73   ASSERT_EQ("http://example.com/\nX\nY", jsEngine->Evaluate("foo.responseText")-
     >AsString()); | 77   ASSERT_EQ("http://example.com/\nX\nY", jsEngine->Evaluate("foo.responseText")-
     >AsString()); | 
| 74   ASSERT_EQ("{\"Foo\":\"Bar\"}", jsEngine->Evaluate("JSON.stringify(foo.response
     Headers)")->AsString()); | 78   ASSERT_EQ("{\"Foo\":\"Bar\"}", jsEngine->Evaluate("JSON.stringify(foo.response
     Headers)")->AsString()); | 
| 75 } | 79 } | 
| 76 | 80 | 
|  | 81 TEST_F(MockWebRequestTest, ConnectionIsAllowedOnJsEngine) | 
|  | 82 { | 
|  | 83   std::atomic<int> isConnectionAllowedCalledTimes(0); | 
|  | 84   jsEngine->SetIsConnectionAllowedCallback([&isConnectionAllowedCalledTimes]()->
     bool | 
|  | 85   { | 
|  | 86     ++isConnectionAllowedCalledTimes; | 
|  | 87     return true; | 
|  | 88   }); | 
|  | 89   jsEngine->Evaluate("_webRequest.GET('http://example.com/', {X: 'Y'}, function(
     result) {foo = result;} )"); | 
|  | 90   ASSERT_TRUE(jsEngine->Evaluate("this.foo")->IsUndefined()); | 
|  | 91   AdblockPlus::Sleep(200); | 
|  | 92   EXPECT_EQ(1u, isConnectionAllowedCalledTimes); | 
|  | 93   EXPECT_EQ(AdblockPlus::WebRequest::NS_OK, jsEngine->Evaluate("foo.status")->As
     Int()); | 
|  | 94   EXPECT_EQ(123, jsEngine->Evaluate("foo.responseStatus")->AsInt()); | 
|  | 95   EXPECT_EQ("http://example.com/\nX\nY", jsEngine->Evaluate("foo.responseText")-
     >AsString()); | 
|  | 96   EXPECT_EQ("{\"Foo\":\"Bar\"}", jsEngine->Evaluate("JSON.stringify(foo.response
     Headers)")->AsString()); | 
|  | 97 } | 
|  | 98 | 
|  | 99 TEST_F(MockWebRequestTest, ConnectionIsNotAllowedOnJsEngine) | 
|  | 100 { | 
|  | 101   std::atomic<int> isConnectionAllowedCalledTimes(0); | 
|  | 102   jsEngine->SetIsConnectionAllowedCallback([&isConnectionAllowedCalledTimes]()->
     bool | 
|  | 103   { | 
|  | 104     ++isConnectionAllowedCalledTimes; | 
|  | 105     return false; | 
|  | 106   }); | 
|  | 107   jsEngine->Evaluate("_webRequest.GET('http://example.com/', {X: 'Y'}, function(
     result) {foo = result;} )"); | 
|  | 108   ASSERT_TRUE(jsEngine->Evaluate("this.foo")->IsUndefined()); | 
|  | 109   AdblockPlus::Sleep(200); | 
|  | 110   EXPECT_EQ(1u, isConnectionAllowedCalledTimes); | 
|  | 111   EXPECT_EQ(AdblockPlus::WebRequest::NS_ERROR_CONNECTION_REFUSED, jsEngine->Eval
     uate("foo.status")->AsInt()); | 
|  | 112   EXPECT_EQ(0, jsEngine->Evaluate("foo.responseStatus")->AsInt()); | 
|  | 113   EXPECT_EQ("", jsEngine->Evaluate("foo.responseText")->AsString()); | 
|  | 114   EXPECT_EQ("{}", jsEngine->Evaluate("JSON.stringify(foo.responseHeaders)")->AsS
     tring()); | 
|  | 115 } | 
|  | 116 | 
|  | 117 namespace | 
|  | 118 { | 
|  | 119   class SyncStrings | 
|  | 120   { | 
|  | 121   public: | 
|  | 122     void Add(const std::string* value) | 
|  | 123     { | 
|  | 124       std::lock_guard<std::mutex> lock(mutex); | 
|  | 125       strings.emplace_back(!!value, value ? *value : ""); | 
|  | 126     } | 
|  | 127     std::vector<std::pair<bool, std::string>> GetStrings() const | 
|  | 128     { | 
|  | 129       std::lock_guard<std::mutex> lock(mutex); | 
|  | 130       return strings; | 
|  | 131     } | 
|  | 132     void Clear() | 
|  | 133     { | 
|  | 134       std::lock_guard<std::mutex> lock(mutex); | 
|  | 135       strings.clear(); | 
|  | 136     } | 
|  | 137   private: | 
|  | 138     mutable std::mutex mutex; | 
|  | 139     std::vector<std::pair<bool, std::string>> strings; | 
|  | 140   }; | 
|  | 141 } | 
|  | 142 | 
|  | 143 TEST_F(MockWebRequestTest, ConnectionIsAllowedOnFilterEngine1) | 
|  | 144 { | 
|  | 145   FilterEngine::CreateParameters createParams; | 
|  | 146   std::string predefinedAllowedConnectionType = "non-metered"; | 
|  | 147   createParams.preconfiguredPrefs.emplace("allowed_connection_type", jsEngine->N
     ewValue(predefinedAllowedConnectionType)); | 
|  | 148   auto receivedConnectionTypes = std::make_shared<SyncStrings>(); | 
|  | 149   createParams.isConnectionAllowed = [receivedConnectionTypes](const std::string
     * allowedConnectionType)->bool { | 
|  | 150     receivedConnectionTypes->Add(allowedConnectionType); | 
|  | 151     return true; | 
|  | 152   }; | 
|  | 153   auto filterEngine = FilterEngine::Create(jsEngine, createParams); | 
|  | 154   jsEngine->Evaluate("_webRequest.GET('http://example.com/', {X: 'Y'}, function(
     result) {foo = result;} )"); | 
|  | 155   ASSERT_TRUE(jsEngine->Evaluate("this.foo")->IsUndefined()); | 
|  | 156   AdblockPlus::Sleep(200); | 
|  | 157   auto receivedConnectionTypesStrings = receivedConnectionTypes->GetStrings(); | 
|  | 158   EXPECT_FALSE(receivedConnectionTypesStrings.empty()); | 
|  | 159   for (const auto& connectionType : receivedConnectionTypesStrings) | 
|  | 160   { | 
|  | 161     EXPECT_TRUE(connectionType.first); | 
|  | 162     EXPECT_EQ(predefinedAllowedConnectionType, connectionType.second); | 
|  | 163   } | 
|  | 164   EXPECT_EQ(AdblockPlus::WebRequest::NS_OK, jsEngine->Evaluate("foo.status")->As
     Int()); | 
|  | 165   EXPECT_EQ(123, jsEngine->Evaluate("foo.responseStatus")->AsInt()); | 
|  | 166   EXPECT_EQ("http://example.com/\nX\nY", jsEngine->Evaluate("foo.responseText")-
     >AsString()); | 
|  | 167   EXPECT_EQ("{\"Foo\":\"Bar\"}", jsEngine->Evaluate("JSON.stringify(foo.response
     Headers)")->AsString()); | 
|  | 168 } | 
|  | 169 | 
|  | 170 TEST_F(MockWebRequestTest, ConnectionIsAllowedOnFilterEngine2) | 
|  | 171 { | 
|  | 172   FilterEngine::CreateParameters createParams; | 
|  | 173   auto receivedConnectionTypes = std::make_shared<SyncStrings>(); | 
|  | 174   createParams.isConnectionAllowed = [receivedConnectionTypes](const std::string
     * allowedConnectionType)->bool { | 
|  | 175     receivedConnectionTypes->Add(allowedConnectionType); | 
|  | 176     return true; | 
|  | 177   }; | 
|  | 178   auto filterEngine = FilterEngine::Create(jsEngine, createParams); | 
|  | 179   jsEngine->Evaluate("_webRequest.GET('http://example.com/', {X: 'Y'}, function(
     result) {foo = result;} )"); | 
|  | 180   ASSERT_TRUE(jsEngine->Evaluate("this.foo")->IsUndefined()); | 
|  | 181   AdblockPlus::Sleep(200); | 
|  | 182   auto receivedConnectionTypesStrings = receivedConnectionTypes->GetStrings(); | 
|  | 183   EXPECT_FALSE(receivedConnectionTypesStrings.empty()); | 
|  | 184   for (const auto& connectionType : receivedConnectionTypesStrings) | 
|  | 185   { | 
|  | 186     EXPECT_FALSE(connectionType.first); | 
|  | 187   } | 
|  | 188   EXPECT_EQ(AdblockPlus::WebRequest::NS_OK, jsEngine->Evaluate("foo.status")->As
     Int()); | 
|  | 189   EXPECT_EQ(123, jsEngine->Evaluate("foo.responseStatus")->AsInt()); | 
|  | 190   EXPECT_EQ("http://example.com/\nX\nY", jsEngine->Evaluate("foo.responseText")-
     >AsString()); | 
|  | 191   EXPECT_EQ("{\"Foo\":\"Bar\"}", jsEngine->Evaluate("JSON.stringify(foo.response
     Headers)")->AsString()); | 
|  | 192 } | 
|  | 193 | 
|  | 194 TEST_F(MockWebRequestTest, ConnectionIsAllowedOnFilterEngine3) | 
|  | 195 { | 
|  | 196   // initially allowed connection type is not defined | 
|  | 197   FilterEngine::CreateParameters createParams; | 
|  | 198   auto receivedConnectionTypes = std::make_shared<SyncStrings>(); | 
|  | 199   createParams.isConnectionAllowed = [receivedConnectionTypes](const std::string
     * allowedConnectionType)->bool { | 
|  | 200     receivedConnectionTypes->Add(allowedConnectionType); | 
|  | 201     return true; | 
|  | 202   }; | 
|  | 203   auto filterEngine = FilterEngine::Create(jsEngine, createParams); | 
|  | 204 | 
|  | 205   jsEngine->Evaluate("_webRequest.GET('http://example.com/', {X: 'Y'}, function(
     result) {foo = result;} )"); | 
|  | 206   ASSERT_TRUE(jsEngine->Evaluate("this.foo")->IsUndefined()); | 
|  | 207   AdblockPlus::Sleep(200); | 
|  | 208   auto receivedConnectionTypesStrings = receivedConnectionTypes->GetStrings(); | 
|  | 209   EXPECT_FALSE(receivedConnectionTypesStrings.empty()); | 
|  | 210   for (const auto& connectionType : receivedConnectionTypesStrings) | 
|  | 211   { | 
|  | 212     EXPECT_FALSE(connectionType.first); | 
|  | 213   } | 
|  | 214   EXPECT_EQ(AdblockPlus::WebRequest::NS_OK, jsEngine->Evaluate("foo.status")->As
     Int()); | 
|  | 215   EXPECT_EQ(123, jsEngine->Evaluate("foo.responseStatus")->AsInt()); | 
|  | 216   EXPECT_EQ("http://example.com/\nX\nY", jsEngine->Evaluate("foo.responseText")-
     >AsString()); | 
|  | 217   EXPECT_EQ("{\"Foo\":\"Bar\"}", jsEngine->Evaluate("JSON.stringify(foo.response
     Headers)")->AsString()); | 
|  | 218 | 
|  | 219   // set allowed connection type | 
|  | 220   std::string allowedConnectionType = "test-connection"; | 
|  | 221   filterEngine->SetAllowedConnectionType(&allowedConnectionType); | 
|  | 222   receivedConnectionTypes->Clear(); | 
|  | 223   jsEngine->Evaluate("_webRequest.GET('http://example.com/', {X: 'Y'}, function(
     result) {foo = result;} )"); | 
|  | 224   AdblockPlus::Sleep(200); | 
|  | 225   receivedConnectionTypesStrings = receivedConnectionTypes->GetStrings(); | 
|  | 226   EXPECT_FALSE(receivedConnectionTypesStrings.empty()); | 
|  | 227   for (const auto& connectionType : receivedConnectionTypesStrings) | 
|  | 228   { | 
|  | 229     EXPECT_TRUE(connectionType.first); | 
|  | 230     EXPECT_EQ(allowedConnectionType, connectionType.second); | 
|  | 231   } | 
|  | 232 | 
|  | 233   // remove allowed connection type | 
|  | 234   filterEngine->SetAllowedConnectionType(nullptr); | 
|  | 235   receivedConnectionTypes->Clear(); | 
|  | 236   jsEngine->Evaluate("_webRequest.GET('http://example.com/', {X: 'Y'}, function(
     result) {foo = result;} )"); | 
|  | 237   AdblockPlus::Sleep(200); | 
|  | 238   receivedConnectionTypesStrings = receivedConnectionTypes->GetStrings(); | 
|  | 239   EXPECT_FALSE(receivedConnectionTypesStrings.empty()); | 
|  | 240   for (const auto& connectionType : receivedConnectionTypesStrings) | 
|  | 241   { | 
|  | 242     EXPECT_FALSE(connectionType.first); | 
|  | 243   } | 
|  | 244 } | 
|  | 245 | 
|  | 246 TEST_F(MockWebRequestTest, ConnectionIsNotAllowedOnFilterEngine) | 
|  | 247 { | 
|  | 248   FilterEngine::CreateParameters createParams; | 
|  | 249   std::string predefinedAllowedConnectionType = "non-metered"; | 
|  | 250   createParams.preconfiguredPrefs.emplace("allowed_connection_type", jsEngine->N
     ewValue(predefinedAllowedConnectionType)); | 
|  | 251   auto receivedConnectionTypes = std::make_shared<SyncStrings>(); | 
|  | 252   createParams.isConnectionAllowed = [receivedConnectionTypes](const std::string
     * allowedConnectionType)->bool { | 
|  | 253     receivedConnectionTypes->Add(allowedConnectionType); | 
|  | 254     return false; | 
|  | 255   }; | 
|  | 256   auto filterEngine = FilterEngine::Create(jsEngine, createParams); | 
|  | 257   jsEngine->Evaluate("_webRequest.GET('http://example.com/', {X: 'Y'}, function(
     result) {foo = result;} )"); | 
|  | 258   ASSERT_TRUE(jsEngine->Evaluate("this.foo")->IsUndefined()); | 
|  | 259   AdblockPlus::Sleep(200); | 
|  | 260   auto receivedConnectionTypesStrings = receivedConnectionTypes->GetStrings(); | 
|  | 261   EXPECT_FALSE(receivedConnectionTypesStrings.empty()); | 
|  | 262   for (const auto& connectionType : receivedConnectionTypesStrings) | 
|  | 263   { | 
|  | 264     EXPECT_TRUE(connectionType.first); | 
|  | 265     EXPECT_EQ(predefinedAllowedConnectionType, connectionType.second); | 
|  | 266   } | 
|  | 267   EXPECT_EQ(AdblockPlus::WebRequest::NS_ERROR_CONNECTION_REFUSED, jsEngine->Eval
     uate("foo.status")->AsInt()); | 
|  | 268   EXPECT_EQ(0, jsEngine->Evaluate("foo.responseStatus")->AsInt()); | 
|  | 269   EXPECT_EQ("", jsEngine->Evaluate("foo.responseText")->AsString()); | 
|  | 270   EXPECT_EQ("{}", jsEngine->Evaluate("JSON.stringify(foo.responseHeaders)")->AsS
     tring()); | 
|  | 271 } | 
|  | 272 | 
| 77 #if defined(HAVE_CURL) || defined(_WIN32) | 273 #if defined(HAVE_CURL) || defined(_WIN32) | 
| 78 TEST_F(DefaultWebRequestTest, RealWebRequest) | 274 TEST_F(DefaultWebRequestTest, RealWebRequest) | 
| 79 { | 275 { | 
| 80   // This URL should redirect to easylist-downloads.adblockplus.org and we | 276   // This URL should redirect to easylist-downloads.adblockplus.org and we | 
| 81   // should get the actual filter list back. | 277   // should get the actual filter list back. | 
| 82   jsEngine->Evaluate("_webRequest.GET('https://easylist-downloads.adblockplus.or
     g/easylist.txt', {}, function(result) {foo = result;} )"); | 278   jsEngine->Evaluate("_webRequest.GET('https://easylist-downloads.adblockplus.or
     g/easylist.txt', {}, function(result) {foo = result;} )"); | 
| 83   do | 279   do | 
| 84   { | 280   { | 
| 85     AdblockPlus::Sleep(200); | 281     AdblockPlus::Sleep(200); | 
| 86   } while (jsEngine->Evaluate("this.foo")->IsUndefined()); | 282   } while (jsEngine->Evaluate("this.foo")->IsUndefined()); | 
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 125     AdblockPlus::Sleep(200); | 321     AdblockPlus::Sleep(200); | 
| 126   } while (jsEngine->Evaluate("this.foo")->IsUndefined()); | 322   } while (jsEngine->Evaluate("this.foo")->IsUndefined()); | 
| 127   ASSERT_EQ(AdblockPlus::WebRequest::NS_ERROR_FAILURE, jsEngine->Evaluate("foo.s
     tatus")->AsInt()); | 323   ASSERT_EQ(AdblockPlus::WebRequest::NS_ERROR_FAILURE, jsEngine->Evaluate("foo.s
     tatus")->AsInt()); | 
| 128   ASSERT_EQ(0, jsEngine->Evaluate("foo.responseStatus")->AsInt()); | 324   ASSERT_EQ(0, jsEngine->Evaluate("foo.responseStatus")->AsInt()); | 
| 129   ASSERT_EQ("", jsEngine->Evaluate("foo.responseText")->AsString()); | 325   ASSERT_EQ("", jsEngine->Evaluate("foo.responseText")->AsString()); | 
| 130   ASSERT_EQ("{}", jsEngine->Evaluate("JSON.stringify(foo.responseHeaders)")->AsS
     tring()); | 326   ASSERT_EQ("{}", jsEngine->Evaluate("JSON.stringify(foo.responseHeaders)")->AsS
     tring()); | 
| 131 } | 327 } | 
| 132 | 328 | 
| 133 TEST_F(DefaultWebRequestTest, XMLHttpRequest) | 329 TEST_F(DefaultWebRequestTest, XMLHttpRequest) | 
| 134 { | 330 { | 
| 135   AdblockPlus::FilterEngine filterEngine(jsEngine); | 331   auto filterEngine = AdblockPlus::FilterEngine::Create(jsEngine); | 
| 136 | 332 | 
| 137   jsEngine->Evaluate("\ | 333   jsEngine->Evaluate("\ | 
| 138     var result;\ | 334     var result;\ | 
| 139     var request = new XMLHttpRequest();\ | 335     var request = new XMLHttpRequest();\ | 
| 140     request.open('GET', 'https://easylist-downloads.adblockplus.org/easylist.txt
     ');\ | 336     request.open('GET', 'https://easylist-downloads.adblockplus.org/easylist.txt
     ');\ | 
| 141     request.setRequestHeader('X', 'Y');\ | 337     request.setRequestHeader('X', 'Y');\ | 
| 142     request.overrideMimeType('text/plain');\ | 338     request.overrideMimeType('text/plain');\ | 
| 143     request.addEventListener('load', function() {result = request.responseText;}
     , false);\ | 339     request.addEventListener('load', function() {result = request.responseText;}
     , false);\ | 
| 144     request.addEventListener('error', function() {result = 'error';}, false);\ | 340     request.addEventListener('error', function() {result = 'error';}, false);\ | 
| 145     request.send(null);"); | 341     request.send(null);"); | 
| 146   do | 342   do | 
| 147   { | 343   { | 
| 148     AdblockPlus::Sleep(200); | 344     AdblockPlus::Sleep(200); | 
| 149   } while (jsEngine->Evaluate("result")->IsUndefined()); | 345   } while (jsEngine->Evaluate("result")->IsUndefined()); | 
| 150   ASSERT_EQ(AdblockPlus::WebRequest::NS_ERROR_FAILURE, jsEngine->Evaluate("reque
     st.channel.status")->AsInt()); | 346   ASSERT_EQ(AdblockPlus::WebRequest::NS_ERROR_FAILURE, jsEngine->Evaluate("reque
     st.channel.status")->AsInt()); | 
| 151   ASSERT_EQ(0, jsEngine->Evaluate("request.status")->AsInt()); | 347   ASSERT_EQ(0, jsEngine->Evaluate("request.status")->AsInt()); | 
| 152   ASSERT_EQ("error", jsEngine->Evaluate("result")->AsString()); | 348   ASSERT_EQ("error", jsEngine->Evaluate("result")->AsString()); | 
| 153   ASSERT_TRUE(jsEngine->Evaluate("request.getResponseHeader('Content-Type')")->I
     sNull()); | 349   ASSERT_TRUE(jsEngine->Evaluate("request.getResponseHeader('Content-Type')")->I
     sNull()); | 
| 154 } | 350 } | 
| 155 | 351 | 
| 156 #endif | 352 #endif | 
| OLD | NEW | 
|---|