Skip to content

Commit

Permalink
Adds config file support.
Browse files Browse the repository at this point in the history
  • Loading branch information
tylerkaraszewski committed Apr 3, 2011
1 parent fe4eeda commit 23dd6fc
Show file tree
Hide file tree
Showing 14 changed files with 217 additions and 57 deletions.
132 changes: 128 additions & 4 deletions Config.cpp
@@ -1,15 +1,139 @@
#include "Config.h"
#include "Logger.h"
#include "Utils.h"
#include <stdio.h>
#include <errno.h>

void Config::import(const string& filename)
using std::string;
using std::vector;
using std::pair;

string Config::S_KEY_ACCESS_FILE_PATH = "AccessLogFile";
string Config::S_KEY_ERROR_FILE_PATH = "ErrorLogFile";
string Config::S_KEY_RUN_AS_USERNAME = "RunAsUserName";
string Config::S_KEY_BASE_PATH = "BasePath";
string Config::S_KEY_GONE_PATH = "GonePath";

size_t Config::S_READ_SIZE = 4096;
string Config::S_WHITESPACE = "\r\n\t ";

Config::Config(const string& filename) :
m_configFile(filename)
{
import();
}

void Config::import()
{

FILE* file = fopen(filename.c_str(), "r");
FILE* file = fopen(m_configFile.c_str(), "r");
if (file == NULL)
{
m_logger.logError("Config file read error(" + Utils::llToString(errno) + "): " + strerror(errno));
return;
}

char buffer[S_READ_SIZE];
bool doneReading = false;
size_t remaining = 0;
while (!doneReading)
{
size_t readSize = S_READ_SIZE - remaining;
size_t bytesRead = fread(buffer + remaining, 1, readSize, file);
if (bytesRead < readSize)
{
doneReading = true;
}

// parse what we've read so far.
vector<string> lines;
char* start = buffer;
char* end = buffer;
while (end < (buffer + bytesRead + remaining))
{
// Skip to a useful character.
if ((*start == '\n') || (*start == '\r'))
{
start++;
end++;
continue;
}

end++;
if ((*end == '\n') || (*end == '\r'))
{
lines.push_back(string(start, end - start));
start = end;
}
}
for (size_t i = 0; i < lines.size(); i++)
{
parseLine(lines[i]);
}
remaining = end - start;
memmove(buffer, start, remaining);
}
// We still have one line in the buffer if it didn't have a terminating newline.
parseLine(string(buffer, remaining));

int fileError = ferror(file);
if (fileError)
{
// Log?
}
fclose(file);
return;
}

void Config::parseLine(string line)
{
size_t front = line.find_first_not_of(S_WHITESPACE);
if (front == line.npos)
{
return;
}
line = line.substr(front);
line = line.substr(0, line.find_first_of("#"));
line = line.substr(0, line.find_last_not_of(S_WHITESPACE) + 1);
if (line.empty())
{
return;
}

// Now leading/trailing whitespace and comments are removed.

string key;
string value;
size_t ws = line.find_first_of(S_WHITESPACE);
if (ws == line.npos)
{
key = line;
}
else
{
key = line.substr(0, ws);
value = line.substr(line.find_first_not_of(S_WHITESPACE, ws));
}

if ((key == S_KEY_ACCESS_FILE_PATH) ||
(key == S_KEY_ERROR_FILE_PATH) ||
(key == S_KEY_RUN_AS_USERNAME) ||
(key == S_KEY_BASE_PATH)
)
{
m_configValues.erase(key);
m_configValues.insert(pair<string, string>(key, value));
}
else if(key == S_KEY_GONE_PATH)
{
m_configValues.insert(pair<string, string>(key, value));
}
}

string Config::getString(const string& key) const
{
std::multimap<std::string, std::string>::const_iterator it = m_configValues.find(key);
if (it == m_configValues.end())
{
return "";
}
return it->second;
}
32 changes: 32 additions & 0 deletions Config.h
@@ -0,0 +1,32 @@
#ifndef CONFIG_H
#define CONFIG_H
#include <string>
#include <vector>
#include <map>

