diff options
author | Pixel <pixel@nobis-crew.org> | 2011-11-29 18:08:42 -0800 |
---|---|---|
committer | Pixel <pixel@nobis-crew.org> | 2011-11-29 18:08:42 -0800 |
commit | e5cfc02faa8994b8eae51590cda626a26fa9da24 (patch) | |
tree | 15642c90911f4af0c816192ac80e69f6229ead04 /src | |
parent | 04b473eebc2f1ab24b96fe62e4a5991e4dfb9bb4 (diff) |
Now using SimpleMustache to render the error messages.
Diffstat (limited to 'src')
-rw-r--r-- | src/HttpServer.cc | 182 |
1 files changed, 105 insertions, 77 deletions
diff --git a/src/HttpServer.cc b/src/HttpServer.cc index 7df6406..3526a2a 100644 --- a/src/HttpServer.cc +++ b/src/HttpServer.cc @@ -2,6 +2,8 @@ #include "HttpServer.h" #include "Socket.h" #include "BStream.h" +#include "SimpleMustache.h" +#include "Main.h" class OutputCheck : public Balau::Handle { public: @@ -25,7 +27,6 @@ class OutputCheck : public Balau::Handle { }; static const ev_tstamp s_httpTimeout = 5; -#define DAEMON_NAME "Balau/1.0" namespace Balau { @@ -33,14 +34,18 @@ class HttpWorker : public Task { public: HttpWorker(IO<Handle> io, void * server); ~HttpWorker(); + static void buildErrorTemplate(IO<Handle> h) { m_errorTemplate.setTemplate(h); } + static void buildErrorTemplate(const char * str, ssize_t s) { m_errorTemplate.setTemplate(str, s); } + static void buildErrorTemplate(const String & str) { m_errorTemplate.setTemplate(str); } private: virtual void Do(); virtual const char * getName(); bool handleClient(); - void send400(); - void send404(); - void send500(const char * msg); + void sendError(int error, const char * msg, bool closeConnection, std::vector<String> trace); + void send400() { std::vector<String> d2; sendError(400, "The HTTP request you've sent is invalid", true, d2); } + void send404() { std::vector<String> d2; sendError(404, "The HTTP request you've sent didn't match any action on this server.", false, d2); } + void send500(const char * msg, std::vector<String> trace) { String smsg; smsg.set("The HTTP request you've sent triggered an internal error: `%s'", msg); sendError(500, smsg.to_charp(), true, trace); } String httpUnescape(const char * in); void readVariables(Http::StringMap & variables, char * str); @@ -48,13 +53,50 @@ class HttpWorker : public Task { IO<BStream> m_strm; String m_name; HttpServer * m_server; + String m_serverName; + static SimpleMustache m_errorTemplate; }; }; +Balau::SimpleMustache Balau::HttpWorker::m_errorTemplate; + +class SetDefaultTemplate : public Balau::AtStart { + public: + SetDefaultTemplate() : AtStart(0) { } + virtual void doStart(); + static const Balau::String m_defaultErrorTemplate; +}; + +static SetDefaultTemplate setDefaultTemplate; + +const Balau::String SetDefaultTemplate::m_defaultErrorTemplate( +"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n" +"\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n" +"<html xmlns=\"http://www.w3.org/1999/xhtml\">\n" +" <head>\n" +" <meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\" />\n" +" <title>{{title}}</title>\n" +" </head>\n" +"\n" +" <body>\n" +" <h1>{{msg}}</h1>\n" +"{{#hasTrace}}\n" +" <br /><h2>Context:</h2>\n" +" {{#trace}}<pre>{{line}}</pre>{{/trace}}<br />\n" +"{{/hasTrace}}\n" +" </body>\n" +"</html>\n" +); + +void SetDefaultTemplate::doStart() { + Balau::HttpWorker::buildErrorTemplate(m_defaultErrorTemplate); +} + Balau::HttpWorker::HttpWorker(IO<Handle> io, void * _server) : m_socket(new WriteOnly(io)), m_strm(new BStream(io)) { m_server = (HttpServer *) _server; m_name.set("HttpWorker(%s)", m_socket->getName()); + m_serverName = "Balau/1.0"; // get stuff from server, such as port number, root document, base URL, default 400/404 actions, etc... } @@ -112,80 +154,64 @@ void Balau::HttpWorker::readVariables(Http::StringMap & variables, char * str) { } while (ampPos); } -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" -"Connection: close\r\n" -"Server: " DAEMON_NAME "\r\n" -"\r\n" -"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n" -"\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n" -"<html xmlns=\"http://www.w3.org/1999/xhtml\">\n" -" <head>\n" -" <title>Bad Request</title>\n" -" </head>\n" -"\n" -" <body>\n" -" The HTTP request you've sent is invalid.\n" -" </body>\n" -"</html>\n"; - - if (!m_socket->isClosed()) - m_socket->forceWrite(str, sizeof(str) - 1); - Balau::Printer::elog(Balau::E_HTTPSERVER, "%s had an invalid request", m_name.to_charp()); +static const char * getErrorMsg(int httpError) { + switch (httpError) { + case 400: + return "Bad Request"; + break; + case 403: + return "Forbidden"; + break; + case 404: + return "Not Found"; + break; + case 500: + default: + return "Internal Error"; + break; + } } -void Balau::HttpWorker::send404() { - static const char str[] = -"HTTP/1.1 404 Not Found\r\n" +void Balau::HttpWorker::sendError(int error, const char * msg, bool closeConnection, std::vector<String> trace) { + SimpleMustache * tpl = &m_errorTemplate; + const char * errorMsg = getErrorMsg(error); + Printer::elog(Balau::E_HTTPSERVER, "%s caused a %i error (%s)", m_name.to_charp(), error, errorMsg); + SimpleMustache::Context ctx; + String title; + title.set("Error %i - %s", error, errorMsg); + ctx["title"] = title; + ctx["hasTrace"] = !trace.empty(); + ctx["msg"] = msg; + if (m_socket->isClosed()) return; + for (std::vector<String>::iterator i = trace.begin(); i != trace.end(); i++) + ctx["trace"][(ssize_t) 0]["line"] = *i; + if (closeConnection) { + String headers; + headers.set( +"HTTP/1.0 %i %s\r\n" "Content-Type: text/html; charset=UTF-8\r\n" -"Server: " DAEMON_NAME "\r\n" -"\r\n" -"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n" -"\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n" -"<html xmlns=\"http://www.w3.org/1999/xhtml\">\n" -" <head>\n" -" <title>404 Not Found</title>\n" -" </head>\n" -"\n" -" <body>\n" -" The HTTP request you've sent didn't match any action on this server.\n" -" </body>\n" -"</html>\n"; - - if (!m_socket->isClosed()) - m_socket->forceWrite(str, sizeof(str) - 1); - Balau::Printer::elog(Balau::E_HTTPSERVER, "%s had an invalid request", m_name.to_charp()); -} - -void Balau::HttpWorker::send500(const char * msg) { - static const char str[] = -"HTTP/1.1 500 Not Found\r\n" +"Connection: close\r\n" +"Server: %s\r\n" +"\r\n", error, errorMsg, m_serverName.to_charp()); + m_socket->forceWrite(headers); + if (m_socket->isClosed()) return; + tpl->render(m_socket, &ctx); + } else { + IO<Buffer> errorText(new Buffer); + tpl->render(errorText, &ctx); + off_t length = errorText->getSize(); + String headers; + headers.set( +"HTTP/1.1 %i %s\r\n" "Content-Type: text/html; charset=UTF-8\r\n" -"Server: " DAEMON_NAME "\r\n" -"\r\n" -"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n" -"\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n" -"<html xmlns=\"http://www.w3.org/1999/xhtml\">\n" -" <head>\n" -" <title>500 Internal Error</title>\n" -" </head>\n" -"\n" -" <body>\n" -" The HTTP request you've sent triggered an internal error: `"; - static const char str2[] = -"'.\n" -" </body>\n" -"</html>\n"; - - if (!m_socket->isClosed()) - m_socket->forceWrite(str, sizeof(str) - 1); - if (!m_socket->isClosed()) - m_socket->forceWrite(msg, strlen(msg)); - if (!m_socket->isClosed()) - m_socket->forceWrite(str2, sizeof(str2) - 1); - Balau::Printer::elog(Balau::E_HTTPSERVER, "%s had an invalid request", m_name.to_charp()); +"Connection: keep-alive\r\n" +"Server: %s\r\n" +"Content-Length: %i\r\n" +"\r\n", error, errorMsg, m_serverName.to_charp(), length); + m_socket->forceWrite(headers); + if (m_socket->isClosed()) return; + m_socket->forceWrite(errorText->getBuffer(), length); + } } bool Balau::HttpWorker::handleClient() { @@ -449,13 +475,15 @@ bool Balau::HttpWorker::handleClient() { for (std::vector<String>::iterator i = trace.begin(); i != trace.end(); i++) Printer::log(M_DEBUG, "%s", i->to_charp()); if (!out->wrote()) - send500(e.getMsg()); + send500(e.getMsg(), e.getTrace()); return false; } catch (...) { Printer::log(M_ERROR, "%s got an unknow exception while processing its request: `%s'", m_name.to_charp()); - if (!out->wrote()) - send500("unknow exception"); + if (!out->wrote()) { + std::vector<String> d; + send500("unknow exception", d); + } return false; } } else { |