From df91ef5f5fcc4b8ac242b40c628c5f2c8d14114e Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Wed, 25 Jan 2017 14:22:42 -0800 Subject: [PATCH] blocking fetch of http scripts --- .../src/entities/EntityServer.cpp | 57 +++++++++++++++++-- assignment-client/src/entities/EntityServer.h | 6 +- 2 files changed, 57 insertions(+), 6 deletions(-) diff --git a/assignment-client/src/entities/EntityServer.cpp b/assignment-client/src/entities/EntityServer.cpp index 84d9b198ea..0e71d82c3a 100644 --- a/assignment-client/src/entities/EntityServer.cpp +++ b/assignment-client/src/entities/EntityServer.cpp @@ -9,9 +9,12 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include #include #include #include +#include +#include #include "EntityServer.h" #include "EntityServerConsts.h" @@ -26,6 +29,10 @@ EntityServer::EntityServer(ReceivedMessage& message) : OctreeServer(message), _entitySimulation(NULL) { + ResourceManager::init(); + DependencyManager::set(); + DependencyManager::set(); + auto& packetReceiver = DependencyManager::get()->getPacketReceiver(); packetReceiver.registerListenerForTypes({ PacketType::EntityAdd, PacketType::EntityEdit, PacketType::EntityErase }, this, "handleEntityPacket"); @@ -286,13 +293,55 @@ void EntityServer::readAdditionalConfiguration(const QJsonObject& settingsSectio tree->setEntityScriptSourceWhitelist(""); } - if (readOptionString("entityEditFilter", settingsSectionObject, _entityEditFilter)) { - // FIXME: Fetch script from file synchronously. We don't want the server processing edits while a restarting entity server is fetching from a DOS'd source. - _entityEditFilterEngine.evaluate(_entityEditFilter); - tree->initEntityEditFilterEngine(&_entityEditFilterEngine); + if (readOptionString("entityEditFilter", settingsSectionObject, _entityEditFilter) && !_entityEditFilter.isEmpty()) { + // Fetch script from file synchronously. We don't want the server processing edits while a restarting entity server is fetching from a DOS'd source. + QUrl scriptURL(_entityEditFilter); + + // The following should be abstracted out for use in Agent.cpp (and maybe later AvatarMixer.cpp) + if (scriptURL.scheme().isEmpty() || (scriptURL.scheme() == URL_SCHEME_FILE)) { + qWarning() << "Cannot load script from local filesystem, because assignment may be on a different computer."; + scriptRequestFinished(); + return; + } + auto scriptRequest = ResourceManager::createResourceRequest(this, scriptURL); + if (!scriptRequest) { + qWarning() << "Could not create ResourceRequest for Agent script at" << scriptURL.toString(); + scriptRequestFinished(); + return; + } + // Agent.cpp sets up a timeout here, but that is unnecessary, as ResourceRequest has its own. + connect(scriptRequest, &ResourceRequest::finished, this, &EntityServer::scriptRequestFinished); + // FIXME: handle atp rquests setup here. See Agent::requestScript() + qInfo() << "Requesting script at URL" << qPrintable(scriptRequest->getUrl().toString()); + scriptRequest->send(); + _scriptRequestLoop.exec(); // Block here, but allow the request to be processed and its signals to be handled. } } +void EntityServer::scriptRequestFinished() { + auto scriptRequest = qobject_cast(sender()); + if (scriptRequest && scriptRequest->getResult() == ResourceRequest::Success) { + auto scriptContents = scriptRequest->getData(); + qInfo() << "Downloaded script:" << scriptContents; + _entityEditFilterEngine.evaluate(scriptContents); + std::static_pointer_cast(_tree)->initEntityEditFilterEngine(&_entityEditFilterEngine); + scriptRequest->deleteLater(); + if (_scriptRequestLoop.isRunning()) { + _scriptRequestLoop.quit(); + } + return; + } else if (scriptRequest) { + qCritical() << "Failed to download script at" << scriptRequest->getUrl().toString(); + // See HTTPResourceRequest::onRequestFinished for interpretation of codes. For example, a 404 is code 6 and 403 is 3. A timeout is 2. Go figure. + qCritical() << "ResourceRequest error was" << scriptRequest->getResult(); + } else { + qCritical() << "Failed to create script request."; + } + // Hard stop of the assignment client on failure. We don't want anyone to think they have a filter in place when they don't. + // Alas, only indications will be the above logging with assignment client restarting repeatedly, and clients will not see any entities. + stop(); +} + void EntityServer::nodeAdded(SharedNodePointer node) { EntityTreePointer tree = std::static_pointer_cast(_tree); tree->knowAvatarID(node->getUUID()); diff --git a/assignment-client/src/entities/EntityServer.h b/assignment-client/src/entities/EntityServer.h index 469ac21dd9..25270c9dd5 100644 --- a/assignment-client/src/entities/EntityServer.h +++ b/assignment-client/src/entities/EntityServer.h @@ -69,6 +69,7 @@ protected: private slots: void handleEntityPacket(QSharedPointer message, SharedNodePointer senderNode); + void scriptRequestFinished(); private: SimpleEntitySimulationPointer _entitySimulation; @@ -77,8 +78,9 @@ private: QReadWriteLock _viewerSendingStatsLock; QMap> _viewerSendingStats; - QString _entityEditFilter; - QScriptEngine _entityEditFilterEngine; + QString _entityEditFilter{}; + QScriptEngine _entityEditFilterEngine{}; + QEventLoop _scriptRequestLoop{}; }; #endif // hifi_EntityServer_h