class Config
{

public:

static std::string S_KEY_ACCESS_FILE_PATH;
static std::string S_KEY_ERROR_FILE_PATH;
static std::string S_KEY_RUN_AS_USERNAME;
static std::string S_KEY_BASE_PATH;
static std::string S_KEY_GONE_PATH;

Config(const std::string& filename);

std::string getString(const std::string& key) const;

private:
void import();
void parseLine(std::string line);

static size_t S_READ_SIZE;
static std::string S_WHITESPACE;

std::string m_configFile;
std::multimap<std::string, std::string> m_configValues;
};
#endif
7 changes: 4 additions & 3 deletions Connection.cpp
Expand Up @@ -12,14 +12,15 @@ using std::string;
const size_t Connection::S_MAX_REQUEST_SIZE = 1024 * 8;
const size_t Connection::S_MAX_WRITE_SIZE = 1024 * 256;

Connection::Connection(const int socket, Logger& logger) :
Connection::Connection(const int socket, Logger& logger, const Config& config) :
m_socket(socket),
m_totalBytesToWrite(0),
m_bytesWritten(0),
m_currentRequest(0),
m_currentResponse(0),
m_isWriting(false),
m_logger(logger)
m_logger(logger),
m_config(config)
{
}

Expand Down Expand Up @@ -111,7 +112,7 @@ bool Connection::process(short int& pollEvents, short int& pollRevents)
m_logger.logError("Debug: parsed '" + ims + "' to: " + Utils::llToString(m_currentRequest->getIfModifiedSince()));
}

m_currentResponse = new HttpResponse(*m_currentRequest, m_logger);
m_currentResponse = new HttpResponse(*m_currentRequest, m_logger, m_config);
m_buffer = m_buffer.substr(bytesParsed); // Trim this off our input buffer since we're done reading it.
pollEvents = POLLOUT; // Now we want to know if we can write.
m_isWriting = true;
Expand Down
4 changes: 3 additions & 1 deletion Connection.h
Expand Up @@ -4,11 +4,12 @@
#include "HttpRequest.h"
#include "HttpResponse.h"
#include "Logger.h"
#include "Config.h"

class Connection
{
public:
Connection(const int socket, Logger& logger);
Connection(const int socket, Logger& logger, const Config& config);
~Connection();
bool process(short int& pollEvents, short int& pollRevents);

Expand All @@ -27,6 +28,7 @@ class Connection
bool m_isWriting;
std::string m_writeBuffer;
Logger& m_logger;
const Config& m_config;
};

#endif
25 changes: 11 additions & 14 deletions FilenameResolver.cpp
Expand Up @@ -11,14 +11,10 @@

using std::string;

#ifdef __linux__
const string FilenameResolver::S_BASE_PATH = "/home/tyler/website/cooked";
#else
const string FilenameResolver::S_BASE_PATH = "/Users/tyler/Sites/newsite/cooked";
#endif

