summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPixel <pixel@nobis-crew.org>2011-11-14 22:44:55 -0800
committerPixel <pixel@nobis-crew.org>2011-11-14 22:44:55 -0800
commitcd8e8948ed17f1985898f8c1d59d32680262457e (patch)
treeafeed4987fd194081b180d3aa68d38f5dedb7f54
parentd2c436e49ae0e870015b106713a711d9356c39cb (diff)
Some more basic work on the HTTP server. Some of the main ideas are not fleshed up, and writing the actual server should now be sort of straightforward.
-rw-r--r--includes/Http.h23
-rw-r--r--includes/HttpServer.h4
-rw-r--r--includes/Printer.h1
-rw-r--r--src/HttpServer.cc95
4 files changed, 110 insertions, 13 deletions
diff --git a/includes/Http.h b/includes/Http.h
new file mode 100644
index 0000000..cbb118f
--- /dev/null
+++ b/includes/Http.h
@@ -0,0 +1,23 @@
+#pragma once
+
+namespace Balau {
+
+namespace Http {
+
+enum {
+ GET,
+ POST,
+
+ REDIRECT = 301,
+
+ BAD_REQUEST = 400,
+ UNAUTHORIZED = 401,
+ FORBIDDEN = 403,
+ NOT_FOUND = 404,
+
+ ERROR = 500,
+};
+
+};
+
+};
diff --git a/includes/HttpServer.h b/includes/HttpServer.h
index 2609283..7ae0dc1 100644
--- a/includes/HttpServer.h
+++ b/includes/HttpServer.h
@@ -5,6 +5,8 @@
namespace Balau {
+class HttpWorker;
+
class HttpServer {
public:
HttpServer() : m_started(false), m_listenerPtr(NULL), m_port(80) { }
@@ -18,6 +20,8 @@ class HttpServer {
void * m_listenerPtr;
int m_port;
String m_local;
+
+ friend class HttpWorker;
};
};
diff --git a/includes/Printer.h b/includes/Printer.h
index 2c40088..dee5adc 100644
--- a/includes/Printer.h
+++ b/includes/Printer.h
@@ -37,6 +37,7 @@ enum {
E_SOCKET = 32,
E_THREAD = 64,
E_OUTPUT = 128,
+ E_HTTPSERVER = 256,
};
class Printer {
diff --git a/src/HttpServer.cc b/src/HttpServer.cc
index acfc9d2..efdadda 100644
--- a/src/HttpServer.cc
+++ b/src/HttpServer.cc
@@ -1,3 +1,4 @@
+#include "Http.h"
#include "HttpServer.h"
#include "Socket.h"
#include "BStream.h"
@@ -8,53 +9,121 @@ namespace Balau {
class HttpWorker : public Task {
public:
- HttpWorker(IO<Socket> & io, void * server) : m_socket(io), m_parent((HttpServer *) server), m_evtTimeout(s_httpTimeout) { m_name.set("HttpWorker(%s)", m_socket->getName()); }
+ HttpWorker(IO<Socket> & io, void * server);
private:
virtual void Do();
virtual const char * getName();
+
+ bool handleClient();
+ void send400();
+
IO<Socket> m_socket;
+ IO<BStream> m_strm;
String m_name;
- HttpServer * m_parent;
- Events::Timeout m_evtTimeout;
};
};
-void Balau::HttpWorker::Do() {
- waitFor(&m_evtTimeout);
+Balau::HttpWorker::HttpWorker(IO<Socket> & io, void * _server) : m_socket(io), m_strm(new BStream(io)) {
+ HttpServer * server = (HttpServer *) _server;
+ m_name.set("HttpWorker(%s)", m_socket->getName());
+}
+
+void Balau::HttpWorker::send400() {
+ static const char str[] =
+"HTTP/1.0 400 Bad Request\r\n"
+"Content-Type: text/html; charset=UTF-8\r\n"
+"\r\n"
+"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\r\n"
+"\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\r\n"
+"<html xmlns=\"http://www.w3.org/1999/xhtml\">\r\n"
+" <head>\r\n"
+" <title>Bad Request</title>\r\n"
+" </head>\r\n"
+"\r\n"
+" <body>\r\n"
+" The HTTP request you've sent is invalid.\r\n"
+" </body>\r\n"
+"</html>\r\n";
+
+ m_socket->write(str, sizeof(str));
+ Balau::Printer::elog(Balau::E_HTTPSERVER, "%s had an invalid request", m_name.to_charp());
+}
+
+bool Balau::HttpWorker::handleClient() {
+ Events::Timeout evtTimeout(s_httpTimeout);
+ waitFor(&evtTimeout);
setOkayToEAgain(true);
String line;
- IO<BStream> strm(m_socket);
bool gotFirst = false;
+ int method = -1;
+ // read client's request
do {
try {
- line = strm->readString();
+ line = m_strm->readString();
}
catch (EAgain) {
- if (m_evtTimeout.gotSignal()) {
- // do some log
- return;
+ if (evtTimeout.gotSignal()) {
+ Balau::Printer::elog(Balau::E_HTTPSERVER, "%s timed out getting request", m_name.to_charp());
+ return false;
}
yield();
continue;
}
+ // until we get a blank line
if (line == "")
break;
if (!gotFirst) {
gotFirst = true;
- // parse request method, URL and HTTP version.
+ int urlBegin = 0;
+
+ // first line is in the form of METHOD URL HTTP/1.x
+ switch(line[0]) {
+ case 'G':
+ if ((line[1] == 'E') && (line[2] == 'T') && (line[3] == ' ')) {
+ urlBegin = 4;
+ method = Http::GET;
+ }
+ break;
+ case 'P':
+ if ((line[1] == 'O') && (line[2] == 'S') && (line[3] == 'T') && (line[4] == ' ')) {
+ urlBegin = 5;
+ method = Http::POST;
+ }
+ break;
+ }
+ if (urlBegin == 0) {
+ send400();
+ return false;
+ }
+
+ int urlEnd = line.strrchr(' ') - 1;
+
+ if (urlEnd < urlBegin) {
+ send400();
+ return false;
+ }
} else {
// parse HTTP header.
}
} while(true);
if (!gotFirst) {
- // do some log
- return;
+ send400();
+ return false;
}
+
+ return true;
+}
+
+void Balau::HttpWorker::Do() {
+ bool clientStop = false;
+
+ while (!clientStop)
+ clientStop = !handleClient() || m_socket.isClosed();
}
const char * Balau::HttpWorker::getName() {