handle programmatic DS requests except for script creation

This commit is contained in:
Stephen Birarda 2014-01-17 11:29:20 -08:00
parent bce40a9963
commit 40cdba203d
6 changed files with 159 additions and 164 deletions

View file

@ -13,6 +13,7 @@
#include <QtCore/QStringList> #include <QtCore/QStringList>
#include <QtCore/QTimer> #include <QtCore/QTimer>
#include <HttpConnection.h>
#include <PacketHeaders.h> #include <PacketHeaders.h>
#include <SharedUtil.h> #include <SharedUtil.h>
#include <UUID.h> #include <UUID.h>
@ -33,7 +34,7 @@ const quint16 DOMAIN_SERVER_HTTP_PORT = 8080;
DomainServer::DomainServer(int argc, char* argv[]) : DomainServer::DomainServer(int argc, char* argv[]) :
QCoreApplication(argc, argv), QCoreApplication(argc, argv),
_httpManager(DOMAIN_SERVER_HTTP_PORT, QString("%1/resources/web/").arg(QCoreApplication::applicationDirPath())), _httpManager(DOMAIN_SERVER_HTTP_PORT, QString("%1/resources/web/").arg(QCoreApplication::applicationDirPath()), this),
_assignmentQueueMutex(), _assignmentQueueMutex(),
_assignmentQueue(), _assignmentQueue(),
_staticAssignmentFile(QString("%1/config.ds").arg(QCoreApplication::applicationDirPath())), _staticAssignmentFile(QString("%1/config.ds").arg(QCoreApplication::applicationDirPath())),
@ -293,142 +294,122 @@ QJsonObject jsonObjectForNode(Node* node) {
return nodeJson; return nodeJson;
} }
//int DomainServer::civetwebRequestHandler(struct mg_connection *connection) { bool DomainServer::handleHTTPRequest(HttpConnection* connection, const QString& path) {
// const struct mg_request_info* ri = mg_get_request_info(connection); const QString JSON_MIME_TYPE = "application/json";
//
// const char RESPONSE_200[] = "HTTP/1.0 200 OK\r\n\r\n"; const QString URI_ASSIGNMENT = "/assignment";
// const char RESPONSE_400[] = "HTTP/1.0 400 Bad Request\r\n\r\n"; const QString URI_NODE = "/node";
//
// const char URI_ASSIGNMENT[] = "/assignment"; if (connection->requestOperation() == QNetworkAccessManager::GetOperation) {
// const char URI_NODE[] = "/node"; if (path == "/assignments.json") {
// // user is asking for json list of assignments
// if (strcmp(ri->request_method, "GET") == 0) {
// if (strcmp(ri->uri, "/assignments.json") == 0) { // setup the JSON
// // user is asking for json list of assignments QJsonObject assignmentJSON;
// QJsonObject assignedNodesJSON;
// // start with a 200 response
// mg_printf(connection, "%s", RESPONSE_200); // enumerate the NodeList to find the assigned nodes
// foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) {
// // setup the JSON if (node->getLinkedData()) {
// QJsonObject assignmentJSON; // add the node using the UUID as the key
// QJsonObject assignedNodesJSON; QString uuidString = uuidStringWithoutCurlyBraces(node->getUUID());
// assignedNodesJSON[uuidString] = jsonObjectForNode(node.data());
// // enumerate the NodeList to find the assigned nodes }
// foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) { }
// if (node->getLinkedData()) {
// // add the node using the UUID as the key assignmentJSON["fulfilled"] = assignedNodesJSON;
// QString uuidString = uuidStringWithoutCurlyBraces(node->getUUID());
// assignedNodesJSON[uuidString] = jsonObjectForNode(node.data()); QJsonObject queuedAssignmentsJSON;
// }
// } // add the queued but unfilled assignments to the json
// std::deque<Assignment*>::iterator assignment = domainServerInstance->_assignmentQueue.begin();
// assignmentJSON["fulfilled"] = assignedNodesJSON;
// while (assignment != domainServerInstance->_assignmentQueue.end()) {
// QJsonObject queuedAssignmentsJSON; QJsonObject queuedAssignmentJSON;
//
// // add the queued but unfilled assignments to the json QString uuidString = uuidStringWithoutCurlyBraces((*assignment)->getUUID());
// std::deque<Assignment*>::iterator assignment = domainServerInstance->_assignmentQueue.begin(); queuedAssignmentJSON[JSON_KEY_TYPE] = QString((*assignment)->getTypeName());
//
// while (assignment != domainServerInstance->_assignmentQueue.end()) { // if the assignment has a pool, add it
// QJsonObject queuedAssignmentJSON; if ((*assignment)->hasPool()) {
// queuedAssignmentJSON[JSON_KEY_POOL] = QString((*assignment)->getPool());
// QString uuidString = uuidStringWithoutCurlyBraces((*assignment)->getUUID()); }
// queuedAssignmentJSON[JSON_KEY_TYPE] = QString((*assignment)->getTypeName());
// // add this queued assignment to the JSON
// // if the assignment has a pool, add it queuedAssignmentsJSON[uuidString] = queuedAssignmentJSON;
// if ((*assignment)->hasPool()) {
// queuedAssignmentJSON[JSON_KEY_POOL] = QString((*assignment)->getPool()); // push forward the iterator to check the next assignment
// } assignment++;
// }
// // add this queued assignment to the JSON
// queuedAssignmentsJSON[uuidString] = queuedAssignmentJSON; assignmentJSON["queued"] = queuedAssignmentsJSON;
//
// // push forward the iterator to check the next assignment // print out the created JSON
// assignment++; QJsonDocument assignmentDocument(assignmentJSON);
// } connection->respond(HttpConnection::StatusCode200, assignmentDocument.toJson(), qPrintable(JSON_MIME_TYPE));
//
// assignmentJSON["queued"] = queuedAssignmentsJSON; // we've processed this request
// return true;
// // print out the created JSON } else if (path == "/nodes.json") {
// QJsonDocument assignmentDocument(assignmentJSON); // setup the JSON
// mg_printf(connection, "%s", assignmentDocument.toJson().constData()); QJsonObject rootJSON;
// QJsonObject nodesJSON;
// // we've processed this request
// return 1; // enumerate the NodeList to find the assigned nodes
// } else if (strcmp(ri->uri, "/nodes.json") == 0) { NodeList* nodeList = NodeList::getInstance();
// // start with a 200 response
// mg_printf(connection, "%s", RESPONSE_200); foreach (const SharedNodePointer& node, nodeList->getNodeHash()) {
// // add the node using the UUID as the key
// // setup the JSON QString uuidString = uuidStringWithoutCurlyBraces(node->getUUID());
// QJsonObject rootJSON; nodesJSON[uuidString] = jsonObjectForNode(node.data());
// QJsonObject nodesJSON; }
//
// // enumerate the NodeList to find the assigned nodes rootJSON["nodes"] = nodesJSON;
// NodeList* nodeList = NodeList::getInstance();
// // print out the created JSON
// foreach (const SharedNodePointer& node, nodeList->getNodeHash()) { QJsonDocument nodesDocument(rootJSON);
// // add the node using the UUID as the key
// QString uuidString = uuidStringWithoutCurlyBraces(node->getUUID()); // send the response
// nodesJSON[uuidString] = jsonObjectForNode(node.data()); connection->respond(HttpConnection::StatusCode200, nodesDocument.toJson(), qPrintable(JSON_MIME_TYPE));
// } }
// } else if (connection->requestOperation() == QNetworkAccessManager::PostOperation) {
// rootJSON["nodes"] = nodesJSON; if (path == URI_ASSIGNMENT) {
// // this is a script upload - ask the HttpConnection to parse the form data
// // print out the created JSON QList<FormData> formData = connection->parseFormData();
// QJsonDocument nodesDocument(rootJSON); qDebug() << formData;
// mg_printf(connection, "%s", nodesDocument.toJson().constData()); }
// } else if (connection->requestOperation() == QNetworkAccessManager::DeleteOperation) {
// // we've processed this request if (path.startsWith(URI_NODE)) {
// return 1; // this is a request to DELETE a node by UUID
// }
// // pull the UUID from the url
// // not processed, pass to document root QUuid deleteUUID = QUuid(path.mid(URI_NODE.size() + sizeof('/')));
// return 0;
// } else if (strcmp(ri->request_method, "POST") == 0) { if (!deleteUUID.isNull()) {
// if (strcmp(ri->uri, URI_ASSIGNMENT) == 0) { SharedNodePointer nodeToKill = NodeList::getInstance()->nodeWithUUID(deleteUUID);
// // return a 200
// mg_printf(connection, "%s", RESPONSE_200); if (nodeToKill) {
// // upload the file // start with a 200 response
// mg_upload(connection, "/tmp"); connection->respond(HttpConnection::StatusCode200);
//
// return 1; // we have a valid UUID and node - kill the node that has this assignment
// } QMetaObject::invokeMethod(NodeList::getInstance(), "killNodeWithUUID", Q_ARG(const QUuid&, deleteUUID));
//
// return 0; // successfully processed request
// } else if (strcmp(ri->request_method, "DELETE") == 0) { return true;
// // this is a DELETE request }
// }
// // check if it is for an assignment
// if (memcmp(ri->uri, URI_NODE, strlen(URI_NODE)) == 0) { // bad request, couldn't pull a node ID
// // pull the UUID from the url connection->respond(HttpConnection::StatusCode400);
// QUuid deleteUUID = QUuid(QString(ri->uri + strlen(URI_NODE) + sizeof('/')));
// return true;
// if (!deleteUUID.isNull()) { }
// SharedNodePointer nodeToKill = NodeList::getInstance()->nodeWithUUID(deleteUUID); }
//
// if (nodeToKill) { // didn't process the request, let the HTTPManager try and handle
// // start with a 200 response return false;
// mg_printf(connection, "%s", RESPONSE_200); }
//
// // we have a valid UUID and node - kill the node that has this assignment
// QMetaObject::invokeMethod(NodeList::getInstance(), "killNodeWithUUID", Q_ARG(const QUuid&, deleteUUID));
//
// // successfully processed request
// return 1;
// }
// }
// }
//
// // request not processed - bad request
// mg_printf(connection, "%s", RESPONSE_400);
//
// // this was processed by civetweb
// return 1;
// } else {
// // have mongoose process this request from the document_root
// return 0;
// }
//}
const char ASSIGNMENT_SCRIPT_HOST_LOCATION[] = "resources/web/assignment"; const char ASSIGNMENT_SCRIPT_HOST_LOCATION[] = "resources/web/assignment";

