1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
|
// A simple HTTP/1.0 web server using Dashel
#include <dashel/dashel.h>
#include <iostream>
#include <fstream>
#include <cassert>
using namespace std;
using namespace Dashel;
// Helper functions for stream
string readLine(Stream* stream)
{
char c;
string line;
do
{
stream->read(&c, 1);
line += c;
}
while (c != '\n');
return line;
}
void sendString(Stream* stream, const string& line)
{
stream->write(line.c_str(), line.length());
stream->flush();
}
void shutdownStream(Stream* stream)
{
// close the stream, this is a hack because Dashel lacks a proper shutdown mechanism
stream->fail(DashelException::Unknown, 0, "Request handling complete");
}
// Helper functions for string
// inspired from: http://stackoverflow.com/questions/289347/using-strtok-with-a-stdstring
vector<string> split(const string& str, const string& delim)
{
vector<string> parts;
size_t start;
size_t end = 0;
while (end < str.size())
{
start = end;
while (start < str.size() && (delim.find(str[start]) != string::npos))
start++; // skip initial whitespace
end = start;
while (end < str.size() && (delim.find(str[end]) == string::npos))
end++; // skip to end of word
if (end-start != 0) // just ignore zero-length strings.
parts.push_back(string(str, start, end-start));
}
return parts;
}
// Web server itself
class WebServer: public Hub
{
public:
explicit WebServer(const string& port)
{
listenStream = connect("tcpin:port=" + port);
}
void connectionCreated(Stream *stream)
{
cerr << stream << " Connection created to " << stream->getTargetName() << endl;
}
void incomingData(Stream *stream)
{
// received request
const string request(readLine(stream));
cerr << stream << " Request: " << request;
// read all options
readLine(stream);
string optionLine;
while ((optionLine = readLine(stream)) != "\r\n")
{
cerr << stream << " Option: " << optionLine;
}
// parse request
vector<string> requestParts(split(request, "\n\r\t "));
// only support GET
if ((requestParts.size() < 2) || requestParts[0] != "GET")
{
cerr << stream << " Unsupported HTTP request" << request << endl;
sendString(stream, "HTTP/1.0 403\r\n\r\n");
shutdownStream(stream);
return;
}
// try to open file
const string fileName(requestParts[1]);
ifstream ifs(fileName.c_str());
char c = ifs.get();
if (!ifs.good())
{
cerr << stream << " Cannot open file" << fileName << endl;
sendString(stream, "HTTP/1.0 404\r\n\r\n");
shutdownStream(stream);
return;
}
// read and send the file
// note: this could be made much more efficient by checking the
// file size and reading it all at once
cerr << stream << " Serving: " << fileName << endl;
sendString(stream, "HTTP/1.0 200\r\n\r\n");
while (ifs.good())
{
stream->write(c);
c = ifs.get();
}
stream->flush();
shutdownStream(stream);
}
void connectionClosed(Stream *stream, bool abnormal)
{
cerr << stream << " Connection closed to " << stream->getTargetName() << endl;
}
protected:
Stream* listenStream;
};
int main(int argc, char* argv[])
{
try
{
WebServer webServer(argc > 1 ? argv[1] : "8080");
webServer.run();
}
catch(const DashelException &e)
{
std::cerr << e.what() << std::endl;
}
return 0;
}
|