diff options
author | Pixel <pixel@nobis-crew.org> | 2011-11-14 22:44:55 -0800 |
---|---|---|
committer | Pixel <pixel@nobis-crew.org> | 2011-11-14 22:44:55 -0800 |
commit | cd8e8948ed17f1985898f8c1d59d32680262457e (patch) | |
tree | afeed4987fd194081b180d3aa68d38f5dedb7f54 | |
parent | d2c436e49ae0e870015b106713a711d9356c39cb (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.h | 23 | ||||
-rw-r--r-- | includes/HttpServer.h | 4 | ||||
-rw-r--r-- | includes/Printer.h | 1 | ||||
-rw-r--r-- | src/HttpServer.cc | 95 |
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() { |