aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJosh Kropf <josh@slashdev.ca>2007-07-27 21:13:06 (GMT)
committerJosh Kropf <josh@slashdev.ca>2007-07-27 21:13:06 (GMT)
commit3e272e0f2cc91bc3822f07891ede1cc4a2f17ff4 (patch)
tree9aadbbe5472a94a14612687deb55f8568ffe6a9e
parent29ce1344f135bcff25c816544a5606ba82015023 (diff)
downloadecho-server-3e272e0f2cc91bc3822f07891ede1cc4a2f17ff4.zip
echo-server-3e272e0f2cc91bc3822f07891ede1cc4a2f17ff4.tar.gz
echo-server-3e272e0f2cc91bc3822f07891ede1cc4a2f17ff4.tar.bz2
Action and ActionMapper is mostly finished
Added config file parsing
-rw-r--r--Makefile8
-rw-r--r--README11
-rw-r--r--common/Config.cpp40
-rw-r--r--common/Config.h50
-rw-r--r--common/config.cpp40
-rw-r--r--common/config.h50
-rw-r--r--echo.conf.example7
-rw-r--r--http/action.cpp23
-rw-r--r--http/action.h21
-rw-r--r--http/dispatcher.cpp20
10 files changed, 236 insertions, 34 deletions
diff --git a/Makefile b/Makefile
index 2b9861f..cd55c0b 100644
--- a/Makefile
+++ b/Makefile
@@ -1,9 +1,11 @@
CXXFLAGS=-Wall -g
-LDFLAGS=-lstdc++ -lfcgi++ -lcgicc
+LDFLAGS=-lstdc++ -lfcgi++ -lcgicc -lconfuse
-OBJS=http/action.o http/fcgi_io.o http/dispatcher.o
+OBJS=common/config.o http/action.o http/fcgi_io.o http/dispatcher.o
TARGETS=http/dispatcher.fcgi
+all: dispatcher.fcgi
+
dispatcher.fcgi: $(OBJS)
$(CXX) $(LDFLAGS) -o $@ $^
@@ -11,4 +13,4 @@ dispatcher.fcgi: $(OBJS)
$(CXX) $(CXXFLAGS) -c $< -o $@
clean:
- rm -f http/*.o
+ rm -f common/*.o http/*.o
diff --git a/README b/README
new file mode 100644
index 0000000..9d28938
--- /dev/null
+++ b/README
@@ -0,0 +1,11 @@
+* Dependancies
+**********************************
+
+cgicc
+http://www.gnu.org/software/cgicc/
+
+fastcgi
+http://www.fastcgi.com/
+
+libconfuse
+http://www.nongnu.org/confuse/
diff --git a/common/Config.cpp b/common/Config.cpp
new file mode 100644
index 0000000..07eba5c
--- /dev/null
+++ b/common/Config.cpp
@@ -0,0 +1,40 @@
+#include "Config.h"
+
+Config::Config()
+{
+ cfg_opt_t action_opts[] = {
+ CFG_STR("root", 0, CFGF_NODEFAULT),
+ CFG_STR_LIST("modules", "{}", CFGF_NONE),
+ CFG_END()
+ };
+
+ cfg_opt_t opts[] = {
+ CFG_SEC("actions", action_opts, CFGF_NONE),
+ CFG_END()
+ };
+
+ _cfg = cfg_init(opts, CFGF_NONE);
+ if (cfg_parse(_cfg, CONFIG_FILE) == CFG_PARSE_ERROR)
+ throw config_error();
+}
+
+Config::~Config()
+{
+ cfg_free(_cfg);
+}
+
+vector<string> Config::modules() const
+{
+ vector<string> modules;
+
+ cfg_t* actions = cfg_getsec(_cfg, "actions");
+ if (actions) {
+ string root = cfg_getstr(actions, "root");
+
+ for (int i=cfg_size(actions, "modules")-1; i>=0; i--) {
+ *modules.end() = root + cfg_getnstr(actions, "modules", i);
+ }
+ }
+
+ return modules;
+}
diff --git a/common/Config.h b/common/Config.h
new file mode 100644
index 0000000..6b27d20
--- /dev/null
+++ b/common/Config.h
@@ -0,0 +1,50 @@
+#include <string>
+#include <vector>
+#include <exception>
+#include <confuse.h>
+
+#ifndef CONFIG_H_
+#define CONFIG_H_
+
+#define CONFIG_FILE "/etc/echo.conf"
+
+using namespace std;
+
+
+class config_error: public exception
+{
+public:
+ virtual const char* what() {
+ return "configuration parse error";
+ }
+};
+
+/**
+ * Config class encapsulates the config file parsing and provides methods
+ * for retreiving configuration options
+ */
+class Config
+{
+private:
+ cfg_t *_cfg;
+
+public:
+
+ /**
+ * Creates the config class and parses the config file
+ * @throws config_error
+ */
+ Config();
+
+ /**
+ * Releases config resources
+ */
+ ~Config();
+
+ /**
+ * Returns fully qualified path names to all the configured action modules
+ */
+ vector<string> modules() const;
+};
+
+#endif /*CONFIG_H_*/
diff --git a/common/config.cpp b/common/config.cpp
new file mode 100644
index 0000000..07eba5c
--- /dev/null
+++ b/common/config.cpp
@@ -0,0 +1,40 @@
+#include "Config.h"
+
+Config::Config()
+{
+ cfg_opt_t action_opts[] = {
+ CFG_STR("root", 0, CFGF_NODEFAULT),
+ CFG_STR_LIST("modules", "{}", CFGF_NONE),
+ CFG_END()
+ };
+
+ cfg_opt_t opts[] = {
+ CFG_SEC("actions", action_opts, CFGF_NONE),
+ CFG_END()
+ };
+
+ _cfg = cfg_init(opts, CFGF_NONE);
+ if (cfg_parse(_cfg, CONFIG_FILE) == CFG_PARSE_ERROR)
+ throw config_error();
+}
+
+Config::~Config()
+{
+ cfg_free(_cfg);
+}
+
+vector<string> Config::modules() const
+{
+ vector<string> modules;
+
+ cfg_t* actions = cfg_getsec(_cfg, "actions");
+ if (actions) {
+ string root = cfg_getstr(actions, "root");
+
+ for (int i=cfg_size(actions, "modules")-1; i>=0; i--) {
+ *modules.end() = root + cfg_getnstr(actions, "modules", i);
+ }
+ }
+
+ return modules;
+}
diff --git a/common/config.h b/common/config.h
new file mode 100644
index 0000000..6b27d20
--- /dev/null
+++ b/common/config.h
@@ -0,0 +1,50 @@
+#include <string>
+#include <vector>
+#include <exception>
+#include <confuse.h>
+
+#ifndef CONFIG_H_
+#define CONFIG_H_
+
+#define CONFIG_FILE "/etc/echo.conf"
+
+using namespace std;
+
+
+class config_error: public exception
+{
+public:
+ virtual const char* what() {
+ return "configuration parse error";
+ }
+};
+
+/**
+ * Config class encapsulates the config file parsing and provides methods
+ * for retreiving configuration options
+ */
+class Config
+{
+private:
+ cfg_t *_cfg;
+
+public:
+
+ /**
+ * Creates the config class and parses the config file
+ * @throws config_error
+ */
+ Config();
+
+ /**
+ * Releases config resources
+ */
+ ~Config();
+
+ /**
+ * Returns fully qualified path names to all the configured action modules
+ */
+ vector<string> modules() const;
+};
+
+#endif /*CONFIG_H_*/
diff --git a/echo.conf.example b/echo.conf.example
new file mode 100644
index 0000000..ee6b513
--- /dev/null
+++ b/echo.conf.example
@@ -0,0 +1,7 @@
+actions {
+ # directory containing action modules
+ root = "/home/josh/echo-server/actions"
+
+ # lists of modules to load
+ modules = { "hello.so" }
+}
diff --git a/http/action.cpp b/http/action.cpp
index e0e65fb..7c854fd 100644
--- a/http/action.cpp
+++ b/http/action.cpp
@@ -1,37 +1,36 @@
#include "action.h"
+#include "Config.h"
#include <fstream>
using namespace http;
using namespace std;
-action_mapping* action_mapping::instance()
+ActionMapping* ActionMapping::instance()
{
- static action_mapping instance("poo");
+ static ActionMapping instance;
return &instance;
}
-action_mapping::action_mapping(const char* configFile)
+ActionMapping::ActionMapping()
{
- ifstream file(configFile);
- string line;
-
- while (!file.eof()) {
- getline(file, line);
+ Config config;
+ vector<string> v = config.modules();
+ while (const_iterator i = v.begin(); i != v.end(); ++i) {
+ // TODO load dynamic library
}
}
-void action_mapping::reg(string key, create_ptr ptr)
+void ActionMapping::reg(string key, create_ptr ptr)
{
_mapping[key] = ptr;
}
-bool action_mapping::contains(string key) const
+bool ActionMapping::contains(string key) const
{
return _mapping.count(key) != 0;
}
-action* action_mapping::get(string key)
+Action* ActionMapping::get(string key)
{
return (*_mapping[key])();
}
-
diff --git a/http/action.h b/http/action.h
index c2c1271..cb9ff92 100644
--- a/http/action.h
+++ b/http/action.h
@@ -12,13 +12,14 @@ namespace http {
* Interface for all dispatchable actions. An action handles an http request
* and formats an http response.
*/
-class action {
+class Action {
public:
+ virtual ~Action();
/**
* Creates the action (usually just new's the class)
*/
- virtual action* create() = 0;
+ virtual Action* create() = 0;
/**
* Executes the action. Actions are passed the cgicc object containing request
@@ -33,28 +34,27 @@ public:
/**
* Typedef for a pointer to the create method in action
*/
-typedef action* (*create_ptr)();
+typedef Action* (*create_ptr)();
/**
* Registry of action mapping.
*/
-class action_mapping {
+class ActionMapping {
private:
std::map<std::string, create_ptr> _mapping;
protected:
/**
- * Reads a list of modules (.so files) line by line from the file and instructs
- * the module to register its actions. Each line is assumed to be an absolute
- * path.
+ * Reads a list of modules from the config file and loads the dynamic library.
+ * Each library has a callback function to register is action handlers.
*/
- action_mapping(const char* configFile);
+ ActionMapping();
public:
/**
* Returns singleton instance of action mapping class
*/
- static action_mapping* instance();
+ static ActionMapping* instance();
/**
* Registers mapping between action create method pointer and string identifier.
@@ -75,10 +75,9 @@ public:
* @param key string identifier
* @return instance of action class
*/
- action* get(std::string key);
+ Action* get(std::string key);
};
} /* end namespace */
#endif
-
diff --git a/http/dispatcher.cpp b/http/dispatcher.cpp
index 859928b..8f72365 100644
--- a/http/dispatcher.cpp
+++ b/http/dispatcher.cpp
@@ -1,6 +1,7 @@
#include <iostream>
#include <fcgio.h>
#include <cgicc/Cgicc.h>
+#include <cgicc/HTTPStatusHeader.h>
#include "fcgi_io.h"
#include "action.h"
@@ -10,7 +11,7 @@ using namespace http;
int main (void)
{
- action_mapping* mapping = action_mapping::instance();
+ ActionMapping* mapping = ActionMapping::instance();
FCGX_Request request;
@@ -21,29 +22,32 @@ int main (void)
fcgi_io io(request);
Cgicc cgi(&io);
- action* action;
+ Action* action;
// script name is the full path of the request
string script = cgi.getEnvironment().getScriptName();
if (script.size() != 0) {
// script name begins with / when dispatcher is handling all requests
- unsigned int begin = script[0] == '/' ? 1 : 0;
+ unsigned int begin = script[0] == '/' ? 1 : 0;
- // find next / after the first one
+ // find next / after the first one
unsigned int end = script.find("/", begin);
// if another / wasn't found, use size as end index
if (end == string::npos) end = script.size();
- string key = script.substr(begin, end-begin);
- if (mapping->contains(key)) {
+ string key = script.substr(begin, end-begin);
+ if (mapping->contains(key)) {
action = mapping->get(key);
- }
+ }
}
if (action != NULL) {
- action->execute(cgi, io);
+ action->execute(cgi, io);
+ delete action;
+ } else {
+ io << HTTPStatusHeader(404, "action not found");
}
FCGX_Finish_r(&request);