summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--includes/Http.h4
-rw-r--r--includes/HttpServer.h24
-rw-r--r--src/HttpServer.cc45
-rw-r--r--tests/test-Http.cc12
4 files changed, 71 insertions, 14 deletions
diff --git a/includes/Http.h b/includes/Http.h
index 8b0e313..62f8786 100644
--- a/includes/Http.h
+++ b/includes/Http.h
@@ -13,8 +13,7 @@ const char * getStatusMsg(int httpStatus);
typedef std::map<String, String> StringMap;
typedef std::map<String, IO<Handle> > FileList;
-class Request {
- public:
+struct Request {
int method;
String host;
String uri;
@@ -22,6 +21,7 @@ class Request {
StringMap headers;
FileList files;
bool persistent;
+ String version;
};
enum {
diff --git a/includes/HttpServer.h b/includes/HttpServer.h
index 37353ac..7dbf912 100644
--- a/includes/HttpServer.h
+++ b/includes/HttpServer.h
@@ -9,6 +9,7 @@
#include <Exceptions.h>
#include <Threads.h>
#include <Handle.h>
+#include <Buffer.h>
#include <Http.h>
namespace Balau {
@@ -18,6 +19,28 @@ class HttpWorker;
class HttpServer {
public:
+ class Response {
+ public:
+ Response(HttpServer * server, Http::Request req, IO<Handle> out) : m_server(server), m_req(req), m_out(out), m_buffer(new Buffer()), m_responseCode(200), m_type("text/html; charset=UTF-8"), m_flushed(false) { }
+ void SetResponseCode(int code) { m_responseCode = code; }
+ void SetContentType(const String & type) { m_type = type; }
+ IO<Buffer> get() { return m_buffer; }
+ IO<Buffer> operator->() { return m_buffer; }
+ void Flush();
+ void AddHeader(const String & line) { m_extraHeaders.push_front(line); }
+ void AddHeader(const String & key, const String & val) { AddHeader(key + ": " + val); }
+ private:
+ HttpServer * m_server;
+ Http::Request m_req;
+ IO<Handle> m_out;
+
+ IO<Buffer> m_buffer;
+ int m_responseCode;
+ String m_type;
+ std::list<String> m_extraHeaders;
+ bool m_flushed;
+ };
+
class Action {
public:
Action(const Regex & regex, const Regex & host = Regexes::any) : m_regex(regex), m_host(host), m_refCount(0) { }
@@ -48,6 +71,7 @@ class HttpServer {
Action::ActionMatch matches;
};
ActionFound findAction(const char * uri, const char * host);
+ String getServerName() { return "Balau/1.0"; }
private:
bool m_started;
void * m_listenerPtr;
diff --git a/src/HttpServer.cc b/src/HttpServer.cc
index a00160f..c596005 100644
--- a/src/HttpServer.cc
+++ b/src/HttpServer.cc
@@ -74,7 +74,6 @@ class HttpWorker : public Task {
IO<BStream> m_strm;
String m_name;
HttpServer * m_server;
- String m_serverName;
static SimpleMustache m_errorTemplate;
};
@@ -122,7 +121,6 @@ void SetDefaultTemplate::doStart() {
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...
}
@@ -204,7 +202,7 @@ void Balau::HttpWorker::sendError(int error, const char * msg, const char * deta
"Content-Type: text/html; charset=UTF-8\r\n"
"Connection: close\r\n"
"Server: %s\r\n",
- error, errorMsg, m_serverName.to_charp());
+ error, errorMsg, m_server->getServerName().to_charp());
for (std::vector<String>::iterator i = extraHeaders.begin(); i != extraHeaders.end(); i++)
headers += *i + "\r\n";
headers += "\r\n";
@@ -222,7 +220,7 @@ void Balau::HttpWorker::sendError(int error, const char * msg, const char * deta
"Connection: keep-alive\r\n"
"Server: %s\r\n"
"Content-Length: %lli\r\n",
- error, errorMsg, m_serverName.to_charp(), length);
+ error, errorMsg, m_server->getServerName().to_charp(), length);
for (std::vector<String>::iterator i = extraHeaders.begin(); i != extraHeaders.end(); i++)
headers += *i + "\r\n";
headers += "\r\n";
@@ -550,6 +548,7 @@ bool Balau::HttpWorker::handleClient() {
req.headers = httpHeaders;
req.files = files;
req.persistent = persistent;
+ req.version = httpVersion;
try {
if (!f.action->Do(m_server, req, f.matches, out))
persistent = false;
@@ -658,3 +657,41 @@ Balau::HttpServer::ActionFound Balau::HttpServer::findAction(const char * uri, c
return r;
}
+
+void Balau::HttpServer::Response::Flush() {
+ AAssert(!m_flushed, "HttpResponse already flushed.");
+
+ m_flushed = true;
+ IO<Buffer> headers(new Buffer());
+
+ headers->writeString("HTTP/");
+ headers->writeString(m_req.version);
+ headers->writeString(" ");
+ String response(m_responseCode);
+ headers->writeString(response);
+ headers->writeString(" ");
+ headers->writeString(Http::getStatusMsg(m_responseCode), -1);
+ headers->writeString("\r\nContent-Type: ");
+ headers->writeString(m_type);
+ headers->writeString("\r\nContent-Length: ");
+ String len(m_buffer->getSize());
+ headers->writeString(len);
+ headers->writeString("\r\nServer: ");
+ headers->writeString(m_server->getServerName());
+ headers->writeString("\r\n");
+ if ((m_req.version == "1.1") && !m_req.persistent) {
+ headers->writeString("Connection: close\r\n");
+ }
+
+ while (!m_extraHeaders.empty()) {
+ String s = m_extraHeaders.front();
+ m_extraHeaders.pop_front();
+ headers->writeString(s);
+ headers->writeString("\r\n");
+ }
+
+ headers->writeString("\r\n");
+
+ m_out->forceWrite(headers->getBuffer(), headers->getSize());
+ m_out->forceWrite(m_buffer->getBuffer(), m_buffer->getSize());
+}
diff --git a/tests/test-Http.cc b/tests/test-Http.cc
index e6ba38d..af78e43 100644
--- a/tests/test-Http.cc
+++ b/tests/test-Http.cc
@@ -13,12 +13,8 @@ class TestAction : public HttpServer::Action {
};
bool TestAction::Do(HttpServer * server, Http::Request & req, HttpServer::Action::ActionMatch & match, IO<Handle> out) throw (GeneralException) {
- static const char str[] =
-"HTTP/1.1 200 Found\r\n"
-"Content-Type: text/html; charset=UTF-8\r\n"
-"Content-Length: 266\r\n"
-"Server: " DAEMON_NAME "\r\n"
-"\r\n"
+ HttpServer::Response response(server, req, out);
+ response->writeString(
"<!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"
@@ -29,9 +25,9 @@ bool TestAction::Do(HttpServer * server, Http::Request & req, HttpServer::Action
" <body>\n"
" This is a test document.\n"
" </body>\n"
-"</html>\n";
+"</html>\n");
- out->forceWrite(str, sizeof(str) - 1);
+ response.Flush();
return true;
}