diff --git a/isis/src/base/apps/spiceit/QtWebApp/Doxyfile b/isis/src/base/apps/spiceit/QtWebApp/Doxyfile deleted file mode 100644 index 659ce81cefe6446ce9a106410e8fdfe2818ce965..0000000000000000000000000000000000000000 --- a/isis/src/base/apps/spiceit/QtWebApp/Doxyfile +++ /dev/null @@ -1,10 +0,0 @@ -PROJECT_NAME = QtWebApp -OUTPUT_DIRECTORY = doc -JAVADOC_AUTOBRIEF = YES -QUIET = YES -INPUT = templateengine logging httpserver qtservice mainpage.dox -INPUT_ENCODING = UTF-8 -RECURSIVE = YES -SOURCE_BROWSER = YES -GENERATE_TREEVIEW = YES -GENERATE_LATEX = NO diff --git a/isis/src/base/apps/spiceit/QtWebApp/QtWebApp.pro b/isis/src/base/apps/spiceit/QtWebApp/QtWebApp.pro deleted file mode 100644 index 6295af29cdfacffe57840504972725ff59522907..0000000000000000000000000000000000000000 --- a/isis/src/base/apps/spiceit/QtWebApp/QtWebApp.pro +++ /dev/null @@ -1,33 +0,0 @@ -# Build this project to generate a shared library (*.dll or *.so). - -TARGET = QtWebApp -TEMPLATE = lib -QT -= gui -VERSION = 1.7.3 - -mac { - QMAKE_MAC_SDK = macosx10.10 - QMAKE_CXXFLAGS += -std=c++11 - CONFIG += c++11 - QMAKE_LFLAGS_SONAME = -Wl,-install_name,/usr/local/lib/ -} - -win32 { - DEFINES += QTWEBAPPLIB_EXPORT -} - -# Windows and Unix get the suffix "d" to indicate a debug version of the library. -# Mac OS gets the suffix "_debug". -CONFIG(debug, debug|release) { - win32: TARGET = $$join(TARGET,,,d) - mac: TARGET = $$join(TARGET,,,_debug) - unix:!mac: TARGET = $$join(TARGET,,,d) -} - -DISTFILES += doc/* mainpage.dox Doxyfile -OTHER_FILES += ../readme.txt - -include(qtservice/qtservice.pri) -include(logging/logging.pri) -include(httpserver/httpserver.pri) -include(templateengine/templateengine.pri) diff --git a/isis/src/base/apps/spiceit/QtWebApp/doc/copyright.txt b/isis/src/base/apps/spiceit/QtWebApp/doc/copyright.txt deleted file mode 100644 index 56cab71ccba47df3f6ed048e3732f0f1491940f1..0000000000000000000000000000000000000000 --- a/isis/src/base/apps/spiceit/QtWebApp/doc/copyright.txt +++ /dev/null @@ -1,11 +0,0 @@ -This program and its source is distributed under the Lesser General Public License version 3. -http://www.gnu.org/licenses/lgpl.html - -When you modify the library, you have to publish your modified version for free under LGPL license. - -Author and Copyright owner: Stefan Frings -stefan@stefanfrings.de -http://www.stefanfrings.de - -The qtservice module had been originally published by Trolltech under the LGPL license as well, -but is now re-published by Digia under the less restrictive BSD License. diff --git a/isis/src/base/apps/spiceit/QtWebApp/doc/lgpl-3.0.txt b/isis/src/base/apps/spiceit/QtWebApp/doc/lgpl-3.0.txt deleted file mode 100644 index 65c5ca88a67c30becee01c5a8816d964b03862f9..0000000000000000000000000000000000000000 --- a/isis/src/base/apps/spiceit/QtWebApp/doc/lgpl-3.0.txt +++ /dev/null @@ -1,165 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - - This version of the GNU Lesser General Public License incorporates -the terms and conditions of version 3 of the GNU General Public -License, supplemented by the additional permissions listed below. - - 0. Additional Definitions. - - As used herein, "this License" refers to version 3 of the GNU Lesser -General Public License, and the "GNU GPL" refers to version 3 of the GNU -General Public License. - - "The Library" refers to a covered work governed by this License, -other than an Application or a Combined Work as defined below. - - An "Application" is any work that makes use of an interface provided -by the Library, but which is not otherwise based on the Library. -Defining a subclass of a class defined by the Library is deemed a mode -of using an interface provided by the Library. - - A "Combined Work" is a work produced by combining or linking an -Application with the Library. The particular version of the Library -with which the Combined Work was made is also called the "Linked -Version". - - The "Minimal Corresponding Source" for a Combined Work means the -Corresponding Source for the Combined Work, excluding any source code -for portions of the Combined Work that, considered in isolation, are -based on the Application, and not on the Linked Version. - - The "Corresponding Application Code" for a Combined Work means the -object code and/or source code for the Application, including any data -and utility programs needed for reproducing the Combined Work from the -Application, but excluding the System Libraries of the Combined Work. - - 1. Exception to Section 3 of the GNU GPL. - - You may convey a covered work under sections 3 and 4 of this License -without being bound by section 3 of the GNU GPL. - - 2. Conveying Modified Versions. - - If you modify a copy of the Library, and, in your modifications, a -facility refers to a function or data to be supplied by an Application -that uses the facility (other than as an argument passed when the -facility is invoked), then you may convey a copy of the modified -version: - - a) under this License, provided that you make a good faith effort to - ensure that, in the event an Application does not supply the - function or data, the facility still operates, and performs - whatever part of its purpose remains meaningful, or - - b) under the GNU GPL, with none of the additional permissions of - this License applicable to that copy. - - 3. Object Code Incorporating Material from Library Header Files. - - The object code form of an Application may incorporate material from -a header file that is part of the Library. You may convey such object -code under terms of your choice, provided that, if the incorporated -material is not limited to numerical parameters, data structure -layouts and accessors, or small macros, inline functions and templates -(ten or fewer lines in length), you do both of the following: - - a) Give prominent notice with each copy of the object code that the - Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the object code with a copy of the GNU GPL and this license - document. - - 4. Combined Works. - - You may convey a Combined Work under terms of your choice that, -taken together, effectively do not restrict modification of the -portions of the Library contained in the Combined Work and reverse -engineering for debugging such modifications, if you also do each of -the following: - - a) Give prominent notice with each copy of the Combined Work that - the Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the Combined Work with a copy of the GNU GPL and this license - document. - - c) For a Combined Work that displays copyright notices during - execution, include the copyright notice for the Library among - these notices, as well as a reference directing the user to the - copies of the GNU GPL and this license document. - - d) Do one of the following: - - 0) Convey the Minimal Corresponding Source under the terms of this - License, and the Corresponding Application Code in a form - suitable for, and under terms that permit, the user to - recombine or relink the Application with a modified version of - the Linked Version to produce a modified Combined Work, in the - manner specified by section 6 of the GNU GPL for conveying - Corresponding Source. - - 1) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (a) uses at run time - a copy of the Library already present on the user's computer - system, and (b) will operate properly with a modified version - of the Library that is interface-compatible with the Linked - Version. - - e) Provide Installation Information, but only if you would otherwise - be required to provide such information under section 6 of the - GNU GPL, and only to the extent that such information is - necessary to install and execute a modified version of the - Combined Work produced by recombining or relinking the - Application with a modified version of the Linked Version. (If - you use option 4d0, the Installation Information must accompany - the Minimal Corresponding Source and Corresponding Application - Code. If you use option 4d1, you must provide the Installation - Information in the manner specified by section 6 of the GNU GPL - for conveying Corresponding Source.) - - 5. Combined Libraries. - - You may place library facilities that are a work based on the -Library side by side in a single library together with other library -facilities that are not Applications and are not covered by this -License, and convey such a combined library under terms of your -choice, if you do both of the following: - - a) Accompany the combined library with a copy of the same work based - on the Library, uncombined with any other library facilities, - conveyed under the terms of this License. - - b) Give prominent notice with the combined library that part of it - is a work based on the Library, and explaining where to find the - accompanying uncombined form of the same work. - - 6. Revised Versions of the GNU Lesser General Public License. - - The Free Software Foundation may publish revised and/or new versions -of the GNU Lesser General Public License from time to time. Such new -versions will be similar in spirit to the present version, but may -differ in detail to address new problems or concerns. - - Each version is given a distinguishing version number. If the -Library as you received it specifies that a certain numbered version -of the GNU Lesser General Public License "or any later version" -applies to it, you have the option of following the terms and -conditions either of that published version or of any later version -published by the Free Software Foundation. If the Library as you -received it does not specify a version number of the GNU Lesser -General Public License, you may choose any version of the GNU Lesser -General Public License ever published by the Free Software Foundation. - - If the Library as you received it specifies that a proxy can decide -whether future versions of the GNU Lesser General Public License shall -apply, that proxy's public statement of acceptance of any version is -permanent authorization for you to choose that version for the -Library. diff --git a/isis/src/base/apps/spiceit/QtWebApp/doc/releasenotes.txt b/isis/src/base/apps/spiceit/QtWebApp/doc/releasenotes.txt deleted file mode 100644 index 43e1da05d4db55d2b4e8e49b8530ef7898bd032b..0000000000000000000000000000000000000000 --- a/isis/src/base/apps/spiceit/QtWebApp/doc/releasenotes.txt +++ /dev/null @@ -1,250 +0,0 @@ -Dont forget to update the release number also in -QtWebApp.pro and httpserver/httpglobal.cpp. - -1.7.3 -25.04.2017 -Wait until all data are sent before closing connections. - -1.7.2 -17.01.2017 -Fixed compile error with MSVC. - -1.7.1 -10.11.2016 -Fixed a possible memory leak in case of broken Multipart HTTP Requests. - -1.7.0 -08.11.2016 -Introduced namespace "stefanfrings". -Improved performance a little. - -1.6.7 -10.10.2016 -Fix type of socketDescriptor in qtservice library. -Add support for INFO log messages (new since QT 5.5). -Improve indentation of log messages. - -1.6.6 -25.07.2016 -Removed useless mutex from TemplateLoader. -Add mutex to TemplateCache (which is now needed). - -1.6.5 -10.06.2016 -Incoming HTTP request headers are now processed case-insensitive. -Add support for the HttpOnly flag of cookies. - -1.6.4 -27.03.2016 -Fixed constructor of Template class did not load the source file properly. -Template loader and cache were not affected. - -1.6.3 -11.03.2016 -Fixed compilation error. -Added missing implementation of HttpRequest::getPeerAddress(). - -1.6.2 -06.03.2016 -Added mime types for some file extensions. - -1.6.1 -25.01.2016 -Fixed parser of boundary value in multi-part request, which caused that -QHttpMultipart did not work on client side. - -1.6.0 -29.12.2015 -Much better output buffering, reduces the number of small IP packages. - -1.5.13 -29.12.2015 -Improved performance a little. -Add support for old HTTP 1.0 clients. -Add HttpResposne::flush() and HttpResponse::isConnected() which are helpful to support -SSE from HTML 5 specification. - -1.5.12 -11.12.2015 -Fix program crash when using SSL with a variable sized thread pool on Windows. -Changed name of HttpSessionStore::timerEvent() to fix compiler warnings since Qt 5.0. -Add HttpRequest::getRawPath(). -HttpSessionStore::sessions is now protected. - -1.5.11 -21.11.2015 -Fix project file for Mac OS. -Add HttpRequest::getPeerAddress() and HttpResponse::getStatusCode(). - -1.5.10 -01.09.2015 -Modified StaticFileController to support ressource files (path starting with ":/" or "qrc://"). - -1.5.9 -06.08.2015 -New HttpListener::listen() method, to restart listening after close. -Add missing include for QObject in logger.h. -Add a call to flush() before closing connections, which solves an issue with nginx. - -1.5.8 -26.07.2015 -Fixed segmentation fault error when closing the application while a HTTP request is in progress. -New HttpListener::close() method to simplifly proper shutdown. - -1.5.7 -20.07.2015 -Fix Qt 5.5 compatibility issue. - -1.5.6 -22.06.2015 -Fixed compilation failes if QT does not support SSL. - -1.5.5 -16.06.2015 -Improved performance of SSL connections. - -1.5.4 -15.06.2015 -Support for Qt versions without OpenSsl. - -1.5.3 -22.05.2015 -Fixed Windows issue: QsslSocket cannot be closed from other threads than it was created in. - -1.5.2 -12.05.2015 -Fixed Windows issue: QSslSocket cannot send signals to another thread than it was created in. - -1.5.1 -14.04.2015 -Add support for pipelining. - -1.5.0 -03.04.2015 -Add support for HTTPS. - -1.4.2 -03.04.2015 -Fixed HTTP request did not work if it was split into multipe IP packages. - -1.4.1 -20.03.2015 -Fixed session cookie expires while the user is active, expiration time was not prolonged on each request. - -1.4.0 -14.03.2015 -This release has a new directory structure and new project files to support the creation of a shared library (*.dll or *.so). - -1.3.8 -12.03.2015 -Improved shutdown procedure. -New config setting "host" which binds the listener to a specific network interface. - -1.3.7 -14.01.2015 -Fixed setting maxMultiPartSize worked only with file-uploads but not with form-data. - -1.3.6 -16.09.2014 -Fixed DualFileLogger produces no output. - -1.3.5 -11.06.2014 -Fixed a multi-threading issue with race condition in StaticFileController. - -1.3.4 -04.06.2014 -Fixed wrong content type when the StaticFileController returns a cached index.html. - -1.3.3 -17.03.2014 -Improved security of StaticFileController by denying "/.." in any position of the request path. -Improved performance of StaticFileController a little. -New convenience method HttpResponse::redirect(url). -Fixed a missing return statement in StaticFileController. - -1.3.2 -08.01.2014 -Fixed HTTP Server ignoring URL parameters when the request contains POST parameters. - -1.3.1 -15.08.2013 -Fixed HTTP server not accepting connections on 64bit OS with QT 5. - -1.3.0 -20.04.2013 -Updated for compatibility QT 5. You may still use QT 4.7 or 4.8, if you like. -Also added support for logging source file name, line number and function name. - -1.2.13 -03.03.2013 -Fixed Logger writing wrong timestamp for buffered messages. -Improved shutdown procedure. The webserver now processes all final signals before the destructor finishes. - -1.2.12 -01.03.2013 -Fixed HttpResponse sending first part of data repeatedly when the amount of data is larger than the available memory for I/O buffer. - -1.2.11 -06.01.2013 -Added clearing the write buffer when accepting a new connection, so that it does not send remaining data from an aborted previous connection (which is possibly a bug in QT). - -1.2.10 -18.12.2012 -Reduced memory usage of HttpResponse in case of large response. - -1.2.9 -29.07.2012 -Added a mutex to HttpConnectionHandlerPool to fix a concurrency issue when a pooled object gets taken from the cache while it times out. -Modified HttpConnectionHandler so that it does not throw an exception anymore when a connection gets closed by the peer in the middle of a read. - -1.2.8 -22.07.2012 -Fixed a possible concurrency issue when the file cache is so small that it stores less files than the number of threads. - -1.2.7 -18.07.2012 -Fixed HttpRequest ignores additional URL parameters of POST requests. -Fixed HttpRequest ignores POST parameters of body if there is no Content-Type header. -Removed unused tempdir variable from HttpRequest. -Added mutex to cache of StaticFileController to prevent concurrency problems. -Removed HTTP response with status 408 after read timeout. Connection gets simply closed now. - -1.2.6 -29.06.2012 -Fixed a compilation error on 64 bit if super verbose debugging is enabled. -Fixed a typo in static file controller related to the document type header. - -1.2.5 -27.06.2012 -Fixed error message "QThread: Destroyed while thread is still running" during program termination. - -1.2.4 -02.06.2012 -Fixed template engine skipping variable tokens when a value is shorter than the token. - -1.2.3 -26.12.2011 -Fixed null pointer error when the HTTP server aborts a request that is too large. - -1.2.2 -06.11.2011 -Fixed compilation error on 64 bit platforms. - -1.2.1 -22.10.2011 -Fixed a multi-threading bug in HttpConnectionHandler. - -1.2.0 -05.12.2010 -Added a controller that serves static files, with cacheing. - - -1.1.0 -19.10.2010 -Added support for sessions. -Separated the base classes into individual libraries. - -1.0.0 -17.10.2010 -First release diff --git a/isis/src/base/apps/spiceit/QtWebApp/httpserver/httpconnectionhandler.cpp b/isis/src/base/apps/spiceit/QtWebApp/httpserver/httpconnectionhandler.cpp deleted file mode 100644 index aa60ea0ef56ae5002f669a25334261d5d97a1a69..0000000000000000000000000000000000000000 --- a/isis/src/base/apps/spiceit/QtWebApp/httpserver/httpconnectionhandler.cpp +++ /dev/null @@ -1,277 +0,0 @@ -/** - @file - @author Stefan Frings -*/ - -#include "httpconnectionhandler.h" -#include "httpresponse.h" - -using namespace stefanfrings; - -HttpConnectionHandler::HttpConnectionHandler(QSettings* settings, HttpRequestHandler* requestHandler, QSslConfiguration* sslConfiguration) - : QThread() -{ - Q_ASSERT(settings!=0); - Q_ASSERT(requestHandler!=0); - this->settings=settings; - this->requestHandler=requestHandler; - this->sslConfiguration=sslConfiguration; - currentRequest=0; - busy=false; - - // Create TCP or SSL socket - createSocket(); - - // execute signals in my own thread - moveToThread(this); - socket->moveToThread(this); - readTimer.moveToThread(this); - - // Connect signals - connect(socket, SIGNAL(readyRead()), SLOT(read())); - connect(socket, SIGNAL(disconnected()), SLOT(disconnected())); - connect(&readTimer, SIGNAL(timeout()), SLOT(readTimeout())); - readTimer.setSingleShot(true); - - qDebug("HttpConnectionHandler (%p): constructed", this); - this->start(); -} - - -HttpConnectionHandler::~HttpConnectionHandler() -{ - quit(); - wait(); - qDebug("HttpConnectionHandler (%p): destroyed", this); -} - - -void HttpConnectionHandler::createSocket() -{ - // If SSL is supported and configured, then create an instance of QSslSocket - #ifndef QT_NO_OPENSSL - if (sslConfiguration) - { - QSslSocket* sslSocket=new QSslSocket(); - sslSocket->setSslConfiguration(*sslConfiguration); - socket=sslSocket; - qDebug("HttpConnectionHandler (%p): SSL is enabled", this); - return; - } - #endif - // else create an instance of QTcpSocket - socket=new QTcpSocket(); -} - - -void HttpConnectionHandler::run() -{ - qDebug("HttpConnectionHandler (%p): thread started", this); - try - { - exec(); - } - catch (...) - { - qCritical("HttpConnectionHandler (%p): an uncatched exception occured in the thread",this); - } - socket->close(); - delete socket; - readTimer.stop(); - qDebug("HttpConnectionHandler (%p): thread stopped", this); -} - - -void HttpConnectionHandler::handleConnection(tSocketDescriptor socketDescriptor) -{ - qDebug("HttpConnectionHandler (%p): handle new connection", this); - busy = true; - Q_ASSERT(socket->isOpen()==false); // if not, then the handler is already busy - - //UGLY workaround - we need to clear writebuffer before reusing this socket - //https://bugreports.qt-project.org/browse/QTBUG-28914 - socket->connectToHost("",0); - socket->abort(); - - if (!socket->setSocketDescriptor(socketDescriptor)) - { - qCritical("HttpConnectionHandler (%p): cannot initialize socket: %s", this,qPrintable(socket->errorString())); - return; - } - - #ifndef QT_NO_OPENSSL - // Switch on encryption, if SSL is configured - if (sslConfiguration) - { - qDebug("HttpConnectionHandler (%p): Starting encryption", this); - ((QSslSocket*)socket)->startServerEncryption(); - } - #endif - - // Start timer for read timeout - int readTimeout=settings->value("readTimeout",10000).toInt(); - readTimer.start(readTimeout); - // delete previous request - delete currentRequest; - currentRequest=0; -} - - -bool HttpConnectionHandler::isBusy() -{ - return busy; -} - -void HttpConnectionHandler::setBusy() -{ - this->busy = true; -} - - -void HttpConnectionHandler::readTimeout() -{ - qDebug("HttpConnectionHandler (%p): read timeout occured",this); - - //Commented out because QWebView cannot handle this. - //socket->write("HTTP/1.1 408 request timeout\r\nConnection: close\r\n\r\n408 request timeout\r\n"); - - while(socket->bytesToWrite()) socket->waitForBytesWritten(); - socket->disconnectFromHost(); - delete currentRequest; - currentRequest=0; -} - - -void HttpConnectionHandler::disconnected() -{ - qDebug("HttpConnectionHandler (%p): disconnected", this); - socket->close(); - readTimer.stop(); - busy = false; -} - -void HttpConnectionHandler::read() -{ - // The loop adds support for HTTP pipelinig - while (socket->bytesAvailable()) - { - #ifdef SUPERVERBOSE - qDebug("HttpConnectionHandler (%p): read input",this); - #endif - - // Create new HttpRequest object if necessary - if (!currentRequest) - { - currentRequest=new HttpRequest(settings); - } - - // Collect data for the request object - while (socket->bytesAvailable() && currentRequest->getStatus()!=HttpRequest::complete && currentRequest->getStatus()!=HttpRequest::abort) - { - currentRequest->readFromSocket(socket); - if (currentRequest->getStatus()==HttpRequest::waitForBody) - { - // Restart timer for read timeout, otherwise it would - // expire during large file uploads. - int readTimeout=settings->value("readTimeout",10000).toInt(); - readTimer.start(readTimeout); - } - } - - // If the request is aborted, return error message and close the connection - if (currentRequest->getStatus()==HttpRequest::abort) - { - socket->write("HTTP/1.1 413 entity too large\r\nConnection: close\r\n\r\n413 Entity too large\r\n"); - while(socket->bytesToWrite()) socket->waitForBytesWritten(); - socket->disconnectFromHost(); - delete currentRequest; - currentRequest=0; - return; - } - - // If the request is complete, let the request mapper dispatch it - if (currentRequest->getStatus()==HttpRequest::complete) - { - readTimer.stop(); - qDebug("HttpConnectionHandler (%p): received request",this); - - // Copy the Connection:close header to the response - HttpResponse response(socket); - bool closeConnection=QString::compare(currentRequest->getHeader("Connection"),"close",Qt::CaseInsensitive)==0; - if (closeConnection) - { - response.setHeader("Connection","close"); - } - - // In case of HTTP 1.0 protocol add the Connection:close header. - // This ensures that the HttpResponse does not activate chunked mode, which is not spported by HTTP 1.0. - else - { - bool http1_0=QString::compare(currentRequest->getVersion(),"HTTP/1.0",Qt::CaseInsensitive)==0; - if (http1_0) - { - closeConnection=true; - response.setHeader("Connection","close"); - } - } - - // Call the request mapper - try - { - requestHandler->service(*currentRequest, response); - } - catch (...) - { - qCritical("HttpConnectionHandler (%p): An uncatched exception occured in the request handler",this); - } - - // Finalize sending the response if not already done - if (!response.hasSentLastPart()) - { - response.write(QByteArray(),true); - } - - qDebug("HttpConnectionHandler (%p): finished request",this); - - // Find out whether the connection must be closed - if (!closeConnection) - { - // Maybe the request handler or mapper added a Connection:close header in the meantime - bool closeResponse=QString::compare(response.getHeaders().value("Connection"),"close",Qt::CaseInsensitive)==0; - if (closeResponse==true) - { - closeConnection=true; - } - else - { - // If we have no Content-Length header and did not use chunked mode, then we have to close the - // connection to tell the HTTP client that the end of the response has been reached. - bool hasContentLength=response.getHeaders().contains("Content-Length"); - if (!hasContentLength) - { - bool hasChunkedMode=QString::compare(response.getHeaders().value("Transfer-Encoding"),"chunked",Qt::CaseInsensitive)==0; - if (!hasChunkedMode) - { - closeConnection=true; - } - } - } - } - - // Close the connection or prepare for the next request on the same connection. - if (closeConnection) - { - while(socket->bytesToWrite()) socket->waitForBytesWritten(); - socket->disconnectFromHost(); - } - else - { - // Start timer for next request - int readTimeout=settings->value("readTimeout",10000).toInt(); - readTimer.start(readTimeout); - } - delete currentRequest; - currentRequest=0; - } - } -} diff --git a/isis/src/base/apps/spiceit/QtWebApp/httpserver/httpconnectionhandler.h b/isis/src/base/apps/spiceit/QtWebApp/httpserver/httpconnectionhandler.h deleted file mode 100644 index c68f4281a23f82ac53ab8093a04bd48bdb033f7d..0000000000000000000000000000000000000000 --- a/isis/src/base/apps/spiceit/QtWebApp/httpserver/httpconnectionhandler.h +++ /dev/null @@ -1,124 +0,0 @@ -/** - @file - @author Stefan Frings -*/ - -#ifndef HTTPCONNECTIONHANDLER_H -#define HTTPCONNECTIONHANDLER_H - -#ifndef QT_NO_OPENSSL - #include <QSslConfiguration> -#endif -#include <QTcpSocket> -#include <QSettings> -#include <QTimer> -#include <QThread> -#include "httpglobal.h" -#include "httprequest.h" -#include "httprequesthandler.h" - -namespace stefanfrings { - -/** Alias type definition, for compatibility to different Qt versions */ -#if QT_VERSION >= 0x050000 - typedef qintptr tSocketDescriptor; -#else - typedef int tSocketDescriptor; -#endif - -/** Alias for QSslConfiguration if OpenSSL is not supported */ -#ifdef QT_NO_OPENSSL - #define QSslConfiguration QObject -#endif - -/** - The connection handler accepts incoming connections and dispatches incoming requests to to a - request mapper. Since HTTP clients can send multiple requests before waiting for the response, - the incoming requests are queued and processed one after the other. - <p> - Example for the required configuration settings: - <code><pre> - readTimeout=60000 - maxRequestSize=16000 - maxMultiPartSize=1000000 - </pre></code> - <p> - The readTimeout value defines the maximum time to wait for a complete HTTP request. - @see HttpRequest for description of config settings maxRequestSize and maxMultiPartSize. -*/ -class DECLSPEC HttpConnectionHandler : public QThread { - Q_OBJECT - Q_DISABLE_COPY(HttpConnectionHandler) - -public: - - /** - Constructor. - @param settings Configuration settings of the HTTP webserver - @param requestHandler Handler that will process each incoming HTTP request - @param sslConfiguration SSL (HTTPS) will be used if not NULL - */ - HttpConnectionHandler(QSettings* settings, HttpRequestHandler* requestHandler, QSslConfiguration* sslConfiguration=NULL); - - /** Destructor */ - virtual ~HttpConnectionHandler(); - - /** Returns true, if this handler is in use. */ - bool isBusy(); - - /** Mark this handler as busy */ - void setBusy(); - -private: - - /** Configuration settings */ - QSettings* settings; - - /** TCP socket of the current connection */ - QTcpSocket* socket; - - /** Time for read timeout detection */ - QTimer readTimer; - - /** Storage for the current incoming HTTP request */ - HttpRequest* currentRequest; - - /** Dispatches received requests to services */ - HttpRequestHandler* requestHandler; - - /** This shows the busy-state from a very early time */ - bool busy; - - /** Configuration for SSL */ - QSslConfiguration* sslConfiguration; - - /** Executes the threads own event loop */ - void run(); - - /** Create SSL or TCP socket */ - void createSocket(); - -public slots: - - /** - Received from from the listener, when the handler shall start processing a new connection. - @param socketDescriptor references the accepted connection. - */ - void handleConnection(tSocketDescriptor socketDescriptor); - -private slots: - - /** Received from the socket when a read-timeout occured */ - void readTimeout(); - - /** Received from the socket when incoming data can be read */ - void read(); - - /** Received from the socket when a connection has been closed */ - void disconnected(); - -}; - -} // end of namespace - -#endif // HTTPCONNECTIONHANDLER_H diff --git a/isis/src/base/apps/spiceit/QtWebApp/httpserver/httpconnectionhandlerpool.cpp b/isis/src/base/apps/spiceit/QtWebApp/httpserver/httpconnectionhandlerpool.cpp deleted file mode 100644 index 3a3615b561b84883b0c2a29a4cd15ce1ef305961..0000000000000000000000000000000000000000 --- a/isis/src/base/apps/spiceit/QtWebApp/httpserver/httpconnectionhandlerpool.cpp +++ /dev/null @@ -1,148 +0,0 @@ -#ifndef QT_NO_OPENSSL - #include <QSslSocket> - #include <QSslKey> - #include <QSslCertificate> - #include <QSslConfiguration> -#endif -#include <QDir> -#include "httpconnectionhandlerpool.h" - -using namespace stefanfrings; - -HttpConnectionHandlerPool::HttpConnectionHandlerPool(QSettings* settings, HttpRequestHandler* requestHandler) - : QObject() -{ - Q_ASSERT(settings!=0); - this->settings=settings; - this->requestHandler=requestHandler; - this->sslConfiguration=NULL; - loadSslConfig(); - cleanupTimer.start(settings->value("cleanupInterval",1000).toInt()); - connect(&cleanupTimer, SIGNAL(timeout()), SLOT(cleanup())); -} - - -HttpConnectionHandlerPool::~HttpConnectionHandlerPool() -{ - // delete all connection handlers and wait until their threads are closed - foreach(HttpConnectionHandler* handler, pool) - { - delete handler; - } - delete sslConfiguration; - qDebug("HttpConnectionHandlerPool (%p): destroyed", this); -} - - -HttpConnectionHandler* HttpConnectionHandlerPool::getConnectionHandler() -{ - HttpConnectionHandler* freeHandler=0; - mutex.lock(); - // find a free handler in pool - foreach(HttpConnectionHandler* handler, pool) - { - if (!handler->isBusy()) - { - freeHandler=handler; - freeHandler->setBusy(); - break; - } - } - // create a new handler, if necessary - if (!freeHandler) - { - int maxConnectionHandlers=settings->value("maxThreads",100).toInt(); - if (pool.count()<maxConnectionHandlers) - { - freeHandler=new HttpConnectionHandler(settings,requestHandler,sslConfiguration); - freeHandler->setBusy(); - pool.append(freeHandler); - } - } - mutex.unlock(); - return freeHandler; -} - - -void HttpConnectionHandlerPool::cleanup() -{ - int maxIdleHandlers=settings->value("minThreads",1).toInt(); - int idleCounter=0; - mutex.lock(); - foreach(HttpConnectionHandler* handler, pool) - { - if (!handler->isBusy()) - { - if (++idleCounter > maxIdleHandlers) - { - delete handler; - pool.removeOne(handler); - qDebug("HttpConnectionHandlerPool: Removed connection handler (%p), pool size is now %i",handler,pool.size()); - break; // remove only one handler in each interval - } - } - } - mutex.unlock(); -} - - -void HttpConnectionHandlerPool::loadSslConfig() -{ - // If certificate and key files are configured, then load them - QString sslKeyFileName=settings->value("sslKeyFile","").toString(); - QString sslCertFileName=settings->value("sslCertFile","").toString(); - if (!sslKeyFileName.isEmpty() && !sslCertFileName.isEmpty()) - { - #ifdef QT_NO_OPENSSL - qWarning("HttpConnectionHandlerPool: SSL is not supported"); - #else - // Convert relative fileNames to absolute, based on the directory of the config file. - QFileInfo configFile(settings->fileName()); - #ifdef Q_OS_WIN32 - if (QDir::isRelativePath(sslKeyFileName) && settings->format()!=QSettings::NativeFormat) - #else - if (QDir::isRelativePath(sslKeyFileName)) - #endif - { - sslKeyFileName=QFileInfo(configFile.absolutePath(),sslKeyFileName).absoluteFilePath(); - } - #ifdef Q_OS_WIN32 - if (QDir::isRelativePath(sslCertFileName) && settings->format()!=QSettings::NativeFormat) - #else - if (QDir::isRelativePath(sslCertFileName)) - #endif - { - sslCertFileName=QFileInfo(configFile.absolutePath(),sslCertFileName).absoluteFilePath(); - } - - // Load the SSL certificate - QFile certFile(sslCertFileName); - if (!certFile.open(QIODevice::ReadOnly)) - { - qCritical("HttpConnectionHandlerPool: cannot open sslCertFile %s", qPrintable(sslCertFileName)); - return; - } - QSslCertificate certificate(&certFile, QSsl::Pem); - certFile.close(); - - // Load the key file - QFile keyFile(sslKeyFileName); - if (!keyFile.open(QIODevice::ReadOnly)) - { - qCritical("HttpConnectionHandlerPool: cannot open sslKeyFile %s", qPrintable(sslKeyFileName)); - return; - } - QSslKey sslKey(&keyFile, QSsl::Rsa, QSsl::Pem); - keyFile.close(); - - // Create the SSL configuration - sslConfiguration=new QSslConfiguration(); - sslConfiguration->setLocalCertificate(certificate); - sslConfiguration->setPrivateKey(sslKey); - sslConfiguration->setPeerVerifyMode(QSslSocket::VerifyNone); - sslConfiguration->setProtocol(QSsl::TlsV1SslV3); - - qDebug("HttpConnectionHandlerPool: SSL settings loaded"); - #endif - } -} diff --git a/isis/src/base/apps/spiceit/QtWebApp/httpserver/httpconnectionhandlerpool.h b/isis/src/base/apps/spiceit/QtWebApp/httpserver/httpconnectionhandlerpool.h deleted file mode 100644 index c6279f1a2dc3dd0b651c30145385384bf13b2ccf..0000000000000000000000000000000000000000 --- a/isis/src/base/apps/spiceit/QtWebApp/httpserver/httpconnectionhandlerpool.h +++ /dev/null @@ -1,99 +0,0 @@ -#ifndef HTTPCONNECTIONHANDLERPOOL_H -#define HTTPCONNECTIONHANDLERPOOL_H - -#include <QList> -#include <QTimer> -#include <QObject> -#include <QMutex> -#include "httpglobal.h" -#include "httpconnectionhandler.h" - -namespace stefanfrings { - -/** - Pool of http connection handlers. The size of the pool grows and - shrinks on demand. - <p> - Example for the required configuration settings: - <code><pre> - minThreads=4 - maxThreads=100 - cleanupInterval=60000 - readTimeout=60000 - ;sslKeyFile=ssl/my.key - ;sslCertFile=ssl/my.cert - maxRequestSize=16000 - maxMultiPartSize=1000000 - </pre></code> - After server start, the size of the thread pool is always 0. Threads - are started on demand when requests come in. The cleanup timer reduces - the number of idle threads slowly by closing one thread in each interval. - But the configured minimum number of threads are kept running. - <p> - For SSL support, you need an OpenSSL certificate file and a key file. - Both can be created with the command - <code><pre> - openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout my.key -out my.cert - </pre></code> - <p> - Visit http://slproweb.com/products/Win32OpenSSL.html to download the Light version of OpenSSL for Windows. - <p> - Please note that a listener with SSL settings can only handle HTTPS protocol. To - support both HTTP and HTTPS simultaneously, you need to start two listeners on different ports - - one with SLL and one without SSL. - @see HttpConnectionHandler for description of the readTimeout - @see HttpRequest for description of config settings maxRequestSize and maxMultiPartSize -*/ - -class DECLSPEC HttpConnectionHandlerPool : public QObject { - Q_OBJECT - Q_DISABLE_COPY(HttpConnectionHandlerPool) -public: - - /** - Constructor. - @param settings Configuration settings for the HTTP server. Must not be 0. - @param requestHandler The handler that will process each received HTTP request. - @warning The requestMapper gets deleted by the destructor of this pool - */ - HttpConnectionHandlerPool(QSettings* settings, HttpRequestHandler* requestHandler); - - /** Destructor */ - virtual ~HttpConnectionHandlerPool(); - - /** Get a free connection handler, or 0 if not available. */ - HttpConnectionHandler* getConnectionHandler(); - -private: - - /** Settings for this pool */ - QSettings* settings; - - /** Will be assigned to each Connectionhandler during their creation */ - HttpRequestHandler* requestHandler; - - /** Pool of connection handlers */ - QList<HttpConnectionHandler*> pool; - - /** Timer to clean-up unused connection handler */ - QTimer cleanupTimer; - - /** Used to synchronize threads */ - QMutex mutex; - - /** The SSL configuration (certificate, key and other settings) */ - QSslConfiguration* sslConfiguration; - - /** Load SSL configuration */ - void loadSslConfig(); - -private slots: - - /** Received from the clean-up timer. */ - void cleanup(); - -}; - -} // end of namespace - -#endif // HTTPCONNECTIONHANDLERPOOL_H diff --git a/isis/src/base/apps/spiceit/QtWebApp/httpserver/httpcookie.cpp b/isis/src/base/apps/spiceit/QtWebApp/httpserver/httpcookie.cpp deleted file mode 100644 index f09a2c37388e56370ed3685af9a805dd3d61ef60..0000000000000000000000000000000000000000 --- a/isis/src/base/apps/spiceit/QtWebApp/httpserver/httpcookie.cpp +++ /dev/null @@ -1,263 +0,0 @@ -/** - @file - @author Stefan Frings -*/ - -#include "httpcookie.h" - -using namespace stefanfrings; - -HttpCookie::HttpCookie() -{ - version=1; - maxAge=0; - secure=false; -} - -HttpCookie::HttpCookie(const QByteArray name, const QByteArray value, const int maxAge, const QByteArray path, const QByteArray comment, const QByteArray domain, const bool secure, const bool httpOnly) -{ - this->name=name; - this->value=value; - this->maxAge=maxAge; - this->path=path; - this->comment=comment; - this->domain=domain; - this->secure=secure; - this->httpOnly=httpOnly; - this->version=1; -} - -HttpCookie::HttpCookie(const QByteArray source) -{ - version=1; - maxAge=0; - secure=false; - QList<QByteArray> list=splitCSV(source); - foreach(QByteArray part, list) - { - - // Split the part into name and value - QByteArray name; - QByteArray value; - int posi=part.indexOf('='); - if (posi) - { - name=part.left(posi).trimmed(); - value=part.mid(posi+1).trimmed(); - } - else - { - name=part.trimmed(); - value=""; - } - - // Set fields - if (name=="Comment") - { - comment=value; - } - else if (name=="Domain") - { - domain=value; - } - else if (name=="Max-Age") - { - maxAge=value.toInt(); - } - else if (name=="Path") - { - path=value; - } - else if (name=="Secure") - { - secure=true; - } - else if (name=="HttpOnly") - { - httpOnly=true; - } - else if (name=="Version") - { - version=value.toInt(); - } - else { - if (this->name.isEmpty()) - { - this->name=name; - this->value=value; - } - else - { - qWarning("HttpCookie: Ignoring unknown %s=%s",name.data(),value.data()); - } - } - } -} - -QByteArray HttpCookie::toByteArray() const -{ - QByteArray buffer(name); - buffer.append('='); - buffer.append(value); - if (!comment.isEmpty()) - { - buffer.append("; Comment="); - buffer.append(comment); - } - if (!domain.isEmpty()) - { - buffer.append("; Domain="); - buffer.append(domain); - } - if (maxAge!=0) - { - buffer.append("; Max-Age="); - buffer.append(QByteArray::number(maxAge)); - } - if (!path.isEmpty()) - { - buffer.append("; Path="); - buffer.append(path); - } - if (secure) { - buffer.append("; Secure"); - } - if (httpOnly) { - buffer.append("; HttpOnly"); - } - buffer.append("; Version="); - buffer.append(QByteArray::number(version)); - return buffer; -} - -void HttpCookie::setName(const QByteArray name) -{ - this->name=name; -} - -void HttpCookie::setValue(const QByteArray value) -{ - this->value=value; -} - -void HttpCookie::setComment(const QByteArray comment) -{ - this->comment=comment; -} - -void HttpCookie::setDomain(const QByteArray domain) -{ - this->domain=domain; -} - -void HttpCookie::setMaxAge(const int maxAge) -{ - this->maxAge=maxAge; -} - -void HttpCookie::setPath(const QByteArray path) -{ - this->path=path; -} - -void HttpCookie::setSecure(const bool secure) -{ - this->secure=secure; -} - -void HttpCookie::setHttpOnly(const bool httpOnly) -{ - this->httpOnly=httpOnly; -} - -QByteArray HttpCookie::getName() const -{ - return name; -} - -QByteArray HttpCookie::getValue() const -{ - return value; -} - -QByteArray HttpCookie::getComment() const -{ - return comment; -} - -QByteArray HttpCookie::getDomain() const -{ - return domain; -} - -int HttpCookie::getMaxAge() const -{ - return maxAge; -} - -QByteArray HttpCookie::getPath() const -{ - return path; -} - -bool HttpCookie::getSecure() const -{ - return secure; -} - -bool HttpCookie::getHttpOnly() const -{ - return httpOnly; -} - -int HttpCookie::getVersion() const -{ - return version; -} - -QList<QByteArray> HttpCookie::splitCSV(const QByteArray source) -{ - bool inString=false; - QList<QByteArray> list; - QByteArray buffer; - for (int i=0; i<source.size(); ++i) - { - char c=source.at(i); - if (inString==false) - { - if (c=='\"') - { - inString=true; - } - else if (c==';') - { - QByteArray trimmed=buffer.trimmed(); - if (!trimmed.isEmpty()) - { - list.append(trimmed); - } - buffer.clear(); - } - else - { - buffer.append(c); - } - } - else - { - if (c=='\"') - { - inString=false; - } - else { - buffer.append(c); - } - } - } - QByteArray trimmed=buffer.trimmed(); - if (!trimmed.isEmpty()) - { - list.append(trimmed); - } - return list; -} diff --git a/isis/src/base/apps/spiceit/QtWebApp/httpserver/httpcookie.h b/isis/src/base/apps/spiceit/QtWebApp/httpserver/httpcookie.h deleted file mode 100644 index 236888928df8296a063ab365b4da0e7ab2ff637a..0000000000000000000000000000000000000000 --- a/isis/src/base/apps/spiceit/QtWebApp/httpserver/httpcookie.h +++ /dev/null @@ -1,123 +0,0 @@ -/** - @file - @author Stefan Frings -*/ - -#ifndef HTTPCOOKIE_H -#define HTTPCOOKIE_H - -#include <QList> -#include <QByteArray> -#include "httpglobal.h" - -namespace stefanfrings { - -/** - HTTP cookie as defined in RFC 2109. This class can also parse - RFC 2965 cookies, but skips fields that are not defined in RFC - 2109. -*/ - -class DECLSPEC HttpCookie -{ -public: - - /** Creates an empty cookie */ - HttpCookie(); - - /** - Create a cookie and set name/value pair. - @param name name of the cookie - @param value value of the cookie - @param maxAge maximum age of the cookie in seconds. 0=discard immediately - @param path Path for that the cookie will be sent, default="/" which means the whole domain - @param comment Optional comment, may be displayed by the web browser somewhere - @param domain Optional domain for that the cookie will be sent. Defaults to the current domain - @param secure If true, the cookie will be sent by the browser to the server only on secure connections - @param httpOnly If true, the browser does not allow client-side scripts to access the cookie - */ - HttpCookie(const QByteArray name, const QByteArray value, const int maxAge, const QByteArray path="/", const QByteArray comment=QByteArray(), const QByteArray domain=QByteArray(), const bool secure=false, const bool httpOnly=false); - - /** - Create a cookie from a string. - @param source String as received in a HTTP Cookie2 header. - */ - HttpCookie(const QByteArray source); - - /** Convert this cookie to a string that may be used in a Set-Cookie header. */ - QByteArray toByteArray() const ; - - /** - Split a string list into parts, where each part is delimited by semicolon. - Semicolons within double quotes are skipped. Double quotes are removed. - */ - static QList<QByteArray> splitCSV(const QByteArray source); - - /** Set the name of this cookie */ - void setName(const QByteArray name); - - /** Set the value of this cookie */ - void setValue(const QByteArray value); - - /** Set the comment of this cookie */ - void setComment(const QByteArray comment); - - /** Set the domain of this cookie */ - void setDomain(const QByteArray domain); - - /** Set the maximum age of this cookie in seconds. 0=discard immediately */ - void setMaxAge(const int maxAge); - - /** Set the path for that the cookie will be sent, default="/" which means the whole domain */ - void setPath(const QByteArray path); - - /** Set secure mode, so that the cookie will be sent by the browser to the server only on secure connections */ - void setSecure(const bool secure); - - /** Set HTTP-only mode, so that he browser does not allow client-side scripts to access the cookie */ - void setHttpOnly(const bool httpOnly); - - /** Get the name of this cookie */ - QByteArray getName() const; - - /** Get the value of this cookie */ - QByteArray getValue() const; - - /** Get the comment of this cookie */ - QByteArray getComment() const; - - /** Get the domain of this cookie */ - QByteArray getDomain() const; - - /** Get the maximum age of this cookie in seconds. */ - int getMaxAge() const; - - /** Set the path of this cookie */ - QByteArray getPath() const; - - /** Get the secure flag of this cookie */ - bool getSecure() const; - - /** Get the HTTP-only flag of this cookie */ - bool getHttpOnly() const; - - /** Returns always 1 */ - int getVersion() const; - -private: - - QByteArray name; - QByteArray value; - QByteArray comment; - QByteArray domain; - int maxAge; - QByteArray path; - bool secure; - bool httpOnly; - int version; - -}; - -} // end of namespace - -#endif // HTTPCOOKIE_H diff --git a/isis/src/base/apps/spiceit/QtWebApp/httpserver/httpglobal.cpp b/isis/src/base/apps/spiceit/QtWebApp/httpserver/httpglobal.cpp deleted file mode 100644 index 8ccfb02dd6097728fef53cc669160f7c0c443806..0000000000000000000000000000000000000000 --- a/isis/src/base/apps/spiceit/QtWebApp/httpserver/httpglobal.cpp +++ /dev/null @@ -1,7 +0,0 @@ -#include "httpglobal.h" - -const char* getQtWebAppLibVersion() -{ - return "1.7.3"; -} - diff --git a/isis/src/base/apps/spiceit/QtWebApp/httpserver/httpglobal.h b/isis/src/base/apps/spiceit/QtWebApp/httpserver/httpglobal.h deleted file mode 100644 index e7e856a9767e689192d16e3d6fa3d6863b6daadc..0000000000000000000000000000000000000000 --- a/isis/src/base/apps/spiceit/QtWebApp/httpserver/httpglobal.h +++ /dev/null @@ -1,28 +0,0 @@ -/** - @file - @author Stefan Frings -*/ - -#ifndef HTTPGLOBAL_H -#define HTTPGLOBAL_H - -#include <QtGlobal> - -// This is specific to Windows dll's -#if defined(Q_OS_WIN) - #if defined(QTWEBAPPLIB_EXPORT) - #define DECLSPEC Q_DECL_EXPORT - #elif defined(QTWEBAPPLIB_IMPORT) - #define DECLSPEC Q_DECL_IMPORT - #endif -#endif -#if !defined(DECLSPEC) - #define DECLSPEC -#endif - -/** Get the library version number */ -DECLSPEC const char* getQtWebAppLibVersion(); - - -#endif // HTTPGLOBAL_H - diff --git a/isis/src/base/apps/spiceit/QtWebApp/httpserver/httplistener.cpp b/isis/src/base/apps/spiceit/QtWebApp/httpserver/httplistener.cpp deleted file mode 100644 index b07c4b8c7e7f76fd712c58e50ac00bf591e4aa39..0000000000000000000000000000000000000000 --- a/isis/src/base/apps/spiceit/QtWebApp/httpserver/httplistener.cpp +++ /dev/null @@ -1,90 +0,0 @@ -/** - @file - @author Stefan Frings -*/ - -#include "httplistener.h" -#include "httpconnectionhandler.h" -#include "httpconnectionhandlerpool.h" -#include <QCoreApplication> - -using namespace stefanfrings; - -HttpListener::HttpListener(QSettings* settings, HttpRequestHandler* requestHandler, QObject *parent) - : QTcpServer(parent) -{ - Q_ASSERT(settings!=0); - Q_ASSERT(requestHandler!=0); - pool=NULL; - this->settings=settings; - this->requestHandler=requestHandler; - // Reqister type of socketDescriptor for signal/slot handling - qRegisterMetaType<tSocketDescriptor>("tSocketDescriptor"); - // Start listening - listen(); -} - - -HttpListener::~HttpListener() -{ - close(); - qDebug("HttpListener: destroyed"); -} - - -void HttpListener::listen() -{ - if (!pool) - { - pool=new HttpConnectionHandlerPool(settings,requestHandler); - } - QString host = settings->value("host").toString(); - int port=settings->value("port").toInt(); - QTcpServer::listen(host.isEmpty() ? QHostAddress::Any : QHostAddress(host), port); - if (!isListening()) - { - qCritical("HttpListener: Cannot bind on port %i: %s",port,qPrintable(errorString())); - } - else { - qDebug("HttpListener: Listening on port %i",port); - } -} - - -void HttpListener::close() { - QTcpServer::close(); - qDebug("HttpListener: closed"); - if (pool) { - delete pool; - pool=NULL; - } -} - -void HttpListener::incomingConnection(tSocketDescriptor socketDescriptor) { -#ifdef SUPERVERBOSE - qDebug("HttpListener: New connection"); -#endif - - HttpConnectionHandler* freeHandler=NULL; - if (pool) - { - freeHandler=pool->getConnectionHandler(); - } - - // Let the handler process the new connection. - if (freeHandler) - { - // The descriptor is passed via event queue because the handler lives in another thread - QMetaObject::invokeMethod(freeHandler, "handleConnection", Qt::QueuedConnection, Q_ARG(tSocketDescriptor, socketDescriptor)); - } - else - { - // Reject the connection - qDebug("HttpListener: Too many incoming connections"); - QTcpSocket* socket=new QTcpSocket(this); - socket->setSocketDescriptor(socketDescriptor); - connect(socket, SIGNAL(disconnected()), socket, SLOT(deleteLater())); - socket->write("HTTP/1.1 503 too many connections\r\nConnection: close\r\n\r\nToo many connections\r\n"); - socket->disconnectFromHost(); - } -} diff --git a/isis/src/base/apps/spiceit/QtWebApp/httpserver/httplistener.h b/isis/src/base/apps/spiceit/QtWebApp/httpserver/httplistener.h deleted file mode 100644 index b1dbfbc9ffba51f5df914710f449d6b868d5faa6..0000000000000000000000000000000000000000 --- a/isis/src/base/apps/spiceit/QtWebApp/httpserver/httplistener.h +++ /dev/null @@ -1,102 +0,0 @@ -/** - @file - @author Stefan Frings -*/ - -#ifndef HTTPLISTENER_H -#define HTTPLISTENER_H - -#include <QTcpServer> -#include <QSettings> -#include <QBasicTimer> -#include "httpglobal.h" -#include "httpconnectionhandler.h" -#include "httpconnectionhandlerpool.h" -#include "httprequesthandler.h" - -namespace stefanfrings { - -/** - Listens for incoming TCP connections and and passes all incoming HTTP requests to your implementation of HttpRequestHandler, - which processes the request and generates the response (usually a HTML document). - <p> - Example for the required settings in the config file: - <code><pre> - ;host=192.168.0.100 - port=8080 - minThreads=1 - maxThreads=10 - cleanupInterval=1000 - readTimeout=60000 - ;sslKeyFile=ssl/my.key - ;sslCertFile=ssl/my.cert - maxRequestSize=16000 - maxMultiPartSize=1000000 - </pre></code> - The optional host parameter binds the listener to one network interface. - The listener handles all network interfaces if no host is configured. - The port number specifies the incoming TCP port that this listener listens to. - @see HttpConnectionHandlerPool for description of config settings minThreads, maxThreads, cleanupInterval and ssl settings - @see HttpConnectionHandler for description of the readTimeout - @see HttpRequest for description of config settings maxRequestSize and maxMultiPartSize -*/ - -class DECLSPEC HttpListener : public QTcpServer { - Q_OBJECT - Q_DISABLE_COPY(HttpListener) -public: - - /** - Constructor. - Creates a connection pool and starts listening on the configured host and port. - @param settings Configuration settings for the HTTP server. Must not be 0. - @param requestHandler Processes each received HTTP request, usually by dispatching to controller classes. - @param parent Parent object. - @warning Ensure to close or delete the listener before deleting the request handler. - */ - HttpListener(QSettings* settings, HttpRequestHandler* requestHandler, QObject* parent = NULL); - - /** Destructor */ - virtual ~HttpListener(); - - /** - Restart listeing after close(). - */ - void listen(); - - /** - Closes the listener, waits until all pending requests are processed, - then closes the connection pool. - */ - void close(); - -protected: - - /** Serves new incoming connection requests */ - void incomingConnection(tSocketDescriptor socketDescriptor); - -private: - - /** Configuration settings for the HTTP server */ - QSettings* settings; - - /** Point to the reuqest handler which processes all HTTP requests */ - HttpRequestHandler* requestHandler; - - /** Pool of connection handlers */ - HttpConnectionHandlerPool* pool; - -signals: - - /** - Sent to the connection handler to process a new incoming connection. - @param socketDescriptor references the accepted connection. - */ - - void handleConnection(tSocketDescriptor socketDescriptor); - -}; - -} // end of namespace - -#endif // HTTPLISTENER_H diff --git a/isis/src/base/apps/spiceit/QtWebApp/httpserver/httprequest.cpp b/isis/src/base/apps/spiceit/QtWebApp/httpserver/httprequest.cpp deleted file mode 100644 index a6ac16ec7480b5dc5c988e4f2f696d117ff7e021..0000000000000000000000000000000000000000 --- a/isis/src/base/apps/spiceit/QtWebApp/httpserver/httprequest.cpp +++ /dev/null @@ -1,569 +0,0 @@ -/** - @file - @author Stefan Frings -*/ - -#include "httprequest.h" -#include <QList> -#include <QDir> -#include "httpcookie.h" - -using namespace stefanfrings; - -HttpRequest::HttpRequest(QSettings* settings) -{ - status=waitForRequest; - currentSize=0; - expectedBodySize=0; - maxSize=settings->value("maxRequestSize","16000").toInt(); - maxMultiPartSize=settings->value("maxMultiPartSize","1000000").toInt(); - tempFile=NULL; -} - - -void HttpRequest::readRequest(QTcpSocket* socket) -{ - #ifdef SUPERVERBOSE - qDebug("HttpRequest: read request"); - #endif - int toRead=maxSize-currentSize+1; // allow one byte more to be able to detect overflow - lineBuffer.append(socket->readLine(toRead)); - currentSize+=lineBuffer.size(); - if (!lineBuffer.contains('\r') && !lineBuffer.contains('\n')) - { - #ifdef SUPERVERBOSE - qDebug("HttpRequest: collecting more parts until line break"); - #endif - return; - } - QByteArray newData=lineBuffer.trimmed(); - lineBuffer.clear(); - if (!newData.isEmpty()) - { - QList<QByteArray> list=newData.split(' '); - if (list.count()!=3 || !list.at(2).contains("HTTP")) - { - qWarning("HttpRequest: received broken HTTP request, invalid first line"); - status=abort; - } - else { - method=list.at(0).trimmed(); - path=list.at(1); - version=list.at(2); - peerAddress = socket->peerAddress(); - status=waitForHeader; - } - } -} - -void HttpRequest::readHeader(QTcpSocket* socket) -{ - #ifdef SUPERVERBOSE - qDebug("HttpRequest: read header"); - #endif - int toRead=maxSize-currentSize+1; // allow one byte more to be able to detect overflow - lineBuffer.append(socket->readLine(toRead)); - currentSize+=lineBuffer.size(); - if (!lineBuffer.contains('\r') && !lineBuffer.contains('\n')) - { - #ifdef SUPERVERBOSE - qDebug("HttpRequest: collecting more parts until line break"); - #endif - return; - } - QByteArray newData=lineBuffer.trimmed(); - lineBuffer.clear(); - int colon=newData.indexOf(':'); - if (colon>0) - { - // Received a line with a colon - a header - currentHeader=newData.left(colon).toLower(); - QByteArray value=newData.mid(colon+1).trimmed(); - headers.insert(currentHeader,value); - #ifdef SUPERVERBOSE - qDebug("HttpRequest: received header %s: %s",currentHeader.data(),value.data()); - #endif - } - else if (!newData.isEmpty()) - { - // received another line - belongs to the previous header - #ifdef SUPERVERBOSE - qDebug("HttpRequest: read additional line of header"); - #endif - // Received additional line of previous header - if (headers.contains(currentHeader)) { - headers.insert(currentHeader,headers.value(currentHeader)+" "+newData); - } - } - else - { - // received an empty line - end of headers reached - #ifdef SUPERVERBOSE - qDebug("HttpRequest: headers completed"); - #endif - // Empty line received, that means all headers have been received - // Check for multipart/form-data - QByteArray contentType=headers.value("content-type"); - if (contentType.startsWith("multipart/form-data")) - { - int posi=contentType.indexOf("boundary="); - if (posi>=0) { - boundary=contentType.mid(posi+9); - if (boundary.startsWith('"') && boundary.endsWith('"')) - { - boundary = boundary.mid(1,boundary.length()-2); - } - } - } - QByteArray contentLength=headers.value("content-length"); - if (!contentLength.isEmpty()) - { - expectedBodySize=contentLength.toInt(); - } - if (expectedBodySize==0) - { - #ifdef SUPERVERBOSE - qDebug("HttpRequest: expect no body"); - #endif - status=complete; - } - else if (boundary.isEmpty() && expectedBodySize+currentSize>maxSize) - { - qWarning("HttpRequest: expected body is too large"); - status=abort; - } - else if (!boundary.isEmpty() && expectedBodySize>maxMultiPartSize) - { - qWarning("HttpRequest: expected multipart body is too large"); - status=abort; - } - else { - #ifdef SUPERVERBOSE - qDebug("HttpRequest: expect %i bytes body",expectedBodySize); - #endif - status=waitForBody; - } - } -} - -void HttpRequest::readBody(QTcpSocket* socket) -{ - Q_ASSERT(expectedBodySize!=0); - if (boundary.isEmpty()) - { - // normal body, no multipart - #ifdef SUPERVERBOSE - qDebug("HttpRequest: receive body"); - #endif - int toRead=expectedBodySize-bodyData.size(); - QByteArray newData=socket->read(toRead); - currentSize+=newData.size(); - bodyData.append(newData); - if (bodyData.size()>=expectedBodySize) - { - status=complete; - } - } - else - { - // multipart body, store into temp file - #ifdef SUPERVERBOSE - qDebug("HttpRequest: receiving multipart body"); - #endif - // Create an object for the temporary file, if not already present - if (tempFile == NULL) - { - tempFile = new QTemporaryFile; - } - if (!tempFile->isOpen()) - { - tempFile->open(); - } - // Transfer data in 64kb blocks - int fileSize=tempFile->size(); - int toRead=expectedBodySize-fileSize; - if (toRead>65536) - { - toRead=65536; - } - fileSize+=tempFile->write(socket->read(toRead)); - if (fileSize>=maxMultiPartSize) - { - qWarning("HttpRequest: received too many multipart bytes"); - status=abort; - } - else if (fileSize>=expectedBodySize) - { - #ifdef SUPERVERBOSE - qDebug("HttpRequest: received whole multipart body"); - #endif - tempFile->flush(); - if (tempFile->error()) - { - qCritical("HttpRequest: Error writing temp file for multipart body"); - } - parseMultiPartFile(); - tempFile->close(); - status=complete; - } - } -} - -void HttpRequest::decodeRequestParams() -{ - #ifdef SUPERVERBOSE - qDebug("HttpRequest: extract and decode request parameters"); - #endif - // Get URL parameters - QByteArray rawParameters; - int questionMark=path.indexOf('?'); - if (questionMark>=0) - { - rawParameters=path.mid(questionMark+1); - path=path.left(questionMark); - } - // Get request body parameters - QByteArray contentType=headers.value("content-type"); - if (!bodyData.isEmpty() && (contentType.isEmpty() || contentType.startsWith("application/x-www-form-urlencoded"))) - { - if (!rawParameters.isEmpty()) - { - rawParameters.append('&'); - rawParameters.append(bodyData); - } - else - { - rawParameters=bodyData; - } - } - // Split the parameters into pairs of value and name - QList<QByteArray> list=rawParameters.split('&'); - foreach (QByteArray part, list) - { - int equalsChar=part.indexOf('='); - if (equalsChar>=0) - { - QByteArray name=part.left(equalsChar).trimmed(); - QByteArray value=part.mid(equalsChar+1).trimmed(); - parameters.insert(urlDecode(name),urlDecode(value)); - } - else if (!part.isEmpty()) - { - // Name without value - parameters.insert(urlDecode(part),""); - } - } -} - -void HttpRequest::extractCookies() -{ - #ifdef SUPERVERBOSE - qDebug("HttpRequest: extract cookies"); - #endif - foreach(QByteArray cookieStr, headers.values("cookie")) - { - QList<QByteArray> list=HttpCookie::splitCSV(cookieStr); - foreach(QByteArray part, list) - { - #ifdef SUPERVERBOSE - qDebug("HttpRequest: found cookie %s",part.data()); - #endif // Split the part into name and value - QByteArray name; - QByteArray value; - int posi=part.indexOf('='); - if (posi) - { - name=part.left(posi).trimmed(); - value=part.mid(posi+1).trimmed(); - } - else - { - name=part.trimmed(); - value=""; - } - cookies.insert(name,value); - } - } - headers.remove("cookie"); -} - -void HttpRequest::readFromSocket(QTcpSocket* socket) -{ - Q_ASSERT(status!=complete); - if (status==waitForRequest) - { - readRequest(socket); - } - else if (status==waitForHeader) - { - readHeader(socket); - } - else if (status==waitForBody) - { - readBody(socket); - } - if ((boundary.isEmpty() && currentSize>maxSize) || (!boundary.isEmpty() && currentSize>maxMultiPartSize)) - { - qWarning("HttpRequest: received too many bytes"); - status=abort; - } - if (status==complete) - { - // Extract and decode request parameters from url and body - decodeRequestParams(); - // Extract cookies from headers - extractCookies(); - } -} - - -HttpRequest::RequestStatus HttpRequest::getStatus() const -{ - return status; -} - - -QByteArray HttpRequest::getMethod() const -{ - return method; -} - - -QByteArray HttpRequest::getPath() const -{ - return urlDecode(path); -} - - -const QByteArray& HttpRequest::getRawPath() const -{ - return path; -} - - -QByteArray HttpRequest::getVersion() const -{ - return version; -} - - -QByteArray HttpRequest::getHeader(const QByteArray& name) const -{ - return headers.value(name.toLower()); -} - -QList<QByteArray> HttpRequest::getHeaders(const QByteArray& name) const -{ - return headers.values(name.toLower()); -} - -QMultiMap<QByteArray,QByteArray> HttpRequest::getHeaderMap() const -{ - return headers; -} - -QByteArray HttpRequest::getParameter(const QByteArray& name) const -{ - return parameters.value(name); -} - -QList<QByteArray> HttpRequest::getParameters(const QByteArray& name) const -{ - return parameters.values(name); -} - -QMultiMap<QByteArray,QByteArray> HttpRequest::getParameterMap() const -{ - return parameters; -} - -QByteArray HttpRequest::getBody() const -{ - return bodyData; -} - -QByteArray HttpRequest::urlDecode(const QByteArray source) -{ - QByteArray buffer(source); - buffer.replace('+',' '); - int percentChar=buffer.indexOf('%'); - while (percentChar>=0) - { - bool ok; - char byte=buffer.mid(percentChar+1,2).toInt(&ok,16); - if (ok) - { - buffer.replace(percentChar,3,(char*)&byte,1); - } - percentChar=buffer.indexOf('%',percentChar+1); - } - return buffer; -} - - -void HttpRequest::parseMultiPartFile() -{ - qDebug("HttpRequest: parsing multipart temp file"); - tempFile->seek(0); - bool finished=false; - while (!tempFile->atEnd() && !finished && !tempFile->error()) - { - #ifdef SUPERVERBOSE - qDebug("HttpRequest: reading multpart headers"); - #endif - QByteArray fieldName; - QByteArray fileName; - while (!tempFile->atEnd() && !finished && !tempFile->error()) - { - QByteArray line=tempFile->readLine(65536).trimmed(); - if (line.startsWith("Content-Disposition:")) - { - if (line.contains("form-data")) - { - int start=line.indexOf(" name=\""); - int end=line.indexOf("\"",start+7); - if (start>=0 && end>=start) - { - fieldName=line.mid(start+7,end-start-7); - } - start=line.indexOf(" filename=\""); - end=line.indexOf("\"",start+11); - if (start>=0 && end>=start) - { - fileName=line.mid(start+11,end-start-11); - } - #ifdef SUPERVERBOSE - qDebug("HttpRequest: multipart field=%s, filename=%s",fieldName.data(),fileName.data()); - #endif - } - else - { - qDebug("HttpRequest: ignoring unsupported content part %s",line.data()); - } - } - else if (line.isEmpty()) - { - break; - } - } - - #ifdef SUPERVERBOSE - qDebug("HttpRequest: reading multpart data"); - #endif - QTemporaryFile* uploadedFile=0; - QByteArray fieldValue; - while (!tempFile->atEnd() && !finished && !tempFile->error()) - { - QByteArray line=tempFile->readLine(65536); - if (line.startsWith("--"+boundary)) - { - // Boundary found. Until now we have collected 2 bytes too much, - // so remove them from the last result - if (fileName.isEmpty() && !fieldName.isEmpty()) - { - // last field was a form field - fieldValue.remove(fieldValue.size()-2,2); - parameters.insert(fieldName,fieldValue); - qDebug("HttpRequest: set parameter %s=%s",fieldName.data(),fieldValue.data()); - } - else if (!fileName.isEmpty() && !fieldName.isEmpty()) - { - // last field was a file - #ifdef SUPERVERBOSE - qDebug("HttpRequest: finishing writing to uploaded file"); - #endif - uploadedFile->resize(uploadedFile->size()-2); - uploadedFile->flush(); - uploadedFile->seek(0); - parameters.insert(fieldName,fileName); - qDebug("HttpRequest: set parameter %s=%s",fieldName.data(),fileName.data()); - uploadedFiles.insert(fieldName,uploadedFile); - qDebug("HttpRequest: uploaded file size is %i",(int) uploadedFile->size()); - } - if (line.contains(boundary+"--")) - { - finished=true; - } - break; - } - else - { - if (fileName.isEmpty() && !fieldName.isEmpty()) - { - // this is a form field. - currentSize+=line.size(); - fieldValue.append(line); - } - else if (!fileName.isEmpty() && !fieldName.isEmpty()) - { - // this is a file - if (!uploadedFile) - { - uploadedFile=new QTemporaryFile(); - uploadedFile->open(); - } - uploadedFile->write(line); - if (uploadedFile->error()) - { - qCritical("HttpRequest: error writing temp file, %s",qPrintable(uploadedFile->errorString())); - } - } - } - } - } - if (tempFile->error()) - { - qCritical("HttpRequest: cannot read temp file, %s",qPrintable(tempFile->errorString())); - } - #ifdef SUPERVERBOSE - qDebug("HttpRequest: finished parsing multipart temp file"); - #endif -} - -HttpRequest::~HttpRequest() -{ - foreach(QByteArray key, uploadedFiles.keys()) - { - QTemporaryFile* file=uploadedFiles.value(key); - if (file->isOpen()) - { - file->close(); - } - delete file; - } - if (tempFile != NULL) - { - if (tempFile->isOpen()) - { - tempFile->close(); - } - delete tempFile; - } -} - -QTemporaryFile* HttpRequest::getUploadedFile(const QByteArray fieldName) const -{ - return uploadedFiles.value(fieldName); -} - -QByteArray HttpRequest::getCookie(const QByteArray& name) const -{ - return cookies.value(name); -} - -/** Get the map of cookies */ -QMap<QByteArray,QByteArray>& HttpRequest::getCookieMap() -{ - return cookies; -} - -/** - Get the address of the connected client. - Note that multiple clients may have the same IP address, if they - share an internet connection (which is very common). - */ -QHostAddress HttpRequest::getPeerAddress() const -{ - return peerAddress; -} - diff --git a/isis/src/base/apps/spiceit/QtWebApp/httpserver/httprequest.h b/isis/src/base/apps/spiceit/QtWebApp/httpserver/httprequest.h deleted file mode 100644 index 42ad41984018325104e45d5586b3abf85958147b..0000000000000000000000000000000000000000 --- a/isis/src/base/apps/spiceit/QtWebApp/httpserver/httprequest.h +++ /dev/null @@ -1,239 +0,0 @@ -/** - @file - @author Stefan Frings -*/ - -#ifndef HTTPREQUEST_H -#define HTTPREQUEST_H - -#include <QByteArray> -#include <QHostAddress> -#include <QTcpSocket> -#include <QMap> -#include <QMultiMap> -#include <QSettings> -#include <QTemporaryFile> -#include <QUuid> -#include "httpglobal.h" - -namespace stefanfrings { - -/** - This object represents a single HTTP request. It reads the request - from a TCP socket and provides getters for the individual parts - of the request. - <p> - The follwing config settings are required: - <code><pre> - maxRequestSize=16000 - maxMultiPartSize=1000000 - </pre></code> - <p> - MaxRequestSize is the maximum size of a HTTP request. In case of - multipart/form-data requests (also known as file-upload), the maximum - size of the body must not exceed maxMultiPartSize. - The body is always a little larger than the file itself. -*/ - -class DECLSPEC HttpRequest { - Q_DISABLE_COPY(HttpRequest) - friend class HttpSessionStore; - -public: - - /** Values for getStatus() */ - enum RequestStatus {waitForRequest, waitForHeader, waitForBody, complete, abort}; - - /** - Constructor. - @param settings Configuration settings - */ - HttpRequest(QSettings* settings); - - /** - Destructor. - */ - virtual ~HttpRequest(); - - /** - Read the HTTP request from a socket. - This method is called by the connection handler repeatedly - until the status is RequestStatus::complete or RequestStatus::abort. - @param socket Source of the data - */ - void readFromSocket(QTcpSocket* socket); - - /** - Get the status of this reqeust. - @see RequestStatus - */ - RequestStatus getStatus() const; - - /** Get the method of the HTTP request (e.g. "GET") */ - QByteArray getMethod() const; - - /** Get the decoded path of the HTPP request (e.g. "/index.html") */ - QByteArray getPath() const; - - /** Get the raw path of the HTTP request (e.g. "/file%20with%20spaces.html") */ - const QByteArray& getRawPath() const; - - /** Get the version of the HTPP request (e.g. "HTTP/1.1") */ - QByteArray getVersion() const; - - /** - Get the value of a HTTP request header. - @param name Name of the header, not case-senitive. - @return If the header occurs multiple times, only the last - one is returned. - */ - QByteArray getHeader(const QByteArray& name) const; - - /** - Get the values of a HTTP request header. - @param name Name of the header, not case-senitive. - */ - QList<QByteArray> getHeaders(const QByteArray& name) const; - - /** - * Get all HTTP request headers. Note that the header names - * are returned in lower-case. - */ - QMultiMap<QByteArray,QByteArray> getHeaderMap() const; - - /** - Get the value of a HTTP request parameter. - @param name Name of the parameter, case-sensitive. - @return If the parameter occurs multiple times, only the last - one is returned. - */ - QByteArray getParameter(const QByteArray& name) const; - - /** - Get the values of a HTTP request parameter. - @param name Name of the parameter, case-sensitive. - */ - QList<QByteArray> getParameters(const QByteArray& name) const; - - /** Get all HTTP request parameters. */ - QMultiMap<QByteArray,QByteArray> getParameterMap() const; - - /** Get the HTTP request body. */ - QByteArray getBody() const; - - /** - Decode an URL parameter. - E.g. replace "%23" by '#' and replace '+' by ' '. - @param source The url encoded strings - @see QUrl::toPercentEncoding for the reverse direction - */ - static QByteArray urlDecode(const QByteArray source); - - /** - Get an uploaded file. The file is already open. It will - be closed and deleted by the destructor of this HttpRequest - object (after processing the request). - <p> - For uploaded files, the method getParameters() returns - the original fileName as provided by the calling web browser. - */ - QTemporaryFile* getUploadedFile(const QByteArray fieldName) const; - - /** - Get the value of a cookie. - @param name Name of the cookie - */ - QByteArray getCookie(const QByteArray& name) const; - - /** Get all cookies. */ - QMap<QByteArray,QByteArray>& getCookieMap(); - - /** - Get the address of the connected client. - Note that multiple clients may have the same IP address, if they - share an internet connection (which is very common). - */ - QHostAddress getPeerAddress() const; - -private: - - /** Request headers */ - QMultiMap<QByteArray,QByteArray> headers; - - /** Parameters of the request */ - QMultiMap<QByteArray,QByteArray> parameters; - - /** Uploaded files of the request, key is the field name. */ - QMap<QByteArray,QTemporaryFile*> uploadedFiles; - - /** Received cookies */ - QMap<QByteArray,QByteArray> cookies; - - /** Storage for raw body data */ - QByteArray bodyData; - - /** Request method */ - QByteArray method; - - /** Request path (in raw encoded format) */ - QByteArray path; - - /** Request protocol version */ - QByteArray version; - - /** - Status of this request. For the state engine. - @see RequestStatus - */ - RequestStatus status; - - /** Address of the connected peer. */ - QHostAddress peerAddress; - - /** Maximum size of requests in bytes. */ - int maxSize; - - /** Maximum allowed size of multipart forms in bytes. */ - int maxMultiPartSize; - - /** Current size */ - int currentSize; - - /** Expected size of body */ - int expectedBodySize; - - /** Name of the current header, or empty if no header is being processed */ - QByteArray currentHeader; - - /** Boundary of multipart/form-data body. Empty if there is no such header */ - QByteArray boundary; - - /** Temp file, that is used to store the multipart/form-data body */ - QTemporaryFile* tempFile; - - /** Parse the multipart body, that has been stored in the temp file. */ - void parseMultiPartFile(); - - /** Sub-procedure of readFromSocket(), read the first line of a request. */ - void readRequest(QTcpSocket* socket); - - /** Sub-procedure of readFromSocket(), read header lines. */ - void readHeader(QTcpSocket* socket); - - /** Sub-procedure of readFromSocket(), read the request body. */ - void readBody(QTcpSocket* socket); - - /** Sub-procedure of readFromSocket(), extract and decode request parameters. */ - void decodeRequestParams(); - - /** Sub-procedure of readFromSocket(), extract cookies from headers */ - void extractCookies(); - - /** Buffer for collecting characters of request and header lines */ - QByteArray lineBuffer; - -}; - -} // end of namespace - -#endif // HTTPREQUEST_H diff --git a/isis/src/base/apps/spiceit/QtWebApp/httpserver/httprequesthandler.cpp b/isis/src/base/apps/spiceit/QtWebApp/httpserver/httprequesthandler.cpp deleted file mode 100644 index f3a5fbe76608b7e142a91734a685883b8a3c3518..0000000000000000000000000000000000000000 --- a/isis/src/base/apps/spiceit/QtWebApp/httpserver/httprequesthandler.cpp +++ /dev/null @@ -1,23 +0,0 @@ -/** - @file - @author Stefan Frings -*/ - -#include "httprequesthandler.h" - -using namespace stefanfrings; - -HttpRequestHandler::HttpRequestHandler(QObject* parent) - : QObject(parent) -{} - -HttpRequestHandler::~HttpRequestHandler() -{} - -void HttpRequestHandler::service(HttpRequest& request, HttpResponse& response) -{ - qCritical("HttpRequestHandler: you need to override the service() function"); - qDebug("HttpRequestHandler: request=%s %s %s",request.getMethod().data(),request.getPath().data(),request.getVersion().data()); - response.setStatus(501,"not implemented"); - response.write("501 not implemented",true); -} diff --git a/isis/src/base/apps/spiceit/QtWebApp/httpserver/httprequesthandler.h b/isis/src/base/apps/spiceit/QtWebApp/httpserver/httprequesthandler.h deleted file mode 100644 index b9c33550e1b7dfb5dac2832ac8e0ed9fa3279a9a..0000000000000000000000000000000000000000 --- a/isis/src/base/apps/spiceit/QtWebApp/httpserver/httprequesthandler.h +++ /dev/null @@ -1,53 +0,0 @@ -/** - @file - @author Stefan Frings -*/ - -#ifndef HTTPREQUESTHANDLER_H -#define HTTPREQUESTHANDLER_H - -#include "httpglobal.h" -#include "httprequest.h" -#include "httpresponse.h" - -namespace stefanfrings { - -/** - The request handler generates a response for each HTTP request. Web Applications - usually have one central request handler that maps incoming requests to several - controllers (servlets) based on the requested path. - <p> - You need to override the service() method or you will always get an HTTP error 501. - <p> - @warning Be aware that the main request handler instance must be created on the heap and - that it is used by multiple threads simultaneously. - @see StaticFileController which delivers static local files. -*/ - -class DECLSPEC HttpRequestHandler : public QObject { - Q_OBJECT - Q_DISABLE_COPY(HttpRequestHandler) -public: - - /** - * Constructor. - * @param parent Parent object. - */ - HttpRequestHandler(QObject* parent=NULL); - - /** Destructor */ - virtual ~HttpRequestHandler(); - - /** - Generate a response for an incoming HTTP request. - @param request The received HTTP request - @param response Must be used to return the response - @warning This method must be thread safe - */ - virtual void service(HttpRequest& request, HttpResponse& response); - -}; - -} // end of namespace - -#endif // HTTPREQUESTHANDLER_H diff --git a/isis/src/base/apps/spiceit/QtWebApp/httpserver/httpresponse.cpp b/isis/src/base/apps/spiceit/QtWebApp/httpserver/httpresponse.cpp deleted file mode 100644 index c7b3eec95792b4935fa1b12d93e0241c3b8f5fa8..0000000000000000000000000000000000000000 --- a/isis/src/base/apps/spiceit/QtWebApp/httpserver/httpresponse.cpp +++ /dev/null @@ -1,200 +0,0 @@ -/** - @file - @author Stefan Frings -*/ - -#include "httpresponse.h" - -using namespace stefanfrings; - -HttpResponse::HttpResponse(QTcpSocket* socket) -{ - this->socket=socket; - statusCode=200; - statusText="OK"; - sentHeaders=false; - sentLastPart=false; - chunkedMode=false; -} - -void HttpResponse::setHeader(QByteArray name, QByteArray value) -{ - Q_ASSERT(sentHeaders==false); - headers.insert(name,value); -} - -void HttpResponse::setHeader(QByteArray name, int value) -{ - Q_ASSERT(sentHeaders==false); - headers.insert(name,QByteArray::number(value)); -} - -QMap<QByteArray,QByteArray>& HttpResponse::getHeaders() -{ - return headers; -} - -void HttpResponse::setStatus(int statusCode, QByteArray description) -{ - this->statusCode=statusCode; - statusText=description; -} - -int HttpResponse::getStatusCode() const -{ - return this->statusCode; -} - -void HttpResponse::writeHeaders() -{ - Q_ASSERT(sentHeaders==false); - QByteArray buffer; - buffer.append("HTTP/1.1 "); - buffer.append(QByteArray::number(statusCode)); - buffer.append(' '); - buffer.append(statusText); - buffer.append("\r\n"); - foreach(QByteArray name, headers.keys()) - { - buffer.append(name); - buffer.append(": "); - buffer.append(headers.value(name)); - buffer.append("\r\n"); - } - foreach(HttpCookie cookie,cookies.values()) - { - buffer.append("Set-Cookie: "); - buffer.append(cookie.toByteArray()); - buffer.append("\r\n"); - } - buffer.append("\r\n"); - writeToSocket(buffer); - sentHeaders=true; -} - -bool HttpResponse::writeToSocket(QByteArray data) -{ - int remaining=data.size(); - char* ptr=data.data(); - while (socket->isOpen() && remaining>0) - { - // If the output buffer has become large, then wait until it has been sent. - if (socket->bytesToWrite()>16384) - { - socket->waitForBytesWritten(-1); - } - - int written=socket->write(ptr,remaining); - if (written==-1) - { - return false; - } - ptr+=written; - remaining-=written; - } - return true; -} - -void HttpResponse::write(QByteArray data, bool lastPart) -{ - Q_ASSERT(sentLastPart==false); - - // Send HTTP headers, if not already done (that happens only on the first call to write()) - if (sentHeaders==false) - { - // If the whole response is generated with a single call to write(), then we know the total - // size of the response and therefore can set the Content-Length header automatically. - if (lastPart) - { - // Automatically set the Content-Length header - headers.insert("Content-Length",QByteArray::number(data.size())); - } - - // else if we will not close the connection at the end, them we must use the chunked mode. - else - { - QByteArray connectionValue=headers.value("Connection",headers.value("connection")); - bool connectionClose=QString::compare(connectionValue,"close",Qt::CaseInsensitive)==0; - if (!connectionClose) - { - headers.insert("Transfer-Encoding","chunked"); - chunkedMode=true; - } - } - - writeHeaders(); - } - - // Send data - if (data.size()>0) - { - if (chunkedMode) - { - if (data.size()>0) - { - QByteArray size=QByteArray::number(data.size(),16); - writeToSocket(size); - writeToSocket("\r\n"); - writeToSocket(data); - writeToSocket("\r\n"); - } - } - else - { - writeToSocket(data); - } - } - - // Only for the last chunk, send the terminating marker and flush the buffer. - if (lastPart) - { - if (chunkedMode) - { - writeToSocket("0\r\n\r\n"); - } - socket->flush(); - sentLastPart=true; - } -} - - -bool HttpResponse::hasSentLastPart() const -{ - return sentLastPart; -} - - -void HttpResponse::setCookie(const HttpCookie& cookie) -{ - Q_ASSERT(sentHeaders==false); - if (!cookie.getName().isEmpty()) - { - cookies.insert(cookie.getName(),cookie); - } -} - - -QMap<QByteArray,HttpCookie>& HttpResponse::getCookies() -{ - return cookies; -} - - -void HttpResponse::redirect(const QByteArray& url) -{ - setStatus(303,"See Other"); - setHeader("Location",url); - write("Redirect",true); -} - - -void HttpResponse::flush() -{ - socket->flush(); -} - - -bool HttpResponse::isConnected() const -{ - return socket->isOpen(); -} diff --git a/isis/src/base/apps/spiceit/QtWebApp/httpserver/httpresponse.h b/isis/src/base/apps/spiceit/QtWebApp/httpserver/httpresponse.h deleted file mode 100644 index 8aa6524a2325d2c14c768db6c9372951f4189473..0000000000000000000000000000000000000000 --- a/isis/src/base/apps/spiceit/QtWebApp/httpserver/httpresponse.h +++ /dev/null @@ -1,163 +0,0 @@ -/** - @file - @author Stefan Frings -*/ - -#ifndef HTTPRESPONSE_H -#define HTTPRESPONSE_H - -#include <QMap> -#include <QString> -#include <QTcpSocket> -#include "httpglobal.h" -#include "httpcookie.h" - -namespace stefanfrings { - -/** - This object represents a HTTP response, used to return something to the web client. - <p> - <code><pre> - response.setStatus(200,"OK"); // optional, because this is the default - response.writeBody("Hello"); - response.writeBody("World!",true); - </pre></code> - <p> - Example how to return an error: - <code><pre> - response.setStatus(500,"server error"); - response.write("The request cannot be processed because the servers is broken",true); - </pre></code> - <p> - In case of large responses (e.g. file downloads), a Content-Length header should be set - before calling write(). Web Browsers use that information to display a progress bar. -*/ - -class DECLSPEC HttpResponse { - Q_DISABLE_COPY(HttpResponse) -public: - - /** - Constructor. - @param socket used to write the response - */ - HttpResponse(QTcpSocket* socket); - - /** - Set a HTTP response header. - You must call this method before the first write(). - @param name name of the header - @param value value of the header - */ - void setHeader(QByteArray name, QByteArray value); - - /** - Set a HTTP response header. - You must call this method before the first write(). - @param name name of the header - @param value value of the header - */ - void setHeader(QByteArray name, int value); - - /** Get the map of HTTP response headers */ - QMap<QByteArray,QByteArray>& getHeaders(); - - /** Get the map of cookies */ - QMap<QByteArray,HttpCookie>& getCookies(); - - /** - Set status code and description. The default is 200,OK. - You must call this method before the first write(). - */ - void setStatus(int statusCode, QByteArray description=QByteArray()); - - /** Return the status code. */ - int getStatusCode() const; - - /** - Write body data to the socket. - <p> - The HTTP status line, headers and cookies are sent automatically before the body. - <p> - If the response contains only a single chunk (indicated by lastPart=true), - then a Content-Length header is automatically set. - <p> - Chunked mode is automatically selected if there is no Content-Length header - and also no Connection:close header. - @param data Data bytes of the body - @param lastPart Indicates that this is the last chunk of data and flushes the output buffer. - */ - void write(QByteArray data, bool lastPart=false); - - /** - Indicates whether the body has been sent completely (write() has been called with lastPart=true). - */ - bool hasSentLastPart() const; - - /** - Set a cookie. - You must call this method before the first write(). - */ - void setCookie(const HttpCookie& cookie); - - /** - Send a redirect response to the browser. - Cannot be combined with write(). - @param url Destination URL - */ - void redirect(const QByteArray& url); - - /** - * Flush the output buffer (of the underlying socket). - * You normally don't need to call this method because flush is - * automatically called after HttpRequestHandler::service() returns. - */ - void flush(); - - /** - * May be used to check whether the connection to the web client has been lost. - * This might be useful to cancel the generation of large or slow responses. - */ - bool isConnected() const; - -private: - - /** Request headers */ - QMap<QByteArray,QByteArray> headers; - - /** Socket for writing output */ - QTcpSocket* socket; - - /** HTTP status code*/ - int statusCode; - - /** HTTP status code description */ - QByteArray statusText; - - /** Indicator whether headers have been sent */ - bool sentHeaders; - - /** Indicator whether the body has been sent completely */ - bool sentLastPart; - - /** Whether the response is sent in chunked mode */ - bool chunkedMode; - - /** Cookies */ - QMap<QByteArray,HttpCookie> cookies; - - /** Write raw data to the socket. This method blocks until all bytes have been passed to the TCP buffer */ - bool writeToSocket(QByteArray data); - - /** - Write the response HTTP status and headers to the socket. - Calling this method is optional, because writeBody() calls - it automatically when required. - */ - void writeHeaders(); - -}; - -} // end of namespace - -#endif // HTTPRESPONSE_H diff --git a/isis/src/base/apps/spiceit/QtWebApp/httpserver/httpserver.pri b/isis/src/base/apps/spiceit/QtWebApp/httpserver/httpserver.pri deleted file mode 100644 index 9bfabd24ec30fbfb19814f25c1f947e8fa96126c..0000000000000000000000000000000000000000 --- a/isis/src/base/apps/spiceit/QtWebApp/httpserver/httpserver.pri +++ /dev/null @@ -1,33 +0,0 @@ -INCLUDEPATH += $$PWD -DEPENDPATH += $$PWD - -QT += network - -# Enable very detailed debug messages when compiling the debug version -CONFIG(debug, debug|release) { - DEFINES += SUPERVERBOSE -} - -HEADERS += $$PWD/httpglobal.h \ - $$PWD/httplistener.h \ - $$PWD/httpconnectionhandler.h \ - $$PWD/httpconnectionhandlerpool.h \ - $$PWD/httprequest.h \ - $$PWD/httpresponse.h \ - $$PWD/httpcookie.h \ - $$PWD/httprequesthandler.h \ - $$PWD/httpsession.h \ - $$PWD/httpsessionstore.h \ - $$PWD/staticfilecontroller.h - -SOURCES += $$PWD/httpglobal.cpp \ - $$PWD/httplistener.cpp \ - $$PWD/httpconnectionhandler.cpp \ - $$PWD/httpconnectionhandlerpool.cpp \ - $$PWD/httprequest.cpp \ - $$PWD/httpresponse.cpp \ - $$PWD/httpcookie.cpp \ - $$PWD/httprequesthandler.cpp \ - $$PWD/httpsession.cpp \ - $$PWD/httpsessionstore.cpp \ - $$PWD/staticfilecontroller.cpp diff --git a/isis/src/base/apps/spiceit/QtWebApp/httpserver/httpsession.cpp b/isis/src/base/apps/spiceit/QtWebApp/httpserver/httpsession.cpp deleted file mode 100644 index 7bcac7f010ee0c0a5791ae2a60362b46a501db07..0000000000000000000000000000000000000000 --- a/isis/src/base/apps/spiceit/QtWebApp/httpserver/httpsession.cpp +++ /dev/null @@ -1,187 +0,0 @@ -/** - @file - @author Stefan Frings -*/ - -#include "httpsession.h" -#include <QDateTime> -#include <QUuid> - -using namespace stefanfrings; - -HttpSession::HttpSession(bool canStore) -{ - if (canStore) - { - dataPtr=new HttpSessionData(); - dataPtr->refCount=1; - dataPtr->lastAccess=QDateTime::currentMSecsSinceEpoch(); - dataPtr->id=QUuid::createUuid().toString().toLocal8Bit(); -#ifdef SUPERVERBOSE - qDebug("HttpSession: created new session data with id %s",dataPtr->id.data()); -#endif - } - else - { - dataPtr=0; - } -} - -HttpSession::HttpSession(const HttpSession& other) -{ - dataPtr=other.dataPtr; - if (dataPtr) - { - dataPtr->lock.lockForWrite(); - dataPtr->refCount++; -#ifdef SUPERVERBOSE - qDebug("HttpSession: refCount of %s is %i",dataPtr->id.data(),dataPtr->refCount); -#endif - dataPtr->lock.unlock(); - } -} - -HttpSession& HttpSession::operator= (const HttpSession& other) -{ - HttpSessionData* oldPtr=dataPtr; - dataPtr=other.dataPtr; - if (dataPtr) - { - dataPtr->lock.lockForWrite(); - dataPtr->refCount++; -#ifdef SUPERVERBOSE - qDebug("HttpSession: refCount of %s is %i",dataPtr->id.data(),dataPtr->refCount); -#endif - dataPtr->lastAccess=QDateTime::currentMSecsSinceEpoch(); - dataPtr->lock.unlock(); - } - if (oldPtr) - { - int refCount; - oldPtr->lock.lockForRead(); - refCount=oldPtr->refCount--; -#ifdef SUPERVERBOSE - qDebug("HttpSession: refCount of %s is %i",oldPtr->id.data(),oldPtr->refCount); -#endif - oldPtr->lock.unlock(); - if (refCount==0) - { - delete oldPtr; - } - } - return *this; -} - -HttpSession::~HttpSession() -{ - if (dataPtr) { - int refCount; - dataPtr->lock.lockForRead(); - refCount=--dataPtr->refCount; -#ifdef SUPERVERBOSE - qDebug("HttpSession: refCount of %s is %i",dataPtr->id.data(),dataPtr->refCount); -#endif - dataPtr->lock.unlock(); - if (refCount==0) - { - qDebug("HttpSession: deleting data"); - delete dataPtr; - } - } -} - - -QByteArray HttpSession::getId() const -{ - if (dataPtr) - { - return dataPtr->id; - } - else - { - return QByteArray(); - } -} - -bool HttpSession::isNull() const { - return dataPtr==0; -} - -void HttpSession::set(const QByteArray& key, const QVariant& value) -{ - if (dataPtr) - { - dataPtr->lock.lockForWrite(); - dataPtr->values.insert(key,value); - dataPtr->lock.unlock(); - } -} - -void HttpSession::remove(const QByteArray& key) -{ - if (dataPtr) - { - dataPtr->lock.lockForWrite(); - dataPtr->values.remove(key); - dataPtr->lock.unlock(); - } -} - -QVariant HttpSession::get(const QByteArray& key) const -{ - QVariant value; - if (dataPtr) - { - dataPtr->lock.lockForRead(); - value=dataPtr->values.value(key); - dataPtr->lock.unlock(); - } - return value; -} - -bool HttpSession::contains(const QByteArray& key) const -{ - bool found=false; - if (dataPtr) - { - dataPtr->lock.lockForRead(); - found=dataPtr->values.contains(key); - dataPtr->lock.unlock(); - } - return found; -} - -QMap<QByteArray,QVariant> HttpSession::getAll() const -{ - QMap<QByteArray,QVariant> values; - if (dataPtr) - { - dataPtr->lock.lockForRead(); - values=dataPtr->values; - dataPtr->lock.unlock(); - } - return values; -} - -qint64 HttpSession::getLastAccess() const -{ - qint64 value=0; - if (dataPtr) - { - dataPtr->lock.lockForRead(); - value=dataPtr->lastAccess; - dataPtr->lock.unlock(); - } - return value; -} - - -void HttpSession::setLastAccess() -{ - if (dataPtr) - { - dataPtr->lock.lockForRead(); - dataPtr->lastAccess=QDateTime::currentMSecsSinceEpoch(); - dataPtr->lock.unlock(); - } -} diff --git a/isis/src/base/apps/spiceit/QtWebApp/httpserver/httpsession.h b/isis/src/base/apps/spiceit/QtWebApp/httpserver/httpsession.h deleted file mode 100644 index e303eb1ef199dfb3c04a3315ff1386536e4255c8..0000000000000000000000000000000000000000 --- a/isis/src/base/apps/spiceit/QtWebApp/httpserver/httpsession.h +++ /dev/null @@ -1,122 +0,0 @@ -/** - @file - @author Stefan Frings -*/ - -#ifndef HTTPSESSION_H -#define HTTPSESSION_H - -#include <QByteArray> -#include <QVariant> -#include <QReadWriteLock> -#include "httpglobal.h" - -namespace stefanfrings { - -/** - This class stores data for a single HTTP session. - A session can store any number of key/value pairs. This class uses implicit - sharing for read and write access. This class is thread safe. - @see HttpSessionStore should be used to create and get instances of this class. -*/ - -class DECLSPEC HttpSession { - -public: - - /** - Constructor. - @param canStore The session can store data, if this parameter is true. - Otherwise all calls to set() and remove() do not have any effect. - */ - HttpSession(bool canStore=false); - - /** - Copy constructor. Creates another HttpSession object that shares the - data of the other object. - */ - HttpSession(const HttpSession& other); - - /** - Copy operator. Detaches from the current shared data and attaches to - the data of the other object. - */ - HttpSession& operator= (const HttpSession& other); - - - /** - Destructor. Detaches from the shared data. - */ - virtual ~HttpSession(); - - /** Get the unique ID of this session. This method is thread safe. */ - QByteArray getId() const; - - /** - Null sessions cannot store data. All calls to set() and remove() - do not have any effect.This method is thread safe. - */ - bool isNull() const; - - /** Set a value. This method is thread safe. */ - void set(const QByteArray& key, const QVariant& value); - - /** Remove a value. This method is thread safe. */ - void remove(const QByteArray& key); - - /** Get a value. This method is thread safe. */ - QVariant get(const QByteArray& key) const; - - /** Check if a key exists. This method is thread safe. */ - bool contains(const QByteArray& key) const; - - /** - Get a copy of all data stored in this session. - Changes to the session do not affect the copy and vice versa. - This method is thread safe. - */ - QMap<QByteArray,QVariant> getAll() const; - - /** - Get the timestamp of last access. That is the time when the last - HttpSessionStore::getSession() has been called. - This method is thread safe. - */ - qint64 getLastAccess() const; - - /** - Set the timestamp of last access, to renew the timeout period. - Called by HttpSessionStore::getSession(). - This method is thread safe. - */ - void setLastAccess(); - -private: - - struct HttpSessionData { - - /** Unique ID */ - QByteArray id; - - /** Timestamp of last access, set by the HttpSessionStore */ - qint64 lastAccess; - - /** Reference counter */ - int refCount; - - /** Used to synchronize threads */ - QReadWriteLock lock; - - /** Storage for the key/value pairs; */ - QMap<QByteArray,QVariant> values; - - }; - - /** Pointer to the shared data. */ - HttpSessionData* dataPtr; - -}; - -} // end of namespace - -#endif // HTTPSESSION_H diff --git a/isis/src/base/apps/spiceit/QtWebApp/httpserver/httpsessionstore.cpp b/isis/src/base/apps/spiceit/QtWebApp/httpserver/httpsessionstore.cpp deleted file mode 100644 index 79e99c851e422860cb4568f10813b07ddf0f9d47..0000000000000000000000000000000000000000 --- a/isis/src/base/apps/spiceit/QtWebApp/httpserver/httpsessionstore.cpp +++ /dev/null @@ -1,127 +0,0 @@ -/** - @file - @author Stefan Frings -*/ - -#include "httpsessionstore.h" -#include <QDateTime> -#include <QUuid> - -using namespace stefanfrings; - -HttpSessionStore::HttpSessionStore(QSettings* settings, QObject* parent) - :QObject(parent) -{ - this->settings=settings; - connect(&cleanupTimer,SIGNAL(timeout()),this,SLOT(sessionTimerEvent())); - cleanupTimer.start(60000); - cookieName=settings->value("cookieName","sessionid").toByteArray(); - expirationTime=settings->value("expirationTime",3600000).toInt(); - qDebug("HttpSessionStore: Sessions expire after %i milliseconds",expirationTime); -} - -HttpSessionStore::~HttpSessionStore() -{ - cleanupTimer.stop(); -} - -QByteArray HttpSessionStore::getSessionId(HttpRequest& request, HttpResponse& response) -{ - // The session ID in the response has priority because this one will be used in the next request. - mutex.lock(); - // Get the session ID from the response cookie - QByteArray sessionId=response.getCookies().value(cookieName).getValue(); - if (sessionId.isEmpty()) - { - // Get the session ID from the request cookie - sessionId=request.getCookie(cookieName); - } - // Clear the session ID if there is no such session in the storage. - if (!sessionId.isEmpty()) - { - if (!sessions.contains(sessionId)) - { - qDebug("HttpSessionStore: received invalid session cookie with ID %s",sessionId.data()); - sessionId.clear(); - } - } - mutex.unlock(); - return sessionId; -} - -HttpSession HttpSessionStore::getSession(HttpRequest& request, HttpResponse& response, bool allowCreate) -{ - QByteArray sessionId=getSessionId(request,response); - mutex.lock(); - if (!sessionId.isEmpty()) - { - HttpSession session=sessions.value(sessionId); - if (!session.isNull()) - { - mutex.unlock(); - // Refresh the session cookie - QByteArray cookieName=settings->value("cookieName","sessionid").toByteArray(); - QByteArray cookiePath=settings->value("cookiePath").toByteArray(); - QByteArray cookieComment=settings->value("cookieComment").toByteArray(); - QByteArray cookieDomain=settings->value("cookieDomain").toByteArray(); - response.setCookie(HttpCookie(cookieName,session.getId(),expirationTime/1000,cookiePath,cookieComment,cookieDomain)); - session.setLastAccess(); - return session; - } - } - // Need to create a new session - if (allowCreate) - { - QByteArray cookieName=settings->value("cookieName","sessionid").toByteArray(); - QByteArray cookiePath=settings->value("cookiePath").toByteArray(); - QByteArray cookieComment=settings->value("cookieComment").toByteArray(); - QByteArray cookieDomain=settings->value("cookieDomain").toByteArray(); - HttpSession session(true); - qDebug("HttpSessionStore: create new session with ID %s",session.getId().data()); - sessions.insert(session.getId(),session); - response.setCookie(HttpCookie(cookieName,session.getId(),expirationTime/1000,cookiePath,cookieComment,cookieDomain)); - mutex.unlock(); - return session; - } - // Return a null session - mutex.unlock(); - return HttpSession(); -} - -HttpSession HttpSessionStore::getSession(const QByteArray id) -{ - mutex.lock(); - HttpSession session=sessions.value(id); - mutex.unlock(); - session.setLastAccess(); - return session; -} - -void HttpSessionStore::sessionTimerEvent() -{ - mutex.lock(); - qint64 now=QDateTime::currentMSecsSinceEpoch(); - QMap<QByteArray,HttpSession>::iterator i = sessions.begin(); - while (i != sessions.end()) - { - QMap<QByteArray,HttpSession>::iterator prev = i; - ++i; - HttpSession session=prev.value(); - qint64 lastAccess=session.getLastAccess(); - if (now-lastAccess>expirationTime) - { - qDebug("HttpSessionStore: session %s expired",session.getId().data()); - sessions.erase(prev); - } - } - mutex.unlock(); -} - - -/** Delete a session */ -void HttpSessionStore::removeSession(HttpSession session) -{ - mutex.lock(); - sessions.remove(session.getId()); - mutex.unlock(); -} diff --git a/isis/src/base/apps/spiceit/QtWebApp/httpserver/httpsessionstore.h b/isis/src/base/apps/spiceit/QtWebApp/httpserver/httpsessionstore.h deleted file mode 100644 index 1d0d5ca865a1ae4b735db010a9469ea916804a5c..0000000000000000000000000000000000000000 --- a/isis/src/base/apps/spiceit/QtWebApp/httpserver/httpsessionstore.h +++ /dev/null @@ -1,110 +0,0 @@ -/** - @file - @author Stefan Frings -*/ - -#ifndef HTTPSESSIONSTORE_H -#define HTTPSESSIONSTORE_H - -#include <QObject> -#include <QMap> -#include <QTimer> -#include <QMutex> -#include "httpglobal.h" -#include "httpsession.h" -#include "httpresponse.h" -#include "httprequest.h" - -namespace stefanfrings { - -/** - Stores HTTP sessions and deletes them when they have expired. - The following configuration settings are required in the config file: - <code><pre> - expirationTime=3600000 - cookieName=sessionid - </pre></code> - The following additional configurations settings are optionally: - <code><pre> - cookiePath=/ - cookieComment=Session ID - ;cookieDomain=stefanfrings.de - </pre></code> -*/ - -class DECLSPEC HttpSessionStore : public QObject { - Q_OBJECT - Q_DISABLE_COPY(HttpSessionStore) -public: - - /** Constructor. */ - HttpSessionStore(QSettings* settings, QObject* parent=NULL); - - /** Destructor */ - virtual ~HttpSessionStore(); - - /** - Get the ID of the current HTTP session, if it is valid. - This method is thread safe. - @warning Sessions may expire at any time, so subsequent calls of - getSession() might return a new session with a different ID. - @param request Used to get the session cookie - @param response Used to get and set the new session cookie - @return Empty string, if there is no valid session. - */ - QByteArray getSessionId(HttpRequest& request, HttpResponse& response); - - /** - Get the session of a HTTP request, eventually create a new one. - This method is thread safe. New sessions can only be created before - the first byte has been written to the HTTP response. - @param request Used to get the session cookie - @param response Used to get and set the new session cookie - @param allowCreate can be set to false, to disable the automatic creation of a new session. - @return If autoCreate is disabled, the function returns a null session if there is no session. - @see HttpSession::isNull() - */ - HttpSession getSession(HttpRequest& request, HttpResponse& response, bool allowCreate=true); - - /** - Get a HTTP session by it's ID number. - This method is thread safe. - @return If there is no such session, the function returns a null session. - @param id ID number of the session - @see HttpSession::isNull() - */ - HttpSession getSession(const QByteArray id); - - /** Delete a session */ - void removeSession(HttpSession session); - -protected: - /** Storage for the sessions */ - QMap<QByteArray,HttpSession> sessions; - -private: - - /** Configuration settings */ - QSettings* settings; - - /** Timer to remove expired sessions */ - QTimer cleanupTimer; - - /** Name of the session cookie */ - QByteArray cookieName; - - /** Time when sessions expire (in ms)*/ - int expirationTime; - - /** Used to synchronize threads */ - QMutex mutex; - -private slots: - - /** Called every minute to cleanup expired sessions. */ - void sessionTimerEvent(); -}; - -} // end of namespace - -#endif // HTTPSESSIONSTORE_H diff --git a/isis/src/base/apps/spiceit/QtWebApp/httpserver/staticfilecontroller.cpp b/isis/src/base/apps/spiceit/QtWebApp/httpserver/staticfilecontroller.cpp deleted file mode 100644 index e6195766d3f206c3f02213ed92d4993943585773..0000000000000000000000000000000000000000 --- a/isis/src/base/apps/spiceit/QtWebApp/httpserver/staticfilecontroller.cpp +++ /dev/null @@ -1,187 +0,0 @@ -/** - @file - @author Stefan Frings -*/ - -#include "staticfilecontroller.h" -#include <QFileInfo> -#include <QDir> -#include <QDateTime> - -using namespace stefanfrings; - -StaticFileController::StaticFileController(QSettings* settings, QObject* parent) - :HttpRequestHandler(parent) -{ - maxAge=settings->value("maxAge","60000").toInt(); - encoding=settings->value("encoding","UTF-8").toString(); - docroot=settings->value("path",".").toString(); - if(!(docroot.startsWith(":/") || docroot.startsWith("qrc://"))) - { - // Convert relative path to absolute, based on the directory of the config file. - #ifdef Q_OS_WIN32 - if (QDir::isRelativePath(docroot) && settings->format()!=QSettings::NativeFormat) - #else - if (QDir::isRelativePath(docroot)) - #endif - { - QFileInfo configFile(settings->fileName()); - docroot=QFileInfo(configFile.absolutePath(),docroot).absoluteFilePath(); - } - } - qDebug("StaticFileController: docroot=%s, encoding=%s, maxAge=%i",qPrintable(docroot),qPrintable(encoding),maxAge); - maxCachedFileSize=settings->value("maxCachedFileSize","65536").toInt(); - cache.setMaxCost(settings->value("cacheSize","1000000").toInt()); - cacheTimeout=settings->value("cacheTime","60000").toInt(); - qDebug("StaticFileController: cache timeout=%i, size=%i",cacheTimeout,cache.maxCost()); -} - - -void StaticFileController::service(HttpRequest& request, HttpResponse& response) -{ - QByteArray path=request.getPath(); - // Check if we have the file in cache - qint64 now=QDateTime::currentMSecsSinceEpoch(); - mutex.lock(); - CacheEntry* entry=cache.object(path); - if (entry && (cacheTimeout==0 || entry->created>now-cacheTimeout)) - { - QByteArray document=entry->document; //copy the cached document, because other threads may destroy the cached entry immediately after mutex unlock. - QByteArray filename=entry->filename; - mutex.unlock(); - qDebug("StaticFileController: Cache hit for %s",path.data()); - setContentType(filename,response); - response.setHeader("Cache-Control","max-age="+QByteArray::number(maxAge/1000)); - response.write(document); - } - else - { - mutex.unlock(); - // The file is not in cache. - qDebug("StaticFileController: Cache miss for %s",path.data()); - // Forbid access to files outside the docroot directory - if (path.contains("/..")) - { - qWarning("StaticFileController: detected forbidden characters in path %s",path.data()); - response.setStatus(403,"forbidden"); - response.write("403 forbidden",true); - return; - } - // If the filename is a directory, append index.html. - if (QFileInfo(docroot+path).isDir()) - { - path+="/index.html"; - } - // Try to open the file - QFile file(docroot+path); - qDebug("StaticFileController: Open file %s",qPrintable(file.fileName())); - if (file.open(QIODevice::ReadOnly)) - { - setContentType(path,response); - response.setHeader("Cache-Control","max-age="+QByteArray::number(maxAge/1000)); - if (file.size()<=maxCachedFileSize) - { - // Return the file content and store it also in the cache - entry=new CacheEntry(); - while (!file.atEnd() && !file.error()) - { - QByteArray buffer=file.read(65536); - response.write(buffer); - entry->document.append(buffer); - } - entry->created=now; - entry->filename=path; - mutex.lock(); - cache.insert(request.getPath(),entry,entry->document.size()); - mutex.unlock(); - } - else - { - // Return the file content, do not store in cache - while (!file.atEnd() && !file.error()) - { - response.write(file.read(65536)); - } - } - file.close(); - } - else { - if (file.exists()) - { - qWarning("StaticFileController: Cannot open existing file %s for reading",qPrintable(file.fileName())); - response.setStatus(403,"forbidden"); - response.write("403 forbidden",true); - } - else - { - response.setStatus(404,"not found"); - response.write("404 not found",true); - } - } - } -} - -void StaticFileController::setContentType(QString fileName, HttpResponse& response) const -{ - if (fileName.endsWith(".png")) - { - response.setHeader("Content-Type", "image/png"); - } - else if (fileName.endsWith(".jpg")) - { - response.setHeader("Content-Type", "image/jpeg"); - } - else if (fileName.endsWith(".gif")) - { - response.setHeader("Content-Type", "image/gif"); - } - else if (fileName.endsWith(".pdf")) - { - response.setHeader("Content-Type", "application/pdf"); - } - else if (fileName.endsWith(".txt")) - { - response.setHeader("Content-Type", qPrintable("text/plain; charset="+encoding)); - } - else if (fileName.endsWith(".html") || fileName.endsWith(".htm")) - { - response.setHeader("Content-Type", qPrintable("text/html; charset="+encoding)); - } - else if (fileName.endsWith(".css")) - { - response.setHeader("Content-Type", "text/css"); - } - else if (fileName.endsWith(".js")) - { - response.setHeader("Content-Type", "text/javascript"); - } - else if (fileName.endsWith(".svg")) - { - response.setHeader("Content-Type", "image/svg+xml"); - } - else if (fileName.endsWith(".woff")) - { - response.setHeader("Content-Type", "font/woff"); - } - else if (fileName.endsWith(".woff2")) - { - response.setHeader("Content-Type", "font/woff2"); - } - else if (fileName.endsWith(".ttf")) - { - response.setHeader("Content-Type", "application/x-font-ttf"); - } - else if (fileName.endsWith(".eot")) - { - response.setHeader("Content-Type", "application/vnd.ms-fontobject"); - } - else if (fileName.endsWith(".otf")) - { - response.setHeader("Content-Type", "application/font-otf"); - } - // Todo: add all of your content types - else - { - qDebug("StaticFileController: unknown MIME type for filename '%s'", qPrintable(fileName)); - } -} diff --git a/isis/src/base/apps/spiceit/QtWebApp/httpserver/staticfilecontroller.h b/isis/src/base/apps/spiceit/QtWebApp/httpserver/staticfilecontroller.h deleted file mode 100644 index 6b2bd1c7a2105aea4ebfbd5651694defec281afc..0000000000000000000000000000000000000000 --- a/isis/src/base/apps/spiceit/QtWebApp/httpserver/staticfilecontroller.h +++ /dev/null @@ -1,91 +0,0 @@ -/** - @file - @author Stefan Frings -*/ - -#ifndef STATICFILECONTROLLER_H -#define STATICFILECONTROLLER_H - -#include <QCache> -#include <QMutex> -#include "httpglobal.h" -#include "httprequest.h" -#include "httpresponse.h" -#include "httprequesthandler.h" - -namespace stefanfrings { - -/** - Delivers static files. It is usually called by the applications main request handler when - the caller requests a path that is mapped to static files. - <p> - The following settings are required in the config file: - <code><pre> - path=../docroot - encoding=UTF-8 - maxAge=60000 - cacheTime=60000 - cacheSize=1000000 - maxCachedFileSize=65536 - </pre></code> - The path is relative to the directory of the config file. In case of windows, if the - settings are in the registry, the path is relative to the current working directory. - <p> - The encoding is sent to the web browser in case of text and html files. - <p> - The cache improves performance of small files when loaded from a network - drive. Large files are not cached. Files are cached as long as possible, - when cacheTime=0. The maxAge value (in msec!) controls the remote browsers cache. - <p> - Do not instantiate this class in each request, because this would make the file cache - useless. Better create one instance during start-up and call it when the application - received a related HTTP request. -*/ - -class DECLSPEC StaticFileController : public HttpRequestHandler { - Q_OBJECT - Q_DISABLE_COPY(StaticFileController) -public: - - /** Constructor */ - StaticFileController(QSettings* settings, QObject* parent = NULL); - - /** Generates the response */ - void service(HttpRequest& request, HttpResponse& response); - -private: - - /** Encoding of text files */ - QString encoding; - - /** Root directory of documents */ - QString docroot; - - /** Maximum age of files in the browser cache */ - int maxAge; - - struct CacheEntry { - QByteArray document; - qint64 created; - QByteArray filename; - }; - - /** Timeout for each cached file */ - int cacheTimeout; - - /** Maximum size of files in cache, larger files are not cached */ - int maxCachedFileSize; - - /** Cache storage */ - QCache<QString,CacheEntry> cache; - - /** Used to synchronize cache access for threads */ - QMutex mutex; - - /** Set a content-type header in the response depending on the ending of the filename */ - void setContentType(QString file, HttpResponse& response) const; -}; - -} // end of namespace - -#endif // STATICFILECONTROLLER_H diff --git a/isis/src/base/apps/spiceit/QtWebApp/logging/dualfilelogger.cpp b/isis/src/base/apps/spiceit/QtWebApp/logging/dualfilelogger.cpp deleted file mode 100644 index b8d5834471e559de528aa49624cd8e49a2597480..0000000000000000000000000000000000000000 --- a/isis/src/base/apps/spiceit/QtWebApp/logging/dualfilelogger.cpp +++ /dev/null @@ -1,27 +0,0 @@ -/** - @file - @author Stefan Frings -*/ - -#include "dualfilelogger.h" - -using namespace stefanfrings; - -DualFileLogger::DualFileLogger(QSettings* firstSettings, QSettings* secondSettings, const int refreshInterval, QObject* parent) - :Logger(parent) -{ - firstLogger=new FileLogger(firstSettings, refreshInterval, this); - secondLogger=new FileLogger(secondSettings, refreshInterval, this); -} - -void DualFileLogger::log(const QtMsgType type, const QString& message, const QString &file, const QString &function, const int line) -{ - firstLogger->log(type,message,file,function,line); - secondLogger->log(type,message,file,function,line); -} - -void DualFileLogger::clear(const bool buffer, const bool variables) -{ - firstLogger->clear(buffer,variables); - secondLogger->clear(buffer,variables); -} diff --git a/isis/src/base/apps/spiceit/QtWebApp/logging/dualfilelogger.h b/isis/src/base/apps/spiceit/QtWebApp/logging/dualfilelogger.h deleted file mode 100644 index ef055ab100ab3e1e7f3c43f654190e241824b16d..0000000000000000000000000000000000000000 --- a/isis/src/base/apps/spiceit/QtWebApp/logging/dualfilelogger.h +++ /dev/null @@ -1,74 +0,0 @@ -/** - @file - @author Stefan Frings -*/ - -#ifndef DUALFILELOGGER_H -#define DUALFILELOGGER_H - -#include <QString> -#include <QSettings> -#include <QtGlobal> -#include "logglobal.h" -#include "logger.h" -#include "filelogger.h" - -namespace stefanfrings { - -/** - Logs messages into two log files simultaneously. - May be used to create two logfiles with different configuration settings. - @see FileLogger for a description of the two underlying loggers. -*/ - -class DECLSPEC DualFileLogger : public Logger { - Q_OBJECT - Q_DISABLE_COPY(DualFileLogger) -public: - - /** - Constructor. - @param firstSettings Configuration settings for the first log file, usually stored in an INI file. - Must not be 0. - Settings are read from the current group, so the caller must have called settings->beginGroup(). - Because the group must not change during runtime, it is recommended to provide a - separate QSettings instance to the logger that is not used by other parts of the program. - @param secondSettings Same as firstSettings, but for the second log file. - @param refreshInterval Interval of checking for changed config settings in msec, or 0=disabled - @param parent Parent object. - */ - DualFileLogger(QSettings* firstSettings, QSettings* secondSettings, const int refreshInterval=10000, QObject *parent = 0); - - /** - Decorate and log the message, if type>=minLevel. - This method is thread safe. - @param type Message type (level) - @param message Message text - @param file Name of the source file where the message was generated (usually filled with the macro __FILE__) - @param function Name of the function where the message was generated (usually filled with the macro __LINE__) - @param line Line Number of the source file, where the message was generated (usually filles with the macro __func__ or __FUNCTION__) - @see LogMessage for a description of the message decoration. - */ - virtual void log(const QtMsgType type, const QString& message, const QString &file="", const QString &function="", const int line=0); - - /** - Clear the thread-local data of the current thread. - This method is thread safe. - @param buffer Whether to clear the backtrace buffer - @param variables Whether to clear the log variables - */ - virtual void clear(const bool buffer=true, const bool variables=true); - -private: - - /** First logger */ - FileLogger* firstLogger; - - /** Second logger */ - FileLogger* secondLogger; - -}; - -} // end of namespace - -#endif // DUALFILELOGGER_H diff --git a/isis/src/base/apps/spiceit/QtWebApp/logging/filelogger.cpp b/isis/src/base/apps/spiceit/QtWebApp/logging/filelogger.cpp deleted file mode 100644 index 3ce1d7acb7938dc802af8ecc039ec2bed7bc09cf..0000000000000000000000000000000000000000 --- a/isis/src/base/apps/spiceit/QtWebApp/logging/filelogger.cpp +++ /dev/null @@ -1,198 +0,0 @@ -/** - @file - @author Stefan Frings -*/ - -#include "filelogger.h" -#include <QTime> -#include <QStringList> -#include <QThread> -#include <QtGlobal> -#include <QFile> -#include <QTimerEvent> -#include <QDir> -#include <QFileInfo> -#include <stdio.h> - -using namespace stefanfrings; - -void FileLogger::refreshSettings() -{ - mutex.lock(); - // Save old file name for later comparision with new settings - QString oldFileName=fileName; - - // Load new config settings - settings->sync(); - fileName=settings->value("fileName").toString(); - // Convert relative fileName to absolute, based on the directory of the config file. -#ifdef Q_OS_WIN32 - if (QDir::isRelativePath(fileName) && settings->format()!=QSettings::NativeFormat) -#else - if (QDir::isRelativePath(fileName)) -#endif - { - QFileInfo configFile(settings->fileName()); - fileName=QFileInfo(configFile.absolutePath(),fileName).absoluteFilePath(); - } - maxSize=settings->value("maxSize",0).toLongLong(); - maxBackups=settings->value("maxBackups",0).toInt(); - msgFormat=settings->value("msgFormat","{timestamp} {type} {msg}").toString(); - timestampFormat=settings->value("timestampFormat","yyyy-MM-dd hh:mm:ss.zzz").toString(); - minLevel=static_cast<QtMsgType>(settings->value("minLevel",0).toInt()); - bufferSize=settings->value("bufferSize",0).toInt(); - - // Create new file if the filename has been changed - if (oldFileName!=fileName) - { - fprintf(stderr,"Logging to %s\n",qPrintable(fileName)); - close(); - open(); - } - mutex.unlock(); -} - - -FileLogger::FileLogger(QSettings* settings, const int refreshInterval, QObject* parent) - : Logger(parent) -{ - Q_ASSERT(settings!=0); - Q_ASSERT(refreshInterval>=0); - this->settings=settings; - file=0; - if (refreshInterval>0) - { - refreshTimer.start(refreshInterval,this); - } - flushTimer.start(1000,this); - refreshSettings(); -} - - -FileLogger::~FileLogger() -{ - close(); -} - - -void FileLogger::write(const LogMessage* logMessage) -{ - // Try to write to the file - if (file) - { - - // Write the message - file->write(qPrintable(logMessage->toString(msgFormat,timestampFormat))); - - // Flush error messages immediately, to ensure that no important message - // gets lost when the program terinates abnormally. - if (logMessage->getType()>=QtCriticalMsg) - { - file->flush(); - } - - // Check for success - if (file->error()) - { - close(); - qWarning("Cannot write to log file %s: %s",qPrintable(fileName),qPrintable(file->errorString())); - } - - } - - // Fall-back to the super class method, if writing failed - if (!file) - { - Logger::write(logMessage); - } - -} - -void FileLogger::open() -{ - if (fileName.isEmpty()) - { - qWarning("Name of logFile is empty"); - } - else { - file=new QFile(fileName); - if (!file->open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text)) - { - qWarning("Cannot open log file %s: %s",qPrintable(fileName),qPrintable(file->errorString())); - file=0; - } - } -} - - -void FileLogger::close() -{ - if (file) - { - file->close(); - delete file; - file=0; - } -} - -void FileLogger::rotate() { - // count current number of existing backup files - int count=0; - forever - { - QFile bakFile(QString("%1.%2").arg(fileName).arg(count+1)); - if (bakFile.exists()) - { - ++count; - } - else - { - break; - } - } - - // Remove all old backup files that exceed the maximum number - while (maxBackups>0 && count>=maxBackups) - { - QFile::remove(QString("%1.%2").arg(fileName).arg(count)); - --count; - } - - // Rotate backup files - for (int i=count; i>0; --i) { - QFile::rename(QString("%1.%2").arg(fileName).arg(i),QString("%1.%2").arg(fileName).arg(i+1)); - } - - // Backup the current logfile - QFile::rename(fileName,fileName+".1"); -} - - -void FileLogger::timerEvent(QTimerEvent* event) -{ - if (!event) - { - return; - } - else if (event->timerId()==refreshTimer.timerId()) - { - refreshSettings(); - } - else if (event->timerId()==flushTimer.timerId() && file) - { - mutex.lock(); - - // Flush the I/O buffer - file->flush(); - - // Rotate the file if it is too large - if (maxSize>0 && file->size()>=maxSize) - { - close(); - rotate(); - open(); - } - - mutex.unlock(); - } -} diff --git a/isis/src/base/apps/spiceit/QtWebApp/logging/filelogger.h b/isis/src/base/apps/spiceit/QtWebApp/logging/filelogger.h deleted file mode 100644 index 120e042dd6e91e1c1805845c7bae29b0f4eebb1b..0000000000000000000000000000000000000000 --- a/isis/src/base/apps/spiceit/QtWebApp/logging/filelogger.h +++ /dev/null @@ -1,127 +0,0 @@ -/** - @file - @author Stefan Frings -*/ - -#ifndef FILELOGGER_H -#define FILELOGGER_H - -#include <QtGlobal> -#include <QSettings> -#include <QFile> -#include <QMutex> -#include <QBasicTimer> -#include "logglobal.h" -#include "logger.h" - -namespace stefanfrings { - -/** - Logger that uses a text file for output. Settings are read from a - config file using a QSettings object. Config settings can be changed at runtime. - <p> - Example for the configuration settings: - <code><pre> - fileName=logs/QtWebApp.log - maxSize=1000000 - maxBackups=2 - minLevel=0 - msgformat={timestamp} {typeNr} {type} thread={thread}: {msg} - timestampFormat=dd.MM.yyyy hh:mm:ss.zzz - bufferSize=0 - </pre></code> - - - fileName is the name of the log file, relative to the directory of the settings file. - In case of windows, if the settings are in the registry, the path is relative to the current - working directory. - - maxSize is the maximum size of that file in bytes. The file will be backed up and - replaced by a new file if it becomes larger than this limit. Please note that - the actual file size may become a little bit larger than this limit. Default is 0=unlimited. - - maxBackups defines the number of backup files to keep. Default is 0=unlimited. - - minLevel defines the minimum type of messages that are written (together with buffered messages) into the file. Defaults is 0=debug. - - msgFormat defines the decoration of log messages, see LogMessage class. Default is "{timestamp} {type} {msg}". - - timestampFormat defines the format of timestamps, see QDateTime::toString(). Default is "yyyy-MM-dd hh:mm:ss.zzz". - - bufferSize defines the size of the buffer. Default is 0=disabled. - - @see set() describes how to set logger variables - @see LogMessage for a description of the message decoration. - @see Logger for a descrition of the buffer. -*/ - -class DECLSPEC FileLogger : public Logger { - Q_OBJECT - Q_DISABLE_COPY(FileLogger) -public: - - /** - Constructor. - @param settings Configuration settings, usually stored in an INI file. Must not be 0. - Settings are read from the current group, so the caller must have called settings->beginGroup(). - Because the group must not change during runtime, it is recommended to provide a - separate QSettings instance to the logger that is not used by other parts of the program. - @param refreshInterval Interval of checking for changed config settings in msec, or 0=disabled - @param parent Parent object - */ - FileLogger(QSettings* settings, const int refreshInterval=10000, QObject* parent = 0); - - /** - Destructor. Closes the file. - */ - virtual ~FileLogger(); - - /** Write a message to the log file */ - virtual void write(const LogMessage* logMessage); - -protected: - - /** - Handler for timer events. - Refreshes config settings or synchronizes I/O buffer, depending on the event. - This method is thread-safe. - @param event used to distinguish between the two timers. - */ - void timerEvent(QTimerEvent* event); - -private: - - /** Configured name of the log file */ - QString fileName; - - /** Configured maximum size of the file in bytes, or 0=unlimited */ - long maxSize; - - /** Configured maximum number of backup files, or 0=unlimited */ - int maxBackups; - - /** Pointer to the configuration settings */ - QSettings* settings; - - /** Output file, or 0=disabled */ - QFile* file; - - /** Timer for refreshing configuration settings */ - QBasicTimer refreshTimer; - - /** Timer for flushing the file I/O buffer */ - QBasicTimer flushTimer; - - /** Open the output file */ - void open(); - - /** Close the output file */ - void close(); - - /** Rotate files and delete some backups if there are too many */ - void rotate(); - - /** - Refreshes the configuration settings. - This method is thread-safe. - */ - void refreshSettings(); - -}; - -} // end of namespace - -#endif // FILELOGGER_H diff --git a/isis/src/base/apps/spiceit/QtWebApp/logging/logger.cpp b/isis/src/base/apps/spiceit/QtWebApp/logging/logger.cpp deleted file mode 100644 index aabd84469c24540a4bc36e9edee071a3be80e003..0000000000000000000000000000000000000000 --- a/isis/src/base/apps/spiceit/QtWebApp/logging/logger.cpp +++ /dev/null @@ -1,192 +0,0 @@ -/** - @file - @author Stefan Frings -*/ - -#include "logger.h" -#include <stdio.h> -#include <stdlib.h> -#include <QMutex> -#include <QDateTime> -#include <QThread> -#include <QObject> - -using namespace stefanfrings; - -Logger* Logger::defaultLogger=0; - - -QThreadStorage<QHash<QString,QString>*> Logger::logVars; - - -QMutex Logger::mutex; - - -Logger::Logger(QObject* parent) - : QObject(parent), - msgFormat("{timestamp} {type} {msg}"), - timestampFormat("dd.MM.yyyy hh:mm:ss.zzz"), - minLevel(QtDebugMsg), - bufferSize(0) - {} - - -Logger::Logger(const QString msgFormat, const QString timestampFormat, const QtMsgType minLevel, const int bufferSize, QObject* parent) - :QObject(parent) -{ - this->msgFormat=msgFormat; - this->timestampFormat=timestampFormat; - this->minLevel=minLevel; - this->bufferSize=bufferSize; -} - - -void Logger::msgHandler(const QtMsgType type, const QString &message, const QString &file, const QString &function, const int line) -{ - static QMutex recursiveMutex(QMutex::Recursive); - static QMutex nonRecursiveMutex(QMutex::NonRecursive); - - // Prevent multiple threads from calling this method simultaneoulsy. - // But allow recursive calls, which is required to prevent a deadlock - // if the logger itself produces an error message. - recursiveMutex.lock(); - - // Fall back to stderr when this method has been called recursively. - if (defaultLogger && nonRecursiveMutex.tryLock()) - { - defaultLogger->log(type, message, file, function, line); - nonRecursiveMutex.unlock(); - } - else - { - fputs(qPrintable(message),stderr); - fflush(stderr); - } - - // Abort the program after logging a fatal message - if (type==QtFatalMsg) - { - abort(); - } - - recursiveMutex.unlock(); -} - - -#if QT_VERSION >= 0x050000 - void Logger::msgHandler5(const QtMsgType type, const QMessageLogContext &context, const QString &message) - { - (void)(context); // suppress "unused parameter" warning - msgHandler(type,message,context.file,context.function,context.line); - } -#else - void Logger::msgHandler4(const QtMsgType type, const char* message) - { - msgHandler(type,message); - } -#endif - - -Logger::~Logger() -{ - if (defaultLogger==this) - { -#if QT_VERSION >= 0x050000 - qInstallMessageHandler(0); -#else - qInstallMsgHandler(0); -#endif - defaultLogger=0; - } -} - - -void Logger::write(const LogMessage* logMessage) -{ - fputs(qPrintable(logMessage->toString(msgFormat,timestampFormat)),stderr); - fflush(stderr); -} - - -void Logger::installMsgHandler() -{ - defaultLogger=this; -#if QT_VERSION >= 0x050000 - qInstallMessageHandler(msgHandler5); -#else - qInstallMsgHandler(msgHandler4); -#endif -} - - -void Logger::set(const QString& name, const QString& value) -{ - mutex.lock(); - if (!logVars.hasLocalData()) - { - logVars.setLocalData(new QHash<QString,QString>); - } - logVars.localData()->insert(name,value); - mutex.unlock(); -} - - -void Logger::clear(const bool buffer, const bool variables) -{ - mutex.lock(); - if (buffer && buffers.hasLocalData()) - { - QList<LogMessage*>* buffer=buffers.localData(); - while (buffer && !buffer->isEmpty()) { - LogMessage* logMessage=buffer->takeLast(); - delete logMessage; - } - } - if (variables && logVars.hasLocalData()) - { - logVars.localData()->clear(); - } - mutex.unlock(); -} - - -void Logger::log(const QtMsgType type, const QString& message, const QString &file, const QString &function, const int line) -{ - mutex.lock(); - - // If the buffer is enabled, write the message into it - if (bufferSize>0) { - // Create new thread local buffer, if necessary - if (!buffers.hasLocalData()) { - buffers.setLocalData(new QList<LogMessage*>()); - } - QList<LogMessage*>* buffer=buffers.localData(); - // Append the decorated log message - LogMessage* logMessage=new LogMessage(type,message,logVars.localData(),file,function,line); - buffer->append(logMessage); - // Delete oldest message if the buffer became too large - if (buffer->size()>bufferSize) - { - delete buffer->takeFirst(); - } - // If the type of the message is high enough, print the whole buffer - if (type>=minLevel) { - while (!buffer->isEmpty()) - { - LogMessage* logMessage=buffer->takeFirst(); - write(logMessage); - delete logMessage; - } - } - } - - // Buffer is disabled, print the message if the type is high enough - else { - if (type>=minLevel) - { - LogMessage logMessage(type,message,logVars.localData(),file,function,line); - write(&logMessage); - } - } - mutex.unlock(); -} diff --git a/isis/src/base/apps/spiceit/QtWebApp/logging/logger.h b/isis/src/base/apps/spiceit/QtWebApp/logging/logger.h deleted file mode 100644 index 8d06f95cfb2aa344afde047732afb6031d52e2a2..0000000000000000000000000000000000000000 --- a/isis/src/base/apps/spiceit/QtWebApp/logging/logger.h +++ /dev/null @@ -1,188 +0,0 @@ -/** - @file - @author Stefan Frings -*/ - -#ifndef LOGGER_H -#define LOGGER_H - -#include <QtGlobal> -#include <QThreadStorage> -#include <QHash> -#include <QStringList> -#include <QMutex> -#include <QObject> -#include "logglobal.h" -#include "logmessage.h" - -namespace stefanfrings { - -/** - Decorates and writes log messages to the console, stderr. - <p> - The decorator uses a predefined msgFormat string to enrich log messages - with additional information (e.g. timestamp). - <p> - The msgFormat string and also the message text may contain additional - variable names in the form <i>{name}</i> that are filled by values - taken from a static thread local dictionary. - <p> - The logger keeps a configurable number of messages in a ring-buffer. - A log message with a severity >= minLevel flushes the buffer, - so the stored messages get written out. If the buffer is disabled, then - only messages with severity >= minLevel are written out. - <p> - If you enable the buffer and use minLevel=2, then the application logs - only errors together with some buffered debug messages. But as long no - error occurs, nothing gets written out. - <p> - Each thread has it's own buffer. - <p> - The logger can be registered to handle messages from - the static global functions qDebug(), qWarning(), qCritical() and qFatal(). - - @see set() describes how to set logger variables - @see LogMessage for a description of the message decoration. - @warning You should prefer a derived class, for example FileLogger, - because logging to the console is less useful. -*/ - -class DECLSPEC Logger : public QObject { - Q_OBJECT - Q_DISABLE_COPY(Logger) -public: - - /** - Constructor. - Uses the same defaults as the other constructor. - @param parent Parent object - */ - Logger(QObject* parent); - - - /** - Constructor. - @param msgFormat Format of the decoration, e.g. "{timestamp} {type} thread={thread}: {msg}" - @param timestampFormat Format of timestamp, e.g. "dd.MM.yyyy hh:mm:ss.zzz" - @param minLevel Minimum severity that genertes an output (0=debug, 1=warning, 2=critical, 3=fatal). - @param bufferSize Size of the backtrace buffer, number of messages per thread. 0=disabled. - @param parent Parent object - @see LogMessage for a description of the message decoration. - */ - Logger(const QString msgFormat="{timestamp} {type} {msg}", const QString timestampFormat="dd.MM.yyyy hh:mm:ss.zzz", const QtMsgType minLevel=QtDebugMsg, const int bufferSize=0, QObject* parent = 0); - - /** Destructor */ - virtual ~Logger(); - - /** - Decorate and log the message, if type>=minLevel. - This method is thread safe. - @param type Message type (level) - @param message Message text - @param file Name of the source file where the message was generated (usually filled with the macro __FILE__) - @param function Name of the function where the message was generated (usually filled with the macro __LINE__) - @param line Line Number of the source file, where the message was generated (usually filles with the macro __func__ or __FUNCTION__) - @see LogMessage for a description of the message decoration. - */ - virtual void log(const QtMsgType type, const QString& message, const QString &file="", const QString &function="", const int line=0); - - /** - Installs this logger as the default message handler, so it - can be used through the global static logging functions (e.g. qDebug()). - */ - void installMsgHandler(); - - /** - Sets a thread-local variable that may be used to decorate log messages. - This method is thread safe. - @param name Name of the variable - @param value Value of the variable - */ - static void set(const QString& name, const QString& value); - - /** - Clear the thread-local data of the current thread. - This method is thread safe. - @param buffer Whether to clear the backtrace buffer - @param variables Whether to clear the log variables - */ - virtual void clear(const bool buffer=true, const bool variables=true); - -protected: - - /** Format string for message decoration */ - QString msgFormat; - - /** Format string of timestamps */ - QString timestampFormat; - - /** Minimum level of message types that are written out */ - QtMsgType minLevel; - - /** Size of backtrace buffer, number of messages per thread. 0=disabled */ - int bufferSize; - - /** Used to synchronize access of concurrent threads */ - static QMutex mutex; - - /** - Decorate and write a log message to stderr. Override this method - to provide a different output medium. - */ - virtual void write(const LogMessage* logMessage); - -private: - - /** Pointer to the default logger, used by msgHandler() */ - static Logger* defaultLogger; - - /** - Message Handler for the global static logging functions (e.g. qDebug()). - Forward calls to the default logger. - <p> - In case of a fatal message, the program will abort. - Variables in the in the message are replaced by their values. - This method is thread safe. - @param type Message type (level) - @param message Message text - @param file Name of the source file where the message was generated (usually filled with the macro __FILE__) - @param function Name of the function where the message was generated (usually filled with the macro __LINE__) - @param line Line Number of the source file, where the message was generated (usually filles with the macro __func__ or __FUNCTION__) - */ - static void msgHandler(const QtMsgType type, const QString &message, const QString &file="", const QString &function="", const int line=0); - - -#if QT_VERSION >= 0x050000 - - /** - Wrapper for QT version 5. - @param type Message type (level) - @param context Message context - @param message Message text - @see msgHandler() - */ - static void msgHandler5(const QtMsgType type, const QMessageLogContext& context, const QString &message); - -#else - - /** - Wrapper for QT version 4. - @param type Message type (level) - @param message Message text - @see msgHandler() - */ - static void msgHandler4(const QtMsgType type, const char * message); - -#endif - - /** Thread local variables to be used in log messages */ - static QThreadStorage<QHash<QString,QString>*> logVars; - - /** Thread local backtrace buffers */ - QThreadStorage<QList<LogMessage*>*> buffers; - -}; - -} // end of namespace - -#endif // LOGGER_H diff --git a/isis/src/base/apps/spiceit/QtWebApp/logging/logging.pri b/isis/src/base/apps/spiceit/QtWebApp/logging/logging.pri deleted file mode 100644 index f62338d66ff5b257468f29b249cbe37e0f139f3b..0000000000000000000000000000000000000000 --- a/isis/src/base/apps/spiceit/QtWebApp/logging/logging.pri +++ /dev/null @@ -1,6 +0,0 @@ -INCLUDEPATH += $$PWD -DEPENDPATH += $$PWD - -HEADERS += $$PWD/logglobal.h $$PWD/logmessage.h $$PWD/logger.h $$PWD/filelogger.h $$PWD/dualfilelogger.h - -SOURCES += $$PWD/logmessage.cpp $$PWD/logger.cpp $$PWD/filelogger.cpp $$PWD/dualfilelogger.cpp diff --git a/isis/src/base/apps/spiceit/QtWebApp/logging/logglobal.h b/isis/src/base/apps/spiceit/QtWebApp/logging/logglobal.h deleted file mode 100644 index 5f6261cb325f3a8bb5313ee9810d9b709c66483c..0000000000000000000000000000000000000000 --- a/isis/src/base/apps/spiceit/QtWebApp/logging/logglobal.h +++ /dev/null @@ -1,24 +0,0 @@ -/** - @file - @author Stefan Frings -*/ - -#ifndef LOGGLOBAL_H -#define LOGGLOBAL_H - -#include <QtGlobal> - -// This is specific to Windows dll's -#if defined(Q_OS_WIN) - #if defined(QTWEBAPPLIB_EXPORT) - #define DECLSPEC Q_DECL_EXPORT - #elif defined(QTWEBAPPLIB_IMPORT) - #define DECLSPEC Q_DECL_IMPORT - #endif -#endif -#if !defined(DECLSPEC) - #define DECLSPEC -#endif - -#endif // LOGGLOBAL_H - diff --git a/isis/src/base/apps/spiceit/QtWebApp/logging/logmessage.cpp b/isis/src/base/apps/spiceit/QtWebApp/logging/logmessage.cpp deleted file mode 100644 index 9ef72fb22eaadb0b07c816ea0613da6157d82e72..0000000000000000000000000000000000000000 --- a/isis/src/base/apps/spiceit/QtWebApp/logging/logmessage.cpp +++ /dev/null @@ -1,90 +0,0 @@ -/** - @file - @author Stefan Frings -*/ - -#include "logmessage.h" -#include <QThread> - -using namespace stefanfrings; - -LogMessage::LogMessage(const QtMsgType type, const QString& message, QHash<QString, QString>* logVars, const QString &file, const QString &function, const int line) -{ - this->type=type; - this->message=message; - this->file=file; - this->function=function; - this->line=line; - timestamp=QDateTime::currentDateTime(); - threadId=QThread::currentThreadId(); - - // Copy the logVars if not null, - // so that later changes in the original do not affect the copy - if (logVars) - { - this->logVars=*logVars; - } -} - -QString LogMessage::toString(const QString& msgFormat, const QString& timestampFormat) const -{ - QString decorated=msgFormat+"\n"; - decorated.replace("{msg}",message); - - if (decorated.contains("{timestamp}")) - { - decorated.replace("{timestamp}",timestamp.toString(timestampFormat)); - } - - QString typeNr; - typeNr.setNum(type); - decorated.replace("{typeNr}",typeNr); - - switch (type) - { - case QtDebugMsg: - decorated.replace("{type}","DEBUG "); - break; - case QtWarningMsg: - decorated.replace("{type}","WARNING "); - break; - case QtCriticalMsg: - decorated.replace("{type}","CRITICAL"); - break; - case QtFatalMsg: - decorated.replace("{type}","FATAL "); - break; - #if (QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)) - case QtInfoMsg: - decorated.replace("{type}","INFO "); - break; - #endif - default: - decorated.replace("{type}",typeNr); - } - - decorated.replace("{file}",file); - decorated.replace("{function}",function); - decorated.replace("{line}",QString::number(line)); - - QString threadId; - threadId.setNum((unsigned long)QThread::currentThreadId()); - decorated.replace("{thread}",threadId); - - // Fill in variables - if (decorated.contains("{") && !logVars.isEmpty()) - { - QList<QString> keys=logVars.keys(); - foreach (QString key, keys) - { - decorated.replace("{"+key+"}",logVars.value(key)); - } - } - - return decorated; -} - -QtMsgType LogMessage::getType() const -{ - return type; -} diff --git a/isis/src/base/apps/spiceit/QtWebApp/logging/logmessage.h b/isis/src/base/apps/spiceit/QtWebApp/logging/logmessage.h deleted file mode 100644 index 6f0ea8a1fff6d5f0cd2d27f0ac301e2759ce59e7..0000000000000000000000000000000000000000 --- a/isis/src/base/apps/spiceit/QtWebApp/logging/logmessage.h +++ /dev/null @@ -1,97 +0,0 @@ -/** - @file - @author Stefan Frings -*/ - -#ifndef LOGMESSAGE_H -#define LOGMESSAGE_H - -#include <QtGlobal> -#include <QDateTime> -#include <QHash> -#include "logglobal.h" - -namespace stefanfrings { - -/** - Represents a single log message together with some data - that are used to decorate the log message. - - The following variables may be used in the message and in msgFormat: - - - {timestamp} Date and time of creation - - {typeNr} Type of the message in numeric format (0-3) - - {type} Type of the message in string format (DEBUG, WARNING, CRITICAL, FATAL) - - {thread} ID number of the thread - - {msg} Message text - - {xxx} For any user-defined logger variable - - Plus some new variables since QT 5.0, only filled when compiled in debug mode: - - - {file} Filename where the message was generated - - {function} Function where the message was generated - - {line} Line number where the message was generated -*/ - -class DECLSPEC LogMessage -{ - Q_DISABLE_COPY(LogMessage) -public: - - /** - Constructor. All parameters are copied, so that later changes to them do not - affect this object. - @param type Type of the message - @param message Message text - @param logVars Logger variables, 0 is allowed - @param file Name of the source file where the message was generated - @param function Name of the function where the message was generated - @param line Line Number of the source file, where the message was generated - */ - LogMessage(const QtMsgType type, const QString& message, QHash<QString,QString>* logVars, const QString &file, const QString &function, const int line); - - /** - Returns the log message as decorated string. - @param msgFormat Format of the decoration. May contain variables and static text, - e.g. "{timestamp} {type} thread={thread}: {msg}". - @param timestampFormat Format of timestamp, e.g. "dd.MM.yyyy hh:mm:ss.zzz", see QDateTime::toString(). - @see QDatetime for a description of the timestamp format pattern - */ - QString toString(const QString& msgFormat, const QString& timestampFormat) const; - - /** - Get the message type. - */ - QtMsgType getType() const; - -private: - - /** Logger variables */ - QHash<QString,QString> logVars; - - /** Date and time of creation */ - QDateTime timestamp; - - /** Type of the message */ - QtMsgType type; - - /** ID number of the thread */ - Qt::HANDLE threadId; - - /** Message text */ - QString message; - - /** Filename where the message was generated */ - QString file; - - /** Function name where the message was generated */ - QString function; - - /** Line number where the message was generated */ - int line; - -}; - -} // end of namespace - -#endif // LOGMESSAGE_H diff --git a/isis/src/base/apps/spiceit/QtWebApp/mainpage.dox b/isis/src/base/apps/spiceit/QtWebApp/mainpage.dox deleted file mode 100644 index 87a1757ab19ade1f22921fdfe0ce8fe5be653395..0000000000000000000000000000000000000000 --- a/isis/src/base/apps/spiceit/QtWebApp/mainpage.dox +++ /dev/null @@ -1,40 +0,0 @@ -/** - @mainpage - @author Stefan Frings - QtWebApp supports you in writing server-side web application in C++ - based on the Qt toolkit. It is a light-weight implementation inspired - by Java Servlets. - <p> - Features: - - - HttpListener is a HTTP 1.1 web server with support for - - HTTPS - - IP v4 and IP v6 - - persistent connections - - pipelining - - file uploads - - cookies - - dynamic thread pool - - optional file cache in StaticFileController - - optional sessions via HttpSessionStore - - The Template engine supports - - multi languages via TemplateLoader - - optional file cache via TemplateCache - - for all text based file formats - - The Logger classes provide - - automatic backups and file rotation - - configurable message format, see LogMessage - - messages may contain thread-local info variables - - optional ring-buffer for writing debug messages in case of errors - - they are configurable at runtime without program restart - - The QtService class - - Runs the application as a Windows service or Unix daemon - - If you write a real application based on this source, take a look into the Demo - applications. They set up a single listener on port 8080, however multiple - listeners with individual configurations are also possible. - <p> - To set up a HA system with loadsharing and/or failover, I recommend an Apache HTTP - server with mod_proxy and sticky sessions -*/ - diff --git a/isis/src/base/apps/spiceit/QtWebApp/qtservice/QtServiceBase b/isis/src/base/apps/spiceit/QtWebApp/qtservice/QtServiceBase deleted file mode 100644 index 57e17a52e92b364479f4a77ab33de2df6acc1bce..0000000000000000000000000000000000000000 --- a/isis/src/base/apps/spiceit/QtWebApp/qtservice/QtServiceBase +++ /dev/null @@ -1 +0,0 @@ -#include "qtservice.h" diff --git a/isis/src/base/apps/spiceit/QtWebApp/qtservice/QtServiceController b/isis/src/base/apps/spiceit/QtWebApp/qtservice/QtServiceController deleted file mode 100644 index 57e17a52e92b364479f4a77ab33de2df6acc1bce..0000000000000000000000000000000000000000 --- a/isis/src/base/apps/spiceit/QtWebApp/qtservice/QtServiceController +++ /dev/null @@ -1 +0,0 @@ -#include "qtservice.h" diff --git a/isis/src/base/apps/spiceit/QtWebApp/qtservice/qtservice.cpp b/isis/src/base/apps/spiceit/QtWebApp/qtservice/qtservice.cpp deleted file mode 100644 index 94f9efdca36b1b530f82e3cb3bb9dd3c3197c34d..0000000000000000000000000000000000000000 --- a/isis/src/base/apps/spiceit/QtWebApp/qtservice/qtservice.cpp +++ /dev/null @@ -1,1112 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the Qt Solutions component. -** -** $QT_BEGIN_LICENSE:BSD$ -** You may use this file under the terms of the BSD license as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names -** of its contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qtservice.h" -#include "qtservice_p.h" -#include <QCoreApplication> -#include <stdio.h> -#include <QTimer> -#include <QVector> -#include <QProcess> - -#if defined(QTSERVICE_DEBUG) -#include <QDebug> -#include <QFile> -#include <QTime> -#include <QMutex> -#if defined(Q_OS_WIN32) -#include <qt_windows.h> -#else -#include <unistd.h> -#include <stdlib.h> -#endif - -static QFile* f = 0; - -static void qtServiceCloseDebugLog() -{ - if (!f) - return; - QString ps(QTime::currentTime().toString("HH:mm:ss.zzz ") + QLatin1String("--- DEBUG LOG CLOSED ---\n\n")); - f->write(ps.toLatin1()); - f->flush(); - f->close(); - delete f; - f = 0; -} - -void qtServiceLogDebug(QtMsgType type, const char* msg) -{ - static QMutex mutex; - QMutexLocker locker(&mutex); - QString s(QTime::currentTime().toString("HH:mm:ss.zzz ")); - s += QString("[%1] ").arg( -#if defined(Q_OS_WIN32) - GetCurrentProcessId()); -#else - getpid()); -#endif - - if (!f) { -#if defined(Q_OS_WIN32) - f = new QFile("c:/service-debuglog.txt"); -#else - f = new QFile("/tmp/service-debuglog.txt"); -#endif - if (!f->open(QIODevice::WriteOnly | QIODevice::Append)) { - delete f; - f = 0; - return; - } - QString ps(QLatin1String("\n") + s + QLatin1String("--- DEBUG LOG OPENED ---\n")); - f->write(ps.toLatin1()); - } - - switch (type) { - case QtWarningMsg: - s += QLatin1String("WARNING: "); - break; - case QtCriticalMsg: - s += QLatin1String("CRITICAL: "); - break; - case QtFatalMsg: - s+= QLatin1String("FATAL: "); - break; - case QtDebugMsg: - s += QLatin1String("DEBUG: "); - break; - default: - // Nothing - break; - } - - s += msg; - s += QLatin1String("\n"); - - f->write(s.toLatin1()); - f->flush(); - - if (type == QtFatalMsg) { - qtServiceCloseDebugLog(); - exit(1); - } -} - -#endif - -/*! - \class QtServiceController - - \brief The QtServiceController class allows you to control - services from separate applications. - - QtServiceController provides a collection of functions that lets - you install and run a service controlling its execution, as well - as query its status. - - In order to run a service, the service must be installed in the - system's service database using the install() function. The system - will start the service depending on the specified StartupType; it - can either be started during system startup, or when a process - starts it manually. - - Once a service is installed, the service can be run and controlled - manually using the start(), stop(), pause(), resume() or - sendCommand() functions. You can at any time query for the - service's status using the isInstalled() and isRunning() - functions, or you can query its properties using the - serviceDescription(), serviceFilePath(), serviceName() and - startupType() functions. For example: - - \code - MyService service; \\ which inherits QtService - QString serviceFilePath; - - QtServiceController controller(service.serviceName()); - - if (controller.install(serviceFilePath)) - controller.start() - - if (controller.isRunning()) - QMessageBox::information(this, tr("Service Status"), - tr("The %1 service is started").arg(controller.serviceName())); - - ... - - controller.stop(); - controller.uninstall(); - } - \endcode - - An instance of the service controller can only control one single - service. To control several services within one application, you - must create en equal number of service controllers. - - The QtServiceController destructor neither stops nor uninstalls - the associated service. To stop a service the stop() function must - be called explicitly. To uninstall a service, you can use the - uninstall() function. - - \sa QtServiceBase, QtService -*/ - -/*! - \enum QtServiceController::StartupType - This enum describes when a service should be started. - - \value AutoStartup The service is started during system startup. - \value ManualStartup The service must be started manually by a process. - - \warning The \a StartupType enum is ignored under UNIX-like - systems. A service, or daemon, can only be started manually on such - systems with current implementation. - - \sa startupType() -*/ - - -/*! - Creates a controller object for the service with the given - \a name. -*/ -QtServiceController::QtServiceController(const QString &name) - : d_ptr(new QtServiceControllerPrivate()) -{ - Q_D(QtServiceController); - d->q_ptr = this; - d->serviceName = name; -} -/*! - Destroys the service controller. This neither stops nor uninstalls - the controlled service. - - To stop a service the stop() function must be called - explicitly. To uninstall a service, you can use the uninstall() - function. - - \sa stop(), QtServiceController::uninstall() -*/ -QtServiceController::~QtServiceController() -{ - delete d_ptr; -} -/*! - \fn bool QtServiceController::isInstalled() const - - Returns true if the service is installed; otherwise returns false. - - On Windows it uses the system's service control manager. - - On Unix it checks configuration written to QSettings::SystemScope - using "QtSoftware" as organization name. - - \sa install() -*/ - -/*! - \fn bool QtServiceController::isRunning() const - - Returns true if the service is running; otherwise returns false. A - service must be installed before it can be run using a controller. - - \sa start(), isInstalled() -*/ - -/*! - Returns the name of the controlled service. - - \sa QtServiceController(), serviceDescription() -*/ -QString QtServiceController::serviceName() const -{ - Q_D(const QtServiceController); - return d->serviceName; -} -/*! - \fn QString QtServiceController::serviceDescription() const - - Returns the description of the controlled service. - - \sa install(), serviceName() -*/ - -/*! - \fn QtServiceController::StartupType QtServiceController::startupType() const - - Returns the startup type of the controlled service. - - \sa install(), serviceName() -*/ - -/*! - \fn QString QtServiceController::serviceFilePath() const - - Returns the file path to the controlled service. - - \sa install(), serviceName() -*/ - -/*! - Installs the service with the given \a serviceFilePath - and returns true if the service is installed - successfully; otherwise returns false. - - On Windows service is installed in the system's service control manager with the given - \a account and \a password. - - On Unix service configuration is written to QSettings::SystemScope - using "QtSoftware" as organization name. \a account and \a password - arguments are ignored. - - \warning Due to the different implementations of how services (daemons) - are installed on various UNIX-like systems, this method doesn't - integrate the service into the system's startup scripts. - - \sa uninstall(), start() -*/ -bool QtServiceController::install(const QString &serviceFilePath, const QString &account, - const QString &password) -{ - QStringList arguments; - arguments << QLatin1String("-i"); - arguments << account; - arguments << password; - return (QProcess::execute(serviceFilePath, arguments) == 0); -} - - -/*! - \fn bool QtServiceController::uninstall() - - Uninstalls the service and returns true if successful; otherwise returns false. - - On Windows service is uninstalled using the system's service control manager. - - On Unix service configuration is cleared using QSettings::SystemScope - with "QtSoftware" as organization name. - - - \sa install() -*/ - -/*! - \fn bool QtServiceController::start(const QStringList &arguments) - - Starts the installed service passing the given \a arguments to the - service. A service must be installed before a controller can run it. - - Returns true if the service could be started; otherwise returns - false. - - \sa install(), stop() -*/ - -/*! - \overload - - Starts the installed service without passing any arguments to the service. -*/ -bool QtServiceController::start() -{ - return start(QStringList()); -} - -/*! - \fn bool QtServiceController::stop() - - Requests the running service to stop. The service will call the - QtServiceBase::stop() implementation unless the service's state - is QtServiceBase::CannotBeStopped. This function does nothing if - the service is not running. - - Returns true if a running service was successfully stopped; - otherwise false. - - \sa start(), QtServiceBase::stop(), QtServiceBase::ServiceFlags -*/ - -/*! - \fn bool QtServiceController::pause() - - Requests the running service to pause. If the service's state is - QtServiceBase::CanBeSuspended, the service will call the - QtServiceBase::pause() implementation. The function does nothing - if the service is not running. - - Returns true if a running service was successfully paused; - otherwise returns false. - - \sa resume(), QtServiceBase::pause(), QtServiceBase::ServiceFlags -*/ - -/*! - \fn bool QtServiceController::resume() - - Requests the running service to continue. If the service's state - is QtServiceBase::CanBeSuspended, the service will call the - QtServiceBase::resume() implementation. This function does nothing - if the service is not running. - - Returns true if a running service was successfully resumed; - otherwise returns false. - - \sa pause(), QtServiceBase::resume(), QtServiceBase::ServiceFlags -*/ - -/*! - \fn bool QtServiceController::sendCommand(int code) - - Sends the user command \a code to the service. The service will - call the QtServiceBase::processCommand() implementation. This - function does nothing if the service is not running. - - Returns true if the request was sent to a running service; - otherwise returns false. - - \sa QtServiceBase::processCommand() -*/ - -class QtServiceStarter : public QObject -{ - Q_OBJECT -public: - QtServiceStarter(QtServiceBasePrivate *service) - : QObject(), d_ptr(service) {} -public slots: - void slotStart() - { - d_ptr->startService(); - } -private: - QtServiceBasePrivate *d_ptr; -}; -#include "qtservice.moc" - -QtServiceBase *QtServiceBasePrivate::instance = 0; - -QtServiceBasePrivate::QtServiceBasePrivate(const QString &name) - : startupType(QtServiceController::ManualStartup), serviceFlags(0), controller(name) -{ - -} - -QtServiceBasePrivate::~QtServiceBasePrivate() -{ - -} - -void QtServiceBasePrivate::startService() -{ - q_ptr->start(); -} - -int QtServiceBasePrivate::run(bool asService, const QStringList &argList) -{ - int argc = argList.size(); - QVector<char *> argv(argc); - QList<QByteArray> argvData; - for (int i = 0; i < argc; ++i) - argvData.append(argList.at(i).toLocal8Bit()); - for (int i = 0; i < argc; ++i) - argv[i] = argvData[i].data(); - - if (asService && !sysInit()) - return -1; - - q_ptr->createApplication(argc, argv.data()); - QCoreApplication *app = QCoreApplication::instance(); - if (!app) - return -1; - - if (asService) - sysSetPath(); - - QtServiceStarter starter(this); - QTimer::singleShot(0, &starter, SLOT(slotStart())); - int res = q_ptr->executeApplication(); - delete app; - - if (asService) - sysCleanup(); - return res; -} - - -/*! - \class QtServiceBase - - \brief The QtServiceBase class provides an API for implementing - Windows services and Unix daemons. - - A Windows service or Unix daemon (a "service"), is a program that - runs "in the background" independently of whether a user is logged - in or not. A service is often set up to start when the machine - boots up, and will typically run continuously as long as the - machine is on. - - Services are usually non-interactive console applications. User - interaction, if required, is usually implemented in a separate, - normal GUI application that communicates with the service through - an IPC channel. For simple communication, - QtServiceController::sendCommand() and QtService::processCommand() - may be used, possibly in combination with a shared settings - file. For more complex, interactive communication, a custom IPC - channel should be used, e.g. based on Qt's networking classes. (In - certain circumstances, a service may provide a GUI itself, - ref. the "interactive" example documentation). - - Typically, you will create a service by subclassing the QtService - template class which inherits QtServiceBase and allows you to - create a service for a particular application type. - - The Windows implementation uses the NT Service Control Manager, - and the application can be controlled through the system - administration tools. Services are usually launched using the - system account, which requires that all DLLs that the service - executable depends on (i.e. Qt), are located in the same directory - as the service, or in a system path. - - On Unix a service is implemented as a daemon. - - You can retrieve the service's description, state, and startup - type using the serviceDescription(), serviceFlags() and - startupType() functions respectively. The service's state is - decribed by the ServiceFlag enum. The mentioned properites can - also be set using the corresponding set functions. In addition you - can retrieve the service's name using the serviceName() function. - - Several of QtServiceBase's protected functions are called on - requests from the QtServiceController class: - - \list - \o start() - \o pause() - \o processCommand() - \o resume() - \o stop() - \endlist - - You can control any given service using an instance of the - QtServiceController class which also allows you to control - services from separate applications. The mentioned functions are - all virtual and won't do anything unless they are - reimplemented. You can reimplement these functions to pause and - resume the service's execution, as well as process user commands - and perform additional clean-ups before shutting down. - - QtServiceBase also provides the static instance() function which - returns a pointer to an application's QtServiceBase instance. In - addition, a service can report events to the system's event log - using the logMessage() function. The MessageType enum describes - the different types of messages a service reports. - - The implementation of a service application's main function - typically creates an service object derived by subclassing the - QtService template class. Then the main function will call this - service's exec() function, and return the result of that call. For - example: - - \code - int main(int argc, char **argv) - { - MyService service(argc, argv); - return service.exec(); - } - \endcode - - When the exec() function is called, it will parse the service - specific arguments passed in \c argv, perform the required - actions, and return. - - \target serviceSpecificArguments - - The following arguments are recognized as service specific: - - \table - \header \i Short \i Long \i Explanation - \row \i -i \i -install \i Install the service. - \row \i -u \i -uninstall \i Uninstall the service. - \row \i -e \i -exec - \i Execute the service as a standalone application (useful for debug purposes). - This is a blocking call, the service will be executed like a normal application. - In this mode you will not be able to communicate with the service from the contoller. - \row \i -t \i -terminate \i Stop the service. - \row \i -p \i -pause \i Pause the service. - \row \i -r \i -resume \i Resume a paused service. - \row \i -c \e{cmd} \i -command \e{cmd} - \i Send the user defined command code \e{cmd} to the service application. - \row \i -v \i -version \i Display version and status information. - \endtable - - If \e none of the arguments is recognized as service specific, - exec() will first call the createApplication() function, then - executeApplication() and finally the start() function. In the end, - exec() returns while the service continues in its own process - waiting for commands from the service controller. - - \sa QtService, QtServiceController -*/ - -/*! - \enum QtServiceBase::MessageType - - This enum describes the different types of messages a service - reports to the system log. - - \value Success An operation has succeeded, e.g. the service - is started. - \value Error An operation failed, e.g. the service failed to start. - \value Warning An operation caused a warning that might require user - interaction. - \value Information Any type of usually non-critical information. -*/ - -/*! - \enum QtServiceBase::ServiceFlag - - This enum describes the different capabilities of a service. - - \value Default The service can be stopped, but not suspended. - \value CanBeSuspended The service can be suspended. - \value CannotBeStopped The service cannot be stopped. - \value NeedsStopOnShutdown (Windows only) The service will be stopped before the system shuts down. Note that Microsoft recommends this only for services that must absolutely clean up during shutdown, because there is a limited time available for shutdown of services. -*/ - -/*! - Creates a service instance called \a name. The \a argc and \a argv - parameters are parsed after the exec() function has been - called. Then they are passed to the application's constructor. - The application type is determined by the QtService subclass. - - The service is neither installed nor started. The name must not - contain any backslashes or be longer than 255 characters. In - addition, the name must be unique in the system's service - database. - - \sa exec(), start(), QtServiceController::install() -*/ -QtServiceBase::QtServiceBase(int argc, char **argv, const QString &name) -{ -#if defined(QTSERVICE_DEBUG) - qInstallMsgHandler(qtServiceLogDebug); - qAddPostRoutine(qtServiceCloseDebugLog); -#endif - - Q_ASSERT(!QtServiceBasePrivate::instance); - QtServiceBasePrivate::instance = this; - - QString nm(name); - if (nm.length() > 255) { - qWarning("QtService: 'name' is longer than 255 characters."); - nm.truncate(255); - } - if (nm.contains('\\')) { - qWarning("QtService: 'name' contains backslashes '\\'."); - nm.replace((QChar)'\\', (QChar)'\0'); - } - - d_ptr = new QtServiceBasePrivate(nm); - d_ptr->q_ptr = this; - - d_ptr->serviceFlags = 0; - d_ptr->sysd = 0; - for (int i = 0; i < argc; ++i) - d_ptr->args.append(QString::fromLocal8Bit(argv[i])); -} - -/*! - Destroys the service object. This neither stops nor uninstalls the - service. - - To stop a service the stop() function must be called - explicitly. To uninstall a service, you can use the - QtServiceController::uninstall() function. - - \sa stop(), QtServiceController::uninstall() -*/ -QtServiceBase::~QtServiceBase() -{ - delete d_ptr; - QtServiceBasePrivate::instance = 0; -} - -/*! - Returns the name of the service. - - \sa QtServiceBase(), serviceDescription() -*/ -QString QtServiceBase::serviceName() const -{ - return d_ptr->controller.serviceName(); -} - -/*! - Returns the description of the service. - - \sa setServiceDescription(), serviceName() -*/ -QString QtServiceBase::serviceDescription() const -{ - return d_ptr->serviceDescription; -} - -/*! - Sets the description of the service to the given \a description. - - \sa serviceDescription() -*/ -void QtServiceBase::setServiceDescription(const QString &description) -{ - d_ptr->serviceDescription = description; -} - -/*! - Returns the service's startup type. - - \sa QtServiceController::StartupType, setStartupType() -*/ -QtServiceController::StartupType QtServiceBase::startupType() const -{ - return d_ptr->startupType; -} - -/*! - Sets the service's startup type to the given \a type. - - \sa QtServiceController::StartupType, startupType() -*/ -void QtServiceBase::setStartupType(QtServiceController::StartupType type) -{ - d_ptr->startupType = type; -} - -/*! - Returns the service's state which is decribed using the - ServiceFlag enum. - - \sa ServiceFlags, setServiceFlags() -*/ -QtServiceBase::ServiceFlags QtServiceBase::serviceFlags() const -{ - return d_ptr->serviceFlags; -} - -/*! - \fn void QtServiceBase::setServiceFlags(ServiceFlags flags) - - Sets the service's state to the state described by the given \a - flags. - - \sa ServiceFlags, serviceFlags() -*/ - -/*! - Executes the service. - - When the exec() function is called, it will parse the \l - {serviceSpecificArguments} {service specific arguments} passed in - \c argv, perform the required actions, and exit. - - If none of the arguments is recognized as service specific, exec() - will first call the createApplication() function, then executeApplication() and - finally the start() function. In the end, exec() - returns while the service continues in its own process waiting for - commands from the service controller. - - \sa QtServiceController -*/ -int QtServiceBase::exec() -{ - if (d_ptr->args.size() > 1) { - QString a = d_ptr->args.at(1); - if (a == QLatin1String("-i") || a == QLatin1String("-install")) { - if (!d_ptr->controller.isInstalled()) { - QString account; - QString password; - if (d_ptr->args.size() > 2) - account = d_ptr->args.at(2); - if (d_ptr->args.size() > 3) - password = d_ptr->args.at(3); - if (!d_ptr->install(account, password)) { - fprintf(stderr, "The service %s could not be installed\n", serviceName().toLatin1().constData()); - return -1; - } else { - printf("The service %s has been installed under: %s\n", - serviceName().toLatin1().constData(), d_ptr->filePath().toLatin1().constData()); - } - } else { - fprintf(stderr, "The service %s is already installed\n", serviceName().toLatin1().constData()); - } - return 0; - } else if (a == QLatin1String("-u") || a == QLatin1String("-uninstall")) { - if (d_ptr->controller.isInstalled()) { - if (!d_ptr->controller.uninstall()) { - fprintf(stderr, "The service %s could not be uninstalled\n", serviceName().toLatin1().constData()); - return -1; - } else { - printf("The service %s has been uninstalled.\n", - serviceName().toLatin1().constData()); - } - } else { - fprintf(stderr, "The service %s is not installed\n", serviceName().toLatin1().constData()); - } - return 0; - } else if (a == QLatin1String("-v") || a == QLatin1String("-version")) { - printf("The service\n" - "\t%s\n\t%s\n\n", serviceName().toLatin1().constData(), d_ptr->args.at(0).toLatin1().constData()); - printf("is %s", (d_ptr->controller.isInstalled() ? "installed" : "not installed")); - printf(" and %s\n\n", (d_ptr->controller.isRunning() ? "running" : "not running")); - return 0; - } else if (a == QLatin1String("-e") || a == QLatin1String("-exec")) { - d_ptr->args.removeAt(1); - int ec = d_ptr->run(false, d_ptr->args); - if (ec == -1) - qErrnoWarning("The service could not be executed."); - return ec; - } else if (a == QLatin1String("-t") || a == QLatin1String("-terminate")) { - if (!d_ptr->controller.stop()) - qErrnoWarning("The service could not be stopped."); - return 0; - } else if (a == QLatin1String("-p") || a == QLatin1String("-pause")) { - d_ptr->controller.pause(); - return 0; - } else if (a == QLatin1String("-r") || a == QLatin1String("-resume")) { - d_ptr->controller.resume(); - return 0; - } else if (a == QLatin1String("-c") || a == QLatin1String("-command")) { - int code = 0; - if (d_ptr->args.size() > 2) - code = d_ptr->args.at(2).toInt(); - d_ptr->controller.sendCommand(code); - return 0; - } else if (a == QLatin1String("-h") || a == QLatin1String("-help")) { - printf("\n%s -[i|u|e|s|v|h]\n" - "\t-i(nstall) [account] [password]\t: Install the service, optionally using given account and password\n" - "\t-u(ninstall)\t: Uninstall the service.\n" - "\t-e(xec)\t\t: Run as a regular application. Useful for debugging.\n" - "\t-t(erminate)\t: Stop the service.\n" - //"\t-c(ommand) num\t: Send command code num to the service.\n" - "\t-v(ersion)\t: Print version and status information.\n" - "\t-h(elp) \t: Show this help\n" - "\tNo arguments\t: Start the service.\n", - d_ptr->args.at(0).toLatin1().constData()); - return 0; - } - } -#if defined(Q_OS_UNIX) - if (::getenv("QTSERVICE_RUN")) { - // Means we're the detached, real service process. - int ec = d_ptr->run(true, d_ptr->args); - if (ec == -1) - qErrnoWarning("The service failed to run."); - return ec; - } -#endif - if (!d_ptr->start()) { - fprintf(stderr, "The service %s could not start\n Run with argument -h for help.\n", serviceName().toLatin1().constData()); - return -4; - } - return 0; -} - -/*! - \fn void QtServiceBase::logMessage(const QString &message, MessageType type, - int id, uint category, const QByteArray &data) - - Reports a message of the given \a type with the given \a message - to the local system event log. The message identifier \a id and - the message \a category are user defined values. The \a data - parameter can contain arbitrary binary data. - - Message strings for \a id and \a category must be provided by a - message file, which must be registered in the system registry. - Refer to the MSDN for more information about how to do this on - Windows. - - \sa MessageType -*/ - -/*! - Returns a pointer to the current application's QtServiceBase - instance. -*/ -QtServiceBase *QtServiceBase::instance() -{ - return QtServiceBasePrivate::instance; -} - -/*! - \fn void QtServiceBase::start() - - This function must be implemented in QtServiceBase subclasses in - order to perform the service's work. Usually you create some main - object on the heap which is the heart of your service. - - The function is only called when no service specific arguments - were passed to the service constructor, and is called by exec() - after it has called the executeApplication() function. - - Note that you \e don't need to create an application object or - call its exec() function explicitly. - - \sa exec(), stop(), QtServiceController::start() -*/ - -/*! - Reimplement this function to perform additional cleanups before - shutting down (for example deleting a main object if it was - created in the start() function). - - This function is called in reply to controller requests. The - default implementation does nothing. - - \sa start(), QtServiceController::stop() -*/ -void QtServiceBase::stop() -{ -} - -/*! - Reimplement this function to pause the service's execution (for - example to stop a polling timer, or to ignore socket notifiers). - - This function is called in reply to controller requests. The - default implementation does nothing. - - \sa resume(), QtServiceController::pause() -*/ -void QtServiceBase::pause() -{ -} - -/*! - Reimplement this function to continue the service after a call to - pause(). - - This function is called in reply to controller requests. The - default implementation does nothing. - - \sa pause(), QtServiceController::resume() -*/ -void QtServiceBase::resume() -{ -} - -/*! - Reimplement this function to process the user command \a code. - - - This function is called in reply to controller requests. The - default implementation does nothing. - - \sa QtServiceController::sendCommand() -*/ -void QtServiceBase::processCommand(int /*code*/) -{ -} - -/*! - \fn void QtServiceBase::createApplication(int &argc, char **argv) - - Creates the application object using the \a argc and \a argv - parameters. - - This function is only called when no \l - {serviceSpecificArguments}{service specific arguments} were - passed to the service constructor, and is called by exec() before - it calls the executeApplication() and start() functions. - - The createApplication() function is implemented in QtService, but - you might want to reimplement it, for example, if the chosen - application type's constructor needs additional arguments. - - \sa exec(), QtService -*/ - -/*! - \fn int QtServiceBase::executeApplication() - - Executes the application previously created with the - createApplication() function. - - This function is only called when no \l - {serviceSpecificArguments}{service specific arguments} were - passed to the service constructor, and is called by exec() after - it has called the createApplication() function and before start() function. - - This function is implemented in QtService. - - \sa exec(), createApplication() -*/ - -/*! - \class QtService - - \brief The QtService is a convenient template class that allows - you to create a service for a particular application type. - - A Windows service or Unix daemon (a "service"), is a program that - runs "in the background" independently of whether a user is logged - in or not. A service is often set up to start when the machine - boots up, and will typically run continuously as long as the - machine is on. - - Services are usually non-interactive console applications. User - interaction, if required, is usually implemented in a separate, - normal GUI application that communicates with the service through - an IPC channel. For simple communication, - QtServiceController::sendCommand() and QtService::processCommand() - may be used, possibly in combination with a shared settings file. For - more complex, interactive communication, a custom IPC channel - should be used, e.g. based on Qt's networking classes. (In certain - circumstances, a service may provide a GUI itself, ref. the - "interactive" example documentation). - - \bold{Note:} On Unix systems, this class relies on facilities - provided by the QtNetwork module, provided as part of the - \l{Qt Open Source Edition} and certain \l{Qt Commercial Editions}. - - The QtService class functionality is inherited from QtServiceBase, - but in addition the QtService class binds an instance of - QtServiceBase with an application type. - - Typically, you will create a service by subclassing the QtService - template class. For example: - - \code - class MyService : public QtService<QApplication> - { - public: - MyService(int argc, char **argv); - ~MyService(); - - protected: - void start(); - void stop(); - void pause(); - void resume(); - void processCommand(int code); - }; - \endcode - - The application type can be QCoreApplication for services without - GUI, QApplication for services with GUI or you can use your own - custom application type. - - You must reimplement the QtServiceBase::start() function to - perform the service's work. Usually you create some main object on - the heap which is the heart of your service. - - In addition, you might want to reimplement the - QtServiceBase::pause(), QtServiceBase::processCommand(), - QtServiceBase::resume() and QtServiceBase::stop() to intervene the - service's process on controller requests. You can control any - given service using an instance of the QtServiceController class - which also allows you to control services from separate - applications. The mentioned functions are all virtual and won't do - anything unless they are reimplemented. - - Your custom service is typically instantiated in the application's - main function. Then the main function will call your service's - exec() function, and return the result of that call. For example: - - \code - int main(int argc, char **argv) - { - MyService service(argc, argv); - return service.exec(); - } - \endcode - - When the exec() function is called, it will parse the \l - {serviceSpecificArguments} {service specific arguments} passed in - \c argv, perform the required actions, and exit. - - If none of the arguments is recognized as service specific, exec() - will first call the createApplication() function, then executeApplication() and - finally the start() function. In the end, exec() - returns while the service continues in its own process waiting for - commands from the service controller. - - \sa QtServiceBase, QtServiceController -*/ - -/*! - \fn QtService::QtService(int argc, char **argv, const QString &name) - - Constructs a QtService object called \a name. The \a argc and \a - argv parameters are parsed after the exec() function has been - called. Then they are passed to the application's constructor. - - There can only be one QtService object in a process. - - \sa QtServiceBase() -*/ - -/*! - \fn QtService::~QtService() - - Destroys the service object. -*/ - -/*! - \fn Application *QtService::application() const - - Returns a pointer to the application object. -*/ - -/*! - \fn void QtService::createApplication(int &argc, char **argv) - - Creates application object of type Application passing \a argc and - \a argv to its constructor. - - \reimp - -*/ - -/*! - \fn int QtService::executeApplication() - - \reimp -*/ - - - diff --git a/isis/src/base/apps/spiceit/QtWebApp/qtservice/qtservice.h b/isis/src/base/apps/spiceit/QtWebApp/qtservice/qtservice.h deleted file mode 100644 index 84198c88fe681e54bae27856c4a918619452d3f1..0000000000000000000000000000000000000000 --- a/isis/src/base/apps/spiceit/QtWebApp/qtservice/qtservice.h +++ /dev/null @@ -1,193 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the Qt Solutions component. -** -** $QT_BEGIN_LICENSE:BSD$ -** You may use this file under the terms of the BSD license as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names -** of its contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ -/** - @file - @author Tolltech -*/ - -#ifndef QTSERVICE_H -#define QTSERVICE_H - -#include <QtGlobal> -#include <QCoreApplication> - -// This is specific to Windows dll's -#if defined(Q_OS_WIN) - #if defined(QTWEBAPPLIB_EXPORT) - #define DECLSPEC Q_DECL_EXPORT - #elif defined(QTWEBAPPLIB_IMPORT) - #define DECLSPEC Q_DECL_IMPORT - #endif -#endif -#if !defined(DECLSPEC) - #define DECLSPEC -#endif - -class QStringList; -class QtServiceControllerPrivate; - -class DECLSPEC QtServiceController -{ - Q_DECLARE_PRIVATE(QtServiceController) -public: - enum StartupType - { - AutoStartup = 0, ManualStartup - }; - - QtServiceController(const QString &name); - virtual ~QtServiceController(); - - bool isInstalled() const; - bool isRunning() const; - - QString serviceName() const; - QString serviceDescription() const; - StartupType startupType() const; - QString serviceFilePath() const; - - static bool install(const QString &serviceFilePath, const QString &account = QString(), - const QString &password = QString()); - bool uninstall(); - - bool start(const QStringList &arguments); - bool start(); - bool stop(); - bool pause(); - bool resume(); - bool sendCommand(int code); - -private: - QtServiceControllerPrivate *d_ptr; -}; - -class QtServiceBasePrivate; - -class DECLSPEC QtServiceBase -{ - Q_DECLARE_PRIVATE(QtServiceBase) -public: - - enum MessageType - { - Success = 0, Error, Warning, Information - }; - - enum ServiceFlag - { - Default = 0x00, - CanBeSuspended = 0x01, - CannotBeStopped = 0x02, - NeedsStopOnShutdown = 0x04 - }; - - Q_DECLARE_FLAGS(ServiceFlags, ServiceFlag) - - QtServiceBase(int argc, char **argv, const QString &name); - virtual ~QtServiceBase(); - - QString serviceName() const; - - QString serviceDescription() const; - void setServiceDescription(const QString &description); - - QtServiceController::StartupType startupType() const; - void setStartupType(QtServiceController::StartupType startupType); - - ServiceFlags serviceFlags() const; - void setServiceFlags(ServiceFlags flags); - - int exec(); - - void logMessage(const QString &message, MessageType type = Success, - int id = 0, uint category = 0, const QByteArray &data = QByteArray()); - - static QtServiceBase *instance(); - -protected: - - virtual void start() = 0; - virtual void stop(); - virtual void pause(); - virtual void resume(); - virtual void processCommand(int code); - - virtual void createApplication(int &argc, char **argv) = 0; - - virtual int executeApplication() = 0; - -private: - - friend class QtServiceSysPrivate; - QtServiceBasePrivate *d_ptr; -}; - -template <typename Application> -class QtService : public QtServiceBase -{ -public: - QtService(int argc, char **argv, const QString &name) - : QtServiceBase(argc, argv, name), app(0) - { } - ~QtService() - { - } - -protected: - Application *application() const - { return app; } - - virtual void createApplication(int &argc, char **argv) - { - app = new Application(argc, argv); - QCoreApplication *a = app; - Q_UNUSED(a); - } - - virtual int executeApplication() - { return Application::exec(); } - -private: - Application *app; -}; - -Q_DECLARE_OPERATORS_FOR_FLAGS(QtServiceBase::ServiceFlags) - -#endif // QTSERVICE_H diff --git a/isis/src/base/apps/spiceit/QtWebApp/qtservice/qtservice.pri b/isis/src/base/apps/spiceit/QtWebApp/qtservice/qtservice.pri deleted file mode 100644 index 7110cbad9bfc69094d4051091d5d5905e148f92a..0000000000000000000000000000000000000000 --- a/isis/src/base/apps/spiceit/QtWebApp/qtservice/qtservice.pri +++ /dev/null @@ -1,13 +0,0 @@ -INCLUDEPATH += $$PWD -DEPENDPATH += $$PWD - -!win32:QT += network -win32:LIBS += -luser32 - -HEADERS += $$PWD/qtservice.h $$PWD/qtservice_p.h -unix:HEADERS += $$PWD/qtunixsocket.h $$PWD/qtunixserversocket.h - -SOURCES += $$PWD/qtservice.cpp -win32:SOURCES += $$PWD/qtservice_win.cpp -unix:SOURCES += $$PWD/qtservice_unix.cpp $$PWD/qtunixsocket.cpp $$PWD/qtunixserversocket.cpp - diff --git a/isis/src/base/apps/spiceit/QtWebApp/qtservice/qtservice_p.h b/isis/src/base/apps/spiceit/QtWebApp/qtservice/qtservice_p.h deleted file mode 100644 index a88992cff3a0cd388d55e35a7ee7cfbb5db66ae3..0000000000000000000000000000000000000000 --- a/isis/src/base/apps/spiceit/QtWebApp/qtservice/qtservice_p.h +++ /dev/null @@ -1,87 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the Qt Solutions component. -** -** $QT_BEGIN_LICENSE:BSD$ -** You may use this file under the terms of the BSD license as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names -** of its contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QTSERVICE_P_H -#define QTSERVICE_P_H - -#include <QStringList> -#include "qtservice.h" - -class QtServiceControllerPrivate -{ - Q_DECLARE_PUBLIC(QtServiceController) -public: - QString serviceName; - QtServiceController *q_ptr; -}; - -class QtServiceBasePrivate -{ - Q_DECLARE_PUBLIC(QtServiceBase) -public: - - QtServiceBasePrivate(const QString &name); - ~QtServiceBasePrivate(); - - QtServiceBase *q_ptr; - - QString serviceDescription; - QtServiceController::StartupType startupType; - QtServiceBase::ServiceFlags serviceFlags; - QStringList args; - - static class QtServiceBase *instance; - - QtServiceController controller; - - void startService(); - int run(bool asService, const QStringList &argList); - bool install(const QString &account, const QString &password); - - bool start(); - - QString filePath() const; - bool sysInit(); - void sysSetPath(); - void sysCleanup(); - class QtServiceSysPrivate *sysd; -}; - -#endif diff --git a/isis/src/base/apps/spiceit/QtWebApp/qtservice/qtservice_unix.cpp b/isis/src/base/apps/spiceit/QtWebApp/qtservice/qtservice_unix.cpp deleted file mode 100644 index a076d2895382612f343669d6030f42fd157caf5c..0000000000000000000000000000000000000000 --- a/isis/src/base/apps/spiceit/QtWebApp/qtservice/qtservice_unix.cpp +++ /dev/null @@ -1,481 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the Qt Solutions component. -** -** $QT_BEGIN_LICENSE:BSD$ -** You may use this file under the terms of the BSD license as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names -** of its contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qtservice.h" -#include "qtservice_p.h" -#include "qtunixsocket.h" -#include "qtunixserversocket.h" -#include <QCoreApplication> -#include <QStringList> -#include <QFile> -#include <QTimer> -#include <QDir> -#include <pwd.h> -#include <fcntl.h> -#include <unistd.h> -#include <stdlib.h> -#include <string.h> -#include <syslog.h> -#include <signal.h> -#include <sys/stat.h> -#include <QMap> -#include <QSettings> -#include <QProcess> - -/** Alias type definition, for compatibility to different Qt versions */ -#if QT_VERSION >= 0x050000 - typedef qintptr tSocketDescriptor; -#else - typedef int tSocketDescriptor; -#endif - -static QString encodeName(const QString &name, bool allowUpper = false) -{ - QString n = name.toLower(); - QString legal = QLatin1String("abcdefghijklmnopqrstuvwxyz1234567890"); - if (allowUpper) - legal += QLatin1String("ABCDEFGHIJKLMNOPQRSTUVWXYZ"); - int pos = 0; - while (pos < n.size()) { - if (legal.indexOf(n[pos]) == -1) - n.remove(pos, 1); - else - ++pos; - } - return n; -} - -static QString login() -{ - QString l; - uid_t uid = getuid(); - passwd *pw = getpwuid(uid); - if (pw) - l = QString(pw->pw_name); - return l; -} - -static QString socketPath(const QString &serviceName) -{ - QString sn = encodeName(serviceName); - return QString(QLatin1String("/var/tmp/") + sn + QLatin1String(".") + login()); -} - -static bool sendCmd(const QString &serviceName, const QString &cmd) -{ - bool retValue = false; - QtUnixSocket sock; - if (sock.connectTo(socketPath(serviceName))) { - sock.write(QString(cmd+"\r\n").toLatin1().constData()); - sock.flush(); - sock.waitForReadyRead(-1); - QString reply = sock.readAll(); - if (reply == QLatin1String("true")) - retValue = true; - sock.close(); - } - return retValue; -} - -static QString absPath(const QString &path) -{ - QString ret; - if (path[0] != QChar('/')) { // Not an absolute path - int slashpos; - if ((slashpos = path.lastIndexOf('/')) != -1) { // Relative path - QDir dir = QDir::current(); - dir.cd(path.left(slashpos)); - ret = dir.absolutePath(); - } else { // Need to search $PATH - char *envPath = ::getenv("PATH"); - if (envPath) { - QStringList envPaths = QString::fromLocal8Bit(envPath).split(':'); - for (int i = 0; i < envPaths.size(); ++i) { - if (QFile::exists(envPaths.at(i) + QLatin1String("/") + QString(path))) { - QDir dir(envPaths.at(i)); - ret = dir.absolutePath(); - break; - } - } - } - } - } else { - QFileInfo fi(path); - ret = fi.absolutePath(); - } - return ret; -} - -QString QtServiceBasePrivate::filePath() const -{ - QString ret; - if (args.isEmpty()) - return ret; - QFileInfo fi(args[0]); - QDir dir(absPath(args[0])); - return dir.absoluteFilePath(fi.fileName()); -} - - -QString QtServiceController::serviceDescription() const -{ - QSettings settings(QSettings::SystemScope, "QtSoftware"); - settings.beginGroup("services"); - settings.beginGroup(serviceName()); - - QString desc = settings.value("description").toString(); - - settings.endGroup(); - settings.endGroup(); - - return desc; -} - -QtServiceController::StartupType QtServiceController::startupType() const -{ - QSettings settings(QSettings::SystemScope, "QtSoftware"); - settings.beginGroup("services"); - settings.beginGroup(serviceName()); - - StartupType startupType = (StartupType)settings.value("startupType").toInt(); - - settings.endGroup(); - settings.endGroup(); - - return startupType; -} - -QString QtServiceController::serviceFilePath() const -{ - QSettings settings(QSettings::SystemScope, "QtSoftware"); - settings.beginGroup("services"); - settings.beginGroup(serviceName()); - - QString path = settings.value("path").toString(); - - settings.endGroup(); - settings.endGroup(); - - return path; -} - -bool QtServiceController::uninstall() -{ - QSettings settings(QSettings::SystemScope, "QtSoftware"); - settings.beginGroup("services"); - - settings.remove(serviceName()); - - settings.endGroup(); - settings.sync(); - - QSettings::Status ret = settings.status(); - if (ret == QSettings::AccessError) { - fprintf(stderr, "Cannot uninstall \"%s\". Cannot write to: %s. Check permissions.\n", - serviceName().toLatin1().constData(), - settings.fileName().toLatin1().constData()); - } - return (ret == QSettings::NoError); -} - - -bool QtServiceController::start(const QStringList &arguments) -{ - if (!isInstalled()) - return false; - if (isRunning()) - return false; - return QProcess::startDetached(serviceFilePath(), arguments); -} - -bool QtServiceController::stop() -{ - return sendCmd(serviceName(), QLatin1String("terminate")); -} - -bool QtServiceController::pause() -{ - return sendCmd(serviceName(), QLatin1String("pause")); -} - -bool QtServiceController::resume() -{ - return sendCmd(serviceName(), QLatin1String("resume")); -} - -bool QtServiceController::sendCommand(int code) -{ - return sendCmd(serviceName(), QString(QLatin1String("num:") + QString::number(code))); -} - -bool QtServiceController::isInstalled() const -{ - QSettings settings(QSettings::SystemScope, "QtSoftware"); - settings.beginGroup("services"); - - QStringList list = settings.childGroups(); - - settings.endGroup(); - - QStringListIterator it(list); - while (it.hasNext()) { - if (it.next() == serviceName()) - return true; - } - - return false; -} - -bool QtServiceController::isRunning() const -{ - QtUnixSocket sock; - if (sock.connectTo(socketPath(serviceName()))) - return true; - return false; -} - - - - -/////////////////////////////////// - -class QtServiceSysPrivate : public QtUnixServerSocket -{ - Q_OBJECT -public: - QtServiceSysPrivate(); - ~QtServiceSysPrivate(); - - char *ident; - - QtServiceBase::ServiceFlags serviceFlags; - -protected: - void incomingConnection(tSocketDescriptor socketDescriptor) Q_DECL_OVERRIDE; - -private slots: - void slotReady(); - void slotClosed(); - -private: - QString getCommand(const QTcpSocket *socket); - QMap<const QTcpSocket *, QString> cache; -}; - -QtServiceSysPrivate::QtServiceSysPrivate() - : QtUnixServerSocket(), ident(0), serviceFlags(0) -{ -} - -QtServiceSysPrivate::~QtServiceSysPrivate() -{ - if (ident) - delete[] ident; -} - -void QtServiceSysPrivate::incomingConnection(tSocketDescriptor socketDescriptor) -{ - QTcpSocket *s = new QTcpSocket(this); - s->setSocketDescriptor(socketDescriptor); - connect(s, SIGNAL(readyRead()), this, SLOT(slotReady())); - connect(s, SIGNAL(disconnected()), this, SLOT(slotClosed())); -} - -void QtServiceSysPrivate::slotReady() -{ - QTcpSocket *s = (QTcpSocket *)sender(); - cache[s] += QString(s->readAll()); - QString cmd = getCommand(s); - while (!cmd.isEmpty()) { - bool retValue = false; - if (cmd == QLatin1String("terminate")) { - if (!(serviceFlags & QtServiceBase::CannotBeStopped)) { - QtServiceBase::instance()->stop(); - QCoreApplication::instance()->quit(); - retValue = true; - } - } else if (cmd == QLatin1String("pause")) { - if (serviceFlags & QtServiceBase::CanBeSuspended) { - QtServiceBase::instance()->pause(); - retValue = true; - } - } else if (cmd == QLatin1String("resume")) { - if (serviceFlags & QtServiceBase::CanBeSuspended) { - QtServiceBase::instance()->resume(); - retValue = true; - } - } else if (cmd == QLatin1String("alive")) { - retValue = true; - } else if (cmd.length() > 4 && cmd.left(4) == QLatin1String("num:")) { - cmd = cmd.mid(4); - QtServiceBase::instance()->processCommand(cmd.toInt()); - retValue = true; - } - QString retString; - if (retValue) - retString = QLatin1String("true"); - else - retString = QLatin1String("false"); - s->write(retString.toLatin1().constData()); - s->flush(); - cmd = getCommand(s); - } -} - -void QtServiceSysPrivate::slotClosed() -{ - QTcpSocket *s = (QTcpSocket *)sender(); - s->deleteLater(); -} - -QString QtServiceSysPrivate::getCommand(const QTcpSocket *socket) -{ - int pos = cache[socket].indexOf("\r\n"); - if (pos >= 0) { - QString ret = cache[socket].left(pos); - cache[socket].remove(0, pos+2); - return ret; - } - return ""; -} - -#include "qtservice_unix.moc" - -bool QtServiceBasePrivate::sysInit() -{ - sysd = new QtServiceSysPrivate; - sysd->serviceFlags = serviceFlags; - // Restrict permissions on files that are created by the service - ::umask(027); - - return true; -} - -void QtServiceBasePrivate::sysSetPath() -{ - if (sysd) - sysd->setPath(socketPath(controller.serviceName())); -} - -void QtServiceBasePrivate::sysCleanup() -{ - if (sysd) { - sysd->close(); - delete sysd; - sysd = 0; - } -} - -bool QtServiceBasePrivate::start() -{ - if (sendCmd(controller.serviceName(), "alive")) { - // Already running - return false; - } - // Could just call controller.start() here, but that would fail if - // we're not installed. We do not want to strictly require installation. - ::setenv("QTSERVICE_RUN", "1", 1); // Tell the detached process it's it - return QProcess::startDetached(filePath(), args.mid(1), "/"); -} - -bool QtServiceBasePrivate::install(const QString &account, const QString &password) -{ - Q_UNUSED(account) - Q_UNUSED(password) - QSettings settings(QSettings::SystemScope, "QtSoftware"); - - settings.beginGroup("services"); - settings.beginGroup(controller.serviceName()); - - settings.setValue("path", filePath()); - settings.setValue("description", serviceDescription); - settings.setValue("automaticStartup", startupType); - - settings.endGroup(); - settings.endGroup(); - settings.sync(); - - QSettings::Status ret = settings.status(); - if (ret == QSettings::AccessError) { - fprintf(stderr, "Cannot install \"%s\". Cannot write to: %s. Check permissions.\n", - controller.serviceName().toLatin1().constData(), - settings.fileName().toLatin1().constData()); - } - return (ret == QSettings::NoError); -} - -void QtServiceBase::logMessage(const QString &message, QtServiceBase::MessageType type, - int, uint, const QByteArray &) -{ - if (!d_ptr->sysd) - return; - int st; - switch(type) { - case QtServiceBase::Error: - st = LOG_ERR; - break; - case QtServiceBase::Warning: - st = LOG_WARNING; - break; - default: - st = LOG_INFO; - } - if (!d_ptr->sysd->ident) { - QString tmp = encodeName(serviceName(), true); - int len = tmp.toLocal8Bit().size(); - d_ptr->sysd->ident = new char[len+1]; - d_ptr->sysd->ident[len] = '\0'; - ::memcpy(d_ptr->sysd->ident, tmp.toLocal8Bit().constData(), len); - } - openlog(d_ptr->sysd->ident, LOG_PID, LOG_DAEMON); - foreach(QString line, message.split('\n')) - syslog(st, "%s", line.toLocal8Bit().constData()); - closelog(); -} - -void QtServiceBase::setServiceFlags(QtServiceBase::ServiceFlags flags) -{ - if (d_ptr->serviceFlags == flags) - return; - d_ptr->serviceFlags = flags; - if (d_ptr->sysd) - d_ptr->sysd->serviceFlags = flags; -} - diff --git a/isis/src/base/apps/spiceit/QtWebApp/qtservice/qtservice_win.cpp b/isis/src/base/apps/spiceit/QtWebApp/qtservice/qtservice_win.cpp deleted file mode 100644 index 997abd22f68e90b37bafd29b336b802bef51a78f..0000000000000000000000000000000000000000 --- a/isis/src/base/apps/spiceit/QtWebApp/qtservice/qtservice_win.cpp +++ /dev/null @@ -1,949 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the Qt Solutions component. -** -** $QT_BEGIN_LICENSE:BSD$ -** You may use this file under the terms of the BSD license as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names -** of its contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qtservice.h" -#include "qtservice_p.h" -#include <QCoreApplication> -#include <QDateTime> -#include <QFile> -#include <QLibrary> -#include <QMutex> -#include <QSemaphore> -#include <QProcess> -#include <QSettings> -#include <QTextStream> -#include <qt_windows.h> -#include <QWaitCondition> -#include <QAbstractEventDispatcher> -#include <QVector> -#include <QThread> -#if QT_VERSION >= 0x050000 -# include <QAbstractNativeEventFilter> -#endif -#include <stdio.h> -#if defined(QTSERVICE_DEBUG) -#include <QDebug> -#endif - -typedef SERVICE_STATUS_HANDLE(WINAPI*PRegisterServiceCtrlHandler)(const wchar_t*,LPHANDLER_FUNCTION); -static PRegisterServiceCtrlHandler pRegisterServiceCtrlHandler = 0; -typedef BOOL(WINAPI*PSetServiceStatus)(SERVICE_STATUS_HANDLE,LPSERVICE_STATUS); -static PSetServiceStatus pSetServiceStatus = 0; -typedef BOOL(WINAPI*PChangeServiceConfig2)(SC_HANDLE,DWORD,LPVOID); -static PChangeServiceConfig2 pChangeServiceConfig2 = 0; -typedef BOOL(WINAPI*PCloseServiceHandle)(SC_HANDLE); -static PCloseServiceHandle pCloseServiceHandle = 0; -typedef SC_HANDLE(WINAPI*PCreateService)(SC_HANDLE,LPCTSTR,LPCTSTR,DWORD,DWORD,DWORD,DWORD,LPCTSTR,LPCTSTR,LPDWORD,LPCTSTR,LPCTSTR,LPCTSTR); -static PCreateService pCreateService = 0; -typedef SC_HANDLE(WINAPI*POpenSCManager)(LPCTSTR,LPCTSTR,DWORD); -static POpenSCManager pOpenSCManager = 0; -typedef BOOL(WINAPI*PDeleteService)(SC_HANDLE); -static PDeleteService pDeleteService = 0; -typedef SC_HANDLE(WINAPI*POpenService)(SC_HANDLE,LPCTSTR,DWORD); -static POpenService pOpenService = 0; -typedef BOOL(WINAPI*PQueryServiceStatus)(SC_HANDLE,LPSERVICE_STATUS); -static PQueryServiceStatus pQueryServiceStatus = 0; -typedef BOOL(WINAPI*PStartServiceCtrlDispatcher)(CONST SERVICE_TABLE_ENTRY*); -static PStartServiceCtrlDispatcher pStartServiceCtrlDispatcher = 0; -typedef BOOL(WINAPI*PStartService)(SC_HANDLE,DWORD,const wchar_t**); -static PStartService pStartService = 0; -typedef BOOL(WINAPI*PControlService)(SC_HANDLE,DWORD,LPSERVICE_STATUS); -static PControlService pControlService = 0; -typedef HANDLE(WINAPI*PDeregisterEventSource)(HANDLE); -static PDeregisterEventSource pDeregisterEventSource = 0; -typedef BOOL(WINAPI*PReportEvent)(HANDLE,WORD,WORD,DWORD,PSID,WORD,DWORD,LPCTSTR*,LPVOID); -static PReportEvent pReportEvent = 0; -typedef HANDLE(WINAPI*PRegisterEventSource)(LPCTSTR,LPCTSTR); -static PRegisterEventSource pRegisterEventSource = 0; -typedef DWORD(WINAPI*PRegisterServiceProcess)(DWORD,DWORD); - -// Do not remove, even if the compiler warns that this variable is unused! -static PRegisterServiceProcess pRegisterServiceProcess = 0; - -typedef BOOL(WINAPI*PQueryServiceConfig)(SC_HANDLE,LPQUERY_SERVICE_CONFIG,DWORD,LPDWORD); -static PQueryServiceConfig pQueryServiceConfig = 0; -typedef BOOL(WINAPI*PQueryServiceConfig2)(SC_HANDLE,DWORD,LPBYTE,DWORD,LPDWORD); -static PQueryServiceConfig2 pQueryServiceConfig2 = 0; - - -#define RESOLVE(name) p##name = (P##name)lib.resolve(#name); -#define RESOLVEA(name) p##name = (P##name)lib.resolve(#name"A"); -#define RESOLVEW(name) p##name = (P##name)lib.resolve(#name"W"); - -static bool winServiceInit() -{ - if (!pOpenSCManager) { - QLibrary lib("advapi32"); - - // only resolve unicode versions - RESOLVEW(RegisterServiceCtrlHandler); - RESOLVE(SetServiceStatus); - RESOLVEW(ChangeServiceConfig2); - RESOLVE(CloseServiceHandle); - RESOLVEW(CreateService); - RESOLVEW(OpenSCManager); - RESOLVE(DeleteService); - RESOLVEW(OpenService); - RESOLVE(QueryServiceStatus); - RESOLVEW(StartServiceCtrlDispatcher); - RESOLVEW(StartService); // need only Ansi version - RESOLVE(ControlService); - RESOLVE(DeregisterEventSource); - RESOLVEW(ReportEvent); - RESOLVEW(RegisterEventSource); - RESOLVEW(QueryServiceConfig); - RESOLVEW(QueryServiceConfig2); - } - return pOpenSCManager != 0; -} - -bool QtServiceController::isInstalled() const -{ - Q_D(const QtServiceController); - bool result = false; - if (!winServiceInit()) - return result; - - // Open the Service Control Manager - SC_HANDLE hSCM = pOpenSCManager(0, 0, 0); - if (hSCM) { - // Try to open the service - SC_HANDLE hService = pOpenService(hSCM, (wchar_t*)d->serviceName.utf16(), - SERVICE_QUERY_CONFIG); - - if (hService) { - result = true; - pCloseServiceHandle(hService); - } - pCloseServiceHandle(hSCM); - } - return result; -} - -bool QtServiceController::isRunning() const -{ - Q_D(const QtServiceController); - bool result = false; - if (!winServiceInit()) - return result; - - // Open the Service Control Manager - SC_HANDLE hSCM = pOpenSCManager(0, 0, 0); - if (hSCM) { - // Try to open the service - SC_HANDLE hService = pOpenService(hSCM, (wchar_t *)d->serviceName.utf16(), - SERVICE_QUERY_STATUS); - if (hService) { - SERVICE_STATUS info; - int res = pQueryServiceStatus(hService, &info); - if (res) - result = info.dwCurrentState != SERVICE_STOPPED; - pCloseServiceHandle(hService); - } - pCloseServiceHandle(hSCM); - } - return result; -} - - -QString QtServiceController::serviceFilePath() const -{ - Q_D(const QtServiceController); - QString result; - if (!winServiceInit()) - return result; - - // Open the Service Control Manager - SC_HANDLE hSCM = pOpenSCManager(0, 0, 0); - if (hSCM) { - // Try to open the service - SC_HANDLE hService = pOpenService(hSCM, (wchar_t *)d->serviceName.utf16(), - SERVICE_QUERY_CONFIG); - if (hService) { - DWORD sizeNeeded = 0; - char data[8 * 1024]; - if (pQueryServiceConfig(hService, (LPQUERY_SERVICE_CONFIG)data, 8 * 1024, &sizeNeeded)) { - LPQUERY_SERVICE_CONFIG config = (LPQUERY_SERVICE_CONFIG)data; - result = QString::fromUtf16((const ushort*)config->lpBinaryPathName); - } - pCloseServiceHandle(hService); - } - pCloseServiceHandle(hSCM); - } - return result; -} - -QString QtServiceController::serviceDescription() const -{ - Q_D(const QtServiceController); - QString result; - if (!winServiceInit()) - return result; - - // Open the Service Control Manager - SC_HANDLE hSCM = pOpenSCManager(0, 0, 0); - if (hSCM) { - // Try to open the service - SC_HANDLE hService = pOpenService(hSCM, (wchar_t *)d->serviceName.utf16(), - SERVICE_QUERY_CONFIG); - if (hService) { - DWORD dwBytesNeeded; - char data[8 * 1024]; - if (pQueryServiceConfig2( - hService, - SERVICE_CONFIG_DESCRIPTION, - (unsigned char *)data, - 8096, - &dwBytesNeeded)) { - LPSERVICE_DESCRIPTION desc = (LPSERVICE_DESCRIPTION)data; - if (desc->lpDescription) - result = QString::fromUtf16((const ushort*)desc->lpDescription); - } - pCloseServiceHandle(hService); - } - pCloseServiceHandle(hSCM); - } - return result; -} - -QtServiceController::StartupType QtServiceController::startupType() const -{ - Q_D(const QtServiceController); - StartupType result = ManualStartup; - if (!winServiceInit()) - return result; - - // Open the Service Control Manager - SC_HANDLE hSCM = pOpenSCManager(0, 0, 0); - if (hSCM) { - // Try to open the service - SC_HANDLE hService = pOpenService(hSCM, (wchar_t *)d->serviceName.utf16(), - SERVICE_QUERY_CONFIG); - if (hService) { - DWORD sizeNeeded = 0; - char data[8 * 1024]; - if (pQueryServiceConfig(hService, (QUERY_SERVICE_CONFIG *)data, 8 * 1024, &sizeNeeded)) { - QUERY_SERVICE_CONFIG *config = (QUERY_SERVICE_CONFIG *)data; - result = config->dwStartType == SERVICE_DEMAND_START ? ManualStartup : AutoStartup; - } - pCloseServiceHandle(hService); - } - pCloseServiceHandle(hSCM); - } - return result; -} - -bool QtServiceController::uninstall() -{ - Q_D(QtServiceController); - bool result = false; - if (!winServiceInit()) - return result; - - // Open the Service Control Manager - SC_HANDLE hSCM = pOpenSCManager(0, 0, SC_MANAGER_ALL_ACCESS); - if (hSCM) { - // Try to open the service - SC_HANDLE hService = pOpenService(hSCM, (wchar_t *)d->serviceName.utf16(), DELETE); - if (hService) { - if (pDeleteService(hService)) - result = true; - pCloseServiceHandle(hService); - } - pCloseServiceHandle(hSCM); - } - return result; -} - -bool QtServiceController::start(const QStringList &args) -{ - Q_D(QtServiceController); - bool result = false; - if (!winServiceInit()) - return result; - - // Open the Service Control Manager - SC_HANDLE hSCM = pOpenSCManager(0, 0, SC_MANAGER_CONNECT); - if (hSCM) { - // Try to open the service - SC_HANDLE hService = pOpenService(hSCM, (wchar_t *)d->serviceName.utf16(), SERVICE_START); - if (hService) { - QVector<const wchar_t *> argv(args.size()); - for (int i = 0; i < args.size(); ++i) - argv[i] = (const wchar_t*)args.at(i).utf16(); - - if (pStartService(hService, args.size(), argv.data())) - result = true; - pCloseServiceHandle(hService); - } - pCloseServiceHandle(hSCM); - } - return result; -} - -bool QtServiceController::stop() -{ - Q_D(QtServiceController); - bool result = false; - if (!winServiceInit()) - return result; - - SC_HANDLE hSCM = pOpenSCManager(0, 0, SC_MANAGER_CONNECT); - if (hSCM) { - SC_HANDLE hService = pOpenService(hSCM, (wchar_t *)d->serviceName.utf16(), SERVICE_STOP|SERVICE_QUERY_STATUS); - if (hService) { - SERVICE_STATUS status; - if (pControlService(hService, SERVICE_CONTROL_STOP, &status)) { - bool stopped = status.dwCurrentState == SERVICE_STOPPED; - int i = 0; - while(!stopped && i < 10) { - Sleep(200); - if (!pQueryServiceStatus(hService, &status)) - break; - stopped = status.dwCurrentState == SERVICE_STOPPED; - ++i; - } - result = stopped; - } else { - qErrnoWarning(GetLastError(), "stopping"); - } - pCloseServiceHandle(hService); - } - pCloseServiceHandle(hSCM); - } - return result; -} - -bool QtServiceController::pause() -{ - Q_D(QtServiceController); - bool result = false; - if (!winServiceInit()) - return result; - - SC_HANDLE hSCM = pOpenSCManager(0, 0, SC_MANAGER_CONNECT); - if (hSCM) { - SC_HANDLE hService = pOpenService(hSCM, (wchar_t *)d->serviceName.utf16(), - SERVICE_PAUSE_CONTINUE); - if (hService) { - SERVICE_STATUS status; - if (pControlService(hService, SERVICE_CONTROL_PAUSE, &status)) - result = true; - pCloseServiceHandle(hService); - } - pCloseServiceHandle(hSCM); - } - return result; -} - -bool QtServiceController::resume() -{ - Q_D(QtServiceController); - bool result = false; - if (!winServiceInit()) - return result; - - SC_HANDLE hSCM = pOpenSCManager(0, 0, SC_MANAGER_CONNECT); - if (hSCM) { - SC_HANDLE hService = pOpenService(hSCM, (wchar_t *)d->serviceName.utf16(), - SERVICE_PAUSE_CONTINUE); - if (hService) { - SERVICE_STATUS status; - if (pControlService(hService, SERVICE_CONTROL_CONTINUE, &status)) - result = true; - pCloseServiceHandle(hService); - } - pCloseServiceHandle(hSCM); - } - return result; -} - -bool QtServiceController::sendCommand(int code) -{ - Q_D(QtServiceController); - bool result = false; - if (!winServiceInit()) - return result; - - if (code < 0 || code > 127 || !isRunning()) - return result; - - SC_HANDLE hSCM = pOpenSCManager(0, 0, SC_MANAGER_CONNECT); - if (hSCM) { - SC_HANDLE hService = pOpenService(hSCM, (wchar_t *)d->serviceName.utf16(), - SERVICE_USER_DEFINED_CONTROL); - if (hService) { - SERVICE_STATUS status; - if (pControlService(hService, 128 + code, &status)) - result = true; - pCloseServiceHandle(hService); - } - pCloseServiceHandle(hSCM); - } - return result; -} - -#if defined(QTSERVICE_DEBUG) -extern void qtServiceLogDebug(QtMsgType type, const char* msg); -#endif - -void QtServiceBase::logMessage(const QString &message, MessageType type, - int id, uint category, const QByteArray &data) -{ -#if defined(QTSERVICE_DEBUG) - QByteArray dbgMsg("[LOGGED "); - switch (type) { - case Error: dbgMsg += "Error] " ; break; - case Warning: dbgMsg += "Warning] "; break; - case Success: dbgMsg += "Success] "; break; - case Information: //fall through - default: dbgMsg += "Information] "; break; - } - dbgMsg += message.toAscii(); - qtServiceLogDebug((QtMsgType)-1, dbgMsg.constData()); -#endif - - Q_D(QtServiceBase); - if (!winServiceInit()) - return; - WORD wType; - switch (type) { - case Error: wType = EVENTLOG_ERROR_TYPE; break; - case Warning: wType = EVENTLOG_WARNING_TYPE; break; - case Information: wType = EVENTLOG_INFORMATION_TYPE; break; - default: wType = EVENTLOG_SUCCESS; break; - } - HANDLE h = pRegisterEventSource(0, (wchar_t *)d->controller.serviceName().utf16()); - if (h) { - const wchar_t *msg = (wchar_t*)message.utf16(); - const char *bindata = data.size() ? data.constData() : 0; - pReportEvent(h, wType, category, id, 0, 1, data.size(),(const wchar_t **)&msg, - const_cast<char *>(bindata)); - pDeregisterEventSource(h); - } -} - -class QtServiceControllerHandler : public QObject -{ - Q_OBJECT -public: - QtServiceControllerHandler(QtServiceSysPrivate *sys); - -protected: - void customEvent(QEvent *e); - -private: - QtServiceSysPrivate *d_sys; -}; - -class QtServiceSysPrivate -{ -public: - enum { - QTSERVICE_STARTUP = 256 - }; - QtServiceSysPrivate(); - - void setStatus( DWORD dwState ); - void setServiceFlags(QtServiceBase::ServiceFlags flags); - DWORD serviceFlags(QtServiceBase::ServiceFlags flags) const; - inline bool available() const; - static void WINAPI serviceMain( DWORD dwArgc, wchar_t** lpszArgv ); - static void WINAPI handler( DWORD dwOpcode ); - - SERVICE_STATUS status; - SERVICE_STATUS_HANDLE serviceStatus; - QStringList serviceArgs; - - static QtServiceSysPrivate *instance; -#if QT_VERSION < 0x050000 - static QCoreApplication::EventFilter nextFilter; -#endif - - QWaitCondition condition; - QMutex mutex; - QSemaphore startSemaphore; - QSemaphore startSemaphore2; - - QtServiceControllerHandler *controllerHandler; - - void handleCustomEvent(QEvent *e); -}; - -QtServiceControllerHandler::QtServiceControllerHandler(QtServiceSysPrivate *sys) - : QObject(), d_sys(sys) -{ - -} - -void QtServiceControllerHandler::customEvent(QEvent *e) -{ - d_sys->handleCustomEvent(e); -} - - -QtServiceSysPrivate *QtServiceSysPrivate::instance = 0; -#if QT_VERSION < 0x050000 -QCoreApplication::EventFilter QtServiceSysPrivate::nextFilter = 0; -#endif - -QtServiceSysPrivate::QtServiceSysPrivate() -{ - instance = this; -} - -inline bool QtServiceSysPrivate::available() const -{ - return 0 != pOpenSCManager; -} - -void WINAPI QtServiceSysPrivate::serviceMain(DWORD dwArgc, wchar_t** lpszArgv) -{ - if (!instance || !QtServiceBase::instance()) - return; - - // Windows spins off a random thread to call this function on - // startup, so here we just signal to the QApplication event loop - // in the main thread to go ahead with start()'ing the service. - - for (DWORD i = 0; i < dwArgc; i++) - instance->serviceArgs.append(QString::fromUtf16((unsigned short*)lpszArgv[i])); - - instance->startSemaphore.release(); // let the qapp creation start - instance->startSemaphore2.acquire(); // wait until its done - // Register the control request handler - instance->serviceStatus = pRegisterServiceCtrlHandler((TCHAR*)QtServiceBase::instance()->serviceName().utf16(), handler); - - if (!instance->serviceStatus) // cannot happen - something is utterly wrong - return; - - handler(QTSERVICE_STARTUP); // Signal startup to the application - - // causes QtServiceBase::start() to be called in the main thread - - // The MSDN doc says that this thread should just exit - the service is - // running in the main thread (here, via callbacks in the handler thread). -} - - -// The handler() is called from the thread that called -// StartServiceCtrlDispatcher, i.e. our HandlerThread, and -// not from the main thread that runs the event loop, so we -// have to post an event to ourselves, and use a QWaitCondition -// and a QMutex to synchronize. -void QtServiceSysPrivate::handleCustomEvent(QEvent *e) -{ - int code = e->type() - QEvent::User; - - switch(code) { - case QTSERVICE_STARTUP: // Startup - QtServiceBase::instance()->start(); - break; - case SERVICE_CONTROL_STOP: - QtServiceBase::instance()->stop(); - QCoreApplication::instance()->quit(); - break; - case SERVICE_CONTROL_PAUSE: - QtServiceBase::instance()->pause(); - break; - case SERVICE_CONTROL_CONTINUE: - QtServiceBase::instance()->resume(); - break; - default: - if (code >= 128 && code <= 255) - QtServiceBase::instance()->processCommand(code - 128); - break; - } - - mutex.lock(); - condition.wakeAll(); - mutex.unlock(); -} - -void WINAPI QtServiceSysPrivate::handler( DWORD code ) -{ - if (!instance) - return; - - instance->mutex.lock(); - switch (code) { - case QTSERVICE_STARTUP: // QtService startup (called from WinMain when started) - instance->setStatus(SERVICE_START_PENDING); - QCoreApplication::postEvent(instance->controllerHandler, new QEvent(QEvent::Type(QEvent::User + code))); - instance->condition.wait(&instance->mutex); - instance->setStatus(SERVICE_RUNNING); - break; - case SERVICE_CONTROL_STOP: // 1 - instance->setStatus(SERVICE_STOP_PENDING); - QCoreApplication::postEvent(instance->controllerHandler, new QEvent(QEvent::Type(QEvent::User + code))); - instance->condition.wait(&instance->mutex); - // status will be reported as stopped by start() when qapp::exec returns - break; - - case SERVICE_CONTROL_PAUSE: // 2 - instance->setStatus(SERVICE_PAUSE_PENDING); - QCoreApplication::postEvent(instance->controllerHandler, new QEvent(QEvent::Type(QEvent::User + code))); - instance->condition.wait(&instance->mutex); - instance->setStatus(SERVICE_PAUSED); - break; - - case SERVICE_CONTROL_CONTINUE: // 3 - instance->setStatus(SERVICE_CONTINUE_PENDING); - QCoreApplication::postEvent(instance->controllerHandler, new QEvent(QEvent::Type(QEvent::User + code))); - instance->condition.wait(&instance->mutex); - instance->setStatus(SERVICE_RUNNING); - break; - - case SERVICE_CONTROL_INTERROGATE: // 4 - break; - - case SERVICE_CONTROL_SHUTDOWN: // 5 - // Don't waste time with reporting stop pending, just do it - QCoreApplication::postEvent(instance->controllerHandler, new QEvent(QEvent::Type(QEvent::User + SERVICE_CONTROL_STOP))); - instance->condition.wait(&instance->mutex); - // status will be reported as stopped by start() when qapp::exec returns - break; - - default: - if ( code >= 128 && code <= 255 ) { - QCoreApplication::postEvent(instance->controllerHandler, new QEvent(QEvent::Type(QEvent::User + code))); - instance->condition.wait(&instance->mutex); - } - break; - } - - instance->mutex.unlock(); - - // Report current status - if (instance->available() && instance->status.dwCurrentState != SERVICE_STOPPED) - pSetServiceStatus(instance->serviceStatus, &instance->status); -} - -void QtServiceSysPrivate::setStatus(DWORD state) -{ - if (!available()) - return; - status.dwCurrentState = state; - pSetServiceStatus(serviceStatus, &status); -} - -void QtServiceSysPrivate::setServiceFlags(QtServiceBase::ServiceFlags flags) -{ - if (!available()) - return; - status.dwControlsAccepted = serviceFlags(flags); - pSetServiceStatus(serviceStatus, &status); -} - -DWORD QtServiceSysPrivate::serviceFlags(QtServiceBase::ServiceFlags flags) const -{ - DWORD control = 0; - if (flags & QtServiceBase::CanBeSuspended) - control |= SERVICE_ACCEPT_PAUSE_CONTINUE; - if (!(flags & QtServiceBase::CannotBeStopped)) - control |= SERVICE_ACCEPT_STOP; - if (flags & QtServiceBase::NeedsStopOnShutdown) - control |= SERVICE_ACCEPT_SHUTDOWN; - - return control; -} - -#include "qtservice_win.moc" - - -class HandlerThread : public QThread -{ -public: - HandlerThread() - : QThread(), success(true), console(false) - {} - - bool calledOk() { return success; } - bool runningAsConsole() { return console; } - -protected: - bool success; - bool console; - void run() - { - SERVICE_TABLE_ENTRYW st [2]; - st[0].lpServiceName = (wchar_t*)QtServiceBase::instance()->serviceName().utf16(); - st[0].lpServiceProc = QtServiceSysPrivate::serviceMain; - st[1].lpServiceName = 0; - st[1].lpServiceProc = 0; - - success = (pStartServiceCtrlDispatcher(st) != 0); // should block - - if (!success) { - if (GetLastError() == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) { - // Means we're started from console, not from service mgr - // start() will ask the mgr to start another instance of us as a service instead - console = true; - } - else { - QtServiceBase::instance()->logMessage(QString("The Service failed to start [%1]").arg(qt_error_string(GetLastError())), QtServiceBase::Error); - } - QtServiceSysPrivate::instance->startSemaphore.release(); // let start() continue, since serviceMain won't be doing it - } - } -}; - -/* - Ignore WM_ENDSESSION system events, since they make the Qt kernel quit -*/ - -#if QT_VERSION >= 0x050000 - -class QtServiceAppEventFilter : public QAbstractNativeEventFilter -{ -public: - QtServiceAppEventFilter() {} - bool nativeEventFilter(const QByteArray &eventType, void *message, long *result); -}; - -bool QtServiceAppEventFilter::nativeEventFilter(const QByteArray &, void *message, long *result) -{ - MSG *winMessage = (MSG*)message; - if (winMessage->message == WM_ENDSESSION && (winMessage->lParam & ENDSESSION_LOGOFF)) { - *result = TRUE; - return true; - } - return false; -} - -Q_GLOBAL_STATIC(QtServiceAppEventFilter, qtServiceAppEventFilter) - -#else - -bool myEventFilter(void* message, long* result) -{ - MSG* msg = reinterpret_cast<MSG*>(message); - if (!msg || (msg->message != WM_ENDSESSION) || !(msg->lParam & ENDSESSION_LOGOFF)) - return QtServiceSysPrivate::nextFilter ? QtServiceSysPrivate::nextFilter(message, result) : false; - - if (QtServiceSysPrivate::nextFilter) - QtServiceSysPrivate::nextFilter(message, result); - if (result) - *result = TRUE; - return true; -} - -#endif - -/* There are three ways we can be started: - - - By a service controller (e.g. the Services control panel), with - no (service-specific) arguments. ServiceBase::exec() will then call - start() below, and the service will start. - - - From the console, but with no (service-specific) arguments. This - means we should ask a controller to start the service (i.e. another - instance of this executable), and then just terminate. We discover - this case (as different from the above) by the fact that - StartServiceCtrlDispatcher will return an error, instead of blocking. - - - From the console, with -e(xec) argument. ServiceBase::exec() will - then call ServiceBasePrivate::exec(), which calls - ServiceBasePrivate::run(), which runs the application as a normal - program. -*/ - -bool QtServiceBasePrivate::start() -{ - sysInit(); - if (!winServiceInit()) - return false; - - // Since StartServiceCtrlDispatcher() blocks waiting for service - // control events, we need to call it in another thread, so that - // the main thread can run the QApplication event loop. - HandlerThread* ht = new HandlerThread(); - ht->start(); - - QtServiceSysPrivate* sys = QtServiceSysPrivate::instance; - - // Wait until service args have been received by serviceMain. - // If Windows doesn't call serviceMain (or - // StartServiceControlDispatcher doesn't return an error) within - // a timeout of 20 secs, something is very wrong; give up - if (!sys->startSemaphore.tryAcquire(1, 20000)) - return false; - - if (!ht->calledOk()) { - if (ht->runningAsConsole()) - return controller.start(args.mid(1)); - else - return false; - } - - int argc = sys->serviceArgs.size(); - QVector<char *> argv(argc); - QList<QByteArray> argvData; - for (int i = 0; i < argc; ++i) - argvData.append(sys->serviceArgs.at(i).toLocal8Bit()); - for (int i = 0; i < argc; ++i) - argv[i] = argvData[i].data(); - - q_ptr->createApplication(argc, argv.data()); - QCoreApplication *app = QCoreApplication::instance(); - if (!app) - return false; - -#if QT_VERSION >= 0x050000 - QAbstractEventDispatcher::instance()->installNativeEventFilter(qtServiceAppEventFilter()); -#else - QtServiceSysPrivate::nextFilter = app->setEventFilter(myEventFilter); -#endif - - sys->controllerHandler = new QtServiceControllerHandler(sys); - - sys->startSemaphore2.release(); // let serviceMain continue (and end) - - sys->status.dwWin32ExitCode = q_ptr->executeApplication(); - sys->setStatus(SERVICE_STOPPED); - - if (ht->isRunning()) - ht->wait(1000); // let the handler thread finish - delete sys->controllerHandler; - sys->controllerHandler = 0; - if (ht->isFinished()) - delete ht; - delete app; - sysCleanup(); - return true; -} - -bool QtServiceBasePrivate::install(const QString &account, const QString &password) -{ - bool result = false; - if (!winServiceInit()) - return result; - - // Open the Service Control Manager - SC_HANDLE hSCM = pOpenSCManager(0, 0, SC_MANAGER_ALL_ACCESS); - if (hSCM) { - QString acc = account; - DWORD dwStartType = startupType == QtServiceController::AutoStartup ? SERVICE_AUTO_START : SERVICE_DEMAND_START; - DWORD dwServiceType = SERVICE_WIN32_OWN_PROCESS; - wchar_t *act = 0; - wchar_t *pwd = 0; - if (!acc.isEmpty()) { - // The act string must contain a string of the format "Domain\UserName", - // so if only a username was specified without a domain, default to the local machine domain. - if (!acc.contains(QChar('\\'))) { - acc.prepend(QLatin1String(".\\")); - } - if (!acc.endsWith(QLatin1String("\\LocalSystem"))) - act = (wchar_t*)acc.utf16(); - } - if (!password.isEmpty() && act) { - pwd = (wchar_t*)password.utf16(); - } - - // Only set INTERACTIVE if act is LocalSystem. (and act should be 0 if it is LocalSystem). - if (!act) dwServiceType |= SERVICE_INTERACTIVE_PROCESS; - - // Create the service - SC_HANDLE hService = pCreateService(hSCM, (wchar_t *)controller.serviceName().utf16(), - (wchar_t *)controller.serviceName().utf16(), - SERVICE_ALL_ACCESS, - dwServiceType, // QObject::inherits ( const char * className ) for no inter active ???? - dwStartType, SERVICE_ERROR_NORMAL, (wchar_t *)filePath().utf16(), - 0, 0, 0, - act, pwd); - if (hService) { - result = true; - if (!serviceDescription.isEmpty()) { - SERVICE_DESCRIPTION sdesc; - sdesc.lpDescription = (wchar_t *)serviceDescription.utf16(); - pChangeServiceConfig2(hService, SERVICE_CONFIG_DESCRIPTION, &sdesc); - } - pCloseServiceHandle(hService); - } - pCloseServiceHandle(hSCM); - } - return result; -} - -QString QtServiceBasePrivate::filePath() const -{ - wchar_t path[_MAX_PATH]; - ::GetModuleFileNameW( 0, path, sizeof(path) ); - return QString::fromUtf16((unsigned short*)path); -} - -bool QtServiceBasePrivate::sysInit() -{ - sysd = new QtServiceSysPrivate(); - - sysd->serviceStatus = 0; - sysd->status.dwServiceType = SERVICE_WIN32_OWN_PROCESS|SERVICE_INTERACTIVE_PROCESS; - sysd->status.dwCurrentState = SERVICE_STOPPED; - sysd->status.dwControlsAccepted = sysd->serviceFlags(serviceFlags); - sysd->status.dwWin32ExitCode = NO_ERROR; - sysd->status.dwServiceSpecificExitCode = 0; - sysd->status.dwCheckPoint = 0; - sysd->status.dwWaitHint = 0; - - return true; -} - -void QtServiceBasePrivate::sysSetPath() -{ - -} - -void QtServiceBasePrivate::sysCleanup() -{ - if (sysd) { - delete sysd; - sysd = 0; - } -} - -void QtServiceBase::setServiceFlags(QtServiceBase::ServiceFlags flags) -{ - if (d_ptr->serviceFlags == flags) - return; - d_ptr->serviceFlags = flags; - if (d_ptr->sysd) - d_ptr->sysd->setServiceFlags(flags); -} - - diff --git a/isis/src/base/apps/spiceit/QtWebApp/qtservice/qtunixserversocket.cpp b/isis/src/base/apps/spiceit/QtWebApp/qtservice/qtunixserversocket.cpp deleted file mode 100644 index 0ad9134c7127cdbe11797c9d5d3fdf32be807a45..0000000000000000000000000000000000000000 --- a/isis/src/base/apps/spiceit/QtWebApp/qtservice/qtunixserversocket.cpp +++ /dev/null @@ -1,92 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the Qt Solutions component. -** -** $QT_BEGIN_LICENSE:BSD$ -** You may use this file under the terms of the BSD license as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names -** of its contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qtunixserversocket.h" -#include <sys/types.h> -#include <sys/un.h> -#include <sys/socket.h> -#include <string.h> -#include <unistd.h> - -#ifndef SUN_LEN -#define SUN_LEN(ptr) ((size_t)(((struct sockaddr_un *) 0)->sun_path) \ - +strlen ((ptr)->sun_path)) -#endif - -QtUnixServerSocket::QtUnixServerSocket(const QString &path, QObject *parent) - : QTcpServer(parent) -{ - setPath(path); -} - -QtUnixServerSocket::QtUnixServerSocket(QObject *parent) - : QTcpServer(parent) -{ -} - -void QtUnixServerSocket::setPath(const QString &path) -{ - path_.clear(); - - int sock = ::socket(PF_UNIX, SOCK_STREAM, 0); - if (sock != -1) { - struct sockaddr_un addr; - ::memset(&addr, 0, sizeof(struct sockaddr_un)); - addr.sun_family = AF_UNIX; - ::unlink(path.toLatin1().constData()); // ### This might need to be changed - unsigned int pathlen = strlen(path.toLatin1().constData()); - if (pathlen > sizeof(addr.sun_path)) pathlen = sizeof(addr.sun_path); - ::memcpy(addr.sun_path, path.toLatin1().constData(), pathlen); - if ((::bind(sock, (struct sockaddr *)&addr, SUN_LEN(&addr)) != -1) && - (::listen(sock, 5) != -1)) { - setSocketDescriptor(sock); - path_ = path; - } - } -} - -void QtUnixServerSocket::close() -{ - QTcpServer::close(); - if (!path_.isEmpty()) { - ::unlink(path_.toLatin1().constData()); - path_.clear(); - } -} diff --git a/isis/src/base/apps/spiceit/QtWebApp/qtservice/qtunixserversocket.h b/isis/src/base/apps/spiceit/QtWebApp/qtservice/qtunixserversocket.h deleted file mode 100644 index 1fc8b702c88bd2c9d6a3be666c310ab51c006d00..0000000000000000000000000000000000000000 --- a/isis/src/base/apps/spiceit/QtWebApp/qtservice/qtunixserversocket.h +++ /dev/null @@ -1,61 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the Qt Solutions component. -** -** $QT_BEGIN_LICENSE:BSD$ -** You may use this file under the terms of the BSD license as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names -** of its contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QTUNIXSERVERSOCKET_H -#define QTUNIXSERVERSOCKET_H - -#include <QTcpServer> - -class QtUnixServerSocket : public QTcpServer -{ - Q_OBJECT -public: - QtUnixServerSocket(const QString &path, QObject *parent = 0); - QtUnixServerSocket(QObject *parent = 0); - - void setPath(const QString &path); - void close(); - -private: - QString path_; -}; - - -#endif diff --git a/isis/src/base/apps/spiceit/QtWebApp/qtservice/qtunixsocket.cpp b/isis/src/base/apps/spiceit/QtWebApp/qtservice/qtunixsocket.cpp deleted file mode 100644 index f6d4c9700fba36f879787bcd551cb3e99abaf1c6..0000000000000000000000000000000000000000 --- a/isis/src/base/apps/spiceit/QtWebApp/qtservice/qtunixsocket.cpp +++ /dev/null @@ -1,78 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the Qt Solutions component. -** -** $QT_BEGIN_LICENSE:BSD$ -** You may use this file under the terms of the BSD license as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names -** of its contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qtunixsocket.h" -#include <sys/types.h> -#include <sys/un.h> -#include <sys/socket.h> -#include <string.h> -#include <unistd.h> - -#ifndef SUN_LEN -#define SUN_LEN(ptr) ((size_t)(((struct sockaddr_un *) 0)->sun_path) \ - +strlen ((ptr)->sun_path)) -#endif - -QtUnixSocket::QtUnixSocket(QObject *parent) - : QTcpSocket(parent) -{ -} - -bool QtUnixSocket::connectTo(const QString &path) -{ - bool ret = false; - int sock = ::socket(PF_UNIX, SOCK_STREAM, 0); - if (sock != -1) { - struct sockaddr_un addr; - ::memset(&addr, 0, sizeof(struct sockaddr_un)); - addr.sun_family = AF_UNIX; - size_t pathlen = strlen(path.toLatin1().constData()); - pathlen = qMin(pathlen, sizeof(addr.sun_path)); - ::memcpy(addr.sun_path, path.toLatin1().constData(), pathlen); - int err = ::connect(sock, (struct sockaddr *)&addr, SUN_LEN(&addr)); - if (err != -1) { - setSocketDescriptor(sock); - ret = true; - } else { - ::close(sock); - } - } - return ret; -} diff --git a/isis/src/base/apps/spiceit/QtWebApp/qtservice/qtunixsocket.h b/isis/src/base/apps/spiceit/QtWebApp/qtservice/qtunixsocket.h deleted file mode 100644 index 1d34fba4d5dae70eef6feb2c64ca287ae9145165..0000000000000000000000000000000000000000 --- a/isis/src/base/apps/spiceit/QtWebApp/qtservice/qtunixsocket.h +++ /dev/null @@ -1,55 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the Qt Solutions component. -** -** $QT_BEGIN_LICENSE:BSD$ -** You may use this file under the terms of the BSD license as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names -** of its contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QTUNIXSOCKET_H -#define QTUNIXSOCKET_H - -#include <QTcpSocket> - -class QtUnixSocket : public QTcpSocket -{ - Q_OBJECT -public: - QtUnixSocket(QObject *parent = 0); - - bool connectTo(const QString &path); -}; - -#endif diff --git a/isis/src/base/apps/spiceit/QtWebApp/templateengine/template.cpp b/isis/src/base/apps/spiceit/QtWebApp/templateengine/template.cpp deleted file mode 100644 index 6508bf1ca7df206b0106688c5cf92be49044791f..0000000000000000000000000000000000000000 --- a/isis/src/base/apps/spiceit/QtWebApp/templateengine/template.cpp +++ /dev/null @@ -1,243 +0,0 @@ -/** - @file - @author Stefan Frings -*/ - -#include "template.h" -#include <QFileInfo> - -using namespace stefanfrings; - -Template::Template(QString source, QString sourceName) - : QString(source) -{ - this->sourceName=sourceName; - this->warnings=false; -} - -Template::Template(QFile& file, QTextCodec* textCodec) -{ - this->warnings=false; - sourceName=QFileInfo(file.fileName()).baseName(); - if (!file.isOpen()) - { - file.open(QFile::ReadOnly | QFile::Text); - } - QByteArray data=file.readAll(); - file.close(); - if (data.size()==0 || file.error()) - { - qCritical("Template: cannot read from %s, %s",qPrintable(sourceName),qPrintable(file.errorString())); - } - else - { - append(textCodec->toUnicode(data)); - } -} - - -int Template::setVariable(QString name, QString value) -{ - int count=0; - QString variable="{"+name+"}"; - int start=indexOf(variable); - while (start>=0) - { - replace(start, variable.length(), value); - count++; - start=indexOf(variable,start+value.length()); - } - if (count==0 && warnings) - { - qWarning("Template: missing variable %s in %s",qPrintable(variable),qPrintable(sourceName)); - } - return count; -} - -int Template::setCondition(QString name, bool value) -{ - int count=0; - QString startTag=QString("{if %1}").arg(name); - QString elseTag=QString("{else %1}").arg(name); - QString endTag=QString("{end %1}").arg(name); - // search for if-else-end - int start=indexOf(startTag); - while (start>=0) - { - int end=indexOf(endTag,start+startTag.length()); - if (end>=0) - { - count++; - int ellse=indexOf(elseTag,start+startTag.length()); - if (ellse>start && ellse<end) - { - // there is an else part - if (value==true) - { - QString truePart=mid(start+startTag.length(), ellse-start-startTag.length()); - replace(start, end-start+endTag.length(), truePart); - } - else - { - // value==false - QString falsePart=mid(ellse+elseTag.length(), end-ellse-elseTag.length()); - replace(start, end-start+endTag.length(), falsePart); - } - } - else if (value==true) - { - // and no else part - QString truePart=mid(start+startTag.length(), end-start-startTag.length()); - replace(start, end-start+endTag.length(), truePart); - } - else - { - // value==false and no else part - replace(start, end-start+endTag.length(), ""); - } - start=indexOf(startTag,start); - } - else - { - qWarning("Template: missing condition end %s in %s",qPrintable(endTag),qPrintable(sourceName)); - } - } - // search for ifnot-else-end - QString startTag2="{ifnot "+name+"}"; - start=indexOf(startTag2); - while (start>=0) - { - int end=indexOf(endTag,start+startTag2.length()); - if (end>=0) - { - count++; - int ellse=indexOf(elseTag,start+startTag2.length()); - if (ellse>start && ellse<end) - { - // there is an else part - if (value==false) - { - QString falsePart=mid(start+startTag2.length(), ellse-start-startTag2.length()); - replace(start, end-start+endTag.length(), falsePart); - } - else - { - // value==true - QString truePart=mid(ellse+elseTag.length(), end-ellse-elseTag.length()); - replace(start, end-start+endTag.length(), truePart); - } - } - else if (value==false) - { - // and no else part - QString falsePart=mid(start+startTag2.length(), end-start-startTag2.length()); - replace(start, end-start+endTag.length(), falsePart); - } - else - { - // value==true and no else part - replace(start, end-start+endTag.length(), ""); - } - start=indexOf(startTag2,start); - } - else - { - qWarning("Template: missing condition end %s in %s",qPrintable(endTag),qPrintable(sourceName)); - } - } - if (count==0 && warnings) - { - qWarning("Template: missing condition %s or %s in %s",qPrintable(startTag),qPrintable(startTag2),qPrintable(sourceName)); - } - return count; -} - -int Template::loop(QString name, int repetitions) -{ - Q_ASSERT(repetitions>=0); - int count=0; - QString startTag="{loop "+name+"}"; - QString elseTag="{else "+name+"}"; - QString endTag="{end "+name+"}"; - // search for loop-else-end - int start=indexOf(startTag); - while (start>=0) - { - int end=indexOf(endTag,start+startTag.length()); - if (end>=0) - { - count++; - int ellse=indexOf(elseTag,start+startTag.length()); - if (ellse>start && ellse<end) - { - // there is an else part - if (repetitions>0) - { - QString loopPart=mid(start+startTag.length(), ellse-start-startTag.length()); - QString insertMe; - for (int i=0; i<repetitions; ++i) - { - // number variables, conditions and sub-loop within the loop - QString nameNum=name+QString::number(i); - QString s=loopPart; - s.replace(QString("{%1.").arg(name), QString("{%1.").arg(nameNum)); - s.replace(QString("{if %1.").arg(name), QString("{if %1.").arg(nameNum)); - s.replace(QString("{ifnot %1.").arg(name), QString("{ifnot %1.").arg(nameNum)); - s.replace(QString("{else %1.").arg(name), QString("{else %1.").arg(nameNum)); - s.replace(QString("{end %1.").arg(name), QString("{end %1.").arg(nameNum)); - s.replace(QString("{loop %1.").arg(name), QString("{loop %1.").arg(nameNum)); - insertMe.append(s); - } - replace(start, end-start+endTag.length(), insertMe); - } - else - { - // repetitions==0 - QString elsePart=mid(ellse+elseTag.length(), end-ellse-elseTag.length()); - replace(start, end-start+endTag.length(), elsePart); - } - } - else if (repetitions>0) - { - // and no else part - QString loopPart=mid(start+startTag.length(), end-start-startTag.length()); - QString insertMe; - for (int i=0; i<repetitions; ++i) - { - // number variables, conditions and sub-loop within the loop - QString nameNum=name+QString::number(i); - QString s=loopPart; - s.replace(QString("{%1.").arg(name), QString("{%1.").arg(nameNum)); - s.replace(QString("{if %1.").arg(name), QString("{if %1.").arg(nameNum)); - s.replace(QString("{ifnot %1.").arg(name), QString("{ifnot %1.").arg(nameNum)); - s.replace(QString("{else %1.").arg(name), QString("{else %1.").arg(nameNum)); - s.replace(QString("{end %1.").arg(name), QString("{end %1.").arg(nameNum)); - s.replace(QString("{loop %1.").arg(name), QString("{loop %1.").arg(nameNum)); - insertMe.append(s); - } - replace(start, end-start+endTag.length(), insertMe); - } - else - { - // repetitions==0 and no else part - replace(start, end-start+endTag.length(), ""); - } - start=indexOf(startTag,start); - } - else - { - qWarning("Template: missing loop end %s in %s",qPrintable(endTag),qPrintable(sourceName)); - } - } - if (count==0 && warnings) - { - qWarning("Template: missing loop %s in %s",qPrintable(startTag),qPrintable(sourceName)); - } - return count; -} - -void Template::enableWarnings(bool enable) -{ - warnings=enable; -} - diff --git a/isis/src/base/apps/spiceit/QtWebApp/templateengine/template.h b/isis/src/base/apps/spiceit/QtWebApp/templateengine/template.h deleted file mode 100644 index 71c94c4fab5726d404c92a59c035922963ac4990..0000000000000000000000000000000000000000 --- a/isis/src/base/apps/spiceit/QtWebApp/templateengine/template.h +++ /dev/null @@ -1,172 +0,0 @@ -/** - @file - @author Stefan Frings -*/ - -#ifndef TEMPLATE_H -#define TEMPLATE_H - -#include <QString> -#include <QRegExp> -#include <QIODevice> -#include <QTextCodec> -#include <QFile> -#include <QString> -#include "templateglobal.h" - -namespace stefanfrings { - -/** - Enhanced version of QString for template processing. Templates - are usually loaded from files, but may also be loaded from - prepared Strings. - Example template file: - <p><code><pre> - Hello {username}, how are you? - - {if locked} - Your account is locked. - {else locked} - Welcome on our system. - {end locked} - - The following users are on-line: - Username Time - {loop user} - {user.name} {user.time} - {end user} - </pre></code></p> - <p> - Example code to fill this template: - <p><code><pre> - Template t(QFile("test.tpl"),QTextCode::codecForName("UTF-8")); - t.setVariable("username", "Stefan"); - t.setCondition("locked",false); - t.loop("user",2); - t.setVariable("user0.name,"Markus"); - t.setVariable("user0.time,"8:30"); - t.setVariable("user1.name,"Roland"); - t.setVariable("user1.time,"8:45"); - </pre></code></p> - <p> - The code example above shows how variable within loops are numbered. - Counting starts with 0. Loops can be nested, for example: - <p><code><pre> - <table> - {loop row} - <tr> - {loop row.column} - <td>{row.column.value}</td> - {end row.column} - </tr> - {end row} - </table> - </pre></code></p> - <p> - Example code to fill this nested loop with 3 rows and 4 columns: - <p><code><pre> - t.loop("row",3); - - t.loop("row0.column",4); - t.setVariable("row0.column0.value","a"); - t.setVariable("row0.column1.value","b"); - t.setVariable("row0.column2.value","c"); - t.setVariable("row0.column3.value","d"); - - t.loop("row1.column",4); - t.setVariable("row1.column0.value","e"); - t.setVariable("row1.column1.value","f"); - t.setVariable("row1.column2.value","g"); - t.setVariable("row1.column3.value","h"); - - t.loop("row2.column",4); - t.setVariable("row2.column0.value","i"); - t.setVariable("row2.column1.value","j"); - t.setVariable("row2.column2.value","k"); - t.setVariable("row2.column3.value","l"); - </pre></code></p> - @see TemplateLoader - @see TemplateCache -*/ - -class DECLSPEC Template : public QString { -public: - - /** - Constructor that reads the template from a string. - @param source The template source text - @param sourceName Name of the source file, used for logging - */ - Template(QString source, QString sourceName); - - /** - Constructor that reads the template from a file. Note that this class does not - cache template files by itself, so using this constructor is only recommended - to be used on local filesystem. - @param file File that provides the source text - @param textCodec Encoding of the source - @see TemplateLoader - @see TemplateCache - */ - Template(QFile& file, QTextCodec* textCodec); - - /** - Replace a variable by the given value. - Affects tags with the syntax - - - {name} - - After settings the - value of a variable, the variable does not exist anymore, - it it cannot be changed multiple times. - @param name name of the variable - @param value new value - @return The count of variables that have been processed - */ - int setVariable(QString name, QString value); - - /** - Set a condition. This affects tags with the syntax - - - {if name}...{end name} - - {if name}...{else name}...{end name} - - {ifnot name}...{end name} - - {ifnot name}...{else name}...{end name} - - @param name Name of the condition - @param value Value of the condition - @return The count of conditions that have been processed - */ - int setCondition(QString name, bool value); - - /** - Set number of repetitions of a loop. - This affects tags with the syntax - - - {loop name}...{end name} - - {loop name}...{else name}...{end name} - - @param name Name of the loop - @param repetitions The number of repetitions - @return The number of loops that have been processed - */ - int loop(QString name, int repetitions); - - /** - Enable warnings for missing tags - @param enable Warnings are enabled, if true - */ - void enableWarnings(bool enable=true); - -private: - - /** Name of the source file */ - QString sourceName; - - /** Enables warnings, if true */ - bool warnings; -}; - -} // end of namespace - -#endif // TEMPLATE_H diff --git a/isis/src/base/apps/spiceit/QtWebApp/templateengine/templatecache.cpp b/isis/src/base/apps/spiceit/QtWebApp/templateengine/templatecache.cpp deleted file mode 100644 index ffee2786e815ea5150b88c26dd6ab9092485c5c0..0000000000000000000000000000000000000000 --- a/isis/src/base/apps/spiceit/QtWebApp/templateengine/templatecache.cpp +++ /dev/null @@ -1,37 +0,0 @@ -#include "templatecache.h" -#include <QDateTime> -#include <QStringList> -#include <QSet> - -using namespace stefanfrings; - -TemplateCache::TemplateCache(QSettings* settings, QObject* parent) - :TemplateLoader(settings,parent) -{ - cache.setMaxCost(settings->value("cacheSize","1000000").toInt()); - cacheTimeout=settings->value("cacheTime","60000").toInt(); - qDebug("TemplateCache: timeout=%i, size=%i",cacheTimeout,cache.maxCost()); -} - -QString TemplateCache::tryFile(QString localizedName) -{ - qint64 now=QDateTime::currentMSecsSinceEpoch(); - mutex.lock(); - // search in cache - qDebug("TemplateCache: trying cached %s",qPrintable(localizedName)); - CacheEntry* entry=cache.object(localizedName); - if (entry && (cacheTimeout==0 || entry->created>now-cacheTimeout)) - { - mutex.unlock(); - return entry->document; - } - // search on filesystem - entry=new CacheEntry(); - entry->created=now; - entry->document=TemplateLoader::tryFile(localizedName); - // Store in cache even when the file did not exist, to remember that there is no such file - cache.insert(localizedName,entry,entry->document.size()); - mutex.unlock(); - return entry->document; -} - diff --git a/isis/src/base/apps/spiceit/QtWebApp/templateengine/templatecache.h b/isis/src/base/apps/spiceit/QtWebApp/templateengine/templatecache.h deleted file mode 100644 index ed8a35c082b2176f1fc22d9a9ba474ef1633427f..0000000000000000000000000000000000000000 --- a/isis/src/base/apps/spiceit/QtWebApp/templateengine/templatecache.h +++ /dev/null @@ -1,84 +0,0 @@ -#ifndef TEMPLATECACHE_H -#define TEMPLATECACHE_H - -#include <QCache> -#include "templateglobal.h" -#include "templateloader.h" - -namespace stefanfrings { - -/** - Caching template loader, reduces the amount of I/O and improves performance - on remote file systems. The cache has a limited size, it prefers to keep - the last recently used files. Optionally, the maximum time of cached entries - can be defined to enforce a reload of the template file after a while. - <p> - In case of local file system, the use of this cache is optionally, since - the operating system caches files already. - <p> - Loads localized versions of template files. If the caller requests a file with the - name "index" and the suffix is ".tpl" and the requested locale is "de_DE, de, en-US", - then files are searched in the following order: - - - index-de_DE.tpl - - index-de.tpl - - index-en_US.tpl - - index-en.tpl - - index.tpl - <p> - The following settings are required: - <code><pre> - path=../templates - suffix=.tpl - encoding=UTF-8 - cacheSize=1000000 - cacheTime=60000 - </pre></code> - The path is relative to the directory of the config file. In case of windows, if the - settings are in the registry, the path is relative to the current working directory. - <p> - Files are cached as long as possible, when cacheTime=0. - @see TemplateLoader -*/ - -class DECLSPEC TemplateCache : public TemplateLoader { - Q_OBJECT - Q_DISABLE_COPY(TemplateCache) -public: - - /** - Constructor. - @param settings configurations settings - @param parent Parent object - */ - TemplateCache(QSettings* settings, QObject* parent=0); - -protected: - - /** - Try to get a file from cache or filesystem. - @param localizedName Name of the template with locale to find - @return The template document, or empty string if not found - */ - virtual QString tryFile(QString localizedName); - -private: - - struct CacheEntry { - QString document; - qint64 created; - }; - - /** Timeout for each cached file */ - int cacheTimeout; - - /** Cache storage */ - QCache<QString,CacheEntry> cache; - - /** Used to synchronize threads */ - QMutex mutex; -}; - -} // end of namespace - -#endif // TEMPLATECACHE_H diff --git a/isis/src/base/apps/spiceit/QtWebApp/templateengine/templateengine.pri b/isis/src/base/apps/spiceit/QtWebApp/templateengine/templateengine.pri deleted file mode 100644 index 722c17fc320fe2992e6192ffa11250e94f931d96..0000000000000000000000000000000000000000 --- a/isis/src/base/apps/spiceit/QtWebApp/templateengine/templateengine.pri +++ /dev/null @@ -1,11 +0,0 @@ -INCLUDEPATH += $$PWD -DEPENDPATH += $$PWD - -HEADERS += $$PWD/templateglobal.h -HEADERS += $$PWD/template.h -HEADERS += $$PWD/templateloader.h -HEADERS += $$PWD/templatecache.h - -SOURCES += $$PWD/template.cpp -SOURCES += $$PWD/templateloader.cpp -SOURCES += $$PWD/templatecache.cpp diff --git a/isis/src/base/apps/spiceit/QtWebApp/templateengine/templateglobal.h b/isis/src/base/apps/spiceit/QtWebApp/templateengine/templateglobal.h deleted file mode 100644 index eb1aa9d44658f0e504dcf1317594d8aaf9469920..0000000000000000000000000000000000000000 --- a/isis/src/base/apps/spiceit/QtWebApp/templateengine/templateglobal.h +++ /dev/null @@ -1,24 +0,0 @@ -/** - @file - @author Stefan Frings -*/ - -#ifndef TEMPLATEGLOBAL_H -#define TEMPLATEGLOBAL_H - -#include <QtGlobal> - -// This is specific to Windows dll's -#if defined(Q_OS_WIN) - #if defined(QTWEBAPPLIB_EXPORT) - #define DECLSPEC Q_DECL_EXPORT - #elif defined(QTWEBAPPLIB_IMPORT) - #define DECLSPEC Q_DECL_IMPORT - #endif -#endif -#if !defined(DECLSPEC) - #define DECLSPEC -#endif - -#endif // TEMPLATEGLOBAL_H - diff --git a/isis/src/base/apps/spiceit/QtWebApp/templateengine/templateloader.cpp b/isis/src/base/apps/spiceit/QtWebApp/templateengine/templateloader.cpp deleted file mode 100644 index 8d1af0a8863438ef9632fdb0dcf5ce9a019962c2..0000000000000000000000000000000000000000 --- a/isis/src/base/apps/spiceit/QtWebApp/templateengine/templateloader.cpp +++ /dev/null @@ -1,113 +0,0 @@ -/** - @file - @author Stefan Frings -*/ - -#include "templateloader.h" -#include <QFile> -#include <QFileInfo> -#include <QStringList> -#include <QDir> -#include <QSet> - -using namespace stefanfrings; - -TemplateLoader::TemplateLoader(QSettings* settings, QObject* parent) - : QObject(parent) -{ - templatePath=settings->value("path",".").toString(); - // Convert relative path to absolute, based on the directory of the config file. -#ifdef Q_OS_WIN32 - if (QDir::isRelativePath(templatePath) && settings->format()!=QSettings::NativeFormat) -#else - if (QDir::isRelativePath(templatePath)) -#endif - { - QFileInfo configFile(settings->fileName()); - templatePath=QFileInfo(configFile.absolutePath(),templatePath).absoluteFilePath(); - } - fileNameSuffix=settings->value("suffix",".tpl").toString(); - QString encoding=settings->value("encoding").toString(); - if (encoding.isEmpty()) - { - textCodec=QTextCodec::codecForLocale(); - } - else - { - textCodec=QTextCodec::codecForName(encoding.toLocal8Bit()); - } - qDebug("TemplateLoader: path=%s, codec=%s",qPrintable(templatePath),textCodec->name().data()); -} - -TemplateLoader::~TemplateLoader() -{} - -QString TemplateLoader::tryFile(QString localizedName) -{ - QString fileName=templatePath+"/"+localizedName+fileNameSuffix; - qDebug("TemplateCache: trying file %s",qPrintable(fileName)); - QFile file(fileName); - if (file.exists()) { - file.open(QIODevice::ReadOnly); - QString document=textCodec->toUnicode(file.readAll()); - file.close(); - if (file.error()) - { - qCritical("TemplateLoader: cannot load file %s, %s",qPrintable(fileName),qPrintable(file.errorString())); - return ""; - } - else - { - return document; - } - } - return ""; -} - -Template TemplateLoader::getTemplate(QString templateName, QString locales) -{ - QSet<QString> tried; // used to suppress duplicate attempts - QStringList locs=locales.split(',',QString::SkipEmptyParts); - - // Search for exact match - foreach (QString loc,locs) - { - loc.replace(QRegExp(";.*"),""); - loc.replace('-','_'); - QString localizedName=templateName+"-"+loc.trimmed(); - if (!tried.contains(localizedName)) - { - QString document=tryFile(localizedName); - if (!document.isEmpty()) { - return Template(document,localizedName); - } - tried.insert(localizedName); - } - } - - // Search for correct language but any country - foreach (QString loc,locs) - { - loc.replace(QRegExp("[;_-].*"),""); - QString localizedName=templateName+"-"+loc.trimmed(); - if (!tried.contains(localizedName)) - { - QString document=tryFile(localizedName); - if (!document.isEmpty()) - { - return Template(document,localizedName); - } - tried.insert(localizedName); - } - } - - // Search for default file - QString document=tryFile(templateName); - if (!document.isEmpty()) - { - return Template(document,templateName); - } - - qCritical("TemplateCache: cannot find template %s",qPrintable(templateName)); - return Template("",templateName); -} diff --git a/isis/src/base/apps/spiceit/QtWebApp/templateengine/templateloader.h b/isis/src/base/apps/spiceit/QtWebApp/templateengine/templateloader.h deleted file mode 100644 index b846f3c57c8a47d6cabd8dd1d10b5ab375fe8110..0000000000000000000000000000000000000000 --- a/isis/src/base/apps/spiceit/QtWebApp/templateengine/templateloader.h +++ /dev/null @@ -1,87 +0,0 @@ -/** - @file - @author Stefan Frings -*/ - -#ifndef TEMPLATELOADER_H -#define TEMPLATELOADER_H - -#include <QString> -#include <QSettings> -#include <QTextCodec> -#include <QMutex> -#include "templateglobal.h" -#include "template.h" - -namespace stefanfrings { - -/** - Loads localized versions of template files. If the caller requests a file with the - name "index" and the suffix is ".tpl" and the requested locale is "de_DE, de, en-US", - then files are searched in the following order: - - - index-de_DE.tpl - - index-de.tpl - - index-en_US.tpl - - index-en.tpl - - index.tpl - - The following settings are required: - <code><pre> - path=../templates - suffix=.tpl - encoding=UTF-8 - </pre></code> - The path is relative to the directory of the config file. In case of windows, if the - settings are in the registry, the path is relative to the current working directory. - @see TemplateCache -*/ - -class DECLSPEC TemplateLoader : public QObject { - Q_OBJECT - Q_DISABLE_COPY(TemplateLoader) -public: - - /** - Constructor. - @param settings configurations settings - @param parent parent object - */ - TemplateLoader(QSettings* settings, QObject* parent=0); - - /** Destructor */ - virtual ~TemplateLoader(); - - /** - Get a template for a given locale. - This method is thread safe. - @param templateName base name of the template file, without suffix and without locale - @param locales Requested locale(s), e.g. "de_DE, en_EN". Strings in the format of - the HTTP header Accept-Locale may be used. Badly formatted parts in the string are silently - ignored. - @return If the template cannot be loaded, an error message is logged and an empty template is returned. - */ - Template getTemplate(QString templateName, QString locales=QString()); - -protected: - - /** - Try to get a file from cache or filesystem. - @param localizedName Name of the template with locale to find - @return The template document, or empty string if not found - */ - virtual QString tryFile(QString localizedName); - - /** Directory where the templates are searched */ - QString templatePath; - - /** Suffix to the filenames */ - QString fileNameSuffix; - - /** Codec for decoding the files */ - QTextCodec* textCodec; -}; - -} // end of namespace - -#endif // TEMPLATELOADER_H diff --git a/isis/src/base/apps/spiceit/spiceit.pro b/isis/src/base/apps/spiceit/spiceit.pro index c6f2195e02b4b7b2b78ab36df28a6c1b4a73d4d3..4fc02fd2041d5806d5429897ae161cb178c6ba03 100644 --- a/isis/src/base/apps/spiceit/spiceit.pro +++ b/isis/src/base/apps/spiceit/spiceit.pro @@ -33,7 +33,8 @@ win32 { } # Directories, where the *.h files are stored -INCLUDEPATH += $$PWD/QtWebApp +#INCLUDEPATH += $$PWD/QtWebApp +INCLUDEPATH += /usgs/pkgs/local/v007/src/QtWebApp # Directory where the release version of the shared library (*.dll or *.so) is stored, and base name of the file. CONFIG(release, debug|release) {