From cd8e8948ed17f1985898f8c1d59d32680262457e Mon Sep 17 00:00:00 2001 From: Pixel Date: Mon, 14 Nov 2011 22:44:55 -0800 Subject: 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. --- src/HttpServer.cc | 95 +++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 82 insertions(+), 13 deletions(-) (limited to 'src') 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 & io, void * server) : m_socket(io), m_parent((HttpServer *) server), m_evtTimeout(s_httpTimeout) { m_name.set("HttpWorker(%s)", m_socket->getName()); } + HttpWorker(IO & io, void * server); private: virtual void Do(); virtual const char * getName(); + + bool handleClient(); + void send400(); + IO m_socket; + IO m_strm; String m_name; - HttpServer * m_parent; - Events::Timeout m_evtTimeout; }; }; -void Balau::HttpWorker::Do() { - waitFor(&m_evtTimeout); +Balau::HttpWorker::HttpWorker(IO & 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" +"\r\n" +"\r\n" +" \r\n" +" Bad Request\r\n" +" \r\n" +"\r\n" +" \r\n" +" The HTTP request you've sent is invalid.\r\n" +" \r\n" +"\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 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() { -- cgit v1.2.3