summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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() {