string FilenameResolver::resolve(const string& webPath, string& redirectPath, time_t* mtime)
string FilenameResolver::resolve(const string& webPath, const Config& config, string& redirectPath, time_t* mtime)
{
string basePath = config.getString(Config::S_KEY_BASE_PATH);

if (mtime != NULL)
{
*mtime = 0; // We'll set this to something useful later if we can. Setting it to 0 implies "N/A".
Expand All @@ -32,7 +28,7 @@ string FilenameResolver::resolve(const string& webPath, string& redirectPath, ti
// Nothing was stripped, indicating if a directory, it was requested like a file.
needToRedirectIfDir = true;
}
string fullPath = S_BASE_PATH + processedWebPath;
string fullPath = basePath + processedWebPath;

// Look our path to see if it exists, and if so, what we should do with it.
struct stat fileStat;
Expand All @@ -51,7 +47,7 @@ string FilenameResolver::resolve(const string& webPath, string& redirectPath, ti
}
else
{
fullPath = resolveDir(processedWebPath, mtime);
fullPath = resolveDir(processedWebPath, config, mtime);
}
}

Expand All @@ -74,22 +70,23 @@ string FilenameResolver::resolve(const string& webPath, string& redirectPath, ti
}


string FilenameResolver::resolveDir(const string& dirPath, time_t* mtime)
string FilenameResolver::resolveDir(const string& dirPath, const Config& config, time_t* mtime)
{
string temp;
string rPath = dirPath;
rPath = resolve(dirPath + "/main.html", temp, mtime);
rPath = resolve(dirPath + "/main.html", config, temp, mtime);
if (!rPath.empty())
{
return rPath;
}

return findNewestInDir(dirPath);
return findNewestInDir(dirPath, config);
}

string FilenameResolver::findNewestInDir(const std::string& webPath)
string FilenameResolver::findNewestInDir(const std::string& webPath, const Config& config)
{
string fullPath = S_BASE_PATH + webPath;
string basePath = config.getString(Config::S_KEY_BASE_PATH);
string fullPath = basePath + webPath;
char * name = 0;
DIR * cwd = opendir(fullPath.c_str());
struct dirent * entry;
Expand Down
12 changes: 6 additions & 6 deletions FilenameResolver.h
@@ -1,28 +1,28 @@
#ifndef FILENAME_RESOLVER_H
#define FILENAME_RESOLVER_H

#include "Config.h"
#include <string>
#include <time.h>

class FilenameResolver
{
public:

// point this at the 'documentRoot' of your website. Do not include a trailing '/'
static const std::string S_BASE_PATH;

// Based on the path given, attempts to resolve that to a file on disk. If possible, returns a string represnting the
// actual file to read. If not possible, returns an empty string.
static std::string resolve(const std::string& webPath, std::string& redirectPath, time_t* mtime);
static std::string resolve(const std::string& webPath, const Config& config,
std::string& redirectPath, time_t* mtime);

// Gets a content-type from a filename. Doesn't do any fancy inspection of the actual file, just looks at filename
// extension.
static std::string getContentType(const std::string& filename);

private:
static std::string resolveDir(const std::string& dirPath, time_t* mtime);
static std::string findNewestInDir(const std::string& webPath);
static std::string resolveDir(const std::string& dirPath, const Config& config, time_t* mtime);
static std::string findNewestInDir(const std::string& webPath, const Config& config);

std::string m_basePath;
};

#endif
7 changes: 4 additions & 3 deletions HttpResponse.cpp
Expand Up @@ -10,10 +10,11 @@ using std::string;
string HttpResponse::S_CGI_EXT = ".cgi";
string HttpResponse::S_STANDARD_HEADERS = "Server: argyle\r\nCache-Control: max-age=600\r\n";

HttpResponse::HttpResponse(const HttpRequest& request, Logger& logger) :
HttpResponse::HttpResponse(const HttpRequest& request, Logger& logger, const Config& config) :
m_request(request),
m_keepAlive(true),
m_reader(NULL)
m_reader(NULL),
m_config(config)
{
if (request.getHttpError())
{
Expand All @@ -24,7 +25,7 @@ m_reader(NULL)

string redirectPath;
time_t mtime = 0;
m_path = FilenameResolver::resolve(unescapeUri(m_request.getPath()), redirectPath, &mtime);
m_path = FilenameResolver::resolve(unescapeUri(m_request.getPath()), m_config, redirectPath, &mtime);
if (!redirectPath.empty())
{
m_reader = new ErrorReader(301, "", "Location: " + redirectPath + "\r\n");
Expand Down
4 changes: 3 additions & 1 deletion HttpResponse.h
Expand Up @@ -4,14 +4,15 @@
#include <string>
#include "HttpRequest.h"
#include "DataReader.h"
#include "Config.h"

class HttpResponse
{
public:
static std::string S_CGI_EXT;
static std::string S_STANDARD_HEADERS;

HttpResponse(const HttpRequest& request, Logger& logger);
HttpResponse(const HttpRequest& request, Logger& logger, const Config& config);
~HttpResponse();

static std::string unescapeUri(const std::string& escapedUri);
Expand All @@ -38,6 +39,7 @@ class HttpResponse
DataReader* m_reader;
std::string m_path;
std::string m_headerBuffer;
const Config& m_config;
};

#endif

0 comments on commit 23dd6fc

Please sign in to comment.