summaryrefslogtreecommitdiffstats
path: root/src/uscxml/server
diff options
context:
space:
mode:
authorStefan Radomski <radomski@tk.informatik.tu-darmstadt.de>2013-02-25 12:28:05 (GMT)
committerStefan Radomski <radomski@tk.informatik.tu-darmstadt.de>2013-02-25 12:28:05 (GMT)
commit49c3c43d18c9cce6de305aae77cc8bd839506129 (patch)
treecfc4ea84416c76e8bbe3e27d2918321115b61e24 /src/uscxml/server
parent47956a35d11495f2ebf6988c7f9d9dffe0bd3a4b (diff)
downloaduscxml-49c3c43d18c9cce6de305aae77cc8bd839506129.zip
uscxml-49c3c43d18c9cce6de305aae77cc8bd839506129.tar.gz
uscxml-49c3c43d18c9cce6de305aae77cc8bd839506129.tar.bz2
Introduced postpone element and reorganized http request representation as events
Diffstat (limited to 'src/uscxml/server')
-rw-r--r--src/uscxml/server/HTTPServer.cpp119
-rw-r--r--src/uscxml/server/HTTPServer.h16
2 files changed, 92 insertions, 43 deletions
diff --git a/src/uscxml/server/HTTPServer.cpp b/src/uscxml/server/HTTPServer.cpp
index fccc8a9..d8a6474 100644
--- a/src/uscxml/server/HTTPServer.cpp
+++ b/src/uscxml/server/HTTPServer.cpp
@@ -5,6 +5,7 @@
#include "uscxml/server/HTTPServer.h"
#include "uscxml/Message.h"
+#include "uscxml/Factory.h"
#include <iostream>
#include <event2/dns.h>
#include <event2/event.h>
@@ -14,7 +15,8 @@
#include <event2/http_struct.h>
#include <event2/thread.h>
-#include <string.h>
+#include <string>
+#include <iostream>
#include <glog/logging.h>
#include <boost/algorithm/string.hpp>
@@ -39,6 +41,9 @@ HTTPServer::HTTPServer(unsigned short port) {
_port++;
}
determineAddress();
+
+ // generic callback
+ evhttp_set_gencb(_http, HTTPServer::httpRecvReqCallback, NULL);
}
HTTPServer::~HTTPServer() {
@@ -71,34 +76,34 @@ void HTTPServer::httpRecvReqCallback(struct evhttp_request *req, void *callbackD
switch (evhttp_request_get_command(req)) {
case EVHTTP_REQ_GET:
- request.type = "GET";
+ request.data.compound["type"] = Data("get", Data::VERBATIM);
break;
case EVHTTP_REQ_POST:
- request.type = "POST";
+ request.data.compound["type"] = Data("post", Data::VERBATIM);
break;
case EVHTTP_REQ_HEAD:
- request.type = "HEAD";
+ request.data.compound["type"] = Data("head", Data::VERBATIM);
break;
case EVHTTP_REQ_PUT:
- request.type = "PUT";
+ request.data.compound["type"] = Data("put", Data::VERBATIM);
break;
case EVHTTP_REQ_DELETE:
- request.type = "DELETE";
+ request.data.compound["type"] = Data("delete", Data::VERBATIM);
break;
case EVHTTP_REQ_OPTIONS:
- request.type = "OPTIONS";
+ request.data.compound["type"] = Data("options", Data::VERBATIM);
break;
case EVHTTP_REQ_TRACE:
- request.type = "TRACE";
+ request.data.compound["type"] = Data("trace", Data::VERBATIM);
break;
case EVHTTP_REQ_CONNECT:
- request.type = "CONNECT";
+ request.data.compound["type"] = Data("connect", Data::VERBATIM);
break;
case EVHTTP_REQ_PATCH:
- request.type = "PATCH";
+ request.data.compound["type"] = Data("patch", Data::VERBATIM);
break;
default:
- request.type = "unknown";
+ request.data.compound["type"] = Data("unknown", Data::VERBATIM);
break;
}
@@ -106,17 +111,38 @@ void HTTPServer::httpRecvReqCallback(struct evhttp_request *req, void *callbackD
struct evkeyval *header;
struct evbuffer *buf;
- // map headers to event structure
+ // insert headers to event data
headers = evhttp_request_get_input_headers(req);
for (header = headers->tqh_first; header; header = header->next.tqe_next) {
- request.headers[header->key] = header->value;
+ request.data.compound["header"].compound[header->key] = Data(header->value, Data::VERBATIM);
}
- request.remoteHost = req->remote_host;
- request.remotePort = req->remote_port;
- request.httpMajor = req->major;
- request.httpMinor = req->minor;
- request.uri = req->uri;
+ request.data.compound["remoteHost"] = Data(req->remote_host, Data::VERBATIM);
+ request.data.compound["remotePort"] = Data(toStr(req->remote_port), Data::VERBATIM);
+ request.data.compound["httpMajor"] = Data(toStr((unsigned short)req->major), Data::VERBATIM);
+ request.data.compound["httpMinor"] = Data(toStr((unsigned short)req->minor), Data::VERBATIM);
+ request.data.compound["uri"] = Data(HTTPServer::getBaseURL() + req->uri, Data::VERBATIM);
+ request.data.compound["path"] = Data(evhttp_uri_get_path(evhttp_request_get_evhttp_uri(req)), Data::VERBATIM);
+
+ // seperate path into components
+ std::stringstream ss(request.data.compound["path"].atom);
+ std::string item;
+ while(std::getline(ss, item, '/')) {
+ if (item.length() == 0)
+ continue;
+ request.data.compound["pathComponent"].array.push_back(Data(item, Data::VERBATIM));
+ }
+
+ // parse query string
+ struct evkeyvalq params;
+ struct evkeyval *param;
+ const char* query = evhttp_uri_get_query(evhttp_request_get_evhttp_uri(req));
+
+ evhttp_parse_query_str(query, &params);
+ for (param = params.tqh_first; param; param = param->next.tqe_next) {
+ request.data.compound["query"].compound[param->key] = Data(param->value, Data::VERBATIM);
+ }
+ evhttp_clear_headers(&params);
// get content
buf = evhttp_request_get_input_buffer(req);
@@ -129,7 +155,40 @@ void HTTPServer::httpRecvReqCallback(struct evhttp_request *req, void *callbackD
}
}
- ((HTTPServlet*)callbackData)->httpRecvRequest(request);
+ if (callbackData == NULL) {
+ HTTPServer::getInstance()->processByMatchingServlet(request);
+ } else {
+ ((HTTPServlet*)callbackData)->httpRecvRequest(request);
+ }
+}
+
+void HTTPServer::processByMatchingServlet(const Request& request) {
+ servlet_iter_t servletIter = _servlets.begin();
+
+ std::string actualPath = request.data.compound.at("path").atom;
+ HTTPServlet* bestMatch = NULL;
+ std::string bestPath;
+
+ while(servletIter != _servlets.end()) {
+ // is the servlet path a prefix of the actual path?
+ std::string servletPath = "/" + servletIter->first;
+ if (boost::iequals(actualPath.substr(0, servletPath.length()), servletPath) && // actual path is a prefix
+ boost::iequals(actualPath.substr(servletPath.length(), 1), "/")) { // and next character is a '/'
+ if (bestPath.length() < servletPath.length()) {
+ // this servlet is a better match
+ bestPath = servletPath;
+ bestMatch = servletIter->second;
+ }
+ }
+ servletIter++;
+ }
+
+ if (bestMatch != NULL) {
+ bestMatch->httpRecvRequest(request);
+ } else {
+ LOG(INFO) << "Got an HTTP request at " << actualPath << " but no servlet is registered there or at a prefix";
+ evhttp_send_error(request.curlReq, 404, NULL);
+ }
}
void HTTPServer::reply(const Reply& reply) {
@@ -154,18 +213,6 @@ bool HTTPServer::registerServlet(const std::string& path, HTTPServlet* servlet)
HTTPServer* INSTANCE = getInstance();
tthread::lock_guard<tthread::recursive_mutex> lock(INSTANCE->_mutex);
- /**
- * Determine path for interpreter.
- *
- * If the interpreter has a name and it is not yet taken, choose it as the path
- * for requests. If the interpreters name path is already taken, append digits
- * until we have an available path.
- *
- * If the interpreter does not specify a name, take its sessionid.
- *
- * Responsibility moved to individual servlets.
- */
-
if(INSTANCE->_servlets.find(path) != INSTANCE->_servlets.end()) {
return false;
}
@@ -182,9 +229,13 @@ bool HTTPServer::registerServlet(const std::string& path, HTTPServlet* servlet)
evhttp_set_cb(INSTANCE->_http, ("/" + path).c_str(), HTTPServer::httpRecvReqCallback, servlet);
return true;
- // generic callback
-// evhttp_set_cb(THIS->_http, "/", EventIOProcessor::httpRecvReq, processor);
-// evhttp_set_gencb(THIS->_http, EventIOProcessor::httpRecvReq, NULL);
+}
+
+std::string HTTPServer::getBaseURL() {
+ HTTPServer* INSTANCE = getInstance();
+ std::stringstream servletURL;
+ servletURL << "http://" << INSTANCE->_address << ":" << INSTANCE->_port;
+ return servletURL.str();
}
void HTTPServer::unregisterServlet(HTTPServlet* servlet) {
diff --git a/src/uscxml/server/HTTPServer.h b/src/uscxml/server/HTTPServer.h
index a387e1f..1ec28c7 100644
--- a/src/uscxml/server/HTTPServer.h
+++ b/src/uscxml/server/HTTPServer.h
@@ -7,6 +7,7 @@
#include <event2/http.h>
#include "uscxml/concurrency/tinythread.h"
+#include "uscxml/Message.h"
namespace uscxml {
@@ -14,23 +15,16 @@ class HTTPServlet;
class HTTPServer {
public:
- class Request {
+ class Request : public Event {
public:
Request() : curlReq(NULL) {}
- std::string type;
- std::map<std::string, std::string> headers;
std::string content;
- std::string remoteHost;
- unsigned short remotePort;
- std::string httpMajor;
- std::string httpMinor;
- std::string uri;
struct evhttp_request* curlReq;
};
class Reply {
public:
- Reply(Request req) : status(200), type(req.type), curlReq(req.curlReq) {}
+ Reply(Request req) : status(200), type(req.data.compound["type"].atom), curlReq(req.curlReq) {}
int status;
std::string type;
std::map<std::string, std::string> headers;
@@ -44,6 +38,8 @@ public:
};
static HTTPServer* getInstance(int port = 8080);
+ static std::string getBaseURL();
+
static void reply(const Reply& reply);
static bool registerServlet(const std::string& path, HTTPServlet* servlet); ///< Register a servlet, returns false if path is already taken
@@ -60,6 +56,8 @@ private:
void determineAddress();
static void httpRecvReqCallback(struct evhttp_request *req, void *callbackData);
+ void processByMatchingServlet(const Request& request);
+
std::map<std::string, HTTPServlet*> _servlets;
typedef std::map<std::string, HTTPServlet*>::iterator servlet_iter_t;