#include "TCivetweb.h"
#include "../civetweb/civetweb.h"
#include <stdlib.h>
#include "THttpServer.h"
#include "TUrl.h"
static int begin_request_handler(struct mg_connection *conn)
{
TCivetweb *engine = (TCivetweb *) mg_get_request_info(conn)->user_data;
if (engine == 0) return 0;
THttpServer *serv = engine->GetServer();
if (serv == 0) return 0;
const struct mg_request_info *request_info = mg_get_request_info(conn);
THttpCallArg arg;
TString filename;
Bool_t execres = kTRUE, debug = engine->IsDebugMode();
if (!debug && serv->IsFileRequested(request_info->uri, filename)) {
if ((filename.Index(".js") != kNPOS) || (filename.Index(".css") != kNPOS)) {
Int_t length = 0;
char *buf = THttpServer::ReadFileContent(filename.Data(), length);
if (buf == 0) {
arg.Set404();
} else {
arg.SetContentType(THttpServer::GetMimeType(filename.Data()));
arg.SetBinData(buf, length);
arg.AddHeader("Cache-Control", "max-age=3600");
arg.SetZipping(2);
}
} else {
arg.SetFile(filename.Data());
}
} else {
arg.SetPathAndFileName(request_info->uri);
arg.SetQuery(request_info->query_string);
arg.SetTopName(engine->GetTopName());
arg.SetMethod(request_info->request_method);
if (request_info->remote_user!=0)
arg.SetUserName(request_info->remote_user);
TString header;
for (int n = 0; n < request_info->num_headers; n++)
header.Append(TString::Format("%s: %s\r\n", request_info->http_headers[n].name, request_info->http_headers[n].value));
arg.SetRequestHeader(header);
const char* len = mg_get_header(conn, "Content-Length");
Int_t ilen = len!=0 ? TString(len).Atoi() : 0;
if (ilen>0) {
void* buf = malloc(ilen+1);
Int_t iread = mg_read(conn, buf, ilen);
if (iread==ilen) arg.SetPostData(buf, ilen);
else free(buf);
}
if (debug) {
TString cont;
cont.Append("<title>Civetweb echo</title>");
cont.Append("<h1>Civetweb echo</h1>\n");
static int count = 0;
cont.Append(TString::Format("Request %d:<br/>\n<pre>\n", ++count));
cont.Append(TString::Format(" Method : %s\n", arg.GetMethod()));
cont.Append(TString::Format(" PathName : %s\n", arg.GetPathName()));
cont.Append(TString::Format(" FileName : %s\n", arg.GetFileName()));
cont.Append(TString::Format(" Query : %s\n", arg.GetQuery()));
cont.Append(TString::Format(" PostData : %ld\n", arg.GetPostDataLength()));
if (arg.GetUserName())
cont.Append(TString::Format(" User : %s\n", arg.GetUserName()));
cont.Append("</pre><p>\n");
cont.Append("Environment:<br/>\n<pre>\n");
for (int n = 0; n < request_info->num_headers; n++)
cont.Append(TString::Format(" %s = %s\n", request_info->http_headers[n].name, request_info->http_headers[n].value));
cont.Append("</pre><p>\n");
arg.SetContentType("text/html");
arg.SetContent(cont);
} else {
execres = serv->ExecuteHttp(&arg);
}
}
if (!execres || arg.Is404()) {
TString hdr;
arg.FillHttpHeader(hdr, "HTTP/1.1");
mg_printf(conn, "%s", hdr.Data());
} else if (arg.IsFile()) {
mg_send_file(conn, (const char *) arg.GetContent());
} else {
Bool_t dozip = arg.GetZipping() > 0;
switch (arg.GetZipping()) {
case 2:
if (arg.GetContentLength() < 10000) {
dozip = kFALSE;
break;
}
case 1:
dozip = kFALSE;
for (int n = 0; n < request_info->num_headers; n++) {
TString name = request_info->http_headers[n].name;
if (name.Index("Accept-Encoding", 0, TString::kIgnoreCase) != 0) continue;
TString value = request_info->http_headers[n].value;
dozip = (value.Index("gzip", 0, TString::kIgnoreCase) != kNPOS);
break;
}
break;
case 3:
dozip = kTRUE;
break;
}
if (dozip) arg.CompressWithGzip();
TString hdr;
arg.FillHttpHeader(hdr, "HTTP/1.1");
mg_printf(conn, "%s", hdr.Data());
if (arg.GetContentLength() > 0)
mg_write(conn, arg.GetContent(), (size_t) arg.GetContentLength());
}
return 1;
}
TCivetweb::TCivetweb() :
THttpEngine("civetweb", "compact embedded http server"),
fCtx(0),
fCallbacks(0),
fTopName(),
fDebug(kFALSE)
{
}
TCivetweb::~TCivetweb()
{
if (fCtx != 0) mg_stop((struct mg_context *) fCtx);
if (fCallbacks != 0) free(fCallbacks);
fCtx = 0;
fCallbacks = 0;
}
Bool_t TCivetweb::Create(const char *args)
{
fCallbacks = malloc(sizeof(struct mg_callbacks));
memset(fCallbacks, 0, sizeof(struct mg_callbacks));
((struct mg_callbacks *) fCallbacks)->begin_request = begin_request_handler;
TString sport = "8080";
TString num_threads = "5";
TString auth_file, auth_domain;
if ((args != 0) && (strlen(args) > 0)) {
sport = "";
while ((*args != 0) && (*args >= '0') && (*args <= '9'))
sport.Append(*args++);
while ((*args != 0) && (*args != '?')) args++;
if (*args == '?') {
TUrl url(TString::Format("http://localhost/folder%s", args));
if (url.IsValid()) {
url.ParseOptions();
const char *top = url.GetValueFromOptions("top");
if (top != 0) fTopName = top;
Int_t thrds = url.GetIntValueFromOptions("thrds");
if (thrds > 0) num_threads.Form("%d", thrds);
const char *afile = url.GetValueFromOptions("auth_file");
if (afile != 0) auth_file = afile;
const char *adomain = url.GetValueFromOptions("auth_domain");
if (adomain != 0) auth_domain = adomain;
if (url.HasOption("debug")) fDebug = kTRUE;
}
}
}
const char *options[100];
int op(0);
Info("Create", "Starting HTTP server on port %s", sport.Data());
options[op++] = "listening_ports";
options[op++] = sport.Data();
options[op++] = "num_threads";
options[op++] = num_threads.Data();
if ((auth_file.Length() > 0) && (auth_domain.Length() > 0)) {
options[op++] = "global_auth_file";
options[op++] = auth_file.Data();
options[op++] = "authentication_domain";
options[op++] = auth_domain.Data();
}
options[op++] = 0;
fCtx = mg_start((struct mg_callbacks *) fCallbacks, this, options);
return kTRUE;
}