View file

@ -21,11 +21,13 @@
const int MAX_STATIC_ASSIGNMENT_FILE_ASSIGNMENTS = 1000; const int MAX_STATIC_ASSIGNMENT_FILE_ASSIGNMENTS = 1000;
class DomainServer : public QCoreApplication { class DomainServer : public QCoreApplication, public HttpRequestHandler {
Q_OBJECT Q_OBJECT
public: public:
DomainServer(int argc, char* argv[]); DomainServer(int argc, char* argv[]);
bool handleHTTPRequest(HttpConnection* connection, const QString& path);
void exit(int retCode = 0); void exit(int retCode = 0);
static void setDomainServerInstance(DomainServer* domainServer); static void setDomainServerInstance(DomainServer* domainServer);

View file

@ -5,10 +5,6 @@
// Created by Stephen Birarda on 1/16/14. // Created by Stephen Birarda on 1/16/14.
// Copyright (c) 2014 HighFidelity, Inc. All rights reserved. // Copyright (c) 2014 HighFidelity, Inc. All rights reserved.
// //
// Heavily based on Andrzej Kapolka's original HttpConnection class
// found from another one of his projects.
// (https://github.com/ey6es/witgap/tree/master/src/cpp/server/http)
//
#include <QBuffer> #include <QBuffer>
@ -18,6 +14,10 @@
#include "HttpConnection.h" #include "HttpConnection.h"
#include "HttpManager.h" #include "HttpManager.h"
const char* HttpConnection::StatusCode200 = "200 OK";
const char* HttpConnection::StatusCode400 = "400 Bad Request";
const char* HttpConnection::StatusCode404 = "404 Not Found";
HttpConnection::HttpConnection (QTcpSocket* socket, HttpManager* parentManager) : HttpConnection::HttpConnection (QTcpSocket* socket, HttpManager* parentManager) :
QObject(parentManager), QObject(parentManager),
_parentManager(parentManager), _parentManager(parentManager),
@ -178,7 +178,7 @@ void HttpConnection::readHeaders() {
QByteArray clength = _requestHeaders.value("Content-Length"); QByteArray clength = _requestHeaders.value("Content-Length");
if (clength.isEmpty()) { if (clength.isEmpty()) {
_parentManager->handleRequest(this, _requestUrl.path()); _parentManager->handleHTTPRequest(this, _requestUrl.path());
} else { } else {
_requestContent.resize(clength.toInt()); _requestContent.resize(clength.toInt());
@ -217,5 +217,5 @@ void HttpConnection::readContent() {
_socket->read(_requestContent.data(), size); _socket->read(_requestContent.data(), size);
_socket->disconnect(this, SLOT(readContent())); _socket->disconnect(this, SLOT(readContent()));
_parentManager->handleRequest(this, _requestUrl.path()); _parentManager->handleHTTPRequest(this, _requestUrl.path());
} }

View file

@ -7,7 +7,7 @@
// //
// Heavily based on Andrzej Kapolka's original HttpConnection class // Heavily based on Andrzej Kapolka's original HttpConnection class
// found from another one of his projects. // found from another one of his projects.
// (https://github.com/ey6es/witgap/tree/master/src/cpp/server/http) // https://github.com/ey6es/witgap/tree/master/src/cpp/server/http
// //
#ifndef __hifi__HttpConnection__ #ifndef __hifi__HttpConnection__
@ -38,6 +38,9 @@ class HttpConnection : public QObject {
Q_OBJECT Q_OBJECT
public: public:
static const char* StatusCode200;
static const char* StatusCode400;
static const char* StatusCode404;
/// WebSocket close status codes. /// WebSocket close status codes.
enum ReasonCode { NoReason = 0, NormalClosure = 1000, GoingAway = 1001 }; enum ReasonCode { NoReason = 0, NormalClosure = 1000, GoingAway = 1001 };

View file

@ -5,10 +5,6 @@
// Created by Stephen Birarda on 1/16/14. // Created by Stephen Birarda on 1/16/14.
// Copyright (c) 2014 HighFidelity, Inc. All rights reserved. // Copyright (c) 2014 HighFidelity, Inc. All rights reserved.
// //
// Heavily based on Andrzej Kapolka's original HttpManager class
// found from another one of his projects.
// (https://github.com/ey6es/witgap/tree/master/src/cpp/server/http)
//
#include <QtCore/QDebug> #include <QtCore/QDebug>
#include <QtCore/QFile> #include <QtCore/QFile>
@ -19,7 +15,15 @@
#include "HttpConnection.h" #include "HttpConnection.h"
#include "HttpManager.h" #include "HttpManager.h"
bool HttpManager::handleRequest(HttpConnection* connection, const QString& path) { bool HttpManager::handleHTTPRequest(HttpConnection* connection, const QString& path) {
if (_requestHandler && _requestHandler->handleHTTPRequest(connection, path)) {
// this request was handled by our _requestHandler object
// so we don't need to attempt to do so in the document root
return true;
}
// check to see if there is a file to serve from the document root for this path
QString subPath = path; QString subPath = path;
// remove any slash at the beginning of the path // remove any slash at the beginning of the path
@ -45,6 +49,8 @@ bool HttpManager::handleRequest(HttpConnection* connection, const QString& path)
if (!filePath.isEmpty()) { if (!filePath.isEmpty()) {
// file exists, serve it
static QMimeDatabase mimeDatabase; static QMimeDatabase mimeDatabase;
QFile localFile(filePath); QFile localFile(filePath);
@ -93,18 +99,20 @@ bool HttpManager::handleRequest(HttpConnection* connection, const QString& path)
} }
} }
connection->respond("200 OK", localFileString.toLocal8Bit(), qPrintable(mimeDatabase.mimeTypeForFile(filePath).name())); connection->respond(HttpConnection::StatusCode200, localFileString.toLocal8Bit(), qPrintable(mimeDatabase.mimeTypeForFile(filePath).name()));
} else { } else {
// respond with a 404 // respond with a 404
connection->respond("404 Not Found", "Resource not found."); connection->respond(HttpConnection::StatusCode404, "Resource not found.");
} }
return true; return true;
} }
HttpManager::HttpManager(quint16 port, const QString& documentRoot, QObject* parent) : HttpManager::HttpManager(quint16 port, const QString& documentRoot, HttpRequestHandler* requestHandler, QObject* parent) :
QTcpServer(parent), QTcpServer(parent),
_documentRoot(documentRoot) { _documentRoot(documentRoot),
_requestHandler(requestHandler)
{
// start listening on the passed port // start listening on the passed port
if (!listen(QHostAddress("0.0.0.0"), port)) { if (!listen(QHostAddress("0.0.0.0"), port)) {
qDebug() << "Failed to open HTTP server socket:" << errorString(); qDebug() << "Failed to open HTTP server socket:" << errorString();

View file

@ -7,36 +7,37 @@
// //
// Heavily based on Andrzej Kapolka's original HttpManager class // Heavily based on Andrzej Kapolka's original HttpManager class
// found from another one of his projects. // found from another one of his projects.
// (https://github.com/ey6es/witgap/tree/master/src/cpp/server/http) // https://github.com/ey6es/witgap/tree/master/src/cpp/server/http
// //
#ifndef __hifi__HttpManager__ #ifndef __hifi__HttpManager__
#define __hifi__HttpManager__ #define __hifi__HttpManager__
#include <QByteArray>
#include <QHash>
#include <QtNetwork/QTcpServer> #include <QtNetwork/QTcpServer>
class HttpConnection; class HttpConnection;
class HttpRequestHandler;
class HttpRequestHandler {
public:
/// Handles an HTTP request.
virtual bool handleHTTPRequest(HttpConnection* connection, const QString& path) = 0;
};
/// Handles HTTP connections /// Handles HTTP connections
class HttpManager : public QTcpServer { class HttpManager : public QTcpServer, public HttpRequestHandler {
Q_OBJECT Q_OBJECT
public: public:
/// Initializes the manager. /// Initializes the manager.
HttpManager(quint16 port, const QString& documentRoot, QObject* parent = 0); HttpManager(quint16 port, const QString& documentRoot, HttpRequestHandler* requestHandler = NULL, QObject* parent = 0);
/// Handles an HTTP request. bool handleHTTPRequest(HttpConnection* connection, const QString& path);
virtual bool handleRequest (HttpConnection* connection, const QString& path);
protected slots: protected slots:
/// Accepts all pending connections /// Accepts all pending connections
void acceptConnections(); void acceptConnections();
protected: protected:
QString _documentRoot; QString _documentRoot;
HttpRequestHandler* _requestHandler;
}; };
#endif /* defined(__hifi__HttpManager__) */ #endif /* defined(__hifi__HttpManager__) */